Index: Doc/Extra/Provider/dbfactorysupport.html ================================================================== --- Doc/Extra/Provider/dbfactorysupport.html +++ Doc/Extra/Provider/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.93.0, Culture=neutral, + Version=1.0.91.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139"/> </DbProviderFactories> </system.data> </configuration> Index: Doc/Extra/Provider/designer.html ================================================================== --- Doc/Extra/Provider/designer.html +++ Doc/Extra/Provider/designer.html @@ -52,11 +52,11 @@

Installation Instructions

Download and run one of the setup packages and then select the "Install the designer components for Visual Studio 20XX." option when prompted.

Express Edition Limitations

Visual Studio design-time Support, works with all versions of Visual Studio - 2005/2008/2010/2012/2013. You can add a SQLite database to the Servers list, design + 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.
Due to Visual Studio licensing restrictions, the Express Editions can no longer be supported. Index: Doc/Extra/Provider/environment.html ================================================================== --- Doc/Extra/Provider/environment.html +++ Doc/Extra/Provider/environment.html @@ -158,24 +158,10 @@ If this environment variable is set [to anything], it will be used by the System.Data.SQLite.SQLiteFactory class as the type name containing the System.Data.Common.DbProviderServices implementation that should be used. - - Use_SQLiteConvert_DefaultDbType - If this environment variable is set [to anything], it will be - used by the System.Data.SQLite.SQLiteConvert class as the default - DbType value that should be used when a per-connection value is not - available. - - - Use_SQLiteConvert_DefaultTypeName - If this environment variable is set [to anything], it will be - used by the System.Data.SQLite.SQLiteConvert class as the default - type name that should be used when a per-connection value is not - available. -


Limitations of this ADO.NET SQLite Data Provider

-

As providers go, this one doesn't have many restrictions. SQLite has no - support for row-level or table-level locks. When a connection locks the database for writing, no other connection or process may read or write to the database until the write operation is complete. The SQLite.NET provider attempts to retry - internally if a database is locked, up to the CommandTimeout property of the +

As providers go, this one doesn't have many restrictions. SQLite has no + support for row-level or table-level locks. When a connection locks the database for writing, no other connection or process may read or write to the database until the write operation is complete. The SQLite.NET provider attempts to retry + internally if a database is locked, up to the CommandTimeout property of the command in question.

-

SQLite is inherently type-less, and only understands a few basic datatypes - natively. They are (in .NET-speak) Int64, Double, String and Blob. The - SQLite.NET provider will use the database schema information it can glean to +

SQLite is inherently type-less, and only understands a few basic datatypes + natively. They are (in .NET-speak) Int64, Double, String and Blob. The + SQLite.NET provider will use the database schema information it can glean to enforce type-ness, but it is an inexact science.

- Hierarchical DataReaders are not supported. In the - case of transactions, any SQLiteCommand created on a connection will (when - executed) automatically join a transaction in progress, regardless of whether + Hierarchical DataReaders are not supported. In the + case of transactions, any SQLiteCommand created on a connection will (when + executed) automatically join a transaction in progress, regardless of whether that transaction was created before or after the command.

-

A SQLiteCommand object can be re-assigned a new SQLiteConnection object +

A SQLiteCommand object can be re-assigned a new SQLiteConnection object as long as no DataReaders are active on the command.

-

Opening a transaction is considered a write operation, so only use them when - you want to write to the database! If you hold open an "immediate" - transaction, all readers on other connections will be blocked until the - transaction is closed!

+

Opening a transaction is considered a write operation, so only use them when + you want to write to the database! If you hold open a transaction, all readers on other + connections + will be blocked until the transaction is closed!

Thread Safety

Multi-threading in SQLite must be done carefully. Here are the restrictions:

  • You May - Clone() a SQLiteConnection object in one thread and pass the cloned object to - another thread. Once passed, the other thread becomes the new owner of the - cloned connection, and the original thread must not keep a reference to the + Clone() a SQLiteConnection object in one thread and pass the cloned object to + another thread. Once passed, the other thread becomes the new owner of the + cloned connection, and the original thread must not keep a reference to the clone or call any methods on the clone.
  • You May - create multiple threads, and those threads can create their own - SQLiteConnection and subsequent objects for accessing a database.  - Multiple connections on multiple threads to the same database file are + create multiple threads, and those threads can create their own + SQLiteConnection and subsequent objects for accessing a database.  + Multiple connections on multiple threads to the same database file are perfectly acceptable and will behave predictably. 
  • You May NOT - call methods or properties or otherwise reference any SQLite provider classes + call methods or properties or otherwise reference any SQLite provider classes that belong to another thread.
  • - You May NOT pass a SQLiteCommand, SQLiteDataReader, SQLiteDataAdapter or - any other SQLite provider class except a cloned SQLiteConnection to another + You May NOT pass a SQLiteCommand, SQLiteDataReader, SQLiteDataAdapter or + any other SQLite provider class except a cloned SQLiteConnection to another thread.
-

Understand again that SQLite has no fine-grained locking mechanisms. It is - therefore your own responsibility in a multi-threaded environment to handle - potential timeouts that may occur if a long-running query in one thread - prevents a query in another thread from executing. These timeouts will only - occur if one thread is attempting to read while another thread is attempting to - write. Whichever thread got its lock first will be the one to execute, and the - other thread will block until the CommandTimeout value elapses or the other +

Understand again that SQLite has no fine-grained locking mechanisms. It is + therefore your own responsibility in a multi-threaded environment to handle + potential timeouts that may occur if a long-running query in one thread + prevents a query in another thread from executing. These timeouts will only + occur if one thread is attempting to read while another thread is attempting to + write. Whichever thread got its lock first will be the one to execute, and the + other thread will block until the CommandTimeout value elapses or the other thread finishes.


Version History

-

1.0.93.0 - June 23, 2014

-
    -
  • Updated to SQLite 3.8.5.
  • -
  • Updated to Entity Framework 6.1.
  • -
  • Add support for mapping transaction isolation levels to their legacy default values. Pursuant to [56b42d99c1].
  • -
  • Add support for setting the default DbType and type name used for mappings on a per-connection basis. Pursuant to [3c00ec5b52].
  • -
  • Add DetectTextAffinity and DetectStringType connection flags to enable automatic detection of column types, when necessary. Pursuant to [3c00ec5b52].
  • -
  • Add SetChunkSize method to the SQLiteConnection class. Pursuant to [d1c008fa0a].
  • -
  • Add SharedFlags static property to the SQLiteConnection class.
  • -
  • Make the ISQLiteSchemaExtensions interface public. ** Potentially Incompatible Change **
  • -
  • Have the SQLiteProviderFactory class (in the System.Data.SQLite.Linq assembly) implement the IServiceProvider interface.
  • -
  • Fix bug in documentation generator automation that prevented some internal documentation links from working.
  • -
  • Fix DateTime constant handling in the LINQ assembly. Fix for [da9f18d039]** Potentially Incompatible Change **
  • -
-

1.0.92.0 - March 19, 2014

-
    -
  • Updated to SQLite 3.8.4.1.
  • -
  • Update the list of keywords returned by SQLiteConnection.GetSchema("ReservedWords"). ** Potentially Incompatible Change **
  • -
  • Raise the static SQLiteConnection.Changed event when any SQLiteCommand or SQLiteDataReader object is closed or disposed.
  • -
  • Add the SQLiteDataReader.StepCount property to return the number of rows seen so far.
  • -
  • Add StickyHasRows connection flag to cause the SQLiteDataReader.HasRows property to return non-zero if there were ever any rows in the associated result sets.
  • -
  • When the TraceWarning connection flag is set, issue warnings about possibly malformed UNC paths. Pursuant to [283344397b].
  • -
  • Convert the primary NuGet package, "System.Data.SQLite", into a meta-package.
  • -
  • Enhancements to the NuGet packages, including the new "modular" packages.
  • -
-

1.0.91.0 - February 12, 2014

-
    -
  • Updated to SQLite 3.8.3.1.
  • +

    1.0.91.0 - February XX, 2014 (release scheduled)

    +
      +
    • Updated to SQLite 3.8.3.
    • Refresh all included SQLite core library documentation (e.g. SQL syntax).
    • Add support for Entity Framework 6.
    • Add support for per-connection mappings between type names and DbType values. Pursuant to [e87af1d06a].
    • Modify the namespace used for all internal classes in the System.Data.SQLite.Linq assembly. ** Potentially Incompatible Change **
    • Add SQLiteCompileOptions and InteropCompileOptions properties to the SQLiteConnection class to return the compile-time options for the SQLite core library and interop assembly, respectively.
    • @@ -80,11 +55,10 @@
    • Add NoConnectionPool and UseConnectionPool connection flags to disable or enable connection pooling by default.
    • Modify handling of the design-time components installer to run Visual Studio devenv.exe /setup after installing the package. This appears to be necessary in some circumstances for Visual Studio 2013. Pursuant to [a47eff2c71].
    • Modify the native library pre-loader to support reading settings from an XML configuration file and to be capable of checking more than one directory. Persuant to [f0246d1817].
    • Support detecting when the native library pre-loader should use the CodeBase property instead of the Location property as the basis for locating the interop assembly.
    • Change the default behavior for the native library pre-loader so it first searches the executing (i.e. System.Data.SQLite) assembly directory and then the application domain directory. Pursuant to [f0246d1817]** Potentially Incompatible Change **
    • -
    • Include DbType.AnsiString in the list of types that need special ColumnSize handling. Fix for [0550f0326e].

    1.0.90.0 - December 23, 2013

    • Updated to SQLite 3.8.2.
    • Add Visual Studio 2013 support to all the applicable solution/project files, their associated supporting files, and the test suite.
    • Index: Doc/Extra/Provider/welcome.html ================================================================== --- Doc/Extra/Provider/welcome.html +++ Doc/Extra/Provider/welcome.html @@ -92,11 +92,11 @@ On the Compact Framework, it is faster than Sql Server Mobile. SQLite's installed size is a fraction of Sql Mobile's. It uses less memory at runtime, runs queries faster, and has a smaller database file size as well.
    • Encrypted database support.  Encrypted databases are fully encrypted and support both binary and cleartext password types.
    • -
    • Visual Studio 2005/2008/2010/2012/2013 Design-Time Support.  You can add a SQLite +
    • Visual Studio 2005/2008/2010/2012 Design-Time Support.  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.
    • Full SQLite schema editing inside Visual Studio.  You can create/edit tables, views, triggers, indexes, check constraints and foreign keys.
    • @@ -158,11 +158,11 @@

      Distributing the Binaries (Compact Framework)

      Both the System.Data.SQLite.DLL and SQLite.Interop.XXX.DLL files must be deployed on the Compact Framework.  The XXX is the build number of - the System.Data.SQLite library (e.g. "093").  The + the System.Data.SQLite library (e.g. "091").  The SQLite.Interop.XXX.DLL file is a fully native assembly compiled for the ARM processor, and System.Data.SQLite is the fully-managed Compact Framework assembly.


    */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 @@ -1089,11 +992,10 @@ #define SQLITE_FCNTL_MMAP_SIZE 18 #define SQLITE_FCNTL_TRACE 19 #define SQLITE_FCNTL_HAS_MOVED 20 #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 -#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an @@ -2903,34 +2805,10 @@ ** 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 ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. -** -**
  • psow: ^The psow parameter may be "true" (or "on" or "yes" or -** "1") or "false" (or "off" or "no" or "0") to indicate that the -** [powersafe overwrite] property does or does not apply to the -** storage media on which the database file resides. ^The psow query -** parameter only works for the built-in unix and Windows VFSes. -** -**
  • nolock: ^The nolock parameter is a boolean query parameter -** which if set disables file locking in rollback journal modes. This -** is useful for accessing a database on a filesystem that does not -** support locking. Caution: Database corruption might result if two -** or more processes write to the same database and any one of those -** processes uses nolock=1. -** -**
  • immutable: ^The immutable parameter is a boolean query -** parameter that indicates that the database file is stored on -** read-only media. ^When immutable is set, SQLite assumes that the -** database file cannot be changed, even by a process with higher -** privilege, and so the database is opened read-only and all locking -** and change detection is disabled. Caution: Setting the immutable -** property on a database file that does in fact change can result -** in incorrect query results and/or [SQLITE_CORRUPT] errors. -** See also: [SQLITE_IOCAP_IMMUTABLE]. -** **
** ** ^Specifying an unknown parameter in the query component of a URI is not an ** error. Future versions of SQLite might understand additional query ** parameters. See "[query parameters with special meaning to SQLite]" for @@ -2956,13 +2834,12 @@ ** in URI filenames. ** file:data.db?mode=ro&cache=private ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. -** file:/home/fred/data.db?vfs=unix-dotfile -** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" -** that uses dot-files in place of posix advisory locking. +** file:/home/fred/data.db?vfs=unix-nolock +** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". ** file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. ** ** ** ^URI hexadecimal escape sequences (%HH) are supported within the path and @@ -6271,13 +6148,11 @@ #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 -#define SQLITE_TESTCTRL_VDBE_COVERAGE 21 -#define SQLITE_TESTCTRL_BYTEORDER 22 -#define SQLITE_TESTCTRL_LAST 22 +#define SQLITE_TESTCTRL_LAST 20 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information @@ -7496,20 +7371,10 @@ #if 0 extern "C" { #endif typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; -typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; - -/* The double-precision datatype used by RTree depends on the -** SQLITE_RTREE_INT_ONLY compile-time option. -*/ -#ifdef SQLITE_RTREE_INT_ONLY - typedef sqlite3_int64 sqlite3_rtree_dbl; -#else - typedef double sqlite3_rtree_dbl; -#endif /* ** Register a geometry callback named zGeom that can be used as part of an ** R-Tree geometry query as follows: ** @@ -7516,11 +7381,15 @@ ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), +#ifdef SQLITE_RTREE_INT_ONLY + int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes), +#else + int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes), +#endif void *pContext ); /* @@ -7528,74 +7397,68 @@ ** argument to callbacks registered using rtree_geometry_callback(). */ struct sqlite3_rtree_geometry { void *pContext; /* Copy of pContext passed to s_r_g_c() */ int nParam; /* Size of array aParam[] */ - sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ + double *aParam; /* Parameters passed to SQL geom function */ void *pUser; /* Callback implementation user data */ void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ }; -/* -** Register a 2nd-generation geometry callback named zScore that can be -** used as part of an R-Tree geometry query as follows: -** -** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) -*/ -SQLITE_API int sqlite3_rtree_query_callback( - sqlite3 *db, - const char *zQueryFunc, - int (*xQueryFunc)(sqlite3_rtree_query_info*), - void *pContext, - void (*xDestructor)(void*) -); - - -/* -** A pointer to a structure of the following type is passed as the -** argument to scored geometry callback registered using -** sqlite3_rtree_query_callback(). -** -** Note that the first 5 fields of this structure are identical to -** sqlite3_rtree_geometry. This structure is a subclass of -** sqlite3_rtree_geometry. -*/ -struct sqlite3_rtree_query_info { - void *pContext; /* pContext from when function registered */ - int nParam; /* Number of function parameters */ - sqlite3_rtree_dbl *aParam; /* value of function parameters */ - void *pUser; /* callback can use this, if desired */ - void (*xDelUser)(void*); /* function to free pUser */ - sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ - unsigned int *anQueue; /* Number of pending entries in the queue */ - int nCoord; /* Number of coordinates */ - int iLevel; /* Level of current node or entry */ - int mxLevel; /* The largest iLevel value in the tree */ - sqlite3_int64 iRowid; /* Rowid for current entry */ - sqlite3_rtree_dbl rParentScore; /* Score of parent node */ - int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visiblity */ - sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ -}; - -/* -** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. -*/ -#define NOT_WITHIN 0 /* Object completely outside of query region */ -#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ -#define FULLY_WITHIN 2 /* Object fully contained within query region */ - #if 0 } /* end of the 'extern "C"' block */ #endif #endif /* ifndef _SQLITE3RTREE_H_ */ /************** End of sqlite3.h *********************************************/ -/************** Continuing where we left off in sqliteInt.h ******************/ +/************** Begin file sqliteInt.h ***************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** Internal interface definitions for SQLite. +** +*/ +#ifndef _SQLITEINT_H_ +#define _SQLITEINT_H_ + +/* +** These #defines should enable >2GB file support on POSIX if the +** underlying operating system supports it. If the OS lacks +** large file support, or if the OS is windows, these should be no-ops. +** +** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any +** system #includes. Hence, this block of code must be the very first +** code in all source files. +** +** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch +** on the compiler command line. This is necessary if you are compiling +** on a recent machine (ex: Red Hat 7.2) but you want your code to work +** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2 +** without this option, LFS is enable. But LFS does not exist in the kernel +** in Red Hat 6.0, so the code won't work. Hence, for maximum binary +** portability you should omit LFS. +** +** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later. +*/ +#ifndef SQLITE_DISABLE_LFS +# define _LARGE_FILE 1 +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# define _LARGEFILE_SOURCE 1 +#endif /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ @@ -8508,14 +8371,14 @@ ** Estimated quantities used for query planning are stored as 16-bit ** logarithms. For quantity X, the value stored is 10*log2(X). This ** gives a possible range of values of approximately 1.0e986 to 1e-986. ** But the allowed values are "grainy". Not every value is representable. ** For example, quantities 16 and 17 are both represented by a LogEst -** of 40. However, since LogEst quantaties are suppose to be estimates, +** of 40. However, since LogEst quantatites are suppose to be estimates, ** not exact values, this imprecision is not a problem. ** -** "LogEst" is short for "Logarithmic Estimate". +** "LogEst" is short for "Logarithimic Estimate". ** ** Examples: ** 1 -> 0 20 -> 43 10000 -> 132 ** 2 -> 10 25 -> 46 25000 -> 146 ** 3 -> 16 100 -> 66 1000000 -> 199 @@ -8529,43 +8392,26 @@ */ typedef INT16_TYPE LogEst; /* ** Macros to determine whether the machine is big or little endian, -** and whether or not that determination is run-time or compile-time. -** -** For best performance, an attempt is made to guess at the byte-order -** using C-preprocessor macros. If that is unsuccessful, or if -** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined -** at run-time. +** evaluated at runtime. */ #ifdef SQLITE_AMALGAMATION SQLITE_PRIVATE const int sqlite3one = 1; #else SQLITE_PRIVATE const int sqlite3one; #endif -#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER) -# define SQLITE_BYTEORDER 1234 +#if defined(i386) || defined(__i386__) || defined(_M_IX86)\ + || defined(__x86_64) || defined(__x86_64__) # define SQLITE_BIGENDIAN 0 # define SQLITE_LITTLEENDIAN 1 # define SQLITE_UTF16NATIVE SQLITE_UTF16LE -#endif -#if (defined(sparc) || defined(__ppc__)) \ - && !defined(SQLITE_RUNTIME_BYTEORDER) -# define SQLITE_BYTEORDER 4321 -# define SQLITE_BIGENDIAN 1 -# define SQLITE_LITTLEENDIAN 0 -# define SQLITE_UTF16NATIVE SQLITE_UTF16BE -#endif -#if !defined(SQLITE_BYTEORDER) -# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ +#else # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) -# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) +# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) #endif /* ** Constants for the largest and smallest possible 64-bit signed integers. ** These macros are designed to work correctly on both 32-bit and 64-bit @@ -8876,13 +8722,11 @@ #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); -#if SQLITE_MAX_MMAP_SIZE>0 -SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); -#endif +SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned); 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); @@ -8928,11 +8772,10 @@ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); -SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*); 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); @@ -8998,20 +8841,21 @@ SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt); SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt); SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); +SQLITE_PRIVATE void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64); +SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor*); SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); -SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *); +SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *); SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *); SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); -SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt); #ifndef NDEBUG SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); #endif @@ -9138,16 +8982,13 @@ } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE - u32 cnt; /* Number of times this instruction was executed */ + int cnt; /* Number of times this instruction was executed */ u64 cycles; /* Total time spent executing this instruction */ #endif -#ifdef SQLITE_VDBE_COVERAGE - int iSrcLine; /* Source-code line that generated this opcode */ -#endif }; typedef struct VdbeOp VdbeOp; /* @@ -9247,81 +9088,81 @@ #define OP_Next 9 #define OP_AggStep 10 /* synopsis: accum=r[P3] step(r[P2@P5]) */ #define OP_Checkpoint 11 #define OP_JournalMode 12 #define OP_Vacuum 13 -#define OP_VFilter 14 /* synopsis: iplan=r[P3] zplan='P4' */ +#define OP_VFilter 14 /* synopsis: iPlan=r[P3] zPlan='P4' */ #define OP_VUpdate 15 /* synopsis: data=r[P3@P2] */ #define OP_Goto 16 #define OP_Gosub 17 #define OP_Return 18 #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ -#define OP_InitCoroutine 20 -#define OP_EndCoroutine 21 -#define OP_Yield 22 -#define OP_HaltIfNull 23 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 24 -#define OP_Integer 25 /* synopsis: r[P2]=P1 */ -#define OP_Int64 26 /* synopsis: r[P2]=P4 */ -#define OP_String 27 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_Null 28 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 29 /* synopsis: r[P1]=NULL */ -#define OP_Blob 30 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 31 /* synopsis: r[P2]=parameter(P1,P4) */ -#define OP_Move 32 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 33 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 34 /* synopsis: r[P2]=r[P1] */ -#define OP_ResultRow 35 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 36 -#define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_MustBeInt 38 -#define OP_RealAffinity 39 -#define OP_Permutation 40 -#define OP_Compare 41 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_Jump 42 -#define OP_Once 43 -#define OP_If 44 -#define OP_IfNot 45 -#define OP_Column 46 /* synopsis: r[P3]=PX */ -#define OP_Affinity 47 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 48 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 49 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 50 -#define OP_SetCookie 51 -#define OP_OpenRead 52 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 53 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenAutoindex 54 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 55 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 56 -#define OP_OpenPseudo 57 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 58 -#define OP_SeekLT 59 -#define OP_SeekLE 60 -#define OP_SeekGE 61 -#define OP_SeekGT 62 -#define OP_Seek 63 /* synopsis: intkey=r[P2] */ -#define OP_NoConflict 64 /* synopsis: key=r[P3@P4] */ -#define OP_NotFound 65 /* synopsis: key=r[P3@P4] */ -#define OP_Found 66 /* synopsis: key=r[P3@P4] */ -#define OP_NotExists 67 /* synopsis: intkey=r[P3] */ -#define OP_Sequence 68 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 69 /* synopsis: r[P2]=rowid */ -#define OP_Insert 70 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_Yield 20 +#define OP_HaltIfNull 21 /* synopsis: if r[P3] null then halt */ +#define OP_Halt 22 +#define OP_Integer 23 /* synopsis: r[P2]=P1 */ +#define OP_Int64 24 /* synopsis: r[P2]=P4 */ +#define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_Null 26 /* synopsis: r[P2..P3]=NULL */ +#define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 30 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */ +#define OP_ResultRow 32 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 33 +#define OP_AddImm 34 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_MustBeInt 35 +#define OP_RealAffinity 36 +#define OP_Permutation 37 +#define OP_Compare 38 +#define OP_Jump 39 +#define OP_Once 40 +#define OP_If 41 +#define OP_IfNot 42 +#define OP_Column 43 /* synopsis: r[P3]=PX */ +#define OP_Affinity 44 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 45 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 46 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 47 +#define OP_SetCookie 48 +#define OP_VerifyCookie 49 +#define OP_OpenRead 50 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 51 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenAutoindex 52 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 53 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 54 +#define OP_OpenPseudo 55 /* synopsis: content in r[P2@P3] */ +#define OP_Close 56 +#define OP_SeekLt 57 /* synopsis: key=r[P3@P4] */ +#define OP_SeekLe 58 /* synopsis: key=r[P3@P4] */ +#define OP_SeekGe 59 /* synopsis: key=r[P3@P4] */ +#define OP_SeekGt 60 /* synopsis: key=r[P3@P4] */ +#define OP_Seek 61 /* synopsis: intkey=r[P2] */ +#define OP_NoConflict 62 /* synopsis: key=r[P3@P4] */ +#define OP_NotFound 63 /* synopsis: key=r[P3@P4] */ +#define OP_Found 64 /* synopsis: key=r[P3@P4] */ +#define OP_NotExists 65 /* synopsis: intkey=r[P3] */ +#define OP_Sequence 66 /* synopsis: r[P2]=rowid */ +#define OP_NewRowid 67 /* synopsis: r[P2]=rowid */ +#define OP_Insert 68 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 69 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 70 #define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_InsertInt 73 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 74 -#define OP_ResetCount 75 +#define OP_ResetCount 73 +#define OP_SorterCompare 74 /* synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2 */ +#define OP_SorterData 75 /* synopsis: r[P2]=data */ #define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */ #define OP_Eq 79 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */ #define OP_Gt 80 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */ #define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */ #define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]=r[P3] goto P2 */ -#define OP_SorterCompare 84 /* synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2 */ +#define OP_RowKey 84 /* synopsis: r[P2]=key */ #define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ #define OP_Add 89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ @@ -9328,73 +9169,68 @@ #define OP_Subtract 90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ #define OP_Multiply 91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ #define OP_Divide 92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ #define OP_Remainder 93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ #define OP_Concat 94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_SorterData 95 /* synopsis: r[P2]=data */ +#define OP_RowData 95 /* synopsis: r[P2]=data */ #define OP_BitNot 96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ #define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_RowKey 98 /* synopsis: r[P2]=key */ -#define OP_RowData 99 /* synopsis: r[P2]=data */ -#define OP_Rowid 100 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 101 -#define OP_Last 102 -#define OP_SorterSort 103 -#define OP_Sort 104 -#define OP_Rewind 105 -#define OP_SorterInsert 106 -#define OP_IdxInsert 107 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 108 /* synopsis: key=r[P2@P3] */ -#define OP_IdxRowid 109 /* synopsis: r[P2]=rowid */ -#define OP_IdxLE 110 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGT 111 /* synopsis: key=r[P3@P4] */ -#define OP_IdxLT 112 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGE 113 /* synopsis: key=r[P3@P4] */ -#define OP_Destroy 114 -#define OP_Clear 115 -#define OP_ResetSorter 116 -#define OP_CreateIndex 117 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_CreateTable 118 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_ParseSchema 119 -#define OP_LoadAnalysis 120 -#define OP_DropTable 121 -#define OP_DropIndex 122 -#define OP_DropTrigger 123 -#define OP_IntegrityCk 124 -#define OP_RowSetAdd 125 /* synopsis: rowset(P1)=r[P2] */ -#define OP_RowSetRead 126 /* synopsis: r[P3]=rowset(P1) */ -#define OP_RowSetTest 127 /* synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 128 -#define OP_Param 129 -#define OP_FkCounter 130 /* synopsis: fkctr[P1]+=P2 */ -#define OP_FkIfZero 131 /* synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_MemMax 132 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_Rowid 98 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 99 +#define OP_Last 100 +#define OP_SorterSort 101 +#define OP_Sort 102 +#define OP_Rewind 103 +#define OP_SorterInsert 104 +#define OP_IdxInsert 105 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 106 /* synopsis: key=r[P2@P3] */ +#define OP_IdxRowid 107 /* synopsis: r[P2]=rowid */ +#define OP_IdxLT 108 /* synopsis: key=r[P3@P4] */ +#define OP_IdxGE 109 /* synopsis: key=r[P3@P4] */ +#define OP_Destroy 110 +#define OP_Clear 111 +#define OP_CreateIndex 112 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_CreateTable 113 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_ParseSchema 114 +#define OP_LoadAnalysis 115 +#define OP_DropTable 116 +#define OP_DropIndex 117 +#define OP_DropTrigger 118 +#define OP_IntegrityCk 119 +#define OP_RowSetAdd 120 /* synopsis: rowset(P1)=r[P2] */ +#define OP_RowSetRead 121 /* synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 122 /* synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 123 +#define OP_Param 124 +#define OP_FkCounter 125 /* synopsis: fkctr[P1]+=P2 */ +#define OP_FkIfZero 126 /* synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_MemMax 127 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_IfPos 128 /* synopsis: if r[P1]>0 goto P2 */ +#define OP_IfNeg 129 /* synopsis: if r[P1]<0 goto P2 */ +#define OP_IfZero 130 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ +#define OP_AggFinal 131 /* synopsis: accum=r[P1] N=P2 */ +#define OP_IncrVacuum 132 #define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_IfPos 134 /* synopsis: if r[P1]>0 goto P2 */ -#define OP_IfNeg 135 /* synopsis: if r[P1]<0 goto P2 */ -#define OP_IfZero 136 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ -#define OP_AggFinal 137 /* synopsis: accum=r[P1] N=P2 */ -#define OP_IncrVacuum 138 -#define OP_Expire 139 -#define OP_TableLock 140 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 141 -#define OP_VCreate 142 +#define OP_Expire 134 +#define OP_TableLock 135 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 136 +#define OP_VCreate 137 +#define OP_VDestroy 138 +#define OP_VOpen 139 +#define OP_VColumn 140 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VNext 141 +#define OP_VRename 142 #define OP_ToText 143 /* same as TK_TO_TEXT */ #define OP_ToBlob 144 /* same as TK_TO_BLOB */ #define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */ #define OP_ToInt 146 /* same as TK_TO_INT */ #define OP_ToReal 147 /* same as TK_TO_REAL */ -#define OP_VDestroy 148 -#define OP_VOpen 149 -#define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VNext 151 -#define OP_VRename 152 -#define OP_Pagecount 153 -#define OP_MaxPgcnt 154 -#define OP_Init 155 /* synopsis: Start at P2 */ -#define OP_Noop 156 -#define OP_Explain 157 +#define OP_Pagecount 148 +#define OP_MaxPgcnt 149 +#define OP_Trace 150 +#define OP_Noop 151 +#define OP_Explain 152 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c ** are encoded into bitvectors as follows: @@ -9407,28 +9243,28 @@ #define OPFLG_OUT2 0x0020 /* out2: P2 is an output */ #define OPFLG_OUT3 0x0040 /* out3: P3 is an output */ #define OPFLG_INITIALIZER {\ /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,\ /* 8 */ 0x01, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\ -/* 16 */ 0x01, 0x01, 0x04, 0x24, 0x01, 0x04, 0x05, 0x10,\ -/* 24 */ 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02,\ -/* 32 */ 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x05, 0x04,\ -/* 40 */ 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00,\ -/* 48 */ 0x00, 0x02, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 56 */ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x08,\ -/* 64 */ 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00, 0x4c,\ +/* 16 */ 0x01, 0x01, 0x04, 0x24, 0x04, 0x10, 0x00, 0x02,\ +/* 24 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x20,\ +/* 32 */ 0x00, 0x00, 0x04, 0x05, 0x04, 0x00, 0x00, 0x01,\ +/* 40 */ 0x01, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02, 0x02,\ +/* 48 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 56 */ 0x00, 0x11, 0x11, 0x11, 0x11, 0x08, 0x11, 0x11,\ +/* 64 */ 0x11, 0x11, 0x02, 0x02, 0x00, 0x00, 0x00, 0x4c,\ /* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\ /* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\ /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\ -/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\ -/* 104 */ 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01, 0x01,\ -/* 112 */ 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00,\ -/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x15,\ -/* 128 */ 0x01, 0x02, 0x00, 0x01, 0x08, 0x02, 0x05, 0x05,\ -/* 136 */ 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04,\ -/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x01,\ -/* 152 */ 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,} +/* 96 */ 0x24, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01,\ +/* 104 */ 0x08, 0x08, 0x00, 0x02, 0x01, 0x01, 0x02, 0x00,\ +/* 112 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 120 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01, 0x08,\ +/* 128 */ 0x05, 0x05, 0x05, 0x00, 0x01, 0x02, 0x00, 0x00,\ +/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04,\ +/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00,\ +/* 152 */ 0x00,} /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* @@ -9440,11 +9276,11 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); -SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); +SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); @@ -9481,16 +9317,13 @@ #ifndef SQLITE_OMIT_TRACE SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); -SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int); +SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); -typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int); -SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); - #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on @@ -9514,47 +9347,10 @@ # define VdbeComment(X) # define VdbeNoopComment(X) # define VdbeModuleComment(X) #endif -/* -** The VdbeCoverage macros are used to set a coverage testing point -** for VDBE branch instructions. The coverage testing points are line -** numbers in the sqlite3.c source file. VDBE branch coverage testing -** only works with an amalagmation build. That's ok since a VDBE branch -** coverage build designed for testing the test suite only. No application -** should ever ship with VDBE branch coverage measuring turned on. -** -** VdbeCoverage(v) // Mark the previously coded instruction -** // as a branch -** -** VdbeCoverageIf(v, conditional) // Mark previous if conditional true -** -** VdbeCoverageAlwaysTaken(v) // Previous branch is always taken -** -** VdbeCoverageNeverTaken(v) // Previous branch is never taken -** -** Every VDBE branch operation must be tagged with one of the macros above. -** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and -** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch() -** routine in vdbe.c, alerting the developer to the missed tag. -*/ -#ifdef SQLITE_VDBE_COVERAGE -SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int); -# define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__) -# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__) -# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2); -# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1); -# define VDBE_OFFSET_LINENO(x) (__LINE__+x) -#else -# define VdbeCoverage(v) -# define VdbeCoverageIf(v,x) -# define VdbeCoverageAlwaysTaken(v) -# define VdbeCoverageNeverTaken(v) -# define VDBE_OFFSET_LINENO(x) 0 -#endif - #endif /************** End of vdbe.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pager.h in the middle of sqliteInt.h *****************/ @@ -9962,75 +9758,87 @@ */ #ifndef _SQLITE_OS_H_ #define _SQLITE_OS_H_ /* -** Attempt to automatically detect the operating system and setup the -** necessary pre-processor macros for it. -*/ -/************** Include os_setup.h in the middle of os.h *********************/ -/************** Begin file os_setup.h ****************************************/ -/* -** 2013 November 25 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains pre-processor directives related to operating system -** detection and/or setup. -*/ -#ifndef _OS_SETUP_H_ -#define _OS_SETUP_H_ - -/* -** Figure out if we are dealing with Unix, Windows, or some other operating -** system. -** -** After the following block of preprocess macros, all of SQLITE_OS_UNIX, -** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of -** the three will be 1. The other two will be 0. +** Figure out if we are dealing with Unix, Windows, or some other +** operating system. After the following block of preprocess macros, +** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, and SQLITE_OS_OTHER +** will defined to either 1 or 0. One of the four will be 1. The other +** three will be 0. */ #if defined(SQLITE_OS_OTHER) -# if SQLITE_OS_OTHER==1 -# undef SQLITE_OS_UNIX -# define SQLITE_OS_UNIX 0 -# undef SQLITE_OS_WIN -# define SQLITE_OS_WIN 0 -# else -# undef SQLITE_OS_OTHER -# endif +# if SQLITE_OS_OTHER==1 +# undef SQLITE_OS_UNIX +# define SQLITE_OS_UNIX 0 +# undef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# else +# undef SQLITE_OS_OTHER +# endif #endif #if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) -# define SQLITE_OS_OTHER 0 -# ifndef SQLITE_OS_WIN -# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \ - defined(__MINGW32__) || defined(__BORLANDC__) -# define SQLITE_OS_WIN 1 -# define SQLITE_OS_UNIX 0 -# else -# define SQLITE_OS_WIN 0 -# define SQLITE_OS_UNIX 1 -# endif -# else -# define SQLITE_OS_UNIX 0 -# endif -#else -# ifndef SQLITE_OS_WIN -# define SQLITE_OS_WIN 0 -# endif -#endif - -#endif /* _OS_SETUP_H_ */ - -/************** End of os_setup.h ********************************************/ -/************** Continuing where we left off in os.h *************************/ +# define SQLITE_OS_OTHER 0 +# ifndef SQLITE_OS_WIN +# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) +# define SQLITE_OS_WIN 1 +# define SQLITE_OS_UNIX 0 +# else +# define SQLITE_OS_WIN 0 +# define SQLITE_OS_UNIX 1 +# endif +# else +# define SQLITE_OS_UNIX 0 +# endif +#else +# ifndef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# endif +#endif + +#if SQLITE_OS_WIN +# include +#endif + +/* +** Determine if we are dealing with Windows NT. +** +** We ought to be able to determine if we are compiling for win98 or winNT +** using the _WIN32_WINNT macro as follows: +** +** #if defined(_WIN32_WINNT) +** # define SQLITE_OS_WINNT 1 +** #else +** # define SQLITE_OS_WINNT 0 +** #endif +** +** However, vs2005 does not set _WIN32_WINNT by default, as it ought to, +** so the above test does not work. We'll just assume that everything is +** winNT unless the programmer explicitly says otherwise by setting +** SQLITE_OS_WINNT to 0. +*/ +#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) +# define SQLITE_OS_WINNT 1 +#endif + +/* +** Determine if we are dealing with WindowsCE - which has a much +** reduced API. +*/ +#if defined(_WIN32_WCE) +# define SQLITE_OS_WINCE 1 +#else +# define SQLITE_OS_WINCE 0 +#endif + +/* +** Determine if we are dealing with WinRT, which provides only a subset of +** the full Win32 API. +*/ +#if !defined(SQLITE_OS_WINRT) +# define SQLITE_OS_WINRT 0 +#endif /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC @@ -10596,11 +10404,12 @@ /* ** Return true if it OK to factor constant expressions into the initialization ** code. The argument is a Parse object for the code generator. */ -#define ConstFactorOk(P) ((P)->okConstFactor) +#define ConstFactorOk(P) \ + ((P)->cookieGoto>0 && OptimizationEnabled((P)->db,SQLITE_FactorOutConst)) /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. @@ -10822,20 +10631,14 @@ #define SQLITE_AFF_MASK 0x67 /* ** Additional bit values that can be ORed with an affinity without ** changing the affinity. -** -** The SQLITE_NOTNULL flag is a combination of NULLEQ and JUMPIFNULL. -** It causes an assert() to fire if either operand to a comparison -** operator is NULL. It is added to certain comparison operators to -** prove that the operands are always NOT NULL. */ #define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */ #define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ -#define SQLITE_NOTNULL 0x88 /* Assert that operands are never NULL */ /* ** An object of this type is created for each virtual table present in ** the database schema. ** @@ -10925,11 +10728,11 @@ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ #ifndef SQLITE_OMIT_CHECK ExprList *pCheck; /* All CHECK constraints */ #endif - LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ + tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */ int tnum; /* Root BTree node for this table (see note above) */ i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */ i16 nCol; /* Number of columns in this table */ u16 nRef; /* Number of pointers to this Table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ @@ -11090,24 +10893,23 @@ ** the OP_MakeRecord opcode of the VDBE and is disassembled by the ** OP_Column opcode. ** ** This structure holds a record that has already been disassembled ** into its constituent fields. -** -** The r1 and r2 member variables are only used by the optimized comparison -** functions vdbeRecordCompareInt() and vdbeRecordCompareString(). */ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ u16 nField; /* Number of entries in apMem[] */ - i8 default_rc; /* Comparison result if keys are equal */ - u8 isCorrupt; /* Corruption detected by xRecordCompare() */ + u8 flags; /* Boolean settings. UNPACKED_... below */ Mem *aMem; /* Values */ - int r1; /* Value to return if (lhs > rhs) */ - int r2; /* Value to return if (rhs < lhs) */ }; +/* +** Allowed values of UnpackedRecord.flags +*/ +#define UNPACKED_INCRKEY 0x01 /* Make this key an epsilon larger */ +#define UNPACKED_PREFIX_MATCH 0x02 /* A prefix match is considered OK */ /* ** Each SQL index is represented in memory by an ** instance of the following structure. ** @@ -11134,11 +10936,11 @@ ** element. */ struct Index { char *zName; /* Name of this index */ i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */ - LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */ + 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 */ @@ -11148,11 +10950,11 @@ int tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ u16 nColumn; /* Number of columns stored in the index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ - unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ + unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 @@ -11161,20 +10963,10 @@ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ #endif }; -/* -** Allowed values for Index.idxType -*/ -#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ -#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ -#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ - -/* Return true if index X is a PRIMARY KEY index */ -#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) - /* ** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ @@ -11375,12 +11167,12 @@ #define EP_Error 0x000008 /* Expression contains one or more errors */ #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ -#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ -#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ +#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */ + /* unused 0x000200 */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ @@ -11440,10 +11232,11 @@ ** of the result column in the form: DATABASE.TABLE.COLUMN. This later ** form is used for name resolution with nested FROM clauses. */ struct ExprList { int nExpr; /* Number of expressions on the list */ + int iECursor; /* VDBE Cursor associated with this ExprList */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The list of expressions */ char *zName; /* Token associated with this expression */ char *zSpan; /* Original text of the expression */ u8 sortOrder; /* 1 for DESC or 0 for ASC */ @@ -11532,22 +11325,21 @@ ** ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. */ struct SrcList { - int nSrc; /* Number of tables or subqueries in the FROM clause */ - u32 nAlloc; /* Number of entries allocated in a[] below */ + u8 nSrc; /* Number of tables or subqueries in the FROM clause */ + u8 nAlloc; /* Number of entries allocated in a[] below */ struct SrcList_item { Schema *pSchema; /* Schema to which this item is fixed */ char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ - int regResult; /* Registers holding results of a co-routine */ u8 jointype; /* Type of join between this able and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ @@ -11589,11 +11381,10 @@ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ -#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ /* Allowed return values from sqlite3WhereIsDistinct() */ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ #define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ @@ -11664,19 +11455,20 @@ struct Select { ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ u16 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ - int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ + int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */ u64 nSelectRow; /* Estimated number of result rows */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ Select *pPrior; /* Prior select in a compound select statement */ Select *pNext; /* Next select to the left in a compound */ + Select *pRightmost; /* Right-most select in a compound select statement */ Expr *pLimit; /* LIMIT expression. NULL means not used. */ Expr *pOffset; /* OFFSET expression. NULL means not used. */ With *pWith; /* WITH clause attached to this select. Or NULL. */ }; @@ -11688,17 +11480,16 @@ #define SF_Resolved 0x0002 /* Identifiers have been resolved */ #define SF_Aggregate 0x0004 /* Contains aggregate functions */ #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ - /* 0x0040 NOT USED */ +#define SF_UseSorter 0x0040 /* Sort using a sorter */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ - /* 0x0100 NOT USED */ +#define SF_Materialize 0x0100 /* Force materialization of views */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ -#define SF_Compound 0x1000 /* Part of a compound query */ /* ** The results of a SELECT can be distributed in several ways, as defined ** by one of the following macros. The "SRT" prefix means "SELECT Result @@ -11743,19 +11534,17 @@ ** of the co-routine is stored in register pDest->iSDParm ** and the result row is stored in pDest->nDest registers ** starting with pDest->iSdst. ** ** SRT_Table Store results in temporary table pDest->iSDParm. -** SRT_Fifo This is like SRT_EphemTab except that the table -** is assumed to already be open. SRT_Fifo has -** the additional property of being able to ignore -** the ORDER BY clause. +** This is like SRT_EphemTab except that the table +** is assumed to already be open. ** -** SRT_DistFifo Store results in a temporary table pDest->iSDParm. +** SRT_DistTable Store results in a temporary table pDest->iSDParm. ** But also use temporary table pDest->iSDParm+1 as ** a record of all prior results and ignore any duplicate -** rows. Name means: "Distinct Fifo". +** rows. Name means: "Distinct Table". ** ** SRT_Queue Store results in priority queue pDest->iSDParm (really ** an index). Append a sequence number so that all entries ** are distinct. ** @@ -11765,24 +11554,23 @@ */ #define SRT_Union 1 /* Store result as keys in an index */ #define SRT_Except 2 /* Remove result from a UNION index */ #define SRT_Exists 3 /* Store 1 if the result is not empty */ #define SRT_Discard 4 /* Do not save the results anywhere */ -#define SRT_Fifo 5 /* Store result as data with an automatic rowid */ -#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */ -#define SRT_Queue 7 /* Store result in an queue */ -#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */ /* The ORDER BY clause is ignored for all of the above */ -#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue) - -#define SRT_Output 9 /* Output each row of result */ -#define SRT_Mem 10 /* Store result in a memory cell */ -#define SRT_Set 11 /* Store results as keys in an index */ -#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ -#define SRT_Coroutine 13 /* Generate a single row of result */ -#define SRT_Table 14 /* Store result as data with an automatic rowid */ +#define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard) + +#define SRT_Output 5 /* Output each row of result */ +#define SRT_Mem 6 /* Store result in a memory cell */ +#define SRT_Set 7 /* Store results as keys in an index */ +#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */ +#define SRT_Coroutine 9 /* Generate a single row of result */ +#define SRT_Table 10 /* Store result as data with an automatic rowid */ +#define SRT_DistTable 11 /* Like SRT_Table, but unique results only */ +#define SRT_Queue 12 /* Store result in an queue */ +#define SRT_DistQueue 13 /* Like SRT_Queue, but unique results only */ /* ** An instance of this object describes where to put of the results of ** a SELECT statement. */ @@ -11876,46 +11664,49 @@ int rc; /* Return code from execution */ u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ + u8 nTempInUse; /* Number of aTempReg[] currently checked out */ + u8 nColCache; /* Number of entries in aColCache[] */ + u8 iColCache; /* Next entry in aColCache[] to replace */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ - u8 okConstFactor; /* OK to factor out constants */ int aTempReg[8]; /* Holding area for temporary registers */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ int nSet; /* Number of sets used so far */ int nOnce; /* Number of OP_Once instructions so far */ int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ + int nLabel; /* Number of labels used */ + int *aLabel; /* Space to hold the labels */ int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */ int ckBase; /* Base register of data during check constraints */ int iPartIdxTab; /* Table corresponding to a partial index */ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */ - int nLabel; /* Number of labels used */ - int *aLabel; /* Space to hold the labels */ struct yColCache { int iTable; /* Table cursor number */ - i16 iColumn; /* Table column number */ + int iColumn; /* Table column number */ u8 tempReg; /* iReg is a temp register that needs to be freed */ int iLevel; /* Nesting level */ int iReg; /* Reg with value of this column. 0 means none. */ int lru; /* Least recently used entry has the smallest value */ } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ ExprList *pConstExpr;/* Constant expressions */ - Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ + int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */ int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ + Token constraintName;/* Name of the constraint currently being parsed */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ @@ -11930,21 +11721,16 @@ u32 newmask; /* Mask of new.* columns referenced */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ - /************************************************************************ - ** Above is constant between recursions. Below is reset before and after - ** each recursion. The boundary between these two regions is determined - ** using offsetof(Parse,nVar) so the nVar field must be the first field - ** in the recursive region. - ************************************************************************/ + /* Above is constant between recursions. Below is reset before and after + ** each recursion */ int nVar; /* Number of '?' variables seen in the SQL so far */ int nzVar; /* Number of available slots in azVar[] */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ - u8 bFreeWith; /* True if pWith should be freed with parser */ u8 explain; /* True if the EXPLAIN flag is found on the query */ #ifndef SQLITE_OMIT_VIRTUALTABLE u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ int nVtabLock; /* Number of virtual tables to lock */ #endif @@ -11967,10 +11753,11 @@ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif Table *pZombieTab; /* List of Table objects to delete after code gen */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ + u8 bFreeWith; /* True if pWith should be freed with parser */ }; /* ** Return true if currently inside an sqlite3_declare_vtab() call. */ @@ -12173,29 +11960,19 @@ int isInit; /* True after initialization has finished */ int inProgress; /* True while initialization in progress */ int isMutexInit; /* True after mutexes are initialized */ int isMallocInit; /* True after malloc is initialized */ int isPCacheInit; /* True after malloc is initialized */ - int nRefInitMutex; /* Number of users of pInitMutex */ sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ + int nRefInitMutex; /* Number of users of pInitMutex */ void (*xLog)(void*,int,const char*); /* Function for logging */ void *pLogArg; /* First argument to xLog() */ + int bLocaltimeFault; /* True to fail localtime() calls */ #ifdef SQLITE_ENABLE_SQLLOG void(*xSqllog)(void*,sqlite3*,const char*, int); void *pSqllogArg; #endif -#ifdef SQLITE_VDBE_COVERAGE - /* The following callback (if not NULL) is invoked on every VDBE branch - ** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE. - */ - void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */ - void *pVdbeBranchArg; /* 1st argument */ -#endif -#ifndef SQLITE_OMIT_BUILTIN_TEST - int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ -#endif - int bLocaltimeFault; /* True to fail localtime() calls */ }; /* ** This macro is used inside of assert() statements to indicate that ** the assert is only valid on a well-formed database. Instead of: @@ -12493,16 +12270,10 @@ SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); SQLITE_PRIVATE int sqlite3CodeOnce(Parse *); -#ifdef SQLITE_OMIT_BUILTIN_TEST -# define sqlite3FaultSim(X) SQLITE_OK -#else -SQLITE_PRIVATE int sqlite3FaultSim(int); -#endif - SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32); SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32); SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*); SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*); @@ -12510,11 +12281,11 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*); SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64); -SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64); +SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, u8 iBatch, i64); SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*); SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) @@ -12531,10 +12302,11 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); #else # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif +SQLITE_PRIVATE int sqlite3CodeCoroutine(Parse*, Select*, SelectDest*); SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int); SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); @@ -12566,29 +12338,27 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*); -SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); -SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*); +SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int); SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int); SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*); SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int); -SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); -SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCode(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8); SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int); -SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCodeAndCache(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int); SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int); @@ -12622,16 +12392,16 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*); SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); +SQLITE_PRIVATE void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); SQLITE_PRIVATE int sqlite3IsRowid(const char*); SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8); SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*); SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); -SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int); SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*); SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*); SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int); @@ -12766,11 +12536,11 @@ #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *); -SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int); +SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *); SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); @@ -12785,11 +12555,11 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int); SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *); SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); @@ -13304,26 +13074,19 @@ 0, /* isInit */ 0, /* inProgress */ 0, /* isMutexInit */ 0, /* isMallocInit */ 0, /* isPCacheInit */ - 0, /* nRefInitMutex */ 0, /* pInitMutex */ + 0, /* nRefInitMutex */ 0, /* xLog */ 0, /* pLogArg */ + 0, /* bLocaltimeFault */ #ifdef SQLITE_ENABLE_SQLLOG 0, /* xSqllog */ - 0, /* pSqllogArg */ -#endif -#ifdef SQLITE_VDBE_COVERAGE - 0, /* xVdbeBranch */ - 0, /* pVbeBranchArg */ -#endif -#ifndef SQLITE_OMIT_BUILTIN_TEST - 0, /* xTestCallback */ -#endif - 0 /* bLocaltimeFault */ + 0 /* pSqllogArg */ +#endif }; /* ** Hash table for global functions - functions common to all ** database connections. After initialization, this table is @@ -13586,13 +13349,10 @@ "OMIT_COMPLETE", #endif #ifdef SQLITE_OMIT_COMPOUND_SELECT "OMIT_COMPOUND_SELECT", #endif -#ifdef SQLITE_OMIT_CTE - "OMIT_CTE", -#endif #ifdef SQLITE_OMIT_DATETIME_FUNCS "OMIT_DATETIME_FUNCS", #endif #ifdef SQLITE_OMIT_DECLTYPE "OMIT_DECLTYPE", @@ -13877,14 +13637,14 @@ u16 nHdrParsed; /* Number of header fields parsed so far */ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ - Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ + Bool multiPseudo:1; /* Multi-register pseudo-cursor */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Rowid being deleted by OP_Delete */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ @@ -13974,10 +13734,11 @@ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ } u; int n; /* Number of characters in string value, excluding '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ + u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */ #endif @@ -14000,14 +13761,13 @@ #define MEM_Null 0x0001 /* Value is NULL */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ -#define MEM_AffMask 0x001f /* Mask of affinity bits */ #define MEM_RowSet 0x0020 /* Value is a RowSet object */ #define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ -#define MEM_Undefined 0x0080 /* Value is undefined */ +#define MEM_Invalid 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_TypeMask 0x01ff /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of @@ -14014,11 +13774,11 @@ ** the following flags must be set to determine the memory management ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated */ #define MEM_Term 0x0200 /* String rep is nul terminated */ -#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */ +#define MEM_Dyn 0x0400 /* Need to call sqliteFree() on Mem.z */ #define MEM_Static 0x0800 /* Mem.z points to a static string */ #define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ #define MEM_Agg 0x2000 /* Mem.z points to an agg function context */ #define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */ #ifdef SQLITE_OMIT_INCRBLOB @@ -14035,11 +13795,11 @@ /* ** Return true if a memory cell is not marked as invalid. This macro ** is for use inside assert() statements only. */ #ifdef SQLITE_DEBUG -#define memIsValid(M) ((M)->flags & MEM_Undefined)==0 +#define memIsValid(M) ((M)->flags & MEM_Invalid)==0 #endif /* ** Each auxilliary data pointer stored by a user defined function ** implementation calling sqlite3_set_auxdata() is stored in an instance @@ -14230,24 +13990,23 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p); -#define VdbeMemDynamic(X) \ - (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) #define VdbeMemRelease(X) \ - if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X); + if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \ + sqlite3VdbeMemReleaseExternal(X); SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); SQLITE_PRIVATE const char *sqlite3OpcodeName(int); SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); +SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem); SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); -SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); @@ -14261,11 +14020,10 @@ # define sqlite3VdbeLeave(X) #endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*); -SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem*); #endif #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int); #else @@ -17983,11 +17741,11 @@ /* Make sure mem5.aiFreelist[iLogsize] contains at least one free ** block. If not, then split a block of the next larger power of ** two in order to create a new free block of size iLogsize. */ - for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){} + for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){} if( iBin>LOGMAX ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte); return 0; } @@ -18010,16 +17768,10 @@ mem5.currentCount++; mem5.currentOut += iFullSz; if( mem5.maxCount -# include /* amalgamator: dontcache */ -#endif - -/* -** Determine if we are dealing with Windows NT. -** -** We ought to be able to determine if we are compiling for Windows 9x or -** Windows NT using the _WIN32_WINNT macro as follows: -** -** #if defined(_WIN32_WINNT) -** # define SQLITE_OS_WINNT 1 -** #else -** # define SQLITE_OS_WINNT 0 -** #endif -** -** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as -** it ought to, so the above test does not work. We'll just assume that -** everything is Windows NT unless the programmer explicitly says otherwise -** by setting SQLITE_OS_WINNT to 0. -*/ -#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) -# define SQLITE_OS_WINNT 1 -#endif - -/* -** Determine if we are dealing with Windows CE - which has a much reduced -** API. -*/ -#if defined(_WIN32_WCE) -# define SQLITE_OS_WINCE 1 -#else -# define SQLITE_OS_WINCE 0 -#endif - -/* -** Determine if we are dealing with WinRT, which provides only a subset of -** the full Win32 API. -*/ -#if !defined(SQLITE_OS_WINRT) -# define SQLITE_OS_WINRT 0 -#endif - -#endif /* _OS_WIN_H_ */ - -/************** End of os_win.h **********************************************/ -/************** Continuing where we left off in mutex_w32.c ******************/ -#endif - /* ** The code in this file is only used if we are compiling multithreaded ** on a win32 system. */ #ifdef SQLITE_MUTEX_W32 @@ -20370,10 +20037,24 @@ digit += '0'; *val = (*val - d)*10.0; return (char)digit; } #endif /* SQLITE_OMIT_FLOATING_POINT */ + +/* +** Append N space characters to the given string buffer. +*/ +SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *pAccum, int N){ + static const char zSpaces[] = " "; + while( N>=(int)sizeof(zSpaces)-1 ){ + sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1); + N -= sizeof(zSpaces)-1; + } + if( N>0 ){ + sqlite3StrAccumAppend(pAccum, zSpaces, N); + } +} /* ** Set the StrAccum object to an error mode. */ static void setStrAccumError(StrAccum *p, u8 eError){ @@ -20460,13 +20141,15 @@ }else{ bArgList = useIntern = 0; } for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ + int amt; bufpt = (char *)fmt; - while( (c=(*++fmt))!='%' && c!=0 ){}; - sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); + amt = 1; + while( (c=(*++fmt))!='%' && c!=0 ) amt++; + sqlite3StrAccumAppend(pAccum, bufpt, amt); if( c==0 ) break; } if( (c=(*++fmt))==0 ){ sqlite3StrAccumAppend(pAccum, "%", 1); break; @@ -20643,12 +20326,14 @@ } *(--bufpt) = zOrd[x*2+1]; *(--bufpt) = zOrd[x*2]; } { - const char *cset = &aDigits[infop->charset]; - u8 base = infop->base; + register const char *cset; /* Use registers for speed */ + register int base; + cset = &aDigits[infop->charset]; + base = infop->base; do{ /* Convert to ascii */ *(--bufpt) = cset[longvalue%base]; longvalue = longvalue/base; }while( longvalue>0 ); } @@ -20948,103 +20633,77 @@ /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long. The field width is "width". Do ** the output. */ - width -= length; - if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width); - sqlite3StrAccumAppend(pAccum, bufpt, length); - if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width); - + if( !flag_leftjustify ){ + register int nspace; + nspace = width-length; + if( nspace>0 ){ + sqlite3AppendSpace(pAccum, nspace); + } + } + if( length>0 ){ + sqlite3StrAccumAppend(pAccum, bufpt, length); + } + if( flag_leftjustify ){ + register int nspace; + nspace = width-length; + if( nspace>0 ){ + sqlite3AppendSpace(pAccum, nspace); + } + } if( zExtra ) sqlite3_free(zExtra); }/* End for loop over the format string */ } /* End of function */ /* -** Enlarge the memory allocation on a StrAccum object so that it is -** able to accept at least N more bytes of text. -** -** Return the number of bytes of text that StrAccum is able to accept -** after the attempted enlargement. The value returned might be zero. -*/ -static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ - char *zNew; - assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ - if( p->accError ){ - testcase(p->accError==STRACCUM_TOOBIG); - testcase(p->accError==STRACCUM_NOMEM); - return 0; - } - if( !p->useMalloc ){ - N = p->nAlloc - p->nChar - 1; - setStrAccumError(p, STRACCUM_TOOBIG); - return N; - }else{ - char *zOld = (p->zText==p->zBase ? 0 : p->zText); - i64 szNew = p->nChar; - szNew += N + 1; - if( szNew > p->mxAlloc ){ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_TOOBIG); - return 0; - }else{ - p->nAlloc = (int)szNew; - } - if( p->useMalloc==1 ){ - zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); - }else{ - zNew = sqlite3_realloc(zOld, p->nAlloc); - } - if( zNew ){ - assert( p->zText!=0 || p->nChar==0 ); - if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); - p->zText = zNew; - }else{ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_NOMEM); - return 0; - } - } - return N; -} - -/* -** Append N space characters to the given string buffer. -*/ -SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){ - if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; - while( (N--)>0 ) p->zText[p->nChar++] = ' '; -} - -/* -** The StrAccum "p" is not large enough to accept N new bytes of z[]. -** So enlarge if first, then do the append. -** -** This is a helper routine to sqlite3StrAccumAppend() that does special-case -** work (enlarging the buffer) using tail recursion, so that the -** sqlite3StrAccumAppend() routine can use fast calling semantics. -*/ -static void enlargeAndAppend(StrAccum *p, const char *z, int N){ - N = sqlite3StrAccumEnlarge(p, N); - if( N>0 ){ - memcpy(&p->zText[p->nChar], z, N); - p->nChar += N; - } -} - -/* -** Append N bytes of text from z to the StrAccum object. Increase the -** size of the memory allocation for StrAccum if necessary. +** Append N bytes of text from z to the StrAccum object. */ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ assert( z!=0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); assert( p->accError==0 || p->nAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ - enlargeAndAppend(p,z,N); - return; + char *zNew; + if( p->accError ){ + testcase(p->accError==STRACCUM_TOOBIG); + testcase(p->accError==STRACCUM_NOMEM); + return; + } + if( !p->useMalloc ){ + N = p->nAlloc - p->nChar - 1; + setStrAccumError(p, STRACCUM_TOOBIG); + if( N<=0 ){ + return; + } + }else{ + char *zOld = (p->zText==p->zBase ? 0 : p->zText); + i64 szNew = p->nChar; + szNew += N + 1; + if( szNew > p->mxAlloc ){ + sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_TOOBIG); + return; + }else{ + p->nAlloc = (int)szNew; + } + if( p->useMalloc==1 ){ + zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); + }else{ + zNew = sqlite3_realloc(zOld, p->nAlloc); + } + if( zNew ){ + if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); + p->zText = zNew; + }else{ + sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_NOMEM); + return; + } + } } assert( p->zText ); memcpy(&p->zText[p->nChar], z, N); p->nChar += N; } @@ -21731,11 +21390,11 @@ assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); sqlite3VdbeMemRelease(pMem); pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem); pMem->enc = desiredEnc; - pMem->flags |= (MEM_Term); + pMem->flags |= (MEM_Term|MEM_Dyn); pMem->z = (char*)zOut; pMem->zMalloc = pMem->z; translate_out: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) @@ -21859,10 +21518,11 @@ sqlite3VdbeMemRelease(&m); m.z = 0; } assert( (m.flags & MEM_Term)!=0 || db->mallocFailed ); assert( (m.flags & MEM_Str)!=0 || db->mallocFailed ); + assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed ); assert( m.z || db->mallocFailed ); return m.z; } /* @@ -21974,28 +21634,10 @@ #ifdef SQLITE_COVERAGE_TEST SQLITE_PRIVATE void sqlite3Coverage(int x){ static unsigned dummy = 0; dummy += (unsigned)x; } -#endif - -/* -** Give a callback to the test harness that can be used to simulate faults -** in places where it is difficult or expensive to do so purely by means -** of inputs. -** -** The intent of the integer argument is to let the fault simulator know -** which of multiple sqlite3FaultSim() calls has been hit. -** -** Return whatever integer value the test callback returns, or return -** SQLITE_OK if no test callback is installed. -*/ -#ifndef SQLITE_OMIT_BUILTIN_TEST -SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ - int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback; - return xCallback ? xCallback(iTest) : SQLITE_OK; -} #endif #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). @@ -23086,16 +22728,17 @@ testcase( iB==-1 ); testcase( iB==0 ); if( iB>=0 ){ testcase( iA>0 && LARGEST_INT64 - iA == iB ); testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 ); if( iA>0 && LARGEST_INT64 - iA < iB ) return 1; + *pA += iB; }else{ testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 ); testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 ); if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1; + *pA += iB; } - *pA += iB; return 0; } SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ testcase( iB==SMALLEST_INT64+1 ); if( iB==SMALLEST_INT64 ){ @@ -23115,22 +22758,13 @@ iA1 = iA/TWOPOWER32; iA0 = iA % TWOPOWER32; iB1 = iB/TWOPOWER32; iB0 = iB % TWOPOWER32; - if( iA1==0 ){ - if( iB1==0 ){ - *pA *= iB; - return 0; - } - r = iA0*iB1; - }else if( iB1==0 ){ - r = iA1*iB0; - }else{ - /* If both iA1 and iB1 are non-zero, overflow will result */ - return 1; - } + if( iA1*iB1 != 0 ) return 1; + assert( iA1*iB0==0 || iA0*iB1==0 ); + r = iA1*iB0 + iA0*iB1; testcase( r==(-TWOPOWER31)-1 ); testcase( r==(-TWOPOWER31) ); testcase( r==TWOPOWER31 ); testcase( r==TWOPOWER31-1 ); if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1; @@ -23209,12 +22843,12 @@ return b+x[b-a]; } } /* -** Convert an integer into a LogEst. In other words, compute an -** approximation for 10*log2(x). +** Convert an integer into a LogEst. In other words, compute a +** good approximatation for 10*log2(x). */ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){ static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; LogEst y = 40; if( x<8 ){ @@ -23566,81 +23200,81 @@ /* 9 */ "Next" OpHelp(""), /* 10 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), /* 11 */ "Checkpoint" OpHelp(""), /* 12 */ "JournalMode" OpHelp(""), /* 13 */ "Vacuum" OpHelp(""), - /* 14 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), + /* 14 */ "VFilter" OpHelp("iPlan=r[P3] zPlan='P4'"), /* 15 */ "VUpdate" OpHelp("data=r[P3@P2]"), /* 16 */ "Goto" OpHelp(""), /* 17 */ "Gosub" OpHelp(""), /* 18 */ "Return" OpHelp(""), /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), - /* 20 */ "InitCoroutine" OpHelp(""), - /* 21 */ "EndCoroutine" OpHelp(""), - /* 22 */ "Yield" OpHelp(""), - /* 23 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 24 */ "Halt" OpHelp(""), - /* 25 */ "Integer" OpHelp("r[P2]=P1"), - /* 26 */ "Int64" OpHelp("r[P2]=P4"), - /* 27 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 28 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 29 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 30 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 31 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), - /* 32 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 33 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 34 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 35 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 36 */ "CollSeq" OpHelp(""), - /* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 38 */ "MustBeInt" OpHelp(""), - /* 39 */ "RealAffinity" OpHelp(""), - /* 40 */ "Permutation" OpHelp(""), - /* 41 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 42 */ "Jump" OpHelp(""), - /* 43 */ "Once" OpHelp(""), - /* 44 */ "If" OpHelp(""), - /* 45 */ "IfNot" OpHelp(""), - /* 46 */ "Column" OpHelp("r[P3]=PX"), - /* 47 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 48 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 49 */ "Count" OpHelp("r[P2]=count()"), - /* 50 */ "ReadCookie" OpHelp(""), - /* 51 */ "SetCookie" OpHelp(""), - /* 52 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 53 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 54 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 55 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 56 */ "SorterOpen" OpHelp(""), - /* 57 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 58 */ "Close" OpHelp(""), - /* 59 */ "SeekLT" OpHelp(""), - /* 60 */ "SeekLE" OpHelp(""), - /* 61 */ "SeekGE" OpHelp(""), - /* 62 */ "SeekGT" OpHelp(""), - /* 63 */ "Seek" OpHelp("intkey=r[P2]"), - /* 64 */ "NoConflict" OpHelp("key=r[P3@P4]"), - /* 65 */ "NotFound" OpHelp("key=r[P3@P4]"), - /* 66 */ "Found" OpHelp("key=r[P3@P4]"), - /* 67 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 68 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 69 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 70 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 20 */ "Yield" OpHelp(""), + /* 21 */ "HaltIfNull" OpHelp("if r[P3] null then halt"), + /* 22 */ "Halt" OpHelp(""), + /* 23 */ "Integer" OpHelp("r[P2]=P1"), + /* 24 */ "Int64" OpHelp("r[P2]=P4"), + /* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 26 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 30 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 32 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 33 */ "CollSeq" OpHelp(""), + /* 34 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 35 */ "MustBeInt" OpHelp(""), + /* 36 */ "RealAffinity" OpHelp(""), + /* 37 */ "Permutation" OpHelp(""), + /* 38 */ "Compare" OpHelp(""), + /* 39 */ "Jump" OpHelp(""), + /* 40 */ "Once" OpHelp(""), + /* 41 */ "If" OpHelp(""), + /* 42 */ "IfNot" OpHelp(""), + /* 43 */ "Column" OpHelp("r[P3]=PX"), + /* 44 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 45 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 46 */ "Count" OpHelp("r[P2]=count()"), + /* 47 */ "ReadCookie" OpHelp(""), + /* 48 */ "SetCookie" OpHelp(""), + /* 49 */ "VerifyCookie" OpHelp(""), + /* 50 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 51 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 52 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 53 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 54 */ "SorterOpen" OpHelp(""), + /* 55 */ "OpenPseudo" OpHelp("content in r[P2@P3]"), + /* 56 */ "Close" OpHelp(""), + /* 57 */ "SeekLt" OpHelp("key=r[P3@P4]"), + /* 58 */ "SeekLe" OpHelp("key=r[P3@P4]"), + /* 59 */ "SeekGe" OpHelp("key=r[P3@P4]"), + /* 60 */ "SeekGt" OpHelp("key=r[P3@P4]"), + /* 61 */ "Seek" OpHelp("intkey=r[P2]"), + /* 62 */ "NoConflict" OpHelp("key=r[P3@P4]"), + /* 63 */ "NotFound" OpHelp("key=r[P3@P4]"), + /* 64 */ "Found" OpHelp("key=r[P3@P4]"), + /* 65 */ "NotExists" OpHelp("intkey=r[P3]"), + /* 66 */ "Sequence" OpHelp("r[P2]=rowid"), + /* 67 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 68 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 69 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 70 */ "Delete" OpHelp(""), /* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 73 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 74 */ "Delete" OpHelp(""), - /* 75 */ "ResetCount" OpHelp(""), + /* 73 */ "ResetCount" OpHelp(""), + /* 74 */ "SorterCompare" OpHelp("if key(P1)!=rtrim(r[P3],P4) goto P2"), + /* 75 */ "SorterData" OpHelp("r[P2]=data"), /* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"), /* 79 */ "Eq" OpHelp("if r[P1]==r[P3] goto P2"), /* 80 */ "Gt" OpHelp("if r[P1]>r[P3] goto P2"), /* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"), /* 82 */ "Lt" OpHelp("if r[P1]=r[P3] goto P2"), - /* 84 */ "SorterCompare" OpHelp("if key(P1)!=rtrim(r[P3],P4) goto P2"), + /* 84 */ "RowKey" OpHelp("r[P2]=key"), /* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), /* 89 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), @@ -23647,73 +23281,68 @@ /* 90 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), /* 91 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), /* 92 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), /* 93 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), /* 94 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 95 */ "SorterData" OpHelp("r[P2]=data"), + /* 95 */ "RowData" OpHelp("r[P2]=data"), /* 96 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), /* 97 */ "String8" OpHelp("r[P2]='P4'"), - /* 98 */ "RowKey" OpHelp("r[P2]=key"), - /* 99 */ "RowData" OpHelp("r[P2]=data"), - /* 100 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 101 */ "NullRow" OpHelp(""), - /* 102 */ "Last" OpHelp(""), - /* 103 */ "SorterSort" OpHelp(""), - /* 104 */ "Sort" OpHelp(""), - /* 105 */ "Rewind" OpHelp(""), - /* 106 */ "SorterInsert" OpHelp(""), - /* 107 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 108 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 109 */ "IdxRowid" OpHelp("r[P2]=rowid"), - /* 110 */ "IdxLE" OpHelp("key=r[P3@P4]"), - /* 111 */ "IdxGT" OpHelp("key=r[P3@P4]"), - /* 112 */ "IdxLT" OpHelp("key=r[P3@P4]"), - /* 113 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 114 */ "Destroy" OpHelp(""), - /* 115 */ "Clear" OpHelp(""), - /* 116 */ "ResetSorter" OpHelp(""), - /* 117 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), - /* 118 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), - /* 119 */ "ParseSchema" OpHelp(""), - /* 120 */ "LoadAnalysis" OpHelp(""), - /* 121 */ "DropTable" OpHelp(""), - /* 122 */ "DropIndex" OpHelp(""), - /* 123 */ "DropTrigger" OpHelp(""), - /* 124 */ "IntegrityCk" OpHelp(""), - /* 125 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 126 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 127 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 128 */ "Program" OpHelp(""), - /* 129 */ "Param" OpHelp(""), - /* 130 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 131 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 132 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 98 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 99 */ "NullRow" OpHelp(""), + /* 100 */ "Last" OpHelp(""), + /* 101 */ "SorterSort" OpHelp(""), + /* 102 */ "Sort" OpHelp(""), + /* 103 */ "Rewind" OpHelp(""), + /* 104 */ "SorterInsert" OpHelp(""), + /* 105 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 106 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 107 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 108 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 109 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 110 */ "Destroy" OpHelp(""), + /* 111 */ "Clear" OpHelp(""), + /* 112 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), + /* 113 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), + /* 114 */ "ParseSchema" OpHelp(""), + /* 115 */ "LoadAnalysis" OpHelp(""), + /* 116 */ "DropTable" OpHelp(""), + /* 117 */ "DropIndex" OpHelp(""), + /* 118 */ "DropTrigger" OpHelp(""), + /* 119 */ "IntegrityCk" OpHelp(""), + /* 120 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 121 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 122 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 123 */ "Program" OpHelp(""), + /* 124 */ "Param" OpHelp(""), + /* 125 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 126 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 127 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 128 */ "IfPos" OpHelp("if r[P1]>0 goto P2"), + /* 129 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"), + /* 130 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"), + /* 131 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 132 */ "IncrVacuum" OpHelp(""), /* 133 */ "Real" OpHelp("r[P2]=P4"), - /* 134 */ "IfPos" OpHelp("if r[P1]>0 goto P2"), - /* 135 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"), - /* 136 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"), - /* 137 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 138 */ "IncrVacuum" OpHelp(""), - /* 139 */ "Expire" OpHelp(""), - /* 140 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 141 */ "VBegin" OpHelp(""), - /* 142 */ "VCreate" OpHelp(""), + /* 134 */ "Expire" OpHelp(""), + /* 135 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 136 */ "VBegin" OpHelp(""), + /* 137 */ "VCreate" OpHelp(""), + /* 138 */ "VDestroy" OpHelp(""), + /* 139 */ "VOpen" OpHelp(""), + /* 140 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 141 */ "VNext" OpHelp(""), + /* 142 */ "VRename" OpHelp(""), /* 143 */ "ToText" OpHelp(""), /* 144 */ "ToBlob" OpHelp(""), /* 145 */ "ToNumeric" OpHelp(""), /* 146 */ "ToInt" OpHelp(""), /* 147 */ "ToReal" OpHelp(""), - /* 148 */ "VDestroy" OpHelp(""), - /* 149 */ "VOpen" OpHelp(""), - /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 151 */ "VNext" OpHelp(""), - /* 152 */ "VRename" OpHelp(""), - /* 153 */ "Pagecount" OpHelp(""), - /* 154 */ "MaxPgcnt" OpHelp(""), - /* 155 */ "Init" OpHelp("Start at P2"), - /* 156 */ "Noop" OpHelp(""), - /* 157 */ "Explain" OpHelp(""), + /* 148 */ "Pagecount" OpHelp(""), + /* 149 */ "MaxPgcnt" OpHelp(""), + /* 150 */ "Trace" OpHelp(""), + /* 151 */ "Noop" OpHelp(""), + /* 152 */ "Explain" OpHelp(""), }; return azName[i]; } #endif @@ -23801,10 +23430,36 @@ # else # define OS_VXWORKS 0 # endif #endif +/* +** These #defines should enable >2GB file support on Posix if the +** underlying operating system supports it. If the OS lacks +** large file support, these should be no-ops. +** +** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch +** on the compiler command line. This is necessary if you are compiling +** on a recent machine (ex: RedHat 7.2) but you want your code to work +** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 +** without this option, LFS is enable. But LFS does not exist in the kernel +** in RedHat 6.0, so the code won't work. Hence, for maximum binary +** portability you should omit LFS. +** +** The previous paragraph was written in 2005. (This paragraph is written +** on 2008-11-28.) These days, all Linux kernels support large files, so +** you should probably leave LFS enabled. But some embedded platforms might +** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful. +*/ +#ifndef SQLITE_DISABLE_LFS +# define _LARGE_FILE 1 +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# define _LARGEFILE_SOURCE 1 +#endif + /* ** standard include files. */ #include #include @@ -24249,11 +23904,10 @@ return geteuid() ? 0 : fchown(fd,uid,gid); } /* Forward reference */ static int openDirectory(const char*, int*); -static int unixGetpagesize(void); /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during ** testing and sandboxing. The following array holds the names and pointers @@ -24373,13 +24027,10 @@ { "mremap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent) #endif - { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, -#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent) - }; /* End of the overrideable system calls */ /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the ** "unix" VFSes. Return SQLITE_OK opon successfully updating the @@ -28035,40 +27686,10 @@ #endif return rc; } -/* -** Return the system page size. -** -** This function should not be called directly by other code in this file. -** Instead, it should be called via macro osGetpagesize(). -*/ -static int unixGetpagesize(void){ -#if defined(_BSD_SOURCE) - return getpagesize(); -#else - return (int)sysconf(_SC_PAGESIZE); -#endif -} - -/* -** Return the minimum number of 32KB shm regions that should be mapped at -** a time, assuming that each mapping must be an integer multiple of the -** current system page-size. -** -** Usually, this is 1. The exception seems to be systems that are configured -** to use 64KB pages - in this case each mapping must cover at least two -** shm regions. -*/ -static int unixShmRegionPerMap(void){ - int shmsz = 32*1024; /* SHM region size */ - int pgsz = osGetpagesize(); /* System page size */ - assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */ - if( pgszpInode->pShmNode; assert( unixMutexHeld() ); if( p && p->nRef==0 ){ - int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->mutex); - for(i=0; inRegion; i+=nShmPerMap){ + for(i=0; inRegion; i++){ if( p->h>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ sqlite3_free(p->apRegion[i]); } @@ -28287,12 +27907,10 @@ ){ unixFile *pDbFd = (unixFile*)fd; unixShm *p; unixShmNode *pShmNode; int rc = SQLITE_OK; - int nShmPerMap = unixShmRegionPerMap(); - int nReqRegion; /* If the shared-memory file has not yet been opened, open it now. */ if( pDbFd->pShm==0 ){ rc = unixOpenSharedMemory(pDbFd); if( rc!=SQLITE_OK ) return rc; @@ -28304,16 +27922,13 @@ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); assert( pShmNode->pInode==pDbFd->pInode ); assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); - /* Minimum number of regions required to be mapped. */ - nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; - - if( pShmNode->nRegionnRegion<=iRegion ){ char **apNew; /* New apRegion[] array */ - int nByte = nReqRegion*szRegion; /* Minimum required file size */ + int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ struct stat sStat; /* Used by fstat() */ pShmNode->szRegion = szRegion; if( pShmNode->h>=0 ){ @@ -28358,23 +27973,21 @@ } } /* Map the requested memory region into this processes address space. */ apNew = (char **)sqlite3_realloc( - pShmNode->apRegion, nReqRegion*sizeof(char *) + pShmNode->apRegion, (iRegion+1)*sizeof(char *) ); if( !apNew ){ rc = SQLITE_IOERR_NOMEM; goto shmpage_out; } pShmNode->apRegion = apNew; - while( pShmNode->nRegionnRegion<=iRegion){ void *pMem; if( pShmNode->h>=0 ){ - pMem = osMmap(0, nMap, + pMem = osMmap(0, szRegion, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion ); if( pMem==MAP_FAILED ){ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); @@ -28386,15 +27999,12 @@ rc = SQLITE_NOMEM; goto shmpage_out; } memset(pMem, 0, szRegion); } - - for(i=0; iapRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i]; - } - pShmNode->nRegion += nShmPerMap; + pShmNode->apRegion[pShmNode->nRegion] = pMem; + pShmNode->nRegion++; } } shmpage_out: if( pShmNode->nRegion>iRegion ){ @@ -28603,10 +28213,23 @@ pFd->pMapRegion = 0; pFd->mmapSize = 0; pFd->mmapSizeActual = 0; } } + +/* +** Return the system page size. +*/ +static int unixGetPagesize(void){ +#if HAVE_MREMAP + return 512; +#elif defined(_BSD_SOURCE) + return getpagesize(); +#else + return (int)sysconf(_SC_PAGESIZE); +#endif +} /* ** Attempt to set the size of the memory mapping maintained by file ** descriptor pFd to nNew bytes. Any existing mapping is discarded. ** @@ -28640,16 +28263,12 @@ assert( MAP_FAILED!=0 ); if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; if( pOrig ){ -#if HAVE_MREMAP - i64 nReuse = pFd->mmapSize; -#else - const int szSyspage = osGetpagesize(); + const int szSyspage = unixGetPagesize(); i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); -#endif u8 *pReq = &pOrig[nReuse]; /* Unmap any pages of the existing mapping that cannot be reused. */ if( nReuse!=nOrig ){ osMunmap(pReq, nOrig-nReuse); @@ -31391,11 +31010,11 @@ }; unsigned int i; /* Loop counter */ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==25 ); + assert( ArraySize(aSyscall)==24 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } @@ -31430,10 +31049,15 @@ ****************************************************************************** ** ** This file contains code that is specific to Windows. */ #if SQLITE_OS_WIN /* This file is used for Windows only */ + +#ifdef __CYGWIN__ +# include +# include /* amalgamator: keep */ +#endif /* ** Include code that is common to all os_*.c files */ /************** Include os_common.h in the middle of os_win.c ****************/ @@ -31644,14 +31268,10 @@ #endif /* !defined(_OS_COMMON_H_) */ /************** End of os_common.h *******************************************/ /************** Continuing where we left off in os_win.c *********************/ -/* -** Include the header file for the Windows VFS. -*/ - /* ** Compiling and using WAL mode requires several APIs that are only ** available in Windows platforms based on the NT kernel. */ #if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL) @@ -33459,36 +33079,10 @@ # define SQLITE_WIN32_IOERR_RETRY_DELAY 25 #endif static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY; static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; -/* -** The "winIoerrCanRetry1" macro is used to determine if a particular I/O -** error code obtained via GetLastError() is eligible to be retried. It -** must accept the error code DWORD as its only argument and should return -** non-zero if the error code is transient in nature and the operation -** responsible for generating the original error might succeed upon being -** retried. The argument to this macro should be a variable. -** -** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it -** is defined, it will be consulted only when the macro "winIoerrCanRetry1" -** returns zero. The "winIoerrCanRetry2" macro is completely optional and -** may be used to include additional error codes in the set that should -** result in the failing I/O operation being retried by the caller. If -** defined, the "winIoerrCanRetry2" macro must exhibit external semantics -** identical to those of the "winIoerrCanRetry1" macro. -*/ -#if !defined(winIoerrCanRetry1) -#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \ - ((a)==ERROR_SHARING_VIOLATION) || \ - ((a)==ERROR_LOCK_VIOLATION) || \ - ((a)==ERROR_DEV_NOT_EXIST) || \ - ((a)==ERROR_NETNAME_DELETED) || \ - ((a)==ERROR_SEM_TIMEOUT) || \ - ((a)==ERROR_NETWORK_UNREACHABLE)) -#endif - /* ** If a ReadFile() or WriteFile() error occurs, invoke this routine ** to see if it should be retried. Return TRUE to retry. Return FALSE ** to give up with an error. */ @@ -33498,22 +33092,17 @@ if( pError ){ *pError = e; } return 0; } - if( winIoerrCanRetry1(e) ){ + if( e==ERROR_ACCESS_DENIED || + e==ERROR_LOCK_VIOLATION || + e==ERROR_SHARING_VIOLATION ){ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } -#if defined(winIoerrCanRetry2) - else if( winIoerrCanRetry2(e) ){ - sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); - ++*pnRetry; - return 1; - } -#endif if( pError ){ *pError = e; } return 0; } @@ -34448,11 +34037,11 @@ #endif if( res == 0 ){ pFile->lastErrno = osGetLastError(); /* No need to log a failure to lock */ } - OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res)); + OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); return res; } /* ** Undo a readlock @@ -34472,11 +34061,11 @@ if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, "winUnlockReadLock", pFile->zPath); } - OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res)); + OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); return res; } /* ** Lock the file with the lock specified by parameter locktype - one @@ -34547,20 +34136,12 @@ ** around problems caused by indexing and/or anti-virus software on ** Windows systems. ** If you are using this code as a model for alternative VFSes, do not ** copy this retry logic. It is a hack intended for Windows only. */ - lastErrno = osGetLastError(); - OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", - pFile->h, cnt, res)); - if( lastErrno==ERROR_INVALID_HANDLE ){ - pFile->lastErrno = lastErrno; - rc = SQLITE_IOERR_LOCK; - OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", - pFile->h, cnt, sqlite3ErrName(rc))); - return rc; - } + OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n", + pFile->h, cnt, sqlite3ErrName(res))); if( cnt ) sqlite3_win32_sleep(1); } gotPendingLock = res; if( !res ){ lastErrno = osGetLastError(); @@ -34641,29 +34222,29 @@ ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero, otherwise zero. */ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ - int res; + int rc; winFile *pFile = (winFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut)); assert( id!=0 ); if( pFile->locktype>=RESERVED_LOCK ){ - res = 1; - OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res)); + rc = 1; + OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc)); }else{ - res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0); - if( res ){ + rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0); + if( rc ){ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } - res = !res; - OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res)); + rc = !rc; + OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc)); } - *pResOut = res; + *pResOut = rc; OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", pFile->h, pResOut, *pResOut)); return SQLITE_OK; } @@ -34800,21 +34381,10 @@ a[1] = winIoerrRetryDelay; } OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } -#ifdef SQLITE_TEST - case SQLITE_FCNTL_WIN32_SET_HANDLE: { - LPHANDLE phFile = (LPHANDLE)pArg; - HANDLE hOldFile = pFile->h; - pFile->h = *phFile; - *phFile = hOldFile; - OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n", - hOldFile, pFile->h)); - return SQLITE_OK; - } -#endif case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = 0; int rc = winGetTempname(pFile->pVfs, &zTFile); if( rc==SQLITE_OK ){ *(char**)pArg = zTFile; @@ -34874,11 +34444,11 @@ ** Windows will only let you create file view mappings ** on allocation size granularity boundaries. ** During sqlite3_os_init() we do a GetSystemInfo() ** to get the granularity size. */ -static SYSTEM_INFO winSysInfo; +SYSTEM_INFO winSysInfo; #ifndef SQLITE_OMIT_WAL /* ** Helper functions to obtain and relinquish the global mutex. The @@ -36808,33 +36378,19 @@ #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. */ +/* +** Interfaces for opening a shared library, finding entry points +** within the shared library, and closing the shared library. +*/ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ HANDLE h; -#if defined(__CYGWIN__) - int nFull = pVfs->mxPathname+1; - char *zFull = sqlite3MallocZero( nFull ); - void *zConverted = 0; - if( zFull==0 ){ - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); - return 0; - } - if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){ - sqlite3_free(zFull); - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); - return 0; - } - zConverted = winConvertFromUtf8Filename(zFull); - sqlite3_free(zFull); -#else void *zConverted = winConvertFromUtf8Filename(zFilename); UNUSED_PARAMETER(pVfs); -#endif if( zConverted==0 ){ - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); return 0; } if( osIsNT() ){ #if SQLITE_OS_WINRT h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0); @@ -36845,30 +36401,24 @@ #ifdef SQLITE_WIN32_HAS_ANSI else{ h = osLoadLibraryA((char*)zConverted); } #endif - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h)); sqlite3_free(zConverted); return (void*)h; } static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ UNUSED_PARAMETER(pVfs); winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut); } static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){ - FARPROC proc; UNUSED_PARAMETER(pVfs); - proc = osGetProcAddressA((HANDLE)pH, zSym); - OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n", - (void*)pH, zSym, (void*)proc)); - return (void(*)(void))proc; + return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym); } static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ UNUSED_PARAMETER(pVfs); osFreeLibrary((HANDLE)pHandle); - OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle)); } #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ #define winDlOpen 0 #define winDlError 0 #define winDlSym 0 @@ -37560,12 +37110,11 @@ PgHdr *pSynced; /* Last synced page in dirty page list */ int nRef; /* Number of referenced pages */ int szCache; /* Configured cache size */ int szPage; /* Size of every page in this cache */ int szExtra; /* Size of extra space for each page */ - u8 bPurgeable; /* True if pages are on backing store */ - u8 eCreate; /* eCreate value for for xFetch() */ + int bPurgeable; /* True if pages are on backing store */ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ void *pStress; /* Argument to xStress */ sqlite3_pcache *pCache; /* Pluggable cache module */ PgHdr *pPage1; /* Reference to page 1 */ }; @@ -37628,14 +37177,10 @@ if( pPage->pDirtyPrev ){ pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; }else{ assert( pPage==p->pDirty ); p->pDirty = pPage->pDirtyNext; - if( p->pDirty==0 && p->bPurgeable ){ - assert( p->eCreate==1 ); - p->eCreate = 2; - } } pPage->pDirtyNext = 0; pPage->pDirtyPrev = 0; expensive_assert( pcacheCheckSynced(p) ); @@ -37652,13 +37197,10 @@ pPage->pDirtyNext = p->pDirty; if( pPage->pDirtyNext ){ assert( pPage->pDirtyNext->pDirtyPrev==0 ); pPage->pDirtyNext->pDirtyPrev = pPage; - }else if( p->bPurgeable ){ - assert( p->eCreate==2 ); - p->eCreate = 1; } p->pDirty = pPage; if( !p->pDirtyTail ){ p->pDirtyTail = pPage; } @@ -37724,11 +37266,10 @@ ){ memset(p, 0, sizeof(PCache)); p->szPage = szPage; p->szExtra = szExtra; p->bPurgeable = bPurgeable; - p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; } @@ -37764,11 +37305,11 @@ PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number to obtain */ int createFlag, /* If true, create page if it does not exist already */ PgHdr **ppPage /* Write the page here */ ){ - sqlite3_pcache_page *pPage; + sqlite3_pcache_page *pPage = 0; PgHdr *pPgHdr = 0; int eCreate; assert( pCache!=0 ); assert( createFlag==1 || createFlag==0 ); @@ -37775,16 +37316,12 @@ assert( pgno>0 ); /* If the pluggable cache (sqlite3_pcache*) has not been allocated, ** allocate it now. */ - if( !pCache->pCache ){ + if( !pCache->pCache && createFlag ){ sqlite3_pcache *p; - if( !createFlag ){ - *ppPage = 0; - return SQLITE_OK; - } p = sqlite3GlobalConfig.pcache2.xCreate( pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable ); if( !p ){ return SQLITE_NOMEM; @@ -37791,20 +37328,15 @@ } sqlite3GlobalConfig.pcache2.xCachesize(p, numberOfCachePages(pCache)); pCache->pCache = p; } - /* eCreate defines what to do if the page does not exist. - ** 0 Do not allocate a new page. (createFlag==0) - ** 1 Allocate a new page if doing so is inexpensive. - ** (createFlag==1 AND bPurgeable AND pDirty) - ** 2 Allocate a new page even it doing so is difficult. - ** (createFlag==1 AND !(bPurgeable AND pDirty) - */ - eCreate = createFlag==0 ? 0 : pCache->eCreate; - assert( (createFlag*(1+(!pCache->bPurgeable||!pCache->pDirty)))==eCreate ); - pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); + eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty)); + if( pCache->pCache ){ + pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); + } + if( !pPage && eCreate==1 ){ PgHdr *pPg; /* Find a dirty page to write-out and recycle. First try to find a ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC @@ -39321,12 +38853,12 @@ struct RowSetEntry *pEntry; /* List of entries using pRight */ struct RowSetEntry *pLast; /* Last entry on the pEntry list */ struct RowSetEntry *pFresh; /* Source of new entry objects */ struct RowSetEntry *pForest; /* List of binary trees of entries */ u16 nFresh; /* Number of objects on pFresh */ - u16 rsFlags; /* Various flags */ - int iBatch; /* Current insert batch */ + u8 rsFlags; /* Various flags */ + u8 iBatch; /* Current insert batch */ }; /* ** Allowed values for RowSet.rsFlags */ @@ -39656,11 +39188,11 @@ ** ** If this is the first test of a new batch and if there exist entires ** on pRowSet->pEntry, then sort those entires into the forest at ** pRowSet->pForest so that they can be tested. */ -SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){ +SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){ struct RowSetEntry *p, *pTree; /* This routine is never called after sqlite3RowSetNext() */ assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 ); @@ -40485,12 +40017,11 @@ u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ - u8 tempFile; /* zFilename is a temporary or immutable file */ - u8 noLock; /* Do not lock (except in WAL mode) */ + u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ /************************************************************************** ** The following block contains those class members that change during @@ -40951,11 +40482,11 @@ assert( !pPager->exclusiveMode || pPager->eLock==eLock ); assert( eLock==NO_LOCK || eLock==SHARED_LOCK ); assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 ); if( isOpen(pPager->fd) ){ assert( pPager->eLock>=eLock ); - rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock); + rc = sqlite3OsUnlock(pPager->fd, eLock); if( pPager->eLock!=UNKNOWN_LOCK ){ pPager->eLock = (u8)eLock; } IOTRACE(("UNLOCK %p %d\n", pPager, eLock)) } @@ -40975,11 +40506,11 @@ static int pagerLockDb(Pager *pPager, int eLock){ int rc = SQLITE_OK; assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK ); if( pPager->eLockeLock==UNKNOWN_LOCK ){ - rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock); + rc = sqlite3OsLock(pPager->fd, eLock); if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){ pPager->eLock = (u8)eLock; IOTRACE(("LOCK %p %d\n", pPager, eLock)) } } @@ -41484,15 +41015,16 @@ assert( pPager->setMaster==0 ); assert( !pagerUseWal(pPager) ); if( !zMaster || pPager->journalMode==PAGER_JOURNALMODE_MEMORY - || !isOpen(pPager->jfd) + || pPager->journalMode==PAGER_JOURNALMODE_OFF ){ return SQLITE_OK; } pPager->setMaster = 1; + assert( isOpen(pPager->jfd) ); assert( pPager->journalHdr <= pPager->journalOff ); /* Calculate the length in bytes and the checksum of zMaster */ for(nMaster=0; zMaster[nMaster]; nMaster++){ cksum += zMaster[nMaster]; @@ -41542,11 +41074,11 @@ ** Find a page in the hash table given its page number. Return ** a pointer to the page or NULL if the requested page is not ** already in memory. */ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ - PgHdr *p = 0; /* Return value */ + PgHdr *p; /* Return value */ /* It is not possible for a call to PcacheFetch() with createFlag==0 to ** fail, since no attempt to allocate dynamic memory will be made. */ (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p); @@ -44534,59 +44066,47 @@ ** ** + SQLITE_DEFAULT_PAGE_SIZE, ** + The value returned by sqlite3OsSectorSize() ** + The largest page size that can be written atomically. */ - if( rc==SQLITE_OK ){ - int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); - if( !readOnly ){ - setSectorSize(pPager); - assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); - if( szPageDfltsectorSize ){ - if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ - szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; - }else{ - szPageDflt = (u32)pPager->sectorSize; - } - } + if( rc==SQLITE_OK && !readOnly ){ + setSectorSize(pPager); + assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); + if( szPageDfltsectorSize ){ + if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ + szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; + }else{ + szPageDflt = (u32)pPager->sectorSize; + } + } #ifdef SQLITE_ENABLE_ATOMIC_WRITE - { - int ii; - assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); - assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); - assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); - for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ - if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ - szPageDflt = ii; - } - } - } -#endif - } - pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0); - if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 - || sqlite3_uri_boolean(zFilename, "immutable", 0) ){ - vfsFlags |= SQLITE_OPEN_READONLY; - goto act_like_temp_file; - } + { + int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); + int ii; + assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); + assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); + assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); + for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ + if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ + szPageDflt = ii; + } + } + } +#endif } }else{ /* If a temporary file is requested, it is not opened immediately. ** In this case we accept the default page size and delay actually ** opening the file until the first call to OsWrite(). ** ** This branch is also run for an in-memory database. An in-memory ** database is the same as a temp-file that is never written out to ** disk and uses an in-memory rollback journal. - ** - ** This branch also runs for files marked as immutable. */ -act_like_temp_file: tempFile = 1; - pPager->eState = PAGER_READER; /* Pretend we already have a lock */ - pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE locking mode */ - pPager->noLock = 1; /* Do no locking */ + pPager->eState = PAGER_READER; + pPager->eLock = EXCLUSIVE_LOCK; readOnly = (vfsFlags&SQLITE_OPEN_READONLY); } /* The following call to PagerSetPagesize() serves to set the value of ** Pager.pageSize and to allocate the Pager.pTmpSpace buffer. @@ -44623,10 +44143,13 @@ /* pPager->stmtSize = 0; */ /* pPager->stmtJSize = 0; */ /* pPager->nPage = 0; */ pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; /* pPager->state = PAGER_UNLOCK; */ +#if 0 + assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) ); +#endif /* pPager->errMask = 0; */ pPager->tempFile = (u8)tempFile; assert( tempFile==PAGER_LOCKINGMODE_NORMAL || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE ); assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 ); @@ -44757,21 +44280,19 @@ */ rc = sqlite3OsCheckReservedLock(pPager->fd, &locked); if( rc==SQLITE_OK && !locked ){ Pgno nPage; /* Number of pages in database file */ + /* Check the size of the database file. If it consists of 0 pages, + ** then delete the journal file. See the header comment above for + ** the reasoning here. Delete the obsolete journal file under + ** a RESERVED lock to avoid race conditions and to avoid violating + ** [H33020]. + */ rc = pagerPagecount(pPager, &nPage); if( rc==SQLITE_OK ){ - /* If the database is zero pages in size, that means that either (1) the - ** journal is a remnant from a prior database with the same name where - ** the database file but not the journal was deleted, or (2) the initial - ** transaction that populates a new database is being rolled back. - ** In either case, the journal file can be deleted. However, take care - ** not to delete the journal file if it is already open due to - ** journal_mode=PERSIST. - */ - if( nPage==0 && !jrnlOpen ){ + if( nPage==0 ){ sqlite3BeginBenignMalloc(); if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){ sqlite3OsDelete(pVfs, pPager->zJournal, 0); if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } @@ -48399,11 +47920,11 @@ if( rc!=SQLITE_OK ){ walIndexClose(pRet, 0); sqlite3OsClose(pRet->pWalFd); sqlite3_free(pRet); }else{ - int iDC = sqlite3OsDeviceCharacteristics(pDbFd); + int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd); if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; } if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){ pRet->padToSectorBoundary = 0; } *ppWal = pRet; @@ -49770,11 +49291,11 @@ if( rc ) return rc; iOffset += iFirstAmt; iAmt -= iFirstAmt; pContent = (void*)(iFirstAmt + (char*)pContent); assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) ); - rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK); + rc = sqlite3OsSync(p->pFd, p->syncFlags); if( iAmt==0 || rc ) return rc; } rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset); return rc; } @@ -50704,34 +50225,32 @@ struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ +#ifndef SQLITE_OMIT_INCRBLOB Pgno *aOverflow; /* Cache of overflow page locations */ - CellInfo info; /* A parse of the cell we are pointing at */ - i64 nKey; /* Size of pKey, or last integer key */ - void *pKey; /* Saved key that was cursor last known position */ +#endif Pgno pgnoRoot; /* The root page of this tree */ - int nOvflAlloc; /* Allocated size of aOverflow[] array */ + sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */ + CellInfo info; /* A parse of the cell we are pointing at */ + i64 nKey; /* Size of pKey, or last integer key */ + void *pKey; /* Saved key that was cursor's last known position */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive */ - u8 curFlags; /* zero or more BTCF_* flags defined below */ + u8 wrFlag; /* True if writable */ + u8 atLast; /* Cursor pointing to the last entry */ + u8 validNKey; /* True if info.nKey is valid */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ +#ifndef SQLITE_OMIT_INCRBLOB + u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */ +#endif u8 hints; /* As configured by CursorSetHints() */ i16 iPage; /* Index of current page in apPage */ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ }; -/* -** Legal values for BtCursor.curFlags -*/ -#define BTCF_WriteFlag 0x01 /* True if a write cursor */ -#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */ -#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */ -#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ -#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ - /* ** Potential values for BtCursor.eState. ** ** CURSOR_INVALID: ** Cursor does not point to a valid entry. This can happen (for example) @@ -51598,15 +51117,20 @@ static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } #endif + +#ifndef SQLITE_OMIT_INCRBLOB /* -** Invalidate the overflow cache of the cursor passed as the first argument. -** on the shared btree structure pBt. +** Invalidate the overflow page-list cache for cursor pCur, if any. */ -#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl) +static void invalidateOverflowCache(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + sqlite3_free(pCur->aOverflow); + pCur->aOverflow = 0; +} /* ** Invalidate the overflow page-list cache for all cursors opened ** on the shared btree structure pBt. */ @@ -51616,11 +51140,10 @@ for(p=pBt->pCursor; p; p=p->pNext){ invalidateOverflowCache(p); } } -#ifndef SQLITE_OMIT_INCRBLOB /* ** This function is called before modifying the contents of a table ** to invalidate any incrblob cursors that are open on the ** row or one of the rows being modified. ** @@ -51639,18 +51162,20 @@ ){ BtCursor *p; BtShared *pBt = pBtree->pBt; assert( sqlite3BtreeHoldsMutex(pBtree) ); for(p=pBt->pCursor; p; p=p->pNext){ - if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){ + if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){ p->eState = CURSOR_INVALID; } } } #else - /* Stub function when INCRBLOB is omitted */ + /* Stub functions when INCRBLOB is omitted */ + #define invalidateOverflowCache(x) + #define invalidateAllOverflowCache(x) #define invalidateIncrblobCursors(x,y,z) #endif /* SQLITE_OMIT_INCRBLOB */ /* ** Set bit pgno of the BtShared.pHasContent bitvec. This is called @@ -51892,36 +51417,24 @@ ** Determine whether or not a cursor has moved from the position it ** was last placed at. Cursors can move when the row they are pointing ** at is deleted out from under them. ** ** This routine returns an error code if something goes wrong. The -** integer *pHasMoved is set as follows: -** -** 0: The cursor is unchanged -** 1: The cursor is still pointing at the same row, but the pointers -** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch() -** might now be invalid because of a balance() or other change to the -** b-tree. -** 2: The cursor is no longer pointing to the row. The row might have -** been deleted out from under the cursor. +** integer *pHasMoved is set to one if the cursor has moved and 0 if not. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){ int rc; - if( pCur->eState==CURSOR_VALID ){ - *pHasMoved = 0; - return SQLITE_OK; - } rc = restoreCursorPosition(pCur); if( rc ){ - *pHasMoved = 2; + *pHasMoved = 1; return rc; } if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){ - *pHasMoved = 2; - }else{ *pHasMoved = 1; + }else{ + *pHasMoved = 0; } return SQLITE_OK; } #ifndef SQLITE_OMIT_AUTOVACUUM @@ -52700,16 +52213,17 @@ assert( sqlite3_mutex_held(pBt->mutex) ); if( pBt->btsFlags & BTS_SECURE_DELETE ){ memset(&data[hdr], 0, pBt->usableSize - hdr); } data[hdr] = (char)flags; - first = hdr + ((flags&PTF_LEAF)==0 ? 12 : 8); + first = hdr + 8 + 4*((flags&PTF_LEAF)==0 ?1:0); memset(&data[hdr+1], 0, 4); data[hdr+7] = 0; put2byte(&data[hdr+5], pBt->usableSize); pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); + pPage->hdrOffset = hdr; pPage->cellOffset = first; pPage->aDataEnd = &data[pBt->usableSize]; pPage->aCellIdx = &data[first]; pPage->nOverflow = 0; assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); @@ -53319,11 +52833,10 @@ sqlite3PagerSetCachesize(pBt->pPager, mxPage); sqlite3BtreeLeave(p); return SQLITE_OK; } -#if SQLITE_MAX_MMAP_SIZE>0 /* ** Change the limit on the amount of the database file that may be ** memory mapped. */ SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ @@ -53332,11 +52845,10 @@ sqlite3BtreeEnter(p); sqlite3PagerSetMmapLimit(pBt->pPager, szMmap); sqlite3BtreeLeave(p); return SQLITE_OK; } -#endif /* SQLITE_MAX_MMAP_SIZE>0 */ /* ** Change the way data is synced to disk in order to increase or decrease ** how well the database resists damage due to OS crashes and power ** failures. Level 1 is the same as asynchronous (no syncs() occur and @@ -53709,12 +53221,11 @@ */ static int countValidCursors(BtShared *pBt, int wrOnly){ BtCursor *pCur; int r = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0) - && pCur->eState!=CURSOR_FAULT ) r++; + if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++; } return r; } #endif @@ -54785,18 +54296,18 @@ pCur->pgnoRoot = (Pgno)iTable; pCur->iPage = -1; pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; - assert( wrFlag==0 || wrFlag==BTCF_WriteFlag ); - pCur->curFlags = wrFlag; + pCur->wrFlag = (u8)wrFlag; pCur->pNext = pBt->pCursor; if( pCur->pNext ){ pCur->pNext->pPrev = pCur; } pBt->pCursor = pCur; pCur->eState = CURSOR_INVALID; + pCur->cachedRowid = 0; return SQLITE_OK; } SQLITE_PRIVATE int sqlite3BtreeCursor( Btree *p, /* The btree */ int iTable, /* Root page of table to open */ @@ -54832,10 +54343,40 @@ ** of run-time by skipping the initialization of those elements. */ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ memset(p, 0, offsetof(BtCursor, iPage)); } + +/* +** Set the cached rowid value of every cursor in the same database file +** as pCur and having the same root page number as pCur. The value is +** set to iRowid. +** +** Only positive rowid values are considered valid for this cache. +** The cache is initialized to zero, indicating an invalid cache. +** A btree will work fine with zero or negative rowids. We just cannot +** cache zero or negative rowids, which means tables that use zero or +** negative rowids might run a little slower. But in practice, zero +** or negative rowids are very uncommon so this should not be a problem. +*/ +SQLITE_PRIVATE void sqlite3BtreeSetCachedRowid(BtCursor *pCur, sqlite3_int64 iRowid){ + BtCursor *p; + for(p=pCur->pBt->pCursor; p; p=p->pNext){ + if( p->pgnoRoot==pCur->pgnoRoot ) p->cachedRowid = iRowid; + } + assert( pCur->cachedRowid==iRowid ); +} + +/* +** Return the cached rowid for the given cursor. A negative or zero +** return value indicates that the rowid cache is invalid and should be +** ignored. If the rowid cache has never before been set, then a +** zero is returned. +*/ +SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor *pCur){ + return pCur->cachedRowid; +} /* ** Close a cursor. The read lock on the database file is released ** when the last cursor is closed. */ @@ -54856,11 +54397,11 @@ } for(i=0; i<=pCur->iPage; i++){ releasePage(pCur->apPage[i]); } unlockBtreeIfUnused(pBt); - sqlite3DbFree(pBtree->db, pCur->aOverflow); + invalidateOverflowCache(pCur); /* sqlite3_free(pCur); */ sqlite3BtreeLeave(pBtree); } return SQLITE_OK; } @@ -54895,22 +54436,22 @@ /* Use a real function in MSVC to work around bugs in that compiler. */ static void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ int iPage = pCur->iPage; btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); - pCur->curFlags |= BTCF_ValidNKey; + pCur->validNKey = 1; }else{ assertCellInfo(pCur); } } #else /* if not _MSC_VER */ /* Use a macro in all other compilers so that the function is inlined */ #define getCellInfo(pCur) \ if( pCur->info.nSize==0 ){ \ int iPage = pCur->iPage; \ - btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ - pCur->curFlags |= BTCF_ValidNKey; \ + btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ + pCur->validNKey = 1; \ }else{ \ assertCellInfo(pCur); \ } #endif /* _MSC_VER */ @@ -55077,28 +54618,26 @@ return SQLITE_OK; } /* ** This function is used to read or overwrite payload information -** for the entry that the pCur cursor is pointing to. The eOp -** argument is interpreted as follows: -** -** 0: The operation is a read. Populate the overflow cache. -** 1: The operation is a write. Populate the overflow cache. -** 2: The operation is a read. Do not populate the overflow cache. +** for the entry that the pCur cursor is pointing to. If the eOp +** parameter is 0, this is a read operation (data copied into +** buffer pBuf). If it is non-zero, a write (data copied from +** buffer pBuf). ** ** A total of "amt" bytes are read or written beginning at "offset". ** Data is read to or from the buffer pBuf. ** ** The content being read or written might appear on the main page ** or be scattered out on multiple overflow pages. ** -** If the current cursor entry uses one or more overflow pages and the -** eOp argument is not 2, this function may allocate space for and lazily -** popluates the overflow page-list cache array (BtCursor.aOverflow). -** Subsequent calls use this cache to make seeking to the supplied offset -** more efficient. +** If the BtCursor.isIncrblobHandle flag is set, and the current +** cursor entry uses one or more overflow pages, this function +** allocates space for and lazily popluates the overflow page-list +** cache array (BtCursor.aOverflow). Subsequent calls use this +** cache to make seeking to the supplied offset more efficient. ** ** Once an overflow page-list cache has been allocated, it may be ** invalidated if some other cursor writes to the same table, or if ** the cursor is moved to a different row. Additionally, in auto-vacuum ** mode, the following events may invalidate an overflow page-list cache. @@ -55118,26 +54657,19 @@ int rc = SQLITE_OK; u32 nKey; int iIdx = 0; MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ -#ifdef SQLITE_DIRECT_OVERFLOW_READ - int bEnd; /* True if reading to end of data */ -#endif assert( pPage ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->aiIdx[pCur->iPage]nCell ); assert( cursorHoldsMutex(pCur) ); - assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ getCellInfo(pCur); aPayload = pCur->info.pCell + pCur->info.nHeader; nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey); -#ifdef SQLITE_DIRECT_OVERFLOW_READ - bEnd = (offset+amt==nKey+pCur->info.nData); -#endif if( NEVER(offset+amt > nKey+pCur->info.nData) || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){ /* Trying to read or write past the end of the data is an error */ @@ -55148,11 +54680,11 @@ if( offsetinfo.nLocal ){ int a = amt; if( a+offset>pCur->info.nLocal ){ a = pCur->info.nLocal - offset; } - rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage); + rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); offset = 0; pBuf += a; amt -= a; }else{ offset -= pCur->info.nLocal; @@ -55162,72 +54694,62 @@ const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */ Pgno nextPage; nextPage = get4byte(&aPayload[pCur->info.nLocal]); - /* If the BtCursor.aOverflow[] has not been allocated, allocate it now. - ** Except, do not allocate aOverflow[] for eOp==2. - ** - ** The aOverflow[] array is sized at one entry for each overflow page - ** in the overflow chain. The page number of the first overflow page is - ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array - ** means "not yet known" (the cache is lazily populated). +#ifndef SQLITE_OMIT_INCRBLOB + /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[] + ** has not been allocated, allocate it now. The array is sized at + ** one entry for each overflow page in the overflow chain. The + ** page number of the first overflow page is stored in aOverflow[0], + ** etc. A value of 0 in the aOverflow[] array means "not yet known" + ** (the cache is lazily populated). */ - if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){ + if( pCur->isIncrblobHandle && !pCur->aOverflow ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; - if( nOvfl>pCur->nOvflAlloc ){ - Pgno *aNew = (Pgno*)sqlite3DbRealloc( - pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno) - ); - if( aNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - pCur->nOvflAlloc = nOvfl*2; - pCur->aOverflow = aNew; - } - } - if( rc==SQLITE_OK ){ - memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); - pCur->curFlags |= BTCF_ValidOvfl; + pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); + /* nOvfl is always positive. If it were zero, fetchPayload would have + ** been used instead of this routine. */ + if( ALWAYS(nOvfl) && !pCur->aOverflow ){ + rc = SQLITE_NOMEM; } } /* If the overflow page-list cache has been allocated and the ** entry for the first required overflow page is valid, skip ** directly to it. */ - if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){ + if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){ iIdx = (offset/ovflSize); nextPage = pCur->aOverflow[iIdx]; offset = (offset%ovflSize); } +#endif for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){ +#ifndef SQLITE_OMIT_INCRBLOB /* If required, populate the overflow page-list cache. */ - if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){ + if( pCur->aOverflow ){ assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage); pCur->aOverflow[iIdx] = nextPage; } +#endif if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page ** number for the next page in the overflow chain. The page ** data is not required. So first try to lookup the overflow ** page-list cache, if any, then fall back to the getOverflowPage() ** function. - ** - ** Note that the aOverflow[] array must be allocated because eOp!=2 - ** here. If eOp==2, then offset==0 and this branch is never taken. */ - assert( eOp!=2 ); - assert( pCur->curFlags & BTCF_ValidOvfl ); - if( pCur->aOverflow[iIdx+1] ){ +#ifndef SQLITE_OMIT_INCRBLOB + if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){ nextPage = pCur->aOverflow[iIdx+1]; - }else{ + } else +#endif rc = getOverflowPage(pBt, nextPage, 0, &nextPage); - } offset -= ovflSize; }else{ /* Need to read this page properly. It contains some of the ** range of data that is being read (eOp==0) or written (eOp!=0). */ @@ -55245,19 +54767,17 @@ ** 1) this is a read operation, and ** 2) data is required from the start of this overflow page, and ** 3) the database is file-backed, and ** 4) there is no open write-transaction, and ** 5) the database is not a WAL database, - ** 6) all data from the page is being read. ** ** then data can be read directly from the database file into the ** output buffer, bypassing the page-cache altogether. This speeds ** up loading large records that span many overflow pages. */ - if( (eOp&0x01)==0 /* (1) */ + if( eOp==0 /* (1) */ && offset==0 /* (2) */ - && (bEnd || a==ovflSize) /* (6) */ && pBt->inTransaction==TRANS_READ /* (4) */ && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */ && pBt->pPage1->aData[19]==0x01 /* (5) */ ){ u8 aSave[4]; @@ -55270,16 +54790,16 @@ #endif { DbPage *pDbPage; rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage, - ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0) + (eOp==0 ? PAGER_GET_READONLY : 0) ); if( rc==SQLITE_OK ){ aPayload = sqlite3PagerGetData(pDbPage); nextPage = get4byte(aPayload); - rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage); + rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); sqlite3PagerUnref(pDbPage); offset = 0; } } amt -= a; @@ -55369,11 +54889,14 @@ assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorHoldsMutex(pCur) ); assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); - assert( pCur->info.nSize>0 ); + if( pCur->info.nSize==0 ){ + btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage], + &pCur->info); + } *pAmt = pCur->info.nLocal; return (void*)(pCur->info.pCell + pCur->info.nHeader); } @@ -55420,18 +54943,18 @@ assert( pCur->iPage>=0 ); if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, newPgno, &pNewPage, - (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0); + pCur->wrFlag==0 ? PAGER_GET_READONLY : 0); if( rc ) return rc; pCur->apPage[i+1] = pNewPage; pCur->aiIdx[i+1] = 0; pCur->iPage++; pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->validNKey = 0; if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){ return SQLITE_CORRUPT_BKPT; } return SQLITE_OK; } @@ -55485,11 +55008,11 @@ testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); releasePage(pCur->apPage[pCur->iPage]); pCur->iPage--; pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->validNKey = 0; } /* ** Move the cursor to point to the root page of its b-tree structure. ** @@ -55532,11 +55055,11 @@ }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; return SQLITE_OK; }else{ rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0], - (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0); + pCur->wrFlag==0 ? PAGER_GET_READONLY : 0); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; @@ -55559,11 +55082,12 @@ return SQLITE_CORRUPT_BKPT; } pCur->aiIdx[0] = 0; pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->atLast = 0; + pCur->validNKey = 0; if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; }else if( !pRoot->leaf ){ Pgno subpage; @@ -55622,11 +55146,11 @@ rc = moveToChild(pCur, pgno); } if( rc==SQLITE_OK ){ pCur->aiIdx[pCur->iPage] = pPage->nCell-1; pCur->info.nSize = 0; - pCur->curFlags &= ~BTCF_ValidNKey; + pCur->validNKey = 0; } return rc; } /* Move the cursor to the first entry in the table. Return SQLITE_OK @@ -55661,11 +55185,11 @@ assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ - if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ + if( CURSOR_VALID==pCur->eState && pCur->atLast ){ #ifdef SQLITE_DEBUG /* This block serves to assert() that the cursor really does point ** to the last entry in the b-tree. */ int ii; for(ii=0; iiiPage; ii++){ @@ -55684,16 +55208,11 @@ *pRes = 1; }else{ assert( pCur->eState==CURSOR_VALID ); *pRes = 0; rc = moveToRightmost(pCur); - if( rc==SQLITE_OK ){ - pCur->curFlags |= BTCF_AtLast; - }else{ - pCur->curFlags &= ~BTCF_AtLast; - } - + pCur->atLast = rc==SQLITE_OK ?1:0; } } return rc; } @@ -55731,43 +55250,31 @@ i64 intKey, /* The table key */ int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; - RecordCompare xRecordCompare; assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ - if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 + if( pCur->eState==CURSOR_VALID && pCur->validNKey && pCur->apPage[0]->intKey ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } - if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKeyatLast && pCur->info.nKeyisCorrupt = 0; - assert( pIdxKey->default_rc==1 - || pIdxKey->default_rc==0 - || pIdxKey->default_rc==-1 - ); - }else{ - xRecordCompare = 0; /* All keys are integers */ - } - rc = moveToRoot(pCur); if( rc ){ return rc; } assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] ); @@ -55796,11 +55303,11 @@ lwr = 0; upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ pCur->aiIdx[pCur->iPage] = (u16)idx; - if( xRecordCompare==0 ){ + if( pPage->intKey ){ for(;;){ i64 nCellKey; pCell = findCell(pPage, idx) + pPage->childPtrSize; if( pPage->hasData ){ while( 0x80 <= *(pCell++) ){ @@ -55814,11 +55321,11 @@ }else if( nCellKey>intKey ){ upr = idx-1; if( lwr>upr ){ c = +1; break; } }else{ assert( nCellKey==intKey ); - pCur->curFlags |= BTCF_ValidNKey; + pCur->validNKey = 1; pCur->info.nKey = nCellKey; pCur->aiIdx[pCur->iPage] = (u16)idx; if( !pPage->leaf ){ lwr = idx; goto moveto_next_layer; @@ -55848,18 +55355,18 @@ if( nCell<=pPage->max1bytePayload ){ /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey, 0); + c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey, 0); + c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated ** and accessPayload() used to retrieve the record into the ** buffer before VdbeRecordCompare() can be called. */ @@ -55871,29 +55378,27 @@ if( pCellKey==0 ){ rc = SQLITE_NOMEM; goto moveto_finish; } pCur->aiIdx[pCur->iPage] = (u16)idx; - rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2); + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); if( rc ){ sqlite3_free(pCellKey); goto moveto_finish; } - c = xRecordCompare(nCell, pCellKey, pIdxKey, 0); + c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } - assert( pIdxKey->isCorrupt==0 || c==0 ); if( c<0 ){ lwr = idx+1; }else if( c>0 ){ upr = idx-1; }else{ assert( c==0 ); *pRes = 0; rc = SQLITE_OK; pCur->aiIdx[pCur->iPage] = (u16)idx; - if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT; goto moveto_finish; } if( lwr>upr ) break; assert( lwr+upr>=0 ); idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ @@ -55918,11 +55423,11 @@ rc = moveToChild(pCur, chldPg); if( rc ) break; } moveto_finish: pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->validNKey = 0; return rc; } /* @@ -55943,31 +55448,20 @@ /* ** Advance the cursor to the next entry in the database. If ** successful then set *pRes=0. If the cursor ** was already pointing to the last entry in the database before ** this routine was called, then set *pRes=1. -** -** The calling function will set *pRes to 0 or 1. The initial *pRes value -** will be 1 if the cursor being stepped corresponds to an SQL index and -** if this routine could have been skipped if that SQL index had been -** a unique index. Otherwise the caller will have set *pRes to zero. -** Zero is the common case. The btree implementation is free to use the -** initial *pRes value as a hint to improve performance, but the current -** SQLite btree implementation does not. (Note that the comdb2 btree -** implementation does use this hint, however.) */ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ int rc; int idx; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); if( pCur->eState!=CURSOR_VALID ){ - invalidateOverflowCache(pCur); rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ *pRes = 0; return rc; } @@ -55997,11 +55491,11 @@ ** only happen if the database is corrupt in such a way as to link the ** page into more than one b-tree structure. */ testcase( idx>pPage->nCell ); pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->validNKey = 0; if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); if( rc ){ *pRes = 0; @@ -56040,29 +55534,19 @@ /* ** Step the cursor to the back to the previous entry in the database. If ** successful then set *pRes=0. If the cursor ** was already pointing to the first entry in the database before ** this routine was called, then set *pRes=1. -** -** The calling function will set *pRes to 0 or 1. The initial *pRes value -** will be 1 if the cursor being stepped corresponds to an SQL index and -** if this routine could have been skipped if that SQL index had been -** a unique index. Otherwise the caller will have set *pRes to zero. -** Zero is the common case. The btree implementation is free to use the -** initial *pRes value as a hint to improve performance, but the current -** SQLite btree implementation does not. (Note that the comdb2 btree -** implementation does use this hint, however.) */ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ int rc; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl); + pCur->atLast = 0; if( pCur->eState!=CURSOR_VALID ){ if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){ rc = btreeRestoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ *pRes = 0; @@ -56103,11 +55587,11 @@ return SQLITE_OK; } moveToParent(pCur); } pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->validNKey = 0; pCur->aiIdx[pCur->iPage]--; pPage = pCur->apPage[pCur->iPage]; if( pPage->intKey && !pPage->leaf ){ rc = sqlite3BtreePrevious(pCur, pRes); @@ -58128,11 +57612,11 @@ assert( pCur->skipNext!=SQLITE_OK ); return pCur->skipNext; } assert( cursorHoldsMutex(pCur) ); - assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE + assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE && (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); /* Assert that the caller has been consistent. If this cursor was opened ** expecting an index b-tree, then the caller should be inserting blob @@ -58153,21 +57637,15 @@ ** not to clear the cursor here. */ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; + /* If this is an insert into a table b-tree, invalidate any incrblob + ** cursors open on the row being replaced (assuming this is a replace + ** operation - if it is not, the following is a no-op). */ if( pCur->pKeyInfo==0 ){ - /* If this is an insert into a table b-tree, invalidate any incrblob - ** cursors open on the row being replaced */ invalidateIncrblobCursors(p, nKey, 0); - - /* If the cursor is currently on the last row and we are appending a - ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto() - ** call */ - if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){ - loc = -1; - } } if( !loc ){ rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc); if( rc ) return rc; @@ -58214,11 +57692,11 @@ insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move - ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey + ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey ** variables. ** ** Previous versions of SQLite called moveToRoot() to move the cursor ** back to the root page as balance() used to invalidate the contents ** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that, @@ -58233,12 +57711,12 @@ ** entry in the table, and the next row inserted has an integer key ** larger than the largest existing key, it is possible to insert the ** row without seeking the cursor. This can be a big performance boost. */ pCur->info.nSize = 0; + pCur->validNKey = 0; if( rc==SQLITE_OK && pPage->nOverflow ){ - pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() ** fails. Internal data structure corruption will result otherwise. ** Also, set the cursor state to invalid. This stops saveCursorPosition() @@ -58266,11 +57744,11 @@ int iCellDepth; /* Depth of node containing pCell */ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); - assert( pCur->curFlags & BTCF_WriteFlag ); + assert( pCur->wrFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell) || NEVER(pCur->eState!=CURSOR_VALID) @@ -58289,11 +57767,11 @@ ** from the internal node. The 'previous' entry is used for this instead ** of the 'next' entry, as the previous entry is always a part of the ** sub-tree headed by the child page of the cell being deleted. This makes ** balancing the tree following the delete operation easier. */ if( !pPage->leaf ){ - int notUsed = 0; + int notUsed; rc = sqlite3BtreePrevious(pCur, ¬Used); if( rc ) return rc; } /* Save the positions of any other cursors open on this table before @@ -58611,19 +58089,10 @@ } sqlite3BtreeLeave(p); return rc; } -/* -** Delete all information from the single table that pCur is open on. -** -** This routine only work for pCur on an ephemeral table. -*/ -SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){ - return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0); -} - /* ** Erase all information in a table and add the root of the table to ** the freelist. Except, the root of the principle table (the one on ** page 1) is never added to the freelist. ** @@ -59579,11 +59048,11 @@ */ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ int rc; assert( cursorHoldsMutex(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); - assert( pCsr->curFlags & BTCF_Incrblob ); + assert( pCsr->isIncrblobHandle ); rc = restoreCursorPosition(pCsr); if( rc!=SQLITE_OK ){ return rc; } @@ -59608,11 +59077,11 @@ ** (b) there is a read/write transaction open, ** (c) the connection holds a write-lock on the table (if required), ** (d) there are no conflicting read-locks, and ** (e) the cursor points at a valid row of an intKey table. */ - if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){ + if( !pCsr->wrFlag ){ return SQLITE_READONLY; } assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0 && pCsr->pBt->inTransaction==TRANS_WRITE ); assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); @@ -59621,14 +59090,24 @@ return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); } /* -** Mark this cursor as an incremental blob cursor. +** Set a flag on this cursor to cache the locations of pages from the +** overflow list for the current row. This is used by cursors opened +** for incremental blob IO only. +** +** This function sets a flag only. The actual page location cache +** (stored in BtCursor.aOverflow[]) is allocated and used by function +** accessPayload() (the worker function for sqlite3BtreeData() and +** sqlite3BtreePutData()). */ -SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){ - pCur->curFlags |= BTCF_Incrblob; +SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + invalidateOverflowCache(pCur); + pCur->isIncrblobHandle = 1; } #endif /* ** Set both the "read version" (single byte at byte offset 18) and @@ -59673,17 +59152,10 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){ assert( mask==BTREE_BULKLOAD || mask==0 ); pCsr->hints = mask; } -/* -** Return true if the given Btree is read-only. -*/ -SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){ - return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; -} - /************** End of btree.c ***********************************************/ /************** Begin file backup.c ******************************************/ /* ** 2009 January 28 ** @@ -60448,46 +59920,10 @@ ** This file contains code use to manipulate "Mem" structure. A "Mem" ** stores a single value in the VDBE. Mem is an opaque structure visible ** only within the VDBE. Interface routines refer to a Mem using the ** name sqlite_value */ - -#ifdef SQLITE_DEBUG -/* -** Check invariants on a Mem object. -** -** This routine is intended for use inside of assert() statements, like -** this: assert( sqlite3VdbeCheckMemInvariants(pMem) ); -*/ -SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ - /* The MEM_Dyn bit is set if and only if Mem.xDel is a non-NULL destructor - ** function for Mem.z - */ - assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); - assert( (p->flags & MEM_Dyn)!=0 || p->xDel==0 ); - - /* If p holds a string or blob, the Mem.z must point to exactly - ** one of the following: - ** - ** (1) Memory in Mem.zMalloc and managed by the Mem object - ** (2) Memory to be freed using Mem.xDel - ** (3) An ephermal string or blob - ** (4) A static string or blob - */ - if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){ - assert( - ((p->z==p->zMalloc)? 1 : 0) + - ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + - ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + - ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 - ); - } - - return 1; -} -#endif - /* ** If pMem is an object with a valid string representation, this routine ** ensures the internal encoding for the string representation is ** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE. @@ -60534,11 +59970,16 @@ ** pMem->z into the new allocation. pMem must be either a string or ** blob if bPreserve is true. If bPreserve is false, any prior content ** in pMem->z is discarded. */ SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ - assert( sqlite3VdbeCheckMemInvariants(pMem) ); + assert( 1 >= + ((pMem->zMalloc && pMem->zMalloc==pMem->z) ? 1 : 0) + + (((pMem->flags&MEM_Dyn)&&pMem->xDel) ? 1 : 0) + + ((pMem->flags&MEM_Ephem) ? 1 : 0) + + ((pMem->flags&MEM_Static) ? 1 : 0) + ); assert( (pMem->flags&MEM_RowSet)==0 ); /* If the bPreserve flag is set to true, then the memory cell must already ** contain a valid string or blob value. */ assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) ); @@ -60552,27 +59993,26 @@ }else{ sqlite3DbFree(pMem->db, pMem->zMalloc); pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); } if( pMem->zMalloc==0 ){ - VdbeMemRelease(pMem); - pMem->z = 0; + sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Null; return SQLITE_NOMEM; } } if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){ memcpy(pMem->zMalloc, pMem->z, pMem->n); } - if( (pMem->flags&MEM_Dyn)!=0 ){ - assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC ); + if( (pMem->flags&MEM_Dyn)!=0 && pMem->xDel ){ + assert( pMem->xDel!=SQLITE_DYNAMIC ); pMem->xDel((void *)(pMem->z)); } pMem->z = pMem->zMalloc; - pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static); + pMem->flags &= ~(MEM_Ephem|MEM_Static); pMem->xDel = 0; return SQLITE_OK; } /* @@ -60737,13 +60177,13 @@ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); sqlite3VdbeMemRelease(p); - }else if( p->flags&MEM_Dyn ){ + }else if( p->flags&MEM_Dyn && p->xDel ){ assert( (p->flags&MEM_RowSet)==0 ); - assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); + assert( p->xDel!=SQLITE_DYNAMIC ); p->xDel((void *)p->z); p->xDel = 0; }else if( p->flags&MEM_RowSet ){ sqlite3RowSetClear(p->u.pRowSet); }else if( p->flags&MEM_Frame ){ @@ -60752,14 +60192,13 @@ } /* ** Release any memory held by the Mem. This may leave the Mem in an ** inconsistent state, for example with (Mem.z==0) and -** (Mem.flags==MEM_Str). +** (Mem.type==SQLITE_TEXT). */ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){ - assert( sqlite3VdbeCheckMemInvariants(p) ); VdbeMemRelease(p); if( p->zMalloc ){ sqlite3DbFree(p->db, p->zMalloc); p->zMalloc = 0; } @@ -60944,10 +60383,11 @@ } if( pMem->flags & MEM_RowSet ){ sqlite3RowSetClear(pMem->u.pRowSet); } MemSetTypeFlag(pMem, MEM_Null); + pMem->type = SQLITE_NULL; } SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){ sqlite3VdbeMemSetNull((Mem*)p); } @@ -60956,10 +60396,11 @@ ** n containing all zeros. */ SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Blob|MEM_Zero; + pMem->type = SQLITE_BLOB; pMem->n = 0; if( n<0 ) n = 0; pMem->u.nZero = n; pMem->enc = SQLITE_UTF8; @@ -60978,10 +60419,11 @@ */ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ sqlite3VdbeMemRelease(pMem); pMem->u.i = val; pMem->flags = MEM_Int; + pMem->type = SQLITE_INTEGER; } #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Delete any previous value and set the value stored in *pMem to val, @@ -60992,10 +60434,11 @@ sqlite3VdbeMemSetNull(pMem); }else{ sqlite3VdbeMemRelease(pMem); pMem->r = val; pMem->flags = MEM_Real; + pMem->type = SQLITE_FLOAT; } } #endif /* @@ -61047,11 +60490,11 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ int i; Mem *pX; for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){ if( pX->pScopyFrom==pMem ){ - pX->flags |= MEM_Undefined; + pX->flags |= MEM_Invalid; pX->pScopyFrom = 0; } } pMem->pScopyFrom = 0; } @@ -61089,11 +60532,10 @@ assert( (pFrom->flags & MEM_RowSet)==0 ); VdbeMemRelease(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; - pTo->xDel = 0; if( pTo->flags&(MEM_Str|MEM_Blob) ){ if( 0==(pFrom->flags&MEM_Static) ){ pTo->flags |= MEM_Ephem; rc = sqlite3VdbeMemMakeWriteable(pTo); @@ -61200,10 +60642,11 @@ } pMem->n = nByte; pMem->flags = flags; pMem->enc = (enc==0 ? SQLITE_UTF8 : enc); + pMem->type = (enc==0 ? SQLITE_BLOB : SQLITE_TEXT); #ifndef SQLITE_OMIT_UTF16 if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ return SQLITE_NOMEM; } @@ -61213,10 +60656,123 @@ return SQLITE_TOOBIG; } return SQLITE_OK; } + +/* +** Compare the values contained by the two memory cells, returning +** negative, zero or positive if pMem1 is less than, equal to, or greater +** than pMem2. Sorting order is NULL's first, followed by numbers (integers +** and reals) sorted numerically, followed by text ordered by the collating +** sequence pColl and finally blob's ordered by memcmp(). +** +** Two NULL values are considered equal by this function. +*/ +SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ + int rc; + int f1, f2; + int combined_flags; + + f1 = pMem1->flags; + f2 = pMem2->flags; + combined_flags = f1|f2; + assert( (combined_flags & MEM_RowSet)==0 ); + + /* If one value is NULL, it is less than the other. If both values + ** are NULL, return 0. + */ + if( combined_flags&MEM_Null ){ + return (f2&MEM_Null) - (f1&MEM_Null); + } + + /* If one value is a number and the other is not, the number is less. + ** If both are numbers, compare as reals if one is a real, or as integers + ** if both values are integers. + */ + if( combined_flags&(MEM_Int|MEM_Real) ){ + double r1, r2; + if( (f1 & f2 & MEM_Int)!=0 ){ + if( pMem1->u.i < pMem2->u.i ) return -1; + if( pMem1->u.i > pMem2->u.i ) return 1; + return 0; + } + if( (f1&MEM_Real)!=0 ){ + r1 = pMem1->r; + }else if( (f1&MEM_Int)!=0 ){ + r1 = (double)pMem1->u.i; + }else{ + return 1; + } + if( (f2&MEM_Real)!=0 ){ + r2 = pMem2->r; + }else if( (f2&MEM_Int)!=0 ){ + r2 = (double)pMem2->u.i; + }else{ + return -1; + } + if( r1r2 ) return 1; + return 0; + } + + /* If one value is a string and the other is a blob, the string is less. + ** If both are strings, compare using the collating functions. + */ + if( combined_flags&MEM_Str ){ + if( (f1 & MEM_Str)==0 ){ + return 1; + } + if( (f2 & MEM_Str)==0 ){ + return -1; + } + + assert( pMem1->enc==pMem2->enc ); + assert( pMem1->enc==SQLITE_UTF8 || + pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); + + /* The collation sequence must be defined at this point, even if + ** the user deletes the collation sequence after the vdbe program is + ** compiled (this was not always the case). + */ + assert( !pColl || pColl->xCmp ); + + if( pColl ){ + if( pMem1->enc==pColl->enc ){ + /* The strings are already in the correct encoding. Call the + ** comparison function directly */ + return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); + }else{ + const void *v1, *v2; + int n1, n2; + Mem c1; + Mem c2; + memset(&c1, 0, sizeof(c1)); + memset(&c2, 0, sizeof(c2)); + sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); + sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); + v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); + n1 = v1==0 ? 0 : c1.n; + v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); + n2 = v2==0 ? 0 : c2.n; + rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); + sqlite3VdbeMemRelease(&c1); + sqlite3VdbeMemRelease(&c2); + return rc; + } + } + /* If a NULL pointer was passed as the collate function, fall through + ** to the blob case and use memcmp(). */ + } + + /* Both values must be blobs. Compare using memcmp(). */ + rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); + if( rc==0 ){ + rc = pMem1->n - pMem2->n; + } + return rc; +} /* ** Move data out of a btree key or data field and into a Mem structure. ** The data or key is taken from the entry that pCur is currently pointing ** to. offset and amt determine what portion of the data or key to retrieve. @@ -61254,26 +60810,26 @@ if( offset+amt<=available ){ sqlite3VdbeMemRelease(pMem); pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; - pMem->n = (int)amt; }else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){ + pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term; + pMem->enc = 0; + pMem->type = SQLITE_BLOB; if( key ){ rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z); }else{ rc = sqlite3BtreeData(pCur, offset, amt, pMem->z); } - if( rc==SQLITE_OK ){ - pMem->z[amt] = 0; - pMem->z[amt+1] = 0; - pMem->flags = MEM_Blob|MEM_Term; - pMem->n = (int)amt; - }else{ + pMem->z[amt] = 0; + pMem->z[amt+1] = 0; + if( rc!=SQLITE_OK ){ sqlite3VdbeMemRelease(pMem); } } + pMem->n = (int)amt; return rc; } /* This function is only available internally, it is not part of the @@ -61327,10 +60883,11 @@ */ SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *db){ Mem *p = sqlite3DbMallocZero(db, sizeof(*p)); if( p ){ p->flags = MEM_Null; + p->type = SQLITE_NULL; p->db = db; } return p; } @@ -61372,13 +60929,15 @@ if( pRec ){ pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx); if( pRec->pKeyInfo ){ assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol ); assert( pRec->pKeyInfo->enc==ENC(db) ); + pRec->flags = UNPACKED_PREFIX_MATCH; pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord))); for(i=0; iaMem[i].flags = MEM_Null; + pRec->aMem[i].type = SQLITE_NULL; pRec->aMem[i].db = db; } }else{ sqlite3DbFree(db, pRec); pRec = 0; @@ -61447,10 +61006,11 @@ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt); }else{ zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); if( zVal==0 ) goto no_mem; sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); + if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT; } if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){ sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); @@ -61464,13 +61024,13 @@ if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) && pVal!=0 ){ sqlite3VdbeMemNumerify(pVal); if( pVal->u.i==SMALLEST_INT64 ){ - pVal->flags &= ~MEM_Int; + pVal->flags &= MEM_Int; pVal->flags |= MEM_Real; - pVal->r = (double)SMALLEST_INT64; + pVal->r = (double)LARGEST_INT64; }else{ pVal->u.i = -pVal->u.i; } pVal->r = -pVal->r; sqlite3ValueApplyAffinity(pVal, affinity, enc); @@ -61492,10 +61052,13 @@ sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2, 0, SQLITE_DYNAMIC); } #endif + if( pVal ){ + sqlite3VdbeMemStoreType(pVal); + } *ppVal = pVal; return rc; no_mem: db->mallocFailed = 1; @@ -61655,10 +61218,11 @@ rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); if( rc==SQLITE_OK ){ sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); } pVal->db = pParse->db; + sqlite3VdbeMemStoreType((Mem*)pVal); } } }else{ rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc); } @@ -61900,13 +61464,10 @@ #endif #ifdef VDBE_PROFILE pOp->cycles = 0; pOp->cnt = 0; #endif -#ifdef SQLITE_VDBE_COVERAGE - pOp->iSrcLine = 0; -#endif return i; } SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){ return sqlite3VdbeAddOp3(p, op, 0, 0, 0); } @@ -62002,11 +61563,11 @@ SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ Parse *p = v->pParse; int j = -1-x; assert( v->magic==VDBE_MAGIC_INIT ); assert( jnLabel ); - if( ALWAYS(j>=0) && p->aLabel ){ + if( j>=0 && p->aLabel ){ p->aLabel[j] = v->nOp; } p->iFixedOp = v->nOp - 1; } @@ -62264,11 +61825,11 @@ /* ** Add a whole list of operations to the operation stack. Return the ** address of the first operation added. */ -SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ +SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ int addr; assert( p->magic==VDBE_MAGIC_INIT ); if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p) ){ return 0; } @@ -62292,15 +61853,10 @@ pOut->p4.p = 0; pOut->p5 = 0; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS pOut->zComment = 0; #endif -#ifdef SQLITE_VDBE_COVERAGE - pOut->iSrcLine = iLineno+i; -#else - (void)iLineno; -#endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); } #endif @@ -62509,13 +62065,11 @@ assert( addrnOp ); if( addr<0 ){ addr = p->nOp - 1; } pOp = &p->aOp[addr]; - assert( pOp->p4type==P4_NOTUSED - || pOp->p4type==P4_INT32 - || pOp->p4type==P4_KEYINFO ); + assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 ); freeP4(db, pOp->p4type, pOp->p4.p); pOp->p4.p = 0; if( n==P4_INT32 ){ /* Note: this cast is safe, because the origin data point was an int ** that was cast to a (const char *). */ @@ -62587,19 +62141,10 @@ va_end(ap); } } #endif /* NDEBUG */ -#ifdef SQLITE_VDBE_COVERAGE -/* -** Set the value if the iSrcLine field for the previously coded instruction. -*/ -SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){ - sqlite3VdbeGetOp(v,-1)->iSrcLine = iLine; -} -#endif /* SQLITE_VDBE_COVERAGE */ - /* ** Return the opcode for a given address. If the address is -1, then ** return the most recently inserted opcode. ** ** If a memory allocation error has occurred prior to the calling of this @@ -62608,17 +62153,28 @@ ** The return of a dummy opcode allows the call to continue functioning ** after a OOM fault without having to check to see if the return from ** this routine is a valid pointer. But because the dummy.opcode is 0, ** dummy will never be written to. This is verified by code inspection and ** by running with Valgrind. +** +** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called +** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE, +** an OP_Trace instruction is always inserted by sqlite3VdbeGet() as soon as +** a new VDBE is created. So we are free to set addr to p->nOp-1 without +** having to double-check to make sure that the result is non-negative. But +** if SQLITE_OMIT_TRACE is defined, the OP_Trace is omitted and we do need to +** check the value of p->nOp-1 before continuing. */ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ /* C89 specifies that the constant "dummy" will be initialized to all ** zeros, which is correct. MSVC generates a warning, nevertheless. */ static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */ assert( p->magic==VDBE_MAGIC_INIT ); if( addr<0 ){ +#ifdef SQLITE_OMIT_TRACE + if( p->nOp==0 ) return (VdbeOp*)&dummy; +#endif addr = p->nOp - 1; } assert( (addr>=0 && addrnOp) || p->db->mallocFailed ); if( p->db->mallocFailed ){ return (VdbeOp*)&dummy; @@ -62919,11 +62475,11 @@ if( pOut==0 ) pOut = stdout; zP4 = displayP4(pOp, zPtr, sizeof(zPtr)); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS displayComment(pOp, zP4, zCom, sizeof(zCom)); #else - zCom[0] = 0; + zCom[0] = 0 #endif /* NB: The sqlite3OpcodeName() function is implemented by code created ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the ** information from the vdbe.c source text */ fprintf(pOut, zFormat1, pc, @@ -62948,11 +62504,10 @@ } return; } for(pEnd=&p[N]; pflags & MEM_Agg ); - testcase( p->flags & MEM_Dyn ); - testcase( p->flags & MEM_Frame ); - testcase( p->flags & MEM_RowSet ); if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ sqlite3VdbeMemRelease(p); }else if( p->zMalloc ){ sqlite3DbFree(db, p->zMalloc); p->zMalloc = 0; } - p->flags = MEM_Undefined; + p->flags = MEM_Invalid; } db->mallocFailed = malloc_failed; } } @@ -63095,17 +62646,19 @@ } pOp = &apSub[j]->aOp[i]; } if( p->explain==1 ){ pMem->flags = MEM_Int; + pMem->type = SQLITE_INTEGER; pMem->u.i = i; /* Program counter */ pMem++; pMem->flags = MEM_Static|MEM_Str|MEM_Term; pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */ assert( pMem->z!=0 ); pMem->n = sqlite3Strlen30(pMem->z); + pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; pMem++; /* When an OP_Program opcode is encounter (the only opcode that has ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms @@ -63127,56 +62680,63 @@ } } pMem->flags = MEM_Int; pMem->u.i = pOp->p1; /* P1 */ + pMem->type = SQLITE_INTEGER; pMem++; pMem->flags = MEM_Int; pMem->u.i = pOp->p2; /* P2 */ + pMem->type = SQLITE_INTEGER; pMem++; pMem->flags = MEM_Int; pMem->u.i = pOp->p3; /* P3 */ + pMem->type = SQLITE_INTEGER; pMem++; if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */ assert( p->db->mallocFailed ); return SQLITE_ERROR; } - pMem->flags = MEM_Str|MEM_Term; + pMem->flags = MEM_Dyn|MEM_Str|MEM_Term; zP4 = displayP4(pOp, pMem->z, 32); if( zP4!=pMem->z ){ sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0); }else{ assert( pMem->z!=0 ); pMem->n = sqlite3Strlen30(pMem->z); pMem->enc = SQLITE_UTF8; } + pMem->type = SQLITE_TEXT; pMem++; if( p->explain==1 ){ if( sqlite3VdbeMemGrow(pMem, 4, 0) ){ assert( p->db->mallocFailed ); return SQLITE_ERROR; } - pMem->flags = MEM_Str|MEM_Term; + pMem->flags = MEM_Dyn|MEM_Str|MEM_Term; pMem->n = 2; sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */ + pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; pMem++; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS if( sqlite3VdbeMemGrow(pMem, 500, 0) ){ assert( p->db->mallocFailed ); return SQLITE_ERROR; } - pMem->flags = MEM_Str|MEM_Term; + pMem->flags = MEM_Dyn|MEM_Str|MEM_Term; pMem->n = displayComment(pOp, zP4, pMem->z, 500); + pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; #else pMem->flags = MEM_Null; /* Comment */ + pMem->type = SQLITE_NULL; #endif } p->nResColumn = 8 - 4*(p->explain-1); p->pResultSet = &p->aMem[1]; @@ -63195,11 +62755,11 @@ const char *z = 0; if( p->zSql ){ z = p->zSql; }else if( p->nOp>=1 ){ const VdbeOp *pOp = &p->aOp[0]; - if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){ + if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){ z = pOp->p4.z; while( sqlite3Isspace(*z) ) z++; } } if( z ) printf("SQL: [%s]\n", z); @@ -63214,11 +62774,11 @@ int nOp = p->nOp; VdbeOp *pOp; if( sqlite3IoTrace==0 ) return; if( nOp<1 ) return; pOp = &p->aOp[0]; - if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){ + if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){ int i, j; char z[1000]; sqlite3_snprintf(sizeof(z), z, "%s", pOp->p4.z); for(i=0; sqlite3Isspace(z[i]); i++){} for(j=0; z[i]; i++){ @@ -63432,11 +62992,11 @@ } if( p->aMem ){ p->aMem--; /* aMem[] goes from 1..nMem */ p->nMem = nMem; /* not from 0..nMem-1 */ for(n=1; n<=nMem; n++){ - p->aMem[n].flags = MEM_Undefined; + p->aMem[n].flags = MEM_Invalid; p->aMem[n].db = db; } } p->explain = pParse->explain; sqlite3VdbeRewind(p); @@ -63544,11 +63104,11 @@ /* Execute assert() statements to ensure that the Vdbe.apCsr[] and ** Vdbe.aMem[] arrays have already been cleaned up. */ int i; if( p->apCsr ) for(i=0; inCursor; i++) assert( p->apCsr[i]==0 ); if( p->aMem ){ - for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); + for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid ); } #endif sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; @@ -64293,28 +63853,16 @@ fprintf(out, "---- "); for(i=0; inOp; i++){ fprintf(out, "%02x", p->aOp[i].opcode); } fprintf(out, "\n"); - if( p->zSql ){ - char c, pc = 0; - fprintf(out, "-- "); - for(i=0; (c = p->zSql[i])!=0; i++){ - if( pc=='\n' ) fprintf(out, "-- "); - putc(c, out); - pc = c; - } - if( pc!='\n' ) fprintf(out, "\n"); - } for(i=0; inOp; i++){ - char zHdr[100]; - sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ", + fprintf(out, "%6d %10lld %8lld ", p->aOp[i].cnt, p->aOp[i].cycles, p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0 ); - fprintf(out, "%s", zHdr); sqlite3VdbePrintOp(out, i, &p->aOp[i]); } fclose(out); } } @@ -64461,11 +64009,11 @@ int hasMoved; int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved); if( rc ) return rc; if( hasMoved ){ p->cacheStatus = CACHE_STALE; - if( hasMoved==2 ) p->nullRow = 1; + p->nullRow = 1; } } return SQLITE_OK; } @@ -64665,18 +64213,10 @@ /* NULL or constants 0 or 1 */ return 0; } -/* Input "x" is a sequence of unsigned characters that represent a -** big-endian integer. Return the equivalent native integer -*/ -#define ONE_BYTE_INT(x) ((i8)(x)[0]) -#define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1]) -#define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2]) -#define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) - /* ** Deserialize the data blob pointed to by buf as serial type serial_type ** and store the result in pMem. Return the number of bytes read. */ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( @@ -64684,46 +64224,47 @@ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ ){ u64 x; u32 y; + int i; switch( serial_type ){ case 10: /* Reserved for future use */ case 11: /* Reserved for future use */ case 0: { /* NULL */ pMem->flags = MEM_Null; break; } case 1: { /* 1-byte signed integer */ - pMem->u.i = ONE_BYTE_INT(buf); + pMem->u.i = (signed char)buf[0]; pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); return 1; } case 2: { /* 2-byte signed integer */ - pMem->u.i = TWO_BYTE_INT(buf); + i = 256*(signed char)buf[0] | buf[1]; + pMem->u.i = (i64)i; pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); return 2; } case 3: { /* 3-byte signed integer */ - pMem->u.i = THREE_BYTE_INT(buf); + i = 65536*(signed char)buf[0] | (buf[1]<<8) | buf[2]; + pMem->u.i = (i64)i; pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); return 3; } case 4: { /* 4-byte signed integer */ - y = FOUR_BYTE_UINT(buf); + y = ((unsigned)buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; pMem->u.i = (i64)*(int*)&y; pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); return 4; } case 5: { /* 6-byte signed integer */ - pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf); + x = 256*(signed char)buf[0] + buf[1]; + y = ((unsigned)buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5]; + x = (x<<32) | y; + pMem->u.i = *(i64*)&x; pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); return 6; } case 6: /* 8-byte signed integer */ case 7: { /* IEEE floating point */ #if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) @@ -64736,17 +64277,16 @@ static const double r1 = 1.0; u64 t2 = t1; swapMixedEndianFloat(t2); assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); #endif - x = FOUR_BYTE_UINT(buf); - y = FOUR_BYTE_UINT(buf+4); + x = ((unsigned)buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; + y = ((unsigned)buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7]; x = (x<<32) | y; if( serial_type==6 ){ pMem->u.i = *(i64*)&x; pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); }else{ assert( sizeof(x)==8 && sizeof(pMem->r)==8 ); swapMixedEndianFloat(x); memcpy(&pMem->r, &x, sizeof(x)); pMem->flags = sqlite3IsNaN(pMem->r) ? MEM_Null : MEM_Real; @@ -64834,11 +64374,11 @@ u32 idx; /* Offset in aKey[] to read from */ u16 u; /* Unsigned loop counter */ u32 szHdr; Mem *pMem = p->aMem; - p->default_rc = 0; + p->flags = 0; assert( EIGHT_BYTE_ALIGNMENT(pMem) ); idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; while( idxnField && d<=nKey ){ @@ -64855,22 +64395,30 @@ } assert( u<=pKeyInfo->nField + 1 ); p->nField = u; } -#if SQLITE_DEBUG /* -** This function compares two index or table record keys in the same way -** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(), -** this function deserializes and compares values using the -** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used -** in assert() statements to ensure that the optimized code in -** sqlite3VdbeRecordCompare() returns results with these two primitives. +** This function compares the two table rows or index records +** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero +** or positive integer if key1 is less than, equal to or +** greater than key2. The {nKey1, pKey1} key must be a blob +** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 +** key must be a parsed key such as obtained from +** sqlite3VdbeParseRecord. +** +** Key1 and Key2 do not have to contain the same number of fields. +** The key with fewer fields is usually compares less than the +** longer key. However if the UNPACKED_INCRKEY flags in pPKey2 is set +** and the common prefixes are equal, then key1 is less than key2. +** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are +** equal, then the keys are considered to be equal and +** the parts beyond the common prefix are ignored. */ -static int vdbeRecordCompareDebug( +SQLITE_PRIVATE int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2 /* Right key */ + UnpackedRecord *pPKey2 /* Right key */ ){ u32 d1; /* Offset into aKey[] of next data element */ u32 idx1; /* Offset into aKey[] of next header element */ u32 szHdr1; /* Number of bytes in header */ int i = 0; @@ -64940,596 +64488,28 @@ ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ assert( mem1.zMalloc==0 ); /* rc==0 here means that one of the keys ran out of fields and - ** all the fields up to that point were equal. Return the the default_rc - ** value. */ - return pPKey2->default_rc; -} -#endif - -/* -** Both *pMem1 and *pMem2 contain string values. Compare the two values -** using the collation sequence pColl. As usual, return a negative , zero -** or positive value if *pMem1 is less than, equal to or greater than -** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);". -*/ -static int vdbeCompareMemString( - const Mem *pMem1, - const Mem *pMem2, - const CollSeq *pColl -){ - if( pMem1->enc==pColl->enc ){ - /* The strings are already in the correct encoding. Call the - ** comparison function directly */ - return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); - }else{ - int rc; - const void *v1, *v2; - int n1, n2; - Mem c1; - Mem c2; - memset(&c1, 0, sizeof(c1)); - memset(&c2, 0, sizeof(c2)); - sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); - sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); - v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); - n1 = v1==0 ? 0 : c1.n; - v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); - n2 = v2==0 ? 0 : c2.n; - rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); - sqlite3VdbeMemRelease(&c1); - sqlite3VdbeMemRelease(&c2); - return rc; - } -} - -/* -** Compare the values contained by the two memory cells, returning -** negative, zero or positive if pMem1 is less than, equal to, or greater -** than pMem2. Sorting order is NULL's first, followed by numbers (integers -** and reals) sorted numerically, followed by text ordered by the collating -** sequence pColl and finally blob's ordered by memcmp(). -** -** Two NULL values are considered equal by this function. -*/ -SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ - int rc; - int f1, f2; - int combined_flags; - - f1 = pMem1->flags; - f2 = pMem2->flags; - combined_flags = f1|f2; - assert( (combined_flags & MEM_RowSet)==0 ); - - /* If one value is NULL, it is less than the other. If both values - ** are NULL, return 0. - */ - if( combined_flags&MEM_Null ){ - return (f2&MEM_Null) - (f1&MEM_Null); - } - - /* If one value is a number and the other is not, the number is less. - ** If both are numbers, compare as reals if one is a real, or as integers - ** if both values are integers. - */ - if( combined_flags&(MEM_Int|MEM_Real) ){ - double r1, r2; - if( (f1 & f2 & MEM_Int)!=0 ){ - if( pMem1->u.i < pMem2->u.i ) return -1; - if( pMem1->u.i > pMem2->u.i ) return 1; - return 0; - } - if( (f1&MEM_Real)!=0 ){ - r1 = pMem1->r; - }else if( (f1&MEM_Int)!=0 ){ - r1 = (double)pMem1->u.i; - }else{ - return 1; - } - if( (f2&MEM_Real)!=0 ){ - r2 = pMem2->r; - }else if( (f2&MEM_Int)!=0 ){ - r2 = (double)pMem2->u.i; - }else{ - return -1; - } - if( r1r2 ) return 1; - return 0; - } - - /* If one value is a string and the other is a blob, the string is less. - ** If both are strings, compare using the collating functions. - */ - if( combined_flags&MEM_Str ){ - if( (f1 & MEM_Str)==0 ){ - return 1; - } - if( (f2 & MEM_Str)==0 ){ - return -1; - } - - assert( pMem1->enc==pMem2->enc ); - assert( pMem1->enc==SQLITE_UTF8 || - pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); - - /* The collation sequence must be defined at this point, even if - ** the user deletes the collation sequence after the vdbe program is - ** compiled (this was not always the case). - */ - assert( !pColl || pColl->xCmp ); - - if( pColl ){ - return vdbeCompareMemString(pMem1, pMem2, pColl); - } - /* If a NULL pointer was passed as the collate function, fall through - ** to the blob case and use memcmp(). */ - } - - /* Both values must be blobs. Compare using memcmp(). */ - rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); - if( rc==0 ){ - rc = pMem1->n - pMem2->n; - } - return rc; -} - - -/* -** The first argument passed to this function is a serial-type that -** corresponds to an integer - all values between 1 and 9 inclusive -** except 7. The second points to a buffer containing an integer value -** serialized according to serial_type. This function deserializes -** and returns the value. -*/ -static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ - u32 y; - assert( CORRUPT_DB || (serial_type>=1 && serial_type<=9 && serial_type!=7) ); - switch( serial_type ){ - case 0: - case 1: - testcase( aKey[0]&0x80 ); - return ONE_BYTE_INT(aKey); - case 2: - testcase( aKey[0]&0x80 ); - return TWO_BYTE_INT(aKey); - case 3: - testcase( aKey[0]&0x80 ); - return THREE_BYTE_INT(aKey); - case 4: { - testcase( aKey[0]&0x80 ); - y = FOUR_BYTE_UINT(aKey); - return (i64)*(int*)&y; - } - case 5: { - testcase( aKey[0]&0x80 ); - return FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey); - } - case 6: { - u64 x = FOUR_BYTE_UINT(aKey); - testcase( aKey[0]&0x80 ); - x = (x<<32) | FOUR_BYTE_UINT(aKey+4); - return (i64)*(i64*)&x; - } - } - - return (serial_type - 8); -} - -/* -** This function compares the two table rows or index records -** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero -** or positive integer if key1 is less than, equal to or -** greater than key2. The {nKey1, pKey1} key must be a blob -** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 -** key must be a parsed key such as obtained from -** sqlite3VdbeParseRecord. -** -** If argument bSkip is non-zero, it is assumed that the caller has already -** determined that the first fields of the keys are equal. -** -** Key1 and Key2 do not have to contain the same number of fields. If all -** fields that appear in both keys are equal, then pPKey2->default_rc is -** returned. -** -** If database corruption is discovered, set pPKey2->isCorrupt to non-zero -** and return 0. -*/ -SQLITE_PRIVATE int sqlite3VdbeRecordCompare( - int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ - int bSkip /* If true, skip the first field */ -){ - u32 d1; /* Offset into aKey[] of next data element */ - int i; /* Index of next field to compare */ - u32 szHdr1; /* Size of record header in bytes */ - u32 idx1; /* Offset of first type in header */ - int rc = 0; /* Return value */ - Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */ - KeyInfo *pKeyInfo = pPKey2->pKeyInfo; - const unsigned char *aKey1 = (const unsigned char *)pKey1; - Mem mem1; - - /* If bSkip is true, then the caller has already determined that the first - ** two elements in the keys are equal. Fix the various stack variables so - ** that this routine begins comparing at the second field. */ - if( bSkip ){ - u32 s1; - idx1 = 1 + getVarint32(&aKey1[1], s1); - szHdr1 = aKey1[0]; - d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1); - i = 1; - pRhs++; - }else{ - idx1 = getVarint32(aKey1, szHdr1); - d1 = szHdr1; - if( d1>(unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; - return 0; /* Corruption */ - } - i = 0; - } - - VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ - assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField - || CORRUPT_DB ); - assert( pPKey2->pKeyInfo->aSortOrder!=0 ); - assert( pPKey2->pKeyInfo->nField>0 ); - assert( idx1<=szHdr1 || CORRUPT_DB ); - do{ - u32 serial_type; - - /* RHS is an integer */ - if( pRhs->flags & MEM_Int ){ - serial_type = aKey1[idx1]; - testcase( serial_type==12 ); - if( serial_type>=12 ){ - rc = +1; - }else if( serial_type==0 ){ - rc = -1; - }else if( serial_type==7 ){ - double rhs = (double)pRhs->u.i; - sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); - if( mem1.rrhs ){ - rc = +1; - } - }else{ - i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); - i64 rhs = pRhs->u.i; - if( lhsrhs ){ - rc = +1; - } - } - } - - /* RHS is real */ - else if( pRhs->flags & MEM_Real ){ - serial_type = aKey1[idx1]; - if( serial_type>=12 ){ - rc = +1; - }else if( serial_type==0 ){ - rc = -1; - }else{ - double rhs = pRhs->r; - double lhs; - sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); - if( serial_type==7 ){ - lhs = mem1.r; - }else{ - lhs = (double)mem1.u.i; - } - if( lhsrhs ){ - rc = +1; - } - } - } - - /* RHS is a string */ - else if( pRhs->flags & MEM_Str ){ - getVarint32(&aKey1[idx1], serial_type); - testcase( serial_type==12 ); - if( serial_type<12 ){ - rc = -1; - }else if( !(serial_type & 0x01) ){ - rc = +1; - }else{ - mem1.n = (serial_type - 12) / 2; - testcase( (d1+mem1.n)==(unsigned)nKey1 ); - testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); - if( (d1+mem1.n) > (unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; - return 0; /* Corruption */ - }else if( pKeyInfo->aColl[i] ){ - mem1.enc = pKeyInfo->enc; - mem1.db = pKeyInfo->db; - mem1.flags = MEM_Str; - mem1.z = (char*)&aKey1[d1]; - rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]); - }else{ - int nCmp = MIN(mem1.n, pRhs->n); - rc = memcmp(&aKey1[d1], pRhs->z, nCmp); - if( rc==0 ) rc = mem1.n - pRhs->n; - } - } - } - - /* RHS is a blob */ - else if( pRhs->flags & MEM_Blob ){ - getVarint32(&aKey1[idx1], serial_type); - testcase( serial_type==12 ); - if( serial_type<12 || (serial_type & 0x01) ){ - rc = -1; - }else{ - int nStr = (serial_type - 12) / 2; - testcase( (d1+nStr)==(unsigned)nKey1 ); - testcase( (d1+nStr+1)==(unsigned)nKey1 ); - if( (d1+nStr) > (unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; - return 0; /* Corruption */ - }else{ - int nCmp = MIN(nStr, pRhs->n); - rc = memcmp(&aKey1[d1], pRhs->z, nCmp); - if( rc==0 ) rc = nStr - pRhs->n; - } - } - } - - /* RHS is null */ - else{ - serial_type = aKey1[idx1]; - rc = (serial_type!=0); - } - - if( rc!=0 ){ - if( pKeyInfo->aSortOrder[i] ){ - rc = -rc; - } - assert( CORRUPT_DB - || (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) - || pKeyInfo->db->mallocFailed - ); - assert( mem1.zMalloc==0 ); /* See comment below */ - return rc; - } - - i++; - pRhs++; - d1 += sqlite3VdbeSerialTypeLen(serial_type); - idx1 += sqlite3VarintLen(serial_type); - }while( idx1<(unsigned)szHdr1 && inField && d1<=(unsigned)nKey1 ); - - /* No memory allocation is ever used on mem1. Prove this using - ** the following assert(). If the assert() fails, it indicates a - ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ - assert( mem1.zMalloc==0 ); - - /* rc==0 here means that one or both of the keys ran out of fields and - ** all the fields up to that point were equal. Return the the default_rc - ** value. */ - assert( CORRUPT_DB - || pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2) - ); - return pPKey2->default_rc; -} - -/* -** This function is an optimized version of sqlite3VdbeRecordCompare() -** that (a) the first field of pPKey2 is an integer, and (b) the -** size-of-header varint at the start of (pKey1/nKey1) fits in a single -** byte (i.e. is less than 128). -** -** To avoid concerns about buffer overreads, this routine is only used -** on schemas where the maximum valid header size is 63 bytes or less. -*/ -static int vdbeRecordCompareInt( - int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ - int bSkip /* Ignored */ -){ - const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; - int serial_type = ((const u8*)pKey1)[1]; - int res; - u32 y; - u64 x; - i64 v = pPKey2->aMem[0].u.i; - i64 lhs; - UNUSED_PARAMETER(bSkip); - - assert( bSkip==0 ); - assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB ); - switch( serial_type ){ - case 1: { /* 1-byte signed integer */ - lhs = ONE_BYTE_INT(aKey); - testcase( lhs<0 ); - break; - } - case 2: { /* 2-byte signed integer */ - lhs = TWO_BYTE_INT(aKey); - testcase( lhs<0 ); - break; - } - case 3: { /* 3-byte signed integer */ - lhs = THREE_BYTE_INT(aKey); - testcase( lhs<0 ); - break; - } - case 4: { /* 4-byte signed integer */ - y = FOUR_BYTE_UINT(aKey); - lhs = (i64)*(int*)&y; - testcase( lhs<0 ); - break; - } - case 5: { /* 6-byte signed integer */ - lhs = FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey); - testcase( lhs<0 ); - break; - } - case 6: { /* 8-byte signed integer */ - x = FOUR_BYTE_UINT(aKey); - x = (x<<32) | FOUR_BYTE_UINT(aKey+4); - lhs = *(i64*)&x; - testcase( lhs<0 ); - break; - } - case 8: - lhs = 0; - break; - case 9: - lhs = 1; - break; - - /* This case could be removed without changing the results of running - ** this code. Including it causes gcc to generate a faster switch - ** statement (since the range of switch targets now starts at zero and - ** is contiguous) but does not cause any duplicate code to be generated - ** (as gcc is clever enough to combine the two like cases). Other - ** compilers might be similar. */ - case 0: case 7: - return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0); - - default: - return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0); - } - - if( v>lhs ){ - res = pPKey2->r1; - }else if( vr2; - }else if( pPKey2->nField>1 ){ - /* The first fields of the two keys are equal. Compare the trailing - ** fields. */ - res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1); - }else{ - /* The first fields of the two keys are equal and there are no trailing - ** fields. Return pPKey2->default_rc in this case. */ - res = pPKey2->default_rc; - } - - assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0) - || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) - || CORRUPT_DB - ); - return res; -} - -/* -** This function is an optimized version of sqlite3VdbeRecordCompare() -** that (a) the first field of pPKey2 is a string, that (b) the first field -** uses the collation sequence BINARY and (c) that the size-of-header varint -** at the start of (pKey1/nKey1) fits in a single byte. -*/ -static int vdbeRecordCompareString( - int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ - int bSkip -){ - const u8 *aKey1 = (const u8*)pKey1; - int serial_type; - int res; - UNUSED_PARAMETER(bSkip); - - assert( bSkip==0 ); - getVarint32(&aKey1[1], serial_type); - - if( serial_type<12 ){ - res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */ - }else if( !(serial_type & 0x01) ){ - res = pPKey2->r2; /* (pKey1/nKey1) is a blob */ - }else{ - int nCmp; - int nStr; - int szHdr = aKey1[0]; - - nStr = (serial_type-12) / 2; - if( (szHdr + nStr) > nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; - return 0; /* Corruption */ - } - nCmp = MIN( pPKey2->aMem[0].n, nStr ); - res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp); - - if( res==0 ){ - res = nStr - pPKey2->aMem[0].n; - if( res==0 ){ - if( pPKey2->nField>1 ){ - res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1); - }else{ - res = pPKey2->default_rc; - } - }else if( res>0 ){ - res = pPKey2->r2; - }else{ - res = pPKey2->r1; - } - }else if( res>0 ){ - res = pPKey2->r2; - }else{ - res = pPKey2->r1; - } - } - - assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0) - || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) - || CORRUPT_DB - ); - return res; -} - -/* -** Return a pointer to an sqlite3VdbeRecordCompare() compatible function -** suitable for comparing serialized records to the unpacked record passed -** as the only argument. -*/ -SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ - /* varintRecordCompareInt() and varintRecordCompareString() both assume - ** that the size-of-header varint that occurs at the start of each record - ** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt() - ** also assumes that it is safe to overread a buffer by at least the - ** maximum possible legal header size plus 8 bytes. Because there is - ** guaranteed to be at least 74 (but not 136) bytes of padding following each - ** buffer passed to varintRecordCompareInt() this makes it convenient to - ** limit the size of the header to 64 bytes in cases where the first field - ** is an integer. - ** - ** The easiest way to enforce this limit is to consider only records with - ** 13 fields or less. If the first field is an integer, the maximum legal - ** header size is (12*5 + 1 + 1) bytes. */ - if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){ - int flags = p->aMem[0].flags; - if( p->pKeyInfo->aSortOrder[0] ){ - p->r1 = 1; - p->r2 = -1; - }else{ - p->r1 = -1; - p->r2 = 1; - } - if( (flags & MEM_Int) ){ - return vdbeRecordCompareInt; - } - testcase( flags & MEM_Real ); - testcase( flags & MEM_Null ); - testcase( flags & MEM_Blob ); - if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){ - assert( flags & MEM_Str ); - return vdbeRecordCompareString; - } - } - - return sqlite3VdbeRecordCompare; -} + ** all the fields up to that point were equal. If the UNPACKED_INCRKEY + ** flag is set, then break the tie by treating key2 as larger. + ** If the UPACKED_PREFIX_MATCH flag is set, then keys with common prefixes + ** are considered to be equal. Otherwise, the longer key is the + ** larger. As it happens, the pPKey2 will always be the longer + ** if there is a difference. + */ + assert( rc==0 ); + if( pPKey2->flags & UNPACKED_INCRKEY ){ + rc = -1; + }else if( pPKey2->flags & UNPACKED_PREFIX_MATCH ){ + /* Leave rc==0 */ + }else if( idx1pCursor; Mem m; assert( sqlite3BtreeCursorIsValid(pCur) ); VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ - /* nCellKey will always be between 0 and 0xffffffff because of the way + /* nCellKey will always be between 0 and 0xffffffff because of the say ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; return SQLITE_CORRUPT_BKPT; } @@ -65639,11 +64619,12 @@ memset(&m, 0, sizeof(m)); rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m); if( rc ){ return rc; } - *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked, 0); + assert( pUnpacked->flags & UNPACKED_PREFIX_MATCH ); + *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); sqlite3VdbeMemRelease(&m); return SQLITE_OK; } /* @@ -65703,10 +64684,11 @@ if( 0==(pMem->flags & MEM_Null) ){ sqlite3_value *pRet = sqlite3ValueNew(v->db); if( pRet ){ sqlite3VdbeMemCopy((Mem *)pRet, pMem); sqlite3ValueApplyAffinity(pRet, aff, SQLITE_UTF8); + sqlite3VdbeMemStoreType((Mem *)pRet); } return pRet; } } return 0; @@ -65876,10 +64858,11 @@ */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){ Mem *p = (Mem*)pVal; if( p->flags & (MEM_Blob|MEM_Str) ){ sqlite3VdbeMemExpandBlob(p); + p->flags &= ~MEM_Str; p->flags |= MEM_Blob; return p->n ? p->z : 0; }else{ return sqlite3_value_text(pVal); } @@ -65912,45 +64895,11 @@ SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16LE); } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ - static const u8 aType[] = { - SQLITE_BLOB, /* 0x00 */ - SQLITE_NULL, /* 0x01 */ - SQLITE_TEXT, /* 0x02 */ - SQLITE_NULL, /* 0x03 */ - SQLITE_INTEGER, /* 0x04 */ - SQLITE_NULL, /* 0x05 */ - SQLITE_INTEGER, /* 0x06 */ - SQLITE_NULL, /* 0x07 */ - SQLITE_FLOAT, /* 0x08 */ - SQLITE_NULL, /* 0x09 */ - SQLITE_FLOAT, /* 0x0a */ - SQLITE_NULL, /* 0x0b */ - SQLITE_INTEGER, /* 0x0c */ - SQLITE_NULL, /* 0x0d */ - SQLITE_INTEGER, /* 0x0e */ - SQLITE_NULL, /* 0x0f */ - SQLITE_BLOB, /* 0x10 */ - SQLITE_NULL, /* 0x11 */ - SQLITE_TEXT, /* 0x12 */ - SQLITE_NULL, /* 0x13 */ - SQLITE_INTEGER, /* 0x14 */ - SQLITE_NULL, /* 0x15 */ - SQLITE_INTEGER, /* 0x16 */ - SQLITE_NULL, /* 0x17 */ - SQLITE_FLOAT, /* 0x18 */ - SQLITE_NULL, /* 0x19 */ - SQLITE_FLOAT, /* 0x1a */ - SQLITE_NULL, /* 0x1b */ - SQLITE_INTEGER, /* 0x1c */ - SQLITE_NULL, /* 0x1d */ - SQLITE_INTEGER, /* 0x1e */ - SQLITE_NULL, /* 0x1f */ - }; - return aType[pVal->flags&MEM_AffMask]; + return pVal->type; } /**************************** sqlite3_result_ ******************************* ** The following routines are used by user-defined functions to specify ** the function result. @@ -66467,34 +65416,10 @@ Vdbe *pVm = (Vdbe *)pStmt; if( pVm==0 || pVm->pResultSet==0 ) return 0; return pVm->nResColumn; } -/* -** Return a pointer to static memory containing an SQL NULL value. -*/ -static const Mem *columnNullValue(void){ - /* Even though the Mem structure contains an element - ** of type i64, on certain architectures (x86) with certain compiler - ** switches (-Os), gcc may align this Mem object on a 4-byte boundary - ** instead of an 8-byte one. This all works fine, except that when - ** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s - ** that a Mem structure is located on an 8-byte boundary. To prevent - ** these assert()s from failing, when building with SQLITE_DEBUG defined - ** using gcc, we force nullMem to be 8-byte aligned using the magical - ** __attribute__((aligned(8))) macro. */ - static const Mem nullMem -#if defined(SQLITE_DEBUG) && defined(__GNUC__) - __attribute__((aligned(8))) -#endif - = {0, "", (double)0, {0}, 0, MEM_Null, 0, -#ifdef SQLITE_DEBUG - 0, 0, /* pScopyFrom, pFiller */ -#endif - 0, 0 }; - return &nullMem; -} /* ** Check to see if column iCol of the given statement is valid. If ** it is, return a pointer to the Mem for the value of that column. ** If iCol is not valid, return a pointer to a Mem which has a value @@ -66507,15 +65432,36 @@ pVm = (Vdbe *)pStmt; if( pVm && pVm->pResultSet!=0 && inResColumn && i>=0 ){ sqlite3_mutex_enter(pVm->db->mutex); pOut = &pVm->pResultSet[i]; }else{ + /* If the value passed as the second argument is out of range, return + ** a pointer to the following static Mem object which contains the + ** value SQL NULL. Even though the Mem structure contains an element + ** of type i64, on certain architectures (x86) with certain compiler + ** switches (-Os), gcc may align this Mem object on a 4-byte boundary + ** instead of an 8-byte one. This all works fine, except that when + ** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s + ** that a Mem structure is located on an 8-byte boundary. To prevent + ** these assert()s from failing, when building with SQLITE_DEBUG defined + ** using gcc, we force nullMem to be 8-byte aligned using the magical + ** __attribute__((aligned(8))) macro. */ + static const Mem nullMem +#if defined(SQLITE_DEBUG) && defined(__GNUC__) + __attribute__((aligned(8))) +#endif + = {0, "", (double)0, {0}, 0, MEM_Null, SQLITE_NULL, 0, +#ifdef SQLITE_DEBUG + 0, 0, /* pScopyFrom, pFiller */ +#endif + 0, 0 }; + if( pVm && ALWAYS(pVm->db) ){ sqlite3_mutex_enter(pVm->db->mutex); sqlite3Error(pVm->db, SQLITE_RANGE, 0); } - pOut = (Mem*)columnNullValue(); + pOut = (Mem*)&nullMem; } return pOut; } /* @@ -66908,11 +65854,11 @@ return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ int rc; - switch( sqlite3_value_type((sqlite3_value*)pValue) ){ + switch( pValue->type ){ case SQLITE_INTEGER: { rc = sqlite3_bind_int64(pStmt, i, pValue->u.i); break; } case SQLITE_FLOAT: { @@ -67409,12 +66355,37 @@ ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* -** The code in this file implements the function that runs the -** bytecode of a prepared statement. +** The code in this file implements execution method of the +** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c") +** handles housekeeping details such as creating and deleting +** VDBE instances. This file is solely interested in executing +** the VDBE program. +** +** In the external interface, an "sqlite3_stmt*" is an opaque pointer +** to a VDBE. +** +** The SQL parser generates a program which is then executed by +** the VDBE to do the work of the SQL statement. VDBE programs are +** similar in form to assembly language. The program consists of +** a linear sequence of operations. Each operation has an opcode +** and 5 operands. Operands P1, P2, and P3 are integers. Operand P4 +** is a null-terminated string. Operand P5 is an unsigned character. +** Few opcodes use all 5 operands. +** +** Computation results are stored on a set of registers numbered beginning +** with 1 and going up to Vdbe.nMem. Each register can store +** either an integer, a null-terminated string, a floating point +** number, or the SQL "NULL" value. An implicit conversion from one +** type to the other occurs as necessary. +** +** Most of the code in this file is taken up by the sqlite3VdbeExec() +** function which does the work of interpreting a VDBE program. +** But other routines are also provided to help in building up +** a program instruction by instruction. ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing @@ -67422,15 +66393,11 @@ */ /* ** Invoke this macro on memory cells just prior to changing the ** value of the cell. This macro verifies that shallow copies are -** not misused. A shallow copy of a string or blob just copies a -** pointer to the string or blob, not the content. If the original -** is changed while the copy is still in use, the string or blob might -** be changed out from under the copy. This macro verifies that nothing -** like that ever happens. +** not misused. */ #ifdef SQLITE_DEBUG # define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M) #else # define memAboutToChange(P,M) @@ -67485,11 +66452,11 @@ } } #endif /* -** The next global variable is incremented each time the OP_Found opcode +** The next global variable is incremented each type the OP_Found opcode ** is executed. This is used to test whether or not the foreign key ** operation implemented using OP_FkIsZero is working. This variable ** has no function other than to help verify the correct operation of the ** library. */ @@ -67505,38 +66472,10 @@ # define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) #else # define UPDATE_MAX_BLOBSIZE(P) #endif -/* -** Invoke the VDBE coverage callback, if that callback is defined. This -** feature is used for test suite validation only and does not appear an -** production builds. -** -** M is an integer, 2 or 3, that indices how many different ways the -** branch can go. It is usually 2. "I" is the direction the branch -** goes. 0 means falls through. 1 means branch is taken. 2 means the -** second alternative branch is taken. -*/ -#if !defined(SQLITE_VDBE_COVERAGE) -# define VdbeBranchTaken(I,M) -#else -# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M) - static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){ - if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){ - M = iSrcLine; - /* Assert the truth of VdbeCoverageAlwaysTaken() and - ** VdbeCoverageNeverTaken() */ - assert( (M & I)==I ); - }else{ - if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ - sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, - iSrcLine,I,M); - } - } -#endif - /* ** Convert the given register into a string if it isn't one ** already. Return non-zero if a malloc() fails. */ #define Stringify(P, enc) \ @@ -67550,18 +66489,42 @@ ** does not control the string, it might be deleted without the register ** knowing it. ** ** This routine converts an ephemeral string into a dynamically allocated ** string that the register itself controls. In other words, it -** converts an MEM_Ephem string into a string with P.z==P.zMalloc. +** converts an MEM_Ephem string into an MEM_Dyn string. */ #define Deephemeralize(P) \ if( ((P)->flags&MEM_Ephem)!=0 \ && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ -#define isSorter(x) ((x)->pSorter!=0) +# define isSorter(x) ((x)->pSorter!=0) + +/* +** Argument pMem points at a register that will be passed to a +** user-defined function or returned to the user as the result of a query. +** This routine sets the pMem->type variable used by the sqlite3_value_*() +** routines. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem){ + int flags = pMem->flags; + if( flags & MEM_Null ){ + pMem->type = SQLITE_NULL; + } + else if( flags & MEM_Int ){ + pMem->type = SQLITE_INTEGER; + } + else if( flags & MEM_Real ){ + pMem->type = SQLITE_FLOAT; + } + else if( flags & MEM_Str ){ + pMem->type = SQLITE_TEXT; + }else{ + pMem->type = SQLITE_BLOB; + } +} /* ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. */ @@ -67687,17 +66650,16 @@ ** into a numeric representation. Use either INTEGER or REAL whichever ** is appropriate. But only do the conversion if it is possible without ** loss of information and return the revised type of the argument. */ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ - int eType = sqlite3_value_type(pVal); - if( eType==SQLITE_TEXT ){ - Mem *pMem = (Mem*)pVal; + Mem *pMem = (Mem*)pVal; + if( pMem->type==SQLITE_TEXT ){ applyNumericAffinity(pMem); - eType = sqlite3_value_type(pVal); + sqlite3VdbeMemStoreType(pMem); } - return eType; + return pMem->type; } /* ** Exported version of applyAffinity(). This one works on sqlite3_value*, ** not the internal Mem* type. @@ -67708,33 +66670,10 @@ u8 enc ){ applyAffinity((Mem *)pVal, affinity, enc); } -/* -** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or -** none. -** -** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. -** But it does set pMem->r and pMem->u.i appropriately. -*/ -static u16 numericType(Mem *pMem){ - if( pMem->flags & (MEM_Int|MEM_Real) ){ - return pMem->flags & (MEM_Int|MEM_Real); - } - if( pMem->flags & (MEM_Str|MEM_Blob) ){ - if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){ - return 0; - } - if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ - return MEM_Int; - } - return MEM_Real; - } - return 0; -} - #ifdef SQLITE_DEBUG /* ** Write a nice string representation of the contents of cell pMem ** into buffer zBuf, length nBuf. */ @@ -67819,11 +66758,11 @@ #ifdef SQLITE_DEBUG /* ** Print the value of a register for tracing purposes: */ static void memTracePrint(Mem *p){ - if( p->flags & MEM_Undefined ){ + if( p->flags & MEM_Invalid ){ printf(" undefined"); }else if( p->flags & MEM_Null ){ printf(" NULL"); }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ printf(" si:%lld", p->u.i); @@ -67951,10 +66890,24 @@ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in vdbe.c ***********************/ #endif + +/* +** The CHECK_FOR_INTERRUPT macro defined here looks to see if the +** sqlite3_interrupt() routine has been called. If it has been, then +** processing of the VDBE program is interrupted. +** +** This macro added to every instruction that does a jump in order to +** implement a loop. This test used to be on every single instruction, +** but that meant we more testing than we needed. By only testing the +** flag on jump instructions, we get a (small) speed improvement. +*/ +#define CHECK_FOR_INTERRUPT \ + if( db->u1.isInterrupted ) goto abort_due_to_interrupt; + #ifndef NDEBUG /* ** This function is only called from within an assert() expression. It ** checks that the sqlite3.nTransaction variable is correctly set to @@ -67974,12 +66927,39 @@ } #endif /* -** Execute as much of a VDBE program as we can. -** This is the core of sqlite3_step(). +** Execute as much of a VDBE program as we can then return. +** +** sqlite3VdbeMakeReady() must be called before this routine in order to +** close the program with a final OP_Halt and to set up the callbacks +** and the error message pointer. +** +** Whenever a row or result data is available, this routine will either +** invoke the result callback (if there is one) or return with +** SQLITE_ROW. +** +** If an attempt is made to open a locked database, then this routine +** will either invoke the busy callback (if there is one) or it will +** return SQLITE_BUSY. +** +** If an error occurs, an error message is written to memory obtained +** from sqlite3_malloc() and p->zErrMsg is made to point to that memory. +** The error code is stored in p->rc and this routine returns SQLITE_ERROR. +** +** If the callback ever returns non-zero, then the program exits +** immediately. There will be no error message but the p->rc field is +** set to SQLITE_ABORT and this routine will return SQLITE_ERROR. +** +** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this +** routine to return SQLITE_ERROR. +** +** Other fatal errors return SQLITE_ERROR. +** +** After this routine has finished, sqlite3VdbeFinalize() should be +** used to clean up the mess that was left behind. */ SQLITE_PRIVATE int sqlite3VdbeExec( Vdbe *p /* The VDBE */ ){ int pc=0; /* The program counter */ @@ -68001,10 +66981,11 @@ Mem *pOut = 0; /* Output operand */ int *aPermute = 0; /* Permutation of columns for OP_Compare */ i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */ #ifdef VDBE_PROFILE u64 start; /* CPU clock count at start of opcode */ + int origPc; /* Program counter at start of opcode */ #endif /*** INSERT STACK UNION HERE ***/ assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ sqlite3VdbeEnter(p); @@ -68018,11 +66999,11 @@ p->rc = SQLITE_OK; p->iCurrentTime = 0; assert( p->explain==0 ); p->pResultSet = 0; db->busyHandler.nBusy = 0; - if( db->u1.isInterrupted ) goto abort_due_to_interrupt; + CHECK_FOR_INTERRUPT; sqlite3VdbeIOTraceSql(p); #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( db->xProgress ){ assert( 0 < db->nProgressOps ); nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; @@ -68062,10 +67043,11 @@ #endif for(pc=p->pc; rc==SQLITE_OK; pc++){ assert( pc>=0 && pcnOp ); if( db->mallocFailed ) goto no_mem; #ifdef VDBE_PROFILE + origPc = pc; start = sqlite3Hwtime(); #endif nVmStep++; pOp = &aOp[pc]; @@ -68109,25 +67091,22 @@ #ifdef SQLITE_DEBUG if( (pOp->opflags & OPFLG_IN1)!=0 ){ assert( pOp->p1>0 ); assert( pOp->p1<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p1]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); } if( (pOp->opflags & OPFLG_IN2)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p2]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); } if( (pOp->opflags & OPFLG_IN3)!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p3]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); } if( (pOp->opflags & OPFLG_OUT2)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=(p->nMem-p->nCursor) ); @@ -68181,15 +67160,10 @@ ** ** An unconditional jump to address P2. ** The next instruction executed will be ** the one at index P2 from the beginning of ** the program. -** -** The P1 parameter is not actually used by this opcode. However, it -** is sometimes set to 1 instead of 0 as a hint to the command-line shell -** that this Goto is the bottom of a loop and that the lines from P2 down -** to the current line should be indented for EXPLAIN output. */ case OP_Goto: { /* jump */ pc = pOp->p2 - 1; /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, @@ -68201,11 +67175,11 @@ ** But that is not due to sloppy coding habits. The code is written this ** way for performance, to avoid having to run the interrupt and progress ** checks on every opcode. This helps sqlite3_step() to run about 1.5% ** faster according to "valgrind --tool=cachegrind" */ check_for_interrupt: - if( db->u1.isInterrupted ) goto abort_due_to_interrupt; + CHECK_FOR_INTERRUPT; #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* Call the progress callback if it is configured and the required number ** of VDBE ops have been executed (either since this invocation of ** sqlite3VdbeExec() or since last time the progress callback was called). ** If the progress callback returns non-zero, exit the virtual machine with @@ -68230,11 +67204,11 @@ ** and then jump to address P2. */ case OP_Gosub: { /* jump */ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); pIn1 = &aMem[pOp->p1]; - assert( VdbeMemDynamic(pIn1)==0 ); + assert( (pIn1->flags & MEM_Dyn)==0 ); memAboutToChange(p, pIn1); pIn1->flags = MEM_Int; pIn1->u.i = pc; REGISTER_TRACE(pOp->p1, pIn1); pc = pOp->p2 - 1; @@ -68241,83 +67215,37 @@ break; } /* Opcode: Return P1 * * * * ** -** Jump to the next instruction after the address in register P1. After -** the jump, register P1 becomes undefined. +** Jump to the next instruction after the address in register P1. */ case OP_Return: { /* in1 */ pIn1 = &aMem[pOp->p1]; - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags & MEM_Int ); pc = (int)pIn1->u.i; - pIn1->flags = MEM_Undefined; - break; -} - -/* Opcode: InitCoroutine P1 P2 P3 * * -** -** Set up register P1 so that it will OP_Yield to the co-routine -** located at address P3. -** -** If P2!=0 then the co-routine implementation immediately follows -** this opcode. So jump over the co-routine implementation to -** address P2. -*/ -case OP_InitCoroutine: { /* jump */ - assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); - assert( pOp->p2>=0 && pOp->p2nOp ); - assert( pOp->p3>=0 && pOp->p3nOp ); - pOut = &aMem[pOp->p1]; - assert( !VdbeMemDynamic(pOut) ); - pOut->u.i = pOp->p3 - 1; - pOut->flags = MEM_Int; - if( pOp->p2 ) pc = pOp->p2 - 1; - break; -} - -/* Opcode: EndCoroutine P1 * * * * -** -** The instruction at the address in register P1 is an OP_Yield. -** Jump to the P2 parameter of that OP_Yield. -** After the jump, register P1 becomes undefined. -*/ -case OP_EndCoroutine: { /* in1 */ - VdbeOp *pCaller; - pIn1 = &aMem[pOp->p1]; - assert( pIn1->flags==MEM_Int ); - assert( pIn1->u.i>=0 && pIn1->u.inOp ); - pCaller = &aOp[pIn1->u.i]; - assert( pCaller->opcode==OP_Yield ); - assert( pCaller->p2>=0 && pCaller->p2nOp ); - pc = pCaller->p2 - 1; - pIn1->flags = MEM_Undefined; - break; -} - -/* Opcode: Yield P1 P2 * * * + break; +} + +/* Opcode: Yield P1 * * * * ** ** Swap the program counter with the value in register P1. -** -** If the co-routine ends with OP_Yield or OP_Return then continue -** to the next instruction. But if the co-routine ends with -** OP_EndCoroutine, jump immediately to P2. */ -case OP_Yield: { /* in1, jump */ +case OP_Yield: { /* in1 */ int pcDest; pIn1 = &aMem[pOp->p1]; - assert( VdbeMemDynamic(pIn1)==0 ); + assert( (pIn1->flags & MEM_Dyn)==0 ); pIn1->flags = MEM_Int; pcDest = (int)pIn1->u.i; pIn1->u.i = pc; REGISTER_TRACE(pOp->p1, pIn1); pc = pcDest; break; } /* Opcode: HaltIfNull P1 P2 P3 P4 P5 -** Synopsis: if r[P3]=null halt +** Synopsis: if r[P3] null then halt ** ** Check the value in register P3. If it is NULL then Halt using ** parameter P1, P2, and P4 as if this were a Halt instruction. If the ** value in register P3 is not NULL, then this routine is a no-op. ** The P5 parameter should be 1. @@ -68461,13 +67389,11 @@ /* Opcode: String8 * P2 * P4 * ** Synopsis: r[P2]='P4' ** ** P4 points to a nul terminated UTF-8 string. This opcode is transformed -** into an OP_String before it is executed for the first time. During -** this transformation, the length of string P4 is computed and stored -** as the P1 parameter. +** into an OP_String before it is executed for the first time. */ case OP_String8: { /* same as TK_STRING, out2-prerelease */ assert( pOp->p4.z!=0 ); pOp->opcode = OP_String; pOp->p1 = sqlite3Strlen30(pOp->p4.z); @@ -68476,13 +67402,14 @@ if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); if( rc==SQLITE_TOOBIG ) goto too_big; if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; assert( pOut->zMalloc==pOut->z ); - assert( VdbeMemDynamic(pOut)==0 ); + assert( pOut->flags & MEM_Dyn ); pOut->zMalloc = 0; pOut->flags |= MEM_Static; + pOut->flags &= ~MEM_Dyn; if( pOp->p4type==P4_DYNAMIC ){ sqlite3DbFree(db, pOp->p4.z); } pOp->p4type = P4_DYNAMIC; pOp->p4.z = pOut->z; @@ -68536,26 +67463,12 @@ cnt--; } break; } -/* Opcode: SoftNull P1 * * * * -** Synopsis: r[P1]=NULL -** -** Set register P1 to have the value NULL as seen by the OP_MakeRecord -** instruction, but do not free any string or blob memory associated with -** the register, so that if the value was a string or blob that was -** previously copied using OP_SCopy, the copies will continue to be valid. -*/ -case OP_SoftNull: { - assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); - pOut = &aMem[pOp->p1]; - pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined; - break; -} - -/* Opcode: Blob P1 P2 * P4 * + +/* Opcode: Blob P1 P2 * P4 ** Synopsis: r[P2]=P4 (len=P1) ** ** P4 points to a blob of data P1 bytes long. Store this ** blob in register P2. */ @@ -68570,11 +67483,11 @@ /* Opcode: Variable P1 P2 * P4 * ** Synopsis: r[P2]=parameter(P1,P4) ** ** Transfer the values of bound parameter P1 into register P2 ** -** If the parameter is named, then its name appears in P4. +** If the parameter is named, then its name appears in P4 and P3==1. ** The P4 value is used by sqlite3_bind_parameter_name(). */ case OP_Variable: { /* out2-prerelease */ Mem *pVar; /* Value being transferred */ @@ -68590,15 +67503,14 @@ } /* Opcode: Move P1 P2 P3 * * ** Synopsis: r[P2@P3]=r[P1@P3] ** -** Move the P3 values in register P1..P1+P3-1 over into -** registers P2..P2+P3-1. Registers P1..P1+P3-1 are +** Move the values in register P1..P1+P3 over into +** registers P2..P2+P3. Registers P1..P1+P3 are ** left holding a NULL. It is an error for register ranges -** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error -** for P3 to be less than 1. +** P1..P1+P3 and P2..P2+P3 to overlap. */ case OP_Move: { char *zMalloc; /* Holding variable for allocated memory */ int n; /* Number of registers left to copy */ int p1; /* Register to copy from */ @@ -68605,35 +67517,33 @@ int p2; /* Register to copy to */ n = pOp->p3; p1 = pOp->p1; p2 = pOp->p2; - assert( n>0 && p1>0 && p2>0 ); + assert( n>=0 && p1>0 && p2>0 ); assert( p1+n<=p2 || p2+n<=p1 ); pIn1 = &aMem[p1]; pOut = &aMem[p2]; do{ assert( pOut<=&aMem[(p->nMem-p->nCursor)] ); assert( pIn1<=&aMem[(p->nMem-p->nCursor)] ); assert( memIsValid(pIn1) ); memAboutToChange(p, pOut); - VdbeMemRelease(pOut); zMalloc = pOut->zMalloc; - memcpy(pOut, pIn1, sizeof(Mem)); + pOut->zMalloc = 0; + sqlite3VdbeMemMove(pOut, pIn1); #ifdef SQLITE_DEBUG if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){ pOut->pScopyFrom += p1 - pOp->p2; } #endif - pIn1->flags = MEM_Undefined; - pIn1->xDel = 0; pIn1->zMalloc = zMalloc; REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; - }while( --n ); + }while( n-- ); break; } /* Opcode: Copy P1 P2 P3 * * ** Synopsis: r[P2@P3+1]=r[P1@P3+1] @@ -68692,12 +67602,12 @@ ** Synopsis: output=r[P1@P2] ** ** The registers P1 through P1+P2-1 contain a single row of ** results. This opcode causes the sqlite3_step() call to terminate ** with an SQLITE_ROW return code and it sets up the sqlite3_stmt -** structure to provide access to the r(P1)..r(P1+P2-1) values as -** the result row. +** structure to provide access to the top P1 values as the result +** row. */ case OP_ResultRow: { Mem *pMem; int i; assert( p->nResColumn==pOp->p2 ); @@ -68758,10 +67668,11 @@ assert( memIsValid(&pMem[i]) ); Deephemeralize(&pMem[i]); assert( (pMem[i].flags & MEM_Ephem)==0 || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 ); sqlite3VdbeMemNulTerminate(&pMem[i]); + sqlite3VdbeMemStoreType(&pMem[i]); REGISTER_TRACE(pOp->p1+i, &pMem[i]); } if( db->mallocFailed ) goto no_mem; /* Return SQLITE_ROW @@ -68800,14 +67711,14 @@ Stringify(pIn2, encoding); nByte = pIn1->n + pIn2->n; if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } + MemSetTypeFlag(pOut, MEM_Str); if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ goto no_mem; } - MemSetTypeFlag(pOut, MEM_Str); if( pOut!=pIn2 ){ memcpy(pOut->z, pIn2->z, pIn2->n); } memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); pOut->z[nByte]=0; @@ -68861,26 +67772,24 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ char bIntint; /* Started out as two integer operands */ - u16 flags; /* Combined MEM_* flags from both inputs */ - u16 type1; /* Numeric type of left operand */ - u16 type2; /* Numeric type of right operand */ + int flags; /* Combined MEM_* flags from both inputs */ i64 iA; /* Integer value of left operand */ i64 iB; /* Integer value of right operand */ double rA; /* Real value of left operand */ double rB; /* Real value of right operand */ pIn1 = &aMem[pOp->p1]; - type1 = numericType(pIn1); + applyNumericAffinity(pIn1); pIn2 = &aMem[pOp->p2]; - type2 = numericType(pIn2); + applyNumericAffinity(pIn2); pOut = &aMem[pOp->p3]; flags = pIn1->flags | pIn2->flags; if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; - if( (type1 & type2 & MEM_Int)!=0 ){ + if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){ iA = pIn1->u.i; iB = pIn2->u.i; bIntint = 1; switch( pOp->opcode ){ case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; @@ -68932,11 +67841,11 @@ if( sqlite3IsNaN(rB) ){ goto arithmetic_result_is_null; } pOut->r = rB; MemSetTypeFlag(pOut, MEM_Real); - if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ + if( (flags & MEM_Real)==0 && !bIntint ){ sqlite3VdbeIntegerAffinity(pOut); } #endif } break; @@ -69005,10 +67914,11 @@ pArg = &aMem[pOp->p2]; for(i=0; ip2+i, pArg); } assert( pOp->p4type==P4_FUNCDEF ); ctx.pFunc = pOp->p4.pFunc; @@ -69183,11 +68093,10 @@ */ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); - VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); if( (pIn1->flags & MEM_Int)==0 ){ if( pOp->p2==0 ){ rc = SQLITE_MISMATCH; goto abort_due_to_error; }else{ @@ -69222,11 +68131,11 @@ #ifndef SQLITE_OMIT_CAST /* Opcode: ToText P1 * * * * ** ** Force the value in register P1 to be text. ** If the value is numeric, convert it to a string using the -** equivalent of sprintf(). Blob values are unchanged and +** equivalent of printf(). Blob values are unchanged and ** are afterwards simply interpreted as text. ** ** A NULL value is not changed by this routine. It remains NULL. */ case OP_ToText: { /* same as TK_TO_TEXT, in1 */ @@ -69424,11 +68333,10 @@ ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); assert( (flags1 & MEM_Cleared)==0 ); - assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 ); if( (flags1&MEM_Null)!=0 && (flags3&MEM_Null)!=0 && (flags3&MEM_Cleared)==0 ){ res = 0; /* Results are equal */ @@ -69438,19 +68346,16 @@ }else{ /* SQLITE_NULLEQ is clear and at least one operand is NULL, ** then the result is always NULL. ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. */ - if( pOp->p5 & SQLITE_STOREP2 ){ + if( pOp->p5 & SQLITE_JUMPIFNULL ){ + pc = pOp->p2-1; + }else if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &aMem[pOp->p2]; MemSetTypeFlag(pOut, MEM_Null); REGISTER_TRACE(pOp->p2, pOut); - }else{ - VdbeBranchTaken(2,3); - if( pOp->p5 & SQLITE_JUMPIFNULL ){ - pc = pOp->p2-1; - } } break; } }else{ /* Neither operand is NULL. Do a comparison. */ @@ -69479,16 +68384,14 @@ pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = res; REGISTER_TRACE(pOp->p2, pOut); - }else{ - VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); - if( res ){ - pc = pOp->p2-1; - } + }else if( res ){ + pc = pOp->p2-1; } + /* Undo any changes made by applyAffinity() to the input registers. */ pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (flags1&MEM_TypeMask); pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (flags3&MEM_TypeMask); break; } @@ -69508,11 +68411,10 @@ aPermute = pOp->p4.ai; break; } /* Opcode: Compare P1 P2 P3 P4 P5 -** Synopsis: r[P1@P3] <-> r[P2@P3] ** ** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this ** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of ** the comparison for use by the next OP_Jump instruct. ** @@ -69582,15 +68484,15 @@ ** in the most recent OP_Compare instruction the P1 vector was less than ** equal to, or greater than the P2 vector, respectively. */ case OP_Jump: { /* jump */ if( iCompare<0 ){ - pc = pOp->p1 - 1; VdbeBranchTaken(0,3); + pc = pOp->p1 - 1; }else if( iCompare==0 ){ - pc = pOp->p2 - 1; VdbeBranchTaken(1,3); + pc = pOp->p2 - 1; }else{ - pc = pOp->p3 - 1; VdbeBranchTaken(2,3); + pc = pOp->p3 - 1; } break; } /* Opcode: And P1 P2 P3 * * @@ -69684,17 +68586,14 @@ } /* Opcode: Once P1 P2 * * * ** ** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise, -** set the flag and fall through to the next instruction. In other words, -** this opcode causes all following opcodes up through P2 (but not including -** P2) to run just once and to be skipped on subsequent times through the loop. +** set the flag and fall through to the next instruction. */ case OP_Once: { /* jump */ assert( pOp->p1nOnceFlag ); - VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2); if( p->aOnceFlag[pOp->p1] ){ pc = pOp->p2-1; }else{ p->aOnceFlag[pOp->p1] = 1; } @@ -69725,11 +68624,10 @@ #else c = sqlite3VdbeRealValue(pIn1)!=0.0; #endif if( pOp->opcode==OP_IfNot ) c = !c; } - VdbeBranchTaken(c!=0, 2); if( c ){ pc = pOp->p2-1; } break; } @@ -69739,11 +68637,10 @@ ** ** Jump to P2 if the value in register P1 is NULL. */ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ pIn1 = &aMem[pOp->p1]; - VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2); if( (pIn1->flags & MEM_Null)!=0 ){ pc = pOp->p2 - 1; } break; } @@ -69753,11 +68650,10 @@ ** ** Jump to P2 if the value in register P1 is not NULL. */ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ pIn1 = &aMem[pOp->p1]; - VdbeBranchTaken( (pIn1->flags & MEM_Null)==0, 2); if( (pIn1->flags & MEM_Null)==0 ){ pc = pOp->p2 - 1; } break; } @@ -69830,10 +68726,15 @@ if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){ if( pC->nullRow ){ if( pCrsr==0 ){ assert( pC->pseudoTableReg>0 ); pReg = &aMem[pC->pseudoTableReg]; + if( pC->multiPseudo ){ + sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem); + Deephemeralize(pDest); + goto op_column_out; + } assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); pC->payloadSize = pC->szRow = avail = pReg->n; pC->aRow = (u8*)pReg->z; }else{ @@ -69980,11 +68881,10 @@ ** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are ** all valid. */ assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); - assert( sqlite3VdbeCheckMemInvariants(pDest) ); if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ VdbeMemRelease(pDest); sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest); @@ -70018,12 +68918,12 @@ ** sqlite3VdbeMemFromBtree() call above) then transfer control of that ** dynamically allocated space over to the pDest structure. ** This prevents a memory copy. */ if( sMem.zMalloc ){ assert( sMem.z==sMem.zMalloc ); - assert( VdbeMemDynamic(pDest)==0 ); - assert( (pDest->flags & (MEM_Blob|MEM_Str))==0 || pDest->z==sMem.z ); + assert( !(pDest->flags & MEM_Dyn) ); + assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z ); pDest->flags &= ~(MEM_Ephem|MEM_Static); pDest->flags |= MEM_Term; pDest->z = sMem.z; pDest->zMalloc = sMem.zMalloc; } @@ -70056,10 +68956,11 @@ assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; while( (cAff = *(zAffinity++))!=0 ){ assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] ); assert( memIsValid(pIn1) ); + ExpandBlob(pIn1); applyAffinity(pIn1, cAff, encoding); pIn1++; } break; } @@ -70133,13 +69034,12 @@ */ assert( pData0<=pLast ); if( zAffinity ){ pRec = pData0; do{ - applyAffinity(pRec++, *(zAffinity++), encoding); - assert( zAffinity[0]==0 || pRec<=pLast ); - }while( zAffinity[0] ); + applyAffinity(pRec, *(zAffinity++), encoding); + }while( (++pRec)<=pLast ); } /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. */ @@ -70202,11 +69102,11 @@ assert( i==nHdr ); assert( j==nByte ); assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); pOut->n = (int)nByte; - pOut->flags = MEM_Blob; + pOut->flags = MEM_Blob | MEM_Dyn; pOut->xDel = 0; if( nZero ){ pOut->u.nZero = nZero; pOut->flags |= MEM_Zero; } @@ -70479,22 +69379,28 @@ rc = SQLITE_ERROR; } break; } -/* Opcode: Transaction P1 P2 P3 P4 P5 +/* Opcode: Transaction P1 P2 * * * ** -** Begin a transaction on database P1 if a transaction is not already -** active. -** If P2 is non-zero, then a write-transaction is started, or if a -** read-transaction is already active, it is upgraded to a write-transaction. -** If P2 is zero, then a read-transaction is started. +** Begin a transaction. The transaction ends when a Commit or Rollback +** opcode is encountered. Depending on the ON CONFLICT setting, the +** transaction might also be rolled back if an error is encountered. ** ** P1 is the index of the database file on which the transaction is ** started. Index 0 is the main database file and index 1 is the ** file used for temporary tables. Indices of 2 or more are used for ** attached databases. +** +** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is +** obtained on the database file when a write-transaction is started. No +** other process can start another write transaction while this transaction is +** underway. Starting a write transaction also creates a rollback journal. A +** write transaction must be started before any changes can be made to the +** database. If P2 is greater than or equal to 2 then an EXCLUSIVE lock is +** also obtained on the file. ** ** If a write-transaction is started and the Vdbe.usesStmtJournal flag is ** true (this flag is set if the Vdbe may modify more than one row and may ** throw an ABORT exception), a statement transaction may also be opened. ** More specifically, a statement transaction is opened iff the database @@ -70502,25 +69408,14 @@ ** active statements. A statement transaction allows the changes made by this ** VDBE to be rolled back after an error without having to roll back the ** entire transaction. If no error is encountered, the statement transaction ** will automatically commit when the VDBE halts. ** -** If P5!=0 then this opcode also checks the schema cookie against P3 -** and the schema generation counter against P4. -** The cookie changes its value whenever the database schema changes. -** This operation is used to detect when that the cookie has changed -** and that the current process needs to reread the schema. If the schema -** cookie in P3 differs from the schema cookie in the database header or -** if the schema generation counter in P4 differs from the current -** generation counter, then an SQLITE_SCHEMA error is raised and execution -** halts. The sqlite3_step() wrapper function might then reprepare the -** statement and rerun it from the beginning. +** If P2 is zero, then a read-lock is obtained on the database file. */ case OP_Transaction: { Btree *pBt; - int iMeta; - int iGen; assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); @@ -70560,39 +69455,10 @@ ** counter. If the statement transaction needs to be rolled back, ** the value of this counter needs to be restored too. */ p->nStmtDefCons = db->nDeferredCons; p->nStmtDefImmCons = db->nDeferredImmCons; } - - /* Gather the schema version number for checking */ - sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); - iGen = db->aDb[pOp->p1].pSchema->iGeneration; - }else{ - iGen = iMeta = 0; - } - assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); - if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){ - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); - /* If the schema-cookie from the database file matches the cookie - ** stored with the in-memory representation of the schema, do - ** not reload the schema from the database file. - ** - ** If virtual-tables are in use, this is not just an optimization. - ** Often, v-tables store their data in other SQLite tables, which - ** are queried from within xNext() and other v-table methods using - ** prepared queries. If such a query is out-of-date, we do not want to - ** discard the database schema, as the user code implementing the - ** v-table would have to be ready for the sqlite3_vtab structure itself - ** to be invalidated whenever sqlite3_step() is called from within - ** a v-table method. - */ - if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ - sqlite3ResetOneSchema(db, pOp->p1); - } - p->expired = 1; - rc = SQLITE_SCHEMA; } break; } /* Opcode: ReadCookie P1 P2 P3 * * @@ -70662,10 +69528,70 @@ sqlite3ExpirePreparedStatements(db); p->expired = 0; } break; } + +/* Opcode: VerifyCookie P1 P2 P3 * * +** +** Check the value of global database parameter number 0 (the +** schema version) and make sure it is equal to P2 and that the +** generation counter on the local schema parse equals P3. +** +** P1 is the database number which is 0 for the main database file +** and 1 for the file holding temporary tables and some higher number +** for auxiliary databases. +** +** The cookie changes its value whenever the database schema changes. +** This operation is used to detect when that the cookie has changed +** and that the current process needs to reread the schema. +** +** Either a transaction needs to have been started or an OP_Open needs +** to be executed (to establish a read lock) before this opcode is +** invoked. +*/ +case OP_VerifyCookie: { + int iMeta; + int iGen; + Btree *pBt; + + assert( pOp->p1>=0 && pOp->p1nDb ); + assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); + assert( p->bIsReader ); + pBt = db->aDb[pOp->p1].pBt; + if( pBt ){ + sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); + iGen = db->aDb[pOp->p1].pSchema->iGeneration; + }else{ + iGen = iMeta = 0; + } + if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){ + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); + /* If the schema-cookie from the database file matches the cookie + ** stored with the in-memory representation of the schema, do + ** not reload the schema from the database file. + ** + ** If virtual-tables are in use, this is not just an optimization. + ** Often, v-tables store their data in other SQLite tables, which + ** are queried from within xNext() and other v-table methods using + ** prepared queries. If such a query is out-of-date, we do not want to + ** discard the database schema, as the user code implementing the + ** v-table would have to be ready for the sqlite3_vtab structure itself + ** to be invalidated whenever sqlite3_step() is called from within + ** a v-table method. + */ + if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ + sqlite3ResetOneSchema(db, pOp->p1); + } + + p->expired = 1; + rc = SQLITE_SCHEMA; + } + break; +} /* Opcode: OpenRead P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** ** Open a read-only cursor for the database table whose root page is @@ -70844,11 +69770,10 @@ assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; - pCx->isEphemeral = 1; rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginTrans(pCx->pBt, 1); } @@ -70877,11 +69802,11 @@ } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); break; } -/* Opcode: SorterOpen P1 P2 * P4 * +/* Opcode: SorterOpen P1 * * P4 * ** ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large ** tables using an external merge-sort algorithm. */ @@ -70897,17 +69822,18 @@ assert( pCx->pKeyInfo->enc==ENC(db) ); rc = sqlite3VdbeSorterInit(db, pCx); break; } -/* Opcode: OpenPseudo P1 P2 P3 * * -** Synopsis: P3 columns in r[P2] +/* Opcode: OpenPseudo P1 P2 P3 * P5 +** Synopsis: content in r[P2@P3] ** ** Open a new cursor that points to a fake table that contains a single -** row of data. The content of that one row is the content of memory -** register P2. In other words, cursor P1 becomes an alias for the -** MEM_Blob content contained in register P2. +** row of data. The content of that one row in the content of memory +** register P2 when P5==0. In other words, cursor P1 becomes an alias for the +** MEM_Blob content contained in register P2. When P5==1, then the +** row is represented by P3 consecutive registers beginning with P2. ** ** A pseudo-table created by this opcode is used to hold a single ** row output from the sorter so that the row can be decomposed into ** individual columns using the OP_Column opcode. The OP_Column opcode ** is the only cursor opcode that works with a pseudo-table. @@ -70923,11 +69849,11 @@ pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->pseudoTableReg = pOp->p2; pCx->isTable = 1; - assert( pOp->p5==0 ); + pCx->multiPseudo = pOp->p5; break; } /* Opcode: Close P1 * * * * ** @@ -70951,11 +69877,11 @@ ** ** Reposition cursor P1 so that it points to the smallest entry that ** is greater than or equal to the key value. If there are no records ** greater than or equal to the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, SeekLt, SeekGt, SeekLe +** See also: Found, NotFound, Distinct, SeekLt, SeekGt, SeekLe */ /* Opcode: SeekGt P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -70965,11 +69891,11 @@ ** ** Reposition cursor P1 so that it points to the smallest entry that ** is greater than the key value. If there are no records greater than ** the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, SeekLt, SeekGe, SeekLe +** See also: Found, NotFound, Distinct, SeekLt, SeekGe, SeekLe */ /* Opcode: SeekLt P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -70979,11 +69905,11 @@ ** ** Reposition cursor P1 so that it points to the largest entry that ** is less than the key value. If there are no records less than ** the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, SeekGt, SeekGe, SeekLe +** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLe */ /* Opcode: SeekLe P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -70993,16 +69919,16 @@ ** ** Reposition cursor P1 so that it points to the largest entry that ** is less than or equal to the key value. If there are no records ** less than or equal to the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, SeekGt, SeekGe, SeekLt +** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLt */ -case OP_SeekLT: /* jump, in3 */ -case OP_SeekLE: /* jump, in3 */ -case OP_SeekGE: /* jump, in3 */ -case OP_SeekGT: { /* jump, in3 */ +case OP_SeekLt: /* jump, in3 */ +case OP_SeekLe: /* jump, in3 */ +case OP_SeekGe: /* jump, in3 */ +case OP_SeekGt: { /* jump, in3 */ int res; int oc; VdbeCursor *pC; UnpackedRecord r; int nField; @@ -71011,13 +69937,13 @@ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p2!=0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pseudoTableReg==0 ); - assert( OP_SeekLE == OP_SeekLT+1 ); - assert( OP_SeekGE == OP_SeekLT+2 ); - assert( OP_SeekGT == OP_SeekLT+3 ); + assert( OP_SeekLe == OP_SeekLt+1 ); + assert( OP_SeekGe == OP_SeekLt+2 ); + assert( OP_SeekGt == OP_SeekLt+3 ); assert( pC->isOrdered ); assert( pC->pCursor!=0 ); oc = pOp->opcode; pC->nullRow = 0; if( pC->isTable ){ @@ -71033,11 +69959,11 @@ ** loss of information, then special processing is required... */ if( (pIn3->flags & MEM_Int)==0 ){ if( (pIn3->flags & MEM_Real)==0 ){ /* If the P3 value cannot be converted into any kind of a number, ** then the seek is not possible, so jump to P2 */ - pc = pOp->p2 - 1; VdbeBranchTaken(1,2); + pc = pOp->p2 - 1; break; } /* If the approximation iKey is larger than the actual real search ** term, substitute >= for > and < for <=. e.g. if the search term @@ -71045,23 +69971,23 @@ ** ** (x > 4.9) -> (x >= 5) ** (x <= 4.9) -> (x < 5) */ if( pIn3->r<(double)iKey ){ - assert( OP_SeekGE==(OP_SeekGT-1) ); - assert( OP_SeekLT==(OP_SeekLE-1) ); - assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); - if( (oc & 0x0001)==(OP_SeekGT & 0x0001) ) oc--; + assert( OP_SeekGe==(OP_SeekGt-1) ); + assert( OP_SeekLt==(OP_SeekLe-1) ); + assert( (OP_SeekLe & 0x0001)==(OP_SeekGt & 0x0001) ); + if( (oc & 0x0001)==(OP_SeekGt & 0x0001) ) oc--; } /* If the approximation iKey is smaller than the actual real search ** term, substitute <= for < and > for >=. */ else if( pIn3->r>(double)iKey ){ - assert( OP_SeekLE==(OP_SeekLT+1) ); - assert( OP_SeekGT==(OP_SeekGE+1) ); - assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); - if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; + assert( OP_SeekLe==(OP_SeekLt+1) ); + assert( OP_SeekGt==(OP_SeekGe+1) ); + assert( (OP_SeekLt & 0x0001)==(OP_SeekGe & 0x0001) ); + if( (oc & 0x0001)==(OP_SeekLt & 0x0001) ) oc++; } } rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; @@ -71076,21 +70002,21 @@ assert( nField>0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)nField; /* The next line of code computes as follows, only faster: - ** if( oc==OP_SeekGT || oc==OP_SeekLE ){ - ** r.default_rc = -1; + ** if( oc==OP_SeekGt || oc==OP_SeekLe ){ + ** r.flags = UNPACKED_INCRKEY; ** }else{ - ** r.default_rc = +1; + ** r.flags = 0; ** } */ - r.default_rc = ((1 & (oc - OP_SeekLT)) ? -1 : +1); - assert( oc!=OP_SeekGT || r.default_rc==-1 ); - assert( oc!=OP_SeekLE || r.default_rc==-1 ); - assert( oc!=OP_SeekGE || r.default_rc==+1 ); - assert( oc!=OP_SeekLT || r.default_rc==+1 ); + r.flags = (u8)(UNPACKED_INCRKEY * (1 & (oc - OP_SeekLt))); + assert( oc!=OP_SeekGt || r.flags==UNPACKED_INCRKEY ); + assert( oc!=OP_SeekLe || r.flags==UNPACKED_INCRKEY ); + assert( oc!=OP_SeekGe || r.flags==0 ); + assert( oc!=OP_SeekLt || r.flags==0 ); r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; ideferredMoveto = 0; pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_TEST sqlite3_search_count++; #endif - if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT ); - if( res<0 || (res==0 && oc==OP_SeekGT) ){ - res = 0; + if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt ); + if( res<0 || (res==0 && oc==OP_SeekGt) ){ rc = sqlite3BtreeNext(pC->pCursor, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; pC->rowidIsValid = 0; }else{ res = 0; } }else{ - assert( oc==OP_SeekLT || oc==OP_SeekLE ); - if( res>0 || (res==0 && oc==OP_SeekLT) ){ - res = 0; + assert( oc==OP_SeekLt || oc==OP_SeekLe ); + if( res>0 || (res==0 && oc==OP_SeekLt) ){ rc = sqlite3BtreePrevious(pC->pCursor, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; pC->rowidIsValid = 0; }else{ /* res might be negative because the table is empty. Check to @@ -71128,11 +70052,10 @@ */ res = sqlite3BtreeEof(pC->pCursor); } } assert( pOp->p2>0 ); - VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; } break; } @@ -71237,35 +70160,38 @@ pFree = 0; /* Not needed. Only used to suppress a compiler warning. */ if( pOp->p4.i>0 ){ r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; r.aMem = pIn3; - for(ii=0; iip3+ii, &r.aMem[ii]); + { + int i; + for(i=0; ip3+i, &r.aMem[i]); + } + } #endif - } + r.flags = UNPACKED_PREFIX_MATCH; pIdxKey = &r; }else{ pIdxKey = sqlite3VdbeAllocUnpackedRecord( pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree ); if( pIdxKey==0 ) goto no_mem; assert( pIn3->flags & MEM_Blob ); assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); + pIdxKey->flags |= UNPACKED_PREFIX_MATCH; } - pIdxKey->default_rc = 0; if( pOp->opcode==OP_NoConflict ){ /* For the OP_NoConflict opcode, take the jump if any of the ** input fields are NULL, since any key with a NULL will not ** conflict */ for(ii=0; iip2 - 1; VdbeBranchTaken(1,2); + pc = pOp->p2 - 1; break; } } } rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res); @@ -71279,14 +70205,12 @@ alreadyExists = (res==0); pC->nullRow = 1-alreadyExists; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; if( pOp->opcode==OP_Found ){ - VdbeBranchTaken(alreadyExists!=0,2); if( alreadyExists ) pc = pOp->p2 - 1; }else{ - VdbeBranchTaken(alreadyExists==0,2); if( !alreadyExists ) pc = pOp->p2 - 1; } break; } @@ -71325,21 +70249,20 @@ pC->lastRowid = pIn3->u.i; pC->rowidIsValid = res==0 ?1:0; pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; - VdbeBranchTaken(res!=0,2); if( res!=0 ){ pc = pOp->p2 - 1; assert( pC->rowidIsValid==0 ); } pC->seekResult = res; break; } /* Opcode: Sequence P1 P2 * * * -** Synopsis: r[P2]=cursor[P1].ctr++ +** Synopsis: r[P2]=rowid ** ** Find the next available sequence number for cursor P1. ** Write the sequence number into register P2. ** The sequence number on the cursor is incremented after this ** instruction. @@ -71407,58 +70330,63 @@ */ # define MAX_ROWID (i64)( (((u64)0x7fffffff)<<32) | (u64)0xffffffff ) #endif if( !pC->useRandomRowid ){ - rc = sqlite3BtreeLast(pC->pCursor, &res); - if( rc!=SQLITE_OK ){ - goto abort_due_to_error; - } - if( res ){ - v = 1; /* IMP: R-61914-48074 */ - }else{ - assert( sqlite3BtreeCursorIsValid(pC->pCursor) ); - rc = sqlite3BtreeKeySize(pC->pCursor, &v); - assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ - if( v>=MAX_ROWID ){ - pC->useRandomRowid = 1; - }else{ - v++; /* IMP: R-29538-34987 */ - } - } - } - -#ifndef SQLITE_OMIT_AUTOINCREMENT - if( pOp->p3 ){ - /* Assert that P3 is a valid memory cell. */ - assert( pOp->p3>0 ); - if( p->pFrame ){ - for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); - /* Assert that P3 is a valid memory cell. */ - assert( pOp->p3<=pFrame->nMem ); - pMem = &pFrame->aMem[pOp->p3]; - }else{ - /* Assert that P3 is a valid memory cell. */ - assert( pOp->p3<=(p->nMem-p->nCursor) ); - pMem = &aMem[pOp->p3]; - memAboutToChange(p, pMem); - } - assert( memIsValid(pMem) ); - - REGISTER_TRACE(pOp->p3, pMem); - sqlite3VdbeMemIntegerify(pMem); - assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ - if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ - rc = SQLITE_FULL; /* IMP: R-12275-61338 */ - goto abort_due_to_error; - } - if( vu.i+1 ){ - v = pMem->u.i + 1; - } - pMem->u.i = v; - } -#endif + v = sqlite3BtreeGetCachedRowid(pC->pCursor); + if( v==0 ){ + rc = sqlite3BtreeLast(pC->pCursor, &res); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } + if( res ){ + v = 1; /* IMP: R-61914-48074 */ + }else{ + assert( sqlite3BtreeCursorIsValid(pC->pCursor) ); + rc = sqlite3BtreeKeySize(pC->pCursor, &v); + assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ + if( v>=MAX_ROWID ){ + pC->useRandomRowid = 1; + }else{ + v++; /* IMP: R-29538-34987 */ + } + } + } + +#ifndef SQLITE_OMIT_AUTOINCREMENT + if( pOp->p3 ){ + /* Assert that P3 is a valid memory cell. */ + assert( pOp->p3>0 ); + if( p->pFrame ){ + for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); + /* Assert that P3 is a valid memory cell. */ + assert( pOp->p3<=pFrame->nMem ); + pMem = &pFrame->aMem[pOp->p3]; + }else{ + /* Assert that P3 is a valid memory cell. */ + assert( pOp->p3<=(p->nMem-p->nCursor) ); + pMem = &aMem[pOp->p3]; + memAboutToChange(p, pMem); + } + assert( memIsValid(pMem) ); + + REGISTER_TRACE(pOp->p3, pMem); + sqlite3VdbeMemIntegerify(pMem); + assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ + if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ + rc = SQLITE_FULL; /* IMP: R-12275-61338 */ + goto abort_due_to_error; + } + if( vu.i+1 ){ + v = pMem->u.i + 1; + } + pMem->u.i = v; + } +#endif + + sqlite3BtreeSetCachedRowid(pC->pCursor, vuseRandomRowid ){ /* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the ** largest possible integer (9223372036854775807) then the database ** engine starts picking positive candidate ROWIDs at random until ** it finds one that is not previously used. */ @@ -71588,10 +70516,11 @@ if( pData->flags & MEM_Zero ){ nZero = pData->u.nZero; }else{ nZero = 0; } + sqlite3BtreeSetCachedRowid(pC->pCursor, 0); rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pData->z, pData->n, nZero, (pOp->p5 & OPFLAG_APPEND)!=0, seekResult ); pC->rowidIsValid = 0; @@ -71649,10 +70578,11 @@ **/ assert( pC->deferredMoveto==0 ); rc = sqlite3VdbeCursorMoveto(pC); if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; + sqlite3BtreeSetCachedRowid(pC->pCursor, 0); rc = sqlite3BtreeDelete(pC->pCursor); pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){ @@ -71700,11 +70630,10 @@ assert( isSorter(pC) ); assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; nIgnore = pOp->p4.i; rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res); - VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2-1; } break; }; @@ -71719,11 +70648,10 @@ pOut = &aMem[pOp->p2]; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); rc = sqlite3VdbeSorterRowkey(pC, pOut); - assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); break; } /* Opcode: RowData P1 P2 * * * ** Synopsis: r[P2]=data @@ -71739,11 +70667,11 @@ /* Opcode: RowKey P1 P2 * * * ** Synopsis: r[P2]=key ** ** Write into register P2 the complete row key for cursor P1. ** There is no interpretation of the data. -** The key is copied onto the P2 register exactly as +** The key is copied onto the P3 register exactly as ** it is found in the database file. ** ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. */ @@ -71901,13 +70829,12 @@ rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->rowidIsValid = 0; pC->cacheStatus = CACHE_STALE; - if( pOp->p2>0 ){ - VdbeBranchTaken(res!=0,2); - if( res ) pc = pOp->p2 - 1; + if( pOp->p2>0 && res ){ + pc = pOp->p2 - 1; } break; } @@ -71960,67 +70887,56 @@ pC->cacheStatus = CACHE_STALE; pC->rowidIsValid = 0; } pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2nOp ); - VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; } break; } -/* Opcode: Next P1 P2 P3 P4 P5 +/* Opcode: Next P1 P2 * * P5 ** ** Advance cursor P1 so that it points to the next key/data pair in its ** table or index. If there are no more key/value pairs then fall through ** to the following instruction. But if the cursor advance was successful, ** jump immediately to P2. ** ** The P1 cursor must be for a real table, not a pseudo-table. P1 must have ** been opened prior to this opcode or the program will segfault. ** -** The P3 value is a hint to the btree implementation. If P3==1, that -** means P1 is an SQL index and that this instruction could have been -** omitted if that index had been unique. P3 is usually 0. P3 is -** always either 0 or 1. -** ** P4 is always of type P4_ADVANCE. The function pointer points to ** sqlite3BtreeNext(). ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. ** ** See also: Prev, NextIfOpen */ -/* Opcode: NextIfOpen P1 P2 P3 P4 P5 +/* Opcode: NextIfOpen P1 P2 * * P5 ** ** This opcode works just like OP_Next except that if cursor P1 is not ** open it behaves a no-op. */ -/* Opcode: Prev P1 P2 P3 P4 P5 +/* Opcode: Prev P1 P2 * * P5 ** ** Back up cursor P1 so that it points to the previous key/data pair in its ** table or index. If there is no previous key/value pairs then fall through ** to the following instruction. But if the cursor backup was successful, ** jump immediately to P2. ** ** The P1 cursor must be for a real table, not a pseudo-table. If P1 is ** not open then the behavior is undefined. ** -** The P3 value is a hint to the btree implementation. If P3==1, that -** means P1 is an SQL index and that this instruction could have been -** omitted if that index had been unique. P3 is usually 0. P3 is -** always either 0 or 1. -** ** P4 is always of type P4_ADVANCE. The function pointer points to ** sqlite3BtreePrevious(). ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. */ -/* Opcode: PrevIfOpen P1 P2 P3 P4 P5 +/* Opcode: PrevIfOpen P1 P2 * * P5 ** ** This opcode works just like OP_Prev except that if cursor P1 is not ** open it behaves a no-op. */ case OP_SorterNext: { /* jump */ @@ -72027,11 +70943,10 @@ VdbeCursor *pC; int res; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); - res = 0; rc = sqlite3VdbeSorterNext(db, pC, &res); goto next_tail; case OP_PrevIfOpen: /* jump */ case OP_NextIfOpen: /* jump */ if( p->apCsr[pOp->p1]==0 ) break; @@ -72039,24 +70954,20 @@ case OP_Prev: /* jump */ case OP_Next: /* jump */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5aCounter) ); pC = p->apCsr[pOp->p1]; - res = pOp->p3; assert( pC!=0 ); assert( pC->deferredMoveto==0 ); assert( pC->pCursor ); - assert( res==0 || (res==1 && pC->isTable==0) ); - testcase( res==1 ); assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious); rc = pOp->p4.xAdvance(pC->pCursor, &res); next_tail: pC->cacheStatus = CACHE_STALE; - VdbeBranchTaken(res==0,2); if( res==0 ){ pC->nullRow = 0; pc = pOp->p2 - 1; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST @@ -72077,18 +70988,10 @@ ** into the index P1. Data for the entry is nil. ** ** P3 is a flag that provides a hint to the b-tree layer that this ** insert is likely to be an append. ** -** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is -** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear, -** then the change counter is unchanged. -** -** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have -** just done a seek to the spot where the new entry is to be inserted. -** This flag avoids doing an extra seek. -** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ case OP_SorterInsert: /* in2 */ case OP_IdxInsert: { /* in2 */ @@ -72145,11 +71048,11 @@ pCrsr = pC->pCursor; assert( pCrsr!=0 ); assert( pOp->p5==0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p3; - r.default_rc = 0; + r.flags = UNPACKED_PREFIX_MATCH; r.aMem = &aMem[pOp->p2]; #ifdef SQLITE_DEBUG { int i; for(i=0; ip1>=0 && pOp->p1nCursor ); @@ -72257,32 +71142,27 @@ assert( pC->deferredMoveto==0 ); assert( pOp->p5==0 || pOp->p5==1 ); assert( pOp->p4type==P4_INT32 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; - if( pOp->opcodeopcode==OP_IdxLE || pOp->opcode==OP_IdxGT ); - r.default_rc = -1; + if( pOp->p5 ){ + r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH; }else{ - assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT ); - r.default_rc = 0; + r.flags = UNPACKED_PREFIX_MATCH; } r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; iopcode&1)==(OP_IdxLT&1) ){ - assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); + if( pOp->opcode==OP_IdxLT ){ res = -res; }else{ - assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxGT ); + assert( pOp->opcode==OP_IdxGE ); res++; } - VdbeBranchTaken(res>0,2); if( res>0 ){ pc = pOp->p2 - 1 ; } break; } @@ -72371,10 +71251,11 @@ case OP_Clear: { int nChange; nChange = 0; assert( p->readOnly==0 ); + assert( pOp->p1!=1 ); assert( (p->btreeMask & (((yDbMask)1)<p2))!=0 ); rc = sqlite3BtreeClearTable( db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) ); if( pOp->p3 ){ @@ -72383,33 +71264,10 @@ assert( memIsValid(&aMem[pOp->p3]) ); memAboutToChange(p, &aMem[pOp->p3]); aMem[pOp->p3].u.i += nChange; } } - break; -} - -/* Opcode: ResetSorter P1 * * * * -** -** Delete all contents from the ephemeral table or sorter -** that is open on cursor P1. -** -** This opcode only works for cursors used for sorting and -** opened with OP_OpenEphemeral or OP_SorterOpen. -*/ -case OP_ResetSorter: { - VdbeCursor *pC; - - assert( pOp->p1>=0 && pOp->p1nCursor ); - pC = p->apCsr[pOp->p1]; - assert( pC!=0 ); - if( pC->pSorter ){ - sqlite3VdbeSorterReset(db, pC->pSorter); - }else{ - assert( pC->isEphemeral ); - rc = sqlite3BtreeClearTableOfCursor(pC->pCursor); - } break; } /* Opcode: CreateTable P1 P2 * * * ** Synopsis: r[P2]=root iDb=P1 @@ -72662,15 +71520,13 @@ || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0 ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); pc = pOp->p2 - 1; - VdbeBranchTaken(1,2); }else{ /* A value was pulled from the index */ sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val); - VdbeBranchTaken(0,2); } goto check_for_interrupt; } /* Opcode: RowSetTest P1 P2 P3 P4 @@ -72715,12 +71571,13 @@ } assert( pOp->p4type==P4_INT32 ); assert( iSet==-1 || iSet>=0 ); if( iSet ){ - exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); - VdbeBranchTaken(exists!=0,2); + exists = sqlite3RowSetTest(pIn1->u.pRowSet, + (u8)(iSet>=0 ? iSet & 0xf : 0xff), + pIn3->u.i); if( exists ){ pc = pOp->p2 - 1; break; } } @@ -72731,11 +71588,11 @@ } #ifndef SQLITE_OMIT_TRIGGER -/* Opcode: Program P1 P2 P3 P4 P5 +/* Opcode: Program P1 P2 P3 P4 * ** ** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). ** ** P1 contains the address of the memory cell that contains the first memory ** cell in an array of values used as arguments to the sub-program. P2 @@ -72743,12 +71600,10 @@ ** exception using the RAISE() function. Register P3 contains the address ** of a memory cell in this (the parent) VM that is used to allocate the ** memory required by the sub-vdbe at runtime. ** ** P4 is a pointer to the VM containing the trigger program. -** -** If P5 is non-zero, then recursive program invocation is enabled. */ case OP_Program: { /* jump */ int nMem; /* Number of memory registers for sub-program */ int nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ @@ -72822,11 +71677,11 @@ pFrame->aOnceFlag = p->aOnceFlag; pFrame->nOnceFlag = p->nOnceFlag; pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ - pMem->flags = MEM_Undefined; + pMem->flags = MEM_Invalid; pMem->db = db; } }else{ pFrame = pRt->u.pFrame; assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem ); @@ -72909,14 +71764,12 @@ ** zero, the jump is taken if the statement constraint-counter is zero ** (immediate foreign key constraint violations). */ case OP_FkIfZero: { /* jump */ if( pOp->p1 ){ - VdbeBranchTaken(db->nDeferredCons==0 && db->nDeferredImmCons==0, 2); if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1; }else{ - VdbeBranchTaken(p->nFkConstraint==0 && db->nDeferredImmCons==0, 2); if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1; } break; } #endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */ @@ -72961,11 +71814,10 @@ ** not contain an integer. An assertion fault will result if you try. */ case OP_IfPos: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); - VdbeBranchTaken( pIn1->u.i>0, 2); if( pIn1->u.i>0 ){ pc = pOp->p2 - 1; } break; } @@ -72979,11 +71831,10 @@ ** not contain an integer. An assertion fault will result if you try. */ case OP_IfNeg: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); - VdbeBranchTaken(pIn1->u.i<0, 2); if( pIn1->u.i<0 ){ pc = pOp->p2 - 1; } break; } @@ -72999,11 +71850,10 @@ */ case OP_IfZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); pIn1->u.i += pOp->p3; - VdbeBranchTaken(pIn1->u.i==0, 2); if( pIn1->u.i==0 ){ pc = pOp->p2 - 1; } break; } @@ -73034,10 +71884,11 @@ assert( apVal || n==0 ); for(i=0; ip4.pFunc; assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); ctx.pMem = pMem = &aMem[pOp->p3]; pMem->n++; @@ -73136,11 +71987,11 @@ break; }; #endif #ifndef SQLITE_OMIT_PRAGMA -/* Opcode: JournalMode P1 P2 P3 * * +/* Opcode: JournalMode P1 P2 P3 * P5 ** ** Change the journal mode of database P1 to P3. P3 must be one of the ** PAGER_JOURNALMODE_XXX values. If changing between the various rollback ** modes (delete, truncate, persist, off and memory), this is a simple ** operation. No IO is required. @@ -73270,11 +72121,10 @@ assert( pOp->p1>=0 && pOp->p1nDb ); assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; rc = sqlite3BtreeIncrVacuum(pBt); - VdbeBranchTaken(rc==SQLITE_DONE,2); if( rc==SQLITE_DONE ){ pc = pOp->p2 - 1; rc = SQLITE_OK; } break; @@ -73415,11 +72265,11 @@ } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VFilter P1 P2 P3 P4 * -** Synopsis: iplan=r[P3] zplan='P4' +** Synopsis: iPlan=r[P3] zPlan='P4' ** ** P1 is a cursor opened using VOpen. P2 is an address to jump to if ** the filtered result set is empty. ** ** P4 is either NULL or a string that was generated by the xBestIndex @@ -73467,20 +72317,21 @@ { res = 0; apArg = p->apArg; for(i = 0; iinVtabMethod = 1; rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg); p->inVtabMethod = 0; sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK ){ res = pModule->xEof(pVtabCursor); } - VdbeBranchTaken(res!=0,2); + if( res ){ pc = pOp->p2 - 1; } } pCur->nullRow = 0; @@ -73581,11 +72432,11 @@ p->inVtabMethod = 0; sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK ){ res = pModule->xEof(pCur->pVtabCursor); } - VdbeBranchTaken(!res,2); + if( !res ){ /* If there is data, jump to P2 */ pc = pOp->p2 - 1; } goto check_for_interrupt; @@ -73622,11 +72473,11 @@ break; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE -/* Opcode: VUpdate P1 P2 P3 P4 P5 +/* Opcode: VUpdate P1 P2 P3 P4 * ** Synopsis: data=r[P3@P2] ** ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** This opcode invokes the corresponding xUpdate method. P2 values ** are contiguous memory cells starting at P3 to pass to the xUpdate @@ -73645,13 +72496,10 @@ ** a row to delete. ** ** P1 is a boolean flag. If it is set to true and the xUpdate call ** is successful, then the value returned by sqlite3_last_insert_rowid() ** is set to the value of the rowid for the row just inserted. -** -** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to -** apply in the case of a constraint failure on an insert or update. */ case OP_VUpdate: { sqlite3_vtab *pVtab; sqlite3_module *pModule; int nArg; @@ -73673,10 +72521,11 @@ apArg = p->apArg; pX = &aMem[pOp->p3]; for(i=0; ivtabOnConflict = pOp->p5; rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); @@ -73735,30 +72584,20 @@ break; } #endif -/* Opcode: Init * P2 * P4 * -** Synopsis: Start at P2 -** -** Programs contain a single instance of this opcode as the very first -** opcode. +#ifndef SQLITE_OMIT_TRACE +/* Opcode: Trace * * * P4 * ** ** If tracing is enabled (by the sqlite3_trace()) interface, then ** the UTF-8 string contained in P4 is emitted on the trace callback. -** Or if P4 is blank, use the string returned by sqlite3_sql(). -** -** If P2 is not zero, jump to instruction P2. */ -case OP_Init: { /* jump */ +case OP_Trace: { char *zTrace; char *z; - if( pOp->p2 ){ - pc = pOp->p2 - 1; - } -#ifndef SQLITE_OMIT_TRACE if( db->xTrace && !p->doingRerun && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ z = sqlite3VdbeExpandSql(p, zTrace); @@ -73768,11 +72607,11 @@ #ifdef SQLITE_USE_FCNTL_TRACE zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); if( zTrace ){ int i; for(i=0; inDb; i++){ - if( (MASKBIT(i) & p->btreeMask)==0 ) continue; + if( MASKBIT(i) & p->btreeMask)==0 ) continue; sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace); } } #endif /* SQLITE_USE_FCNTL_TRACE */ #ifdef SQLITE_DEBUG @@ -73780,13 +72619,13 @@ && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); } #endif /* SQLITE_DEBUG */ -#endif /* SQLITE_OMIT_TRACE */ break; } +#endif /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump @@ -73811,13 +72650,17 @@ *****************************************************************************/ } #ifdef VDBE_PROFILE { - u64 endTime = sqlite3Hwtime(); - if( endTime>start ) pOp->cycles += endTime - start; + u64 elapsed = sqlite3Hwtime() - start; + pOp->cycles += elapsed; pOp->cnt++; +#if 0 + fprintf(stdout, "%10llu ", elapsed); + sqlite3VdbePrintOp(stdout, origPc, &aOp[origPc]); +#endif } #endif /* The following code adds nothing to the actual functionality ** of the program. It is only here for testing and debugging. @@ -73983,11 +72826,13 @@ p->pStmt = 0; }else{ p->iOffset = pC->aType[p->iCol + pC->nField]; p->nByte = sqlite3VdbeSerialTypeLen(type); p->pCsr = pC->pCursor; - sqlite3BtreeIncrblobCursor(p->pCsr); + sqlite3BtreeEnterCursor(p->pCsr); + sqlite3BtreeCacheOverflow(p->pCsr); + sqlite3BtreeLeaveCursor(p->pCsr); } } if( rc==SQLITE_ROW ){ rc = SQLITE_OK; @@ -74037,24 +72882,26 @@ ** ** The sqlite3_blob_close() function finalizes the vdbe program, ** which closes the b-tree cursor and (possibly) commits the ** transaction. */ - static const int iLn = VDBE_OFFSET_LINENO(4); static const VdbeOpList openBlob[] = { - /* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */ - {OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */ + {OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */ + {OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */ + {OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */ + /* One of the following two instructions is replaced by an OP_Noop. */ - {OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */ - {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */ - {OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */ - {OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */ - {OP_Column, 0, 0, 1}, /* 6 */ - {OP_ResultRow, 1, 0, 0}, /* 7 */ - {OP_Goto, 0, 4, 0}, /* 8 */ - {OP_Close, 0, 0, 0}, /* 9 */ - {OP_Halt, 0, 0, 0}, /* 10 */ + {OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */ + {OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */ + + {OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */ + {OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */ + {OP_Column, 0, 0, 1}, /* 7 */ + {OP_ResultRow, 1, 0, 0}, /* 8 */ + {OP_Goto, 0, 5, 0}, /* 9 */ + {OP_Close, 0, 0, 0}, /* 10 */ + {OP_Halt, 0, 0, 0}, /* 11 */ }; int rc = SQLITE_OK; char *zErr = 0; Table *pTab; @@ -74163,45 +73010,50 @@ assert( pBlob->pStmt || db->mallocFailed ); if( pBlob->pStmt ){ Vdbe *v = (Vdbe *)pBlob->pStmt; int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob); - sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags, - pTab->pSchema->schema_cookie, - pTab->pSchema->iGeneration); - sqlite3VdbeChangeP5(v, 1); - sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); + + /* Configure the OP_Transaction */ + sqlite3VdbeChangeP1(v, 0, iDb); + sqlite3VdbeChangeP2(v, 0, flags); + + /* Configure the OP_VerifyCookie */ + sqlite3VdbeChangeP1(v, 1, iDb); + sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie); + sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration); /* Make sure a mutex is held on the table to be accessed */ sqlite3VdbeUsesBtree(v, iDb); /* Configure the OP_TableLock instruction */ #ifdef SQLITE_OMIT_SHARED_CACHE - sqlite3VdbeChangeToNoop(v, 1); + sqlite3VdbeChangeToNoop(v, 2); #else - sqlite3VdbeChangeP1(v, 1, iDb); - sqlite3VdbeChangeP2(v, 1, pTab->tnum); - sqlite3VdbeChangeP3(v, 1, flags); - sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT); + sqlite3VdbeChangeP1(v, 2, iDb); + sqlite3VdbeChangeP2(v, 2, pTab->tnum); + sqlite3VdbeChangeP3(v, 2, flags); + sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT); #endif /* Remove either the OP_OpenWrite or OpenRead. Set the P2 ** parameter of the other to pTab->tnum. */ - sqlite3VdbeChangeToNoop(v, 3 - flags); - sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum); - sqlite3VdbeChangeP3(v, 2 + flags, iDb); + sqlite3VdbeChangeToNoop(v, 4 - flags); + sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum); + sqlite3VdbeChangeP3(v, 3 + flags, iDb); /* Configure the number of columns. Configure the cursor to ** think that the table has one more column than it really ** does. An OP_Column to retrieve this imaginary column will ** always return an SQL NULL. This is useful because it means ** we can invoke OP_Column to fill in the vdbe cursors type ** and offset cache without causing any IO. */ - sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); - sqlite3VdbeChangeP2(v, 6, pTab->nCol); + sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); + sqlite3VdbeChangeP2(v, 7, pTab->nCol); if( !db->mallocFailed ){ pParse->nVar = 1; pParse->nMem = 1; pParse->nTab = 1; sqlite3VdbeMakeReady(v, pParse); @@ -74723,10 +73575,11 @@ nRead = (int)(pSorter->iWriteOff - iStart); } rc = sqlite3OsRead( pSorter->pTemp1, &pIter->aBuffer[iBuf], nRead, iStart ); + assert( rc!=SQLITE_IOERR_SHORT_READ ); } if( rc==SQLITE_OK ){ u64 nByte; /* Size of PMA in bytes */ pIter->iEof = pSorter->iWriteOff; @@ -74781,14 +73634,14 @@ if( r2->aMem[i].flags & MEM_Null ){ *pRes = -1; return; } } - assert( r2->default_rc==0 ); + r2->flags |= UNPACKED_PREFIX_MATCH; } - *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2, 0); + *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2); } /* ** This function is called to compare two iterator keys when merging ** multiple b-tree segments. Parameter iOut is the index of the aTree[] @@ -74875,45 +73728,28 @@ for(p=pRecord; p; p=pNext){ pNext = p->pNext; sqlite3DbFree(db, p); } } - -/* -** Reset a sorting cursor back to its original empty state. -*/ -SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ - if( pSorter->aIter ){ - int i; - for(i=0; inTree; i++){ - vdbeSorterIterZero(db, &pSorter->aIter[i]); - } - sqlite3DbFree(db, pSorter->aIter); - pSorter->aIter = 0; - } - if( pSorter->pTemp1 ){ - sqlite3OsCloseFree(pSorter->pTemp1); - pSorter->pTemp1 = 0; - } - vdbeSorterRecordFree(db, pSorter->pRecord); - pSorter->pRecord = 0; - pSorter->iWriteOff = 0; - pSorter->iReadOff = 0; - pSorter->nInMemory = 0; - pSorter->nTree = 0; - pSorter->nPMA = 0; - pSorter->aTree = 0; -} - /* ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. */ SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ VdbeSorter *pSorter = pCsr->pSorter; if( pSorter ){ - sqlite3VdbeSorterReset(db, pSorter); + if( pSorter->aIter ){ + int i; + for(i=0; inTree; i++){ + vdbeSorterIterZero(db, &pSorter->aIter[i]); + } + sqlite3DbFree(db, pSorter->aIter); + } + if( pSorter->pTemp1 ){ + sqlite3OsCloseFree(pSorter->pTemp1); + } + vdbeSorterRecordFree(db, pSorter->pRecord); sqlite3DbFree(db, pSorter->pUnpacked); sqlite3DbFree(db, pSorter); pCsr->pSorter = 0; } } @@ -75345,59 +74181,18 @@ VdbeSorter *pSorter = pCsr->pSorter; int rc; /* Return code */ if( pSorter->aTree ){ int iPrev = pSorter->aTree[1];/* Index of iterator to advance */ + int i; /* Index of aTree[] to recalculate */ + rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]); - if( rc==SQLITE_OK ){ - int i; /* Index of aTree[] to recalculate */ - VdbeSorterIter *pIter1; /* First iterator to compare */ - VdbeSorterIter *pIter2; /* Second iterator to compare */ - u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */ - - /* Find the first two iterators to compare. The one that was just - ** advanced (iPrev) and the one next to it in the array. */ - pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)]; - pIter2 = &pSorter->aIter[(iPrev | 0x0001)]; - pKey2 = pIter2->aKey; - - for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){ - /* Compare pIter1 and pIter2. Store the result in variable iRes. */ - int iRes; - if( pIter1->pFile==0 ){ - iRes = +1; - }else if( pIter2->pFile==0 ){ - iRes = -1; - }else{ - vdbeSorterCompare(pCsr, 0, - pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes - ); - } - - /* If pIter1 contained the smaller value, set aTree[i] to its index. - ** Then set pIter2 to the next iterator to compare to pIter1. In this - ** case there is no cache of pIter2 in pSorter->pUnpacked, so set - ** pKey2 to point to the record belonging to pIter2. - ** - ** Alternatively, if pIter2 contains the smaller of the two values, - ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare() - ** was actually called above, then pSorter->pUnpacked now contains - ** a value equivalent to pIter2. So set pKey2 to NULL to prevent - ** vdbeSorterCompare() from decoding pIter2 again. */ - if( iRes<=0 ){ - pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter); - pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; - pKey2 = pIter2->aKey; - }else{ - if( pIter1->pFile ) pKey2 = 0; - pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter); - pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; - } - - } - *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); - } + for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){ + rc = vdbeSorterDoCompare(pCsr, i); + } + + *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); }else{ SorterRecord *pFree = pSorter->pRecord; pSorter->pRecord = pFree->pNext; pFree->pNext = 0; vdbeSorterRecordFree(db, pFree); @@ -76479,12 +75274,10 @@ pExpr->iTable = 1; pTab = pParse->pTriggerTab; }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){ pExpr->iTable = 0; pTab = pParse->pTriggerTab; - }else{ - pTab = 0; } if( pTab ){ int iCol; pSchema = pTab->pSchema; @@ -76524,12 +75317,12 @@ #endif /* !defined(SQLITE_OMIT_TRIGGER) */ /* ** Perhaps the name is a reference to the ROWID */ - if( cnt==0 && cntTab==1 && pMatch && sqlite3IsRowid(zCol) - && HasRowid(pMatch->pTab) ){ + assert( pTab!=0 || cntTab==0 ); + if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) && HasRowid(pTab) ){ cnt = 1; pExpr->iColumn = -1; /* IMP: R-44911-55124 */ pExpr->affinity = SQLITE_AFF_INTEGER; } @@ -77629,11 +76422,10 @@ ** SELECT * FROM t1 WHERE (select a from t1); */ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ int op; pExpr = sqlite3ExprSkipCollate(pExpr); - if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE; op = pExpr->op; if( op==TK_SELECT ){ assert( pExpr->flags&EP_xIsSelect ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } @@ -77662,15 +76454,11 @@ ** implements the COLLATE operator. ** ** If a memory allocation error occurs, that fact is recorded in pParse->db ** and the pExpr parameter is returned unchanged. */ -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( - Parse *pParse, /* Parsing context */ - Expr *pExpr, /* Add the "COLLATE" clause to this expression */ - const Token *pCollName /* Name of collating sequence */ -){ +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){ if( pCollName->n>0 ){ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1); if( pNew ){ pNew->pLeft = pExpr; pNew->flags |= EP_Collate|EP_Skip; @@ -77719,11 +76507,10 @@ sqlite3 *db = pParse->db; CollSeq *pColl = 0; Expr *p = pExpr; while( p ){ int op = p->op; - if( p->flags & EP_Generic ) break; if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; } if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){ @@ -78551,10 +77338,11 @@ struct ExprList_item *pItem, *pOldItem; int i; if( p==0 ) return 0; pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); if( pNew==0 ) return 0; + pNew->iECursor = 0; pNew->nExpr = i = p->nExpr; if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; inExpr; i+=i){} pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) ); if( pItem==0 ){ sqlite3DbFree(db, pNew); @@ -78661,12 +77449,14 @@ pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags); pNew->iLimit = 0; pNew->iOffset = 0; pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; + pNew->pRightmost = 0; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; + pNew->addrOpenEphm[2] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = withDup(db, p->pWith); return pNew; } #else @@ -78968,10 +77758,28 @@ return 0; default: return 1; } } + +/* +** Generate an OP_IsNull instruction that tests register iReg and jumps +** to location iDest if the value in iReg is NULL. The value in iReg +** was computed by pExpr. If we can look at pExpr at compile-time and +** determine that it can never generate a NULL, then the OP_IsNull operation +** can be omitted. +*/ +SQLITE_PRIVATE void sqlite3ExprCodeIsNullJump( + Vdbe *v, /* The VDBE under construction */ + const Expr *pExpr, /* Only generate OP_IsNull if this expr can be NULL */ + int iReg, /* Test the value in this register for NULL */ + int iDest /* Jump here if the value is null */ +){ + if( sqlite3ExprCanBeNull(pExpr) ){ + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iDest); + } +} /* ** Return TRUE if the given expression is a constant which would be ** unchanged by OP_Affinity with the affinity given in the second ** argument. @@ -79165,11 +77973,11 @@ assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ pTab = p->pSrc->a[0].pTab; pExpr = p->pEList->a[0].pExpr; iCol = (i16)pExpr->iColumn; - /* Code an OP_Transaction and OP_TableLock for . */ + /* Code an OP_VerifyCookie and OP_TableLock for
. */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); /* This function is only called from two places. In both cases the vdbe @@ -79176,12 +77984,13 @@ ** has already been allocated. So assume sqlite3GetVdbe() is always ** successful here. */ assert(v); if( iCol<0 ){ - int iAddr = sqlite3CodeOnce(pParse); - VdbeCoverage(v); + int iAddr; + + iAddr = sqlite3CodeOnce(pParse); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; sqlite3VdbeJumpHere(v, iAddr); @@ -79202,22 +78011,22 @@ for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){ if( (pIdx->aiColumn[0]==iCol) && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq && (!mustBeUnique || (pIdx->nKeyCol==1 && pIdx->onError!=OE_None)) ){ - int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); + int iAddr = sqlite3CodeOnce(pParse); sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; + sqlite3VdbeJumpHere(v, iAddr); if( prNotFound && !pTab->aCol[iCol].notNull ){ *prNotFound = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); } - sqlite3VdbeJumpHere(v, iAddr); } } } } @@ -79230,10 +78039,11 @@ eType = IN_INDEX_EPH; if( prNotFound ){ *prNotFound = rMayHaveNull = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); }else{ + testcase( pParse->nQueryLoop>0 ); pParse->nQueryLoop = 0; if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ eType = IN_INDEX_ROWID; } } @@ -79301,11 +78111,11 @@ ** ** If all of the above are false, then we can run this code just once ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasProperty(pExpr, EP_VarSelect) ){ - testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); + testAddr = sqlite3CodeOnce(pParse); } #ifndef SQLITE_OMIT_EXPLAIN if( pParse->explain==2 ){ char *zMsg = sqlite3MPrintf( @@ -79342,10 +78152,11 @@ ** 'x' nor the SELECT... statement are columns, then numeric affinity ** is used. */ pExpr->iTable = pParse->nTab++; addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid); + if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED); pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* Case 1: expr IN (SELECT ...) ** @@ -79417,11 +78228,10 @@ }else{ r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); if( isRowid ){ sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3); }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); sqlite3ExprCacheAffinityChange(pParse, r3, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2); @@ -79479,11 +78289,11 @@ } if( testAddr>=0 ){ sqlite3VdbeJumpHere(v, testAddr); } - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); return rReg; } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -79541,25 +78351,23 @@ ** on whether the RHS is empty or not, respectively. */ if( destIfNull==destIfFalse ){ /* Shortcut for the common case where the false and NULL outcomes are ** the same. */ - sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); }else{ - int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); + int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); - VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); sqlite3VdbeJumpHere(v, addr1); } if( eType==IN_INDEX_ROWID ){ /* In this case, the RHS is the ROWID of table b-tree */ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); - VdbeCoverage(v); }else{ /* In this case, the RHS is an index b-tree. */ sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); @@ -79576,49 +78384,51 @@ ** ** Also run this branch if NULL is equivalent to FALSE ** for this particular IN operator. */ sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1); - VdbeCoverage(v); + }else{ /* In this branch, the RHS of the IN might contain a NULL and ** the presence of a NULL on the RHS makes a difference in the ** outcome. */ - int j1, j2; + int j1, j2, j3; /* First check to see if the LHS is contained in the RHS. If so, ** then the presence of NULLs in the RHS does not matter, so jump ** over all of the code that follows. */ j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); - VdbeCoverage(v); /* Here we begin generating code that runs if the LHS is not ** contained within the RHS. Generate additional code that ** tests the RHS for NULLs. If the RHS contains a NULL then ** jump to destIfNull. If there are no NULLs in the RHS then ** jump to destIfFalse. */ - sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_IfNot, rRhsHasNull, destIfFalse); VdbeCoverage(v); - j2 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Integer, 0, rRhsHasNull); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + j2 = sqlite3VdbeAddOp1(v, OP_NotNull, rRhsHasNull); + j3 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1); + sqlite3VdbeAddOp2(v, OP_Integer, -1, rRhsHasNull); + sqlite3VdbeJumpHere(v, j3); + sqlite3VdbeAddOp2(v, OP_AddImm, rRhsHasNull, 1); sqlite3VdbeJumpHere(v, j2); - sqlite3VdbeAddOp2(v, OP_Integer, 1, rRhsHasNull); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); + + /* Jump to the appropriate target depending on whether or not + ** the RHS contains a NULL + */ + sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); /* The OP_Found at the top of this branch jumps here when true, ** causing the overall IN expression evaluation to fall through. */ sqlite3VdbeJumpHere(v, j1); } } sqlite3ReleaseTempReg(pParse, r1); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); VdbeComment((v, "end IN expr")); } #endif /* SQLITE_OMIT_SUBQUERY */ /* @@ -79797,18 +78607,19 @@ #endif } /* ** Remove from the column cache any entries that were added since the -** the previous sqlite3ExprCachePush operation. In other words, restore -** the cache to the state it was in prior the most recent Push. +** the previous N Push operations. In other words, restore the cache +** to the state it was in N Pushes ago. */ -SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){ +SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse, int N){ int i; struct yColCache *p; - assert( pParse->iCacheLevel>=1 ); - pParse->iCacheLevel--; + assert( N>0 ); + assert( pParse->iCacheLevel>=N ); + pParse->iCacheLevel -= N; #ifdef SQLITE_DEBUG if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ printf("POP to %d\n", pParse->iCacheLevel); } #endif @@ -79933,11 +78744,11 @@ */ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ int i; struct yColCache *p; assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); - sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); + sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1); for(i=0, p=pParse->aColCache; iiReg; if( x>=iFrom && xiReg += iTo-iFrom; } @@ -80125,20 +78936,26 @@ case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { + assert( TK_LT==OP_Lt ); + assert( TK_LE==OP_Le ); + assert( TK_GT==OP_Gt ); + assert( TK_GE==OP_Ge ); + assert( TK_EQ==OP_Eq ); + assert( TK_NE==OP_Ne ); + testcase( op==TK_LT ); + testcase( op==TK_LE ); + testcase( op==TK_GT ); + testcase( op==TK_GE ); + testcase( op==TK_EQ ); + testcase( op==TK_NE ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2); - assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); - assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); - assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); - assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); - assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); - assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_IS: @@ -80148,12 +78965,10 @@ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); op = (op==TK_IS) ? TK_EQ : TK_NE; codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ); - VdbeCoverageIf(v, op==TK_EQ); - VdbeCoverageIf(v, op==TK_NE); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_AND: @@ -80166,21 +78981,32 @@ case TK_BITOR: case TK_SLASH: case TK_LSHIFT: case TK_RSHIFT: case TK_CONCAT: { - assert( TK_AND==OP_And ); testcase( op==TK_AND ); - assert( TK_OR==OP_Or ); testcase( op==TK_OR ); - assert( TK_PLUS==OP_Add ); testcase( op==TK_PLUS ); - assert( TK_MINUS==OP_Subtract ); testcase( op==TK_MINUS ); - assert( TK_REM==OP_Remainder ); testcase( op==TK_REM ); - assert( TK_BITAND==OP_BitAnd ); testcase( op==TK_BITAND ); - assert( TK_BITOR==OP_BitOr ); testcase( op==TK_BITOR ); - assert( TK_SLASH==OP_Divide ); testcase( op==TK_SLASH ); - assert( TK_LSHIFT==OP_ShiftLeft ); testcase( op==TK_LSHIFT ); - assert( TK_RSHIFT==OP_ShiftRight ); testcase( op==TK_RSHIFT ); - assert( TK_CONCAT==OP_Concat ); testcase( op==TK_CONCAT ); + assert( TK_AND==OP_And ); + assert( TK_OR==OP_Or ); + assert( TK_PLUS==OP_Add ); + assert( TK_MINUS==OP_Subtract ); + assert( TK_REM==OP_Remainder ); + assert( TK_BITAND==OP_BitAnd ); + assert( TK_BITOR==OP_BitOr ); + assert( TK_SLASH==OP_Divide ); + assert( TK_LSHIFT==OP_ShiftLeft ); + assert( TK_RSHIFT==OP_ShiftRight ); + assert( TK_CONCAT==OP_Concat ); + testcase( op==TK_AND ); + testcase( op==TK_OR ); + testcase( op==TK_PLUS ); + testcase( op==TK_MINUS ); + testcase( op==TK_REM ); + testcase( op==TK_BITAND ); + testcase( op==TK_BITOR ); + testcase( op==TK_SLASH ); + testcase( op==TK_LSHIFT ); + testcase( op==TK_RSHIFT ); + testcase( op==TK_CONCAT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); sqlite3VdbeAddOp3(v, op, r2, r1, target); testcase( regFree1==0 ); testcase( regFree2==0 ); @@ -80208,29 +79034,31 @@ inReg = target; break; } case TK_BITNOT: case TK_NOT: { - assert( TK_BITNOT==OP_BitNot ); testcase( op==TK_BITNOT ); - assert( TK_NOT==OP_Not ); testcase( op==TK_NOT ); + assert( TK_BITNOT==OP_BitNot ); + assert( TK_NOT==OP_Not ); + testcase( op==TK_BITNOT ); + testcase( op==TK_NOT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); inReg = target; sqlite3VdbeAddOp2(v, op, r1, inReg); break; } case TK_ISNULL: case TK_NOTNULL: { int addr; - assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); - assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); + assert( TK_ISNULL==OP_IsNull ); + assert( TK_NOTNULL==OP_NotNull ); + testcase( op==TK_ISNULL ); + testcase( op==TK_NOTNULL ); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); addr = sqlite3VdbeAddOp1(v, op, r1); - VdbeCoverageIf(v, op==TK_ISNULL); - VdbeCoverageIf(v, op==TK_NOTNULL); sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeJumpHere(v, addr); break; } case TK_AGG_FUNCTION: { @@ -80278,15 +79106,14 @@ int endCoalesce = sqlite3VdbeMakeLabel(v); assert( nFarg>=2 ); sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); for(i=1; ia[i].pExpr, target); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); } sqlite3VdbeResolveLabel(v, endCoalesce); break; } @@ -80334,13 +79161,13 @@ pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG); } } sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ - sqlite3ExprCodeExprList(pParse, pFarg, r1, + sqlite3ExprCodeExprList(pParse, pFarg, r1, SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); - sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */ + sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */ }else{ r1 = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Possibly overload the function if the first argument is @@ -80416,18 +79243,17 @@ testcase( regFree1==0 ); testcase( regFree2==0 ); r3 = sqlite3GetTempReg(pParse); r4 = sqlite3GetTempReg(pParse); codeCompare(pParse, pLeft, pRight, OP_Ge, - r1, r2, r3, SQLITE_STOREP2); VdbeCoverage(v); + r1, r2, r3, SQLITE_STOREP2); pLItem++; pRight = pLItem->pExpr; sqlite3ReleaseTempReg(pParse, regFree2); r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2); testcase( regFree2==0 ); codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2); - VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_And, r3, r4, target); sqlite3ReleaseTempReg(pParse, r3); sqlite3ReleaseTempReg(pParse, r4); break; } @@ -80556,17 +79382,17 @@ testcase( pTest->op==TK_COLUMN ); sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ sqlite3ExprCachePush(pParse); sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } assert( db->mallocFailed || pParse->nErr>0 || pParse->iCacheLevel==iCacheLevel ); @@ -80590,11 +79416,10 @@ } assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->affinity==OE_Ignore ){ sqlite3VdbeAddOp4( v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); - VdbeCoverage(v); }else{ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER, pExpr->affinity, pExpr->u.zToken, 0, 0); } @@ -80678,11 +79503,11 @@ /* ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. */ -SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ +SQLITE_PRIVATE int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int inReg; assert( target>0 && target<=pParse->nMem ); if( pExpr && pExpr->op==TK_REGISTER ){ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target); @@ -80691,24 +79516,11 @@ assert( pParse->pVdbe || pParse->db->mallocFailed ); if( inReg!=target && pParse->pVdbe ){ sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target); } } -} - -/* -** Generate code that will evaluate expression pExpr and store the -** results in register target. The results are guaranteed to appear -** in register target. If the expression is constant, then this routine -** might choose to code the expression at initialization time. -*/ -SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ - if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){ - sqlite3ExprCodeAtInit(pParse, pExpr, target, 0); - }else{ - sqlite3ExprCode(pParse, pExpr, target); - } + return target; } /* ** Generate code that evalutes the given expression and puts the result ** in register target. @@ -80719,20 +79531,29 @@ ** ** This routine is used for expressions that are used multiple ** times. They are evaluated once and the results of the expression ** are reused. */ -SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ +SQLITE_PRIVATE int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; - int iMem; - + int inReg; + inReg = sqlite3ExprCode(pParse, pExpr, target); assert( target>0 ); - assert( pExpr->op!=TK_REGISTER ); - sqlite3ExprCode(pParse, pExpr, target); - iMem = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Copy, target, iMem); - exprToRegister(pExpr, iMem); + /* The only place, other than this routine, where expressions can be + ** converted to TK_REGISTER is internal subexpressions in BETWEEN and + ** CASE operators. Neither ever calls this routine. And this routine + ** is never called twice on the same expression. Hence it is impossible + ** for the input to this routine to already be a register. Nevertheless, + ** it seems prudent to keep the ALWAYS() in case the conditions above + ** change with future modifications or enhancements. */ + if( ALWAYS(pExpr->op!=TK_REGISTER) ){ + int iMem; + iMem = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem); + exprToRegister(pExpr, iMem); + } + return inReg; } #if defined(SQLITE_ENABLE_TREE_EXPLAIN) /* ** Generate a human-readable explanation of an expression tree. @@ -81141,19 +79962,19 @@ testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); break; } case TK_OR: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); @@ -81163,21 +79984,27 @@ case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { + assert( TK_LT==OP_Lt ); + assert( TK_LE==OP_Le ); + assert( TK_GT==OP_Gt ); + assert( TK_GE==OP_Ge ); + assert( TK_EQ==OP_Eq ); + assert( TK_NE==OP_Ne ); + testcase( op==TK_LT ); + testcase( op==TK_LE ); + testcase( op==TK_GT ); + testcase( op==TK_GE ); + testcase( op==TK_EQ ); + testcase( op==TK_NE ); testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull); - assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); - assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); - assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); - assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); - assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); - assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_IS: @@ -81187,24 +80014,22 @@ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); op = (op==TK_IS) ? TK_EQ : TK_NE; codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, SQLITE_NULLEQ); - VdbeCoverageIf(v, op==TK_EQ); - VdbeCoverageIf(v, op==TK_NE); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { - assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); - assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); + assert( TK_ISNULL==OP_IsNull ); + assert( TK_NOTNULL==OP_NotNull ); + testcase( op==TK_ISNULL ); + testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeAddOp2(v, op, r1, dest); - VdbeCoverageIf(v, op==TK_ISNULL); - VdbeCoverageIf(v, op==TK_NOTNULL); testcase( regFree1==0 ); break; } case TK_BETWEEN: { testcase( jumpIfNull==0 ); @@ -81227,11 +80052,10 @@ }else if( exprAlwaysFalse(pExpr) ){ /* No-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); - VdbeCoverage(v); testcase( regFree1==0 ); testcase( jumpIfNull==0 ); } break; } @@ -81295,21 +80119,21 @@ case TK_AND: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); break; } case TK_OR: { int d2 = sqlite3VdbeMakeLabel(v); testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); @@ -81319,21 +80143,21 @@ case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { + testcase( op==TK_LT ); + testcase( op==TK_LE ); + testcase( op==TK_GT ); + testcase( op==TK_GE ); + testcase( op==TK_EQ ); + testcase( op==TK_NE ); testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull); - assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); - assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); - assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); - assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); - assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); - assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_IS: @@ -81343,22 +80167,20 @@ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, SQLITE_NULLEQ); - VdbeCoverageIf(v, op==TK_EQ); - VdbeCoverageIf(v, op==TK_NE); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { + testcase( op==TK_ISNULL ); + testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeAddOp2(v, op, r1, dest); - testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); - testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); testcase( regFree1==0 ); break; } case TK_BETWEEN: { testcase( jumpIfNull==0 ); @@ -81383,11 +80205,10 @@ }else if( exprAlwaysTrue(pExpr) ){ /* no-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); - VdbeCoverage(v); testcase( regFree1==0 ); testcase( jumpIfNull==0 ); } break; } @@ -81930,12 +80751,12 @@ len = sqlite3GetToken(zCsr, &token); } while( token==TK_SPACE ); assert( len>0 ); } while( token!=TK_LP && token!=TK_USING ); - zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql), - zSql, zTableName, tname.z+tname.n); + zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql, + zTableName, tname.z+tname.n); sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); } } /* @@ -81969,11 +80790,10 @@ unsigned const char *z; /* Pointer to token */ int n; /* Length of token z */ int token; /* Type of token */ UNUSED_PARAMETER(NotUsed); - if( zInput==0 || zOld==0 ) return; for(z=zInput; *z; z=z+n){ n = sqlite3GetToken(z, &token); if( token==TK_REFERENCES ){ char *zParent; do { @@ -81984,11 +80804,11 @@ zParent = sqlite3DbStrNDup(db, (const char *)z, n); if( zParent==0 ) break; sqlite3Dequote(zParent); if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){ char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"", - (zOutput?zOutput:""), (int)(z-zInput), zInput, (const char *)zNew + (zOutput?zOutput:""), z-zInput, zInput, (const char *)zNew ); sqlite3DbFree(db, zOutput); zOutput = zOut; zInput = &z[n]; } @@ -82070,12 +80890,12 @@ } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) ); /* Variable tname now contains the token that is the old table-name ** in the CREATE TRIGGER statement. */ - zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql), - zSql, zTableName, tname.z+tname.n); + zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql, + zTableName, tname.z+tname.n); sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); } } #endif /* !SQLITE_OMIT_TRIGGER */ @@ -82323,11 +81143,11 @@ pVTab = 0; } } #endif - /* Begin a transaction for database iDb. + /* Begin a transaction and code the VerifyCookie for database iDb. ** Then modify the schema cookie (since the ALTER TABLE modifies the ** schema). Open a statement transaction if the table is a virtual ** table. */ v = sqlite3GetVdbe(pParse); @@ -82459,11 +81279,10 @@ int j1; sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2); j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2); sqlite3VdbeJumpHere(v, j1); sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } @@ -83685,11 +82504,11 @@ nCol = pIdx->nKeyCol; aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*(nCol+1)); if( aGotoChng==0 ) continue; /* Populate the register containing the index name. */ - if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ + if( pIdx->autoIndex==2 && !HasRowid(pTab) ){ zIdxName = pTab->zName; }else{ zIdxName = pIdx->zName; } sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, zIdxName, 0); @@ -83760,11 +82579,10 @@ ** regChng = 0 ** goto next_push_0; ** */ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); - VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); addrGotoChng0 = sqlite3VdbeAddOp0(v, OP_Goto); /* ** next_row: @@ -83782,11 +82600,10 @@ sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); aGotoChng[i] = sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); - VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_Integer, nCol, regChng); aGotoChng[nCol] = sqlite3VdbeAddOp0(v, OP_Goto); /* @@ -83829,11 +82646,11 @@ #endif assert( regChng==(regStat4+1) ); sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp); sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 2+IsStat34); - sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); /* Add the entry to the stat1 table. */ callStatGet(v, regStat4, STAT_GET_STAT1, regStat1); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); @@ -83856,19 +82673,14 @@ pParse->nMem = MAX(pParse->nMem, regCol+nCol+1); addrNext = sqlite3VdbeCurrentAddr(v); callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid); addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid); - VdbeCoverage(v); callStatGet(v, regStat4, STAT_GET_NEQ, regEq); callStatGet(v, regStat4, STAT_GET_NLT, regLt); callStatGet(v, regStat4, STAT_GET_NDLT, regDLt); sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0); - /* We know that the regSampleRowid row exists because it was read by - ** the previous loop. Thus the not-found jump of seekOp will never - ** be taken */ - VdbeCoverageNeverTaken(v); #ifdef SQLITE_ENABLE_STAT3 sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pIdx->aiColumn[0], regSample); #else for(i=0; iaiColumn[i]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol+1, regSample); #endif - sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 6, regTemp, "bbbbbb", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid); - sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext); sqlite3VdbeJumpHere(v, addrIsNull); } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ /* End of analysis */ @@ -83895,11 +82707,11 @@ ** name and the row count as the content. */ if( pOnlyIdx==0 && needTableCnt ){ VdbeComment((v, "%s", pTab->zName)); sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1); - jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v); + jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -84054,11 +82866,10 @@ */ static void decodeIntArray( char *zIntArray, /* String containing int array to decode */ int nOut, /* Number of slots in aOut[] */ tRowcnt *aOut, /* Store integers here */ - LogEst *aLog, /* Or, if aOut==0, here */ Index *pIndex /* Handle extra flags for this index, if not NULL */ ){ char *z = zIntArray; int c; int i; @@ -84073,21 +82884,11 @@ v = 0; while( (c=z[0])>='0' && c<='9' ){ v = v*10 + c - '0'; z++; } -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - if( aOut ){ - aOut[i] = v; - }else -#else - assert( aOut==0 ); - UNUSED_PARAMETER(aOut); -#endif - { - aLog[i] = sqlite3LogEst(v); - } + aOut[i] = v; if( *z==' ' ) z++; } #ifndef SQLITE_ENABLE_STAT3_OR_STAT4 assert( pIndex!=0 ); #else @@ -84139,16 +82940,16 @@ pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); } z = argv[2]; if( pIndex ){ - decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex); - if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; + decodeIntArray((char*)z, pIndex->nKeyCol+1, pIndex->aiRowEst, pIndex); + if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0]; }else{ Index fakeIdx; fakeIdx.szIdxRow = pTable->szTabRow; - decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx); + decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx); pTable->szTabRow = fakeIdx.szIdxRow; } return 0; } @@ -84336,13 +83137,13 @@ if( pIdx!=pPrevIdx ){ initAvgEq(pPrevIdx); pPrevIdx = pIdx; } pSample = &pIdx->aSample[pIdx->nSample]; - decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0); - decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0); - decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,1), nCol, pSample->anEq, 0); + decodeIntArray((char*)sqlite3_column_text(pStmt,2), nCol, pSample->anLt, 0); + decodeIntArray((char*)sqlite3_column_text(pStmt,3), nCol, pSample->anDLt,0); /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer. ** This is in case the sample record is corrupted. In that case, the ** sqlite3VdbeRecordCompare() may read up to two varints past the ** end of the allocated buffer before it realizes it is dealing with @@ -85444,26 +84245,24 @@ ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a ** transaction on each used database and to verify the schema cookie ** on each used database. */ - if( db->mallocFailed==0 && (pParse->cookieMask || pParse->pConstExpr) ){ + if( pParse->cookieGoto>0 ){ yDbMask mask; - int iDb, i; - assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init ); - sqlite3VdbeJumpHere(v, 0); + int iDb, i, addr; + sqlite3VdbeJumpHere(v, pParse->cookieGoto-1); for(iDb=0, mask=1; iDbnDb; mask<<=1, iDb++){ if( (mask & pParse->cookieMask)==0 ) continue; sqlite3VdbeUsesBtree(v, iDb); - sqlite3VdbeAddOp4Int(v, - OP_Transaction, /* Opcode */ - iDb, /* P1 */ - (mask & pParse->writeMask)!=0, /* P2 */ - pParse->cookieValue[iDb], /* P3 */ - db->aDb[iDb].pSchema->iGeneration /* P4 */ - ); - if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); + sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0); + if( db->init.busy==0 ){ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + sqlite3VdbeAddOp3(v, OP_VerifyCookie, + iDb, pParse->cookieValue[iDb], + db->aDb[iDb].pSchema->iGeneration); + } } #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; inVtabLock; i++){ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]); sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB); @@ -85480,20 +84279,21 @@ /* Initialize any AUTOINCREMENT data structures required. */ sqlite3AutoincrementBegin(pParse); /* Code constant expressions that where factored out of inner loops */ + addr = pParse->cookieGoto; if( pParse->pConstExpr ){ ExprList *pEL = pParse->pConstExpr; - pParse->okConstFactor = 0; + pParse->cookieGoto = 0; for(i=0; inExpr; i++){ sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg); } } /* Finally, jump back to the beginning of the executable code. */ - sqlite3VdbeAddOp2(v, OP_Goto, 0, 1); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); } } /* Get the VDBE program ready for execution @@ -85512,10 +84312,11 @@ pParse->nTab = 0; pParse->nMem = 0; pParse->nSet = 0; pParse->nVar = 0; pParse->cookieMask = 0; + pParse->cookieGoto = 0; } /* ** Run the parser and code generator recursively in order to generate ** code for the SQL statement given onto the end of the pParse context @@ -86052,11 +84853,11 @@ /* ** Return the PRIMARY KEY index of a table */ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){ Index *p; - for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} + for(p=pTab->pIndex; p && p->autoIndex!=2; p=p->pNext){} return p; } /* ** Return the column of index pIdx that corresponds to table @@ -86200,11 +85001,11 @@ } pTable->zName = zName; pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; - pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + pTable->nRowEst = 1048576; assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; /* If this is the magic sqlite_sequence table used by autoincrement, ** then record a pointer to this table in the main database structure @@ -86243,11 +85044,11 @@ reg1 = pParse->regRowid = ++pParse->nMem; reg2 = pParse->regRoot = ++pParse->nMem; reg3 = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); - j1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); + j1 = sqlite3VdbeAddOp1(v, OP_If, reg3); fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? 1 : SQLITE_MAX_FILE_FORMAT; sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3); sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3); @@ -86581,11 +85382,11 @@ Index *p; if( v ) pParse->addrSkipPK = sqlite3VdbeAddOp0(v, OP_Noop); p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); if( p ){ - p->idxType = SQLITE_IDXTYPE_PRIMARYKEY; + p->autoIndex = 2; if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK); } pList = 0; } @@ -86601,14 +85402,11 @@ Parse *pParse, /* Parsing context */ Expr *pCheckExpr /* The check expression */ ){ #ifndef SQLITE_OMIT_CHECK Table *pTab = pParse->pNewTable; - sqlite3 *db = pParse->db; - if( pTab && !IN_DECLARE_VTAB - && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) - ){ + if( pTab && !IN_DECLARE_VTAB ){ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); if( pParse->constraintName.n ){ sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); } }else @@ -86956,11 +85754,11 @@ pTab->aCol[pTab->iPKey].zName); pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0); if( pPk==0 ) return; - pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY; + pPk->autoIndex = 2; pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); } pPk->isCovering = 1; @@ -86979,11 +85777,11 @@ /* Update the in-memory representation of all UNIQUE indices by converting ** the final rowid column into one or more columns of the PRIMARY KEY. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int n; - if( IsPrimaryKeyIndex(pIdx) ) continue; + if( pIdx->autoIndex==2 ) continue; for(i=n=0; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++; } if( n==0 ){ /* This index is a superset of the primary key */ @@ -87973,40 +86771,40 @@ sqlite3KeyInfoRef(pKey), P4_KEYINFO); /* 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); VdbeCoverage(v); + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); regRecord = sqlite3GetTempReg(pParse); sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); - sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); - sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); + sqlite3VdbeResolveLabel(v, iPartIdxLabel); + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, (char *)pKey, P4_KEYINFO); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); - addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); + addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); assert( pKey!=0 || db->mallocFailed || pParse->nErr ); if( pIndex->onError!=OE_None && pKey!=0 ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, - pKey->nField - pIndex->nKeyCol); VdbeCoverage(v); + pKey->nField - pIndex->nKeyCol); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); - sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_Close, iTab); sqlite3VdbeAddOp1(v, OP_Close, iIdx); sqlite3VdbeAddOp1(v, OP_Close, iSorter); @@ -88028,19 +86826,19 @@ Index *p; /* Allocated index object */ int nByte; /* Bytes of space for Index object + arrays */ nByte = ROUND8(sizeof(Index)) + /* Index structure */ ROUND8(sizeof(char*)*nCol) + /* Index.azColl */ - ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */ + ROUND8(sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */ sizeof(i16)*nCol + /* Index.aiColumn */ sizeof(u8)*nCol); /* Index.aSortOrder */ p = sqlite3DbMallocZero(db, nByte + nExtra); if( p ){ char *pExtra = ((char*)p)+ROUND8(sizeof(Index)); - p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); - p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1); - p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; + p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); + p->aiRowEst = (tRowcnt*)pExtra; pExtra += sizeof(tRowcnt)*(nCol+1); + p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; p->aSortOrder = (u8*)pExtra; p->nColumn = nCol; p->nKeyCol = nCol - 1; *ppExtra = ((char*)p) + nByte; } @@ -88059,11 +86857,11 @@ ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. ** ** If the index is created successfully, return a pointer to the new Index ** structure. This is used by sqlite3AddPrimaryKey() to mark the index -** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY) +** as the tables primary key (Index.autoIndex==2). */ SQLITE_PRIVATE Index *sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ @@ -88266,19 +87064,19 @@ pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol, nName + nExtra + 1, &zExtra); if( db->mallocFailed ){ goto exit_create_index; } - assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) ); + assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) ); assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); pIndex->zName = zExtra; zExtra += nName + 1; memcpy(pIndex->zName, zName, nName+1); pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; - pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE; + pIndex->autoIndex = (u8)(pName==0); pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->nKeyCol = pList->nExpr; if( pPIWhere ){ sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0); pIndex->pPartIdxWhere = pPIWhere; @@ -88386,11 +87184,11 @@ */ Index *pIdx; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int k; assert( pIdx->onError!=OE_None ); - assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF ); + assert( pIdx->autoIndex ); assert( pIndex->onError!=OE_None ); if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue; for(k=0; knKeyCol; k++){ const char *z1; @@ -88547,11 +87345,11 @@ ** ** aiRowEst[0] is suppose to contain the number of elements in the index. ** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the ** number of rows in the table that match any particular value of the ** first column of the index. aiRowEst[2] is an estimate of the number -** of rows that match any particular combination of the first 2 columns +** of rows that match any particular combiniation of the first 2 columns ** of the index. And so forth. It must always be the case that * ** aiRowEst[N]<=aiRowEst[N-1] ** aiRowEst[N]>=1 ** @@ -88558,31 +87356,24 @@ ** Apart from that, we have little to go on besides intuition as to ** how aiRowEst[] should be initialized. The numbers generated here ** are based on typical values found in actual indices. */ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ - /* 10, 9, 8, 7, 6 */ - LogEst aVal[] = { 33, 32, 30, 28, 26 }; - LogEst *a = pIdx->aiRowLogEst; - int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); + tRowcnt *a = pIdx->aiRowEst; int i; - - /* Set the first entry (number of rows in the index) to the estimated - ** number of rows in the table. Or 10, if the estimated number of rows - ** in the table is less than that. */ - a[0] = pIdx->pTable->nRowLogEst; - if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); - - /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is - ** 6 and each subsequent value (if any) is 5. */ - memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); - for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ - a[i] = 23; assert( 23==sqlite3LogEst(5) ); - } - - assert( 0==sqlite3LogEst(1) ); - if( pIdx->onError!=OE_None ) a[pIdx->nKeyCol] = 0; + tRowcnt n; + assert( a!=0 ); + a[0] = pIdx->pTable->nRowEst; + if( a[0]<10 ) a[0] = 10; + n = 10; + for(i=1; i<=pIdx->nKeyCol; i++){ + a[i] = n; + if( n>5 ) n--; + } + if( pIdx->onError!=OE_None ){ + a[pIdx->nKeyCol] = 1; + } } /* ** This routine will drop an existing named index. This routine ** implements the DROP INDEX statement. @@ -88609,11 +87400,11 @@ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); } pParse->checkSchema = 1; goto exit_drop_index; } - if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ + if( pIndex->autoIndex ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; } iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); @@ -88778,11 +87569,11 @@ assert( nExtra>=1 ); assert( pSrc!=0 ); assert( iStart<=pSrc->nSrc ); /* Allocate additional space if needed */ - if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ + if( pSrc->nSrc+nExtra>pSrc->nAlloc ){ SrcList *pNew; int nAlloc = pSrc->nSrc+nExtra; int nGot; pNew = sqlite3DbRealloc(db, pSrc, sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); @@ -88790,19 +87581,19 @@ assert( db->mallocFailed ); return pSrc; } pSrc = pNew; nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1; - pSrc->nAlloc = nGot; + pSrc->nAlloc = (u8)nGot; } /* Move existing slots that come after the newly inserted slots ** out of the way */ for(i=pSrc->nSrc-1; i>=iStart; i--){ pSrc->a[i+nExtra] = pSrc->a[i]; } - pSrc->nSrc += nExtra; + pSrc->nSrc += (i8)nExtra; /* Zero the newly allocated slots */ memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra); for(i=iStart; ia[i].iCursor = -1; @@ -89130,30 +87921,63 @@ } return 0; } /* -** Record the fact that the schema cookie will need to be verified -** for database iDb. The code to actually verify the schema cookie -** will occur at the end of the top-level VDBE and will be generated -** later, by sqlite3FinishCoding(). +** Generate VDBE code that will verify the schema cookie and start +** a read-transaction for all named database files. +** +** It is important that all schema cookies be verified and all +** read transactions be started before anything else happens in +** the VDBE program. But this routine can be called after much other +** code has been generated. So here is what we do: +** +** The first time this routine is called, we code an OP_Goto that +** will jump to a subroutine at the end of the program. Then we +** record every database that needs its schema verified in the +** pParse->cookieMask field. Later, after all other code has been +** generated, the subroutine that does the cookie verifications and +** starts the transactions will be coded and the OP_Goto P2 value +** will be made to point to that subroutine. The generation of the +** cookie verification subroutine code happens in sqlite3FinishCoding(). +** +** If iDb<0 then code the OP_Goto only - don't set flag to verify the +** schema on any databases. This can be used to position the OP_Goto +** 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); - sqlite3 *db = pToplevel->db; - yDbMask mask; - - assert( iDb>=0 && iDbnDb ); - assert( db->aDb[iDb].pBt!=0 || iDb==1 ); - assert( iDbcookieMask & mask)==0 ){ - pToplevel->cookieMask |= mask; - pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; - if( !OMIT_TEMPDB && iDb==1 ){ - sqlite3OpenTempDatabase(pToplevel); + +#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; + } + if( iDb>=0 ){ + sqlite3 *db = pToplevel->db; + yDbMask mask; + + assert( iDbnDb ); + assert( db->aDb[iDb].pBt!=0 || iDb==1 ); + assert( iDbcookieMask & mask)==0 ){ + pToplevel->cookieMask |= mask; + pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; + if( !OMIT_TEMPDB && iDb==1 ){ + sqlite3OpenTempDatabase(pToplevel); + } } } } /* @@ -89268,12 +88092,11 @@ sqlite3StrAccumAppend(&errMsg, ".", 1); sqlite3StrAccumAppendAll(&errMsg, zCol); } zErr = sqlite3StrAccumFinish(&errMsg); sqlite3HaltConstraint(pParse, - IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY - : SQLITE_CONSTRAINT_UNIQUE, + (pIdx->autoIndex==2)?SQLITE_CONSTRAINT_PRIMARYKEY:SQLITE_CONSTRAINT_UNIQUE, onError, zErr, P4_DYNAMIC, P5_ConstraintUnique); } /* @@ -90121,20 +88944,25 @@ SelectDest dest; Select *pSel; SrcList *pFrom; 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; + sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pSel, &dest); sqlite3SelectDelete(db, pSel); } #endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */ @@ -90467,11 +89295,11 @@ }else if( pPk ){ /* Construct a composite key for the row to be deleted and remember it */ iKey = ++pParse->nMem; nKey = 0; /* Zero tells OP_Found to use a composite key */ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, - sqlite3IndexAffinityStr(v, pPk), nPk); + sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT); sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey); }else{ /* Get the rowid of the row to be deleted and remember it in the RowSet */ nKey = 1; /* OP_Seek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); @@ -90505,19 +89333,17 @@ /* Just one row. Hence the top-of-loop is a no-op */ assert( nKey==nPk ); /* OP_Found will use an unpacked key */ if( aToOpen[iDataCur-iTabCur] ){ assert( pPk!=0 ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); - VdbeCoverage(v); } }else if( pPk ){ - addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); + addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey); assert( nKey==0 ); /* OP_Found will use a composite key */ }else{ addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey); - VdbeCoverage(v); assert( nKey==1 ); } /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -90537,11 +89363,11 @@ /* End of the loop over all rowids/primary-keys. */ if( okOnePass ){ sqlite3VdbeResolveLabel(v, addrBypass); }else if( pPk ){ - sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); sqlite3VdbeJumpHere(v, addrLoop); }else{ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrLoop); sqlite3VdbeJumpHere(v, addrLoop); } @@ -90635,15 +89461,11 @@ /* Seek cursor iCur to the row to delete. If this row no longer exists ** (this can happen if a trigger program has already deleted it), do ** not attempt to delete it or fire any DELETE triggers. */ iLabel = sqlite3VdbeMakeLabel(v); opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound; - if( !bNoSeek ){ - sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); - VdbeCoverageIf(v, opSeek==OP_NotExists); - VdbeCoverageIf(v, opSeek==OP_NotFound); - } + if( !bNoSeek ) sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); /* If there are any triggers to fire, allocate a range of registers to ** use for the old.* references in the triggers. */ if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){ u32 mask; /* Mask of OLD.* columns in use */ @@ -90681,12 +89503,10 @@ ** the cursor or of already deleted the row that the cursor was ** pointing to. */ if( addrStartzName)); r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); - sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); + sqlite3VdbeResolveLabel(v, iPartIdxLabel); pPrior = pIdx; } } /* @@ -90782,15 +89602,14 @@ ** block of registers has already been deallocated by the time ** this routine returns. ** ** If *piPartIdxLabel is not NULL, fill it in with a label and jump ** to that label if pIdx is a partial index that should be skipped. -** The label should be resolved using sqlite3ResolvePartIdxLabel(). ** A partial index should be skipped if its WHERE clause evaluates ** to false or null. If pIdx is not a partial index, *piPartIdxLabel ** will be set to zero which is an empty label that is ignored by -** sqlite3ResolvePartIdxLabel(). +** sqlite3VdbeResolveLabel(). ** ** The pPrior and regPrior parameters are used to implement a cache to ** avoid unnecessary register loads. If pPrior is not NULL, then it is ** a pointer to a different index for which an index key has just been ** computed into register regPrior. If the current pIdx index is generating @@ -90819,11 +89638,10 @@ if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); pParse->iPartIdxTab = iDataCur; - sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); }else{ *piPartIdxLabel = 0; } @@ -90848,22 +89666,10 @@ } sqlite3ReleaseTempRange(pParse, regBase, nCol); return regBase; } -/* -** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label -** because it was a partial index, then this routine should be called to -** resolve that label. -*/ -SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ - if( iLabel ){ - sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); - sqlite3ExprCachePop(pParse); - } -} - /************** End of delete.c **********************************************/ /************** Begin file func.c ********************************************/ /* ** 2002 February 23 ** @@ -91879,11 +90685,11 @@ int argc, sqlite3_value **argv ){ unsigned char *z, *zOut; int i; - zOut = z = sqlite3_malloc( argc*4+1 ); + zOut = z = sqlite3_malloc( argc*4 ); if( z==0 ){ sqlite3_result_error_nomem(context); return; } for(i=0; iautoIndex==2 ){ if( aiCol ){ int i; for(i=0; iaCol[i].iFrom; } break; @@ -92954,15 +91760,14 @@ ** Check if any of the key columns in the child table row are NULL. If ** any are, then the constraint is considered satisfied. No need to ** search for a matching row in the parent table. */ if( nIncr<0 ){ sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk); - VdbeCoverage(v); } for(i=0; inCol; i++){ int iReg = aiCol[i] + regData + 1; - sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); } if( isIgnore==0 ){ if( pIdx==0 ){ /* If pIdx is NULL, then the parent key is the INTEGER PRIMARY KEY @@ -92975,23 +91780,21 @@ ** is no matching parent key. Before using MustBeInt, make a copy of ** the value. Otherwise, the value inserted into the child key column ** will have INTEGER affinity applied to it, which may not be correct. */ sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp); iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0); - VdbeCoverage(v); /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not ** increment the constraint-counter. */ if( pTab==pFKey->pFrom && nIncr==1 ){ - sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); VdbeCoverage(v); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); } sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); - sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); sqlite3VdbeJumpHere(v, iMustBeInt); sqlite3ReleaseTempReg(pParse, regTemp); }else{ @@ -93023,19 +91826,19 @@ assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ /* The parent key is a composite key that includes the IPK column */ iParent = regData; } - sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); } sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk); } - sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec, - sqlite3IndexAffinityStr(v,pIdx), nCol); - sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regTemp, nCol, regRec); + sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT); + sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempRange(pParse, regTemp, nCol); } } @@ -93169,11 +91972,10 @@ assert( pIdx!=0 || pFKey->nCol==1 ); assert( pIdx!=0 || HasRowid(pTab) ); if( nIncr<0 ){ iFkIfZero = sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, 0); - VdbeCoverage(v); } /* Create an Expr object representing an SQL expression like: ** ** = AND = ... @@ -93332,11 +92134,11 @@ for(p=pTab->pFKey; p; p=p->pNextFrom){ if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break; } if( !p ) return; iSkip = sqlite3VdbeMakeLabel(v); - sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); } pParse->disableTriggers = 1; sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0); pParse->disableTriggers = 0; @@ -93350,11 +92152,10 @@ ** the statement transaction will not be rolled back even if FK ** constraints are violated. */ if( (db->flags & SQLITE_DeferFKs)==0 ){ sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, OE_Abort, 0, P4_STATIC, P5_ConstraintFK); } if( iSkip ){ @@ -93510,11 +92311,11 @@ */ Vdbe *v = sqlite3GetVdbe(pParse); int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1; for(i=0; inCol; i++){ int iReg = pFKey->aCol[i].iFrom + regOld + 1; - sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1); } continue; } @@ -94077,73 +92878,69 @@ return pIdx->zColAff; } /* -** Compute the affinity string for table pTab, if it has not already been -** computed. As an optimization, omit trailing SQLITE_AFF_NONE affinities. -** -** If the affinity exists (if it is no entirely SQLITE_AFF_NONE values) and -** if iReg>0 then code an OP_Affinity opcode that will set the affinities -** for register iReg and following. Or if affinities exists and iReg==0, -** then just set the P4 operand of the previous opcode (which should be -** an OP_MakeRecord) to the affinity string. -** -** A column affinity string has one character per column: +** Set P4 of the most recently inserted opcode to a column affinity +** string for table pTab. A column affinity string has one character +** for each column indexed by the index, according to the affinity of the +** column: ** ** Character Column affinity ** ------------------------------ ** 'a' TEXT ** 'b' NONE ** 'c' NUMERIC ** 'd' INTEGER ** 'e' REAL */ -SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ - int i; - char *zColAff = pTab->zColAff; - if( zColAff==0 ){ +SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){ + /* The first time a column affinity string for a particular table + ** is required, it is allocated and populated here. It is then + ** stored as a member of the Table structure for subsequent use. + ** + ** The column affinity string will eventually be deleted by + ** sqlite3DeleteTable() when the Table structure itself is cleaned up. + */ + if( !pTab->zColAff ){ + char *zColAff; + int i; sqlite3 *db = sqlite3VdbeDb(v); + zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1); if( !zColAff ){ db->mallocFailed = 1; return; } for(i=0; inCol; i++){ zColAff[i] = pTab->aCol[i].affinity; } - do{ - zColAff[i--] = 0; - }while( i>=0 && zColAff[i]==SQLITE_AFF_NONE ); + zColAff[pTab->nCol] = '\0'; + pTab->zColAff = zColAff; } - i = sqlite3Strlen30(zColAff); - if( i ){ - if( iReg ){ - sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); - }else{ - sqlite3VdbeChangeP4(v, -1, zColAff, i); - } - } + + sqlite3VdbeChangeP4(v, -1, pTab->zColAff, P4_TRANSIENT); } /* ** Return non-zero if the table pTab in database iDb or any of its indices -** have been opened at any point in the VDBE program. This is used to see if +** have been opened at any point in the VDBE program beginning at location +** iStartAddr throught the end of the program. This is used to see if ** a statement of the form "INSERT INTO SELECT ..." can -** run without using a temporary table for the results of the SELECT. +** run without using temporary table for the results of the SELECT. */ -static int readsTable(Parse *p, int iDb, Table *pTab){ +static int readsTable(Parse *p, int iStartAddr, int iDb, Table *pTab){ Vdbe *v = sqlite3GetVdbe(p); int i; int iEnd = sqlite3VdbeCurrentAddr(v); #ifndef SQLITE_OMIT_VIRTUALTABLE VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0; #endif - for(i=1; iopcode==OP_OpenRead && pOp->p3==iDb ){ Index *pIndex; int tnum = pOp->p2; @@ -94240,18 +93037,18 @@ assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1); addr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0); - sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId); - sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1); sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId); sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9); - sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); sqlite3VdbeAddOp2(v, OP_Integer, 0, memId); sqlite3VdbeAddOp0(v, OP_Close); } } @@ -94282,20 +93079,29 @@ sqlite3 *db = pParse->db; assert( v ); for(p = pParse->pAinc; p; p = p->pNext){ Db *pDb = &db->aDb[p->iDb]; - int j1; + int j1, j2, j3, j4, j5; int iRec; int memId = p->regCtr; iRec = sqlite3GetTempReg(pParse); assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v); + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); + j2 = sqlite3VdbeAddOp0(v, OP_Rewind); + j3 = sqlite3VdbeAddOp3(v, OP_Column, 0, 0, iRec); + j4 = sqlite3VdbeAddOp3(v, OP_Eq, memId-1, 0, iRec); + sqlite3VdbeAddOp2(v, OP_Next, 0, j3); + sqlite3VdbeJumpHere(v, j2); sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1); + j5 = sqlite3VdbeAddOp0(v, OP_Goto); + sqlite3VdbeJumpHere(v, j4); + sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1); sqlite3VdbeJumpHere(v, j1); + sqlite3VdbeJumpHere(v, j5); sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec); sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp0(v, OP_Close); sqlite3ReleaseTempReg(pParse, iRec); @@ -94307,10 +93113,101 @@ ** above are all no-ops */ # define autoIncBegin(A,B,C) (0) # define autoIncStep(A,B,C) #endif /* SQLITE_OMIT_AUTOINCREMENT */ + + +/* +** Generate code for a co-routine that will evaluate a subquery one +** row at a time. +** +** The pSelect parameter is the subquery that the co-routine will evaluation. +** Information about the location of co-routine and the registers it will use +** is returned by filling in the pDest object. +** +** Registers are allocated as follows: +** +** pDest->iSDParm The register holding the next entry-point of the +** co-routine. Run the co-routine to its next breakpoint +** by calling "OP_Yield $X" where $X is pDest->iSDParm. +** +** pDest->iSDParm+1 The register holding the "completed" flag for the +** co-routine. This register is 0 if the previous Yield +** generated a new result row, or 1 if the subquery +** has completed. If the Yield is called again +** after this register becomes 1, then the VDBE will +** halt with an SQLITE_INTERNAL error. +** +** pDest->iSdst First result register. +** +** pDest->nSdst Number of result registers. +** +** This routine handles all of the register allocation and fills in the +** pDest structure appropriately. +** +** Here is a schematic of the generated code assuming that X is the +** co-routine entry-point register reg[pDest->iSDParm], that EOF is the +** completed flag reg[pDest->iSDParm+1], and R and S are the range of +** registers that hold the result set, reg[pDest->iSdst] through +** reg[pDest->iSdst+pDest->nSdst-1]: +** +** X <- A +** EOF <- 0 +** goto B +** A: setup for the SELECT +** loop rows in the SELECT +** load results into registers R..S +** yield X +** end loop +** cleanup after the SELECT +** EOF <- 1 +** yield X +** halt-error +** B: +** +** To use this subroutine, the caller generates code as follows: +** +** [ Co-routine generated by this subroutine, shown above ] +** S: yield X +** if EOF goto E +** if skip this row, goto C +** if terminate loop, goto E +** deal with this row +** C: goto S +** E: +*/ +SQLITE_PRIVATE int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){ + int regYield; /* Register holding co-routine entry-point */ + int regEof; /* Register holding co-routine completion flag */ + int addrTop; /* Top of the co-routine */ + int j1; /* Jump instruction */ + int rc; /* Result code */ + Vdbe *v; /* VDBE under construction */ + + regYield = ++pParse->nMem; + regEof = ++pParse->nMem; + v = sqlite3GetVdbe(pParse); + addrTop = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_Integer, addrTop+2, regYield); /* X <- A */ + VdbeComment((v, "Co-routine entry point")); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */ + VdbeComment((v, "Co-routine completion flag")); + sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield); + j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); + rc = sqlite3Select(pParse, pSelect, pDest); + assert( pParse->nErr==0 || rc ); + if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM; + if( rc ) return rc; + sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */ + sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */ + sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort); + VdbeComment((v, "End of coroutine")); + sqlite3VdbeJumpHere(v, j1); /* label B: */ + return rc; +} + /* Forward declaration */ static int xferOptimization( Parse *pParse, /* Parser context */ @@ -94371,21 +93268,25 @@ ** ** The 3rd template is for when the second template does not apply ** and the SELECT clause does not read from
at any time. ** The generated code follows this template: ** +** EOF <- 0 ** X <- A ** goto B ** A: setup for the SELECT ** loop over the rows in the SELECT ** load values into registers R..R+n ** yield X ** end loop ** cleanup after the SELECT -** end-coroutine X +** EOF <- 1 +** yield X +** goto A ** B: open write cursor to
and its indices -** C: yield X, at EOF goto D +** C: yield X +** if EOF goto D ** insert the select result into
from R..R+n ** goto C ** D: cleanup ** ** The 4th template is used if the insert statement takes its @@ -94392,21 +93293,25 @@ ** values from a SELECT but the data is being inserted into a table ** that is also read as part of the SELECT. In the third form, ** we have to use a intermediate table to store the results of ** the select. The template is like this: ** +** EOF <- 0 ** X <- A ** goto B ** A: setup for the SELECT ** loop over the tables in the SELECT ** load value into register R..R+n ** yield X ** end loop ** cleanup after the SELECT -** end co-routine R +** EOF <- 1 +** yield X +** halt-error ** B: open temp table -** L: yield X, at EOF goto M +** L: yield X +** if EOF goto M ** insert row from R..R+n into temp table ** goto L ** M: open write cursor to
and its indices ** rewind temp table ** C: loop over rows of intermediate table @@ -94432,29 +93337,30 @@ int nHidden = 0; /* Number of hidden columns if TABLE is virtual */ int iDataCur = 0; /* VDBE cursor that is the main data repository */ int iIdxCur = 0; /* First index cursor */ int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ int endOfLoop; /* Label for the end of the insertion loop */ + int useTempTable = 0; /* Store SELECT results in intermediate table */ int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ int addrInsTop = 0; /* Jump to label "D" */ int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */ + int addrSelect = 0; /* Address of coroutine that implements the SELECT */ SelectDest dest; /* Destination for SELECT on rhs of INSERT */ int iDb; /* Index of database holding TABLE */ Db *pDb; /* The database containing table being inserted into */ - u8 useTempTable = 0; /* Store SELECT results in intermediate table */ - u8 appendFlag = 0; /* True if the insert is likely to be an append */ - u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ - u8 bIdListInOrder = 1; /* True if IDLIST is in table order */ + int appendFlag = 0; /* True if the insert is likely to be an append */ + int withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ ExprList *pList = 0; /* List of VALUES() to be inserted */ /* Register allocations */ int regFromSelect = 0;/* Base register for data coming from SELECT */ int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */ int regRowCount = 0; /* Memory cell used for the row counter */ int regIns; /* Block of regs holding rowid+data being inserted */ int regRowid; /* registers holding insert rowid */ int regData; /* register holding first column to insert */ + int regEof = 0; /* Register recording end of SELECT data */ int *aRegIdx = 0; /* One register allocated to each index */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ Trigger *pTrigger; /* List of triggers on pTab, if required */ @@ -94553,86 +93459,25 @@ /* If this is an AUTOINCREMENT table, look up the sequence number in the ** sqlite_sequence table and store it in memory cell regAutoinc. */ regAutoinc = autoIncBegin(pParse, iDb, pTab); - /* Allocate registers for holding the rowid of the new row, - ** the content of the new row, and the assemblied row record. - */ - regRowid = regIns = pParse->nMem+1; - pParse->nMem += pTab->nCol + 1; - if( IsVirtual(pTab) ){ - regRowid++; - pParse->nMem++; - } - regData = regRowid+1; - - /* If the INSERT statement included an IDLIST term, then make sure - ** all elements of the IDLIST really are columns of the table and - ** remember the column indices. - ** - ** If the table has an INTEGER PRIMARY KEY column and that column - ** is named in the IDLIST, then record in the ipkColumn variable - ** the index into IDLIST of the primary key column. ipkColumn is - ** the index of the primary key as it appears in IDLIST, not as - ** is appears in the original table. (The index of the INTEGER - ** PRIMARY KEY in the original table is pTab->iPKey.) - */ - if( pColumn ){ - for(i=0; inId; i++){ - pColumn->a[i].idx = -1; - } - for(i=0; inId; i++){ - for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ - pColumn->a[i].idx = j; - if( i!=j ) bIdListInOrder = 0; - if( j==pTab->iPKey ){ - ipkColumn = i; assert( !withoutRowid ); - } - break; - } - } - if( j>=pTab->nCol ){ - if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ - ipkColumn = i; - bIdListInOrder = 0; - }else{ - sqlite3ErrorMsg(pParse, "table %S has no column named %s", - pTabList, 0, pColumn->a[i].zName); - pParse->checkSchema = 1; - goto insert_cleanup; - } - } - } - } - /* Figure out how many columns of data are supplied. If the data ** is coming from a SELECT statement, then generate a co-routine that ** produces a single row of the SELECT on each invocation. The ** co-routine is the common header to the 3rd and 4th templates. */ if( pSelect ){ /* Data is coming from a SELECT. Generate a co-routine to run the SELECT */ - int regYield; /* Register holding co-routine entry-point */ - int addrTop; /* Top of the co-routine */ - int rc; /* Result code */ - - regYield = ++pParse->nMem; - addrTop = sqlite3VdbeCurrentAddr(v) + 1; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); - sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); - dest.iSdst = bIdListInOrder ? regData : 0; - dest.nSdst = pTab->nCol; - rc = sqlite3Select(pParse, pSelect, &dest); - regFromSelect = dest.iSdst; - assert( pParse->nErr==0 || rc ); - if( rc || db->mallocFailed ) goto insert_cleanup; - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); - sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ + int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest); + if( rc ) goto insert_cleanup; + + regEof = dest.iSDParm + 1; + regFromSelect = dest.iSdst; assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; + assert( dest.nSdst==nColumn ); /* Set useTempTable to TRUE if the result of the SELECT statement ** should be written into a temporary table (template 4). Set to ** FALSE if each output row of the SELECT can be written directly into ** the destination table (template 3). @@ -94639,39 +93484,42 @@ ** ** A temp table must be used if the table being updated is also one ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ - if( pTrigger || readsTable(pParse, iDb, pTab) ){ + if( pTrigger || readsTable(pParse, addrSelect, iDb, pTab) ){ useTempTable = 1; } if( useTempTable ){ /* Invoke the coroutine to extract information from the SELECT ** and add it to a transient table srcTab. The code generated ** here is from the 4th template: ** ** B: open temp table - ** L: yield X, goto M at EOF + ** L: yield X + ** if EOF goto M ** insert row from R..R+n into temp table ** goto L ** M: ... */ int regRec; /* Register to hold packed record */ int regTempRowid; /* Register to hold temp table ROWID */ - int addrL; /* Label "L" */ + int addrTop; /* Label "L" */ + int addrIf; /* Address of jump to M */ srcTab = pParse->nTab++; regRec = sqlite3GetTempReg(pParse); regTempRowid = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn); - addrL = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); + addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); + addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof); sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec); sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid); sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid); - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrL); - sqlite3VdbeJumpHere(v, addrL); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); + sqlite3VdbeJumpHere(v, addrIf); sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempReg(pParse, regTempRowid); } }else{ /* This is the case if the data for the INSERT is coming from a VALUES @@ -94688,18 +93536,10 @@ goto insert_cleanup; } } } - /* If there is no IDLIST term but the table has an integer primary - ** key, the set the ipkColumn variable to the integer primary key - ** column index in the original table definition. - */ - if( pColumn==0 && nColumn>0 ){ - ipkColumn = pTab->iPKey; - } - /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ if( IsVirtual(pTab) ){ for(i=0; inCol; i++){ @@ -94714,10 +93554,56 @@ } if( pColumn!=0 && nColumn!=pColumn->nId ){ sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId); goto insert_cleanup; } + + /* If the INSERT statement included an IDLIST term, then make sure + ** all elements of the IDLIST really are columns of the table and + ** remember the column indices. + ** + ** If the table has an INTEGER PRIMARY KEY column and that column + ** is named in the IDLIST, then record in the ipkColumn variable + ** the index into IDLIST of the primary key column. ipkColumn is + ** the index of the primary key as it appears in IDLIST, not as + ** is appears in the original table. (The index of the INTEGER + ** PRIMARY KEY in the original table is pTab->iPKey.) + */ + if( pColumn ){ + for(i=0; inId; i++){ + pColumn->a[i].idx = -1; + } + for(i=0; inId; i++){ + for(j=0; jnCol; j++){ + if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ + pColumn->a[i].idx = j; + if( j==pTab->iPKey ){ + ipkColumn = i; assert( !withoutRowid ); + } + break; + } + } + if( j>=pTab->nCol ){ + if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ + ipkColumn = i; + }else{ + sqlite3ErrorMsg(pParse, "table %S has no column named %s", + pTabList, 0, pColumn->a[i].zName); + pParse->checkSchema = 1; + goto insert_cleanup; + } + } + } + } + + /* If there is no IDLIST term but the table has an integer primary + ** key, the set the ipkColumn variable to the integer primary key + ** column index in the original table definition. + */ + if( pColumn==0 && nColumn>0 ){ + ipkColumn = pTab->iPKey; + } /* Initialize the count of rows to be inserted */ if( db->flags & SQLITE_CountRows ){ regRowCount = ++pParse->nMem; @@ -94741,30 +93627,42 @@ /* This is the top of the main insertion loop */ if( useTempTable ){ /* This block codes the top of loop only. The complete loop is the ** following pseudocode (template 4): ** - ** rewind temp table, if empty goto D + ** rewind temp table ** C: loop over rows of intermediate table ** transfer values form intermediate table into
** end loop ** D: ... */ - addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab); VdbeCoverage(v); + addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab); addrCont = sqlite3VdbeCurrentAddr(v); }else if( pSelect ){ /* This block codes the top of loop only. The complete loop is the ** following pseudocode (template 3): ** - ** C: yield X, at EOF goto D + ** C: yield X + ** if EOF goto D ** insert the select result into
from R..R+n ** goto C ** D: ... */ - addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); - VdbeCoverage(v); + addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); + addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof); } + + /* Allocate registers for holding the rowid of the new row, + ** the content of the new row, and the assemblied row record. + */ + regRowid = regIns = pParse->nMem+1; + pParse->nMem += pTab->nCol + 1; + if( IsVirtual(pTab) ){ + regRowid++; + pParse->nMem++; + } + regData = regRowid+1; /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(v); if( tmask & TRIGGER_BEFORE ){ @@ -94785,14 +93683,14 @@ sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols); } - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v); + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, j1); - sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); } /* Cannot have triggers on a virtual table. If it were possible, ** this block would have to account for hidden column. */ @@ -94822,11 +93720,12 @@ ** do not attempt any conversions before assembling the record. ** If this is a real table, attempt conversions as required by the ** table column affinities. */ if( !isView ){ - sqlite3TableAffinity(v, pTab, regCols+1); + sqlite3VdbeAddOp2(v, OP_Affinity, regCols+1, pTab->nCol); + sqlite3TableAffinityStr(v, pTab); } /* Fire BEFORE or INSTEAD OF triggers */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, pTab, regCols-pTab->nCol-1, onError, endOfLoop); @@ -94844,11 +93743,11 @@ } if( ipkColumn>=0 ){ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid); }else if( pSelect ){ - sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); + sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+ipkColumn, regRowid); }else{ VdbeOp *pOp; sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid); pOp = sqlite3VdbeGetOp(v, -1); if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){ @@ -94863,18 +93762,18 @@ ** to generate a unique primary key value. */ if( !appendFlag ){ int j1; if( !IsVirtual(pTab) ){ - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v); + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); sqlite3VdbeJumpHere(v, j1); }else{ j1 = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, j1+2); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, j1+2); } - sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); } }else if( IsVirtual(pTab) || withoutRowid ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); @@ -94890,13 +93789,12 @@ int iRegStore = regRowid+1+i; if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the rowid will be substituted ** in its place. Hence, fill this column with a NULL to avoid - ** taking up data space with information that will never be used. - ** As there may be shallow copies of this value, make it a soft-NULL */ - sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); + ** taking up data space with information that will never be used. */ + sqlite3VdbeAddOp2(v, OP_Null, 0, iRegStore); continue; } if( pColumn==0 ){ if( IsHiddenColumn(&pTab->aCol[i]) ){ assert( IsVirtual(pTab) ); @@ -94909,17 +93807,15 @@ for(j=0; jnId; j++){ if( pColumn->a[j].idx==i ) break; } } if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){ - sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); }else if( pSelect ){ - if( regFromSelect!=regData ){ - sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore); - } + sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore); }else{ sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore); } } @@ -94961,11 +93857,11 @@ /* The bottom of the main insertion loop, if the data source ** is a SELECT statement. */ sqlite3VdbeResolveLabel(v, endOfLoop); if( useTempTable ){ - sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); sqlite3VdbeJumpHere(v, addrInsTop); sqlite3VdbeAddOp1(v, OP_Close, srcTab); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrCont); sqlite3VdbeJumpHere(v, addrInsTop); @@ -95128,11 +94024,10 @@ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ int ipkTop = 0; /* Top of the rowid change constraint check */ int ipkBottom = 0; /* Bottom of the rowid change constraint check */ u8 isUpdate; /* True if this is an UPDATE operation */ - u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ int regRowid = -1; /* Register holding ROWID value */ isUpdate = regOldData!=0; db = pParse->db; v = sqlite3GetVdbe(pParse); @@ -95183,21 +94078,19 @@ char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, pTab->aCol[i].zName); sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, regNewData+1+i, zMsg, P4_DYNAMIC); sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); - VdbeCoverage(v); break; } case OE_Ignore: { sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest); - VdbeCoverage(v); break; } default: { assert( onError==OE_Replace ); - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); VdbeCoverage(v); + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); sqlite3VdbeJumpHere(v, j1); break; } } @@ -95245,12 +94138,10 @@ if( isUpdate ){ /* pkChng!=0 does not mean that the rowid has change, only that ** it might have changed. Skip the conflict logic below if the rowid ** is unchanged. */ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); - VdbeCoverage(v); } /* If the response to a rowid conflict is REPLACE but the response ** to some other UNIQUE constraint is FAIL or IGNORE, then we need ** to defer the running of the rowid conflict checking until after @@ -95266,11 +94157,10 @@ } /* Check to see if the new rowid already exists in the table. Skip ** the following conflict logic if it does not. */ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); - VdbeCoverage(v); /* Generate code that deals with a rowid collision */ switch( onError ){ default: { onError = OE_Abort; @@ -95345,14 +94235,10 @@ int regR; /* Range of registers holding conflicting PK */ int iThisCur; /* Cursor for this UNIQUE index */ int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ - if( bAffinityDone==0 ){ - sqlite3TableAffinity(v, pTab, regNewData+1); - bAffinityDone = 1; - } iThisCur = iIdxCur+ix; addrUniqueOk = sqlite3VdbeMakeLabel(v); /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ @@ -95379,10 +94265,11 @@ } sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); + sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT); VdbeComment((v, "for %s", pIdx->zName)); sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn); /* In an UPDATE operation, if this index is the PRIMARY KEY index ** of a WITHOUT ROWID table and there has been no change the @@ -95406,11 +94293,11 @@ onError = OE_Abort; } /* Check to see if the new index entry will be unique */ sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, - regIdx, pIdx->nKeyCol); VdbeCoverage(v); + regIdx, pIdx->nKeyCol); /* Generate code to handle collisions */ regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField); if( isUpdate || onError==OE_Replace ){ if( HasRowid(pTab) ){ @@ -95417,12 +94304,10 @@ sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR); /* Conflict only if the rowid of the existing index entry ** is different from old-rowid */ if( isUpdate ){ sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); - VdbeCoverage(v); } }else{ int x; /* Extract the PRIMARY KEY from the end of the index entry and ** store it in registers regR..regR+nPk-1 */ @@ -95442,11 +94327,11 @@ ** For a UNIQUE index, only conflict if the PRIMARY KEY values ** of the matched index row are different from the original PRIMARY ** KEY values of this row before the update. */ int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int op = OP_Ne; - int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); + int regCmp = (pIdx->autoIndex==2 ? regIdx : regR); for(i=0; inKeyCol; i++){ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); x = pPk->aiColumn[i]; if( i==(pPk->nKeyCol-1) ){ @@ -95454,13 +94339,10 @@ op = OP_Eq; } sqlite3VdbeAddOp4(v, op, regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ ); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); - VdbeCoverageIf(v, op==OP_Eq); - VdbeCoverageIf(v, op==OP_Ne); } } } } @@ -95528,36 +94410,33 @@ Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ int regData; /* Content registers (after the rowid) */ int regRec; /* Register holding assemblied record for the table */ int i; /* Loop counter */ - u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( aRegIdx[i]==0 ) continue; - bAffinityDone = 1; if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]); pik_flags = 0; if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT; - if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ + if( pIdx->autoIndex==2 && !HasRowid(pTab) ){ assert( pParse->nested==0 ); pik_flags |= OPFLAG_NCHANGE; } if( pik_flags ) sqlite3VdbeChangeP5(v, pik_flags); } if( !HasRowid(pTab) ) return; regData = regNewData + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); - if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0); + sqlite3TableAffinityStr(v, pTab); sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol); if( pParse->nested ){ pik_flags = 0; }else{ pik_flags = OPFLAG_NCHANGE; @@ -95629,11 +94508,11 @@ } if( piIdxCur ) *piIdxCur = iBase; for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ int iIdxCur = iBase++; assert( pIdx->pSchema==pTab->pSchema ); - if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){ + if( pIdx->autoIndex==2 && !HasRowid(pTab) && piDataCur ){ *piDataCur = iIdxCur; } if( aToOpen==0 || aToOpen[i+1] ){ sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); @@ -95845,28 +94724,19 @@ } if( pDest->iPKey!=pSrc->iPKey ){ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } for(i=0; inCol; i++){ - Column *pDestCol = &pDest->aCol[i]; - Column *pSrcCol = &pSrc->aCol[i]; - if( pDestCol->affinity!=pSrcCol->affinity ){ + if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){ return 0; /* Affinity must be the same on all columns */ } - if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){ + if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){ return 0; /* Collating sequence must be the same on all columns */ } - if( pDestCol->notNull && !pSrcCol->notNull ){ + if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){ return 0; /* tab2 must be NOT NULL if tab1 is */ } - /* Default values for second and subsequent columns need to match. */ - if( i>0 - && ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0) - || (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0)) - ){ - return 0; /* Default values must be the same for all columns */ - } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ if( pDestIdx->onError!=OE_None ){ destHasUniqueIdx = 1; } @@ -95931,21 +94801,20 @@ ** (2) The destination has a unique index. (The xfer optimization ** is unable to test uniqueness.) ** ** (3) onError is something other than OE_Abort and OE_Rollback. */ - addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v); + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); sqlite3VdbeJumpHere(v, addr1); } if( HasRowid(pSrc) ){ sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); - emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); + emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); - VdbeCoverage(v); sqlite3RowidConstraint(pParse, onError, pDest); sqlite3VdbeJumpHere(v, addr2); autoIncStep(pParse, regAutoinc, regRowid); }else if( pDest->pIndex==0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); @@ -95955,11 +94824,11 @@ } sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData); sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND); sqlite3VdbeChangeP4(v, -1, pDest->zName, 0); - sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); }else{ sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName); sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName); @@ -95974,19 +94843,19 @@ VdbeComment((v, "%s", pSrcIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest); sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); - addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData); sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1); - sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); } - if( emptySrcTest ) sqlite3VdbeJumpHere(v, emptySrcTest); + sqlite3VdbeJumpHere(v, emptySrcTest); sqlite3ReleaseTempReg(pParse, regRowid); sqlite3ReleaseTempReg(pParse, regData); if( emptyDestTest ){ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0); sqlite3VdbeJumpHere(v, emptyDestTest); @@ -98216,11 +97085,10 @@ ** is always on by default regardless of the sign of the default cache ** size. But continue to take the absolute value of the default cache ** size of historical compatibility. */ case PragTyp_DEFAULT_CACHE_SIZE: { - static const int iLn = VDBE_OFFSET_LINENO(2); 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_Integer, 0, 2, 0}, @@ -98234,11 +97102,11 @@ sqlite3VdbeUsesBtree(v, iDb); if( !zRight ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC); pParse->nMem += 2; - addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn); + addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize); sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr+1, iDb); sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE); }else{ int size = sqlite3AbsInt32(sqlite3Atoi(zRight)); @@ -98479,21 +97347,20 @@ /* When setting the auto_vacuum mode to either "full" or ** "incremental", write the value of meta[6] in the database ** file. Before writing to meta[6], check that meta[3] indicates ** that this really is an auto-vacuum capable database. */ - static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList setMeta6[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE}, { OP_If, 1, 0, 0}, /* 2 */ { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */ { OP_Integer, 0, 1, 0}, /* 4 */ { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */ }; int iAddr; - iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn); + iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6); sqlite3VdbeChangeP1(v, iAddr, iDb); sqlite3VdbeChangeP1(v, iAddr+1, iDb); sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4); sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1); sqlite3VdbeChangeP1(v, iAddr+5, iDb); @@ -98515,14 +97382,14 @@ if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){ iLimit = 0x7fffffff; } sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1); - addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb); VdbeCoverage(v); + addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb); sqlite3VdbeAddOp1(v, OP_ResultRow, 1); sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); - sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr); sqlite3VdbeJumpHere(v, addr); break; } #endif @@ -98880,19 +97747,17 @@ Table *pTab = sqliteHashData(i); sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pTab->zName, 0); sqlite3VdbeAddOp2(v, OP_Null, 0, 2); sqlite3VdbeAddOp2(v, OP_Integer, (int)sqlite3LogEstToInt(pTab->szTabRow), 3); - sqlite3VdbeAddOp2(v, OP_Integer, - (int)sqlite3LogEstToInt(pTab->nRowLogEst), 4); + sqlite3VdbeAddOp2(v, OP_Integer, (int)pTab->nRowEst, 4); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); sqlite3VdbeAddOp2(v, OP_Integer, (int)sqlite3LogEstToInt(pIdx->szIdxRow), 3); - sqlite3VdbeAddOp2(v, OP_Integer, - (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]), 4); + sqlite3VdbeAddOp2(v, OP_Integer, (int)pIdx->aiRowEst[0], 4); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); } } } break; @@ -99091,11 +97956,11 @@ } } assert( pParse->nErr>0 || pFK==0 ); if( pFK ) break; if( pParse->nTabnTab = i; - addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v); + addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); pIdx = 0; aiCols = 0; if( pParent ){ @@ -99107,30 +97972,30 @@ 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); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow, - sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v); + 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); VdbeCoverage(v); + 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[j].iFrom, regRow+j); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); } if( pParent ){ - sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, - sqlite3IndexAffinityStr(v,pIdx), pFK->nCol); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey); + sqlite3VdbeChangeP4(v, -1, + sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT); sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); - VdbeCoverage(v); } } sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0, pFK->zTo, P4_TRANSIENT); @@ -99137,11 +98002,11 @@ 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); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); sqlite3VdbeJumpHere(v, addrTop); } } break; #endif /* !defined(SQLITE_OMIT_TRIGGER) */ @@ -99184,11 +98049,10 @@ /* Code that appears at the end of the integrity check. If no error ** messages have been generated, output OK. Otherwise output the ** error message */ - static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { { OP_AddImm, 1, 0, 0}, /* 0 */ { OP_IfNeg, 1, 0, 0}, /* 1 */ { OP_String8, 0, 3, 0}, /* 2 */ { OP_ResultRow, 3, 1, 0}, @@ -99233,11 +98097,10 @@ if( OMIT_TEMPDB && i==1 ) continue; if( iDb>=0 && i!=iDb ) continue; sqlite3CodeVerifySchema(pParse, i); addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */ - VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); sqlite3VdbeJumpHere(v, addr); /* Do an integrity check of the B-Tree ** @@ -99265,15 +98128,15 @@ pParse->nMem = MAX( pParse->nMem, cnt+8 ); /* Do the b-tree integrity checks */ sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1); sqlite3VdbeChangeP5(v, (u8)i); - addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); + addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P4_DYNAMIC); - sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); + sqlite3VdbeAddOp2(v, OP_Move, 2, 4); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. @@ -99287,11 +98150,10 @@ int r1 = -1; if( pTab->pIndex==0 ) continue; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */ - VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); sqlite3VdbeJumpHere(v, addr); sqlite3ExprCacheClear(pParse); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 1, 0, &iDataCur, &iIdxCur); @@ -99298,58 +98160,57 @@ sqlite3VdbeAddOp2(v, OP_Integer, 0, 7); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */ } pParse->nMem = MAX(pParse->nMem, 8+j); - sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2, jmp3, jmp4; if( pPk==pIdx ) continue; r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, pPrior, r1); pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1, - pIdx->nColumn); VdbeCoverage(v); + pIdx->nColumn); sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, " missing from index ", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); - jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); + jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); sqlite3VdbeAddOp0(v, OP_Halt); sqlite3VdbeJumpHere(v, jmp4); sqlite3VdbeJumpHere(v, jmp2); - sqlite3ResolvePartIdxLabel(pParse, jmp3); + sqlite3VdbeResolveLabel(v, jmp3); } - sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); sqlite3VdbeJumpHere(v, loopTop-1); #ifndef SQLITE_OMIT_BTREECOUNT sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, "wrong # of entries in index ", P4_STATIC); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ if( pPk==pIdx ) continue; addr = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); - sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT); sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7); sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1); } #endif /* SQLITE_OMIT_BTREECOUNT */ } } - addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); + addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); sqlite3VdbeChangeP2(v, addr, -mxErr); sqlite3VdbeJumpHere(v, addr+1); sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); } break; @@ -99483,11 +98344,11 @@ static const VdbeOpList setCookie[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ { OP_Integer, 0, 1, 0}, /* 1 */ { OP_SetCookie, 0, 0, 1}, /* 2 */ }; - int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); + int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie); sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight)); sqlite3VdbeChangeP1(v, addr+2, iDb); sqlite3VdbeChangeP2(v, addr+2, iCookie); }else{ @@ -99495,11 +98356,11 @@ static const VdbeOpList readCookie[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, 0}, /* 1 */ { OP_ResultRow, 1, 1, 0} }; - int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0); + int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie); sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr+1, iDb); sqlite3VdbeChangeP3(v, addr+1, iCookie); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT); @@ -100607,38 +99468,10 @@ ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. */ -/* -** An instance of the following object is used to record information about -** how to process the DISTINCT keyword, to simplify passing that information -** into the selectInnerLoop() routine. -*/ -typedef struct DistinctCtx DistinctCtx; -struct DistinctCtx { - u8 isTnct; /* True if the DISTINCT keyword is present */ - u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ - int tabTnct; /* Ephemeral table used for DISTINCT processing */ - int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ -}; - -/* -** An instance of the following object is used to record information about -** the ORDER BY (or GROUP BY) clause of query is being coded. -*/ -typedef struct SortCtx SortCtx; -struct SortCtx { - ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */ - int nOBSat; /* Number of ORDER BY terms satisfied by indices */ - int iECursor; /* Cursor number for the sorter */ - int regReturn; /* Register holding block-output return address */ - int labelBkOut; /* Start label for the block-output subroutine */ - int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ - u8 sortFlags; /* Zero or more SORTFLAG_* bits */ -}; -#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure but do not deallocate ** the select structure itself. */ @@ -100708,10 +99541,11 @@ pNew->pLimit = pLimit; pNew->pOffset = pOffset; assert( pOffset==0 || pLimit!=0 ); pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; + pNew->addrOpenEphm[2] = -1; if( db->mallocFailed ) { clearSelect(db, pNew); if( pNew!=&standin ) sqlite3DbFree(db, pNew); pNew = 0; }else{ @@ -100729,18 +99563,10 @@ clearSelect(db, p); sqlite3DbFree(db, p); } } -/* -** Return a pointer to the right-most SELECT statement in a compound. -*/ -static Select *findRightmost(Select *p){ - while( p->pNext ) p = p->pNext; - return p; -} - /* ** Given 1 to 3 identifiers preceding the JOIN keyword, determine the ** type of join. Return an integer constant that expresses that type ** in terms of the following bit values: ** @@ -101039,91 +99865,52 @@ } } return 0; } -/* Forward reference */ -static KeyInfo *keyInfoFromExprList( - Parse *pParse, /* Parsing context */ - ExprList *pList, /* Form the KeyInfo object from this ExprList */ - int iStart, /* Begin with this column of pList */ - int nExtra /* Add this many extra columns to the end */ -); - /* -** Insert code into "v" that will push the record in register regData -** into the sorter. +** Insert code into "v" that will push the record on the top of the +** stack into the sorter. */ static void pushOntoSorter( Parse *pParse, /* Parser context */ - SortCtx *pSort, /* Information about the ORDER BY clause */ + ExprList *pOrderBy, /* The ORDER BY clause */ Select *pSelect, /* The whole SELECT statement */ int regData /* Register holding data to be sorted */ ){ Vdbe *v = pParse->pVdbe; - int nExpr = pSort->pOrderBy->nExpr; - int regRecord = ++pParse->nMem; - int regBase = pParse->nMem+1; - int nOBSat = pSort->nOBSat; + int nExpr = pOrderBy->nExpr; + int regBase = sqlite3GetTempRange(pParse, nExpr+2); + int regRecord = sqlite3GetTempReg(pParse); int op; - - pParse->nMem += nExpr+2; /* nExpr+2 registers allocated at regBase */ sqlite3ExprCacheClear(pParse); - sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0); - sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); + sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0); + sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat,regRecord); - if( nOBSat>0 ){ - int regPrevKey; /* The first nOBSat columns of the previous row */ - int addrFirst; /* Address of the OP_IfNot opcode */ - int addrJmp; /* Address of the OP_Jump opcode */ - VdbeOp *pOp; /* Opcode that opens the sorter */ - int nKey; /* Number of sorting key columns, including OP_Sequence */ - KeyInfo *pKI; /* Original KeyInfo on the sorter table */ - - regPrevKey = pParse->nMem+1; - pParse->nMem += pSort->nOBSat; - nKey = nExpr - pSort->nOBSat + 1; - addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); - pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); - if( pParse->db->mallocFailed ) return; - pOp->p2 = nKey + 1; - pKI = pOp->p4.pKeyInfo; - memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ - sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); - pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1); - addrJmp = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); - pSort->labelBkOut = sqlite3VdbeMakeLabel(v); - pSort->regReturn = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); - sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); - sqlite3VdbeJumpHere(v, addrFirst); - sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat); - sqlite3VdbeJumpHere(v, addrJmp); - } - if( pSort->sortFlags & SORTFLAG_UseSorter ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord); + if( pSelect->selFlags & SF_UseSorter ){ op = OP_SorterInsert; }else{ op = OP_IdxInsert; } - sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); + sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord); + sqlite3ReleaseTempReg(pParse, regRecord); + sqlite3ReleaseTempRange(pParse, regBase, nExpr+2); if( pSelect->iLimit ){ int addr1, addr2; int iLimit; if( pSelect->iOffset ){ iLimit = pSelect->iOffset+1; }else{ iLimit = pSelect->iLimit; } - addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v); + addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1); addr2 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, addr1); - sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); - sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); + sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor); + sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor); sqlite3VdbeJumpHere(v, addr2); } } /* @@ -101132,14 +99919,14 @@ static void codeOffset( Vdbe *v, /* Generate code into this VM */ int iOffset, /* Register holding the offset counter */ int iContinue /* Jump here to skip the current record */ ){ - if( iOffset>0 ){ + if( iOffset>0 && iContinue!=0 ){ int addr; sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1); - addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v); + addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue); VdbeComment((v, "skip OFFSET records")); sqlite3VdbeJumpHere(v, addr); } } @@ -101163,11 +99950,11 @@ Vdbe *v; int r1; v = pParse->pVdbe; r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v); + sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1); sqlite3ReleaseTempReg(pParse, r1); } @@ -101193,10 +99980,23 @@ return 0; } } #endif +/* +** An instance of the following object is used to record information about +** how to process the DISTINCT keyword, to simplify passing that information +** into the selectInnerLoop() routine. +*/ +typedef struct DistinctCtx DistinctCtx; +struct DistinctCtx { + u8 isTnct; /* True if the DISTINCT keyword is present */ + u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ + int tabTnct; /* Ephemeral table used for DISTINCT processing */ + int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ +}; + /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** ** If srcTab is negative, then the pEList expressions @@ -101207,11 +100007,11 @@ static void selectInnerLoop( Parse *pParse, /* The parser context */ Select *p, /* The complete select statement being coded */ ExprList *pEList, /* List of values being extracted */ int srcTab, /* Pull data from this table */ - SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */ + ExprList *pOrderBy, /* If not NULL, sort results using this key */ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */ SelectDest *pDest, /* How to dispose of the results */ int iContinue, /* Jump here to continue with next row */ int iBreak /* Jump here to break out of the inner loop */ ){ @@ -101224,32 +100024,24 @@ int nResultCol; /* Number of result columns */ assert( v ); assert( pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; - if( pSort && pSort->pOrderBy==0 ) pSort = 0; - if( pSort==0 && !hasDistinct ){ - assert( iContinue!=0 ); + if( pOrderBy==0 && !hasDistinct ){ codeOffset(v, p->iOffset, iContinue); } /* Pull the requested columns. */ nResultCol = pEList->nExpr; - if( pDest->iSdst==0 ){ pDest->iSdst = pParse->nMem+1; - pParse->nMem += nResultCol; - }else if( pDest->iSdst+nResultCol > pParse->nMem ){ - /* This is an error condition that can result, for example, when a SELECT - ** on the right-hand side of an INSERT contains more result columns than - ** there are columns in the table on the left. The error will be caught - ** and reported later. But we need to make sure enough memory is allocated - ** to avoid other spurious errors in the meantime. */ - pParse->nMem += nResultCol; - } - pDest->nSdst = nResultCol; + pDest->nSdst = nResultCol; + pParse->nMem += nResultCol; + }else{ + assert( pDest->nSdst==nResultCol ); + } regResult = pDest->iSdst; if( srcTab>=0 ){ for(i=0; ia[i].zName)); @@ -101257,11 +100049,11 @@ }else if( eDest!=SRT_Exists ){ /* If the destination is an EXISTS(...) expression, the actual ** values returned by the SELECT are not required. */ sqlite3ExprCodeExprList(pParse, pEList, regResult, - (eDest==SRT_Output||eDest==SRT_Coroutine)?SQLITE_ECEL_DUP:0); + (eDest==SRT_Output)?SQLITE_ECEL_DUP:0); } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. @@ -101292,15 +100084,13 @@ iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; for(i=0; ia[i].pExpr); if( ieTnctType==WHERE_DISTINCT_UNORDERED ); codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult); break; } } - if( pSort==0 ){ + if( pOrderBy==0 ){ codeOffset(v, p->iOffset, iContinue); } } switch( eDest ){ @@ -101347,33 +100137,32 @@ } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ /* Store the result as data using a unique key. */ - case SRT_Fifo: - case SRT_DistFifo: + case SRT_DistTable: case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); #ifndef SQLITE_OMIT_CTE - if( eDest==SRT_DistFifo ){ - /* If the destination is DistFifo, then cursor (iParm+1) is open + if( eDest==SRT_DistTable ){ + /* If the destination is DistTable, then cursor (iParm+1) is open ** on an ephemeral index. If the current row is already present ** in the index, do not write it to the output. If not, add the ** current row to the index and proceed with writing it to the ** output table as well. */ int addr = sqlite3VdbeCurrentAddr(v) + 4; - sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v); + sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1); - assert( pSort==0 ); + assert( pOrderBy==0 ); } #endif - if( pSort ){ - pushOntoSorter(pParse, pSort, p, r1); + if( pOrderBy ){ + pushOntoSorter(pParse, pOrderBy, p, r1); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -101390,16 +100179,16 @@ */ case SRT_Set: { assert( nResultCol==1 ); pDest->affSdst = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst); - if( pSort ){ + if( pOrderBy ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ - pushOntoSorter(pParse, pSort, p, regResult); + pushOntoSorter(pParse, pOrderBy, p, regResult); }else{ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1); sqlite3ExprCacheAffinityChange(pParse, regResult, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); @@ -101420,28 +100209,32 @@ ** store the results in the appropriate memory cell and break out ** of the scan loop. */ case SRT_Mem: { assert( nResultCol==1 ); - if( pSort ){ - pushOntoSorter(pParse, pSort, p, regResult); + if( pOrderBy ){ + pushOntoSorter(pParse, pOrderBy, p, regResult); }else{ sqlite3ExprCodeMove(pParse, regResult, iParm, 1); /* The LIMIT clause will jump out of the loop for us */ } break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ - case SRT_Coroutine: /* Send data to a co-routine */ - case SRT_Output: { /* Return the results */ + /* Send the data to the callback function or to a subroutine. In the + ** case of a subroutine, the subroutine itself is responsible for + ** popping the data from the stack. + */ + case SRT_Coroutine: + case SRT_Output: { testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); - if( pSort ){ + if( pOrderBy ){ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); - pushOntoSorter(pParse, pSort, p, r1); + pushOntoSorter(pParse, pOrderBy, p, r1); sqlite3ReleaseTempReg(pParse, r1); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); @@ -101467,20 +100260,17 @@ assert( pSO ); nKey = pSO->nExpr; r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempRange(pParse, nKey+2); r3 = r2+nKey+1; + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r3); if( eDest==SRT_DistQueue ){ /* If the destination is DistQueue, then cursor (iParm+1) is open ** on a second ephemeral index that holds all values every previously - ** added to the queue. */ - addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0, - regResult, nResultCol); - VdbeCoverage(v); - } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r3); - if( eDest==SRT_DistQueue ){ + ** added to the queue. Only add this new value if it has never before + ** been added */ + addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0, r3, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); } for(i=0; iiLimit ){ - sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); + if( pOrderBy==0 && p->iLimit ){ + sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); } } /* ** Allocate a KeyInfo object sufficient for an index of N key columns and @@ -101585,32 +100375,27 @@ ** ** Space to hold the KeyInfo structure is obtain from malloc. The calling ** function is responsible for seeing that this structure is eventually ** freed. */ -static KeyInfo *keyInfoFromExprList( - Parse *pParse, /* Parsing context */ - ExprList *pList, /* Form the KeyInfo object from this ExprList */ - int iStart, /* Begin with this column of pList */ - int nExtra /* Add this many extra columns to the end */ -){ +static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){ int nExpr; KeyInfo *pInfo; struct ExprList_item *pItem; sqlite3 *db = pParse->db; int i; nExpr = pList->nExpr; - pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1); + pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra, 1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); - for(i=iStart, pItem=pList->a+iStart; ia; ipExpr); if( !pColl ) pColl = db->pDfltColl; - pInfo->aColl[i-iStart] = pColl; - pInfo->aSortOrder[i-iStart] = pItem->sortOrder; + pInfo->aColl[i] = pColl; + pInfo->aSortOrder[i] = pItem->sortOrder; } } return pInfo; } @@ -101708,60 +100493,49 @@ ** routine generates the code needed to do that. */ static void generateSortTail( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ - SortCtx *pSort, /* Information on the ORDER BY clause */ + Vdbe *v, /* Generate code into this VDBE */ int nColumn, /* Number of columns of data */ SelectDest *pDest /* Write the sorted results here */ ){ - Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */ int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */ int addr; - int addrOnce = 0; int iTab; int pseudoTab = 0; - ExprList *pOrderBy = pSort->pOrderBy; + ExprList *pOrderBy = p->pOrderBy; + int eDest = pDest->eDest; int iParm = pDest->iSDParm; + int regRow; int regRowid; - int nKey; - - if( pSort->labelBkOut ){ - sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak); - sqlite3VdbeResolveLabel(v, pSort->labelBkOut); - addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); - } - iTab = pSort->iECursor; + + iTab = pOrderBy->iECursor; regRow = sqlite3GetTempReg(pParse); if( eDest==SRT_Output || eDest==SRT_Coroutine ){ pseudoTab = pParse->nTab++; sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn); regRowid = 0; }else{ regRowid = sqlite3GetTempReg(pParse); } - nKey = pOrderBy->nExpr - pSort->nOBSat; - if( pSort->sortFlags & SORTFLAG_UseSorter ){ + if( p->selFlags & SF_UseSorter ){ int regSortOut = ++pParse->nMem; int ptab2 = pParse->nTab++; - sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2); - if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); + sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); - VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut); - sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow); + sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow); sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); }else{ - if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); - addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); + addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); codeOffset(v, p->iOffset, addrContinue); - sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow); + sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow); } switch( eDest ){ case SRT_Table: case SRT_EphemTab: { testcase( eDest==SRT_Table ); @@ -101812,17 +100586,19 @@ sqlite3ReleaseTempReg(pParse, regRowid); /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); - if( pSort->sortFlags & SORTFLAG_UseSorter ){ - sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v); + if( p->selFlags & SF_UseSorter ){ + sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); }else{ - sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); } - if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn); sqlite3VdbeResolveLabel(v, addrBreak); + if( eDest==SRT_Output || eDest==SRT_Coroutine ){ + sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0); + } } /* ** Return a pointer to a string containing the 'declaration type' of the ** expression pExpr. The string may be treated as static by the caller. @@ -102184,11 +100960,11 @@ for(j=cnt=0; j1 && sqlite3Isdigit(zName[k]); k--){} - if( k>=0 && zName[k]==':' ) nName = k; + if( zName[k]==':' ) nName = k; zName[nName] = 0; zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt); sqlite3DbFree(db, zName); zName = zNewName; j = -1; @@ -102278,11 +101054,11 @@ /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside ** is disabled */ assert( db->lookaside.bEnabled==0 ); pTab->nRef = 1; pTab->zName = 0; - pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + pTab->nRowEst = 1048576; selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); selectAddColumnTypeAndCollation(pParse, pTab, pSelect); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); @@ -102297,17 +101073,15 @@ */ SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ Vdbe *v = pParse->pVdbe; if( v==0 ){ v = pParse->pVdbe = sqlite3VdbeCreate(pParse); - if( v ) sqlite3VdbeAddOp0(v, OP_Init); - if( pParse->pToplevel==0 - && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst) - ){ - pParse->okConstFactor = 1; +#ifndef SQLITE_OMIT_TRACE + if( v ){ + sqlite3VdbeAddOp0(v, OP_Trace); } - +#endif } return v; } @@ -102361,26 +101135,26 @@ }else if( n>=0 && p->nSelectRow>(u64)n ){ p->nSelectRow = n; } }else{ sqlite3ExprCode(pParse, p->pLimit, iLimit); - sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeComment((v, "LIMIT counter")); - sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); } if( p->pOffset ){ p->iOffset = iOffset = ++pParse->nMem; pParse->nMem++; /* Allocate an extra register for limit+offset */ sqlite3ExprCode(pParse, p->pOffset, iOffset); - sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeComment((v, "OFFSET counter")); - addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset); VdbeCoverage(v); + addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset); sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1); VdbeComment((v, "LIMIT+OFFSET")); - addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit); VdbeCoverage(v); + addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit); sqlite3VdbeAddOp2(v, OP_Integer, -1, iOffset+1); sqlite3VdbeJumpHere(v, addr1); } } } @@ -102496,11 +101270,11 @@ int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ int iCurrent = 0; /* The Current table */ int regCurrent; /* Register holding Current table */ int iQueue; /* The Queue table */ int iDistinct = 0; /* To ensure unique results if UNION */ - int eDest = SRT_Fifo; /* How to write to Queue */ + int eDest = SRT_Table; /* How to write to Queue */ SelectDest destQueue; /* SelectDest targetting the Queue table */ int i; /* Loop counter */ int rc; /* Result code */ ExprList *pOrderBy; /* The ORDER BY clause */ Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */ @@ -102528,17 +101302,17 @@ } } /* Allocate cursors numbers for Queue and Distinct. The cursor number for ** the Distinct table must be exactly one greater than Queue in order - ** for the SRT_DistFifo and SRT_DistQueue destinations to work. */ + ** for the SRT_DistTable and SRT_DistQueue destinations to work. */ iQueue = pParse->nTab++; if( p->op==TK_UNION ){ - eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo; + eDest = pOrderBy ? SRT_DistQueue : SRT_DistTable; iDistinct = pParse->nTab++; }else{ - eDest = pOrderBy ? SRT_Queue : SRT_Fifo; + eDest = pOrderBy ? SRT_Queue : SRT_Table; } sqlite3SelectDestInit(&destQueue, eDest, iQueue); /* Allocate cursors for Current, Queue, and Distinct. */ regCurrent = ++pParse->nMem; @@ -102559,17 +101333,15 @@ /* Detach the ORDER BY clause from the compound SELECT */ p->pOrderBy = 0; /* Store the results of the setup-query in Queue. */ - pSetup->pNext = 0; rc = sqlite3Select(pParse, pSetup, &destQueue); - pSetup->pNext = p; if( rc ) goto end_of_recursive_query; /* Find the next row in the Queue and output that row */ - addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v); + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); /* Transfer the next row in Queue over to Current */ sqlite3VdbeAddOp1(v, OP_NullRow, iCurrent); /* To reset column cache */ if( pOrderBy ){ sqlite3VdbeAddOp3(v, OP_Column, iQueue, pOrderBy->nExpr+1, regCurrent); @@ -102581,14 +101353,11 @@ /* Output the single row in Current */ addrCont = sqlite3VdbeMakeLabel(v); codeOffset(v, regOffset, addrCont); selectInnerLoop(pParse, p, p->pEList, iCurrent, 0, 0, pDest, addrCont, addrBreak); - if( regLimit ){ - sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1); - VdbeCoverage(v); - } + if( regLimit ) sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1); sqlite3VdbeResolveLabel(v, addrCont); /* Execute the recursive SELECT taking the single row in Current as ** the value for the recursive-table. Store the results in the Queue. */ @@ -102600,11 +101369,10 @@ /* Keep running the loop until the Queue is empty */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); sqlite3VdbeResolveLabel(v, addrBreak); end_of_recursive_query: - sqlite3ExprListDelete(pParse->db, p->pOrderBy); p->pOrderBy = pOrderBy; p->pLimit = pLimit; p->pOffset = pOffset; return; } @@ -102670,10 +101438,12 @@ */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); db = pParse->db; pPrior = p->pPrior; + assert( pPrior->pRightmost!=pPrior ); + assert( pPrior->pRightmost==p->pRightmost ); dest = *pDest; if( pPrior->pOrderBy ){ sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before", selectOpName(p->op)); rc = 1; @@ -102745,11 +101515,11 @@ } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ - addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeCoverage(v); + addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeComment((v, "Jump ahead if LIMIT reached")); } explainSetInteger(iSub2, pParse->iNextSelectId); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); @@ -102777,14 +101547,16 @@ SelectDest uniondest; testcase( p->op==TK_EXCEPT ); testcase( p->op==TK_UNION ); priorOp = SRT_Union; - if( dest.eDest==priorOp ){ + if( dest.eDest==priorOp && ALWAYS(!p->pLimit &&!p->pOffset) ){ /* We can reuse a temporary table generated by a SELECT to our ** right. */ + assert( p->pRightmost!=p ); /* Can only happen for leftward elements + ** of a 3-way or more compound */ assert( p->pLimit==0 ); /* Not allowed on leftward elements */ assert( p->pOffset==0 ); /* Not allowed on leftward elements */ unionTab = dest.iSDParm; }else{ /* We will need to create our own temporary table to hold the @@ -102793,11 +101565,11 @@ unionTab = pParse->nTab++; assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; - findRightmost(p)->selFlags |= SF_UsesEphemeral; + p->pRightmost->selFlags |= SF_UsesEphemeral; assert( p->pEList ); } /* Code the SELECT statements to our left */ @@ -102852,16 +101624,16 @@ generateColumnNames(pParse, 0, pFirst->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, p->pEList, unionTab, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); } break; } @@ -102882,11 +101654,11 @@ assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; - findRightmost(p)->selFlags |= SF_UsesEphemeral; + p->pRightmost->selFlags |= SF_UsesEphemeral; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); @@ -102927,19 +101699,19 @@ generateColumnNames(pParse, 0, pFirst->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1); - sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); + sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); sqlite3ReleaseTempReg(pParse, r1); selectInnerLoop(pParse, p, p->pEList, tab1, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); break; } @@ -102961,11 +101733,11 @@ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ Select *pLoop; /* For looping through SELECT statements */ CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ int nCol; /* Number of columns in result set */ - assert( p->pNext==0 ); + assert( p->pRightmost==p ); nCol = p->pEList->nExpr; pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); if( !pKeyInfo ){ rc = SQLITE_NOMEM; goto multi_select_end; @@ -103042,14 +101814,14 @@ /* Suppress duplicates for UNION, EXCEPT, and INTERSECT */ if( regPrev ){ int j1, j2; - j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v); + j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); j2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst, (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); - sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2); sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1); sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev); } if( pParse->db->mallocFailed ) return 0; @@ -103146,11 +101918,11 @@ } /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit ){ - sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); } /* Generate the subroutine return */ sqlite3VdbeResolveLabel(v, iContinue); @@ -103254,19 +102026,20 @@ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ SelectDest destA; /* Destination for coroutine A */ SelectDest destB; /* Destination for coroutine B */ int regAddrA; /* Address register for select-A coroutine */ + int regEofA; /* Flag to indicate when select-A is complete */ int regAddrB; /* Address register for select-B coroutine */ + int regEofB; /* Flag to indicate when select-B is complete */ int addrSelectA; /* Address of the select-A coroutine */ int addrSelectB; /* Address of the select-B coroutine */ int regOutA; /* Address register for the output-A subroutine */ int regOutB; /* Address register for the output-B subroutine */ int addrOutA; /* Address of the output-A subroutine */ int addrOutB = 0; /* Address of the output-B subroutine */ int addrEofA; /* Address of the select-A-exhausted subroutine */ - int addrEofA_noB; /* Alternate addrEofA if B is uninitialized */ int addrEofB; /* Address of the select-B-exhausted subroutine */ int addrAltB; /* Address of the AB subroutine */ int regLimitA; /* Limit register for select-A */ @@ -103377,11 +102150,10 @@ } /* Separate the left and the right query from one another */ p->pPrior = 0; - pPrior->pNext = 0; sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER"); if( pPrior->pPrior==0 ){ sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER"); } @@ -103400,43 +102172,52 @@ p->pLimit = 0; sqlite3ExprDelete(db, p->pOffset); p->pOffset = 0; regAddrA = ++pParse->nMem; + regEofA = ++pParse->nMem; regAddrB = ++pParse->nMem; + regEofB = ++pParse->nMem; regOutA = ++pParse->nMem; regOutB = ++pParse->nMem; sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); + + /* Jump past the various subroutines and coroutines to the main + ** merge loop + */ + j1 = sqlite3VdbeAddOp0(v, OP_Goto); + addrSelectA = sqlite3VdbeCurrentAddr(v); + /* Generate a coroutine to evaluate the SELECT statement to the ** left of the compound operator - the "A" select. */ - addrSelectA = sqlite3VdbeCurrentAddr(v) + 1; - j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); - VdbeComment((v, "left SELECT")); + VdbeNoopComment((v, "Begin coroutine for left SELECT")); pPrior->iLimit = regLimitA; explainSetInteger(iSub1, pParse->iNextSelectId); sqlite3Select(pParse, pPrior, &destA); - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA); - sqlite3VdbeJumpHere(v, j1); + sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); + VdbeNoopComment((v, "End coroutine for left SELECT")); /* Generate a coroutine to evaluate the SELECT statement on ** the right - the "B" select */ - addrSelectB = sqlite3VdbeCurrentAddr(v) + 1; - j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB); - VdbeComment((v, "right SELECT")); + addrSelectB = sqlite3VdbeCurrentAddr(v); + VdbeNoopComment((v, "Begin coroutine for right SELECT")); savedLimit = p->iLimit; savedOffset = p->iOffset; p->iLimit = regLimitB; p->iOffset = 0; explainSetInteger(iSub2, pParse->iNextSelectId); sqlite3Select(pParse, p, &destB); p->iLimit = savedLimit; p->iOffset = savedOffset; - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB); + sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); + VdbeNoopComment((v, "End coroutine for right SELECT")); /* Generate a subroutine that outputs the current row of the A ** select as the next output row of the compound select. */ VdbeNoopComment((v, "Output routine for A")); @@ -103456,17 +102237,17 @@ sqlite3KeyInfoUnref(pKeyDup); /* Generate a subroutine to run when the results from select A ** are exhausted and only data in select B remains. */ + VdbeNoopComment((v, "eof-A subroutine")); if( op==TK_EXCEPT || op==TK_INTERSECT ){ - addrEofA_noB = addrEofA = labelEnd; + addrEofA = sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd); }else{ - VdbeNoopComment((v, "eof-A subroutine")); - addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); - addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd); - VdbeCoverage(v); + addrEofA = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd); + sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA); p->nSelectRow += pPrior->nSelectRow; } /* Generate a subroutine to run when the results from select B @@ -103475,20 +102256,22 @@ if( op==TK_INTERSECT ){ addrEofB = addrEofA; if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; }else{ VdbeNoopComment((v, "eof-B subroutine")); - addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); - sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v); + addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd); + sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofB); } /* Generate code to handle the case of AB */ @@ -103508,27 +102292,32 @@ VdbeNoopComment((v, "A-gt-B subroutine")); addrAgtB = sqlite3VdbeCurrentAddr(v); if( op==TK_ALL || op==TK_UNION ){ sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); } - sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); + sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB); sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr); /* This code runs once to initialize everything. */ sqlite3VdbeJumpHere(v, j1); - sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB); + sqlite3VdbeAddOp2(v, OP_Gosub, regAddrA, addrSelectA); + sqlite3VdbeAddOp2(v, OP_Gosub, regAddrB, addrSelectB); + sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA); + sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB); /* Implement the main merge loop */ 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); sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); - sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); /* Jump to the this point in order to terminate the query. */ sqlite3VdbeResolveLabel(v, labelEnd); @@ -103544,11 +102333,10 @@ ** by the calling function */ if( p->pPrior ){ sqlite3SelectDelete(db, p->pPrior); } p->pPrior = pPrior; - pPrior->pNext = p; /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ explainComposite(pParse, p->op, iSub1, iSub2, 0); return SQLITE_OK; @@ -103810,11 +102598,11 @@ ** because they could be computed at compile-time. But when LIMIT and OFFSET ** became arbitrary expressions, we were forced to add restrictions (13) ** and (14). */ if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */ if( pSub->pOffset ) return 0; /* Restriction (14) */ - if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){ + if( p->pRightmost && pSub->pLimit ){ return 0; /* Restriction (15) */ } if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */ if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){ @@ -103961,18 +102749,18 @@ p->pOffset = pOffset; p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->pSrc = pSrc; p->op = TK_ALL; + p->pRightmost = 0; if( pNew==0 ){ - p->pPrior = pPrior; + pNew = pPrior; }else{ pNew->pPrior = pPrior; - if( pPrior ) pPrior->pNext = pNew; - pNew->pNext = p; - p->pPrior = pNew; + pNew->pRightmost = 0; } + p->pPrior = pNew; if( db->mallocFailed ) return 1; } /* Begin flattening the iFrom-th entry of the FROM clause ** in the outer query. @@ -104307,14 +103095,10 @@ p->pWhere = 0; pNew->pGroupBy = 0; pNew->pHaving = 0; pNew->pOrderBy = 0; p->pPrior = 0; - p->pNext = 0; - p->selFlags &= ~SF_Compound; - assert( pNew->pPrior!=0 ); - pNew->pPrior->pNext = pNew; pNew->pLimit = 0; pNew->pOffset = 0; return WRC_Continue; } @@ -104417,11 +103201,11 @@ pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; pTab->nRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; - pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + pTab->nRowEst = 1048576; pTab->tabFlags |= TF_Ephemeral; pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); if( db->mallocFailed ) return SQLITE_NOMEM; assert( pFrom->pSelect ); @@ -104498,14 +103282,13 @@ ** sqlite3SelectExpand() when walking a SELECT tree to resolve table ** names and other FROM clause elements. */ static void selectPopWith(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; - With *pWith = findRightmost(p)->pWith; - if( pWith!=0 ){ - assert( pParse->pWith==pWith ); - pParse->pWith = pWith->pOuter; + if( p->pWith ){ + assert( pParse->pWith==p->pWith ); + pParse->pWith = p->pWith->pOuter; } } #else #define selectPopWith 0 #endif @@ -104551,11 +103334,11 @@ if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } pTabList = p->pSrc; pEList = p->pEList; - sqlite3WithPush(pParse, findRightmost(p)->pWith, 0); + sqlite3WithPush(pParse, p->pWith, 0); /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. */ sqlite3SrcListAssignCursors(pParse, pTabList); @@ -104593,11 +103376,11 @@ pTab->nRef = 1; pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab); while( pSel->pPrior ){ pSel = pSel->pPrior; } selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol); pTab->iPKey = -1; - pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + pTab->nRowEst = 1048576; pTab->tabFlags |= TF_Ephemeral; #endif }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); @@ -104972,11 +103755,11 @@ if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one " "argument"); pFunc->iDistinct = -1; }else{ - KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0); + KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0); sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); } } } @@ -105064,11 +103847,11 @@ ** ** Another solution would be to change the OP_SCopy used to copy cached ** values to an OP_Copy. */ if( regHit ){ - addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); + addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); } sqlite3ExprCacheClear(pParse); for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ sqlite3ExprCode(pParse, pC->pExpr, pC->iMem); } @@ -105088,15 +103871,14 @@ Parse *pParse, /* Parse context */ Table *pTab, /* Table being queried */ Index *pIdx /* Index used to optimize scan, or NULL */ ){ if( pParse->explain==2 ){ - int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", - pTab->zName, - bCover ? " USING COVERING INDEX " : "", - bCover ? pIdx->zName : "" + pTab->zName, + pIdx ? " USING COVERING INDEX " : "", + pIdx ? pIdx->zName : "" ); sqlite3VdbeAddOp4( pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC ); } @@ -105128,15 +103910,16 @@ Vdbe *v; /* The virtual machine under construction */ int isAgg; /* True for select lists like "count(*)" */ ExprList *pEList; /* List of columns to extract. */ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ + ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ int rc = 1; /* Value to return from this function */ + int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ - SortCtx sSort; /* Info on how to code the ORDER BY clause */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ #ifndef SQLITE_OMIT_EXPLAIN @@ -105149,28 +103932,21 @@ return 1; } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); - assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); - assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); - assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); - assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); if( IgnorableOrderby(pDest) ){ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || - pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || - pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo || - pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo); + pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard); /* If ORDER BY makes no difference in the output then neither does ** DISTINCT so it can be removed too. */ sqlite3ExprListDelete(db, p->pOrderBy); p->pOrderBy = 0; p->selFlags &= ~SF_Distinct; } sqlite3SelectPrep(pParse, p, 0); - memset(&sSort, 0, sizeof(sSort)); - sSort.pOrderBy = p->pOrderBy; + pOrderBy = p->pOrderBy; pTabList = p->pSrc; pEList = p->pEList; if( pParse->nErr || db->mallocFailed ){ goto select_end; } @@ -105230,28 +104006,46 @@ if( isAggSub ){ isAgg = 1; p->selFlags |= SF_Aggregate; } i = -1; - }else if( pTabList->nSrc==1 - && OptimizationEnabled(db, SQLITE_SubqCoroutine) + }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 = sqlite3VdbeCurrentAddr(v)+1; + int addrTop; + int addrEof; pItem->regReturn = ++pParse->nMem; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); - VdbeComment((v, "%s", pItem->pTab->zName)); + 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->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); + pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; pItem->viaCoroutine = 1; - pItem->regResult = dest.iSdst; - sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); + 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 @@ -105263,23 +104057,21 @@ int retAddr; assert( pItem->addrFillSub==0 ); 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 ** a trigger, then we only need to compute the value of the subquery ** once. */ - onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); - VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); - }else{ - VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); + onceAddr = sqlite3CodeOnce(pParse); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); + pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %s", pItem->pTab->zName)); sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); @@ -105288,11 +104080,11 @@ goto select_end; } pParse->nHeight -= sqlite3SelectExprHeight(p); pTabList = p->pSrc; if( !IgnorableOrderby(pDest) ){ - sSort.pOrderBy = p->pOrderBy; + pOrderBy = p->pOrderBy; } } pEList = p->pEList; #endif pWhere = p->pWhere; @@ -105302,15 +104094,42 @@ #ifndef SQLITE_OMIT_COMPOUND_SELECT /* If there is are a sequence of queries, do the earlier ones first. */ if( p->pPrior ){ + if( p->pRightmost==0 ){ + Select *pLoop, *pRight = 0; + int cnt = 0; + int mxSelect; + for(pLoop=p; pLoop; pLoop=pLoop->pPrior, cnt++){ + pLoop->pRightmost = p; + pLoop->pNext = pRight; + pRight = pLoop; + } + mxSelect = db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT]; + if( mxSelect && cnt>mxSelect ){ + sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); + goto select_end; + } + } rc = multiSelect(pParse, p, pDest); explainSetInteger(pParse->iSelectId, iRestoreSelectId); return rc; } #endif + + /* If there is both a GROUP BY and an ORDER BY clause and they are + ** identical, then disable the ORDER BY clause since the GROUP BY + ** will cause elements to come out in the correct order. This is + ** an optimization - the correct answer should result regardless. + ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER + ** to disable this optimization for testing purposes. + */ + if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0 + && OptimizationEnabled(db, SQLITE_GroupByOrder) ){ + pOrderBy = 0; + } /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: ** @@ -105324,16 +104143,16 @@ ** used for both the ORDER BY and DISTINCT processing. As originally ** written the query must use a temp-table for at least one of the ORDER ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct - && sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0 + && sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0 ){ p->selFlags &= ~SF_Distinct; p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); pGroupBy = p->pGroupBy; - sSort.pOrderBy = 0; + pOrderBy = 0; /* Notice that even thought SF_Distinct has been cleared from p->selFlags, ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ assert( sDistinct.isTnct ); } @@ -105343,20 +104162,20 @@ ** extracted in pre-sorted order. If that is the case, then the ** OP_OpenEphemeral instruction will be changed to an OP_Noop once ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. */ - if( sSort.pOrderBy ){ + if( pOrderBy ){ KeyInfo *pKeyInfo; - pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0); - sSort.iECursor = pParse->nTab++; - sSort.addrSortIndex = + pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0); + pOrderBy->iECursor = pParse->nTab++; + p->addrOpenEphm[2] = addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - sSort.iECursor, sSort.pOrderBy->nExpr+2, 0, + pOrderBy->iECursor, pOrderBy->nExpr+2, 0, (char*)pKeyInfo, P4_KEYINFO); }else{ - sSort.addrSortIndex = -1; + addrSortIndex = -1; } /* If the output is destined for a temporary table, open that table. */ if( pDest->eDest==SRT_EphemTab ){ @@ -105366,22 +104185,22 @@ /* Set the limiter. */ iEnd = sqlite3VdbeMakeLabel(v); p->nSelectRow = LARGEST_INT64; computeLimitRegisters(pParse, p, iEnd); - if( p->iLimit==0 && sSort.addrSortIndex>=0 ){ - sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen; - sSort.sortFlags |= SORTFLAG_UseSorter; + if( p->iLimit==0 && addrSortIndex>=0 ){ + sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen; + p->selFlags |= SF_UseSorter; } /* Open a virtual index to use for the distinct set. */ if( p->selFlags & SF_Distinct ){ sDistinct.tabTnct = pParse->nTab++; sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, sDistinct.tabTnct, 0, 0, - (char*)keyInfoFromExprList(pParse, p->pEList,0,0), + (char*)keyInfoFromExprList(pParse, p->pEList, 0), P4_KEYINFO); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; }else{ sDistinct.eTnctType = WHERE_DISTINCT_NOOP; @@ -105390,36 +104209,32 @@ if( !isAgg && pGroupBy==0 ){ /* No aggregate functions and no GROUP BY clause */ u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); /* Begin the database scan. */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, - p->pEList, wctrlFlags, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList, + wctrlFlags, 0); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } - if( sSort.pOrderBy ){ - sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); - if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ - sSort.pOrderBy = 0; - } - } + if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0; /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ - if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){ - sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); + if( addrSortIndex>=0 && pOrderBy==0 ){ + sqlite3VdbeChangeToNoop(v, addrSortIndex); + p->addrOpenEphm[2] = -1; } /* Use the standard inner loop. */ - selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest, + selectInnerLoop(pParse, p, pEList, -1, pOrderBy, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); /* End the database scan loop. */ @@ -105436,11 +104251,10 @@ int iAbortFlag; /* Mem address which causes query abort if positive */ int groupBySort; /* Rows come from source in GROUP BY order */ int addrEnd; /* End of processing for this SELECT */ int sortPTab = 0; /* Pseudotable used to decode sorting results */ int sortOut = 0; /* Output register from the sorter */ - int orderByGrp = 0; /* True if the GROUP BY and ORDER BY are the same */ /* Remove any and all aliases between the result set and the ** GROUP BY clause. */ if( pGroupBy ){ @@ -105456,22 +104270,10 @@ if( p->nSelectRow>100 ) p->nSelectRow = 100; }else{ p->nSelectRow = 1; } - - /* If there is both a GROUP BY and an ORDER BY clause and they are - ** identical, then it may be possible to disable the ORDER BY clause - ** on the grounds that the GROUP BY will cause elements to come out - ** in the correct order. It also may not - the GROUP BY may use a - ** database index that causes rows to be grouped together as required - ** but not actually sorted. Either way, record the fact that the - ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp - ** variable. */ - if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ - orderByGrp = 1; - } /* Create a label to jump to when we want to abort the query */ addrEnd = sqlite3VdbeMakeLabel(v); /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in @@ -105484,11 +104286,11 @@ sNC.pAggInfo = &sAggInfo; sAggInfo.mnReg = pParse->nMem+1; sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; sAggInfo.pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); - sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); + sqlite3ExprAnalyzeAggList(&sNC, pOrderBy); if( pHaving ){ sqlite3ExprAnalyzeAggregates(&sNC, pHaving); } sAggInfo.nAccumulator = sAggInfo.nColumn; for(i=0; inTab++; - pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0); + pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0); addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); /* Initialize memory locations used by GROUP BY aggregate processing @@ -105547,15 +104349,14 @@ ** This might involve two separate loops with an OP_Sort in between, or ** it might be a single loop that uses an index to extract information ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, - WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 - ); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, + WHERE_GROUPBY, 0); if( pWInfo==0 ) goto select_end; - if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ + if( sqlite3WhereIsOrdered(pWInfo) ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo */ groupBySort = 0; @@ -105611,28 +104412,13 @@ sqlite3WhereEnd(pWInfo); sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++; sortOut = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd); - VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); + VdbeComment((v, "GROUP BY sort")); sAggInfo.useSortingIdx = 1; sqlite3ExprCacheClear(pParse); - - } - - /* If the index or temporary table used by the GROUP BY sort - ** will naturally deliver rows in the order required by the ORDER BY - ** clause, cancel the ephemeral table open coded earlier. - ** - ** This is an optimization - the correct answer should result regardless. - ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to - ** disable this optimization for testing purposes. */ - if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder) - && (groupBySort || sqlite3WhereIsSorted(pWInfo)) - ){ - sSort.pOrderBy = 0; - sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } /* Evaluate the current GROUP BY terms and store in b0, b1, b2... ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) ** Then compare the current GROUP BY terms against the GROUP BY terms @@ -105653,11 +104439,11 @@ } } sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); j1 = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp3(v, OP_Jump, j1+1, 0, j1+1); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Jump, j1+1, 0, j1+1); /* Generate code that runs whenever the GROUP BY changes. ** Changes in the GROUP BY are detected by the previous code ** block. If there were no changes, this block is skipped. ** @@ -105667,11 +104453,11 @@ ** for the next GROUP BY batch. */ sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr); sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); VdbeComment((v, "output one row")); - sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeComment((v, "check abort flag")); sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); VdbeComment((v, "reset accumulator")); /* Update the aggregate accumulators based on the content of @@ -105684,11 +104470,10 @@ /* End of the loop */ if( groupBySort ){ sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop); - VdbeCoverage(v); }else{ sqlite3WhereEnd(pWInfo); sqlite3VdbeChangeToNoop(v, addrSortingIdx); } @@ -105712,16 +104497,16 @@ sqlite3VdbeAddOp2(v, OP_Integer, 1, iAbortFlag); VdbeComment((v, "set abort flag")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); sqlite3VdbeResolveLabel(v, addrOutputRow); addrOutputRow = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, &sAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, &sSort, + selectInnerLoop(pParse, p, p->pEList, -1, pOrderBy, &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); VdbeComment((v, "end groupby result generator")); @@ -105849,20 +104634,20 @@ sqlite3ExprListDelete(db, pDel); goto select_end; } updateAccumulator(pParse, &sAggInfo); assert( pMinMax==0 || pMinMax->nExpr==1 ); - if( sqlite3WhereIsOrdered(pWInfo)>0 ){ + if( sqlite3WhereIsOrdered(pWInfo) ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo)); VdbeComment((v, "%s() by index", (flag==WHERE_ORDERBY_MIN?"min":"max"))); } sqlite3WhereEnd(pWInfo); finalizeAggFunctions(pParse, &sAggInfo); } - sSort.pOrderBy = 0; + pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, pDest, addrEnd, addrEnd); sqlite3ExprListDelete(db, pDel); } @@ -105875,13 +104660,13 @@ } /* If there is an ORDER BY clause, then we need to sort the results ** and send them to the callback one by one. */ - if( sSort.pOrderBy ){ - explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); - generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); + if( pOrderBy ){ + explainTempTable(pParse, "ORDER BY"); + generateSortTail(pParse, p, v, pEList->nExpr, pDest); } /* Jump here to skip this query */ sqlite3VdbeResolveLabel(v, iEnd); @@ -105984,10 +104769,14 @@ } 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; } sqlite3ExplainPush(pVdbe); while( p ){ explainOneSelect(pVdbe, p); p = p->pNext; @@ -106769,11 +105558,10 @@ /* Generate code to destroy the database record of the trigger. */ assert( pTable!=0 ); if( (v = sqlite3GetVdbe(pParse))!=0 ){ int base; - static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList dropTrigger[] = { { OP_Rewind, 0, ADDR(9), 0}, { OP_String8, 0, 1, 0}, /* 1 */ { OP_Column, 0, 1, 2}, { OP_Ne, 2, ADDR(8), 1}, @@ -106784,11 +105572,11 @@ { OP_Next, 0, ADDR(1), 0}, /* 8 */ }; sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3OpenMasterTable(pParse, iDb); - base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger, iLn); + base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); sqlite3VdbeChangeP4(v, base+1, pTrigger->zName, P4_TRANSIENT); sqlite3VdbeChangeP4(v, base+4, "trigger", P4_STATIC); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp2(v, OP_Close, 0, 0); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); @@ -106930,11 +105718,19 @@ ** ** 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; - assert( pParse->okConstFactor==0 ); + + /* 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), @@ -107516,11 +106312,11 @@ */ pTabList->a[0].iCursor = iBaseCur = iDataCur = pParse->nTab++; iIdxCur = iDataCur+1; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ - if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){ + if( pIdx->autoIndex==2 && pPk!=0 ){ iDataCur = pParse->nTab; pTabList->a[0].iCursor = iDataCur; } pParse->nTab++; } @@ -107719,11 +106515,11 @@ sqlite3VdbeChangeToNoop(v, addrOpen); nKey = nPk; regKey = iPk; }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, - sqlite3IndexAffinityStr(v, pPk), nPk); + sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT); sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey); } sqlite3WhereEnd(pWInfo); } @@ -107763,37 +106559,32 @@ /* Top of the update loop */ if( okOnePass ){ if( aToOpen[iDataCur-iBaseCur] ){ assert( pPk!=0 ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey); - VdbeCoverageNeverTaken(v); } labelContinue = labelBreak; sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); - VdbeCoverage(v); }else if( pPk ){ labelContinue = sqlite3VdbeMakeLabel(v); - sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0); - VdbeCoverage(v); }else{ labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, labelBreak, regOldRowid); - VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); - VdbeCoverage(v); } /* If the record number will change, set register regNewRowid to ** contain the new value. If the record number is not being modified, ** then regNewRowid is the same register as regOldRowid, which is ** already populated. */ assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid ); if( chngRowid ){ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); - sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); } /* Compute the old pre-UPDATE content of the row being changed, if that ** information is needed */ if( chngPk || hasFK || pTrigger ){ @@ -107858,11 +106649,12 @@ /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ if( tmask&TRIGGER_BEFORE ){ - sqlite3TableAffinity(v, pTab, regNew); + sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol); + sqlite3TableAffinityStr(v, pTab); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue); /* The row-trigger may have deleted the row being updated. In this ** case, jump to the next row. No updates or AFTER triggers are @@ -107870,14 +106662,12 @@ ** is deleted or renamed by a BEFORE trigger - is left undefined in the ** documentation. */ if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey); - VdbeCoverage(v); }else{ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); - VdbeCoverage(v); } /* If it did not delete it, the row-trigger may still have modified ** some of the columns of the row being updated. Load the values for ** all columns not modified by the update statement into their @@ -107909,11 +106699,10 @@ if( pPk ){ j1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey); }else{ j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid); } - VdbeCoverageNeverTaken(v); } sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx); /* If changing the record number, delete the old record. */ if( hasFK || chngKey || pPk!=0 ){ @@ -107953,11 +106742,11 @@ */ if( okOnePass ){ /* Nothing to do at end-of-loop for a single-pass */ }else if( pPk ){ sqlite3VdbeResolveLabel(v, labelContinue); - sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); }else{ sqlite3VdbeAddOp2(v, OP_Goto, 0, labelContinue); } sqlite3VdbeResolveLabel(v, labelBreak); @@ -108082,21 +106871,21 @@ sqlite3Select(pParse, pSelect, &dest); /* Generate code to scan the ephemeral table and call VUpdate. */ iReg = ++pParse->nMem; pParse->nMem += pTab->nCol+1; - addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); VdbeCoverage(v); + addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg); sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1); for(i=0; inCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i); } sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); sqlite3MayAbort(pParse); - sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); /* Cleanup */ sqlite3SelectDelete(db, pSelect); @@ -109664,11 +108453,11 @@ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ u8 iFrom; /* Which entry in the FROM clause */ - u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ + u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to ends the loop */ union { /* Information that depends on pWLoop->wsFlags */ struct { int nIn; /* Number of entries in aInLoop[] */ struct InLoop { @@ -109715,11 +108504,11 @@ Index *pIndex; /* Index used, or NULL */ } btree; struct { /* Information for virtual tables */ int idxNum; /* Index number */ u8 needFree; /* True if sqlite3_free(idxStr) is needed */ - i8 isOrdered; /* True if satisfies ORDER BY */ + u8 isOrdered; /* True if satisfies ORDER BY */ u16 omitMask; /* Terms that may be omitted */ char *idxStr; /* Index identifier string */ } vtab; } u; u32 wsFlags; /* WHERE_* flags describing the plan */ @@ -109777,11 +108566,12 @@ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ LogEst nRow; /* Estimated number of rows generated by this path */ LogEst rCost; /* Total cost of this path */ - i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */ + u8 isOrdered; /* True if this path satisfies ORDER BY */ + u8 isOrderedValid; /* True if the isOrdered field is valid */ WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ }; /* ** The query generator uses an array of instances of this structure to @@ -109991,12 +108781,11 @@ ExprList *pResultSet; /* Result set. DISTINCT operates on these */ WhereLoop *pLoops; /* List of all WhereLoop objects */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ LogEst nRowOut; /* Estimated number of output rows */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ - i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ - u8 sorted; /* True if really sorted (not just grouped) */ + u8 bOBSat; /* ORDER BY satisfied by indices */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ u8 nLevel; /* Number of nested loop */ int iTop; /* The very beginning of the WHERE loop */ @@ -110051,11 +108840,10 @@ #define WHERE_IN_ABLE 0x00000800 /* Able to support an IN operator */ #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ #define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */ -#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/ /************** End of whereInt.h ********************************************/ /************** Continuing where we left off in where.c **********************/ /* @@ -110076,19 +108864,18 @@ /* ** Return TRUE if the WHERE clause returns rows in ORDER BY order. ** Return FALSE if the output needs to be sorted. */ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ - return pWInfo->nOBSat; + return pWInfo->bOBSat!=0; } /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. */ SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ - assert( pWInfo->iContinue!=0 ); return pWInfo->iContinue; } /* ** Return the VDBE address or label to jump to in order to break @@ -110264,11 +109051,11 @@ } pTerm = &pWC->a[idx = pWC->nTerm++]; if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 99; }else{ - pTerm->truthProb = 1; + pTerm->truthProb = -1; } pTerm->pExpr = sqlite3ExprSkipCollate(p); pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; pTerm->iParent = -1; @@ -111639,11 +110426,11 @@ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ v = pParse->pVdbe; assert( v!=0 ); - addrInit = sqlite3CodeOnce(pParse); VdbeCoverage(v); + addrInit = sqlite3CodeOnce(pParse); /* Count the number of columns that will be added to the index ** and used to match WHERE clause constraints */ nKeyCol = 0; pTable = pSrc->pTab; @@ -111746,16 +110533,16 @@ sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ - addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); + addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); regRecord = sqlite3GetTempReg(pParse); sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); - sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); /* Jump here when skipping the initialization */ @@ -111951,11 +110738,11 @@ iCol = pRec->nField - 1; assert( pIdx->nSample>0 ); assert( pRec->nField>0 && iColnSampleCol ); do{ iTest = (iMin+i)/2; - res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec, 0); + res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec); if( res<0 ){ iMin = iTest+1; }else{ i = iTest; } @@ -111966,20 +110753,20 @@ ** above found the right answer. This block serves no purpose other ** than to invoke the asserts. */ if( res==0 ){ /* If (res==0) is true, then sample $i must be equal to pRec */ assert( inSample ); - assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0) + assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) || pParse->db->mallocFailed ); }else{ /* Otherwise, pRec must be smaller than sample $i and larger than ** sample ($i-1). */ assert( i==pIdx->nSample - || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0)>0 + || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 || pParse->db->mallocFailed ); assert( i==0 - || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec, 0)<0 + || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 || pParse->db->mallocFailed ); } #endif /* ifdef SQLITE_DEBUG */ /* At this point, aSample[i] is the first sample that is greater than @@ -111993,12 +110780,11 @@ tRowcnt iLower, iUpper, iGap; if( i==0 ){ iLower = 0; iUpper = aSample[0].anLt[iCol]; }else{ - i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]); - iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol]; + iUpper = i>=pIdx->nSample ? pIdx->aiRowEst[0] : aSample[i].anLt[iCol]; iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol]; } aStat[1] = (pIdx->nKeyCol>iCol ? pIdx->aAvgEq[iCol] : 1); if( iLower>=iUpper ){ iGap = 0; @@ -112013,33 +110799,10 @@ aStat[0] = iLower + iGap; } } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ -/* -** If it is not NULL, pTerm is a term that provides an upper or lower -** bound on a range scan. Without considering pTerm, it is estimated -** that the scan will visit nNew rows. This function returns the number -** estimated to be visited after taking pTerm into account. -** -** If the user explicitly specified a likelihood() value for this term, -** then the return value is the likelihood multiplied by the number of -** input rows. Otherwise, this function assumes that an "IS NOT NULL" term -** has a likelihood of 0.50, and any other term a likelihood of 0.25. -*/ -static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){ - LogEst nRet = nNew; - if( pTerm ){ - if( pTerm->truthProb<=0 ){ - nRet += pTerm->truthProb; - }else if( (pTerm->wtFlags & TERM_VNULL)==0 ){ - nRet -= 20; assert( 20==sqlite3LogEst(4) ); - } - } - return nRet; -} - /* ** This function is used to estimate the number of rows that will be visited ** by scanning an index for a range of values. The range may have an upper ** bound, a lower bound, or both. The WHERE clause terms that set the upper ** and lower bounds are represented by pLower and pUpper respectively. For @@ -112128,11 +110891,11 @@ aff = p->pTable->aCol[p->aiColumn[nEq]].affinity; } /* Determine iLower and iUpper using ($P) only. */ if( nEq==0 ){ iLower = 0; - iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]); + iUpper = p->aiRowEst[0]; }else{ /* Note: this call could be optimized away - since the same values must ** have been requested when testing key $P in whereEqualScanEst(). */ whereKeyStats(pParse, p, pRec, 0, a); iLower = a[0]; @@ -112188,22 +110951,21 @@ #else UNUSED_PARAMETER(pParse); UNUSED_PARAMETER(pBuilder); #endif assert( pLower || pUpper ); - assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 ); - nNew = whereRangeAdjust(pLower, nOut); - nNew = whereRangeAdjust(pUpper, nNew); - - /* TUNING: If there is both an upper and lower limit, assume the range is - ** reduced by an additional 75%. This means that, by default, an open-ended - ** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the - ** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to - ** match 1/64 of the index. */ - if( pLower && pUpper ) nNew -= 20; - - nOut -= (pLower!=0) + (pUpper!=0); + /* TUNING: Each inequality constraint reduces the search space 4-fold. + ** A BETWEEN operator, therefore, reduces the search space 16-fold */ + nNew = nOut; + if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){ + nNew -= 20; assert( 20==sqlite3LogEst(4) ); + nOut--; + } + if( pUpper ){ + nNew -= 20; assert( 20==sqlite3LogEst(4) ); + nOut--; + } if( nNew<10 ) nNew = 10; if( nNewnOut = (LogEst)nOut; return rc; } @@ -112296,27 +111058,26 @@ WhereLoopBuilder *pBuilder, ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ tRowcnt *pnRow /* Write the revised row estimate here */ ){ Index *p = pBuilder->pNew->u.btree.pIndex; - i64 nRow0 = sqlite3LogEstToInt(p->aiRowLogEst[0]); int nRecValid = pBuilder->nRecValid; int rc = SQLITE_OK; /* Subfunction return code */ tRowcnt nEst; /* Number of rows for a single term */ tRowcnt nRowEst = 0; /* New estimate of the number of rows */ int i; /* Loop counter */ assert( p->aSample!=0 ); for(i=0; rc==SQLITE_OK && inExpr; i++){ - nEst = nRow0; + nEst = p->aiRowEst[0]; rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst); nRowEst += nEst; pBuilder->nRecValid = nRecValid; } if( rc==SQLITE_OK ){ - if( nRowEst > nRow0 ) nRowEst = nRow0; + if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0]; *pnRow = nRowEst; WHERETRACE(0x10,("IN row estimate: est=%g\n", nRowEst)); } assert( pBuilder->nRecValid==nRecValid ); return rc; @@ -112453,12 +111214,10 @@ testcase( bRev ); bRev = !bRev; } iTab = pX->iTable; sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); - VdbeCoverageIf(v, bRev); - VdbeCoverageIf(v, !bRev); assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(v); } @@ -112474,11 +111233,11 @@ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); }else{ pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); } pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; - sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_IsNull, iReg); }else{ pLevel->u.in.nIn = 0; } #endif } @@ -112569,18 +111328,14 @@ } if( nSkip ){ int iIdxCur = pLevel->iIdxCur; sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); - VdbeCoverageIf(v, bRev==0); - VdbeCoverageIf(v, bRev!=0); VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); j = sqlite3VdbeAddOp0(v, OP_Goto); - pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), + pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLt:OP_SeekGt), iIdxCur, 0, regBase, nSkip); - VdbeCoverageIf(v, bRev==0); - VdbeCoverageIf(v, bRev!=0); sqlite3VdbeJumpHere(v, j); for(j=0; jaiColumn[j]>=0 ); VdbeComment((v, "%s", pIdx->pTable->aCol[pIdx->aiColumn[j]].zName)); @@ -112609,14 +111364,11 @@ } testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IN ); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ Expr *pRight = pTerm->pExpr->pRight; - if( sqlite3ExprCanBeNull(pRight) ){ - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); - VdbeCoverage(v); - } + sqlite3ExprCodeIsNullJump(v, pRight, regBase+j, pLevel->addrBrk); if( zAff ){ if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_NONE ){ zAff[j] = SQLITE_AFF_NONE; } if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){ @@ -112755,24 +111507,17 @@ zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); } if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 && ALWAYS(pLoop->u.btree.pIndex!=0) ){ - const char *zFmt; - Index *pIdx = pLoop->u.btree.pIndex; char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); - assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); - if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ - zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s"; - }else if( flags & WHERE_AUTO_INDEX ){ - zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s"; - }else if( flags & WHERE_IDX_ONLY ){ - zFmt = "%s USING COVERING INDEX %s%s"; - }else{ - zFmt = "%s USING INDEX %s%s"; - } - zMsg = sqlite3MAppendf(db, zMsg, zFmt, zMsg, pIdx->zName, zWhere); + zMsg = sqlite3MAppendf(db, zMsg, + ((flags & WHERE_AUTO_INDEX) ? + "%s USING AUTOMATIC %sINDEX%.0s%s" : + "%s USING %sINDEX %s%s"), + zMsg, ((flags & WHERE_IDX_ONLY) ? "COVERING " : ""), + pLoop->u.btree.pIndex->zName, zWhere); sqlite3DbFree(db, zWhere); }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ @@ -112865,14 +111610,14 @@ } /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->viaCoroutine ){ int regYield = pTabItem->regReturn; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); - pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); - VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + 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( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ @@ -112900,11 +111645,10 @@ sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC); - VdbeCoverage(v); pLoop->u.vtab.needFree = 0; for(j=0; ju.vtab.omitMask>>j)&1 ){ disableTerm(pLevel, pLoop->aLTerm[j]); } @@ -112911,11 +111655,11 @@ } pLevel->op = OP_VNext; pLevel->p1 = iCur; pLevel->p2 = sqlite3VdbeCurrentAddr(v); sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); - sqlite3ExprCachePop(pParse); + sqlite3ExprCachePop(pParse, 1); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0 @@ -112924,22 +111668,20 @@ ** equality comparison against the ROWID field. Or ** we reference multiple rows using a "rowid IN (...)" ** construct. */ assert( pLoop->u.btree.nEq==1 ); + iReleaseReg = sqlite3GetTempReg(pParse); pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); - iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); - if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; - sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); - VdbeCoverage(v); sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); pLevel->op = OP_Noop; }else if( (pLoop->wsFlags & WHERE_IPK)!=0 @@ -112969,14 +111711,14 @@ /* The following constant maps TK_xx codes into corresponding ** seek opcodes. It depends on a particular ordering of TK_xx */ const u8 aMoveOp[] = { - /* TK_GT */ OP_SeekGT, - /* TK_LE */ OP_SeekLE, - /* TK_LT */ OP_SeekLT, - /* TK_GE */ OP_SeekGE + /* TK_GT */ OP_SeekGt, + /* TK_LE */ OP_SeekLe, + /* TK_LT */ OP_SeekLt, + /* TK_GE */ OP_SeekGe }; assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */ assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */ assert( TK_GE==TK_GT+3 ); /* ... is correcct. */ @@ -112986,21 +111728,15 @@ assert( pX!=0 ); testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1); VdbeComment((v, "pk")); - VdbeCoverageIf(v, pX->op==TK_GT); - VdbeCoverageIf(v, pX->op==TK_LE); - VdbeCoverageIf(v, pX->op==TK_LT); - VdbeCoverageIf(v, pX->op==TK_GE); sqlite3ExprCacheAffinityChange(pParse, r1, 1); sqlite3ReleaseTempReg(pParse, rTemp); disableTerm(pLevel, pStart); }else{ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk); - VdbeCoverageIf(v, bRev==0); - VdbeCoverageIf(v, bRev!=0); } if( pEnd ){ Expr *pX; pX = pEnd->pExpr; assert( pX!=0 ); @@ -113020,18 +111756,14 @@ pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; assert( pLevel->p5==0 ); if( testOp!=OP_Noop ){ - iRowidReg = ++pParse->nMem; + iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); - VdbeCoverageIf(v, testOp==OP_Le); - VdbeCoverageIf(v, testOp==OP_Lt); - VdbeCoverageIf(v, testOp==OP_Ge); - VdbeCoverageIf(v, testOp==OP_Gt); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); } }else if( pLoop->wsFlags & WHERE_INDEXED ){ /* Case 4: A scan using an index. ** @@ -113067,23 +111799,24 @@ static const u8 aStartOp[] = { 0, 0, OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */ OP_Last, /* 3: (!start_constraints && startEq && bRev) */ - OP_SeekGT, /* 4: (start_constraints && !startEq && !bRev) */ - OP_SeekLT, /* 5: (start_constraints && !startEq && bRev) */ - OP_SeekGE, /* 6: (start_constraints && startEq && !bRev) */ - OP_SeekLE /* 7: (start_constraints && startEq && bRev) */ + OP_SeekGt, /* 4: (start_constraints && !startEq && !bRev) */ + OP_SeekLt, /* 5: (start_constraints && !startEq && bRev) */ + OP_SeekGe, /* 6: (start_constraints && startEq && !bRev) */ + OP_SeekLe /* 7: (start_constraints && startEq && bRev) */ }; static const u8 aEndOp[] = { - OP_IdxGE, /* 0: (end_constraints && !bRev && !endEq) */ - OP_IdxGT, /* 1: (end_constraints && !bRev && endEq) */ - OP_IdxLE, /* 2: (end_constraints && bRev && !endEq) */ - OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */ + OP_Noop, /* 0: (!end_constraints) */ + OP_IdxGE, /* 1: (end_constraints && !bRev) */ + OP_IdxLT /* 2: (end_constraints && bRev) */ }; u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */ + int isMinQuery = 0; /* If this is an optimized SELECT min(x).. */ int regBase; /* Base register holding constraint values */ + int r1; /* Temp register */ WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */ WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */ int startEq; /* True if range start uses ==, >= or <= */ int endEq; /* True if range end uses ==, >= or <= */ int start_constraints; /* Start of range is constrained */ @@ -113092,12 +111825,10 @@ int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ char *zStartAff; /* Affinity for start of range constraint */ char cEndAff = 0; /* Affinity for end of range constraint */ - u8 bSeekPastNull = 0; /* True to seek past initial nulls */ - u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; assert( nEq>=pLoop->u.btree.nSkip ); @@ -113107,19 +111838,16 @@ ** a single iteration. This means that the first row returned ** should not have a NULL value stored in 'x'. If column 'x' is ** the first one after the nEq equality constraints in the index, ** this requires some special handling. */ - assert( pWInfo->pOrderBy==0 - || pWInfo->pOrderBy->nExpr==1 - || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 ); if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 - && pWInfo->nOBSat>0 + && (pWInfo->bOBSat!=0) && (pIdx->nKeyCol>nEq) ){ assert( pLoop->u.btree.nSkip==0 ); - bSeekPastNull = 1; + isMinQuery = 1; nExtraReg = 1; } /* Find any inequality constraint terms for the start and end ** of the range. @@ -113130,18 +111858,11 @@ nExtraReg = 1; } if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ pRangeEnd = pLoop->aLTerm[j++]; nExtraReg = 1; - if( pRangeStart==0 - && (j = pIdx->aiColumn[nEq])>=0 - && pIdx->pTable->aCol[j].notNull==0 - ){ - bSeekPastNull = 1; - } - } - assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); + } /* Generate code to evaluate all constraint terms using == or IN ** and store the values of those terms in an array of registers ** starting at regBase. */ @@ -113156,11 +111877,10 @@ */ if( (nEqnKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) || (bRev && pIdx->nKeyCol==nEq) ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); - SWAP(u8, bSeekPastNull, bStopAtNull); } testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); @@ -113172,15 +111892,12 @@ /* Seek the index cursor to the start of the range. */ nConstraint = nEq; if( pRangeStart ){ Expr *pRight = pRangeStart->pExpr->pRight; sqlite3ExprCode(pParse, pRight, regBase+nEq); - if( (pRangeStart->wtFlags & TERM_VNULL)==0 - && sqlite3ExprCanBeNull(pRight) - ){ - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); - VdbeCoverage(v); + if( (pRangeStart->wtFlags & TERM_VNULL)==0 ){ + sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt); } if( zStartAff ){ if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_NONE){ /* Since the comparison is to be performed with no conversions ** applied to the operands, set the affinity to apply to pRight to @@ -113191,88 +111908,98 @@ zStartAff[nEq] = SQLITE_AFF_NONE; } } nConstraint++; testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); - }else if( bSeekPastNull ){ + }else if( isMinQuery ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); nConstraint++; startEq = 0; start_constraints = 1; } - codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); + codeApplyAffinity(pParse, regBase, nConstraint, zStartAff); op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); + testcase( op==OP_Rewind ); + testcase( op==OP_Last ); + testcase( op==OP_SeekGt ); + testcase( op==OP_SeekGe ); + testcase( op==OP_SeekLe ); + testcase( op==OP_SeekLt ); sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); - VdbeCoverage(v); - VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); - VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); - VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); - VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); - VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); - VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); /* Load the value for the inequality constraint at the end of the ** range (if any). */ nConstraint = nEq; if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); sqlite3ExprCode(pParse, pRight, regBase+nEq); - if( (pRangeEnd->wtFlags & TERM_VNULL)==0 - && sqlite3ExprCanBeNull(pRight) - ){ - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); - VdbeCoverage(v); + if( (pRangeEnd->wtFlags & TERM_VNULL)==0 ){ + sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt); } if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_NONE && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff) ){ codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff); } nConstraint++; testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); - }else if( bStopAtNull ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); - endEq = 0; - nConstraint++; } sqlite3DbFree(db, zStartAff); /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ - if( nConstraint ){ - op = aEndOp[bRev*2 + endEq]; + op = aEndOp[(pRangeEnd || nEq) * (1 + bRev)]; + testcase( op==OP_Noop ); + testcase( op==OP_IdxGE ); + testcase( op==OP_IdxLT ); + if( op!=OP_Noop ){ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); - testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); - testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); - testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); - testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); + sqlite3VdbeChangeP5(v, endEq!=bRev ?1:0); } + + /* If there are inequality constraints, check that the value + ** of the table column that the inequality contrains is not NULL. + ** If it is, jump to the next iteration of the loop. + */ + r1 = sqlite3GetTempReg(pParse); + testcase( pLoop->wsFlags & WHERE_BTM_LIMIT ); + testcase( pLoop->wsFlags & WHERE_TOP_LIMIT ); + if( (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 + && (j = pIdx->aiColumn[nEq])>=0 + && pIdx->pTable->aCol[j].notNull==0 + && (nEq || (pLoop->wsFlags & WHERE_BTM_LIMIT)==0) + ){ + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1); + VdbeComment((v, "%s", pIdx->pTable->aCol[j].zName)); + sqlite3VdbeAddOp2(v, OP_IsNull, r1, addrCont); + } + sqlite3ReleaseTempReg(pParse, r1); /* Seek the table cursor, if required */ disableTerm(pLevel, pRangeStart); disableTerm(pLevel, pRangeEnd); if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ - iRowidReg = ++pParse->nMem; + iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */ - }else if( iCur!=iIdxCur ){ + }else{ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); } sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, - iRowidReg, pPk->nKeyCol); VdbeCoverage(v); + iRowidReg, pPk->nKeyCol); } /* Record the instruction used to terminate the loop. Disable ** WHERE clause terms made redundant by the index range scan. */ @@ -113282,11 +112009,10 @@ pLevel->op = OP_Prev; }else{ pLevel->op = OP_Next; } pLevel->p1 = iIdxCur; - pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0; if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; }else{ assert( pLevel->p5==0 ); } @@ -113330,14 +112056,10 @@ ** ** Return 2 # Jump back to the Gosub ** ** B: ** - ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then - ** use an ephermeral index instead of a RowSet to record the primary - ** keys of the rows we have already seen. - ** */ WhereClause *pOrWc; /* The OR-clause broken out into subterms */ SrcList *pOrTab; /* Shortened table list or OR-clause generation */ Index *pCov = 0; /* Potential covering index (or NULL) */ int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ @@ -113348,11 +112070,10 @@ int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */ int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ - Table *pTab = pTabItem->pTab; pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->eOperator & WO_OR ); assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); @@ -113381,12 +112102,11 @@ }else{ pOrTab = pWInfo->pTabList; } /* Initialize the rowset register to contain NULL. An SQL NULL is - ** equivalent to an empty rowset. Or, create an ephermeral index - ** capable of holding primary keys in the case of a WITHOUT ROWID. + ** equivalent to an empty rowset. ** ** Also initialize regReturn to contain the address of the instruction ** immediately following the OP_Return at the bottom of the loop. This ** is required in a few obscure LEFT JOIN cases where control jumps ** over the top of the loop into the body of it. In this case the @@ -113393,20 +112113,13 @@ ** correct response for the end-of-loop code (the OP_Return) is to ** fall through to the next instruction, just as an OP_Next does if ** called on an uninitialized cursor. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - if( HasRowid(pTab) ){ - regRowset = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); - }else{ - Index *pPk = sqlite3PrimaryKeyIndex(pTab); - regRowset = pParse->nTab++; - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol); - sqlite3VdbeSetP4KeyInfo(pParse, pPk); - } + regRowset = ++pParse->nMem; regRowid = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); } iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y ** Then for every term xN, evaluate as the subexpression: xN AND z @@ -113426,32 +112139,25 @@ int iTerm; for(iTerm=0; iTermnTerm; iTerm++){ Expr *pExpr = pWC->a[iTerm].pExpr; if( &pWC->a[iTerm] == pTerm ) continue; if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; - testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); - testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); - if( pWC->a[iTerm].wtFlags & (TERM_ORINFO|TERM_VIRTUAL) ) continue; + if( pWC->a[iTerm].wtFlags & (TERM_ORINFO) ) continue; if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; pExpr = sqlite3ExprDup(db, pExpr, 0); pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr); } if( pAndExpr ){ pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0); } } - /* Run a separate WHERE clause for each term of the OR clause. After - ** eliminating duplicates from other WHERE clauses, the action for each - ** sub-WHERE clause is to to invoke the main loop body as a subroutine. - */ for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ - WhereInfo *pSubWInfo; /* Info for single OR-term scan */ - Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ - int j1 = 0; /* Address of jump operation */ + WhereInfo *pSubWInfo; /* Info for single OR-term scan */ + Expr *pOrExpr = pOrTerm->pExpr; if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ @@ -113462,66 +112168,19 @@ if( pSubWInfo ){ WhereLoop *pSubLoop; explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); - /* This is the sub-WHERE clause body. First skip over - ** duplicate rows from prior sub-WHERE clauses, and record the - ** rowid (or PRIMARY KEY) for the current row so that the same - ** row will be skipped in subsequent sub-WHERE clauses. - */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ + int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); int r; - int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); - if( HasRowid(pTab) ){ - r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0); - j1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, r,iSet); - VdbeCoverage(v); - }else{ - Index *pPk = sqlite3PrimaryKeyIndex(pTab); - int nPk = pPk->nKeyCol; - int iPk; - - /* Read the PK into an array of temp registers. */ - r = sqlite3GetTempRange(pParse, nPk); - for(iPk=0; iPkaiColumn[iPk]; - sqlite3ExprCodeGetColumn(pParse, pTab, iCol, iCur, r+iPk, 0); - } - - /* Check if the temp table already contains this key. If so, - ** the row has already been included in the result set and - ** can be ignored (by jumping past the Gosub below). Otherwise, - ** insert the key into the temp table and proceed with processing - ** the row. - ** - ** Use some of the same optimizations as OP_RowSetTest: If iSet - ** is zero, assume that the key cannot already be present in - ** the temp table. And if iSet is -1, assume that there is no - ** need to insert the key into the temp table, as it will never - ** be tested for. */ - if( iSet ){ - j1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk); - VdbeCoverage(v); - } - if( iSet>=0 ){ - sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid); - sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0); - if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); - } - - /* Release the array of temp registers */ - sqlite3ReleaseTempRange(pParse, r, nPk); - } - } - - /* Invoke the main loop body as a subroutine */ - sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody); - - /* Jump here (skipping the main loop body subroutine) if the - ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */ - if( j1 ) sqlite3VdbeJumpHere(v, j1); + r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur, + regRowid, 0); + sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, + sqlite3VdbeCurrentAddr(v)+2, r, iSet); + } + sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody); /* The pSubWInfo->untestedTerms flag means that this OR term ** contained one or more AND term from a notReady table. The ** terms from the notReady table could not be tested and will ** need to be tested later. @@ -113542,11 +112201,10 @@ */ pSubLoop = pSubWInfo->a[0].pWLoop; assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) - && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; }else{ pCov = 0; @@ -113585,12 +112243,10 @@ pLevel->op = OP_Noop; }else{ pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); - VdbeCoverageIf(v, bRev==0); - VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } } /* Insert code to test every subexpression that can be completely @@ -113668,10 +112324,11 @@ assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } } + sqlite3ReleaseTempReg(pParse, iReleaseReg); return pLevel->notReady; } #if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN) @@ -113846,180 +112503,38 @@ } sqlite3DbFree(db, pWInfo); } } -/* -** Return TRUE if both of the following are true: -** -** (1) X has the same or lower cost that Y -** (2) X is a proper subset of Y -** -** By "proper subset" we mean that X uses fewer WHERE clause terms -** than Y and that every WHERE clause term used by X is also used -** by Y. -** -** If X is a proper subset of Y then Y is a better choice and ought -** to have a lower cost. This routine returns TRUE when that cost -** relationship is inverted and needs to be adjusted. -*/ -static int whereLoopCheaperProperSubset( - const WhereLoop *pX, /* First WhereLoop to compare */ - const WhereLoop *pY /* Compare against this WhereLoop */ -){ - int i, j; - if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */ - if( pX->rRun >= pY->rRun ){ - if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ - if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ - } - for(i=pX->nLTerm-1; i>=0; i--){ - for(j=pY->nLTerm-1; j>=0; j--){ - if( pY->aLTerm[j]==pX->aLTerm[i] ) break; - } - if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ - } - return 1; /* All conditions meet */ -} - -/* -** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so -** that: -** -** (1) pTemplate costs less than any other WhereLoops that are a proper -** subset of pTemplate -** -** (2) pTemplate costs more than any other WhereLoops for which pTemplate -** is a proper subset. -** -** To say "WhereLoop X is a proper subset of Y" means that X uses fewer -** WHERE clause terms than Y and that every WHERE clause term used by X is -** also used by Y. -** -** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the -** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE -** clause terms covered, since some of the first nLTerm entries in aLTerm[] -** will be NULL (because they are skipped). That makes it more difficult -** to compare the loops. We could add extra code to do the comparison, and -** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this -** adjustment is sufficient minor, that it is very difficult to construct -** a test case where the extra code would improve the query plan. Better -** to avoid the added complexity and just omit cost adjustments to SKIPSCAN -** loops. -*/ -static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ - if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return; - if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return; - for(; p; p=p->pNextLoop){ - if( p->iTab!=pTemplate->iTab ) continue; - if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; - if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue; - if( whereLoopCheaperProperSubset(p, pTemplate) ){ - /* Adjust pTemplate cost downward so that it is cheaper than its - ** subset p */ - pTemplate->rRun = p->rRun; - pTemplate->nOut = p->nOut - 1; - }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ - /* Adjust pTemplate cost upward so that it is costlier than p since - ** pTemplate is a proper subset of p */ - pTemplate->rRun = p->rRun; - pTemplate->nOut = p->nOut + 1; - } - } -} - -/* -** Search the list of WhereLoops in *ppPrev looking for one that can be -** supplanted by pTemplate. -** -** Return NULL if the WhereLoop list contains an entry that can supplant -** pTemplate, in other words if pTemplate does not belong on the list. -** -** If pX is a WhereLoop that pTemplate can supplant, then return the -** link that points to pX. -** -** If pTemplate cannot supplant any existing element of the list but needs -** to be added to the list, then return a pointer to the tail of the list. -*/ -static WhereLoop **whereLoopFindLesser( - WhereLoop **ppPrev, - const WhereLoop *pTemplate -){ - WhereLoop *p; - for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){ - if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ - /* If either the iTab or iSortIdx values for two WhereLoop are different - ** then those WhereLoops need to be considered separately. Neither is - ** a candidate to replace the other. */ - continue; - } - /* In the current implementation, the rSetup value is either zero - ** or the cost of building an automatic index (NlogN) and the NlogN - ** is the same for compatible WhereLoops. */ - assert( p->rSetup==0 || pTemplate->rSetup==0 - || p->rSetup==pTemplate->rSetup ); - - /* whereLoopAddBtree() always generates and inserts the automatic index - ** case first. Hence compatible candidate WhereLoops never have a larger - ** rSetup. Call this SETUP-INVARIANT */ - assert( p->rSetup>=pTemplate->rSetup ); - - /* If existing WhereLoop p is better than pTemplate, pTemplate can be - ** discarded. WhereLoop p is better if: - ** (1) p has no more dependencies than pTemplate, and - ** (2) p has an equal or lower cost than pTemplate - */ - if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */ - && p->rSetup<=pTemplate->rSetup /* (2a) */ - && p->rRun<=pTemplate->rRun /* (2b) */ - && p->nOut<=pTemplate->nOut /* (2c) */ - ){ - return 0; /* Discard pTemplate */ - } - - /* If pTemplate is always better than p, then cause p to be overwritten - ** with pTemplate. pTemplate is better than p if: - ** (1) pTemplate has no more dependences than p, and - ** (2) pTemplate has an equal or lower cost than p. - */ - if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */ - && p->rRun>=pTemplate->rRun /* (2a) */ - && p->nOut>=pTemplate->nOut /* (2b) */ - ){ - assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ - break; /* Cause p to be overwritten by pTemplate */ - } - } - return ppPrev; -} - /* ** Insert or replace a WhereLoop entry using the template supplied. ** ** An existing WhereLoop entry might be overwritten if the new template ** is better and has fewer dependencies. Or the template will be ignored ** and no insert will occur if an existing WhereLoop is faster and has ** fewer dependencies than the template. Otherwise a new WhereLoop is ** added based on the template. ** -** If pBuilder->pOrSet is not NULL then we care about only the +** If pBuilder->pOrSet is not NULL then we only care about only the ** prerequisites and rRun and nOut costs of the N best loops. That ** information is gathered in the pBuilder->pOrSet object. This special ** processing mode is used only for OR clause processing. ** ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we ** still might overwrite similar loops with the new template if the -** new template is better. Loops may be overwritten if the following +** template is better. Loops may be overwritten if the following ** conditions are met: ** ** (1) They have the same iTab. ** (2) They have the same iSortIdx. ** (3) The template has same or fewer dependencies than the current loop ** (4) The template has the same or lower cost than the current loop +** (5) The template uses more terms of the same index but has no additional +** dependencies */ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ - WhereLoop **ppPrev, *p; + WhereLoop **ppPrev, *p, *pNext = 0; WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. @@ -114038,27 +112553,68 @@ } #endif return SQLITE_OK; } - /* Look for an existing WhereLoop to replace with pTemplate + /* Search for an existing WhereLoop to overwrite, or which takes + ** priority over pTemplate. */ - whereLoopAdjustCost(pWInfo->pLoops, pTemplate); - ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); - - if( ppPrev==0 ){ - /* There already exists a WhereLoop on the list that is better - ** than pTemplate, so just ignore pTemplate */ -#if WHERETRACE_ENABLED /* 0x8 */ - if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-noop: "); - whereLoopPrint(pTemplate, pBuilder->pWC); - } -#endif - return SQLITE_OK; - }else{ - p = *ppPrev; + for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ + if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ + /* If either the iTab or iSortIdx values for two WhereLoop are different + ** then those WhereLoops need to be considered separately. Neither is + ** a candidate to replace the other. */ + continue; + } + /* In the current implementation, the rSetup value is either zero + ** or the cost of building an automatic index (NlogN) and the NlogN + ** is the same for compatible WhereLoops. */ + assert( p->rSetup==0 || pTemplate->rSetup==0 + || p->rSetup==pTemplate->rSetup ); + + /* whereLoopAddBtree() always generates and inserts the automatic index + ** case first. Hence compatible candidate WhereLoops never have a larger + ** rSetup. Call this SETUP-INVARIANT */ + assert( p->rSetup>=pTemplate->rSetup ); + + if( (p->prereq & pTemplate->prereq)==p->prereq + && p->rSetup<=pTemplate->rSetup + && p->rRun<=pTemplate->rRun + && p->nOut<=pTemplate->nOut + ){ + /* This branch taken when p is equal or better than pTemplate in + ** all of (1) dependencies (2) setup-cost, (3) run-cost, and + ** (4) number of output rows. */ + assert( p->rSetup==pTemplate->rSetup ); + if( p->prereq==pTemplate->prereq + && p->nLTermnLTerm + && (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0 + && (p->u.btree.pIndex==pTemplate->u.btree.pIndex + || pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm) + ){ + /* Overwrite an existing WhereLoop with an similar one that uses + ** more terms of the index */ + pNext = p->pNextLoop; + break; + }else{ + /* pTemplate is not helpful. + ** Return without changing or adding anything */ + goto whereLoopInsert_noop; + } + } + if( (p->prereq & pTemplate->prereq)==pTemplate->prereq + && p->rRun>=pTemplate->rRun + && p->nOut>=pTemplate->nOut + ){ + /* Overwrite an existing WhereLoop with a better one: one that is + ** better at one of (1) dependencies, (2) setup-cost, (3) run-cost + ** or (4) number of output rows, and is no worse in any of those + ** categories. */ + assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ + pNext = p->pNextLoop; + break; + } } /* If we reach this point it means that either p[] should be overwritten ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new ** WhereLoop and insert it. @@ -114072,44 +112628,34 @@ sqlite3DebugPrintf("ins-new: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif if( p==0 ){ - /* Allocate a new WhereLoop to add to the end of the list */ - *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); + p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM; whereLoopInit(p); - p->pNextLoop = 0; - }else{ - /* We will be overwriting WhereLoop p[]. But before we do, first - ** go through the rest of the list and delete any other entries besides - ** p[] that are also supplated by pTemplate */ - WhereLoop **ppTail = &p->pNextLoop; - WhereLoop *pToDel; - while( *ppTail ){ - ppTail = whereLoopFindLesser(ppTail, pTemplate); - if( NEVER(ppTail==0) ) break; - pToDel = *ppTail; - if( pToDel==0 ) break; - *ppTail = pToDel->pNextLoop; -#if WHERETRACE_ENABLED /* 0x8 */ - if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-del: "); - whereLoopPrint(pToDel, pBuilder->pWC); - } -#endif - whereLoopDelete(db, pToDel); - } } whereLoopXfer(db, p, pTemplate); + p->pNextLoop = pNext; + *ppPrev = p; if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; if( pIndex && pIndex->tnum==0 ){ p->u.btree.pIndex = 0; } } return SQLITE_OK; + + /* Jump here if the insert is a no-op */ +whereLoopInsert_noop: +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf("ins-noop: "); + whereLoopPrint(pTemplate, pBuilder->pWC); + } +#endif + return SQLITE_OK; } /* ** Adjust the WhereLoop.nOut value downward to account for terms of the ** WHERE clause that reference the loop but which are not used by an @@ -114135,24 +112681,17 @@ pX = pLoop->aLTerm[j]; if( pX==0 ) continue; if( pX==pTerm ) break; if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } - if( j<0 ){ - pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1); - } + if( j<0 ) pLoop->nOut += pTerm->truthProb; } } /* -** We have so far matched pBuilder->pNew->u.btree.nEq terms of the -** index pIndex. Try to match one more. -** -** When this function is called, pBuilder->pNew->nOut contains the -** number of rows expected to be visited by filtering using the nEq -** terms only. If it is modified, this value is restored before this -** function returns. +** We have so far matched pBuilder->pNew->u.btree.nEq terms of the index pIndex. +** Try to match one more. ** ** If pProbe->tnum==0, that means pIndex is a fake index used for the ** INTEGER PRIMARY KEY. */ static int whereLoopAddBtreeIndex( @@ -114174,10 +112713,11 @@ u16 saved_nSkip; /* Original value of pNew->u.btree.nSkip */ u32 saved_wsFlags; /* Original value of pNew->wsFlags */ LogEst saved_nOut; /* Original value of pNew->nOut */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ + LogEst nRowEst; /* Estimated index selectivity */ LogEst rLogSize; /* Logarithm of table size */ WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM; @@ -114194,12 +112734,15 @@ if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); assert( pNew->u.btree.nEq<=pProbe->nKeyCol ); if( pNew->u.btree.nEq < pProbe->nKeyCol ){ iCol = pProbe->aiColumn[pNew->u.btree.nEq]; + nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]); + if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1; }else{ iCol = -1; + nRowEst = 0; } pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, opMask, pProbe); saved_nEq = pNew->u.btree.nEq; saved_nSkip = pNew->u.btree.nSkip; @@ -114206,189 +112749,139 @@ saved_nLTerm = pNew->nLTerm; saved_wsFlags = pNew->wsFlags; saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pNew->rSetup = 0; - rLogSize = estLog(pProbe->aiRowLogEst[0]); + rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0])); /* Consider using a skip-scan if there are no WHERE clause constraints ** available for the left-most terms of the index, and if the average - ** number of repeats in the left-most terms is at least 18. - ** - ** The magic number 18 is selected on the basis that scanning 17 rows - ** is almost always quicker than an index seek (even though if the index - ** contains fewer than 2^17 rows we assume otherwise in other parts of - ** the code). And, even if it is not, it should not be too much slower. - ** On the other hand, the extra seeks could end up being significantly - ** more expensive. */ - assert( 42==sqlite3LogEst(18) ); + ** number of repeats in the left-most terms is at least 18. The magic + ** number 18 was found by experimentation to be the payoff point where + ** skip-scan become faster than a full-scan. + */ if( pTerm==0 && saved_nEq==saved_nSkip && saved_nEq+1nKeyCol - && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ + && pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ LogEst nIter; pNew->u.btree.nEq++; pNew->u.btree.nSkip++; pNew->aLTerm[pNew->nLTerm++] = 0; pNew->wsFlags |= WHERE_SKIPSCAN; - nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; - pNew->nOut -= nIter; - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); - pNew->nOut = saved_nOut; + nIter = sqlite3LogEst(pProbe->aiRowEst[0]/pProbe->aiRowEst[saved_nEq+1]); + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter); } for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ - u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ - LogEst rCostIdx; - LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ int nIn = 0; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nRecValid = pBuilder->nRecValid; #endif - if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) + if( (pTerm->eOperator==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) && (iCol<0 || pSrc->pTab->aCol[iCol].notNull) ){ continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */ } if( pTerm->prereqRight & pNew->maskSelf ) continue; + + assert( pNew->nOut==saved_nOut ); pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->nLTerm = saved_nLTerm; if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTerm; pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; - - assert( nInMul==0 - || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0 - || (pNew->wsFlags & WHERE_COLUMN_IN)!=0 - || (pNew->wsFlags & WHERE_SKIPSCAN)!=0 - ); - - if( eOp & WO_IN ){ + pNew->rRun = rLogSize; /* Baseline cost is log2(N). Adjustments below */ + if( pTerm->eOperator & WO_IN ){ Expr *pExpr = pTerm->pExpr; pNew->wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ nIn = 46; assert( 46==sqlite3LogEst(25) ); }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ nIn = sqlite3LogEst(pExpr->x.pList->nExpr); } - assert( nIn>0 ); /* RHS always has 2 or more terms... The parser - ** changes "x IN (?)" into "x=?". */ - - }else if( eOp & (WO_EQ) ){ + pNew->rRun += nIn; + pNew->u.btree.nEq++; + pNew->nOut = nRowEst + nInMul + nIn; + }else if( pTerm->eOperator & (WO_EQ) ){ + assert( + (pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN|WHERE_SKIPSCAN))!=0 + || nInMul==0 + ); pNew->wsFlags |= WHERE_COLUMN_EQ; - if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){ - if( iCol>=0 && pProbe->onError==OE_None ){ - pNew->wsFlags |= WHERE_UNQ_WANTED; - }else{ - pNew->wsFlags |= WHERE_ONEROW; - } - } - }else if( eOp & WO_ISNULL ){ + if( iCol<0 + || (pProbe->onError!=OE_None && nInMul==0 + && pNew->u.btree.nEq==pProbe->nKeyCol-1) + ){ + assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 ); + pNew->wsFlags |= WHERE_ONEROW; + } + pNew->u.btree.nEq++; + pNew->nOut = nRowEst + nInMul; + }else if( pTerm->eOperator & (WO_ISNULL) ){ pNew->wsFlags |= WHERE_COLUMN_NULL; - }else if( eOp & (WO_GT|WO_GE) ){ - testcase( eOp & WO_GT ); - testcase( eOp & WO_GE ); + pNew->u.btree.nEq++; + /* TUNING: IS NULL selects 2 rows */ + nIn = 10; assert( 10==sqlite3LogEst(2) ); + pNew->nOut = nRowEst + nInMul + nIn; + }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ + testcase( pTerm->eOperator & WO_GT ); + testcase( pTerm->eOperator & WO_GE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pBtm = pTerm; pTop = 0; }else{ - assert( eOp & (WO_LT|WO_LE) ); - testcase( eOp & WO_LT ); - testcase( eOp & WO_LE ); + assert( pTerm->eOperator & (WO_LT|WO_LE) ); + testcase( pTerm->eOperator & WO_LT ); + testcase( pTerm->eOperator & WO_LE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; pTop = pTerm; pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? pNew->aLTerm[pNew->nLTerm-2] : 0; } - - /* At this point pNew->nOut is set to the number of rows expected to - ** be visited by the index scan before considering term pTerm, or the - ** values of nIn and nInMul. In other words, assuming that all - ** "x IN(...)" terms are replaced with "x = ?". This block updates - ** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */ - assert( pNew->nOut==saved_nOut ); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ - /* Adjust nOut using stat3/stat4 data. Or, if there is no stat3/stat4 - ** data, using some other estimate. */ + /* Adjust nOut and rRun for STAT3 range values */ + assert( pNew->nOut==saved_nOut ); whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew); - }else{ - int nEq = ++pNew->u.btree.nEq; - assert( eOp & (WO_ISNULL|WO_EQ|WO_IN) ); - - assert( pNew->nOut==saved_nOut ); - if( pTerm->truthProb<=0 && iCol>=0 ){ - assert( (eOp & WO_IN) || nIn==0 ); - testcase( eOp & WO_IN ); - pNew->nOut += pTerm->truthProb; - pNew->nOut -= nIn; - }else{ + } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - tRowcnt nOut = 0; - if( nInMul==0 - && pProbe->nSample - && pNew->u.btree.nEq<=pProbe->nSampleCol - && OptimizationEnabled(db, SQLITE_Stat3) - && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) - ){ - Expr *pExpr = pTerm->pExpr; - if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){ - testcase( eOp & WO_EQ ); - testcase( eOp & WO_ISNULL ); - rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); - }else{ - rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); - } - assert( rc!=SQLITE_OK || nOut>0 ); - if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; - if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */ - if( nOut ){ - pNew->nOut = sqlite3LogEst(nOut); - if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; - pNew->nOut -= nIn; - } - } - if( nOut==0 ) -#endif - { - pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]); - if( eOp & WO_ISNULL ){ - /* TUNING: If there is no likelihood() value, assume that a - ** "col IS NULL" expression matches twice as many rows - ** as (col=?). */ - pNew->nOut += 10; - } - } - } - } - - /* Set rCostIdx to the cost of visiting selected rows in index. Add - ** it to pNew->rRun, which is currently set to the cost of the index - ** seek only. Then, if this is a non-covering index, add the cost of - ** visiting the rows in the main table. */ - rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; - pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); + if( nInMul==0 + && pProbe->nSample + && pNew->u.btree.nEq<=pProbe->nSampleCol + && OptimizationEnabled(db, SQLITE_Stat3) + ){ + Expr *pExpr = pTerm->pExpr; + tRowcnt nOut = 0; + if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ + testcase( pTerm->eOperator & WO_EQ ); + testcase( pTerm->eOperator & WO_ISNULL ); + rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); + }else if( (pTerm->eOperator & WO_IN) + && !ExprHasProperty(pExpr, EP_xIsSelect) ){ + rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); + } + assert( nOut==0 || rc==SQLITE_OK ); + if( nOut ){ + pNew->nOut = sqlite3LogEst(nOut); + if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; + } + } +#endif if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ - pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); + /* Each row involves a step of the index, then a binary search of + ** the main table */ + pNew->rRun = sqlite3LogEstAdd(pNew->rRun,rLogSize>27 ? rLogSize-17 : 10); } - - nOutUnadjusted = pNew->nOut; - pNew->rRun += nInMul + nIn; - pNew->nOut += nInMul + nIn; + /* Step cost for each output row */ + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut); whereLoopOutputAdjust(pBuilder->pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); - - if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ - pNew->nOut = saved_nOut; - }else{ - pNew->nOut = nOutUnadjusted; - } - if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEq<(pProbe->nKeyCol + (pProbe->zName!=0)) ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } @@ -114468,42 +112961,19 @@ /* ** Add all WhereLoop objects for a single table of the join where the table ** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be ** a b-tree table, not a virtual table. -** -** The costs (WhereLoop.rRun) of the b-tree loops added by this function -** are calculated as follows: -** -** For a full scan, assuming the table (or index) contains nRow rows: -** -** cost = nRow * 3.0 // full-table scan -** cost = nRow * K // scan of covering index -** cost = nRow * (K+3.0) // scan of non-covering index -** -** where K is a value between 1.1 and 3.0 set based on the relative -** estimated average size of the index and table records. -** -** For an index scan, where nVisit is the number of index rows visited -** by the scan, and nSeek is the number of seek operations required on -** the index b-tree: -** -** cost = nSeek * (log(nRow) + K * nVisit) // covering index -** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index -** -** Normally, nSeek is 1. nSeek values greater than 1 come about if the -** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when -** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans. */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ Bitmask mExtra /* Extra prerequesites for using this table */ ){ WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ Index sPk; /* A fake index object for the primary key */ - LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ + tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ SrcList *pTabList; /* The FROM clause */ struct SrcList_item *pSrc; /* The FROM clause btree term to add */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ @@ -114534,25 +113004,24 @@ ** indices to follow */ Index *pFirst; /* First of real indices on the table */ memset(&sPk, 0, sizeof(Index)); sPk.nKeyCol = 1; sPk.aiColumn = &aiColumnPk; - sPk.aiRowLogEst = aiRowEstPk; + sPk.aiRowEst = aiRowEstPk; sPk.onError = OE_Replace; sPk.pTable = pTab; - sPk.szIdxRow = pTab->szTabRow; - aiRowEstPk[0] = pTab->nRowLogEst; - aiRowEstPk[1] = 0; + aiRowEstPk[0] = pTab->nRowEst; + aiRowEstPk[1] = 1; pFirst = pSrc->pTab->pIndex; if( pSrc->notIndexed==0 ){ /* The real indices of the table are only considered if the ** NOT INDEXED qualifier is omitted from the FROM clause */ sPk.pNext = pFirst; } pProbe = &sPk; } - rSize = pTab->nRowLogEst; + rSize = sqlite3LogEst(pTab->nRowEst); rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet @@ -114598,11 +113067,10 @@ for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){ if( pProbe->pPartIdxWhere!=0 && !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){ continue; /* Partial index inappropriate for this query */ } - rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; pNew->u.btree.nSkip = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; pNew->rSetup = 0; @@ -114616,12 +113084,14 @@ /* Integer primary key index */ pNew->wsFlags = WHERE_IPK; /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; - /* TUNING: Cost of full table scan is (N*3.0). */ - pNew->rRun = rSize + 16; + /* TUNING: Cost of full table scan is 3*(N + log2(N)). + ** + The extra 3 factor is to encourage the use of indexed lookups + ** over full scans. FIXME */ + pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 16; whereLoopOutputAdjust(pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; }else{ @@ -114644,20 +113114,23 @@ && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ) ){ pNew->iSortIdx = b ? iSortIdx : 0; - - /* The cost of visiting the index rows is N*K, where K is - ** between 1.1 and 3.0, depending on the relative sizes of the - ** index and table rows. If this is a non-covering index scan, - ** also add the cost of visiting table rows (N*3.0). */ - pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow; - if( m!=0 ){ - pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16); - } - + if( m==0 ){ + /* TUNING: Cost of a covering index scan is K*(N + log2(N)). + ** + The extra factor K of between 1.1 and 3.0 that depends + ** on the relative sizes of the table and the index. K + ** is smaller for smaller indices, thus favoring them. + */ + pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 + + (15*pProbe->szIdxRow)/pTab->szTabRow; + }else{ + /* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N) + ** which we will simplify to just N*log2(N) */ + pNew->rRun = rSize + rLogSize; + } whereLoopOutputAdjust(pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; } @@ -114824,12 +113297,12 @@ assert( pNew->nLTerm<=pNew->nLSlot ); pNew->u.vtab.idxNum = pIdxInfo->idxNum; pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; - pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? - pIdxInfo->nOrderBy : 0); + pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0) + && pIdxInfo->orderByConsumed); pNew->rSetup = 0; pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ @@ -114857,19 +113330,20 @@ WhereTerm *pTerm, *pWCEnd; int rc = SQLITE_OK; int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; - WhereOrSet sSum, sCur; + WhereOrSet sSum, sCur, sPrev; struct SrcList_item *pItem; pWC = pBuilder->pWC; if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; memset(&sSum, 0, sizeof(sSum)); pItem = pWInfo->pTabList->a + pNew->iTab; + if( !HasRowid(pItem->pTab) ) return SQLITE_OK; iCur = pItem->iCursor; for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 @@ -114912,11 +113386,10 @@ break; }else if( once ){ whereOrMove(&sSum, &sCur); once = 0; }else{ - WhereOrSet sPrev; whereOrMove(&sPrev, &sSum); sSum.n = 0; for(i=0; iwsFlags = WHERE_MULTI_OR; pNew->rSetup = 0; pNew->iSortIdx = 0; memset(&pNew->u, 0, sizeof(pNew->u)); for(i=0; rc==SQLITE_OK && irRun = sSum.a[i].rRun + 1; + /* TUNING: Multiple by 3.5 for the secondary table lookup */ + pNew->rRun = sSum.a[i].rRun + 18; pNew->nOut = sSum.a[i].nOut; pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } } @@ -114997,25 +113459,25 @@ } /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 5th ** parameters) to see if it outputs rows in the requested ORDER BY -** (or GROUP BY) without requiring a separate sort operation. Return N: +** (or GROUP BY) without requiring a separate sort operation. Return: ** -** N>0: N terms of the ORDER BY clause are satisfied -** N==0: No terms of the ORDER BY clause are satisfied -** N<0: Unknown yet how many terms of ORDER BY might be satisfied. +** 0: ORDER BY is not satisfied. Sorting required +** 1: ORDER BY is satisfied. Omit sorting +** -1: Unknown at this time ** ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as ** strict. With GROUP BY and DISTINCT the only requirement is that ** equivalent rows appear immediately adjacent to one another. GROUP BY -** and DISTINCT do not require rows to appear in any particular order as long +** and DISTINT do not require rows to appear in any particular order as long ** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ -static i8 wherePathSatisfiesOrderBy( +static int wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */ u16 nLoop, /* Number of entries in pPath->aLoop[] */ @@ -115067,10 +113529,18 @@ ** rowid appears in the ORDER BY clause, the corresponding WhereLoop is ** automatically order-distinct. */ assert( pOrderBy!=0 ); + + /* Sortability of virtual tables is determined by the xBestIndex method + ** of the virtual table itself */ + if( pLast->wsFlags & WHERE_VIRTUALTABLE ){ + testcase( nLoop>0 ); /* True when outer loops are one-row and match + ** no ORDER BY terms */ + return pLast->u.vtab.isOrdered; + } if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; nOrderBy = pOrderBy->nExpr; testcase( nOrderBy==BMS-1 ); if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ @@ -115079,14 +113549,11 @@ orderDistinctMask = 0; ready = 0; for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; pLoop = iLoopaLoop[iLoop] : pLast; - if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ - if( pLoop->u.vtab.isOrdered ) obSat = obDone; - break; - } + assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; /* Mark off any ORDER BY term X that is a column in the table of ** the current loop for which there is term in the WHERE ** clause of the form X IS NULL or X=? that reference only outer @@ -115170,11 +113637,11 @@ ){ isOrderDistinct = 0; } /* Find the ORDER BY term that corresponds to the j-th column - ** of the index and mark that ORDER BY term off + ** of the index and and mark that ORDER BY term off */ bOnce = 1; isMatch = 0; for(i=0; bOnce && izName, pIndex->azColl[j])!=0 ) continue; } isMatch = 1; break; } - if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ - /* Make sure the sort order is compatible in an ORDER BY clause. - ** Sort order is irrelevant for a GROUP BY clause. */ - if( revSet ){ - if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0; - }else{ - rev = revIdx ^ pOrderBy->a[i].sortOrder; - if( rev ) *pRevMask |= MASKBIT(iLoop); - revSet = 1; - } - } if( isMatch ){ if( iColumn<0 ){ testcase( distinctColumns==0 ); distinctColumns = 1; } obSat |= MASKBIT(i); + if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ + /* Make sure the sort order is compatible in an ORDER BY clause. + ** Sort order is irrelevant for a GROUP BY clause. */ + if( revSet ){ + if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0; + }else{ + rev = revIdx ^ pOrderBy->a[i].sortOrder; + if( rev ) *pRevMask |= MASKBIT(iLoop); + revSet = 1; + } + } }else{ /* No match found */ if( j==0 || jmaskSelf; for(i=0; ia[i].pExpr; - mTerm = exprTableUsage(&pWInfo->sMaskSet,p); - if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue; - if( (mTerm&~orderDistinctMask)==0 ){ + if( (exprTableUsage(&pWInfo->sMaskSet, p)&~orderDistinctMask)==0 ){ obSat |= MASKBIT(i); } } } } /* End the loop over all WhereLoops from outer-most down to inner-most */ - if( obSat==obDone ) return (i8)nOrderBy; - if( !isOrderDistinct ){ - for(i=nOrderBy-1; i>0; i--){ - Bitmask m = MASKBIT(i) - 1; - if( (obSat&m)==m ) return i; - } - return 0; - } + if( obSat==obDone ) return 1; + if( !isOrderDistinct ) return 0; return -1; } - -/* -** If the WHERE_GROUPBY flag is set in the mask passed to sqlite3WhereBegin(), -** the planner assumes that the specified pOrderBy list is actually a GROUP -** BY clause - and so any order that groups rows as required satisfies the -** request. -** -** Normally, in this case it is not possible for the caller to determine -** whether or not the rows are really being delivered in sorted order, or -** just in some other order that provides the required grouping. However, -** if the WHERE_SORTBYGROUP flag is also passed to sqlite3WhereBegin(), then -** this function may be called on the returned WhereInfo object. It returns -** true if the rows really will be sorted in the specified order, or false -** otherwise. -** -** For example, assuming: -** -** CREATE INDEX i1 ON t1(x, Y); -** -** then -** -** SELECT * FROM t1 GROUP BY x,y ORDER BY x,y; -- IsSorted()==1 -** SELECT * FROM t1 GROUP BY y,x ORDER BY y,x; -- IsSorted()==0 -*/ -SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo *pWInfo){ - assert( pWInfo->wctrlFlags & WHERE_GROUPBY ); - assert( pWInfo->wctrlFlags & WHERE_SORTBYGROUP ); - return pWInfo->sorted; -} - #ifdef WHERETRACE_ENABLED /* For debugging use only: */ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ static char zName[65]; int i; @@ -115291,10 +113719,11 @@ if( pLast ) zName[i++] = pLast->cId; zName[i] = 0; return zName; } #endif + /* ** Given the list of WhereLoop objects at pWInfo->pLoops, this routine ** attempts to find the lowest cost path that visits each WhereLoop ** once. This path is then loaded into the pWInfo->a[].pWLoop fields. @@ -115312,15 +113741,15 @@ Parse *pParse; /* Parsing context */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ - int nOrderBy; /* Number of ORDER BY clause terms */ LogEst rCost; /* Cost of a path */ LogEst nOut; /* Number of outputs */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ LogEst mxOut = 0; /* Maximum nOut value on the set of paths */ + LogEst rSortCost; /* Cost to do a sort */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ WherePath *pFrom; /* An element of aFrom[] that we are working on */ WherePath *pTo; /* An element of aTo[] that we are working on */ @@ -115332,11 +113761,11 @@ db = pParse->db; nLoop = pWInfo->nLevel; /* TUNING: For simple queries, only the best path is tracked. ** For 2-way joins, the 5 best paths are followed. ** For joins of 3 or more tables, track the 10 best paths */ - mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10); + mxChoice = (nLoop==1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); WHERETRACE(0x002, ("---- begin solver\n")); /* Allocate and initialize space for aTo and aFrom */ ii = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; @@ -115358,16 +113787,20 @@ aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) ); nFrom = 1; /* Precompute the cost of sorting the final result set, if the caller ** to sqlite3WhereBegin() was concerned about sorting */ + rSortCost = 0; if( pWInfo->pOrderBy==0 || nRowEst==0 ){ - aFrom[0].isOrdered = 0; - nOrderBy = 0; + aFrom[0].isOrderedValid = 1; }else{ - aFrom[0].isOrdered = nLoop>0 ? -1 : 1; - nOrderBy = pWInfo->pOrderBy->nExpr; + /* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the + ** number of output rows. The 48 is the expected size of a row to sort. + ** FIXME: compute a better estimate of the 48 multiplier based on the + ** result set expressions. */ + rSortCost = nRowEst + estLog(nRowEst); + WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost)); } /* Compute successively longer WherePaths using the previous generation ** of WherePaths as the basis for the next. Keep track of the mxChoice ** best paths at each generation */ @@ -115375,61 +113808,43 @@ nTo = 0; for(ii=0, pFrom=aFrom; iipLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ Bitmask maskNew; Bitmask revMask = 0; - i8 isOrdered = pFrom->isOrdered; + u8 isOrderedValid = pFrom->isOrderedValid; + u8 isOrdered = pFrom->isOrdered; if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); rCost = sqlite3LogEstAdd(rCost, pFrom->rCost); nOut = pFrom->nRow + pWLoop->nOut; maskNew = pFrom->maskLoop | pWLoop->maskSelf; - if( isOrdered<0 ){ - isOrdered = wherePathSatisfiesOrderBy(pWInfo, + if( !isOrderedValid ){ + switch( wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, - iLoop, pWLoop, &revMask); - if( isOrdered>=0 && isOrdered0 && 66==sqlite3LogEst(100) ); - rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy) - 66; - rSortCost = nRowEst + estLog(nRowEst) + rScale + 16; - - /* TUNING: The cost of implementing DISTINCT using a B-TREE is - ** similar but with a larger constant of proportionality. - ** Multiply by an additional factor of 3.0. */ - if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ - rSortCost += 16; - } - WHERETRACE(0x002, - ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n", - rSortCost, (nOrderBy-isOrdered), nOrderBy, rCost, - sqlite3LogEstAdd(rCost,rSortCost))); - rCost = sqlite3LogEstAdd(rCost, rSortCost); + iLoop, pWLoop, &revMask) ){ + case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ + isOrdered = 1; + isOrderedValid = 1; + break; + case 0: /* No. pFrom+pWLoop will require a separate sort */ + isOrdered = 0; + isOrderedValid = 1; + rCost = sqlite3LogEstAdd(rCost, rSortCost); + break; + default: /* Cannot tell yet. Try again on the next iteration */ + break; } }else{ revMask = pFrom->revLoop; } /* Check to see if pWLoop should be added to the mxChoice best so far */ for(jj=0, pTo=aTo; jjmaskLoop==maskNew - && ((pTo->isOrdered^isOrdered)&80)==0 + && pTo->isOrderedValid==isOrderedValid && ((pTo->rCost<=rCost && pTo->nRow<=nOut) || (pTo->rCost>=rCost && pTo->nRow>=nOut)) ){ testcase( jj==nTo-1 ); break; @@ -115439,11 +113854,11 @@ if( nTo>=mxChoice && rCost>=mxCost ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrdered>=0 ? isOrdered+'0' : '?'); + isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); } #endif continue; } /* Add a new Path to the aTo[] set */ @@ -115457,24 +113872,24 @@ pTo = &aTo[jj]; #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrdered>=0 ? isOrdered+'0' : '?'); + isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); } #endif }else{ if( pTo->rCost<=rCost && pTo->nRow<=nOut ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Skip %s cost=%-3d,%3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrdered>=0 ? isOrdered+'0' : '?'); + isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } #endif testcase( pTo->rCost==rCost ); continue; } @@ -115483,22 +113898,23 @@ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Update %s cost=%-3d,%3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrdered>=0 ? isOrdered+'0' : '?'); + isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } #endif } /* pWLoop is a winner. Add it to the set of best so far */ pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; pTo->revLoop = revMask; pTo->nRow = nOut; pTo->rCost = rCost; + pTo->isOrderedValid = isOrderedValid; pTo->isOrdered = isOrdered; memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); pTo->aLoop[iLoop] = pWLoop; if( nTo>=mxChoice ){ mxI = 0; @@ -115519,12 +113935,12 @@ if( sqlite3WhereTrace>=2 ){ sqlite3DebugPrintf("---- after round %d ----\n", iLoop); for(ii=0, pTo=aTo; iirCost, pTo->nRow, - pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?'); - if( pTo->isOrdered>0 ){ + pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); + if( pTo->isOrderedValid && pTo->isOrdered ){ sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop); }else{ sqlite3DebugPrintf("\n"); } } @@ -115563,37 +113979,20 @@ && nRowEst ){ Bitmask notUsed; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); - if( rc==pWInfo->pResultSet->nExpr ){ - pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; - } + if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } - if( pWInfo->pOrderBy ){ + if( pFrom->isOrdered ){ if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ - if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ - pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; - } + pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; }else{ - pWInfo->nOBSat = pFrom->isOrdered; - if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0; + pWInfo->bOBSat = 1; pWInfo->revMask = pFrom->revLoop; } - if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) - && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr - ){ - Bitmask notUsed = 0; - int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, - pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used - ); - assert( pWInfo->sorted==0 ); - pWInfo->sorted = (nOrder==pWInfo->pOrderBy->nExpr); - } - } - - + } pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ sqlite3DbFree(db, pSpace); return SQLITE_OK; @@ -115671,11 +114070,11 @@ pLoop->nOut = (LogEst)1; pWInfo->a[0].pWLoop = pLoop; pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur); pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; - if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; + if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1; if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } #ifdef SQLITE_DEBUG pLoop->cId = '0'; @@ -115775,11 +114174,11 @@ */ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ - ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ + ExprList *pOrderBy, /* An ORDER BY clause, or NULL */ ExprList *pResultSet, /* Result set of the query */ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ ){ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ @@ -115797,14 +114196,10 @@ /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); - - /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ - testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); - if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; sWLB.pOrderBy = pOrderBy; /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ @@ -115845,11 +114240,11 @@ pWInfo->nLevel = nTabList; pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; pWInfo->pResultSet = pResultSet; - pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); + pWInfo->iBreak = sqlite3VdbeMakeLabel(v); pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; pMaskSet = &pWInfo->sMaskSet; sWLB.pWInfo = pWInfo; sWLB.pWC = &pWInfo->sWC; @@ -115864,10 +114259,11 @@ ** subexpression is separated by an AND operator. */ initMaskSet(pMaskSet); whereClauseInit(&pWInfo->sWC, pWInfo); whereSplit(&pWInfo->sWC, pWhere, TK_AND); + sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. */ for(ii=0; iinTerm; ii++){ @@ -115879,11 +114275,11 @@ } /* Special case: No FROM clause */ if( nTabList==0 ){ - if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr; + if( pOrderBy ) pWInfo->bOBSat = 1; if( wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } } @@ -115924,10 +114320,26 @@ */ exprAnalyzeAll(pTabList, &pWInfo->sWC); if( db->mallocFailed ){ goto whereBeginError; } + + /* If the ORDER BY (or GROUP BY) clause contains references to general + ** expressions, then we won't be able to satisfy it using indices, so + ** go ahead and disable it now. + */ + if( pOrderBy && (wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){ + for(ii=0; iinExpr; ii++){ + Expr *pExpr = sqlite3ExprSkipCollate(pOrderBy->a[ii].pExpr); + if( pExpr->op!=TK_COLUMN ){ + pWInfo->pOrderBy = pOrderBy = 0; + break; + }else if( pExpr->iColumn<0 ){ + break; + } + } + } if( wctrlFlags & WHERE_WANT_DISTINCT ){ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ /* The DISTINCT marking is pointless. Ignore it. */ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; @@ -115990,12 +114402,12 @@ } #ifdef WHERETRACE_ENABLED /* !=0 */ if( sqlite3WhereTrace ){ int ii; sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); - if( pWInfo->nOBSat>0 ){ - sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); + if( pWInfo->bOBSat ){ + sqlite3DebugPrintf(" ORDERBY=0x%llx", pWInfo->revMask); } switch( pWInfo->eDistinct ){ case WHERE_DISTINCT_UNIQUE: { sqlite3DebugPrintf(" DISTINCT=unique"); break; @@ -116114,18 +114526,11 @@ Index *pIx = pLoop->u.btree.pIndex; int iIndexCur; int op = OP_OpenRead; /* iIdxCur is always set if to a positive value if ONEPASS is possible */ assert( iIdxCur!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); - if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) - && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 - ){ - /* This is one term of an OR-optimization using the PRIMARY KEY of a - ** WITHOUT ROWID table. No need for a separate index */ - iIndexCur = pLevel->iTabCur; - op = 0; - }else if( pWInfo->okOnePass ){ + if( pWInfo->okOnePass ){ Index *pJ = pTabItem->pTab->pIndex; iIndexCur = iIdxCur; assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); while( ALWAYS(pJ) && pJ!=pIx ){ iIndexCur++; @@ -116139,17 +114544,15 @@ iIndexCur = pParse->nTab++; } pLevel->iIdxCur = iIndexCur; assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); - if( op ){ - sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); - sqlite3VdbeSetP4KeyInfo(pParse, pIx); - VdbeComment((v, "%s", pIx->zName)); - } + sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIx); + VdbeComment((v, "%s", pIx->zName)); } - if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iDb); notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor); } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); if( db->mallocFailed ) goto whereBeginError; @@ -116207,27 +114610,20 @@ int addr; pLevel = &pWInfo->a[i]; pLoop = pLevel->pWLoop; sqlite3VdbeResolveLabel(v, pLevel->addrCont); if( pLevel->op!=OP_Noop ){ - sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); + sqlite3VdbeAddOp2(v, pLevel->op, pLevel->p1, pLevel->p2); sqlite3VdbeChangeP5(v, pLevel->p5); - VdbeCoverage(v); - VdbeCoverageIf(v, pLevel->op==OP_Next); - VdbeCoverageIf(v, pLevel->op==OP_Prev); - VdbeCoverageIf(v, pLevel->op==OP_VNext); } if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ 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); - VdbeCoverage(v); - VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen); - VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } sqlite3DbFree(db, pLevel->u.in.aInLoop); } sqlite3VdbeResolveLabel(v, pLevel->addrBrk); @@ -116236,11 +114632,11 @@ VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); sqlite3VdbeJumpHere(v, pLevel->addrSkip); sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); } if( pLevel->iLeftJoin ){ - addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); + addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || (pLoop->wsFlags & WHERE_INDEXED)!=0 ); if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor); } @@ -116263,42 +114659,16 @@ */ sqlite3VdbeResolveLabel(v, pWInfo->iBreak); assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ - int k, last; - VdbeOp *pOp; Index *pIdx = 0; struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); pLoop = pLevel->pWLoop; - /* For a co-routine, change all OP_Column references to the table of - ** the co-routine into OP_SCopy of result contained in a register. - ** OP_Rowid becomes OP_Null. - */ - if( pTabItem->viaCoroutine && !db->mallocFailed ){ - last = sqlite3VdbeCurrentAddr(v); - k = pLevel->addrBody; - pOp = sqlite3VdbeGetOp(v, k); - for(; kp1!=pLevel->iTabCur ) continue; - if( pOp->opcode==OP_Column ){ - pOp->opcode = OP_Copy; - pOp->p1 = pOp->p2 + pTabItem->regResult; - pOp->p2 = pOp->p3; - pOp->p3 = 0; - }else if( pOp->opcode==OP_Rowid ){ - pOp->opcode = OP_Null; - pOp->p1 = 0; - pOp->p3 = 0; - } - } - continue; - } - /* Close all of the cursors that were opened by sqlite3WhereBegin. ** Except, do not close cursors that will be reused by the OR optimization ** (WHERE_OMIT_OPEN_CLOSE). And do not close the OP_OpenWrite cursors ** created for the ONEPASS optimization. */ @@ -116333,10 +114703,13 @@ pIdx = pLoop->u.btree.pIndex; }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ pIdx = pLevel->u.pCovidx; } if( pIdx && !db->mallocFailed ){ + int k, last; + VdbeOp *pOp; + last = sqlite3VdbeCurrentAddr(v); k = pLevel->addrBody; pOp = sqlite3VdbeGetOp(v, k); for(; kp1!=pLevel->iTabCur ) continue; @@ -118746,54 +117119,33 @@ sqlite3ExplainFinish(pParse->pVdbe); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3); } break; case 112: /* select ::= with selectnowith */ -{ - Select *p = yymsp[0].minor.yy3, *pNext, *pLoop; - if( p ){ - int cnt = 0, mxSelect; - p->pWith = yymsp[-1].minor.yy59; - if( p->pPrior ){ - pNext = 0; - for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ - pLoop->pNext = pNext; - pLoop->selFlags |= SF_Compound; - } - mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT]; - if( mxSelect && cnt>mxSelect ){ - sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); - } - } +{ + if( yymsp[0].minor.yy3 ){ + yymsp[0].minor.yy3->pWith = yymsp[-1].minor.yy59; }else{ sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy59); } - yygotominor.yy3 = p; + yygotominor.yy3 = yymsp[0].minor.yy3; } break; case 113: /* selectnowith ::= oneselect */ case 119: /* oneselect ::= values */ yytestcase(yyruleno==119); {yygotominor.yy3 = yymsp[0].minor.yy3;} break; case 114: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - Select *pRhs = yymsp[0].minor.yy3; - if( pRhs && pRhs->pPrior ){ - SrcList *pFrom; - Token x; - x.n = 0; - pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); - pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0); - } - if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy328; - pRhs->pPrior = yymsp[-2].minor.yy3; + if( yymsp[0].minor.yy3 ){ + yymsp[0].minor.yy3->op = (u8)yymsp[-1].minor.yy328; + yymsp[0].minor.yy3->pPrior = yymsp[-2].minor.yy3; if( yymsp[-1].minor.yy328!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, yymsp[-2].minor.yy3); } - yygotominor.yy3 = pRhs; + yygotominor.yy3 = yymsp[0].minor.yy3; } break; case 116: /* multiselect_op ::= UNION ALL */ {yygotominor.yy328 = TK_ALL;} break; @@ -119230,37 +117582,10 @@ ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy328]); sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy346.pExpr); - }else if( yymsp[-1].minor.yy14->nExpr==1 ){ - /* Expressions of the form: - ** - ** expr1 IN (?1) - ** expr1 NOT IN (?2) - ** - ** with exactly one value on the RHS can be simplified to something - ** like this: - ** - ** expr1 == ?1 - ** expr1 <> ?2 - ** - ** But, the RHS of the == or <> is marked with the EP_Generic flag - ** so that it may not contribute to the computation of comparison - ** affinity or the collating sequence to use for comparison. Otherwise, - ** the semantics would be subtly different from IN or NOT IN. - */ - Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr; - yymsp[-1].minor.yy14->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); - /* pRHS cannot be NULL because a malloc error would have been detected - ** before now and control would have never reached this point */ - if( ALWAYS(pRHS) ){ - pRHS->flags &= ~EP_Collate; - pRHS->flags |= EP_Generic; - } - yygotominor.yy346.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy328 ? TK_NE : TK_EQ, yymsp[-4].minor.yy346.pExpr, pRHS, 0); }else{ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0); if( yygotominor.yy346.pExpr ){ yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14; sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr); @@ -121877,11 +120202,10 @@ Table *pTab = (Table *)sqliteHashData(p); if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); } } } - sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); #else UNUSED_PARAMETER(db); #endif } @@ -124191,32 +122515,10 @@ int *aProg = va_arg(ap, int*); rc = sqlite3BitvecBuiltinTest(sz, aProg); break; } - /* - ** sqlite3_test_control(FAULT_INSTALL, xCallback) - ** - ** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called, - ** if xCallback is not NULL. - ** - ** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0) - ** is called immediately after installing the new callback and the return - ** value from sqlite3FaultSim(0) becomes the return from - ** sqlite3_test_control(). - */ - case SQLITE_TESTCTRL_FAULT_INSTALL: { - /* MSVC is picky about pulling func ptrs from va lists. - ** http://support.microsoft.com/kb/47961 - ** sqlite3Config.xTestCallback = va_arg(ap, int(*)(int)); - */ - typedef int(*TESTCALLBACKFUNC_t)(int); - sqlite3Config.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t); - rc = sqlite3FaultSim(0); - break; - } - /* ** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd) ** ** Register hooks to call to indicate which malloc() failures ** are benign. @@ -124304,26 +122606,10 @@ int x = va_arg(ap,int); rc = ALWAYS(x); break; } - /* - ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER); - ** - ** The integer returned reveals the byte-order of the computer on which - ** SQLite is running: - ** - ** 1 big-endian, determined at run-time - ** 10 little-endian, determined at run-time - ** 432101 big-endian, determined at compile-time - ** 123410 little-endian, determined at compile-time - */ - case SQLITE_TESTCTRL_BYTEORDER: { - rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; - break; - } - /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N) ** ** Set the nReserve size to N for the main database on the database ** connection db. */ @@ -124423,25 +122709,10 @@ case SQLITE_TESTCTRL_NEVER_CORRUPT: { sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int); break; } - - /* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr); - ** - ** Set the VDBE coverage callback function to xCallback with context - ** pointer ptr. - */ - case SQLITE_TESTCTRL_VDBE_COVERAGE: { -#ifdef SQLITE_VDBE_COVERAGE - typedef void (*branch_callback)(void*,int,u8,u8); - sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback); - sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*); -#endif - break; - } - } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ return rc; } @@ -124522,11 +122793,11 @@ ** Return 1 if database is read-only or 0 if read/write. Return -1 if ** no such database exists. */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ Btree *pBt = sqlite3DbNameToBtree(db, zDbName); - return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; + return pBt ? sqlite3PagerIsreadonly(sqlite3BtreePager(pBt)) : -1; } /************** End of main.c ************************************************/ /************** Begin file notify.c ******************************************/ /* @@ -125642,24 +123913,24 @@ char **azColumn; /* column names. malloced */ u8 *abNotindexed; /* True for 'notindexed' columns */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ char *zContentTbl; /* content=xxx option, or NULL */ char *zLanguageid; /* languageid=xxx option, or NULL */ - int nAutoincrmerge; /* Value configured by 'automerge' */ + u8 bAutoincrmerge; /* True if automerge=1 */ u32 nLeafAdd; /* Number of leaf blocks added this trans */ /* Precompiled statements used by the implementation. Each of these ** statements is run and reset within a single virtual table API call. */ - sqlite3_stmt *aStmt[40]; + sqlite3_stmt *aStmt[37]; char *zReadExprlist; char *zWriteExprlist; int nNodeSize; /* Soft limit for node size */ u8 bFts4; /* True for FTS4, false for FTS3 */ - u8 bHasStat; /* True if %_stat table exists (2==unknown) */ + u8 bHasStat; /* True if %_stat table exists */ u8 bHasDocsize; /* True if %_docsize table exists */ u8 bDescIdx; /* True if doclists are in reverse order */ u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */ int nPgsz; /* Page size for host database */ char *zSegmentsTbl; /* Name of %_segments table */ @@ -127070,11 +125341,11 @@ p->nMaxPendingData = FTS3_MAX_PENDING_DATA; p->bHasDocsize = (isFts4 && bNoDocsize==0); p->bHasStat = isFts4; p->bFts4 = isFts4; p->bDescIdx = bDescIdx; - p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */ + p->bAutoincrmerge = 0xff; /* 0xff means setting unknown */ p->zContentTbl = zContent; p->zLanguageid = zLanguageid; zContent = 0; zLanguageid = 0; TESTONLY( p->inTransaction = -1 ); @@ -127113,13 +125384,11 @@ /* Fill in the abNotindexed array */ for(iCol=0; iColazColumn[iCol]); for(i=0; iazColumn[iCol], zNot, n) - ){ + if( zNot && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n) ){ p->abNotindexed[iCol] = 1; sqlite3_free(zNot); azNotindexed[i] = 0; } } @@ -127149,11 +125418,14 @@ /* Check to see if a legacy fts3 table has been "upgraded" by the ** addition of a %_stat table so that it can use incremental merge. */ if( !isFts4 && !isCreate ){ - p->bHasStat = 2; + int rc2 = SQLITE_OK; + fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2", + p->zDb, p->zName); + if( rc2==SQLITE_OK ) p->bHasStat = 1; } /* Figure out the page-size for the database. This is required in order to ** estimate the cost of loading large doclists from the database. */ fts3DatabasePageSize(&rc, p); @@ -129041,56 +127313,26 @@ const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */ Fts3Table *p = (Fts3Table*)pVtab; int rc = sqlite3Fts3PendingTermsFlush(p); - if( rc==SQLITE_OK - && p->nLeafAdd>(nMinMerge/16) - && p->nAutoincrmerge && p->nAutoincrmerge!=0xff - ){ + if( rc==SQLITE_OK && p->bAutoincrmerge==1 && p->nLeafAdd>(nMinMerge/16) ){ int mxLevel = 0; /* Maximum relative level value in db */ int A; /* Incr-merge parameter A */ rc = sqlite3Fts3MaxLevel(p, &mxLevel); assert( rc==SQLITE_OK || mxLevel==0 ); A = p->nLeafAdd * mxLevel; A += (A/2); - if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge); + if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8); } sqlite3Fts3SegmentsClose(p); return rc; } /* -** If it is currently unknown whether or not the FTS table has an %_stat -** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat -** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code -** if an error occurs. -*/ -static int fts3SetHasStat(Fts3Table *p){ - int rc = SQLITE_OK; - if( p->bHasStat==2 ){ - const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'"; - char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName); - if( zSql ){ - sqlite3_stmt *pStmt = 0; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - if( rc==SQLITE_OK ){ - int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW); - rc = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ) p->bHasStat = bHasStat; - } - sqlite3_free(zSql); - }else{ - rc = SQLITE_NOMEM; - } - } - return rc; -} - -/* -** Implementation of xBegin() method. +** Implementation of xBegin() method. This is a no-op. */ static int fts3BeginMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; UNUSED_PARAMETER(pVtab); assert( p->pSegments==0 ); @@ -129097,11 +127339,11 @@ assert( p->nPendingData==0 ); assert( p->inTransaction!=1 ); TESTONLY( p->inTransaction = 1 ); TESTONLY( p->mxSavepoint = -1; ); p->nLeafAdd = 0; - return fts3SetHasStat(p); + return SQLITE_OK; } /* ** Implementation of xCommit() method. This is a no-op. The contents of ** the pending-terms hash-table have already been flushed into the database @@ -129346,24 +127588,18 @@ ){ Fts3Table *p = (Fts3Table *)pVtab; sqlite3 *db = p->db; /* Database connection */ int rc; /* Return Code */ - /* At this point it must be known if the %_stat table exists or not. - ** So bHasStat may not be 2. */ - rc = fts3SetHasStat(p); - /* As it happens, the pending terms table is always empty here. This is ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction ** always opens a savepoint transaction. And the xSavepoint() method ** flushes the pending terms table. But leave the (no-op) call to ** PendingTermsFlush() in in case that changes. */ assert( p->nPendingData==0 ); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3PendingTermsFlush(p); - } + rc = sqlite3Fts3PendingTermsFlush(p); if( p->zContentTbl==0 ){ fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", p->zDb, p->zName, zName @@ -132275,27 +130511,44 @@ sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; int rc; sqlite3_tokenizer_cursor *pCursor; Fts3Expr *pRet = 0; - int i = 0; - - /* Set variable i to the maximum number of bytes of input to tokenize. */ - for(i=0; iiLangid, z, i, &pCursor); + 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 nByte; /* total space to allocate */ rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); - if( rc==SQLITE_OK ){ + + if( (rc==SQLITE_OK || rc==SQLITE_DONE) && sqlite3_fts3_enable_parentheses ){ + int i; + if( rc==SQLITE_DONE ) iStart = n; + for(i=0; inNest++; + rc = fts3ExprParse(pParse, &z[i+1], n-i-1, &pRet, &nConsumed); + if( rc==SQLITE_OK && !pRet ){ + rc = SQLITE_DONE; + } + nConsumed = (int)(i + 1 + nConsumed); + break; + } + + if( z[i]==')' ){ + rc = SQLITE_DONE; + pParse->nNest--; + nConsumed = i+1; + break; + } + } + } + + if( nConsumed==0 && rc==SQLITE_OK ){ nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; pRet = (Fts3Expr *)fts3MallocZero(nByte); if( !pRet ){ rc = SQLITE_NOMEM; }else{ @@ -132325,18 +130578,17 @@ break; } } } - *pnConsumed = iEnd; - }else if( i && rc==SQLITE_DONE ){ - rc = SQLITE_OK; + nConsumed = iEnd; } pModule->xClose(pCursor); } + *pnConsumed = nConsumed; *ppExpr = pRet; return rc; } @@ -132582,25 +130834,10 @@ return SQLITE_ERROR; } return getNextString(pParse, &zInput[1], ii-1, ppExpr); } - if( sqlite3_fts3_enable_parentheses ){ - if( *zInput=='(' ){ - int nConsumed = 0; - pParse->nNest++; - rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); - if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; } - *pnConsumed = (int)(zInput - z) + 1 + nConsumed; - return rc; - }else if( *zInput==')' ){ - pParse->nNest--; - *pnConsumed = (int)((zInput - z) + 1); - *ppExpr = 0; - return SQLITE_DONE; - } - } /* If control flows to this point, this must be a regular token, or ** the end of the input. Read a regular token using the sqlite3_tokenizer ** interface. Before doing so, figure out if there is an explicit ** column specifier for the token. @@ -132715,104 +130952,100 @@ int isRequirePhrase = 1; while( rc==SQLITE_OK ){ Fts3Expr *p = 0; int nByte = 0; - - rc = getNextNode(pParse, zIn, nIn, &p, &nByte); - assert( nByte>0 || (rc!=SQLITE_OK && p==0) ); - if( rc==SQLITE_OK ){ - if( p ){ - int isPhrase; - - if( !sqlite3_fts3_enable_parentheses - && p->eType==FTSQUERY_PHRASE && pParse->isNot - ){ - /* Create an implicit NOT operator. */ - Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); - if( !pNot ){ - sqlite3Fts3ExprFree(p); - 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; - isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); - - /* The isRequirePhrase variable is set to true if a phrase or - ** an expression contained in parenthesis is required. If a - ** binary operator (AND, OR, NOT or NEAR) is encounted when - ** isRequirePhrase is set, this is a syntax error. - */ - if( !isPhrase && isRequirePhrase ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_ERROR; - goto exprparse_out; - } - - if( isPhrase && !isRequirePhrase ){ - /* Insert an implicit AND operator. */ - Fts3Expr *pAnd; - assert( pRet && pPrev ); - pAnd = fts3MallocZero(sizeof(Fts3Expr)); - if( !pAnd ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_NOMEM; - goto exprparse_out; - } - pAnd->eType = FTSQUERY_AND; - insertBinaryOperator(&pRet, pPrev, pAnd); - pPrev = pAnd; - } - - /* This test catches attempts to make either operand of a NEAR - ** operator something other than a phrase. For example, either of - ** the following: - ** - ** (bracketed expression) NEAR phrase - ** phrase NEAR (bracketed expression) - ** - ** Return an error in either case. - */ - if( pPrev && ( - (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE) - || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR) - )){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_ERROR; - goto exprparse_out; - } - - if( isPhrase ){ - if( pRet ){ - assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); - pPrev->pRight = p; - p->pParent = pPrev; - }else{ - pRet = p; - } - }else{ - insertBinaryOperator(&pRet, pPrev, p); - } - isRequirePhrase = !isPhrase; - } - pPrev = p; + rc = getNextNode(pParse, zIn, nIn, &p, &nByte); + if( rc==SQLITE_OK ){ + int isPhrase; + + if( !sqlite3_fts3_enable_parentheses + && p->eType==FTSQUERY_PHRASE && pParse->isNot + ){ + /* Create an implicit NOT operator. */ + Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); + if( !pNot ){ + sqlite3Fts3ExprFree(p); + 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; + isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); + + /* The isRequirePhrase variable is set to true if a phrase or + ** an expression contained in parenthesis is required. If a + ** binary operator (AND, OR, NOT or NEAR) is encounted when + ** isRequirePhrase is set, this is a syntax error. + */ + if( !isPhrase && isRequirePhrase ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; + } + + if( isPhrase && !isRequirePhrase ){ + /* Insert an implicit AND operator. */ + Fts3Expr *pAnd; + assert( pRet && pPrev ); + pAnd = fts3MallocZero(sizeof(Fts3Expr)); + if( !pAnd ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_NOMEM; + goto exprparse_out; + } + pAnd->eType = FTSQUERY_AND; + insertBinaryOperator(&pRet, pPrev, pAnd); + pPrev = pAnd; + } + + /* This test catches attempts to make either operand of a NEAR + ** operator something other than a phrase. For example, either of + ** the following: + ** + ** (bracketed expression) NEAR phrase + ** phrase NEAR (bracketed expression) + ** + ** Return an error in either case. + */ + if( pPrev && ( + (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE) + || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR) + )){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; + } + + if( isPhrase ){ + if( pRet ){ + assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); + pPrev->pRight = p; + p->pParent = pPrev; + }else{ + pRet = p; + } + }else{ + insertBinaryOperator(&pRet, pPrev, p); + } + isRequirePhrase = !isPhrase; } assert( nByte>0 ); } assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) ); nIn -= nByte; zIn += nByte; + pPrev = p; } if( rc==SQLITE_DONE && pRet && isRequirePhrase ){ rc = SQLITE_ERROR; } @@ -135796,11 +134029,10 @@ int nMalloc; /* Size of malloc'd buffer at zMalloc */ char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ int nSize; /* Size of allocation at aData */ int nData; /* Bytes of data in aData */ char *aData; /* Pointer to block from malloc() */ - i64 nLeafData; /* Number of bytes of leaf data written */ }; /* ** Type SegmentNode is used by the following three functions to create ** the interior part of the segment b+-tree structures (everything except @@ -135872,14 +134104,10 @@ #define SQL_CHOMP_SEGDIR 33 #define SQL_SEGMENT_IS_APPENDABLE 34 #define SQL_SELECT_INDEXES 35 #define SQL_SELECT_MXLEVEL 36 -#define SQL_SELECT_LEVEL_RANGE2 37 -#define SQL_UPDATE_LEVEL_IDX 38 -#define SQL_UPDATE_LEVEL 39 - /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, ** *pp is set to the requested statement handle and SQLITE_OK returned. ** Otherwise, an SQLite error code is returned and *pp is set to 0. @@ -135977,22 +134205,11 @@ ** Return the list of valid segment indexes for absolute level ? */ /* 35 */ "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC", /* SQL_SELECT_MXLEVEL ** Return the largest relative level in the FTS index or indexes. */ -/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'", - - /* Return segments in order from oldest to newest.*/ -/* 37 */ "SELECT level, idx, end_block " - "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? " - "ORDER BY level DESC, idx ASC", - - /* Update statements used while promoting segments */ -/* 38 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=-1,idx=? " - "WHERE level=? AND idx=?", -/* 39 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=? WHERE level=-1" - +/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'" }; int rc = SQLITE_OK; sqlite3_stmt *pStmt; assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); @@ -137529,11 +135746,10 @@ sqlite3_int64 iLevel, /* Value for "level" field (absolute level) */ int iIdx, /* Value for "idx" field */ sqlite3_int64 iStartBlock, /* Value for "start_block" field */ sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */ sqlite3_int64 iEndBlock, /* Value for "end_block" field */ - sqlite3_int64 nLeafData, /* Bytes of leaf data in segment */ char *zRoot, /* Blob value for "root" field */ int nRoot /* Number of bytes in buffer zRoot */ ){ sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_INSERT_SEGDIR, &pStmt, 0); @@ -137540,17 +135756,11 @@ if( rc==SQLITE_OK ){ sqlite3_bind_int64(pStmt, 1, iLevel); sqlite3_bind_int(pStmt, 2, iIdx); sqlite3_bind_int64(pStmt, 3, iStartBlock); sqlite3_bind_int64(pStmt, 4, iLeafEndBlock); - if( nLeafData==0 ){ - sqlite3_bind_int64(pStmt, 5, iEndBlock); - }else{ - char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); - if( !zEnd ) return SQLITE_NOMEM; - sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); - } + sqlite3_bind_int64(pStmt, 5, iEndBlock); sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); } return rc; @@ -137872,13 +136082,10 @@ nTerm + /* Term suffix */ sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ nDoclist; /* Doclist data */ } - /* Increase the total number of bytes written to account for the new entry. */ - pWriter->nLeafData += nReq; - /* If the buffer currently allocated is too small for this entry, realloc ** the buffer to make it large enough. */ if( nReq>pWriter->nSize ){ char *aNew = sqlite3_realloc(pWriter->aData, nReq); @@ -137946,17 +136153,17 @@ if( rc==SQLITE_OK ){ rc = fts3NodeWrite(p, pWriter->pTree, 1, pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot); } if( rc==SQLITE_OK ){ - rc = fts3WriteSegdir(p, iLevel, iIdx, - pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot); + rc = fts3WriteSegdir( + p, iLevel, iIdx, pWriter->iFirst, iLastLeaf, iLast, zRoot, nRoot); } }else{ /* The entire tree fits on the root node. Write it to the segdir table. */ - rc = fts3WriteSegdir(p, iLevel, iIdx, - 0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData); + rc = fts3WriteSegdir( + p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData); } p->nLeafAdd++; return rc; } @@ -138033,41 +136240,10 @@ getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) ); if( SQLITE_ROW==sqlite3_step(pStmt) ){ *pnMax = sqlite3_column_int64(pStmt, 0); } - return sqlite3_reset(pStmt); -} - -/* -** iAbsLevel is an absolute level that may be assumed to exist within -** the database. This function checks if it is the largest level number -** within its index. Assuming no error occurs, *pbMax is set to 1 if -** iAbsLevel is indeed the largest level, or 0 otherwise, and SQLITE_OK -** is returned. If an error occurs, an error code is returned and the -** final value of *pbMax is undefined. -*/ -static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){ - - /* Set pStmt to the compiled version of: - ** - ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? - ** - ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). - */ - sqlite3_stmt *pStmt; - int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); - if( rc!=SQLITE_OK ) return rc; - sqlite3_bind_int64(pStmt, 1, iAbsLevel+1); - sqlite3_bind_int64(pStmt, 2, - ((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL - ); - - *pbMax = 0; - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL; - } return sqlite3_reset(pStmt); } /* ** Delete all entries in the %_segments table associated with the segment @@ -138602,144 +136778,10 @@ pCsr->apSegment = 0; pCsr->aBuffer = 0; } } -/* -** Decode the "end_block" field, selected by column iCol of the SELECT -** statement passed as the first argument. -** -** The "end_block" field may contain either an integer, or a text field -** containing the text representation of two non-negative integers separated -** by one or more space (0x20) characters. In the first case, set *piEndBlock -** to the integer value and *pnByte to zero before returning. In the second, -** set *piEndBlock to the first value and *pnByte to the second. -*/ -static void fts3ReadEndBlockField( - sqlite3_stmt *pStmt, - int iCol, - i64 *piEndBlock, - i64 *pnByte -){ - const unsigned char *zText = sqlite3_column_text(pStmt, iCol); - if( zText ){ - int i; - int iMul = 1; - i64 iVal = 0; - for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ - iVal = iVal*10 + (zText[i] - '0'); - } - *piEndBlock = iVal; - while( zText[i]==' ' ) i++; - iVal = 0; - if( zText[i]=='-' ){ - i++; - iMul = -1; - } - for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ - iVal = iVal*10 + (zText[i] - '0'); - } - *pnByte = (iVal * (i64)iMul); - } -} - - -/* -** A segment of size nByte bytes has just been written to absolute level -** iAbsLevel. Promote any segments that should be promoted as a result. -*/ -static int fts3PromoteSegments( - Fts3Table *p, /* FTS table handle */ - sqlite3_int64 iAbsLevel, /* Absolute level just updated */ - sqlite3_int64 nByte /* Size of new segment at iAbsLevel */ -){ - int rc = SQLITE_OK; - sqlite3_stmt *pRange; - - rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE2, &pRange, 0); - - if( rc==SQLITE_OK ){ - int bOk = 0; - i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1; - i64 nLimit = (nByte*3)/2; - - /* Loop through all entries in the %_segdir table corresponding to - ** segments in this index on levels greater than iAbsLevel. If there is - ** at least one such segment, and it is possible to determine that all - ** such segments are smaller than nLimit bytes in size, they will be - ** promoted to level iAbsLevel. */ - sqlite3_bind_int64(pRange, 1, iAbsLevel+1); - sqlite3_bind_int64(pRange, 2, iLast); - while( SQLITE_ROW==sqlite3_step(pRange) ){ - i64 nSize = 0, dummy; - fts3ReadEndBlockField(pRange, 2, &dummy, &nSize); - if( nSize<=0 || nSize>nLimit ){ - /* If nSize==0, then the %_segdir.end_block field does not not - ** contain a size value. This happens if it was written by an - ** old version of FTS. In this case it is not possible to determine - ** the size of the segment, and so segment promotion does not - ** take place. */ - bOk = 0; - break; - } - bOk = 1; - } - rc = sqlite3_reset(pRange); - - if( bOk ){ - int iIdx = 0; - sqlite3_stmt *pUpdate1; - sqlite3_stmt *pUpdate2; - - if( rc==SQLITE_OK ){ - rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0); - } - if( rc==SQLITE_OK ){ - rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL, &pUpdate2, 0); - } - - if( rc==SQLITE_OK ){ - - /* Loop through all %_segdir entries for segments in this index with - ** levels equal to or greater than iAbsLevel. As each entry is visited, - ** updated it to set (level = -1) and (idx = N), where N is 0 for the - ** oldest segment in the range, 1 for the next oldest, and so on. - ** - ** In other words, move all segments being promoted to level -1, - ** setting the "idx" fields as appropriate to keep them in the same - ** order. The contents of level -1 (which is never used, except - ** transiently here), will be moved back to level iAbsLevel below. */ - sqlite3_bind_int64(pRange, 1, iAbsLevel); - while( SQLITE_ROW==sqlite3_step(pRange) ){ - sqlite3_bind_int(pUpdate1, 1, iIdx++); - sqlite3_bind_int(pUpdate1, 2, sqlite3_column_int(pRange, 0)); - sqlite3_bind_int(pUpdate1, 3, sqlite3_column_int(pRange, 1)); - sqlite3_step(pUpdate1); - rc = sqlite3_reset(pUpdate1); - if( rc!=SQLITE_OK ){ - sqlite3_reset(pRange); - break; - } - } - } - if( rc==SQLITE_OK ){ - rc = sqlite3_reset(pRange); - } - - /* Move level -1 to level iAbsLevel */ - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pUpdate2, 1, iAbsLevel); - sqlite3_step(pUpdate2); - rc = sqlite3_reset(pUpdate2); - } - } - } - - - return rc; -} - /* ** Merge all level iLevel segments in the database into a single ** iLevel+1 segment. Or, if iLevel<0, merge all segments into a ** single segment with a level equal to the numerically largest level ** currently present in the database. @@ -138760,11 +136802,10 @@ sqlite3_int64 iNewLevel = 0; /* Level/index to create new segment at */ SegmentWriter *pWriter = 0; /* Used to write the new, merged, segment */ Fts3SegFilter filter; /* Segment term filter condition */ Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */ int bIgnoreEmpty = 0; /* True to ignore empty segments */ - i64 iMaxLevel = 0; /* Max level number for this index/langid */ assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel==FTS3_SEGCURSOR_PENDING || iLevel>=0 ); @@ -138772,39 +136813,34 @@ assert( iIndex>=0 && iIndexnIndex ); rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr); if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished; - if( iLevel!=FTS3_SEGCURSOR_PENDING ){ - rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iMaxLevel); - if( rc!=SQLITE_OK ) goto finished; - } - if( iLevel==FTS3_SEGCURSOR_ALL ){ /* This call is to merge all segments in the database to a single ** segment. The level of the new segment is equal to the numerically ** greatest segment level currently present in the database for this ** index. The idx of the new segment is always 0. */ if( csr.nSegment==1 ){ rc = SQLITE_DONE; goto finished; } - iNewLevel = iMaxLevel; + rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iNewLevel); bIgnoreEmpty = 1; + }else if( iLevel==FTS3_SEGCURSOR_PENDING ){ + iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, 0); + rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, 0, &iIdx); }else{ /* This call is to merge all segments at level iLevel. find the next ** available segment index at level iLevel+1. The call to ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to ** a single iLevel+2 segment if necessary. */ - assert( FTS3_SEGCURSOR_PENDING==-1 ); + rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1); - rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); - bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel); } if( rc!=SQLITE_OK ) goto finished; - assert( csr.nSegment>0 ); assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); assert( iNewLevelnLeafData); - } - } - } + rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx); finished: fts3SegWriterFree(pWriter); sqlite3Fts3SegReaderFinish(&csr); return rc; } /* -** Flush the contents of pendingTerms to level 0 segments. +** Flush the contents of pendingTerms to level 0 segments. */ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ int rc = SQLITE_OK; int i; @@ -138858,23 +136887,18 @@ /* Determine the auto-incr-merge setting if unknown. If enabled, ** estimate the number of leaf blocks of content to be written */ if( rc==SQLITE_OK && p->bHasStat - && p->nAutoincrmerge==0xff && p->nLeafAdd>0 + && p->bAutoincrmerge==0xff && p->nLeafAdd>0 ){ sqlite3_stmt *pStmt = 0; rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); rc = sqlite3_step(pStmt); - if( rc==SQLITE_ROW ){ - p->nAutoincrmerge = sqlite3_column_int(pStmt, 0); - if( p->nAutoincrmerge==1 ) p->nAutoincrmerge = 8; - }else if( rc==SQLITE_DONE ){ - p->nAutoincrmerge = 0; - } + p->bAutoincrmerge = (rc==SQLITE_ROW && sqlite3_column_int(pStmt, 0)); rc = sqlite3_reset(pStmt); } } return rc; } @@ -139238,12 +137262,10 @@ int nWork; /* Number of leaf pages flushed */ sqlite3_int64 iAbsLevel; /* Absolute level of input segments */ int iIdx; /* Index of *output* segment in iAbsLevel+1 */ sqlite3_int64 iStart; /* Block number of first allocated block */ sqlite3_int64 iEnd; /* Block number of last allocated block */ - sqlite3_int64 nLeafData; /* Bytes of leaf page data so far */ - u8 bNoLeafData; /* If true, store 0 for segment size */ NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT]; }; /* ** An object of the following type is used to read data from a single @@ -139578,12 +137600,12 @@ nSpace = 1; nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; } - pWriter->nLeafData += nSpace; blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc); + if( rc==SQLITE_OK ){ if( pLeaf->block.n==0 ){ pLeaf->block.n = 1; pLeaf->block.a[0] = '\0'; } @@ -139678,11 +137700,10 @@ pWriter->iAbsLevel+1, /* level */ pWriter->iIdx, /* idx */ pWriter->iStart, /* start_block */ pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */ pWriter->iEnd, /* end_block */ - (pWriter->bNoLeafData==0 ? pWriter->nLeafData : 0), /* end_block */ pRoot->block.a, pRoot->block.n /* root */ ); } sqlite3_free(pRoot->block.a); sqlite3_free(pRoot->key.a); @@ -139780,15 +137801,11 @@ sqlite3_bind_int64(pSelect, 1, iAbsLevel+1); sqlite3_bind_int(pSelect, 2, iIdx); if( sqlite3_step(pSelect)==SQLITE_ROW ){ iStart = sqlite3_column_int64(pSelect, 1); iLeafEnd = sqlite3_column_int64(pSelect, 2); - fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); - if( pWriter->nLeafData<0 ){ - pWriter->nLeafData = pWriter->nLeafData * -1; - } - pWriter->bNoLeafData = (pWriter->nLeafData==0); + iEnd = sqlite3_column_int64(pSelect, 3); nRoot = sqlite3_column_bytes(pSelect, 4); aRoot = sqlite3_column_blob(pSelect, 4); }else{ return sqlite3_reset(pSelect); } @@ -140385,15 +138402,15 @@ /* ** Attempt an incremental merge that writes nMerge leaf blocks. ** -** Incremental merges happen nMin segments at a time. The segments -** to be merged are the nMin oldest segments (the ones with the smallest -** values for the _segdir.idx field) in the highest level that contains -** at least nMin segments. Multiple merges might occur in an attempt to -** write the quota of nMerge leaf blocks. +** Incremental merges happen nMin segments at a time. The two +** segments to be merged are the nMin oldest segments (the ones with +** the smallest indexes) in the highest level that contains at least +** nMin segments. Multiple merges might occur in an attempt to write the +** quota of nMerge leaf blocks. */ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ int rc; /* Return code */ int nRem = nMerge; /* Number of leaf pages yet to be written */ Fts3MultiSegReader *pCsr; /* Cursor used to read input data */ @@ -140414,11 +138431,10 @@ rc = fts3IncrmergeHintLoad(p, &hint); while( rc==SQLITE_OK && nRem>0 ){ const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex; sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */ int bUseHint = 0; /* True if attempting to append */ - int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ /* Search the %_segdir table for the absolute level with the smallest ** relative level number that contains at least nMin segments, if any. ** If one is found, set iAbsLevel to the absolute level number and ** nSeg to nMin. If no level with at least nMin segments can be found, @@ -140468,36 +138484,27 @@ ** segments available in level iAbsLevel. In this case, no work is ** done on iAbsLevel - fall through to the next iteration of the loop ** to start work on some other level. */ memset(pWriter, 0, nAlloc); pFilter->flags = FTS3_SEGMENT_REQUIRE_POS; - - if( rc==SQLITE_OK ){ - rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); - assert( bUseHint==1 || bUseHint==0 ); - if( iIdx==0 || (bUseHint && iIdx==1) ){ - int bIgnore = 0; - rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore); - if( bIgnore ){ - pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY; - } - } - } - if( rc==SQLITE_OK ){ rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); } if( SQLITE_OK==rc && pCsr->nSegment==nSeg && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr)) ){ - if( bUseHint && iIdx>0 ){ - const char *zKey = pCsr->zTerm; - int nKey = pCsr->nTerm; - rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); - }else{ - rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); + int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ + rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); + if( rc==SQLITE_OK ){ + if( bUseHint && iIdx>0 ){ + const char *zKey = pCsr->zTerm; + int nKey = pCsr->nTerm; + rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); + }else{ + rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); + } } if( rc==SQLITE_OK && pWriter->nLeafEst ){ fts3LogMerge(nSeg, iAbsLevel); do { @@ -140515,17 +138522,11 @@ fts3IncrmergeHintPush(&hint, iAbsLevel, nSeg, &rc); } } } - if( nSeg!=0 ){ - pWriter->nLeafData = pWriter->nLeafData * -1; - } fts3IncrmergeRelease(p, pWriter, &rc); - if( nSeg==0 && pWriter->bNoLeafData==0 ){ - fts3PromoteSegments(p, iAbsLevel+1, pWriter->nLeafData); - } } sqlite3Fts3SegReaderFinish(pCsr); } @@ -140608,23 +138609,20 @@ Fts3Table *p, /* FTS3 table handle */ const char *zParam /* Nul-terminated string containing boolean */ ){ int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; - p->nAutoincrmerge = fts3Getint(&zParam); - if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){ - p->nAutoincrmerge = 8; - } + p->bAutoincrmerge = fts3Getint(&zParam)!=0; if( !p->bHasStat ){ assert( p->bFts4==0 ); sqlite3Fts3CreateStatTable(&rc, p); if( rc ) return rc; } rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); if( rc ) return rc; sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); - sqlite3_bind_int(pStmt, 2, p->nAutoincrmerge); + sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); return rc; } @@ -141109,14 +139107,10 @@ u32 *aSzIns = 0; /* Sizes of inserted documents */ u32 *aSzDel = 0; /* Sizes of deleted documents */ int nChng = 0; /* Net change in number of documents */ int bInsertDone = 0; - /* At this point it must be known if the %_stat table exists or not. - ** So bHasStat may not be 2. */ - assert( p->bHasStat==0 || p->bHasStat==1 ); - assert( p->pSegments==0 ); assert( nArg==1 /* DELETE operations */ || nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */ ); @@ -143603,24 +141597,64 @@ ** child page. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE) +/* +** This file contains an implementation of a couple of different variants +** of the r-tree algorithm. See the README file for further details. The +** same data-structure is used for all, but the algorithms for insert and +** delete operations vary. The variants used are selected at compile time +** by defining the following symbols: +*/ + +/* Either, both or none of the following may be set to activate +** r*tree variant algorithms. +*/ +#define VARIANT_RSTARTREE_CHOOSESUBTREE 0 +#define VARIANT_RSTARTREE_REINSERT 1 + +/* +** Exactly one of the following must be set to 1. +*/ +#define VARIANT_GUTTMAN_QUADRATIC_SPLIT 0 +#define VARIANT_GUTTMAN_LINEAR_SPLIT 0 +#define VARIANT_RSTARTREE_SPLIT 1 + +#define VARIANT_GUTTMAN_SPLIT \ + (VARIANT_GUTTMAN_LINEAR_SPLIT||VARIANT_GUTTMAN_QUADRATIC_SPLIT) + +#if VARIANT_GUTTMAN_QUADRATIC_SPLIT + #define PickNext QuadraticPickNext + #define PickSeeds QuadraticPickSeeds + #define AssignCells splitNodeGuttman +#endif +#if VARIANT_GUTTMAN_LINEAR_SPLIT + #define PickNext LinearPickNext + #define PickSeeds LinearPickSeeds + #define AssignCells splitNodeGuttman +#endif +#if VARIANT_RSTARTREE_SPLIT + #define AssignCells splitNodeStartree +#endif + +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif + #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT1 #else #endif /* #include */ /* #include */ -/* #include */ #ifndef SQLITE_AMALGAMATION #include "sqlite3rtree.h" typedef sqlite3_int64 i64; typedef unsigned char u8; -typedef unsigned short u16; typedef unsigned int u32; #endif /* The following macro is used to suppress compiler warnings. */ @@ -143634,20 +141668,19 @@ typedef struct RtreeCell RtreeCell; typedef struct RtreeConstraint RtreeConstraint; typedef struct RtreeMatchArg RtreeMatchArg; typedef struct RtreeGeomCallback RtreeGeomCallback; typedef union RtreeCoord RtreeCoord; -typedef struct RtreeSearchPoint RtreeSearchPoint; /* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ #define RTREE_MAX_DIMENSIONS 5 /* Size of hash table Rtree.aHash. This hash table is not expected to ** ever contain very many entries, so a fixed number of buckets is ** used. */ -#define HASHSIZE 97 +#define HASHSIZE 128 /* The xBestIndex method of this virtual table requires an estimate of ** the number of rows in the virtual table to calculate the costs of ** various strategies. If possible, this estimate is loaded from the ** sqlite_stat1 table (with RTREE_MIN_ROWEST as a hard-coded minimum). @@ -143659,19 +141692,19 @@ /* ** An rtree virtual-table object. */ struct Rtree { - sqlite3_vtab base; /* Base class. Must be first */ + sqlite3_vtab base; sqlite3 *db; /* Host database connection */ int iNodeSize; /* Size in bytes of each node in the node table */ - u8 nDim; /* Number of dimensions */ - u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ - u8 nBytesPerCell; /* Bytes consumed per cell */ + int nDim; /* Number of dimensions */ + int nBytesPerCell; /* Bytes consumed per cell */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ + RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ int nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ /* List of nodes removed during a CondenseTree operation. List is ** linked together via the pointer normally used for hash chains - @@ -143694,14 +141727,14 @@ /* Statements to read/write/delete a record from xxx_parent */ sqlite3_stmt *pReadParent; sqlite3_stmt *pWriteParent; sqlite3_stmt *pDeleteParent; - RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ + int eCoordType; }; -/* Possible values for Rtree.eCoordType: */ +/* Possible values for eCoordType: */ #define RTREE_COORD_REAL32 0 #define RTREE_COORD_INT32 1 /* ** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will @@ -143709,34 +141742,15 @@ ** will be done. */ #ifdef SQLITE_RTREE_INT_ONLY typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */ typedef int RtreeValue; /* Low accuracy coordinate */ -# define RTREE_ZERO 0 #else typedef double RtreeDValue; /* High accuracy coordinate */ typedef float RtreeValue; /* Low accuracy coordinate */ -# define RTREE_ZERO 0.0 #endif -/* -** When doing a search of an r-tree, instances of the following structure -** record intermediate results from the tree walk. -** -** The id is always a node-id. For iLevel>=1 the id is the node-id of -** the node that the RtreeSearchPoint represents. When iLevel==0, however, -** the id is of the parent node and the cell that RtreeSearchPoint -** represents is the iCell-th entry in the parent node. -*/ -struct RtreeSearchPoint { - RtreeDValue rScore; /* The score for this node. Smallest goes first. */ - sqlite3_int64 id; /* Node ID */ - u8 iLevel; /* 0=entries. 1=leaf node. 2+ for higher */ - u8 eWithin; /* PARTLY_WITHIN or FULLY_WITHIN */ - u8 iCell; /* Cell index within the node */ -}; - /* ** The minimum number of cells allowed for a node is a third of the ** maximum. In Gutman's notation: ** ** m = M/3 @@ -143755,48 +141769,25 @@ ** 2^40 is greater than 2^64, an r-tree structure always has a depth of ** 40 or less. */ #define RTREE_MAX_DEPTH 40 - -/* -** Number of entries in the cursor RtreeNode cache. The first entry is -** used to cache the RtreeNode for RtreeCursor.sPoint. The remaining -** entries cache the RtreeNode for the first elements of the priority queue. -*/ -#define RTREE_CACHE_SZ 5 - /* ** An rtree cursor object. */ struct RtreeCursor { - sqlite3_vtab_cursor base; /* Base class. Must be first */ - u8 atEOF; /* True if at end of search */ - u8 bPoint; /* True if sPoint is valid */ + sqlite3_vtab_cursor base; + RtreeNode *pNode; /* Node cursor is currently pointing at */ + int iCell; /* Index of current cell in pNode */ int iStrategy; /* Copy of idxNum search parameter */ int nConstraint; /* Number of entries in aConstraint */ RtreeConstraint *aConstraint; /* Search constraints. */ - int nPointAlloc; /* Number of slots allocated for aPoint[] */ - int nPoint; /* Number of slots used in aPoint[] */ - int mxLevel; /* iLevel value for root of the tree */ - RtreeSearchPoint *aPoint; /* Priority queue for search points */ - RtreeSearchPoint sPoint; /* Cached next search point */ - RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ - u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ }; -/* Return the Rtree of a RtreeCursor */ -#define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) - -/* -** A coordinate can be either a floating point number or a integer. All -** coordinates within a single R-Tree are always of the same time. -*/ union RtreeCoord { - RtreeValue f; /* Floating point value */ - int i; /* Integer value */ - u32 u; /* Unsigned for byte-order conversions */ + RtreeValue f; + int i; }; /* ** The argument is an RtreeCoord. Return the value stored within the RtreeCoord ** formatted as a RtreeDValue (double or int64). This macro assumes that local @@ -143817,71 +141808,42 @@ ** A search constraint. */ struct RtreeConstraint { int iCoord; /* Index of constrained coordinate */ int op; /* Constraining operation */ - union { - RtreeDValue rValue; /* Constraint value. */ - int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*); - int (*xQueryFunc)(sqlite3_rtree_query_info*); - } u; - sqlite3_rtree_query_info *pInfo; /* xGeom and xQueryFunc argument */ + RtreeDValue rValue; /* Constraint value. */ + int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); + sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */ }; /* Possible values for RtreeConstraint.op */ -#define RTREE_EQ 0x41 /* A */ -#define RTREE_LE 0x42 /* B */ -#define RTREE_LT 0x43 /* C */ -#define RTREE_GE 0x44 /* D */ -#define RTREE_GT 0x45 /* E */ -#define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ -#define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ - +#define RTREE_EQ 0x41 +#define RTREE_LE 0x42 +#define RTREE_LT 0x43 +#define RTREE_GE 0x44 +#define RTREE_GT 0x45 +#define RTREE_MATCH 0x46 /* ** An rtree structure node. */ struct RtreeNode { - RtreeNode *pParent; /* Parent node */ - i64 iNode; /* The node number */ - int nRef; /* Number of references to this node */ - int isDirty; /* True if the node needs to be written to disk */ - u8 *zData; /* Content of the node, as should be on disk */ - RtreeNode *pNext; /* Next node in this hash collision chain */ + RtreeNode *pParent; /* Parent node */ + i64 iNode; + int nRef; + int isDirty; + u8 *zData; + RtreeNode *pNext; /* Next node in this hash chain */ }; - -/* Return the number of cells in a node */ #define NCELL(pNode) readInt16(&(pNode)->zData[2]) /* -** A single cell from a node, deserialized +** Structure to store a deserialized rtree record. */ struct RtreeCell { - i64 iRowid; /* Node or entry ID */ - RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; /* Bounding box coordinates */ -}; - - -/* -** This object becomes the sqlite3_user_data() for the SQL functions -** that are created by sqlite3_rtree_geometry_callback() and -** sqlite3_rtree_query_callback() and which appear on the right of MATCH -** operators in order to constrain a search. -** -** xGeom and xQueryFunc are the callback functions. Exactly one of -** xGeom and xQueryFunc fields is non-NULL, depending on whether the -** SQL function was created using sqlite3_rtree_geometry_callback() or -** sqlite3_rtree_query_callback(). -** -** This object is deleted automatically by the destructor mechanism in -** sqlite3_create_function_v2(). -*/ -struct RtreeGeomCallback { - int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); - int (*xQueryFunc)(sqlite3_rtree_query_info*); - void (*xDestructor)(void*); - void *pContext; + i64 iRowid; + RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; }; /* ** Value for the first field of every RtreeMatchArg object. The MATCH @@ -143889,20 +141851,33 @@ ** value to avoid operating on invalid blobs (which could cause a segfault). */ #define RTREE_GEOMETRY_MAGIC 0x891245AB /* -** An instance of this structure (in the form of a BLOB) is returned by -** the SQL functions that sqlite3_rtree_geometry_callback() and -** sqlite3_rtree_query_callback() create, and is read as the right-hand -** operand to the MATCH operator of an R-Tree. +** An instance of this structure must be supplied as a blob argument to +** the right-hand-side of an SQL MATCH operator used to constrain an +** r-tree query. */ struct RtreeMatchArg { - u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ - RtreeGeomCallback cb; /* Info about the callback functions */ - int nParam; /* Number of parameters to the SQL function */ - RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ + u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ + int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *); + void *pContext; + int nParam; + RtreeDValue aParam[1]; +}; + +/* +** When a geometry callback is created (see sqlite3_rtree_geometry_callback), +** a single instance of the following structure is allocated. It is used +** as the context for the user-function created by by s_r_g_c(). The object +** is eventually deleted by the destructor mechanism provided by +** sqlite3_create_function_v2() (which is called by s_r_g_c() to create +** the geometry callback function). +*/ +struct RtreeGeomCallback { + int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); + void *pContext; }; #ifndef MAX # define MAX(x,y) ((x) < (y) ? (y) : (x)) #endif @@ -143992,11 +141967,14 @@ /* ** Given a node number iNode, return the corresponding key to use ** in the Rtree.aHash table. */ static int nodeHash(i64 iNode){ - return iNode % HASHSIZE; + return ( + (iNode>>56) ^ (iNode>>48) ^ (iNode>>40) ^ (iNode>>32) ^ + (iNode>>24) ^ (iNode>>16) ^ (iNode>> 8) ^ (iNode>> 0) + ) % HASHSIZE; } /* ** Search the node hash table for node iNode. If found, return a pointer ** to it. Otherwise, return 0. @@ -144052,11 +142030,12 @@ } /* ** Obtain a reference to an r-tree node. */ -static int nodeAcquire( +static int +nodeAcquire( Rtree *pRtree, /* R-tree structure */ i64 iNode, /* Node number to load */ RtreeNode *pParent, /* Either the parent node or NULL */ RtreeNode **ppNode /* OUT: Acquired node */ ){ @@ -144141,14 +142120,14 @@ /* ** Overwrite cell iCell of node pNode with the contents of pCell. */ static void nodeOverwriteCell( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* The node into which the cell is to be written */ - RtreeCell *pCell, /* The cell to write */ - int iCell /* Index into pNode into which pCell is written */ + Rtree *pRtree, + RtreeNode *pNode, + RtreeCell *pCell, + int iCell ){ int ii; u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; p += writeInt64(p, pCell->iRowid); for(ii=0; ii<(pRtree->nDim*2); ii++){ @@ -144156,11 +142135,11 @@ } pNode->isDirty = 1; } /* -** Remove the cell with index iCell from node pNode. +** Remove cell the cell with index iCell from node pNode. */ static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; u8 *pSrc = &pDst[pRtree->nBytesPerCell]; int nByte = (NCELL(pNode) - iCell - 1) * pRtree->nBytesPerCell; @@ -144173,14 +142152,15 @@ ** Insert the contents of cell pCell into node pNode. If the insert ** is successful, return SQLITE_OK. ** ** If there is not enough free space in pNode, return SQLITE_FULL. */ -static int nodeInsertCell( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* Write new cell into this node */ - RtreeCell *pCell /* The cell to be inserted */ +static int +nodeInsertCell( + Rtree *pRtree, + RtreeNode *pNode, + RtreeCell *pCell ){ int nCell; /* Current number of cells in pNode */ int nMaxCell; /* Maximum number of cells for pNode */ nMaxCell = (pRtree->iNodeSize-4)/pRtree->nBytesPerCell; @@ -144197,11 +142177,12 @@ } /* ** If the node is dirty, write it out to the database. */ -static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){ +static int +nodeWrite(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode->isDirty ){ sqlite3_stmt *p = pRtree->pWriteNode; if( pNode->iNode ){ sqlite3_bind_int64(p, 1, pNode->iNode); @@ -144222,11 +142203,12 @@ /* ** Release a reference to a node. If the node is dirty and the reference ** count drops to zero, the node data is written to the database. */ -static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ +static int +nodeRelease(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode ){ assert( pNode->nRef>0 ); pNode->nRef--; if( pNode->nRef==0 ){ @@ -144250,50 +142232,45 @@ ** Return the 64-bit integer value associated with cell iCell of ** node pNode. If pNode is a leaf node, this is a rowid. If it is ** an internal node, then the 64-bit integer is a child page number. */ static i64 nodeGetRowid( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* The node from which to extract the ID */ - int iCell /* The cell index from which to extract the ID */ + Rtree *pRtree, + RtreeNode *pNode, + int iCell ){ assert( iCellzData[4 + pRtree->nBytesPerCell*iCell]); } /* ** Return coordinate iCoord from cell iCell in node pNode. */ static void nodeGetCoord( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* The node from which to extract a coordinate */ - int iCell, /* The index of the cell within the node */ - int iCoord, /* Which coordinate to extract */ - RtreeCoord *pCoord /* OUT: Space to write result to */ + Rtree *pRtree, + RtreeNode *pNode, + int iCell, + int iCoord, + RtreeCoord *pCoord /* Space to write result to */ ){ readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); } /* ** Deserialize cell iCell of node pNode. Populate the structure pointed ** to by pCell with the results. */ static void nodeGetCell( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* The node containing the cell to be read */ - int iCell, /* Index of the cell within the node */ - RtreeCell *pCell /* OUT: Write the cell contents here */ + Rtree *pRtree, + RtreeNode *pNode, + int iCell, + RtreeCell *pCell ){ - u8 *pData; - u8 *pEnd; - RtreeCoord *pCoord; + int ii; pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); - pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); - pEnd = pData + pRtree->nDim*8; - pCoord = pCell->aCoord; - for(; pDatanDim*2; ii++){ + nodeGetCoord(pRtree, pNode, iCell, ii, &pCell->aCoord[ii]); } } /* Forward declaration for the function that does the work of @@ -144415,14 +142392,14 @@ */ static void freeCursorConstraints(RtreeCursor *pCsr){ if( pCsr->aConstraint ){ int i; /* Used to iterate through constraint array */ for(i=0; inConstraint; i++){ - sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo; - if( pInfo ){ - if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser); - sqlite3_free(pInfo); + sqlite3_rtree_geometry *pGeom = pCsr->aConstraint[i].pGeom; + if( pGeom ){ + if( pGeom->xDelUser ) pGeom->xDelUser(pGeom->pUser); + sqlite3_free(pGeom); } } sqlite3_free(pCsr->aConstraint); pCsr->aConstraint = 0; } @@ -144431,17 +142408,16 @@ /* ** Rtree virtual table module xClose method. */ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); - int ii; + int rc; RtreeCursor *pCsr = (RtreeCursor *)cur; freeCursorConstraints(pCsr); - sqlite3_free(pCsr->aPoint); - for(ii=0; iiaNode[ii]); + rc = nodeRelease(pRtree, pCsr->pNode); sqlite3_free(pCsr); - return SQLITE_OK; + return rc; } /* ** Rtree virtual table module xEof method. ** @@ -144448,168 +142424,198 @@ ** Return non-zero if the cursor does not currently point to a valid ** record (i.e if the scan has finished), or zero otherwise. */ static int rtreeEof(sqlite3_vtab_cursor *cur){ RtreeCursor *pCsr = (RtreeCursor *)cur; - return pCsr->atEOF; -} - -/* -** Convert raw bits from the on-disk RTree record into a coordinate value. -** The on-disk format is big-endian and needs to be converted for little- -** endian platforms. The on-disk record stores integer coordinates if -** eInt is true and it stores 32-bit floating point records if eInt is -** false. a[] is the four bytes of the on-disk record to be decoded. -** Store the results in "r". -** -** There are three versions of this macro, one each for little-endian and -** big-endian processors and a third generic implementation. The endian- -** specific implementations are much faster and are preferred if the -** processor endianness is known at compile-time. The SQLITE_BYTEORDER -** macro is part of sqliteInt.h and hence the endian-specific -** implementation will only be used if this module is compiled as part -** of the amalgamation. -*/ -#if defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==1234 -#define RTREE_DECODE_COORD(eInt, a, r) { \ - RtreeCoord c; /* Coordinate decoded */ \ - memcpy(&c.u,a,4); \ - c.u = ((c.u>>24)&0xff)|((c.u>>8)&0xff00)| \ - ((c.u&0xff)<<24)|((c.u&0xff00)<<8); \ - r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ -} -#elif defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==4321 -#define RTREE_DECODE_COORD(eInt, a, r) { \ - RtreeCoord c; /* Coordinate decoded */ \ - memcpy(&c.u,a,4); \ - r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ -} -#else -#define RTREE_DECODE_COORD(eInt, a, r) { \ - RtreeCoord c; /* Coordinate decoded */ \ - c.u = ((u32)a[0]<<24) + ((u32)a[1]<<16) \ - +((u32)a[2]<<8) + a[3]; \ - r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ -} -#endif - -/* -** Check the RTree node or entry given by pCellData and p against the MATCH -** constraint pConstraint. -*/ -static int rtreeCallbackConstraint( - RtreeConstraint *pConstraint, /* The constraint to test */ - int eInt, /* True if RTree holding integer coordinates */ - u8 *pCellData, /* Raw cell content */ - RtreeSearchPoint *pSearch, /* Container of this cell */ - sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */ - int *peWithin /* OUT: visibility of the cell */ -){ - int i; /* Loop counter */ - sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */ - int nCoord = pInfo->nCoord; /* No. of coordinates */ - int rc; /* Callback return code */ - sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */ - - assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY ); - assert( nCoord==2 || nCoord==4 || nCoord==6 || nCoord==8 || nCoord==10 ); - - if( pConstraint->op==RTREE_QUERY && pSearch->iLevel==1 ){ - pInfo->iRowid = readInt64(pCellData); - } - pCellData += 8; - for(i=0; iop==RTREE_MATCH ){ - rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo, - nCoord, aCoord, &i); - if( i==0 ) *peWithin = NOT_WITHIN; - *prScore = RTREE_ZERO; - }else{ - pInfo->aCoord = aCoord; - pInfo->iLevel = pSearch->iLevel - 1; - pInfo->rScore = pInfo->rParentScore = pSearch->rScore; - pInfo->eWithin = pInfo->eParentWithin = pSearch->eWithin; - rc = pConstraint->u.xQueryFunc(pInfo); - if( pInfo->eWithin<*peWithin ) *peWithin = pInfo->eWithin; - if( pInfo->rScore<*prScore || *prScorerScore; - } - } + return (pCsr->pNode==0); +} + +/* +** The r-tree constraint passed as the second argument to this function is +** guaranteed to be a MATCH constraint. +*/ +static int testRtreeGeom( + Rtree *pRtree, /* R-Tree object */ + RtreeConstraint *pConstraint, /* MATCH constraint to test */ + RtreeCell *pCell, /* Cell to test */ + int *pbRes /* OUT: Test result */ +){ + int i; + RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2]; + int nCoord = pRtree->nDim*2; + + assert( pConstraint->op==RTREE_MATCH ); + assert( pConstraint->pGeom ); + + for(i=0; iaCoord[i]); + } + return pConstraint->xGeom(pConstraint->pGeom, nCoord, aCoord, pbRes); +} + +/* +** Cursor pCursor currently points to a cell in a non-leaf page. +** Set *pbEof to true if the sub-tree headed by the cell is filtered +** (excluded) by the constraints in the pCursor->aConstraint[] +** array, or false otherwise. +** +** Return SQLITE_OK if successful or an SQLite error code if an error +** occurs within a geometry callback. +*/ +static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){ + RtreeCell cell; + int ii; + int bRes = 0; + int rc = SQLITE_OK; + + nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); + for(ii=0; bRes==0 && iinConstraint; ii++){ + RtreeConstraint *p = &pCursor->aConstraint[ii]; + RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]); + RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]); + + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH + ); + + switch( p->op ){ + case RTREE_LE: case RTREE_LT: + bRes = p->rValuerValue>cell_max; + break; + + case RTREE_EQ: + bRes = (p->rValue>cell_max || p->rValueop==RTREE_MATCH ); + rc = testRtreeGeom(pRtree, p, &cell, &bRes); + bRes = !bRes; + break; + } + } + } + + *pbEof = bRes; return rc; } /* -** Check the internal RTree node given by pCellData against constraint p. -** If this constraint cannot be satisfied by any child within the node, -** set *peWithin to NOT_WITHIN. -*/ -static void rtreeNonleafConstraint( - RtreeConstraint *p, /* The constraint to test */ - int eInt, /* True if RTree holds integer coordinates */ - u8 *pCellData, /* Raw cell content as appears on disk */ - int *peWithin /* Adjust downward, as appropriate */ -){ - sqlite3_rtree_dbl val; /* Coordinate value convert to a double */ - - /* p->iCoord might point to either a lower or upper bound coordinate - ** in a coordinate pair. But make pCellData point to the lower bound. - */ - pCellData += 8 + 4*(p->iCoord&0xfe); - - assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE - || p->op==RTREE_GT || p->op==RTREE_EQ ); - switch( p->op ){ - case RTREE_LE: - case RTREE_LT: - case RTREE_EQ: - RTREE_DECODE_COORD(eInt, pCellData, val); - /* val now holds the lower bound of the coordinate pair */ - if( p->u.rValue>=val ) return; - if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */ - /* Fall through for the RTREE_EQ case */ - - default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */ - pCellData += 4; - RTREE_DECODE_COORD(eInt, pCellData, val); - /* val now holds the upper bound of the coordinate pair */ - if( p->u.rValue<=val ) return; - } - *peWithin = NOT_WITHIN; +** Test if the cell that cursor pCursor currently points to +** would be filtered (excluded) by the constraints in the +** pCursor->aConstraint[] array. If so, set *pbEof to true before +** returning. If the cell is not filtered (excluded) by the constraints, +** set pbEof to zero. +** +** Return SQLITE_OK if successful or an SQLite error code if an error +** occurs within a geometry callback. +** +** This function assumes that the cell is part of a leaf node. +*/ +static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){ + RtreeCell cell; + int ii; + *pbEof = 0; + + nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); + for(ii=0; iinConstraint; ii++){ + RtreeConstraint *p = &pCursor->aConstraint[ii]; + RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]); + int res; + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH + ); + switch( p->op ){ + case RTREE_LE: res = (coord<=p->rValue); break; + case RTREE_LT: res = (coordrValue); break; + case RTREE_GE: res = (coord>=p->rValue); break; + case RTREE_GT: res = (coord>p->rValue); break; + case RTREE_EQ: res = (coord==p->rValue); break; + default: { + int rc; + assert( p->op==RTREE_MATCH ); + rc = testRtreeGeom(pRtree, p, &cell, &res); + if( rc!=SQLITE_OK ){ + return rc; + } + break; + } + } + + if( !res ){ + *pbEof = 1; + return SQLITE_OK; + } + } + + return SQLITE_OK; } /* -** Check the leaf RTree cell given by pCellData against constraint p. -** If this constraint is not satisfied, set *peWithin to NOT_WITHIN. -** If the constraint is satisfied, leave *peWithin unchanged. -** -** The constraint is of the form: xN op $val -** -** The op is given by p->op. The xN is p->iCoord-th coordinate in -** pCellData. $val is given by p->u.rValue. +** Cursor pCursor currently points at a node that heads a sub-tree of +** height iHeight (if iHeight==0, then the node is a leaf). Descend +** to point to the left-most cell of the sub-tree that matches the +** configured constraints. */ -static void rtreeLeafConstraint( - RtreeConstraint *p, /* The constraint to test */ - int eInt, /* True if RTree holds integer coordinates */ - u8 *pCellData, /* Raw cell content as appears on disk */ - int *peWithin /* Adjust downward, as appropriate */ +static int descendToCell( + Rtree *pRtree, + RtreeCursor *pCursor, + int iHeight, + int *pEof /* OUT: Set to true if cannot descend */ ){ - RtreeDValue xN; /* Coordinate value converted to a double */ - - assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE - || p->op==RTREE_GT || p->op==RTREE_EQ ); - pCellData += 8 + p->iCoord*4; - RTREE_DECODE_COORD(eInt, pCellData, xN); - switch( p->op ){ - case RTREE_LE: if( xN <= p->u.rValue ) return; break; - case RTREE_LT: if( xN < p->u.rValue ) return; break; - case RTREE_GE: if( xN >= p->u.rValue ) return; break; - case RTREE_GT: if( xN > p->u.rValue ) return; break; - default: if( xN == p->u.rValue ) return; break; - } - *peWithin = NOT_WITHIN; + int isEof; + int rc; + int ii; + RtreeNode *pChild; + sqlite3_int64 iRowid; + + RtreeNode *pSavedNode = pCursor->pNode; + int iSavedCell = pCursor->iCell; + + assert( iHeight>=0 ); + + if( iHeight==0 ){ + rc = testRtreeEntry(pRtree, pCursor, &isEof); + }else{ + rc = testRtreeCell(pRtree, pCursor, &isEof); + } + if( rc!=SQLITE_OK || isEof || iHeight==0 ){ + goto descend_to_cell_out; + } + + iRowid = nodeGetRowid(pRtree, pCursor->pNode, pCursor->iCell); + rc = nodeAcquire(pRtree, iRowid, pCursor->pNode, &pChild); + if( rc!=SQLITE_OK ){ + goto descend_to_cell_out; + } + + nodeRelease(pRtree, pCursor->pNode); + pCursor->pNode = pChild; + isEof = 1; + for(ii=0; isEof && iiiCell = ii; + rc = descendToCell(pRtree, pCursor, iHeight-1, &isEof); + if( rc!=SQLITE_OK ){ + goto descend_to_cell_out; + } + } + + if( isEof ){ + assert( pCursor->pNode==pChild ); + nodeReference(pSavedNode); + nodeRelease(pRtree, pChild); + pCursor->pNode = pSavedNode; + pCursor->iCell = iSavedCell; + } + +descend_to_cell_out: + *pEof = isEof; + return rc; } /* ** One of the cells in node pNode is guaranteed to have a 64-bit ** integer value equal to iRowid. Return the index of this cell. @@ -144620,11 +142626,10 @@ i64 iRowid, int *piIndex ){ int ii; int nCell = NCELL(pNode); - assert( nCell<200 ); for(ii=0; iirScorerScore ) return -1; - if( pA->rScore>pB->rScore ) return +1; - if( pA->iLeveliLevel ) return -1; - if( pA->iLevel>pB->iLevel ) return +1; - return 0; -} - -/* -** Interchange to search points in a cursor. -*/ -static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){ - RtreeSearchPoint t = p->aPoint[i]; - assert( iaPoint[i] = p->aPoint[j]; - p->aPoint[j] = t; - i++; j++; - if( i=RTREE_CACHE_SZ ){ - nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); - p->aNode[i] = 0; - }else{ - RtreeNode *pTemp = p->aNode[i]; - p->aNode[i] = p->aNode[j]; - p->aNode[j] = pTemp; - } - } -} - -/* -** Return the search point with the lowest current score. -*/ -static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){ - return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0; -} - -/* -** Get the RtreeNode for the search point with the lowest score. -*/ -static RtreeNode *rtreeNodeOfFirstSearchPoint(RtreeCursor *pCur, int *pRC){ - sqlite3_int64 id; - int ii = 1 - pCur->bPoint; - assert( ii==0 || ii==1 ); - assert( pCur->bPoint || pCur->nPoint ); - if( pCur->aNode[ii]==0 ){ - assert( pRC!=0 ); - id = ii ? pCur->aPoint[0].id : pCur->sPoint.id; - *pRC = nodeAcquire(RTREE_OF_CURSOR(pCur), id, 0, &pCur->aNode[ii]); - } - return pCur->aNode[ii]; -} - -/* -** Push a new element onto the priority queue -*/ -static RtreeSearchPoint *rtreeEnqueue( - RtreeCursor *pCur, /* The cursor */ - RtreeDValue rScore, /* Score for the new search point */ - u8 iLevel /* Level for the new search point */ -){ - int i, j; - RtreeSearchPoint *pNew; - if( pCur->nPoint>=pCur->nPointAlloc ){ - int nNew = pCur->nPointAlloc*2 + 8; - pNew = sqlite3_realloc(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); - if( pNew==0 ) return 0; - pCur->aPoint = pNew; - pCur->nPointAlloc = nNew; - } - i = pCur->nPoint++; - pNew = pCur->aPoint + i; - pNew->rScore = rScore; - pNew->iLevel = iLevel; - assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH ); - while( i>0 ){ - RtreeSearchPoint *pParent; - j = (i-1)/2; - pParent = pCur->aPoint + j; - if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break; - rtreeSearchPointSwap(pCur, j, i); - i = j; - pNew = pParent; - } - return pNew; -} - -/* -** Allocate a new RtreeSearchPoint and return a pointer to it. Return -** NULL if malloc fails. -*/ -static RtreeSearchPoint *rtreeSearchPointNew( - RtreeCursor *pCur, /* The cursor */ - RtreeDValue rScore, /* Score for the new search point */ - u8 iLevel /* Level for the new search point */ -){ - RtreeSearchPoint *pNew, *pFirst; - pFirst = rtreeSearchPointFirst(pCur); - pCur->anQueue[iLevel]++; - if( pFirst==0 - || pFirst->rScore>rScore - || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) - ){ - if( pCur->bPoint ){ - int ii; - pNew = rtreeEnqueue(pCur, rScore, iLevel); - if( pNew==0 ) return 0; - ii = (int)(pNew - pCur->aPoint) + 1; - if( iiaNode[ii]==0 ); - pCur->aNode[ii] = pCur->aNode[0]; - }else{ - nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); - } - pCur->aNode[0] = 0; - *pNew = pCur->sPoint; - } - pCur->sPoint.rScore = rScore; - pCur->sPoint.iLevel = iLevel; - pCur->bPoint = 1; - return &pCur->sPoint; - }else{ - return rtreeEnqueue(pCur, rScore, iLevel); - } -} - -#if 0 -/* Tracing routines for the RtreeSearchPoint queue */ -static void tracePoint(RtreeSearchPoint *p, int idx, RtreeCursor *pCur){ - if( idx<0 ){ printf(" s"); }else{ printf("%2d", idx); } - printf(" %d.%05lld.%02d %g %d", - p->iLevel, p->id, p->iCell, p->rScore, p->eWithin - ); - idx++; - if( idxaNode[idx]); - }else{ - printf("\n"); - } -} -static void traceQueue(RtreeCursor *pCur, const char *zPrefix){ - int ii; - printf("=== %9s ", zPrefix); - if( pCur->bPoint ){ - tracePoint(&pCur->sPoint, -1, pCur); - } - for(ii=0; iinPoint; ii++){ - if( ii>0 || pCur->bPoint ) printf(" "); - tracePoint(&pCur->aPoint[ii], ii, pCur); - } -} -# define RTREE_QUEUE_TRACE(A,B) traceQueue(A,B) -#else -# define RTREE_QUEUE_TRACE(A,B) /* no-op */ -#endif - -/* Remove the search point with the lowest current score. -*/ -static void rtreeSearchPointPop(RtreeCursor *p){ - int i, j, k, n; - i = 1 - p->bPoint; - assert( i==0 || i==1 ); - if( p->aNode[i] ){ - nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); - p->aNode[i] = 0; - } - if( p->bPoint ){ - p->anQueue[p->sPoint.iLevel]--; - p->bPoint = 0; - }else if( p->nPoint ){ - p->anQueue[p->aPoint[0].iLevel]--; - n = --p->nPoint; - p->aPoint[0] = p->aPoint[n]; - if( naNode[1] = p->aNode[n+1]; - p->aNode[n+1] = 0; - } - i = 0; - while( (j = i*2+1)aPoint[k], &p->aPoint[j])<0 ){ - if( rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[i])<0 ){ - rtreeSearchPointSwap(p, i, k); - i = k; - }else{ - break; - } - }else{ - if( rtreeSearchPointCompare(&p->aPoint[j], &p->aPoint[i])<0 ){ - rtreeSearchPointSwap(p, i, j); - i = j; - }else{ - break; - } - } - } - } -} - - -/* -** Continue the search on cursor pCur until the front of the queue -** contains an entry suitable for returning as a result-set row, -** or until the RtreeSearchPoint queue is empty, indicating that the -** query has completed. -*/ -static int rtreeStepToLeaf(RtreeCursor *pCur){ - RtreeSearchPoint *p; - Rtree *pRtree = RTREE_OF_CURSOR(pCur); - RtreeNode *pNode; - int eWithin; - int rc = SQLITE_OK; - int nCell; - int nConstraint = pCur->nConstraint; - int ii; - int eInt; - RtreeSearchPoint x; - - eInt = pRtree->eCoordType==RTREE_COORD_INT32; - while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ - pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); - if( rc ) return rc; - nCell = NCELL(pNode); - assert( nCell<200 ); - while( p->iCellzData + (4+pRtree->nBytesPerCell*p->iCell); - eWithin = FULLY_WITHIN; - for(ii=0; iiaConstraint + ii; - if( pConstraint->op>=RTREE_MATCH ){ - rc = rtreeCallbackConstraint(pConstraint, eInt, pCellData, p, - &rScore, &eWithin); - if( rc ) return rc; - }else if( p->iLevel==1 ){ - rtreeLeafConstraint(pConstraint, eInt, pCellData, &eWithin); - }else{ - rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin); - } - if( eWithin==NOT_WITHIN ) break; - } - p->iCell++; - if( eWithin==NOT_WITHIN ) continue; - x.iLevel = p->iLevel - 1; - if( x.iLevel ){ - x.id = readInt64(pCellData); - x.iCell = 0; - }else{ - x.id = p->id; - x.iCell = p->iCell - 1; - } - if( p->iCell>=nCell ){ - RTREE_QUEUE_TRACE(pCur, "POP-S:"); - rtreeSearchPointPop(pCur); - } - if( rScoreeWithin = eWithin; - p->id = x.id; - p->iCell = x.iCell; - RTREE_QUEUE_TRACE(pCur, "PUSH-S:"); - break; - } - if( p->iCell>=nCell ){ - RTREE_QUEUE_TRACE(pCur, "POP-Se:"); - rtreeSearchPointPop(pCur); - } - } - pCur->atEOF = p==0; - return SQLITE_OK; -} - /* ** Rtree virtual table module xNext method. */ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ + Rtree *pRtree = (Rtree *)(pVtabCursor->pVtab); RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; int rc = SQLITE_OK; - /* Move to the next entry that matches the configured constraints. */ - RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); - rtreeSearchPointPop(pCsr); - rc = rtreeStepToLeaf(pCsr); + /* RtreeCursor.pNode must not be NULL. If is is NULL, then this cursor is + ** already at EOF. It is against the rules to call the xNext() method of + ** a cursor that has already reached EOF. + */ + assert( pCsr->pNode ); + + if( pCsr->iStrategy==1 ){ + /* This "scan" is a direct lookup by rowid. There is no next entry. */ + nodeRelease(pRtree, pCsr->pNode); + pCsr->pNode = 0; + }else{ + /* Move to the next entry that matches the configured constraints. */ + int iHeight = 0; + while( pCsr->pNode ){ + RtreeNode *pNode = pCsr->pNode; + int nCell = NCELL(pNode); + for(pCsr->iCell++; pCsr->iCelliCell++){ + int isEof; + rc = descendToCell(pRtree, pCsr, iHeight, &isEof); + if( rc!=SQLITE_OK || !isEof ){ + return rc; + } + } + pCsr->pNode = pNode->pParent; + rc = nodeParentIndex(pRtree, pNode, &pCsr->iCell); + if( rc!=SQLITE_OK ){ + return rc; + } + nodeReference(pCsr->pNode); + nodeRelease(pRtree, pNode); + iHeight++; + } + } + return rc; } /* ** Rtree virtual table module xRowid method. */ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ + Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; - RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); - int rc = SQLITE_OK; - RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); - if( rc==SQLITE_OK && p ){ - *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); - } - return rc; + + assert(pCsr->pNode); + *pRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell); + + return SQLITE_OK; } /* ** Rtree virtual table module xColumn method. */ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ Rtree *pRtree = (Rtree *)cur->pVtab; RtreeCursor *pCsr = (RtreeCursor *)cur; - RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); - RtreeCoord c; - int rc = SQLITE_OK; - RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); - if( rc ) return rc; - if( p==0 ) return SQLITE_OK; if( i==0 ){ - sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); + i64 iRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell); + sqlite3_result_int64(ctx, iRowid); }else{ - if( rc ) return rc; - nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); + RtreeCoord c; + nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ sqlite3_result_double(ctx, c.f); }else #endif @@ -144984,10 +142729,11 @@ { assert( pRtree->eCoordType==RTREE_COORD_INT32 ); sqlite3_result_int(ctx, c.i); } } + return SQLITE_OK; } /* ** Use nodeAcquire() to obtain the leaf node containing the record with @@ -144994,22 +142740,16 @@ ** rowid iRowid. If successful, set *ppLeaf to point to the node and ** return SQLITE_OK. If there is no such record in the table, set ** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf ** to zero and return an SQLite error code. */ -static int findLeafNode( - Rtree *pRtree, /* RTree to search */ - i64 iRowid, /* The rowid searching for */ - RtreeNode **ppLeaf, /* Write the node here */ - sqlite3_int64 *piNode /* Write the node-id here */ -){ +static int findLeafNode(Rtree *pRtree, i64 iRowid, RtreeNode **ppLeaf){ int rc; *ppLeaf = 0; sqlite3_bind_int64(pRtree->pReadRowid, 1, iRowid); if( sqlite3_step(pRtree->pReadRowid)==SQLITE_ROW ){ i64 iNode = sqlite3_column_int64(pRtree->pReadRowid, 0); - if( piNode ) *piNode = iNode; rc = nodeAcquire(pRtree, iNode, 0, ppLeaf); sqlite3_reset(pRtree->pReadRowid); }else{ rc = sqlite3_reset(pRtree->pReadRowid); } @@ -145021,14 +142761,13 @@ ** as the second argument for a MATCH constraint. The value passed as the ** first argument to this function is the right-hand operand to the MATCH ** operator. */ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ - RtreeMatchArg *pBlob; /* BLOB returned by geometry function */ - sqlite3_rtree_query_info *pInfo; /* Callback information */ - int nBlob; /* Size of the geometry function blob */ - int nExpected; /* Expected size of the BLOB */ + RtreeMatchArg *p; + sqlite3_rtree_geometry *pGeom; + int nBlob; /* Check that value is actually a blob. */ if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR; /* Check that the blob is roughly the right size. */ @@ -145037,33 +142776,31 @@ || ((nBlob-sizeof(RtreeMatchArg))%sizeof(RtreeDValue))!=0 ){ return SQLITE_ERROR; } - pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob ); - if( !pInfo ) return SQLITE_NOMEM; - memset(pInfo, 0, sizeof(*pInfo)); - pBlob = (RtreeMatchArg*)&pInfo[1]; - - memcpy(pBlob, sqlite3_value_blob(pValue), nBlob); - nExpected = (int)(sizeof(RtreeMatchArg) + - (pBlob->nParam-1)*sizeof(RtreeDValue)); - if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){ - sqlite3_free(pInfo); + pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc( + sizeof(sqlite3_rtree_geometry) + nBlob + ); + if( !pGeom ) return SQLITE_NOMEM; + memset(pGeom, 0, sizeof(sqlite3_rtree_geometry)); + p = (RtreeMatchArg *)&pGeom[1]; + + memcpy(p, sqlite3_value_blob(pValue), nBlob); + if( p->magic!=RTREE_GEOMETRY_MAGIC + || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(RtreeDValue)) + ){ + sqlite3_free(pGeom); return SQLITE_ERROR; } - pInfo->pContext = pBlob->cb.pContext; - pInfo->nParam = pBlob->nParam; - pInfo->aParam = pBlob->aParam; - - if( pBlob->cb.xGeom ){ - pCons->u.xGeom = pBlob->cb.xGeom; - }else{ - pCons->op = RTREE_QUERY; - pCons->u.xQueryFunc = pBlob->cb.xQueryFunc; - } - pCons->pInfo = pInfo; + + pGeom->pContext = p->pContext; + pGeom->nParam = p->nParam; + pGeom->aParam = p->aParam; + + pCons->xGeom = p->xGeom; + pCons->pGeom = pGeom; return SQLITE_OK; } /* ** Rtree virtual table module xFilter method. @@ -145073,96 +142810,91 @@ int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; - int iCell = 0; rtreeReference(pRtree); freeCursorConstraints(pCsr); pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ - RtreeSearchPoint *p; /* Search point for the the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); - i64 iNode = 0; - rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); - if( rc==SQLITE_OK && pLeaf!=0 ){ - p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); - assert( p!=0 ); /* Always returns pCsr->sPoint */ - pCsr->aNode[0] = pLeaf; - p->id = iNode; - p->eWithin = PARTLY_WITHIN; - rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); - p->iCell = iCell; - RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); - }else{ - pCsr->atEOF = 1; + rc = findLeafNode(pRtree, iRowid, &pLeaf); + pCsr->pNode = pLeaf; + if( pLeaf ){ + assert( rc==SQLITE_OK ); + rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &pCsr->iCell); } }else{ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array ** with the configured constraints. */ - rc = nodeAcquire(pRtree, 1, 0, &pRoot); - if( rc==SQLITE_OK && argc>0 ){ + if( argc>0 ){ pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc); pCsr->nConstraint = argc; if( !pCsr->aConstraint ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); - memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); assert( (idxStr==0 && argc==0) || (idxStr && (int)strlen(idxStr)==argc*2) ); for(ii=0; iiaConstraint[ii]; p->op = idxStr[ii*2]; - p->iCoord = idxStr[ii*2+1]-'0'; - if( p->op>=RTREE_MATCH ){ + p->iCoord = idxStr[ii*2+1]-'a'; + if( p->op==RTREE_MATCH ){ /* A MATCH operator. The right-hand-side must be a blob that ** can be cast into an RtreeMatchArg object. One created using ** an sqlite3_rtree_geometry_callback() SQL user function. */ rc = deserializeGeometry(argv[ii], p); if( rc!=SQLITE_OK ){ break; } - p->pInfo->nCoord = pRtree->nDim*2; - p->pInfo->anQueue = pCsr->anQueue; - p->pInfo->mxLevel = pRtree->iDepth + 1; }else{ #ifdef SQLITE_RTREE_INT_ONLY - p->u.rValue = sqlite3_value_int64(argv[ii]); + p->rValue = sqlite3_value_int64(argv[ii]); #else - p->u.rValue = sqlite3_value_double(argv[ii]); + p->rValue = sqlite3_value_double(argv[ii]); #endif } } } } + + if( rc==SQLITE_OK ){ + pCsr->pNode = 0; + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + } if( rc==SQLITE_OK ){ - RtreeSearchPoint *pNew; - pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, pRtree->iDepth+1); - if( pNew==0 ) return SQLITE_NOMEM; - pNew->id = 1; - pNew->iCell = 0; - pNew->eWithin = PARTLY_WITHIN; - assert( pCsr->bPoint==1 ); - pCsr->aNode[0] = pRoot; - pRoot = 0; - RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); - rc = rtreeStepToLeaf(pCsr); + int isEof = 1; + int nCell = NCELL(pRoot); + pCsr->pNode = pRoot; + for(pCsr->iCell=0; rc==SQLITE_OK && pCsr->iCelliCell++){ + assert( pCsr->pNode==pRoot ); + rc = descendToCell(pRtree, pCsr, pRtree->iDepth, &isEof); + if( !isEof ){ + break; + } + } + if( rc==SQLITE_OK && isEof ){ + assert( pCsr->pNode==pRoot ); + nodeRelease(pRtree, pRoot); + pCsr->pNode = 0; + } + assert( rc!=SQLITE_OK || !pCsr->pNode || pCsr->iCellpNode) ); } } - nodeRelease(pRtree, pRoot); rtreeRelease(pRtree); return rc; } /* @@ -145260,11 +142992,11 @@ assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH ); op = RTREE_MATCH; break; } zIdxStr[iIdx++] = op; - zIdxStr[iIdx++] = p->iColumn - 1 + '0'; + zIdxStr[iIdx++] = p->iColumn - 1 + 'a'; pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); pIdxInfo->aConstraintUsage[ii].omit = 1; } } @@ -145353,36 +143085,66 @@ area = cellArea(pRtree, &cell); cellUnion(pRtree, &cell, pCell); return (cellArea(pRtree, &cell)-area); } +#if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT static RtreeDValue cellOverlap( Rtree *pRtree, RtreeCell *p, RtreeCell *aCell, - int nCell + int nCell, + int iExclude ){ int ii; - RtreeDValue overlap = RTREE_ZERO; + RtreeDValue overlap = 0.0; for(ii=0; iinDim*2); jj+=2){ - RtreeDValue x1, x2; - x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); - x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); - if( x2nDim*2); jj+=2){ + RtreeDValue x1, x2; + + x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); + x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); + + if( x2iDepth-iHeight); ii++){ int iCell; sqlite3_int64 iBest = 0; - RtreeDValue fMinGrowth = RTREE_ZERO; - RtreeDValue fMinArea = RTREE_ZERO; + RtreeDValue fMinGrowth = 0.0; + RtreeDValue fMinArea = 0.0; +#if VARIANT_RSTARTREE_CHOOSESUBTREE + RtreeDValue fMinOverlap = 0.0; + RtreeDValue overlap; +#endif int nCell = NCELL(pNode); RtreeCell cell; RtreeNode *pChild; RtreeCell *aCell = 0; + +#if VARIANT_RSTARTREE_CHOOSESUBTREE + if( ii==(pRtree->iDepth-1) ){ + int jj; + aCell = sqlite3_malloc(sizeof(RtreeCell)*nCell); + if( !aCell ){ + rc = SQLITE_NOMEM; + nodeRelease(pRtree, pNode); + pNode = 0; + continue; + } + for(jj=0; jjiDepth-1) ){ + overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell); + }else{ + overlap = 0.0; + } + if( (iCell==0) + || (overlappWriteParent); } static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int); +#if VARIANT_GUTTMAN_LINEAR_SPLIT +/* +** Implementation of the linear variant of the PickNext() function from +** Guttman[84]. +*/ +static RtreeCell *LinearPickNext( + Rtree *pRtree, + RtreeCell *aCell, + int nCell, + RtreeCell *pLeftBox, + RtreeCell *pRightBox, + int *aiUsed +){ + int ii; + for(ii=0; aiUsed[ii]; ii++); + aiUsed[ii] = 1; + return &aCell[ii]; +} + +/* +** Implementation of the linear variant of the PickSeeds() function from +** Guttman[84]. +*/ +static void LinearPickSeeds( + Rtree *pRtree, + RtreeCell *aCell, + int nCell, + int *piLeftSeed, + int *piRightSeed +){ + int i; + int iLeftSeed = 0; + int iRightSeed = 1; + RtreeDValue maxNormalInnerWidth = (RtreeDValue)0; + + /* Pick two "seed" cells from the array of cells. The algorithm used + ** here is the LinearPickSeeds algorithm from Gutman[1984]. The + ** indices of the two seed cells in the array are stored in local + ** variables iLeftSeek and iRightSeed. + */ + for(i=0; inDim; i++){ + RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]); + RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]); + RtreeDValue x3 = x1; + RtreeDValue x4 = x2; + int jj; + + int iCellLeft = 0; + int iCellRight = 0; + + for(jj=1; jjx4 ) x4 = right; + if( left>x3 ){ + x3 = left; + iCellRight = jj; + } + if( rightmaxNormalInnerWidth ){ + iLeftSeed = iCellLeft; + iRightSeed = iCellRight; + } + } + } + + *piLeftSeed = iLeftSeed; + *piRightSeed = iRightSeed; +} +#endif /* VARIANT_GUTTMAN_LINEAR_SPLIT */ + +#if VARIANT_GUTTMAN_QUADRATIC_SPLIT +/* +** Implementation of the quadratic variant of the PickNext() function from +** Guttman[84]. +*/ +static RtreeCell *QuadraticPickNext( + Rtree *pRtree, + RtreeCell *aCell, + int nCell, + RtreeCell *pLeftBox, + RtreeCell *pRightBox, + int *aiUsed +){ + #define FABS(a) ((a)<0.0?-1.0*(a):(a)) + + int iSelect = -1; + RtreeDValue fDiff; + int ii; + for(ii=0; iifDiff ){ + fDiff = diff; + iSelect = ii; + } + } + } + aiUsed[iSelect] = 1; + return &aCell[iSelect]; +} + +/* +** Implementation of the quadratic variant of the PickSeeds() function from +** Guttman[84]. +*/ +static void QuadraticPickSeeds( + Rtree *pRtree, + RtreeCell *aCell, + int nCell, + int *piLeftSeed, + int *piRightSeed +){ + int ii; + int jj; + + int iLeftSeed = 0; + int iRightSeed = 1; + RtreeDValue fWaste = 0.0; + + for(ii=0; iifWaste ){ + iLeftSeed = ii; + iRightSeed = jj; + fWaste = waste; + } + } + } + + *piLeftSeed = iLeftSeed; + *piRightSeed = iRightSeed; +} +#endif /* VARIANT_GUTTMAN_QUADRATIC_SPLIT */ /* ** Arguments aIdx, aDistance and aSpare all point to arrays of size ** nIdx. The aIdx array contains the set of integers from 0 to ** (nIdx-1) in no particular order. This function sorts the values @@ -145633,10 +143581,11 @@ } #endif } } +#if VARIANT_RSTARTREE_SPLIT /* ** Implementation of the R*-tree variant of SplitNode from Beckman[1990]. */ static int splitNodeStartree( Rtree *pRtree, @@ -145651,11 +143600,11 @@ int *aSpare; int ii; int iBestDim = 0; int iBestSplit = 0; - RtreeDValue fBestMargin = RTREE_ZERO; + RtreeDValue fBestMargin = 0.0; int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); aaSorted = (int **)sqlite3_malloc(nByte); if( !aaSorted ){ @@ -145672,13 +143621,13 @@ } SortByDimension(pRtree, aaSorted[ii], nCell, ii, aCell, aSpare); } for(ii=0; iinDim; ii++){ - RtreeDValue margin = RTREE_ZERO; - RtreeDValue fBestOverlap = RTREE_ZERO; - RtreeDValue fBestArea = RTREE_ZERO; + RtreeDValue margin = 0.0; + RtreeDValue fBestOverlap = 0.0; + RtreeDValue fBestArea = 0.0; int iBestLeft = 0; int nLeft; for( nLeft=RTREE_MINCELLS(pRtree); @@ -145700,11 +143649,11 @@ cellUnion(pRtree, &right, &aCell[aaSorted[ii][kk]]); } } margin += cellMargin(pRtree, &left); margin += cellMargin(pRtree, &right); - overlap = cellOverlap(pRtree, &left, &right, 1); + overlap = cellOverlap(pRtree, &left, &right, 1, -1); area = cellArea(pRtree, &left) + cellArea(pRtree, &right); if( (nLeft==RTREE_MINCELLS(pRtree)) || (overlap0; i--){ + RtreeCell *pNext; + pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed); + RtreeDValue diff = + cellGrowth(pRtree, pBboxLeft, pNext) - + cellGrowth(pRtree, pBboxRight, pNext) + ; + if( (RTREE_MINCELLS(pRtree)-NCELL(pRight)==i) + || (diff>0.0 && (RTREE_MINCELLS(pRtree)-NCELL(pLeft)!=i)) + ){ + nodeInsertCell(pRtree, pRight, pNext); + cellUnion(pRtree, pBboxRight, pNext); + }else{ + nodeInsertCell(pRtree, pLeft, pNext); + cellUnion(pRtree, pBboxLeft, pNext); + } + } + + sqlite3_free(aiUsed); + return SQLITE_OK; +} +#endif static int updateMapping( Rtree *pRtree, i64 iRowid, RtreeNode *pNode, @@ -145810,12 +143815,11 @@ } memset(pLeft->zData, 0, pRtree->iNodeSize); memset(pRight->zData, 0, pRtree->iNodeSize); - rc = splitNodeStartree(pRtree, aCell, nCell, pLeft, pRight, - &leftbbox, &rightbbox); + rc = AssignCells(pRtree, aCell, nCell, pLeft, pRight, &leftbbox, &rightbbox); if( rc!=SQLITE_OK ){ goto splitnode_out; } /* Ensure both child nodes have node numbers assigned to them by calling @@ -146094,11 +144098,11 @@ for(iDim=0; iDimnDim; iDim++){ aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2)); } for(ii=0; iinDim; iDim++){ RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - DCOORD(aCell[ii].aCoord[iDim*2])); aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]); } @@ -146160,16 +144164,20 @@ nodeReference(pNode); pChild->pParent = pNode; } } if( nodeInsertCell(pRtree, pNode, pCell) ){ +#if VARIANT_RSTARTREE_REINSERT if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){ rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ pRtree->iReinsertHeight = iHeight; rc = Reinsert(pRtree, pNode, pCell, iHeight); } +#else + rc = SplitNode(pRtree, pNode, pCell, iHeight); +#endif }else{ rc = AdjustTree(pRtree, pNode, pCell); if( rc==SQLITE_OK ){ if( iHeight==0 ){ rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); @@ -146235,11 +144243,11 @@ /* Obtain a reference to the leaf node that contains the entry ** about to be deleted. */ if( rc==SQLITE_OK ){ - rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); + rc = findLeafNode(pRtree, iDelete, &pLeaf); } /* Delete the cell in question from the leaf node. */ if( rc==SQLITE_OK ){ int rc2; @@ -146480,36 +144488,30 @@ ** This function populates the pRtree->nRowEst variable with an estimate ** of the number of rows in the virtual table. If possible, this is based ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. */ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ - const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; - char *zSql; + const char *zSql = "SELECT stat FROM sqlite_stat1 WHERE tbl= ? || '_rowid'"; sqlite3_stmt *p; int rc; i64 nRow = 0; - zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); - if( rc==SQLITE_OK ){ - if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); - rc = sqlite3_finalize(p); - }else if( rc!=SQLITE_NOMEM ){ - rc = SQLITE_OK; - } - - if( rc==SQLITE_OK ){ - if( nRow==0 ){ - pRtree->nRowEst = RTREE_DEFAULT_ROWEST; - }else{ - pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); - } - } - sqlite3_free(zSql); + rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_text(p, 1, pRtree->zName, -1, SQLITE_STATIC); + if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); + rc = sqlite3_finalize(p); + }else if( rc!=SQLITE_NOMEM ){ + rc = SQLITE_OK; + } + + if( rc==SQLITE_OK ){ + if( nRow==0 ){ + pRtree->nRowEst = RTREE_DEFAULT_ROWEST; + }else{ + pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); + } } return rc; } @@ -146572,12 +144574,11 @@ if( isCreate ){ char *zCreate = sqlite3_mprintf( "CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY, data BLOB);" "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY, nodeno INTEGER);" -"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY," - " parentnode INTEGER);" +"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY, parentnode INTEGER);" "INSERT INTO '%q'.'%q_node' VALUES(1, zeroblob(%d))", zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, pRtree->iNodeSize ); if( !zCreate ){ return SQLITE_NOMEM; @@ -146775,12 +144776,10 @@ } if( rc==SQLITE_OK ){ *ppVtab = (sqlite3_vtab *)pRtree; }else{ - assert( *ppVtab==0 ); - assert( pRtree->nBusy==1 ); rtreeRelease(pRtree); } return rc; } @@ -146787,14 +144786,14 @@ /* ** Implementation of a scalar function that decodes r-tree nodes to ** human readable strings. This can be used for debugging and analysis. ** -** The scalar function takes two arguments: (1) the number of dimensions -** to the rtree (between 1 and 5, inclusive) and (2) a blob of data containing -** an r-tree node. For a two-dimensional r-tree structure called "rt", to -** deserialize all nodes, a statement like: +** The scalar function takes two arguments, a blob of data containing +** an r-tree node, and the number of dimensions the r-tree indexes. +** For a two-dimensional r-tree structure called "rt", to deserialize +** all nodes, a statement like: ** ** SELECT rtreenode(2, data) FROM rt_node; ** ** The human readable string takes the form of a Tcl list with one ** entry for each cell in the r-tree node. Each entry is itself a @@ -146823,11 +144822,11 @@ nodeGetCell(&tree, &node, ii, &cell); sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid); nCell = (int)strlen(zCell); for(jj=0; jjxDestructor ) pInfo->xDestructor(pInfo->pContext); +static void doSqlite3Free(void *p){ sqlite3_free(p); } /* -** Each call to sqlite3_rtree_geometry_callback() or -** sqlite3_rtree_query_callback() creates an ordinary SQLite -** scalar function that is implemented by this routine. -** -** All this function does is construct an RtreeMatchArg object that -** contains the geometry-checking callback routines and a list of -** parameters to this function, then return that RtreeMatchArg object -** as a BLOB. -** -** The R-Tree MATCH operator will read the returned BLOB, deserialize -** the RtreeMatchArg object, and use the RtreeMatchArg object to figure -** out which elements of the R-Tree should be returned by the query. +** Each call to sqlite3_rtree_geometry_callback() creates an ordinary SQLite +** scalar user function. This C function is the callback used for all such +** registered SQL functions. +** +** The scalar user functions return a blob that is interpreted by r-tree +** table MATCH operators. */ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx); RtreeMatchArg *pBlob; int nBlob; @@ -146933,68 +144914,45 @@ if( !pBlob ){ sqlite3_result_error_nomem(ctx); }else{ int i; pBlob->magic = RTREE_GEOMETRY_MAGIC; - pBlob->cb = pGeomCtx[0]; + pBlob->xGeom = pGeomCtx->xGeom; + pBlob->pContext = pGeomCtx->pContext; pBlob->nParam = nArg; for(i=0; iaParam[i] = sqlite3_value_int64(aArg[i]); #else pBlob->aParam[i] = sqlite3_value_double(aArg[i]); #endif } - sqlite3_result_blob(ctx, pBlob, nBlob, sqlite3_free); + sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free); } } /* ** Register a new geometry function for use with the r-tree MATCH operator. */ SQLITE_API int sqlite3_rtree_geometry_callback( - sqlite3 *db, /* Register SQL function on this connection */ - const char *zGeom, /* Name of the new SQL function */ - int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */ - void *pContext /* Extra data associated with the callback */ + sqlite3 *db, + const char *zGeom, + int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *), + void *pContext ){ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ /* Allocate and populate the context object. */ pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); if( !pGeomCtx ) return SQLITE_NOMEM; pGeomCtx->xGeom = xGeom; - pGeomCtx->xQueryFunc = 0; - pGeomCtx->xDestructor = 0; pGeomCtx->pContext = pContext; + + /* Create the new user-function. Register a destructor function to delete + ** the context object when it is no longer required. */ return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY, - (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback - ); -} - -/* -** Register a new 2nd-generation geometry function for use with the -** r-tree MATCH operator. -*/ -SQLITE_API int sqlite3_rtree_query_callback( - sqlite3 *db, /* Register SQL function on this connection */ - const char *zQueryFunc, /* Name of new SQL function */ - int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */ - void *pContext, /* Extra data passed into the callback */ - void (*xDestructor)(void*) /* Destructor for the extra data */ -){ - RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ - - /* Allocate and populate the context object. */ - pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); - if( !pGeomCtx ) return SQLITE_NOMEM; - pGeomCtx->xGeom = 0; - pGeomCtx->xQueryFunc = xQueryFunc; - pGeomCtx->xDestructor = xDestructor; - pGeomCtx->pContext = pContext; - return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY, - (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback + (void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free ); } #if !SQLITE_CORE #ifdef _WIN32 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.8.5" -#define SQLITE_VERSION_NUMBER 3008005 -#define SQLITE_SOURCE_ID "2014-06-04 14:06:34 b1ed4f2a34ba66c29b130f8d13e9092758019212" +#define SQLITE_VERSION "3.8.3" +#define SQLITE_VERSION_NUMBER 3008003 +#define SQLITE_SOURCE_ID "2014-02-03 13:52:03 e816dd924619db5f766de6df74ea2194f3e3b538" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** @@ -558,14 +558,11 @@ ** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that ** after reboot following a crash or power loss, the only bytes in a ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN -** flag indicate that a file cannot be deleted when open. The -** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on -** read-only media and cannot be changed even by processes with -** elevated privileges. +** flag indicate that a file cannot be deleted when open. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 #define SQLITE_IOCAP_ATOMIC1K 0x00000004 #define SQLITE_IOCAP_ATOMIC2K 0x00000008 @@ -576,11 +573,10 @@ #define SQLITE_IOCAP_ATOMIC64K 0x00000100 #define SQLITE_IOCAP_SAFE_APPEND 0x00000200 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 -#define SQLITE_IOCAP_IMMUTABLE 0x00002000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second @@ -945,16 +941,10 @@ ** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a ** pointer to an integer and it writes a boolean into that integer depending ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** -**
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] -** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This -** opcode causes the xFileControl method to swap the file handle with the one -** pointed to by the pArg argument. This capability is used during testing -** and only needs to be supported when SQLITE_TEST is defined. -** ** */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 @@ -974,11 +964,10 @@ #define SQLITE_FCNTL_MMAP_SIZE 18 #define SQLITE_FCNTL_TRACE 19 #define SQLITE_FCNTL_HAS_MOVED 20 #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 -#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an @@ -2788,34 +2777,10 @@ ** 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 ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. -** -**
  • psow: ^The psow parameter may be "true" (or "on" or "yes" or -** "1") or "false" (or "off" or "no" or "0") to indicate that the -** [powersafe overwrite] property does or does not apply to the -** storage media on which the database file resides. ^The psow query -** parameter only works for the built-in unix and Windows VFSes. -** -**
  • nolock: ^The nolock parameter is a boolean query parameter -** which if set disables file locking in rollback journal modes. This -** is useful for accessing a database on a filesystem that does not -** support locking. Caution: Database corruption might result if two -** or more processes write to the same database and any one of those -** processes uses nolock=1. -** -**
  • immutable: ^The immutable parameter is a boolean query -** parameter that indicates that the database file is stored on -** read-only media. ^When immutable is set, SQLite assumes that the -** database file cannot be changed, even by a process with higher -** privilege, and so the database is opened read-only and all locking -** and change detection is disabled. Caution: Setting the immutable -** property on a database file that does in fact change can result -** in incorrect query results and/or [SQLITE_CORRUPT] errors. -** See also: [SQLITE_IOCAP_IMMUTABLE]. -** ** ** ** ^Specifying an unknown parameter in the query component of a URI is not an ** error. Future versions of SQLite might understand additional query ** parameters. See "[query parameters with special meaning to SQLite]" for @@ -2841,13 +2806,12 @@ ** in URI filenames. **
  • file:data.db?mode=ro&cache=private ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. -**
    file:/home/fred/data.db?vfs=unix-dotfile -** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" -** that uses dot-files in place of posix advisory locking. +**
    file:/home/fred/data.db?vfs=unix-nolock +** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". **
    file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. **
    ** ** ^URI hexadecimal escape sequences (%HH) are supported within the path and @@ -6156,13 +6120,11 @@ #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 -#define SQLITE_TESTCTRL_VDBE_COVERAGE 21 -#define SQLITE_TESTCTRL_BYTEORDER 22 -#define SQLITE_TESTCTRL_LAST 22 +#define SQLITE_TESTCTRL_LAST 20 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information @@ -7381,20 +7343,10 @@ #ifdef __cplusplus extern "C" { #endif typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; -typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; - -/* The double-precision datatype used by RTree depends on the -** SQLITE_RTREE_INT_ONLY compile-time option. -*/ -#ifdef SQLITE_RTREE_INT_ONLY - typedef sqlite3_int64 sqlite3_rtree_dbl; -#else - typedef double sqlite3_rtree_dbl; -#endif /* ** Register a geometry callback named zGeom that can be used as part of an ** R-Tree geometry query as follows: ** @@ -7401,11 +7353,15 @@ ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), +#ifdef SQLITE_RTREE_INT_ONLY + int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes), +#else + int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes), +#endif void *pContext ); /* @@ -7413,66 +7369,17 @@ ** argument to callbacks registered using rtree_geometry_callback(). */ struct sqlite3_rtree_geometry { void *pContext; /* Copy of pContext passed to s_r_g_c() */ int nParam; /* Size of array aParam[] */ - sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ + double *aParam; /* Parameters passed to SQL geom function */ void *pUser; /* Callback implementation user data */ void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ }; -/* -** Register a 2nd-generation geometry callback named zScore that can be -** used as part of an R-Tree geometry query as follows: -** -** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) -*/ -SQLITE_API int sqlite3_rtree_query_callback( - sqlite3 *db, - const char *zQueryFunc, - int (*xQueryFunc)(sqlite3_rtree_query_info*), - void *pContext, - void (*xDestructor)(void*) -); - - -/* -** A pointer to a structure of the following type is passed as the -** argument to scored geometry callback registered using -** sqlite3_rtree_query_callback(). -** -** Note that the first 5 fields of this structure are identical to -** sqlite3_rtree_geometry. This structure is a subclass of -** sqlite3_rtree_geometry. -*/ -struct sqlite3_rtree_query_info { - void *pContext; /* pContext from when function registered */ - int nParam; /* Number of function parameters */ - sqlite3_rtree_dbl *aParam; /* value of function parameters */ - void *pUser; /* callback can use this, if desired */ - void (*xDelUser)(void*); /* function to free pUser */ - sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ - unsigned int *anQueue; /* Number of pending entries in the queue */ - int nCoord; /* Number of coordinates */ - int iLevel; /* Level of current node or entry */ - int mxLevel; /* The largest iLevel value in the tree */ - sqlite3_int64 iRowid; /* Rowid for current entry */ - sqlite3_rtree_dbl rParentScore; /* Score of parent node */ - int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visiblity */ - sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ -}; - -/* -** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. -*/ -#define NOT_WITHIN 0 /* Object completely outside of query region */ -#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ -#define FULLY_WITHIN 2 /* Object fully contained within query region */ - #ifdef __cplusplus } /* end of the 'extern "C"' block */ #endif #endif /* ifndef _SQLITE3RTREE_H_ */ Index: SQLite.Interop/src/win/interop.h ================================================================== --- SQLite.Interop/src/win/interop.h +++ SQLite.Interop/src/win/interop.h @@ -4,11 +4,11 @@ * Written by Joe Mistachkin. * Released to the public domain, use at your own risk! */ #ifndef INTEROP_VERSION -#define INTEROP_VERSION "1.0.93.0" +#define INTEROP_VERSION "1.0.91.0" #endif #ifndef INTEROP_SOURCE_ID #define INTEROP_SOURCE_ID "0000000000000000000000000000000000000000" #endif Index: SQLite.NET.2005.MSBuild.sln ================================================================== --- SQLite.NET.2005.MSBuild.sln +++ SQLite.NET.2005.MSBuild.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2005", "System.Data.SQLite\System.Data.SQLite.2005.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2005", "System.Data.SQLite\System.Data.SQLite.Module.2005.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2005.sln ================================================================== --- SQLite.NET.2005.sln +++ SQLite.NET.2005.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2005", "System.Data.SQLite\System.Data.SQLite.2005.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2005", "System.Data.SQLite\System.Data.SQLite.Module.2005.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2008.MSBuild.sln ================================================================== --- SQLite.NET.2008.MSBuild.sln +++ SQLite.NET.2008.MSBuild.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2008", "System.Data.SQLite\System.Data.SQLite.2008.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2008", "System.Data.SQLite\System.Data.SQLite.Module.2008.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2008.sln ================================================================== --- SQLite.NET.2008.sln +++ SQLite.NET.2008.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2008", "System.Data.SQLite\System.Data.SQLite.2008.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2008", "System.Data.SQLite\System.Data.SQLite.Module.2008.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2010.MSBuild.sln ================================================================== --- SQLite.NET.2010.MSBuild.sln +++ SQLite.NET.2010.MSBuild.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2010", "System.Data.SQLite\System.Data.SQLite.2010.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2010", "System.Data.SQLite\System.Data.SQLite.Module.2010.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2010.sln ================================================================== --- SQLite.NET.2010.sln +++ SQLite.NET.2010.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2010", "System.Data.SQLite\System.Data.SQLite.2010.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2010", "System.Data.SQLite\System.Data.SQLite.Module.2010.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2012.MSBuild.sln ================================================================== --- SQLite.NET.2012.MSBuild.sln +++ SQLite.NET.2012.MSBuild.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2012", "System.Data.SQLite\System.Data.SQLite.2012.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2012", "System.Data.SQLite\System.Data.SQLite.Module.2012.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2012.sln ================================================================== --- SQLite.NET.2012.sln +++ SQLite.NET.2012.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2012", "System.Data.SQLite\System.Data.SQLite.2012.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2012", "System.Data.SQLite\System.Data.SQLite.Module.2012.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2013.MSBuild.sln ================================================================== --- SQLite.NET.2013.MSBuild.sln +++ SQLite.NET.2013.MSBuild.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 13.00 # Visual Studio 2013 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2013", "System.Data.SQLite\System.Data.SQLite.2013.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2013", "System.Data.SQLite\System.Data.SQLite.Module.2013.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" Index: SQLite.NET.2013.sln ================================================================== --- SQLite.NET.2013.sln +++ SQLite.NET.2013.sln @@ -1,37 +1,29 @@ Microsoft Visual Studio Solution File, Format Version 13.00 # Visual Studio 2013 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject - data\exclude_bin.txt = data\exclude_bin.txt - data\exclude_src.txt = data\exclude_src.txt - Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk - Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk - NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform - NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform - NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform - NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1 - NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1 - NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1 - NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1 + exclude_bin.txt = exclude_bin.txt + exclude_src.txt = exclude_src.txt + NuGet\net20\config.transform = NuGet\net20\config.transform + NuGet\net40\config.transform = NuGet\net40\config.transform + NuGet\net20\install.ps1 = NuGet\net20\install.ps1 + NuGet\net40\install.ps1 = NuGet\net40\install.ps1 NuGet\SQLite.Beta.nuspec = NuGet\SQLite.Beta.nuspec - NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec - NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec - NuGet\SQLite.EF6.nuspec = NuGet\SQLite.EF6.nuspec - NuGet\SQLite.Linq.nuspec = NuGet\SQLite.Linq.nuspec NuGet\SQLite.MSIL.nuspec = NuGet\SQLite.MSIL.nuspec NuGet\SQLite.nuspec = NuGet\SQLite.nuspec - NuGet\SQLite.Test.nuspec = NuGet\SQLite.Test.nuspec NuGet\SQLite.x64.nuspec = NuGet\SQLite.x64.nuspec NuGet\SQLite.x86.nuspec = NuGet\SQLite.x86.nuspec readme.htm = readme.htm - System.Data.SQLite\Targets\System.Data.SQLite.Files.targets = System.Data.SQLite\Targets\System.Data.SQLite.Files.targets - System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets = System.Data.SQLite\Targets\System.Data.SQLite.Properties.targets - System.Data.SQLite\Targets\System.Data.SQLite.References.targets = System.Data.SQLite\Targets\System.Data.SQLite.References.targets - Targets\SQLite.NET.Settings.targets = Targets\SQLite.NET.Settings.targets - Targets\SQLite.NET.Settings.targets.netFx35 = Targets\SQLite.NET.Settings.targets.netFx35 - Targets\SQLite.NET.targets = Targets\SQLite.NET.targets + SQLite.NET.Settings.targets = SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets = SQLite.NET.targets + 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 + System.Data.SQLite\System.Data.SQLite.Properties.targets = System.Data.SQLite\System.Data.SQLite.Properties.targets + System.Data.SQLite\System.Data.SQLite.References.targets = System.Data.SQLite\System.Data.SQLite.References.targets + System.Data.SQLite\System.Data.SQLite.snk = System.Data.SQLite\System.Data.SQLite.snk EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.2013", "System.Data.SQLite\System.Data.SQLite.2013.csproj", "{AC139952-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite.Module.2013", "System.Data.SQLite\System.Data.SQLite.Module.2013.csproj", "{AC139952-261A-4463-B6FA-AEBC25284A66}" ADDED SQLite.NET.Settings.targets Index: SQLite.NET.Settings.targets ================================================================== --- /dev/null +++ SQLite.NET.Settings.targets @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + false + + + true + + + false + + + + + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + + + + + false + + + false + + + false + + + true + + + true + + + false + + + false + + + false + + + true + + + true + + + true + + + true + false + + + true + + + true + false + + + false + + + true + false + + + true + + + true + + + false + + + + + + + false + + + false + + + true + + + true + + + false + + + true + + + + + + + 4 + 618,1591;3001 + + + + + 4 + 618,1591;3001 + + + + + + + + + + + + + + $(SQLiteNetDir)\obj\$(ConfigurationYear)\ + $(SQLiteNetDir)\obj\$(ConfigurationYear)\$(ConfigurationSuffix)\ + + + + + + + $(SQLiteNetDir)\bin\$(ConfigurationYear)\$(Configuration)$(ConfigurationSuffix)\bin\ + + + + + + + true + + + false + + + $(SQLiteNetDir)\System.Data.SQLite\System.Data.SQLite.snk + $(SQLiteNetDir)\System.Data.SQLite\System.Data.SQLite.CF.snk + + ADDED SQLite.NET.Settings.targets.netFx35 Index: SQLite.NET.Settings.targets.netFx35 ================================================================== --- /dev/null +++ SQLite.NET.Settings.targets.netFx35 @@ -0,0 +1,23 @@ + + + + true + true + false + false + false + v3.5 + + false + v110 + + ADDED SQLite.NET.targets Index: SQLite.NET.targets ================================================================== --- /dev/null +++ SQLite.NET.targets @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: Setup/SQLite.iss ================================================================== --- Setup/SQLite.iss +++ Setup/SQLite.iss @@ -9,15 +9,15 @@ #define GacProcessor StringChange(AppProcessor, "x64", "amd64") #if Pos("NativeOnly", AppConfiguration) == 0 #define InstallerCondition "Application\Core\MSIL and Application\Designer and Application\Designer\Installer" #define AppVersion GetStringFileInfo("..\bin\" + Year + "\" + AppPlatform + "\" + AppConfiguration + "\System.Data.SQLite.dll", PRODUCT_VERSION) -#define OutputConfiguration StringChange(StringChange(AppConfiguration, "Debug", "setup-debug"), "Release", "setup") + "-bundle" +#define OutputConfiguration StringChange(StringChange(AppConfiguration, "Debug", "setup"), "Release", "setup") + "-bundle" #else #define InstallerCondition "Application\Core\MSIL and Application\Core\" + AppProcessor + " and Application\Designer and Application\Designer\Installer" #define AppVersion GetStringFileInfo("..\bin\" + Year + "\" + BaseConfiguration + "\bin\System.Data.SQLite.dll", PRODUCT_VERSION) -#define OutputConfiguration StringChange(StringChange(BaseConfiguration, "Debug", "setup-debug"), "Release", "setup") +#define OutputConfiguration StringChange(StringChange(BaseConfiguration, "Debug", "setup"), "Release", "setup") #endif [Setup] AllowNoIcons=true @@ -32,11 +32,11 @@ AppName=System.Data.SQLite AppPublisher=System.Data.SQLite Team AppPublisherURL={#AppURL} AppSupportURL={#AppURL} AppUpdatesURL={#AppURL} -AppVerName=System.Data.SQLite v{#AppVersion} ({#AppConfiguration}) +AppVerName=System.Data.SQLite v{#AppVersion} AppVersion={#AppVersion} AppComments=The ADO.NET adapter for the SQLite database engine. AppReadmeFile={app}\readme.htm DefaultDirName={pf}\System.Data.SQLite\{#Year} DefaultGroupName=System.Data.SQLite\{#Year} Index: Setup/archive.bat ================================================================== --- Setup/archive.bat +++ Setup/archive.bat @@ -80,11 +80,11 @@ ECHO Could not create directory "Setup\Output". GOTO errors ) ) -%__ECHO% zip.exe -v -r Setup\Output\sqlite-netFx-source-%VERSION%.zip * -x @data\exclude_src.txt +%__ECHO% zip.exe -v -r Setup\Output\sqlite-netFx-source-%VERSION%.zip * -x @exclude_src.txt IF ERRORLEVEL 1 ( ECHO Failed to archive source files. GOTO errors ) ADDED Setup/deployAndTestCe.eagle Index: Setup/deployAndTestCe.eagle ================================================================== --- /dev/null +++ Setup/deployAndTestCe.eagle @@ -0,0 +1,394 @@ +############################################################################### +# +# deployAndTestCe.eagle -- Windows CE Deployment & Testing Tool +# +# Written by Joe Mistachkin. +# Released to the public domain, use at your own risk! +# +############################################################################### + +package require Eagle + +proc usage { error } { + if {[string length $error] > 0} then {puts stdout $error} + + puts stdout "usage:\ +[file tail [info nameofexecutable]]\ +[file tail [info script]] \[year\] \[platform\] \[configuration\]\ +\[culture\] \[platformId\] \[deviceId\] \[quiet\]" + + # + # NOTE: Indicate to the caller, if any, that we have failed. + # + exit 1 +} + +# +# 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 { + eval puts $args; flush stdout + } +} + +# +# NOTE: This procedure looks up and returns the target device based on the +# locale, platform Id, and device Id. +# +proc getDevice { cultureInfo platformId deviceId } { + set datastoreManager [object create -alias \ + Microsoft.SmartDevice.Connectivity.DatastoreManager \ + [$cultureInfo LCID]] + + set platform [$datastoreManager -alias GetPlatform [object create \ + Microsoft.SmartDevice.Connectivity.ObjectId $platformId]] + + if {[string length $deviceId] == 0} then { + set deviceId [$platform GetDefaultDeviceId] + } + + set device [$platform -alias GetDevice $deviceId] + + qputs stdout [appendArgs \ + "returning device \"" [$device Name] "\" of platform \"" \ + [$device Platform.ToString] "\" with Id \"" [$device Id.ToString] \ + \"...] + + return $device +} + +# +# NOTE: This procedure starts a process on the target device and optionally +# waits for it to complete. +# +proc startRemoteProcess { device fileName arguments {wait true} } { + set remoteProcess [$device -alias GetRemoteProcess] + + if {![$remoteProcess Start $fileName $arguments]} then { + error [appendArgs "could not start remote process \"" $fileName \"] + } + + if {$wait} then { + qputs stdout [appendArgs \ + "waiting for remote process " [$remoteProcess GetId] ...] + + while {![$remoteProcess HasExited]} { + qputs -nonewline stdout . + after 1000 + } + + qputs stdout "" + return [$remoteProcess GetExitCode] + } + + return -1 +} + +set argc [llength $argv] + +if {$argc >= 0 && $argc <= 7} then { + # + # NOTE: Setup the default values for all command line options. + # + array set default { + year 2008 + platform {Pocket PC 2003 (ARMV4)} + configuration Release + culture en-US + platformId 3c41c503-53ef-4c2a-8dd4-a8217cad115e + deviceId {} + quiet false + } + + # + # NOTE: Process all the command line options. If a command line option + # is not present, use the default value. + # + set names [list \ + year platform configuration culture platformId deviceId quiet] + + for {set index 0} {$index < [llength $names]} {incr index} { + set name [lindex $names $index]; set value "" + + if {$argc > $index} then { + set value [string trim [lindex $argv $index]] + } + + if {[string length $value] > 0} then { + set $name $value; set defaultValue false + } else { + set $name $default($name); set defaultValue true + } + + 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: 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]] + } + + # + # NOTE: Save the path where this script is running from. + # + set path [file dirname [info script]] + + # + # NOTE: The base path should be the project root directory, which should + # be one level above the one containing this script. + # + set base_path [file dirname $path] + + # + # NOTE: The managed binaries to be deployed to the target device should + # be located in the "\bin\\Compact\bin" + # directory. + # + set managed_directory [file join \ + $base_path bin $year [appendArgs $configuration Compact] bin] + + # + # NOTE: The native binaries to be deployed to the target device should + # be located in the "\bin\\\" + # directory. + # + set native_directory [file join \ + $base_path bin $year $platform $configuration] + + # + # NOTE: Build the list of all application files that need to be deployed to + # the target device, including all the native and managed binaries. + # + if {![info exists fileNames]} then { + # + # NOTE: Grab the assembly name instance based on the primary managed + # assembly file name. This is needed because the build portion of + # the assembly version is used when building the default list of + # application files to be deployed to the target device. + # + set assemblyName [object invoke -alias System.Reflection.AssemblyName \ + GetAssemblyName [file join $managed_directory System.Data.SQLite.dll]] + + # + # NOTE: The default list of application files includes the test application + # itself, the System.Data.SQLite managed assembly, the SQLite interop + # assembly, and the test application configuration file. + # + 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]] + } + + # + # NOTE: Setup the directory on the target device where the application files + # should be deployed to. + # + if {![info exists device_directory]} then { + set device_directory "\\Program Files\\testce\\" + } + + # + # NOTE: Load the managed assembly that allows us to communicate with the + # target device. If this fails, the necessary SDK components are + # probably not available on this system. + # + object load Microsoft.Smartdevice.Connectivity + + # + # NOTE: Lookup the necessary device based on the platform and device Ids. + # + set device [getDevice $cultureInfo $platformId $deviceId] + + # + # NOTE: Attempt to connect to the target device, which may be an emulator. + # By default, we attempt to connect to the "Pocket PC 2003 SE Emulator" + # device of the "Pocket PC 2003" platform (English). If this fails, + # the target device is probably unavailable, either because it is not + # connected or some SDK components are missing. + # + $device Connect + + # + # NOTE: Grab the file deployer instance for the target device. This will + # 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 application file to be sent to the target device. + # + foreach fileName $fileNames { + qputs stdout [appendArgs \ + "sending file \"" $fileName "\" to device..."] + + # + # NOTE: All the application files are sent to the same directory on the + # target device and the SendFile method requires a fully qualified + # file name; therefore, grab the file name only from the source file + # name and append that to the directory name on the target device. + # Using [file join] and/or [file normalize] should be avoided here + # because the directory name on the target device is not necessarily + # valid a file name on this system and vice versa. + # + $fileDeployer SendFile $fileName [appendArgs $device_directory \ + [file tail $fileName]] true false + } + + # + # NOTE: Run the test application on the target device in "automatic" mode + # (i.e. no user interaction is required) and capture the exit code. + # The exit code will be zero upon success (i.e. all tests passed) or + # non-zero otherwise. + # + set testFileName [file nativename [file join $device_directory testce.exe]] + set exitCode [startRemoteProcess $device $testFileName true] + + # + # NOTE: Is the target device actually an emulator running on this system? + # + set isEmulator [$device IsEmulator] + + # + # NOTE: We no longer need to be connected to the target device. + # + $device Disconnect + + # + # NOTE: Also, if the device is an emulator, attempt to shutdown the process + # containing it now (since we probably caused it to start). + # + if {$isEmulator} then { + # + # NOTE: Try to find the top-level window for the device emulator process + # based on the "LCDDisplay" window class name. Using this method + # of finding the target window is somewhat fragile and may not work + # reliably in the future. + # + set hWnd [lindex [lindex [info windows LCDDisplay] 0] 0]; # FIXME: ??? + + # + # NOTE: Make sure we found it before trying to lookup the parent process. + # + if {[string is integer -strict $hWnd] && $hWnd != 0} then { + # + # NOTE: Attempt to lookup the parent process for the target window. + # + qputs stdout [appendArgs "found device emulator window handle " $hWnd \ + ", looking up the process Id..."] + + set processId 0; set threadId 0; set error null + + if {[object invoke -flags +NonPublic \ + Eagle._Components.Private.WindowOps GetWindowThreadProcessId \ + [object create IntPtr $hWnd] processId threadId error] eq "Ok" && \ + [string is integer -strict $processId] && $processId != 0} then { + # + # NOTE: This is not ideal; however, if we simply try to close the + # target window, it will prompt to save state changes and that + # requires user interaction. We never want to save the state; + # therefore, just forcibly kill the process containing the + # emulator. + # + qputs stdout [appendArgs "found device emulator process Id " \ + $processId ", killing..."] + + kill -force $processId + } + } + } + + # + # NOTE: Print the overall result of running the test application and exit + # using the exit code from the test application on the target device. + # + qputs stdout [expr {$exitCode == 0 ? "SUCCESS" : "FAILURE"}] + exit $exitCode +} else { + usage "" +} DELETED Setup/deployAndTestCe200x.eagle Index: Setup/deployAndTestCe200x.eagle ================================================================== --- Setup/deployAndTestCe200x.eagle +++ /dev/null @@ -1,417 +0,0 @@ -############################################################################### -# -# deployAndTestCe200x.eagle -- Windows CE Deployment & Testing Tool -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle - -proc usage { error } { - if {[string length $error] > 0} then {puts stdout $error} - - puts stdout "usage:\ -[file tail [info nameofexecutable]]\ -[file tail [info script]] \[year\] \[platform\] \[configuration\]\ -\[culture\] \[platformId\] \[deviceId\] \[quiet\]" - - # - # NOTE: Indicate to the caller, if any, that we have failed. - # - exit 1 -} - -# -# 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 { - eval puts $args; flush stdout - } -} - -proc showPlatforms { cultureInfo } { - set datastoreManager [object create -alias \ - Microsoft.SmartDevice.Connectivity.DatastoreManager \ - [$cultureInfo LCID]] - - object foreach -alias platform [$datastoreManager GetPlatforms] { - qputs stdout [appendArgs \ - "found platform \"" [$platform Id.ToString] "\" with name \"" \ - [$platform Name] \"...] - } -} - -# -# NOTE: This procedure looks up and returns the target device based on the -# locale, platform Id, and device Id. -# -proc getDevice { cultureInfo platformId deviceId } { - set datastoreManager [object create -alias \ - Microsoft.SmartDevice.Connectivity.DatastoreManager \ - [$cultureInfo LCID]] - - set platform [$datastoreManager -alias GetPlatform [object create \ - Microsoft.SmartDevice.Connectivity.ObjectId $platformId]] - - if {[string length $deviceId] == 0} then { - set deviceId [$platform GetDefaultDeviceId] - } - - set device [$platform -alias GetDevice $deviceId] - - qputs stdout [appendArgs \ - "returning device \"" [$device Name] "\" of platform \"" \ - [$device Platform.ToString] "\" with Id \"" [$device Id.ToString] \ - \"...] - - return $device -} - -# -# NOTE: This procedure starts a process on the target device and optionally -# waits for it to complete. -# -proc startRemoteProcess { device fileName arguments {wait true} } { - set remoteProcess [$device -alias GetRemoteProcess] - - if {![$remoteProcess Start $fileName $arguments]} then { - error [appendArgs "could not start remote process \"" $fileName \"] - } - - if {$wait} then { - qputs stdout [appendArgs \ - "waiting for remote process " [$remoteProcess GetId] ...] - - while {![$remoteProcess HasExited]} { - qputs -nonewline stdout . - after 1000 - } - - qputs stdout "" - return [$remoteProcess GetExitCode] - } - - return -1 -} - -set argc [llength $argv] - -if {$argc >= 0 && $argc <= 7} then { - # - # NOTE: Setup the default values for all command line options. - # - array set default { - year 2008 - platform {Pocket PC 2003 (ARMV4)} - configuration Release - culture en-US - platformId 3c41c503-53ef-4c2a-8dd4-a8217cad115e - deviceId {} - quiet false - } - - # - # NOTE: Process all the command line options. If a command line option - # is not present, use the default value. - # - set names [list \ - year platform configuration culture platformId deviceId quiet] - - for {set index 0} {$index < [llength $names]} {incr index} { - set name [lindex $names $index]; set value "" - - if {$argc > $index} then { - set value [string trim [lindex $argv $index]] - } - - if {[string length $value] > 0} then { - set $name $value; set defaultValue false - } else { - set $name $default($name); set defaultValue true - } - - 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: 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]] - } - - # - # NOTE: Save the path where this script is running from. - # - set path [file dirname [info script]] - - # - # NOTE: The base path should be the project root directory, which should - # be one level above the one containing this script. - # - set base_path [file dirname $path] - - # - # NOTE: The managed binaries to be deployed to the target device should - # be located in the "\bin\\Compact\bin" - # directory. - # - set managed_directory [file join \ - $base_path bin $year [appendArgs $configuration Compact] bin] - - # - # NOTE: The native binaries to be deployed to the target device should - # be located in the "\bin\\\" - # directory. - # - set native_directory [file join \ - $base_path bin $year $platform $configuration] - - # - # NOTE: Build the list of all application files that need to be deployed to - # the target device, including all the native and managed binaries. - # - if {![info exists fileNames]} then { - # - # NOTE: Grab the assembly name instance based on the primary managed - # assembly file name. This is needed because the build portion of - # the assembly version is used when building the default list of - # application files to be deployed to the target device. - # - set assemblyName [object invoke -alias System.Reflection.AssemblyName \ - GetAssemblyName [file join $managed_directory System.Data.SQLite.dll]] - - # - # NOTE: The default list of application files includes the test application - # itself, the System.Data.SQLite managed assembly, the SQLite interop - # assembly, and the test application configuration file. - # - 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]] - } - - # - # NOTE: Setup the directory on the target device where the application files - # should be deployed to. - # - if {![info exists device_directory]} then { - set device_directory "\\Program Files\\testce\\" - } - - # - # NOTE: Load the managed assembly that allows us to communicate with the - # target device. If this fails, the necessary SDK components are - # probably not available on this system. - # - # NOTE: As of Visual Studio 2013 Update 2 (?), this must specify the full - # (versioned) assembly name here in order to make sure the assembly - # associated with the Pocket PC 2003 platform(s) gets loaded. - # - object load [appendArgs \ - "Microsoft.Smartdevice.Connectivity, Version=9.0.0.0, " \ - "Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"] - - # - # NOTE: Show the full list of available platforms. - # - showPlatforms $cultureInfo - - # - # NOTE: Lookup the necessary device based on the platform and device Ids. - # - set device [getDevice $cultureInfo $platformId $deviceId] - - # - # NOTE: Attempt to connect to the target device, which may be an emulator. - # By default, we attempt to connect to the "Pocket PC 2003 SE Emulator" - # device of the "Pocket PC 2003" platform (English). If this fails, - # the target device is probably unavailable, either because it is not - # connected or some SDK components are missing. - # - $device Connect - - # - # NOTE: Grab the file deployer instance for the target device. This will - # 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 application file to be sent to the target device. - # - foreach fileName $fileNames { - qputs stdout [appendArgs \ - "sending file \"" $fileName "\" to device..."] - - # - # NOTE: All the application files are sent to the same directory on the - # target device and the SendFile method requires a fully qualified - # file name; therefore, grab the file name only from the source file - # name and append that to the directory name on the target device. - # Using [file join] and/or [file normalize] should be avoided here - # because the directory name on the target device is not necessarily - # valid a file name on this system and vice versa. - # - $fileDeployer SendFile $fileName [appendArgs $device_directory \ - [file tail $fileName]] true false - } - - # - # NOTE: Run the test application on the target device in "automatic" mode - # (i.e. no user interaction is required) and capture the exit code. - # The exit code will be zero upon success (i.e. all tests passed) or - # non-zero otherwise. - # - set testFileName [file nativename [file join $device_directory testce.exe]] - set exitCode [startRemoteProcess $device $testFileName true] - - # - # NOTE: Is the target device actually an emulator running on this system? - # - set isEmulator [$device IsEmulator] - - # - # NOTE: We no longer need to be connected to the target device. - # - $device Disconnect - - # - # NOTE: Also, if the device is an emulator, attempt to shutdown the process - # containing it now (since we probably caused it to start). - # - if {$isEmulator} then { - # - # NOTE: Try to find the top-level window for the device emulator process - # based on the "LCDDisplay" window class name. Using this method - # of finding the target window is somewhat fragile and may not work - # reliably in the future. - # - set hWnd [lindex [lindex [info windows LCDDisplay] 0] 0]; # FIXME: ??? - - # - # NOTE: Make sure we found it before trying to lookup the parent process. - # - if {[string is integer -strict $hWnd] && $hWnd != 0} then { - # - # NOTE: Attempt to lookup the parent process for the target window. - # - qputs stdout [appendArgs "found device emulator window handle " $hWnd \ - ", looking up the process Id..."] - - set processId 0; set threadId 0; set error null - - if {[object invoke -flags +NonPublic \ - Eagle._Components.Private.WindowOps GetWindowThreadProcessId \ - [object create IntPtr $hWnd] processId threadId error] eq "Ok" && \ - [string is integer -strict $processId] && $processId != 0} then { - # - # NOTE: This is not ideal; however, if we simply try to close the - # target window, it will prompt to save state changes and that - # requires user interaction. We never want to save the state; - # therefore, just forcibly kill the process containing the - # emulator. - # - qputs stdout [appendArgs "found device emulator process Id " \ - $processId ", killing..."] - - kill -force $processId - } - } - } - - # - # NOTE: Print the overall result of running the test application and exit - # using the exit code from the test application on the target device. - # - qputs stdout [expr {$exitCode == 0 ? "SUCCESS" : "FAILURE"}] - exit $exitCode -} else { - usage "" -} Index: Setup/release.bat ================================================================== --- Setup/release.bat +++ Setup/release.bat @@ -168,25 +168,25 @@ IF DEFINED BASE_CONFIGURATIONSUFFIX ( FOR /F "delims=" %%F IN ('DIR /B /S /AD "bin\%YEAR%\%BASE_CONFIGURATION%%BASE_CONFIGURATIONSUFFIX%\bin" 2^> NUL') DO ( %__ECHO% RMDIR /S /Q "%%F" ) - %__ECHO% zip.exe -v -j -r "Setup\Output\sqlite-%FRAMEWORK%-%TYPE%-%BASE_PLATFORM%%EXTRA_PLATFORM%-%YEAR%-%VERSION%.zip" "bin\%YEAR%\%BASE_CONFIGURATION%%BASE_CONFIGURATIONSUFFIX%\bin" -x @data\exclude_bin.txt + %__ECHO% zip.exe -v -j -r "Setup\Output\sqlite-%FRAMEWORK%-%TYPE%-%BASE_PLATFORM%%EXTRA_PLATFORM%-%YEAR%-%VERSION%.zip" "bin\%YEAR%\%BASE_CONFIGURATION%%BASE_CONFIGURATIONSUFFIX%\bin" -x @exclude_bin.txt ) ELSE ( FOR /F "delims=" %%F IN ('DIR /B /S /AD "bin\%YEAR%\%BASE_CONFIGURATION%\bin" 2^> NUL') DO ( %__ECHO% RMDIR /S /Q "%%F" ) - %__ECHO% zip.exe -v -j -r "Setup\Output\sqlite-%FRAMEWORK%-%TYPE%-%BASE_PLATFORM%%EXTRA_PLATFORM%-%YEAR%-%VERSION%.zip" "bin\%YEAR%\%BASE_CONFIGURATION%\bin" -x @data\exclude_bin.txt + %__ECHO% zip.exe -v -j -r "Setup\Output\sqlite-%FRAMEWORK%-%TYPE%-%BASE_PLATFORM%%EXTRA_PLATFORM%-%YEAR%-%VERSION%.zip" "bin\%YEAR%\%BASE_CONFIGURATION%\bin" -x @exclude_bin.txt ) IF /I "%CONFIGURATION%" == "%BASE_CONFIGURATION%" ( IF NOT DEFINED BASE_CONFIGURATIONSUFFIX ( %__ECHO% zip -v -d "Setup\Output\sqlite-%FRAMEWORK%-%TYPE%-%BASE_PLATFORM%%EXTRA_PLATFORM%-%YEAR%-%VERSION%.zip" SQLite.Interop.* ) ) -%__ECHO% zip.exe -v -j -r "Setup\Output\sqlite-%FRAMEWORK%-%TYPE%-%BASE_PLATFORM%%EXTRA_PLATFORM%-%YEAR%-%VERSION%.zip" "bin\%YEAR%\%PLATFORM%\%CONFIGURATION%%CONFIGURATIONSUFFIX%" -x @data\exclude_bin.txt +%__ECHO% zip.exe -v -j -r "Setup\Output\sqlite-%FRAMEWORK%-%TYPE%-%BASE_PLATFORM%%EXTRA_PLATFORM%-%YEAR%-%VERSION%.zip" "bin\%YEAR%\%PLATFORM%\%CONFIGURATION%%CONFIGURATIONSUFFIX%" -x @exclude_bin.txt IF ERRORLEVEL 1 ( ECHO Failed to archive binary files. GOTO errors ) DELETED Setup/set_Debug.bat Index: Setup/set_Debug.bat ================================================================== --- Setup/set_Debug.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -REM SET MSBUILD_ARGS=/p:TargetFrameworkVersion=v3.5 /p:PlatformToolset=v100 DELETED Setup/set_DebugNativeOnly.bat Index: Setup/set_DebugNativeOnly.bat ================================================================== --- Setup/set_DebugNativeOnly.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -REM SET MSBUILD_ARGS=/property:TargetFrameworkVersion=v3.5 DELETED Setup/set_DebugNativeOnly_ARMV7.bat Index: Setup/set_DebugNativeOnly_ARMV7.bat ================================================================== --- Setup/set_DebugNativeOnly_ARMV7.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_ARMV7.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_DebugNativeOnly.bat" DELETED Setup/set_DebugNativeOnly_CEPC DevPlatform.bat Index: Setup/set_DebugNativeOnly_CEPC DevPlatform.bat ================================================================== --- Setup/set_DebugNativeOnly_CEPC DevPlatform.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_CEPC DevPlatform.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_DebugNativeOnly.bat" DELETED Setup/set_DebugNativeOnly_Pocket PC 2003 (ARMV4).bat Index: Setup/set_DebugNativeOnly_Pocket PC 2003 (ARMV4).bat ================================================================== --- Setup/set_DebugNativeOnly_Pocket PC 2003 (ARMV4).bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_Pocket PC 2003 (ARMV4).bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_DebugNativeOnly.bat" DELETED Setup/set_DebugNativeOnly_Win32.bat Index: Setup/set_DebugNativeOnly_Win32.bat ================================================================== --- Setup/set_DebugNativeOnly_Win32.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_Win32.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_DebugNativeOnly.bat" DELETED Setup/set_DebugNativeOnly_x64.bat Index: Setup/set_DebugNativeOnly_x64.bat ================================================================== --- Setup/set_DebugNativeOnly_x64.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x64.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_DebugNativeOnly.bat" DELETED Setup/set_DebugNativeOnly_x64_2005.bat Index: Setup/set_DebugNativeOnly_x64_2005.bat ================================================================== --- Setup/set_DebugNativeOnly_x64_2005.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x64_2005.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x64_2005.bat" DELETED Setup/set_DebugNativeOnly_x64_2008.bat Index: Setup/set_DebugNativeOnly_x64_2008.bat ================================================================== --- Setup/set_DebugNativeOnly_x64_2008.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x64_2008.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x64_2008.bat" DELETED Setup/set_DebugNativeOnly_x64_2010.bat Index: Setup/set_DebugNativeOnly_x64_2010.bat ================================================================== --- Setup/set_DebugNativeOnly_x64_2010.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x64_2010.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x64_2010.bat" DELETED Setup/set_DebugNativeOnly_x64_2012.bat Index: Setup/set_DebugNativeOnly_x64_2012.bat ================================================================== --- Setup/set_DebugNativeOnly_x64_2012.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x64_2012.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x64_2012.bat" DELETED Setup/set_DebugNativeOnly_x64_2013.bat Index: Setup/set_DebugNativeOnly_x64_2013.bat ================================================================== --- Setup/set_DebugNativeOnly_x64_2013.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x64_2013.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x64_2013.bat" DELETED Setup/set_DebugNativeOnly_x86_2005.bat Index: Setup/set_DebugNativeOnly_x86_2005.bat ================================================================== --- Setup/set_DebugNativeOnly_x86_2005.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x86_2005.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x86_2005.bat" DELETED Setup/set_DebugNativeOnly_x86_2008.bat Index: Setup/set_DebugNativeOnly_x86_2008.bat ================================================================== --- Setup/set_DebugNativeOnly_x86_2008.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x86_2008.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x86_2008.bat" DELETED Setup/set_DebugNativeOnly_x86_2010.bat Index: Setup/set_DebugNativeOnly_x86_2010.bat ================================================================== --- Setup/set_DebugNativeOnly_x86_2010.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x86_2010.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x86_2010.bat" DELETED Setup/set_DebugNativeOnly_x86_2012.bat Index: Setup/set_DebugNativeOnly_x86_2012.bat ================================================================== --- Setup/set_DebugNativeOnly_x86_2012.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x86_2012.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x86_2012.bat" DELETED Setup/set_DebugNativeOnly_x86_2013.bat Index: Setup/set_DebugNativeOnly_x86_2013.bat ================================================================== --- Setup/set_DebugNativeOnly_x86_2013.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_DebugNativeOnly_x86_2013.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=DebugNativeOnly -CALL "%~dp0\set_x86_2013.bat" DELETED Setup/set_Debug_ARMV7.bat Index: Setup/set_Debug_ARMV7.bat ================================================================== --- Setup/set_Debug_ARMV7.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_ARMV7.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_Debug.bat" DELETED Setup/set_Debug_CEPC DevPlatform.bat Index: Setup/set_Debug_CEPC DevPlatform.bat ================================================================== --- Setup/set_Debug_CEPC DevPlatform.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_CEPC DevPlatform.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_Debug.bat" DELETED Setup/set_Debug_Pocket PC 2003 (ARMV4).bat Index: Setup/set_Debug_Pocket PC 2003 (ARMV4).bat ================================================================== --- Setup/set_Debug_Pocket PC 2003 (ARMV4).bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_Pocket PC 2003 (ARMV4).bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_Debug.bat" DELETED Setup/set_Debug_Win32.bat Index: Setup/set_Debug_Win32.bat ================================================================== --- Setup/set_Debug_Win32.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_Win32.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_Debug.bat" DELETED Setup/set_Debug_x64.bat Index: Setup/set_Debug_x64.bat ================================================================== --- Setup/set_Debug_x64.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x64.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -CALL "%~dp0\set_Debug.bat" DELETED Setup/set_Debug_x64_2005.bat Index: Setup/set_Debug_x64_2005.bat ================================================================== --- Setup/set_Debug_x64_2005.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x64_2005.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x64_2005.bat" DELETED Setup/set_Debug_x64_2008.bat Index: Setup/set_Debug_x64_2008.bat ================================================================== --- Setup/set_Debug_x64_2008.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x64_2008.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x64_2008.bat" DELETED Setup/set_Debug_x64_2010.bat Index: Setup/set_Debug_x64_2010.bat ================================================================== --- Setup/set_Debug_x64_2010.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x64_2010.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x64_2010.bat" DELETED Setup/set_Debug_x64_2012.bat Index: Setup/set_Debug_x64_2012.bat ================================================================== --- Setup/set_Debug_x64_2012.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x64_2012.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x64_2012.bat" DELETED Setup/set_Debug_x64_2013.bat Index: Setup/set_Debug_x64_2013.bat ================================================================== --- Setup/set_Debug_x64_2013.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x64_2013.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x64_2013.bat" DELETED Setup/set_Debug_x86_2005.bat Index: Setup/set_Debug_x86_2005.bat ================================================================== --- Setup/set_Debug_x86_2005.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x86_2005.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x86_2005.bat" DELETED Setup/set_Debug_x86_2008.bat Index: Setup/set_Debug_x86_2008.bat ================================================================== --- Setup/set_Debug_x86_2008.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x86_2008.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x86_2008.bat" DELETED Setup/set_Debug_x86_2010.bat Index: Setup/set_Debug_x86_2010.bat ================================================================== --- Setup/set_Debug_x86_2010.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x86_2010.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x86_2010.bat" DELETED Setup/set_Debug_x86_2012.bat Index: Setup/set_Debug_x86_2012.bat ================================================================== --- Setup/set_Debug_x86_2012.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x86_2012.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x86_2012.bat" DELETED Setup/set_Debug_x86_2013.bat Index: Setup/set_Debug_x86_2013.bat ================================================================== --- Setup/set_Debug_x86_2013.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -:: -:: set_Debug_x86_2013.bat -- -:: -:: Written by Joe Mistachkin. -:: Released to the public domain, use at your own risk! -:: - -SET CONFIGURATION=Debug -CALL "%~dp0\set_x86_2013.bat" Index: Setup/set_common.bat ================================================================== --- Setup/set_common.bat +++ Setup/set_common.bat @@ -18,39 +18,23 @@ IF NOT DEFINED PUBLICKEY ( SET PUBLICKEY=db937bc2d44ff139 ) IF NOT DEFINED BUILD_CONFIGURATIONS ( - IF DEFINED BUILD_DEBUG ( - SET BUILD_CONFIGURATIONS=Debug DebugNativeOnly Release ReleaseNativeOnly - ) ELSE ( - SET BUILD_CONFIGURATIONS=Release ReleaseNativeOnly - ) + SET BUILD_CONFIGURATIONS=Debug DebugNativeOnly Release ReleaseNativeOnly ) IF NOT DEFINED TEST_CONFIGURATIONS ( - IF DEFINED TEST_DEBUG ( - SET TEST_CONFIGURATIONS=Debug Release - ) ELSE ( - SET TEST_CONFIGURATIONS=Release - ) + SET TEST_CONFIGURATIONS=Debug Release ) IF NOT DEFINED BAKE_CONFIGURATIONS ( - IF DEFINED BAKE_DEBUG ( - SET BAKE_CONFIGURATIONS=Debug DebugNativeOnly Release ReleaseNativeOnly - ) ELSE ( - SET BAKE_CONFIGURATIONS=Release ReleaseNativeOnly - ) + SET BAKE_CONFIGURATIONS=Release ReleaseNativeOnly ) IF NOT DEFINED RELEASE_CONFIGURATIONS ( - IF DEFINED RELEASE_DEBUG ( - SET RELEASE_CONFIGURATIONS=Debug DebugNativeOnly Release ReleaseNativeOnly - ) ELSE ( - SET RELEASE_CONFIGURATIONS=Release ReleaseNativeOnly - ) + SET RELEASE_CONFIGURATIONS=Release ReleaseNativeOnly ) IF NOT DEFINED PLATFORMS ( SET PLATFORMS=Win32 x64 ) Index: Setup/set_netFx451.bat ================================================================== --- Setup/set_netFx451.bat +++ Setup/set_netFx451.bat @@ -10,11 +10,11 @@ IF NOT DEFINED ISNETFX2 ( SET ISNETFX2=False ) IF NOT DEFINED VCRUNTIME ( - SET VCRUNTIME=2013_VSU2 + SET VCRUNTIME=2013_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 @@ -13,9 +13,8 @@ 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:TraceDetection=true SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TraceHandle=true SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TraceStatement=true SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TrackMemoryBytes=true Index: Setup/set_x64_2013.bat ================================================================== --- Setup/set_x64_2013.bat +++ Setup/set_x64_2013.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=False -SET VCRUNTIME=2013_VSU2 +SET VCRUNTIME=2013_RTM SET PLATFORM=x64 SET PROCESSOR=x64 SET YEAR=2013 Index: Setup/set_x86_2013.bat ================================================================== --- Setup/set_x86_2013.bat +++ Setup/set_x86_2013.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=False -SET VCRUNTIME=2013_VSU2 +SET VCRUNTIME=2013_RTM SET PLATFORM=Win32 SET PROCESSOR=x86 SET YEAR=2013 Index: Setup/test_ce_200x.bat ================================================================== --- Setup/test_ce_200x.bat +++ Setup/test_ce_200x.bat @@ -98,11 +98,11 @@ %_VECHO% EagleShell = '%EAGLESHELL%' FOR %%C IN (%TEST_CONFIGURATIONS%) DO ( FOR %%P IN (%PLATFORMS%) DO ( FOR %%Y IN (%YEARS%) DO ( - %__ECHO% "%EAGLESHELL%" -file "%TOOLS%\deployAndTestCe200x.eagle" %%Y %%P %%C + %__ECHO% "%EAGLESHELL%" -file "%TOOLS%\deployAndTestCe.eagle" %%Y %%P %%C IF ERRORLEVEL 1 ( ECHO Tests failed for %%C/%%P/%%Y binaries. GOTO errors ) Index: Setup/verify.eagle ================================================================== --- Setup/verify.eagle +++ Setup/verify.eagle @@ -88,17 +88,10 @@ major minor build revision regexp -- {(\d{4})-(\d{2})-(\d{2})-(\d{2})} $manifest \ dummy year month day sequence - # - # HACK: Attempt to match and remove sub-strings from the - # manifest file name that look like the name of a - # build configuration (e.g. "debug" or "release"). - # - regsub -- {-debug-|-release-} $manifest {-} manifest - # # HACK: Attempt to match and remove sub-strings from the # manifest file name that look like a version number # in the format "..." # and/or a date/time string matching the format Index: Setup/verify.lst ================================================================== --- Setup/verify.lst +++ Setup/verify.lst @@ -14,13 +14,10 @@ # # NOTE: This is the list of all files that should be present in the standard # source code archive. # set sds_manifests(source) { - data/ - data/exclude_bin.txt - data/exclude_src.txt Doc/ Doc/buildChm.tcl Doc/Extra/ Doc/Extra/Core/ Doc/Extra/Core/images/ @@ -141,43 +138,31 @@ Doc/Extra/Provider/welcome.html Doc/SQLite.NET.chm Doc/SQLite.NET.hhc Doc/SQLite.NET.hhp Doc/SQLite.NET.ndoc + exclude_bin.txt + exclude_src.txt Externals/ Externals/Eagle/ Externals/Eagle/bin/ Externals/Eagle/bin/EagleShell.exe.config Externals/Eagle/bin/EagleShell.exe.mda.config Externals/Eagle/lib/ Externals/Eagle/lib/Eagle1.0/ Externals/Eagle/lib/Eagle1.0/vendor.eagle Externals/Eagle/lib/Test1.0/ - Keys/ - Keys/System.Data.SQLite.CF.snk - Keys/System.Data.SQLite.snk NuGet/ NuGet/net20/ - NuGet/net20/Core/ - NuGet/net20/Core/config.transform - NuGet/net20/Core/install.ps1 + NuGet/net20/config.transform + NuGet/net20/install.ps1 NuGet/net40/ - NuGet/net40/Core/ - NuGet/net40/Core/config.transform - NuGet/net40/Core/install.ps1 - NuGet/net40/EF6/ - NuGet/net40/EF6/config.transform - NuGet/net40/EF6/install.ps1 - NuGet/net40/EF6/provider.ps1 + NuGet/net40/config.transform + NuGet/net40/install.ps1 NuGet/SQLite.Beta.nuspec - NuGet/SQLite.Core.nuspec - NuGet/SQLite.Core.MSIL.nuspec - NuGet/SQLite.EF6.nuspec - NuGet/SQLite.Linq.nuspec NuGet/SQLite.MSIL.nuspec NuGet/SQLite.nuspec - NuGet/SQLite.Test.nuspec NuGet/SQLite.x64.nuspec NuGet/SQLite.x86.nuspec readme.htm Setup/ Setup/archive.bat @@ -187,11 +172,11 @@ Setup/build_all.bat Setup/build_ce_200x.bat Setup/build_ce_2013.bat Setup/CheckForNetFx.pas Setup/clean.bat - Setup/deployAndTestCe200x.eagle + Setup/deployAndTestCe.eagle Setup/InitializeSetup.pas Setup/release.bat Setup/release_all.bat Setup/release_ce_200x.bat Setup/release_ce_2013.bat @@ -200,42 +185,10 @@ Setup/set_2008.bat Setup/set_2010.bat Setup/set_2012.bat Setup/set_2013.bat Setup/set_common.bat - Setup/set_Debug.bat - Setup/set_DebugNativeOnly.bat - "Setup/set_DebugNativeOnly_CEPC DevPlatform.bat" - "Setup/set_DebugNativeOnly_Pocket PC 2003 (ARMV4).bat" - "Setup/set_DebugNativeOnly_ARMV7.bat" - Setup/set_DebugNativeOnly_Win32.bat - Setup/set_DebugNativeOnly_x64.bat - Setup/set_DebugNativeOnly_x64_2005.bat - Setup/set_DebugNativeOnly_x64_2008.bat - Setup/set_DebugNativeOnly_x64_2010.bat - Setup/set_DebugNativeOnly_x64_2012.bat - Setup/set_DebugNativeOnly_x64_2013.bat - Setup/set_DebugNativeOnly_x86_2005.bat - Setup/set_DebugNativeOnly_x86_2008.bat - Setup/set_DebugNativeOnly_x86_2010.bat - Setup/set_DebugNativeOnly_x86_2012.bat - Setup/set_DebugNativeOnly_x86_2013.bat - "Setup/set_Debug_CEPC DevPlatform.bat" - "Setup/set_Debug_Pocket PC 2003 (ARMV4).bat" - "Setup/set_Debug_ARMV7.bat" - Setup/set_Debug_Win32.bat - Setup/set_Debug_x64.bat - Setup/set_Debug_x64_2005.bat - Setup/set_Debug_x64_2008.bat - Setup/set_Debug_x64_2010.bat - Setup/set_Debug_x64_2012.bat - Setup/set_Debug_x64_2013.bat - Setup/set_Debug_x86_2005.bat - Setup/set_Debug_x86_2008.bat - Setup/set_Debug_x86_2010.bat - Setup/set_Debug_x86_2012.bat - Setup/set_Debug_x86_2013.bat Setup/set_netFx20.bat Setup/set_netFx35.bat Setup/set_netFx40.bat Setup/set_netFx45.bat Setup/set_netFx451.bat @@ -422,37 +375,35 @@ SQLite.NET.2012.Compact.sln SQLite.NET.2012.MSBuild.sln SQLite.NET.2012.sln SQLite.NET.2013.MSBuild.sln SQLite.NET.2013.sln + SQLite.NET.Settings.targets + SQLite.NET.Settings.targets.netFx35 + SQLite.NET.targets System.Data.SQLite/ System.Data.SQLite/AssemblyInfo.cs System.Data.SQLite/AssemblySourceIdAttribute.cs System.Data.SQLite/AssemblySourceTimeStampAttribute.cs - System.Data.SQLite/Configurations/ - System.Data.SQLite/Configurations/System.Data.SQLite.dll.config + System.Data.SQLite/DataTypes.xml System.Data.SQLite/LINQ/ System.Data.SQLite/LINQ/SQLiteConnection_Linq.cs System.Data.SQLite/LINQ/SQLiteFactory_Linq.cs - System.Data.SQLite/Resources/ - System.Data.SQLite/Resources/DataTypes.xml - System.Data.SQLite/Resources/MetaDataCollections.xml - System.Data.SQLite/Resources/SQLiteCommand.bmp - System.Data.SQLite/Resources/SQLiteConnection.bmp - System.Data.SQLite/Resources/SQLiteDataAdapter.bmp - System.Data.SQLite/Resources/SR.Designer.cs - System.Data.SQLite/Resources/SR.resx + System.Data.SQLite/MetaDataCollections.xml System.Data.SQLite/SQLite3.cs System.Data.SQLite/SQLite3_UTF16.cs System.Data.SQLite/SQLiteBackup.cs System.Data.SQLite/SQLiteBase.cs + System.Data.SQLite/SQLiteCommand.bmp System.Data.SQLite/SQLiteCommand.cs System.Data.SQLite/SQLiteCommandBuilder.cs + System.Data.SQLite/SQLiteConnection.bmp System.Data.SQLite/SQLiteConnection.cs System.Data.SQLite/SQLiteConnectionPool.cs System.Data.SQLite/SQLiteConnectionStringBuilder.cs System.Data.SQLite/SQLiteConvert.cs + System.Data.SQLite/SQLiteDataAdapter.bmp System.Data.SQLite/SQLiteDataAdapter.cs System.Data.SQLite/SQLiteDataReader.cs System.Data.SQLite/SQLiteDefineConstants.cs System.Data.SQLite/SQLiteEnlistment.cs System.Data.SQLite/SQLiteException.cs @@ -468,27 +419,31 @@ System.Data.SQLite/SQLiteParameter.cs System.Data.SQLite/SQLiteParameterCollection.cs System.Data.SQLite/SQLitePatchLevel.cs System.Data.SQLite/SQLiteStatement.cs System.Data.SQLite/SQLiteTransaction.cs + System.Data.SQLite/SR.Designer.cs + System.Data.SQLite/SR.resx System.Data.SQLite/System.Data.SQLite.2005.csproj System.Data.SQLite/System.Data.SQLite.2008.csproj System.Data.SQLite/System.Data.SQLite.2010.csproj System.Data.SQLite/System.Data.SQLite.2012.csproj System.Data.SQLite/System.Data.SQLite.2013.csproj + System.Data.SQLite/System.Data.SQLite.CF.snk System.Data.SQLite/System.Data.SQLite.Compact.2005.csproj System.Data.SQLite/System.Data.SQLite.Compact.2008.csproj System.Data.SQLite/System.Data.SQLite.Compact.2012.csproj + System.Data.SQLite/System.Data.SQLite.Files.targets System.Data.SQLite/System.Data.SQLite.Module.2005.csproj System.Data.SQLite/System.Data.SQLite.Module.2008.csproj System.Data.SQLite/System.Data.SQLite.Module.2010.csproj System.Data.SQLite/System.Data.SQLite.Module.2012.csproj System.Data.SQLite/System.Data.SQLite.Module.2013.csproj - System.Data.SQLite/Targets/ - System.Data.SQLite/Targets/System.Data.SQLite.Files.targets - System.Data.SQLite/Targets/System.Data.SQLite.Properties.targets - System.Data.SQLite/Targets/System.Data.SQLite.References.targets + System.Data.SQLite/System.Data.SQLite.Properties.targets + System.Data.SQLite/System.Data.SQLite.References.targets + System.Data.SQLite/System.Data.SQLite.dll.config + System.Data.SQLite/System.Data.SQLite.snk System.Data.SQLite/UnsafeNativeMethods.cs System.Data.SQLite.Linq/ System.Data.SQLite.Linq/AssemblyInfo.cs System.Data.SQLite.Linq/Properties/ System.Data.SQLite.Linq/Properties/Resources.Designer.cs @@ -535,14 +490,10 @@ System.Data.SQLite.Linq/System.Data.SQLite.EF6.2013.csproj System.Data.SQLite.Linq/System.Data.SQLite.Linq.2008.csproj System.Data.SQLite.Linq/System.Data.SQLite.Linq.2010.csproj System.Data.SQLite.Linq/System.Data.SQLite.Linq.2012.csproj System.Data.SQLite.Linq/System.Data.SQLite.Linq.2013.csproj - Targets/ - Targets/SQLite.NET.Settings.targets - Targets/SQLite.NET.Settings.targets.netFx35 - Targets/SQLite.NET.targets test/ test/app.config test/AssemblyInfo.cs test/Program.cs test/Properties/ @@ -629,11 +580,10 @@ Tests/Installer_Test_Vs2010.log Tests/Installer_Test_Vs2012.log Tests/Installer_Test_Vs2013.log Tests/nonWal.db Tests/pkgIndex.eagle - Tests/speed.eagle Tests/stress.eagle Tests/testlinq.out Tests/thread.eagle Tests/tkt-00f86f9739.eagle Tests/tkt-0d5b1ef362.eagle @@ -645,11 +595,10 @@ Tests/tkt-3113734605.eagle Tests/tkt-343d392b51.eagle Tests/tkt-3567020edf.eagle Tests/tkt-393d954be0.eagle Tests/tkt-3aa50d8413.eagle - Tests/tkt-3c00ec5b52.eagle Tests/tkt-448d663d11.eagle Tests/tkt-47f4bac575.eagle Tests/tkt-48a6b8e4ca.eagle Tests/tkt-4a791e70ab.eagle Tests/tkt-544dba0a2f.eagle @@ -670,11 +619,10 @@ Tests/tkt-ae5267b863.eagle Tests/tkt-b4a7ddc83f.eagle Tests/tkt-bb4b04d457.eagle Tests/tkt-c010fa6584.eagle Tests/tkt-ccfa69fc32.eagle - Tests/tkt-da9f18d039.eagle Tests/tkt-e06c4caff3.eagle Tests/tkt-e1b2e0f769.eagle Tests/tkt-e30b820248.eagle Tests/tkt-e47b3d8346.eagle Tests/tkt-ef2216192d.eagle @@ -967,20 +915,20 @@ # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 4.5.1 for x86. # set sds_manifests(setupX86Vs2013) { - {{tmp}\vcredist_x86_2013_VSU2.exe} + {{tmp}\vcredist_x86_2013_RTM.exe} } ############################################################################### # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 4.5.1 for x64. # set sds_manifests(setupX64Vs2013) { - {{tmp}\vcredist_x64_2013_VSU2.exe} + {{tmp}\vcredist_x64_2013_RTM.exe} } ############################################################################### # # NOTE: These are the master archive manifest groups, based on file name. The Index: System.Data.SQLite.Linq/AssemblyInfo.cs ================================================================== --- System.Data.SQLite.Linq/AssemblyInfo.cs +++ System.Data.SQLite.Linq/AssemblyInfo.cs @@ -51,7 +51,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.93.0")] -[assembly: AssemblyFileVersion("1.0.93.0")] +[assembly: AssemblyVersion("1.0.91.0")] +[assembly: AssemblyFileVersion("1.0.91.0")] Index: System.Data.SQLite.Linq/SQL Generation/SqlGenerator.cs ================================================================== --- System.Data.SQLite.Linq/SQL Generation/SqlGenerator.cs +++ System.Data.SQLite.Linq/SQL Generation/SqlGenerator.cs @@ -887,11 +887,11 @@ case PrimitiveTypeKind.Byte: result.Append(e.Value.ToString()); break; case PrimitiveTypeKind.DateTime: - result.Append(EscapeSingleQuote(SQLiteConvert.ToString((System.DateTime)e.Value, SQLiteDateFormats.ISO8601, DateTimeKind.Unspecified, null), false /* IsUnicode */)); + result.Append(EscapeSingleQuote(((System.DateTime)e.Value).ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture), false /* IsUnicode */)); break; case PrimitiveTypeKind.Decimal: string strDecimal = ((Decimal)e.Value).ToString(CultureInfo.InvariantCulture); // if the decimal value has no decimal part, cast as decimal to preserve type Index: System.Data.SQLite.Linq/SQLiteProviderFactory.cs ================================================================== --- System.Data.SQLite.Linq/SQLiteProviderFactory.cs +++ System.Data.SQLite.Linq/SQLiteProviderFactory.cs @@ -12,19 +12,14 @@ #endif { using System; using System.Data.Common; -#if USE_ENTITY_FRAMEWORK_6 - using System.Data.Entity.Core.Common; -#endif - /// /// SQLite implementation of . /// - public sealed class SQLiteProviderFactory : - DbProviderFactory, IServiceProvider, IDisposable + public sealed class SQLiteProviderFactory : DbProviderFactory, IDisposable { #region Public Static Data /// /// Static instance member which returns an instanced /// class. @@ -116,37 +111,10 @@ public override DbParameter CreateParameter() { CheckDisposed(); return new SQLiteParameter(); } - #endregion - - /////////////////////////////////////////////////////////////////////// - - #region IServiceProvider Members - /// - /// Gets the service object of the specified type. - /// - /// - /// An object that specifies the type of service object to get. - /// - /// - /// A service object of type serviceType -OR- a null reference if - /// there is no service object of type serviceType. - /// - public object GetService( - Type serviceType - ) - { - if ((serviceType == typeof(ISQLiteSchemaExtensions)) || - (serviceType == typeof(DbProviderServices))) - { - return SQLiteProviderServices.Instance; - } - - return null; - } #endregion /////////////////////////////////////////////////////////////////////// #region IDisposable Members Index: System.Data.SQLite.Linq/SQLiteProviderServices.cs ================================================================== --- System.Data.SQLite.Linq/SQLiteProviderServices.cs +++ System.Data.SQLite.Linq/SQLiteProviderServices.cs @@ -330,11 +330,11 @@ /// be able to query on schema tables. Therefore we need to "fake" it by generating temporary tables /// filled with the schema of the current connection. We get away with making this information static /// because schema information seems to always be queried on a new connection object, so the schema is /// always fresh. /// - /// The connection upon which to build the schema tables. + /// The connection upon which to build the schema tables void ISQLiteSchemaExtensions.BuildTempSchema(SQLiteConnection cnn) { string[] arr = new string[] { "TABLES", "COLUMNS", "VIEWS", "VIEWCOLUMNS", "INDEXES", "INDEXCOLUMNS", "FOREIGNKEYS", "CATALOGS" }; using (DataTable table = cnn.GetSchema("Tables", new string[] { "temp", null, String.Format("SCHEMA{0}", arr[0]) })) Index: System.Data.SQLite.Linq/System.Data.SQLite.Core.2010.csproj ================================================================== --- System.Data.SQLite.Linq/System.Data.SQLite.Core.2010.csproj +++ System.Data.SQLite.Linq/System.Data.SQLite.Core.2010.csproj @@ -25,11 +25,11 @@ Client $(MSBuildProjectDirectory)\.. true 2010 - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.Linq.xml $(BinaryOutputPath)System.Data.SQLite.EF6.xml @@ -118,15 +118,15 @@ {AC139952-261A-4463-B6FA-AEBC25283A66} System.Data.SQLite.2010 - + Index: System.Data.SQLite.Linq/System.Data.SQLite.Core.2012.csproj ================================================================== --- System.Data.SQLite.Linq/System.Data.SQLite.Core.2012.csproj +++ System.Data.SQLite.Linq/System.Data.SQLite.Core.2012.csproj @@ -23,11 +23,11 @@ $(MSBuildProjectDirectory)\.. true 2012 v4.5 - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.Linq.xml $(BinaryOutputPath)System.Data.SQLite.EF6.xml @@ -116,15 +116,15 @@ {AC139952-261A-4463-B6FA-AEBC25283A66} System.Data.SQLite.2012 - + Index: System.Data.SQLite.Linq/System.Data.SQLite.Core.2013.csproj ================================================================== --- System.Data.SQLite.Linq/System.Data.SQLite.Core.2013.csproj +++ System.Data.SQLite.Linq/System.Data.SQLite.Core.2013.csproj @@ -23,11 +23,11 @@ $(MSBuildProjectDirectory)\.. true 2013 v4.5.1 - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.Linq.xml $(BinaryOutputPath)System.Data.SQLite.EF6.xml @@ -116,15 +116,15 @@ {AC139952-261A-4463-B6FA-AEBC25283A66} System.Data.SQLite.2013 - + Index: System.Data.SQLite.Linq/System.Data.SQLite.EF6.2010.csproj ================================================================== --- System.Data.SQLite.Linq/System.Data.SQLite.EF6.2010.csproj +++ System.Data.SQLite.Linq/System.Data.SQLite.EF6.2010.csproj Index: System.Data.SQLite.Linq/System.Data.SQLite.Linq.2008.csproj ================================================================== --- System.Data.SQLite.Linq/System.Data.SQLite.Linq.2008.csproj +++ System.Data.SQLite.Linq/System.Data.SQLite.Linq.2008.csproj @@ -21,11 +21,11 @@ 2.0 $(MSBuildProjectDirectory)\.. true 2008 - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.Linq.xml @@ -101,15 +101,15 @@ {AC139952-261A-4463-B6FA-AEBC25283A66} System.Data.SQLite.2008 - + Index: System.Data.SQLite/AssemblyInfo.cs ================================================================== --- System.Data.SQLite/AssemblyInfo.cs +++ System.Data.SQLite/AssemblyInfo.cs @@ -70,9 +70,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.93.0")] +[assembly: AssemblyVersion("1.0.91.0")] #if !PLATFORM_COMPACTFRAMEWORK -[assembly: AssemblyFileVersion("1.0.93.0")] +[assembly: AssemblyFileVersion("1.0.91.0")] #endif DELETED System.Data.SQLite/Configurations/System.Data.SQLite.dll.config Index: System.Data.SQLite/Configurations/System.Data.SQLite.dll.config ================================================================== --- System.Data.SQLite/Configurations/System.Data.SQLite.dll.config +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ADDED System.Data.SQLite/DataTypes.xml Index: System.Data.SQLite/DataTypes.xml ================================================================== --- /dev/null +++ System.Data.SQLite/DataTypes.xml @@ -0,0 +1,806 @@ + + + + + + + smallint + 10 + 5 + System.Int16 + smallint + false + false + true + true + false + true + true + false + false + true + + + int + 11 + 10 + System.Int32 + int + false + false + true + true + false + true + true + false + false + true + + + real + 8 + 6 + System.Double + real + false + false + true + false + false + true + true + false + false + true + + + single + 15 + 7 + System.Single + single + false + false + true + false + false + true + true + false + false + true + + + float + 8 + 6 + System.Double + float + false + false + true + false + false + true + true + false + false + true + + + double + 8 + 6 + System.Double + double + false + false + true + false + false + true + true + false + false + false + + + money + 7 + 19 + System.Decimal + money + false + false + true + true + false + true + true + false + false + true + + + currency + 7 + 19 + System.Decimal + currency + false + false + true + true + false + true + true + false + false + false + + + decimal + 7 + 19 + System.Decimal + decimal + false + false + true + true + false + true + true + false + false + true + + + numeric + 7 + 19 + System.Decimal + numeric + false + false + true + true + false + true + true + false + false + false + + + bit + 3 + 1 + System.Boolean + bit + false + false + true + false + false + true + true + false + true + + + yesno + 3 + 1 + System.Boolean + yesno + false + false + true + false + false + true + true + false + false + + + logical + 3 + 1 + System.Boolean + logical + false + false + true + false + false + true + true + false + false + + + bool + 3 + 1 + System.Boolean + bool + false + false + true + false + false + true + true + false + false + + + boolean + 3 + 1 + System.Boolean + boolean + false + false + true + false + false + true + true + false + false + + + tinyint + 2 + 3 + System.Byte + tinyint + false + false + true + true + false + true + true + false + true + true + + + integer + 12 + 19 + System.Int64 + integer + true + false + true + true + false + true + true + false + false + true + + + counter + 12 + 19 + System.Int64 + counter + true + false + true + true + false + true + true + false + false + false + + + autoincrement + 12 + 19 + System.Int64 + autoincrement + true + false + true + true + false + true + true + false + false + false + + + identity + 12 + 19 + System.Int64 + identity + true + false + true + true + false + true + true + false + false + false + + + long + 12 + 19 + System.Int64 + long + true + false + true + true + false + true + true + false + false + false + + + bigint + 12 + 19 + System.Int64 + bigint + true + false + true + true + false + true + true + false + false + false + + + binary + 1 + 2147483647 + System.Byte[] + binary + false + false + false + false + false + true + false + false + X' + ' + true + + + varbinary + 1 + 2147483647 + System.Byte[] + varbinary + false + false + false + false + false + true + false + false + X' + ' + false + + + blob + 1 + 2147483647 + System.Byte[] + blob + false + false + false + false + false + true + false + false + X' + ' + false + + + image + 1 + 2147483647 + System.Byte[] + image + false + false + false + false + false + true + false + false + X' + ' + false + + + general + 1 + 2147483647 + System.Byte[] + general + false + false + false + false + false + true + false + false + X' + ' + false + + + oleobject + 1 + 2147483647 + System.Byte[] + oleobject + false + false + false + false + false + true + false + false + X' + ' + false + + + varchar + 16 + 2147483647 + max length + System.String + varchar({0}) + false + false + false + false + false + true + true + true + ' + ' + true + + + nvarchar + 16 + 2147483647 + max length + System.String + nvarchar({0}) + false + false + false + false + false + true + true + true + ' + ' + true + + + memo + 16 + 2147483647 + max length + System.String + memo({0}) + false + false + false + false + false + true + true + true + ' + ' + false + + + longtext + 16 + 2147483647 + max length + System.String + longtext({0}) + false + false + false + false + false + true + true + true + ' + ' + false + + + note + 16 + 2147483647 + max length + System.String + note({0}) + false + false + false + false + false + true + true + true + ' + ' + false + + + text + 16 + 2147483647 + max length + System.String + text({0}) + false + false + false + false + false + true + true + true + ' + ' + false + + + ntext + 16 + 2147483647 + max length + System.String + ntext({0}) + false + false + false + false + false + true + true + true + ' + ' + false + + + string + 16 + 2147483647 + max length + System.String + string({0}) + false + false + false + false + false + true + true + true + ' + ' + false + + + char + 16 + 2147483647 + max length + System.String + char({0}) + false + false + false + false + false + true + true + true + ' + ' + false + + + nchar + 16 + 2147483647 + max length + System.String + char({0}) + false + false + false + false + false + true + true + true + ' + ' + false + + + datetime + 6 + 23 + System.DateTime + datetime + false + false + true + false + false + true + true + true + ' + ' + true + + + smalldate + 6 + 23 + System.DateTime + smalldate + false + false + true + false + false + true + true + true + ' + ' + false + + + timestamp + 6 + 23 + System.DateTime + timestamp + false + false + true + false + false + true + true + true + ' + ' + false + + + date + 6 + 23 + System.DateTime + date + false + false + true + false + false + true + true + true + ' + ' + false + + + time + 6 + 23 + System.DateTime + time + false + false + true + false + false + true + true + true + ' + ' + false + + + uniqueidentifier + 4 + 16 + System.Guid + uniqueidentifier + false + false + true + false + false + true + true + false + ' + ' + true + + + guid + 4 + 16 + System.Guid + guid + false + false + true + false + false + true + true + false + ' + ' + false + + Index: System.Data.SQLite/LINQ/SQLiteFactory_Linq.cs ================================================================== --- System.Data.SQLite/LINQ/SQLiteFactory_Linq.cs +++ System.Data.SQLite/LINQ/SQLiteFactory_Linq.cs @@ -47,13 +47,13 @@ if (UnsafeNativeMethods.sqlite3_config_log_interop() == SQLiteErrorCode.Ok) { UnsafeNativeMethods.sqlite3_log( SQLiteErrorCode.Ok, SQLiteConvert.ToUTF8("logging initialized.")); } -#endif - +#else SQLiteLog.Initialize(); +#endif string version = #if NET_40 || NET_45 || NET_451 "4.0.0.0"; #else ADDED System.Data.SQLite/MetaDataCollections.xml Index: System.Data.SQLite/MetaDataCollections.xml ================================================================== --- /dev/null +++ System.Data.SQLite/MetaDataCollections.xml @@ -0,0 +1,78 @@ + + + + + + + MetaDataCollections + 0 + 0 + + + DataSourceInformation + 0 + 0 + + + DataTypes + 0 + 0 + + + ReservedWords + 0 + 0 + + + Catalogs + 1 + 1 + + + Columns + 4 + 4 + + + Indexes + 4 + 3 + + + IndexColumns + 5 + 4 + + + Tables + 4 + 3 + + + Views + 3 + 3 + + + ViewColumns + 4 + 4 + + + ForeignKeys + 4 + 3 + + + Triggers + 4 + 3 + + DELETED System.Data.SQLite/Resources/DataTypes.xml Index: System.Data.SQLite/Resources/DataTypes.xml ================================================================== --- System.Data.SQLite/Resources/DataTypes.xml +++ /dev/null @@ -1,806 +0,0 @@ - - - - - - - smallint - 10 - 5 - System.Int16 - smallint - false - false - true - true - false - true - true - false - false - true - - - int - 11 - 10 - System.Int32 - int - false - false - true - true - false - true - true - false - false - true - - - real - 8 - 6 - System.Double - real - false - false - true - false - false - true - true - false - false - true - - - single - 15 - 7 - System.Single - single - false - false - true - false - false - true - true - false - false - true - - - float - 8 - 6 - System.Double - float - false - false - true - false - false - true - true - false - false - true - - - double - 8 - 6 - System.Double - double - false - false - true - false - false - true - true - false - false - false - - - money - 7 - 19 - System.Decimal - money - false - false - true - true - false - true - true - false - false - true - - - currency - 7 - 19 - System.Decimal - currency - false - false - true - true - false - true - true - false - false - false - - - decimal - 7 - 19 - System.Decimal - decimal - false - false - true - true - false - true - true - false - false - true - - - numeric - 7 - 19 - System.Decimal - numeric - false - false - true - true - false - true - true - false - false - false - - - bit - 3 - 1 - System.Boolean - bit - false - false - true - false - false - true - true - false - true - - - yesno - 3 - 1 - System.Boolean - yesno - false - false - true - false - false - true - true - false - false - - - logical - 3 - 1 - System.Boolean - logical - false - false - true - false - false - true - true - false - false - - - bool - 3 - 1 - System.Boolean - bool - false - false - true - false - false - true - true - false - false - - - boolean - 3 - 1 - System.Boolean - boolean - false - false - true - false - false - true - true - false - false - - - tinyint - 2 - 3 - System.Byte - tinyint - false - false - true - true - false - true - true - false - true - true - - - integer - 12 - 19 - System.Int64 - integer - true - false - true - true - false - true - true - false - false - true - - - counter - 12 - 19 - System.Int64 - counter - true - false - true - true - false - true - true - false - false - false - - - autoincrement - 12 - 19 - System.Int64 - autoincrement - true - false - true - true - false - true - true - false - false - false - - - identity - 12 - 19 - System.Int64 - identity - true - false - true - true - false - true - true - false - false - false - - - long - 12 - 19 - System.Int64 - long - true - false - true - true - false - true - true - false - false - false - - - bigint - 12 - 19 - System.Int64 - bigint - true - false - true - true - false - true - true - false - false - false - - - binary - 1 - 2147483647 - System.Byte[] - binary - false - false - false - false - false - true - false - false - X' - ' - true - - - varbinary - 1 - 2147483647 - System.Byte[] - varbinary - false - false - false - false - false - true - false - false - X' - ' - false - - - blob - 1 - 2147483647 - System.Byte[] - blob - false - false - false - false - false - true - false - false - X' - ' - false - - - image - 1 - 2147483647 - System.Byte[] - image - false - false - false - false - false - true - false - false - X' - ' - false - - - general - 1 - 2147483647 - System.Byte[] - general - false - false - false - false - false - true - false - false - X' - ' - false - - - oleobject - 1 - 2147483647 - System.Byte[] - oleobject - false - false - false - false - false - true - false - false - X' - ' - false - - - varchar - 16 - 2147483647 - max length - System.String - varchar({0}) - false - false - false - false - false - true - true - true - ' - ' - true - - - nvarchar - 16 - 2147483647 - max length - System.String - nvarchar({0}) - false - false - false - false - false - true - true - true - ' - ' - true - - - memo - 16 - 2147483647 - max length - System.String - memo({0}) - false - false - false - false - false - true - true - true - ' - ' - false - - - longtext - 16 - 2147483647 - max length - System.String - longtext({0}) - false - false - false - false - false - true - true - true - ' - ' - false - - - note - 16 - 2147483647 - max length - System.String - note({0}) - false - false - false - false - false - true - true - true - ' - ' - false - - - text - 16 - 2147483647 - max length - System.String - text({0}) - false - false - false - false - false - true - true - true - ' - ' - false - - - ntext - 16 - 2147483647 - max length - System.String - ntext({0}) - false - false - false - false - false - true - true - true - ' - ' - false - - - string - 16 - 2147483647 - max length - System.String - string({0}) - false - false - false - false - false - true - true - true - ' - ' - false - - - char - 16 - 2147483647 - max length - System.String - char({0}) - false - false - false - false - false - true - true - true - ' - ' - false - - - nchar - 16 - 2147483647 - max length - System.String - char({0}) - false - false - false - false - false - true - true - true - ' - ' - false - - - datetime - 6 - 23 - System.DateTime - datetime - false - false - true - false - false - true - true - true - ' - ' - true - - - smalldate - 6 - 23 - System.DateTime - smalldate - false - false - true - false - false - true - true - true - ' - ' - false - - - timestamp - 6 - 23 - System.DateTime - timestamp - false - false - true - false - false - true - true - true - ' - ' - false - - - date - 6 - 23 - System.DateTime - date - false - false - true - false - false - true - true - true - ' - ' - false - - - time - 6 - 23 - System.DateTime - time - false - false - true - false - false - true - true - true - ' - ' - false - - - uniqueidentifier - 4 - 16 - System.Guid - uniqueidentifier - false - false - true - false - false - true - true - false - ' - ' - true - - - guid - 4 - 16 - System.Guid - guid - false - false - true - false - false - true - true - false - ' - ' - false - - DELETED System.Data.SQLite/Resources/MetaDataCollections.xml Index: System.Data.SQLite/Resources/MetaDataCollections.xml ================================================================== --- System.Data.SQLite/Resources/MetaDataCollections.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - MetaDataCollections - 0 - 0 - - - DataSourceInformation - 0 - 0 - - - DataTypes - 0 - 0 - - - ReservedWords - 0 - 0 - - - Catalogs - 1 - 1 - - - Columns - 4 - 4 - - - Indexes - 4 - 3 - - - IndexColumns - 5 - 4 - - - Tables - 4 - 3 - - - Views - 3 - 3 - - - ViewColumns - 4 - 4 - - - ForeignKeys - 4 - 3 - - - Triggers - 4 - 3 - - DELETED System.Data.SQLite/Resources/SQLiteCommand.bmp Index: System.Data.SQLite/Resources/SQLiteCommand.bmp ================================================================== --- System.Data.SQLite/Resources/SQLiteCommand.bmp +++ /dev/null cannot compute difference between binary files DELETED System.Data.SQLite/Resources/SQLiteConnection.bmp Index: System.Data.SQLite/Resources/SQLiteConnection.bmp ================================================================== --- System.Data.SQLite/Resources/SQLiteConnection.bmp +++ /dev/null cannot compute difference between binary files DELETED System.Data.SQLite/Resources/SQLiteDataAdapter.bmp Index: System.Data.SQLite/Resources/SQLiteDataAdapter.bmp ================================================================== --- System.Data.SQLite/Resources/SQLiteDataAdapter.bmp +++ /dev/null cannot compute difference between binary files DELETED System.Data.SQLite/Resources/SR.Designer.cs Index: System.Data.SQLite/Resources/SR.Designer.cs ================================================================== --- System.Data.SQLite/Resources/SR.Designer.cs +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************** - * 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! - ********************************************************/ - -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.1 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace System.Data.SQLite { - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] -#if !NET_COMPACT_20 - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] -#endif - internal sealed class SR { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal SR() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Data.SQLite.SR", typeof(SR).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" standalone="yes"?> - ///<DocumentElement> - /// <DataTypes> - /// <TypeName>smallint</TypeName> - /// <ProviderDbType>10</ProviderDbType> - /// <ColumnSize>5</ColumnSize> - /// <DataType>System.Int16</DataType> - /// <CreateFormat>smallint</CreateFormat> - /// <IsAutoIncrementable>false</IsAutoIncrementable> - /// <IsCaseSensitive>false</IsCaseSensitive> - /// <IsFixedLength>true</IsFixedLength> - /// <IsFixedPrecisionScale>true</IsFixedPrecisionScale> - /// <IsLong>false</IsLong> - /// <IsNullable>true</ [rest of string was truncated]";. - /// - internal static string DataTypes { - get { - return ResourceManager.GetString("DataTypes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ALL,ALTER,AND,AS,AUTOINCREMENT,BETWEEN,BY,CASE,CHECK,COLLATE,COMMIT,CONSTRAINT,CREATE,CROSS,DEFAULT,DEFERRABLE,DELETE,DISTINCT,DROP,ELSE,ESCAPE,EXCEPT,FOREIGN,FROM,FULL,GROUP,HAVING,IN,INDEX,INNER,INSERT,INTERSECT,INTO,IS,ISNULL,JOIN,LEFT,LIMIT,NATURAL,NOT,NOTNULL,NULL,ON,OR,ORDER,OUTER,PRIMARY,REFERENCES,RIGHT,ROLLBACK,SELECT,SET,TABLE,THEN,TO,TRANSACTION,UNION,UNIQUE,UPDATE,USING,VALUES,WHEN,WHERE. - /// - internal static string Keywords { - get { - return ResourceManager.GetString("Keywords", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> - ///<DocumentElement> - /// <MetaDataCollections> - /// <CollectionName>MetaDataCollections</CollectionName> - /// <NumberOfRestrictions>0</NumberOfRestrictions> - /// <NumberOfIdentifierParts>0</NumberOfIdentifierParts> - /// </MetaDataCollections> - /// <MetaDataCollections> - /// <CollectionName>DataSourceInformation</CollectionName> - /// <NumberOfRestrictions>0</NumberOfRestrictions> - /// <NumberOfIdentifierParts>0</NumberOfIdentifierParts> - /// </MetaDataCollections> - /// <MetaDataC [rest of string was truncated]";. - /// - internal static string MetaDataCollections { - get { - return ResourceManager.GetString("MetaDataCollections", resourceCulture); - } - } - } -} DELETED System.Data.SQLite/Resources/SR.resx Index: System.Data.SQLite/Resources/SR.resx ================================================================== --- System.Data.SQLite/Resources/SR.resx +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - DataTypes.xml;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - ABORT,ACTION,ADD,AFTER,ALL,ALTER,ANALYZE,AND,AS,ASC,ATTACH,AUTOINCREMENT,BEFORE,BEGIN,BETWEEN,BY,CASCADE,CASE,CAST,CHECK,COLLATE,COLUMN,COMMIT,CONFLICT,CONSTRAINT,CREATE,CROSS,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,DATABASE,DEFAULT,DEFERRABLE,DEFERRED,DELETE,DESC,DETACH,DISTINCT,DROP,EACH,ELSE,END,ESCAPE,EXCEPT,EXCLUSIVE,EXISTS,EXPLAIN,FAIL,FOR,FOREIGN,FROM,FULL,GLOB,GROUP,HAVING,IF,IGNORE,IMMEDIATE,IN,INDEX,INDEXED,INITIALLY,INNER,INSERT,INSTEAD,INTERSECT,INTO,IS,ISNULL,JOIN,KEY,LEFT,LIKE,LIMIT,MATCH,NATURAL,NO,NOT,NOTNULL,NULL,OF,OFFSET,ON,OR,ORDER,OUTER,PLAN,PRAGMA,PRIMARY,QUERY,RAISE,RECURSIVE,REFERENCES,REGEXP,REINDEX,RELEASE,RENAME,REPLACE,RESTRICT,RIGHT,ROLLBACK,ROW,SAVEPOINT,SELECT,SET,TABLE,TEMP,TEMPORARY,THEN,TO,TRANSACTION,TRIGGER,UNION,UNIQUE,UPDATE,USING,VACUUM,VALUES,VIEW,VIRTUAL,WHEN,WHERE,WITH,WITHOUT - - - MetaDataCollections.xml;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - 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.93.0"; + internal const string DesignerVersion = "1.0.91.0"; #endif /// /// The opaque pointer returned to us by the sqlite provider /// Index: System.Data.SQLite/SQLiteBase.cs ================================================================== --- System.Data.SQLite/SQLiteBase.cs +++ System.Data.SQLite/SQLiteBase.cs @@ -857,22 +857,13 @@ GC.KeepAlive(hdl); /* NOTE: Unreachable code. */ return result; } } - /// - /// - /// - public interface ISQLiteSchemaExtensions - { - /// - /// Creates temporary tables on the connection so schema information can be queried. - /// - /// - /// The connection upon which to build the schema tables. - /// - void BuildTempSchema(SQLiteConnection connection); + internal interface ISQLiteSchemaExtensions + { + void BuildTempSchema(SQLiteConnection cnn); } [Flags] internal enum SQLiteOpenFlagsEnum { @@ -1041,52 +1032,10 @@ /// associated values. Therefore, use of this flag /// is not recommended. /// NoGlobalTypes = 0x200000, - /// - /// When the property is used, it - /// should return non-zero if there were ever any rows in the associated - /// result sets. - /// - StickyHasRows = 0x400000, - - /// - /// Enable "strict" transaction enlistment semantics. Setting this flag - /// will cause an exception to be thrown if an attempt is made to enlist - /// in a transaction with an unavailable or unsupported isolation level. - /// In the future, more extensive checks may be enabled by this flag as - /// well. - /// - StrictEnlistment = 0x800000, - - /// - /// Enable mapping of unsupported transaction isolation levels to the - /// closest supported transaction isolation level. - /// - MapIsolationLevels = 0x1000000, - - /// - /// When returning column values, attempt to detect the affinity of - /// textual values by checking if they fully conform to those of the - /// , - /// , - /// , - /// or types. - /// - DetectTextAffinity = 0x2000000, - - /// - /// When returning column values, attempt to detect the type of - /// string values by checking if they fully conform to those of - /// the , - /// , - /// , - /// or types. - /// - DetectStringType = 0x4000000, - /// /// When binding parameter values or returning column values, always /// treat them as though they were plain text (i.e. no numeric, /// date/time, or other conversions should be attempted). /// @@ -1124,16 +1073,11 @@ LogModuleException, /// /// The default extra flags for new connections. /// - Default = LogCallbackException | LogModuleException, - - /// - /// The default extra flags for new connections with all logging enabled. - /// - DefaultAndLogAll = Default | LogAll + Default = LogCallbackException | LogModuleException } // These are the options to the internal sqlite3_config call. internal enum SQLiteConfigOpsEnum { ADDED System.Data.SQLite/SQLiteCommand.bmp Index: System.Data.SQLite/SQLiteCommand.bmp ================================================================== --- /dev/null +++ System.Data.SQLite/SQLiteCommand.bmp cannot compute difference between binary files Index: System.Data.SQLite/SQLiteCommand.cs ================================================================== --- System.Data.SQLite/SQLiteCommand.cs +++ System.Data.SQLite/SQLiteCommand.cs @@ -187,14 +187,10 @@ /// Disposes of the command and clears all member variables /// /// Whether or not the class is being explicitly or implicitly disposed protected override void Dispose(bool disposing) { - SQLiteConnection.OnChanged(_cnn, new ConnectionEventArgs( - SQLiteConnectionEventType.DisposingCommand, null, _transaction, this, - null, null, null, new object[] { disposing, disposed })); - bool skippedDispose = false; try { if (!disposed) ADDED System.Data.SQLite/SQLiteConnection.bmp Index: System.Data.SQLite/SQLiteConnection.bmp ================================================================== --- /dev/null +++ System.Data.SQLite/SQLiteConnection.bmp cannot compute difference between binary files Index: System.Data.SQLite/SQLiteConnection.cs ================================================================== --- System.Data.SQLite/SQLiteConnection.cs +++ System.Data.SQLite/SQLiteConnection.cs @@ -336,13 +336,10 @@ /// internal const string DefaultBaseSchemaName = "sqlite_default_schema"; private const string MemoryFileName = ":memory:"; - internal const IsolationLevel DeferredIsolationLevel = IsolationLevel.ReadCommitted; - internal const IsolationLevel ImmediateIsolationLevel = IsolationLevel.Serializable; - private const SQLiteConnectionFlags DefaultFlags = SQLiteConnectionFlags.Default; private const SQLiteSynchronousEnum DefaultSynchronous = SQLiteSynchronousEnum.Default; private const SQLiteJournalModeEnum DefaultJournalMode = SQLiteJournalModeEnum.Default; private const IsolationLevel DefaultIsolationLevel = IsolationLevel.Serializable; private const SQLiteDateFormats DefaultDateTimeFormat = SQLiteDateFormats.ISO8601; @@ -357,11 +354,10 @@ private const int DefaultPageSize = 1024; private const int DefaultMaxPageCount = 0; private const int DefaultCacheSize = 2000; private const int DefaultMaxPoolSize = 100; private const int DefaultConnectionTimeout = 30; - private const bool DefaultNoSharedFlags = false; private const bool DefaultFailIfMissing = false; private const bool DefaultReadOnly = false; private const bool DefaultBinaryGUID = true; private const bool DefaultUseUTF16Encoding = false; private const bool DefaultToFullPath = true; @@ -369,11 +365,10 @@ private const bool DefaultLegacyFormat = false; private const bool DefaultForeignKeys = false; private const bool DefaultEnlist = true; private const bool DefaultSetDefaults = true; - private const int SQLITE_FCNTL_CHUNK_SIZE = 6; private const int SQLITE_FCNTL_WIN32_AV_RETRY = 9; private const string _dataDirectory = "|DataDirectory|"; private const string _masterdb = "sqlite_master"; private const string _tempmasterdb = "sqlite_temp_master"; @@ -396,15 +391,10 @@ /// /// Static variable to store the connection event handlers to call. /// private static event SQLiteConnectionEventHandler _handlers; - /// - /// The extra connection flags to be used for all opened connections. - /// - private static SQLiteConnectionFlags _sharedFlags; - #if SQLITE_STANDARD && !PLATFORM_COMPACTFRAMEWORK /// /// Used to hold the active library version number of SQLite. /// private static int _versionNumber; @@ -477,24 +467,10 @@ /// enumeration for a list of /// possible values. /// private SQLiteConnectionFlags _flags; - /// - /// The default databse type for this connection. This value will only - /// be used if the - /// flag is set. - /// - private DbType _defaultDbType; - - /// - /// The default databse type name for this connection. This value will only - /// be used if the - /// flag is set. - /// - private string _defaultTypeName; - /// /// Default command timeout /// private int _defaultTimeout = 30; @@ -595,11 +571,13 @@ { #if (SQLITE_STANDARD || USE_INTEROP_DLL || PLATFORM_COMPACTFRAMEWORK) && PRELOAD_NATIVE_LIBRARY UnsafeNativeMethods.Initialize(); #endif +#if !INTEROP_LOG 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 @@ -632,12 +610,10 @@ #endif _typeNames = new SQLiteDbTypeMap(); _parseViaFramework = parseViaFramework; _flags = SQLiteConnectionFlags.Default; - _defaultDbType = SQLiteConvert.FallbackDefaultDbType; - _defaultTypeName = SQLiteConvert.FallbackDefaultTypeName; _connectionState = ConnectionState.Closed; _connectionString = null; if (connectionString != null) ConnectionString = connectionString; @@ -1254,19 +1230,20 @@ eventArgs = localEventArgs; } } +#if !PLATFORM_COMPACTFRAMEWORK /// /// Determines and returns the fallback default isolation level when one cannot be /// obtained from an existing connection instance. /// /// /// The fallback default isolation level for this connection instance -OR- /// if it cannot be determined. /// - private static IsolationLevel GetFallbackDefaultIsolationLevel() + internal static IsolationLevel GetFallbackDefaultIsolationLevel() { return DefaultIsolationLevel; } /// @@ -1278,10 +1255,11 @@ /// internal IsolationLevel GetDefaultIsolationLevel() { return _defaultIsolation; } +#endif /// /// OBSOLETE. Creates a new SQLiteTransaction if one isn't already active on the connection. /// /// This parameter is ignored. @@ -1291,11 +1269,11 @@ /// Returns a SQLiteTransaction object. [Obsolete("Use one of the standard BeginTransaction methods, this one will be removed soon")] public SQLiteTransaction BeginTransaction(IsolationLevel isolationLevel, bool deferredLock) { CheckDisposed(); - return (SQLiteTransaction)BeginDbTransaction(deferredLock == false ? ImmediateIsolationLevel : DeferredIsolationLevel); + return (SQLiteTransaction)BeginDbTransaction(deferredLock == false ? IsolationLevel.Serializable : IsolationLevel.ReadCommitted); } /// /// OBSOLETE. Creates a new SQLiteTransaction if one isn't already active on the connection. /// @@ -1305,11 +1283,11 @@ /// Returns a SQLiteTransaction object. [Obsolete("Use one of the standard BeginTransaction methods, this one will be removed soon")] public SQLiteTransaction BeginTransaction(bool deferredLock) { CheckDisposed(); - return (SQLiteTransaction)BeginDbTransaction(deferredLock == false ? ImmediateIsolationLevel : DeferredIsolationLevel); + return (SQLiteTransaction)BeginDbTransaction(deferredLock == false ? IsolationLevel.Serializable : IsolationLevel.ReadCommitted); } /// /// Creates a new if one isn't already active on the connection. /// @@ -1350,17 +1328,16 @@ { if (_connectionState != ConnectionState.Open) throw new InvalidOperationException(); if (isolationLevel == IsolationLevel.Unspecified) isolationLevel = _defaultIsolation; - isolationLevel = GetEffectiveIsolationLevel(isolationLevel); - if (isolationLevel != ImmediateIsolationLevel && isolationLevel != DeferredIsolationLevel) + if (isolationLevel != IsolationLevel.Serializable && isolationLevel != IsolationLevel.ReadCommitted) throw new ArgumentException("isolationLevel"); SQLiteTransaction transaction = - new SQLiteTransaction(this, isolationLevel != ImmediateIsolationLevel); + new SQLiteTransaction(this, isolationLevel != IsolationLevel.Serializable); OnChanged(this, new ConnectionEventArgs( SQLiteConnectionEventType.NewTransaction, null, transaction, null, null, null, null, null)); @@ -1884,16 +1861,11 @@ if (_transactionLevel > 0 && transaction != null) throw new ArgumentException("Unable to enlist in transaction, a local transaction already exists"); else if (transaction == null) throw new ArgumentNullException("Unable to enlist in transaction, it is null"); - bool strictEnlistment = ((_flags & SQLiteConnectionFlags.StrictEnlistment) == - SQLiteConnectionFlags.StrictEnlistment); - - _enlistment = new SQLiteEnlistment(this, transaction, - GetFallbackDefaultIsolationLevel(), strictEnlistment, - strictEnlistment); + _enlistment = new SQLiteEnlistment(this, transaction); OnChanged(this, new ConnectionEventArgs( SQLiteConnectionEventType.EnlistTransaction, null, null, null, null, null, null, new object[] { _enlistment })); } @@ -1922,11 +1894,11 @@ /// /// The enumerated type to convert the string value to. /// The string value to be converted. /// Non-zero to make the conversion case-insensitive. /// The enumerated value upon success or null upon error. - internal static object TryParseEnum( + private static object TryParseEnum( Type type, string value, bool ignoreCase ) { @@ -2209,49 +2181,10 @@ } return result; } - /// - /// Determines the transaction isolation level that should be used by - /// the caller, primarily based upon the one specified by the caller. - /// If mapping of transaction isolation levels is enabled, the returned - /// transaction isolation level may be significantly different than the - /// originally specified one. - /// - /// - /// The originally specified transaction isolation level. - /// - /// - /// The transaction isolation level that should be used. - /// - private IsolationLevel GetEffectiveIsolationLevel( - IsolationLevel isolationLevel - ) - { - if ((_flags & SQLiteConnectionFlags.MapIsolationLevels) - != SQLiteConnectionFlags.MapIsolationLevels) - { - return isolationLevel; - } - - switch (isolationLevel) - { - case IsolationLevel.Unspecified: - case IsolationLevel.Chaos: - case IsolationLevel.ReadUncommitted: - case IsolationLevel.ReadCommitted: - return DeferredIsolationLevel; - case IsolationLevel.RepeatableRead: - case IsolationLevel.Serializable: - case IsolationLevel.Snapshot: - return ImmediateIsolationLevel; - default: - return GetFallbackDefaultIsolationLevel(); - } - } - /// /// Opens the connection using the parameters found in the . /// public override void Open() { @@ -2276,20 +2209,10 @@ object enumValue; enumValue = TryParseEnum(typeof(SQLiteConnectionFlags), FindKey(opts, "Flags", DefaultFlags.ToString()), true); _flags = (enumValue is SQLiteConnectionFlags) ? (SQLiteConnectionFlags)enumValue : DefaultFlags; - bool noSharedFlags = SQLiteConvert.ToBoolean(FindKey(opts, "NoSharedFlags", DefaultNoSharedFlags.ToString())); - if (!noSharedFlags) { lock (_syncRoot) { _flags |= _sharedFlags; } } - - enumValue = TryParseEnum(typeof(DbType), FindKey(opts, "DefaultDbType", SQLiteConvert.FallbackDefaultDbType.ToString()), true); - _defaultDbType = (enumValue is DbType) ? (DbType)enumValue : SQLiteConvert.FallbackDefaultDbType; - _defaultTypeName = FindKey(opts, "DefaultTypeName", SQLiteConvert.FallbackDefaultTypeName); - -#if !NET_COMPACT_20 && TRACE_WARNING - bool uri = false; -#endif bool fullUri = false; string fileName; 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)); @@ -2306,36 +2229,15 @@ throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Data Source cannot be empty. Use {0} to open an in-memory database", MemoryFileName)); else fullUri = true; } else - { fileName = MapUriPath(fileName); -#if !NET_COMPACT_20 && TRACE_WARNING - uri = true; -#endif - } } bool isMemory = (String.Compare(fileName, MemoryFileName, StringComparison.OrdinalIgnoreCase) == 0); -#if !NET_COMPACT_20 && TRACE_WARNING - if ((_flags & SQLiteConnectionFlags.TraceWarning) == SQLiteConnectionFlags.TraceWarning) - { - if (!uri && !fullUri && !isMemory && !String.IsNullOrEmpty(fileName) && - fileName.StartsWith("\\", StringComparison.OrdinalIgnoreCase) && - !fileName.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase)) - { - System.Diagnostics.Trace.WriteLine(String.Format(CultureInfo.CurrentCulture, - "WARNING: Detected a possibly malformed UNC database file name \"{0}\" that " + - "may have originally started with two backslashes; however, four leading " + - "backslashes may be required, e.g.: \"Data Source=\\\\\\{0};\"", - fileName)); - } - } -#endif - if (!fullUri) { if (isMemory) fileName = MemoryFileName; else @@ -2356,13 +2258,12 @@ _defaultTimeout = Convert.ToInt32(FindKey(opts, "Default Timeout", DefaultConnectionTimeout.ToString()), CultureInfo.InvariantCulture); enumValue = TryParseEnum(typeof(IsolationLevel), FindKey(opts, "Default IsolationLevel", DefaultIsolationLevel.ToString()), true); _defaultIsolation = (enumValue is IsolationLevel) ? (IsolationLevel)enumValue : DefaultIsolationLevel; - _defaultIsolation = GetEffectiveIsolationLevel(_defaultIsolation); - if (_defaultIsolation != ImmediateIsolationLevel && _defaultIsolation != DeferredIsolationLevel) + if (_defaultIsolation != IsolationLevel.Serializable && _defaultIsolation != IsolationLevel.ReadCommitted) throw new NotSupportedException("Invalid Default IsolationLevel specified"); _baseSchemaName = FindKey(opts, "BaseSchemaName", DefaultBaseSchemaName); if (_sql == null) @@ -2497,11 +2398,11 @@ cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA journal_mode={0}", strValue); cmd.ExecuteNonQuery(); } strValue = FindKey(opts, "Foreign Keys", DefaultForeignKeys.ToString()); - boolValue = SQLiteConvert.ToBoolean(strValue); + boolValue = Convert.ToBoolean(strValue, CultureInfo.InvariantCulture); if (boolValue != DefaultForeignKeys) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA foreign_keys={0}", boolValue ? "ON" : "OFF"); cmd.ExecuteNonQuery(); } @@ -2591,32 +2492,10 @@ { get { CheckDisposed(); return _flags; } set { CheckDisposed(); _flags = value; } } - /// - /// Gets/sets the default database type for this connection. This value - /// will only be used if the - /// flag is set. - /// - public DbType DefaultDbType - { - get { CheckDisposed(); return _defaultDbType; } - set { CheckDisposed(); _defaultDbType = value; } - } - - /// - /// Gets/sets the default database type name for this connection. This value - /// will only be used if the - /// flag is set. - /// - public string DefaultTypeName - { - get { CheckDisposed(); return _defaultTypeName; } - set { CheckDisposed(); _defaultTypeName = value; } - } - /// /// Returns non-zero if the underlying native connection handle is /// owned by this instance. /// public bool OwnHandle @@ -2999,19 +2878,10 @@ return null; } } } - /// - /// The extra connection flags to be used for all opened connections. - /// - public static SQLiteConnectionFlags SharedFlags - { - get { lock (_syncRoot) { return _sharedFlags; } } - set { lock (_syncRoot) { _sharedFlags = value; } } - } - /// /// Returns the state of the connection. /// #if !PLATFORM_COMPACTFRAMEWORK [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] @@ -3223,11 +3093,11 @@ Marshal.WriteInt32(pArg, 0, count); Marshal.WriteInt32(pArg, sizeof(int), interval); rc = _sql.FileControl(null, SQLITE_FCNTL_WIN32_AV_RETRY, pArg); - if (rc == SQLiteErrorCode.Ok) + if (rc == 0) { count = Marshal.ReadInt32(pArg, 0); interval = Marshal.ReadInt32(pArg, sizeof(int)); } } @@ -3238,45 +3108,10 @@ } return rc; } - /// - /// Sets the chunk size for the primary file associated with this database - /// connection. - /// - /// - /// The new chunk size for the main database, in bytes. - /// - /// - /// Zero for success, non-zero for error. - /// - public SQLiteErrorCode SetChunkSize(int size) - { - CheckDisposed(); - - if (_connectionState != ConnectionState.Open) - throw new InvalidOperationException( - "Database must be opened before changing the chunk size."); - - IntPtr pArg = IntPtr.Zero; - - try - { - pArg = Marshal.AllocHGlobal(sizeof(int) * 1); - - Marshal.WriteInt32(pArg, 0, size); - - return _sql.FileControl(null, SQLITE_FCNTL_CHUNK_SIZE, pArg); - } - finally - { - if (pArg != IntPtr.Zero) - Marshal.FreeHGlobal(pArg); - } - } - /// /// 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, /// or contains quotes that are not balanced, nothing is done and the original /// string value will be returned. @@ -3791,11 +3626,11 @@ row["TABLE_CATALOG"] = strCatalog; row["TABLE_NAME"] = rdTables.GetString(2); row["INDEX_CATALOG"] = strCatalog; row["INDEX_NAME"] = rd.GetString(1); - row["UNIQUE"] = SQLiteConvert.ToBoolean(rd.GetValue(2), CultureInfo.InvariantCulture, false); + row["UNIQUE"] = rd.GetBoolean(2); row["PRIMARY_KEY"] = false; // get the index definition using (SQLiteCommand cmdIndexes = new SQLiteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[{2}] WHERE [type] LIKE 'index' AND [name] LIKE '{1}'", strCatalog, rd.GetString(1).Replace("'", "''"), master), this)) using (SQLiteDataReader rdIndexes = cmdIndexes.ExecuteReader()) Index: System.Data.SQLite/SQLiteConnectionStringBuilder.cs ================================================================== --- System.Data.SQLite/SQLiteConnectionStringBuilder.cs +++ System.Data.SQLite/SQLiteConnectionStringBuilder.cs @@ -112,11 +112,10 @@ } /// /// Gets/Sets the encoding for the connection string. The default is "False" which indicates UTF-8 encoding. /// - [DisplayName("Use UTF-16 Encoding")] [Browsable(true)] [DefaultValue(false)] public bool UseUTF16Encoding { get @@ -152,11 +151,10 @@ /// /// Gets/Sets whethor not to store GUID's in binary format. The default is True /// which saves space in the database. /// - [DisplayName("Binary GUID")] [Browsable(true)] [DefaultValue(true)] public bool BinaryGUID { get @@ -192,13 +190,11 @@ } /// /// An alternate to the data source property /// - [DisplayName("URI")] - [Browsable(true)] - [DefaultValue(null)] + [Browsable(false)] public string Uri { get { object value; @@ -212,13 +208,11 @@ } /// /// An alternate to the data source property that uses the SQLite URI syntax. /// - [DisplayName("Full URI")] - [Browsable(true)] - [DefaultValue(null)] + [Browsable(false)] public string FullUri { get { object value; @@ -274,11 +268,10 @@ /// /// 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. /// - [DisplayName("Fail If Missing")] [Browsable(true)] [DefaultValue(false)] public bool FailIfMissing { get @@ -355,11 +348,10 @@ } /// /// Gets/sets the database encryption hexadecimal password /// - [DisplayName("Hexadecimal Password")] [Browsable(true)] [PasswordPropertyText(true)] [DefaultValue(null)] public byte[] HexPassword { @@ -404,11 +396,11 @@ } /// /// Gets/Sets the maximum number of pages the database may hold /// - [DisplayName("Maximum Page Count")] + [DisplayName("Max Page Count")] [Browsable(true)] [DefaultValue(0)] public int MaxPageCount { get @@ -444,11 +436,10 @@ } /// /// Gets/Sets the DateTime format for the connection. /// - [DisplayName("DateTime Format")] [Browsable(true)] [DefaultValue(SQLiteDateFormats.Default)] public SQLiteDateFormats DateTimeFormat { get @@ -473,11 +464,10 @@ } /// /// Gets/Sets the DateTime kind for the connection. /// - [DisplayName("DateTime Kind")] [Browsable(true)] [DefaultValue(DateTimeKind.Unspecified)] public DateTimeKind DateTimeKind { get @@ -503,11 +493,10 @@ /// /// Gets/sets the DateTime format string used for formatting /// and parsing purposes. /// - [DisplayName("DateTime Format String")] [Browsable(true)] [DefaultValue(null)] public string DateTimeFormatString { get @@ -532,11 +521,10 @@ /// /// Gets/Sets the placeholder base schema name used for /// .NET Framework compatibility purposes. /// - [DisplayName("Base Schema Name")] [Browsable(true)] [DefaultValue(SQLiteConnection.DefaultBaseSchemaName)] public string BaseSchemaName { get @@ -603,53 +591,10 @@ { this["default isolationlevel"] = value; } } - /// - /// Gets/sets the default database type for the connection. - /// - [DisplayName("Default Database Type")] - [Browsable(true)] - [DefaultValue(SQLiteConvert.FallbackDefaultDbType)] - public DbType DefaultDbType - { - get - { - object value; - TryGetValue("defaultdbtype", out value); - if (value is string) - return (DbType)TypeDescriptor.GetConverter(typeof(DbType)).ConvertFrom(value); - else - return (DbType)value; - } - set - { - this["defaultdbtype"] = value; - } - } - - /// - /// Gets/sets the default type name for the connection. - /// - [DisplayName("Default Type Name")] - [Browsable(true)] - [DefaultValue(null)] - public string DefaultTypeName - { - get - { - object value; - TryGetValue("defaulttypename", out value); - return value.ToString(); - } - set - { - this["defaulttypename"] = value; - } - } - /// /// If enabled, use foreign key constraints /// [DisplayName("Foreign Keys")] [Browsable(true)] @@ -697,11 +642,11 @@ } /// /// If enabled, apply the default connection settings to opened databases. /// - [DisplayName("Set Defaults")] + [DisplayName("SetDefaults")] [Browsable(true)] [DefaultValue(true)] public bool SetDefaults { get @@ -718,11 +663,11 @@ /// /// If enabled, attempt to resolve the provided data source file name to a /// full path before opening. /// - [DisplayName("To Full Path")] + [DisplayName("ToFullPath")] [Browsable(true)] [DefaultValue(true)] public bool ToFullPath { get @@ -735,30 +680,10 @@ { this["tofullpath"] = value; } } - /// - /// If enabled, skip using the configured shared connection flags. - /// - [DisplayName("No Shared Flags")] - [Browsable(true)] - [DefaultValue(false)] - public bool NoSharedFlags - { - get - { - object value; - TryGetValue("nosharedflags", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["nosharedflags"] = value; - } - } - /// /// Helper function for retrieving values from the connectionstring /// /// The keyword to retrieve settings for /// The resulting parameter value Index: System.Data.SQLite/SQLiteConvert.cs ================================================================== --- System.Data.SQLite/SQLiteConvert.cs +++ System.Data.SQLite/SQLiteConvert.cs @@ -21,22 +21,10 @@ /// /// This base class provides datatype conversion services for the SQLite provider. /// public abstract class SQLiteConvert { - /// - /// The fallback default database type when one cannot be obtained from an - /// existing connection instance. - /// - internal const DbType FallbackDefaultDbType = DbType.Object; - - /// - /// The fallback default database type name when one cannot be obtained from - /// an existing connection instance. - /// - internal static readonly string FallbackDefaultTypeName = String.Empty; - /// /// The value for the Unix epoch (e.g. January 1, 1970 at midnight, in UTC). /// protected static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); @@ -497,51 +485,30 @@ /// Either a string containing the long integer number of 100-nanosecond units since System.DateTime.MinValue, a /// Julian day double, an integer number of seconds since the Unix epoch, a culture-independent formatted date and time /// string, a formatted date and time string in the current culture, or an ISO8601-format date/time string. public string ToString(DateTime dateValue) { - return ToString(dateValue, _datetimeFormat, _datetimeKind, _datetimeFormatString); - } - - /// - /// Converts a string into a DateTime, using the DateTimeFormat, DateTimeKind, - /// and DateTimeFormatString specified for the connection when it was opened. - /// - /// The DateTime value to convert - /// The SQLiteDateFormats to use. - /// The DateTimeKind to use. - /// The DateTime format string to use. - /// Either a string containing the long integer number of 100-nanosecond units since System.DateTime.MinValue, a - /// Julian day double, an integer number of seconds since the Unix epoch, a culture-independent formatted date and time - /// string, a formatted date and time string in the current culture, or an ISO8601-format date/time string. - public static string ToString( - DateTime dateValue, - SQLiteDateFormats format, - DateTimeKind kind, - string formatString - ) - { - switch (format) + switch (_datetimeFormat) { case SQLiteDateFormats.Ticks: return dateValue.Ticks.ToString(CultureInfo.InvariantCulture); case SQLiteDateFormats.JulianDay: return ToJulianDay(dateValue).ToString(CultureInfo.InvariantCulture); case SQLiteDateFormats.UnixEpoch: return ((long)(dateValue.Subtract(UnixEpoch).Ticks / TimeSpan.TicksPerSecond)).ToString(); case SQLiteDateFormats.InvariantCulture: - return dateValue.ToString((formatString != null) ? - formatString : FullFormat, CultureInfo.InvariantCulture); + return dateValue.ToString((_datetimeFormatString != null) ? + _datetimeFormatString : FullFormat, CultureInfo.InvariantCulture); case SQLiteDateFormats.CurrentCulture: - return dateValue.ToString((formatString != null) ? - formatString : FullFormat, CultureInfo.CurrentCulture); + return dateValue.ToString((_datetimeFormatString != null) ? + _datetimeFormatString : FullFormat, CultureInfo.CurrentCulture); default: return (dateValue.Kind == DateTimeKind.Unspecified) ? - DateTime.SpecifyKind(dateValue, kind).ToString( - GetDateTimeKindFormat(kind, formatString), + DateTime.SpecifyKind(dateValue, _datetimeKind).ToString( + GetDateTimeKindFormat(_datetimeKind, _datetimeFormatString), CultureInfo.InvariantCulture) : dateValue.ToString( - GetDateTimeKindFormat(dateValue.Kind, formatString), + GetDateTimeKindFormat(dateValue.Kind, _datetimeFormatString), CultureInfo.InvariantCulture); } } /// @@ -800,84 +767,10 @@ return convertible.ToString(provider); return obj.ToString(); /* not IConvertible */ } - /// - /// Attempts to convert an arbitrary object to the Boolean data type. - /// Null object values are converted to false. Throws an exception - /// upon failure. - /// - /// - /// The object value to convert. - /// - /// - /// The format provider to use. - /// - /// - /// If non-zero, a string value will be converted using the - /// - /// method; otherwise, the - /// method will be used. - /// - /// - /// The converted boolean value. - /// - internal static bool ToBoolean( - object obj, - IFormatProvider provider, - bool viaFramework - ) - { - if (obj == null) - return false; - - TypeCode typeCode = Type.GetTypeCode(obj.GetType()); - - switch (typeCode) - { - case TypeCode.Empty: - case TypeCode.DBNull: - return false; - case TypeCode.Boolean: - return (bool)obj; - case TypeCode.Char: - return ((char)obj) != (char)0 ? true : false; - case TypeCode.SByte: - return ((sbyte)obj) != (sbyte)0 ? true : false; - case TypeCode.Byte: - return ((byte)obj) != (byte)0 ? true : false; - case TypeCode.Int16: - return ((short)obj) != (short)0 ? true : false; - case TypeCode.UInt16: - return ((ushort)obj) != (ushort)0 ? true : false; - case TypeCode.Int32: - return ((int)obj) != (int)0 ? true : false; - case TypeCode.UInt32: - return ((uint)obj) != (uint)0 ? true : false; - case TypeCode.Int64: - return ((long)obj) != (long)0 ? true : false; - case TypeCode.UInt64: - return ((ulong)obj) != (ulong)0 ? true : false; - case TypeCode.Single: - return ((float)obj) != (float)0.0 ? true : false; - case TypeCode.Double: - return ((double)obj) != (double)0.0 ? true : false; - case TypeCode.Decimal: - return ((decimal)obj) != Decimal.Zero ? true : false; - case TypeCode.String: - return viaFramework ? - Convert.ToBoolean(obj, provider) : - ToBoolean(ToStringWithProvider(obj, provider)); - default: - throw new SQLiteException(String.Format( - CultureInfo.CurrentCulture, - "Cannot convert type {0} to boolean", - typeCode)); - } - } - /// /// Convert a value to true or false. /// /// A string or number representing true or false /// @@ -1089,28 +982,10 @@ DBNull.Value, // StringFixedLength (23) DBNull.Value, // ?? (24) DBNull.Value // Xml (25) }; - /// - /// Determines the default database type name to be used when a - /// per-connection value is not available. - /// - /// - /// The default database type name to use. - /// - private static string GetDefaultTypeName() - { - string value = UnsafeNativeMethods.GetSettingValue( - "Use_SQLiteConvert_DefaultTypeName", null); - - if (value == null) - return FallbackDefaultTypeName; - - return value; - } - /// /// Determines the type name for the given database value type. /// /// The connection context for custom type mappings, if any. /// The database value type. @@ -1120,12 +995,10 @@ SQLiteConnection connection, DbType dbType, SQLiteConnectionFlags flags ) { - string defaultTypeName = GetDefaultTypeName(); - if (connection != null) { flags |= connection.Flags; if ((flags & SQLiteConnectionFlags.UseConnectionTypes) == SQLiteConnectionFlags.UseConnectionTypes) @@ -1137,17 +1010,14 @@ SQLiteDbTypeMapping value; if (connectionTypeNames.TryGetValue(dbType, out value)) return value.typeName; } - - // - // NOTE: Use the default database type name for the connection. - // - defaultTypeName = connection.DefaultTypeName; } } + + string defaultTypeName = String.Empty; if ((flags & SQLiteConnectionFlags.NoGlobalTypes) == SQLiteConnectionFlags.NoGlobalTypes) return defaultTypeName; lock (_syncRoot) @@ -1337,201 +1207,10 @@ new SQLiteDbTypeMapping("VARCHAR2", DbType.AnsiString, false), new SQLiteDbTypeMapping("YESNO", DbType.Boolean, false) }); } - /// - /// Determines if a database type is considered to be a string. - /// - /// - /// The database type to check. - /// - /// - /// Non-zero if the database type is considered to be a string, zero - /// otherwise. - /// - internal static bool IsStringDbType( - DbType type - ) - { - switch (type) - { - case DbType.AnsiString: - case DbType.String: - case DbType.AnsiStringFixedLength: - case DbType.StringFixedLength: - return true; - default: - return false; - } - } - - /// - /// Determines the default value to be used when a - /// per-connection value is not available. - /// - /// - /// The default value to use. - /// - private static DbType GetDefaultDbType() - { - string value = UnsafeNativeMethods.GetSettingValue( - "Use_SQLiteConvert_DefaultDbType", null); - - if (value == null) - return FallbackDefaultDbType; - - object enumValue = SQLiteConnection.TryParseEnum( - typeof(DbType), value, true); - - if (!(enumValue is DbType)) - return FallbackDefaultDbType; - - return (DbType)enumValue; - } - - /// - /// Determines if the specified textual value appears to be a - /// value. - /// - /// - /// The textual value to inspect. - /// - /// - /// Non-zero if the text looks like a value, - /// zero otherwise. - /// - internal static bool LooksLikeNull( - string text - ) - { - return (text == null); - } - - /// - /// Determines if the specified textual value appears to be an - /// value. - /// - /// - /// The textual value to inspect. - /// - /// - /// Non-zero if the text looks like an value, - /// zero otherwise. - /// - internal static bool LooksLikeInt64( - string text - ) - { - long longValue; - -#if !PLATFORM_COMPACTFRAMEWORK - if (!long.TryParse( - text, NumberStyles.Integer, CultureInfo.InvariantCulture, - out longValue)) - { - return false; - } -#else - try - { - longValue = long.Parse( - text, NumberStyles.Integer, CultureInfo.InvariantCulture); - } - catch - { - return false; - } -#endif - - return String.Equals( - longValue.ToString(CultureInfo.InvariantCulture), text, - StringComparison.Ordinal); - } - - /// - /// Determines if the specified textual value appears to be a - /// value. - /// - /// - /// The textual value to inspect. - /// - /// - /// Non-zero if the text looks like a value, - /// zero otherwise. - /// - internal static bool LooksLikeDouble( - string text - ) - { - double doubleValue; - -#if !PLATFORM_COMPACTFRAMEWORK - if (!double.TryParse( - text, NumberStyles.Float | NumberStyles.AllowThousands, - CultureInfo.InvariantCulture, out doubleValue)) - { - return false; - } -#else - try - { - doubleValue = double.Parse(text, CultureInfo.InvariantCulture); - } - catch - { - return false; - } -#endif - - return String.Equals( - doubleValue.ToString(CultureInfo.InvariantCulture), text, - StringComparison.Ordinal); - } - - /// - /// Determines if the specified textual value appears to be a - /// value. - /// - /// - /// The object instance configured with - /// the chosen format. - /// - /// - /// The textual value to inspect. - /// - /// - /// Non-zero if the text looks like a in the - /// configured format, zero otherwise. - /// - internal static bool LooksLikeDateTime( - SQLiteConvert convert, - string text - ) - { - if (convert == null) - return false; - - try - { - DateTime dateTimeValue = convert.ToDateTime(text); - - if (String.Equals( - convert.ToString(dateTimeValue), - text, StringComparison.Ordinal)) - { - return true; - } - } - catch - { - // do nothing. - } - - return false; - } - /// /// For a given type name, return a closest-match .NET type /// /// The connection context for custom type mappings, if any. /// The name of the type to match @@ -1541,12 +1220,10 @@ SQLiteConnection connection, string name, SQLiteConnectionFlags flags ) { - DbType defaultDbType = GetDefaultDbType(); - if (connection != null) { flags |= connection.Flags; if ((flags & SQLiteConnectionFlags.UseConnectionTypes) == SQLiteConnectionFlags.UseConnectionTypes) @@ -1573,17 +1250,14 @@ return value.dataType; } } } } - - // - // NOTE: Use the default database type for the connection. - // - defaultDbType = connection.DefaultDbType; } } + + DbType defaultDbType = DbType.Object; if ((flags & SQLiteConnectionFlags.NoGlobalTypes) == SQLiteConnectionFlags.NoGlobalTypes) return defaultDbType; lock (_syncRoot) @@ -1742,26 +1416,11 @@ Closing = 10, /// /// The connection was closed. /// - Closed = 11, - - /// - /// A command is being disposed. - /// - DisposingCommand = 12, - - /// - /// A data reader is being disposed. - /// - DisposingDataReader = 13, - - /// - /// A data reader is being closed. - /// - ClosingDataReader = 14 + Closed = 11 } /// /// This implementation of SQLite for ADO.NET can process date/time fields in /// databases in one of six formats. @@ -2199,41 +1858,10 @@ internal DbType Type; /// /// The affinity of a column, used for expressions or when Type is DbType.Object /// internal TypeAffinity Affinity; - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Constructs a default instance of this type. - /// - public SQLiteType() - { - // do nothing. - } - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Constructs an instance of this type with the specified field values. - /// - /// - /// The type affinity to use for the new instance. - /// - /// - /// The database type to use for the new instance. - /// - public SQLiteType( - TypeAffinity affinity, - DbType type - ) - : this() - { - this.Affinity = affinity; - this.Type = type; - } } ///////////////////////////////////////////////////////////////////////////// internal sealed class SQLiteDbTypeMap ADDED System.Data.SQLite/SQLiteDataAdapter.bmp Index: System.Data.SQLite/SQLiteDataAdapter.bmp ================================================================== --- /dev/null +++ System.Data.SQLite/SQLiteDataAdapter.bmp cannot compute difference between binary files Index: System.Data.SQLite/SQLiteDataReader.cs ================================================================== --- System.Data.SQLite/SQLiteDataReader.cs +++ System.Data.SQLite/SQLiteDataReader.cs @@ -46,15 +46,10 @@ /// /// Count of fields (columns) in the row-returning statement currently being processed /// private int _fieldCount; /// - /// The number of calls to Step() that have returned true (i.e. the number of rows that - /// have been read in the current result set). - /// - private int _stepCount; - /// /// Maps the field (column) names to their corresponding indexes within the results. /// private Dictionary _fieldIndexes; /// /// Datatypes of active fields (columns) in the current statement, used for type-restricting data @@ -107,16 +102,18 @@ _commandBehavior = behave; _activeStatementIndex = -1; _rowsAffected = -1; - SQLiteConnection.OnChanged(GetConnection(this), - new ConnectionEventArgs(SQLiteConnectionEventType.NewDataReader, - null, null, _command, this, null, null, new object[] { behave })); - if (_command != null) + { + SQLiteConnection.OnChanged(_command.Connection, + new ConnectionEventArgs(SQLiteConnectionEventType.NewDataReader, + null, null, _command, this, null, null, new object[] { behave })); + NextResult(); + } } /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members @@ -135,16 +132,10 @@ /// Dispose of all resources used by this datareader. /// /// protected override void Dispose(bool disposing) { - SQLiteConnection.OnChanged(GetConnection(this), - new ConnectionEventArgs(SQLiteConnectionEventType.DisposingDataReader, - null, null, _command, this, null, null, new object[] { disposing, - disposed, _commandBehavior, _readingState, _rowsAffected, _stepCount, - _fieldCount, _disposeCommand, _throwOnDisposed })); - try { if (!disposed) { //if (disposing) @@ -189,16 +180,10 @@ /// public override void Close() { CheckDisposed(); - SQLiteConnection.OnChanged(GetConnection(this), - new ConnectionEventArgs(SQLiteConnectionEventType.ClosingDataReader, - null, null, _command, this, null, null, new object[] { _commandBehavior, - _readingState, _rowsAffected, _stepCount, _fieldCount, _disposeCommand, - _throwOnDisposed })); - try { if (_command != null) { try @@ -314,24 +299,10 @@ return _fieldCount + _keyInfo.Count; } } - /// - /// Returns the number of rows seen so far in the current result set. - /// - public int StepCount - { - get - { - CheckDisposed(); - CheckClosed(); - - return _stepCount; - } - } - /// /// Returns the number of visible fields in the current resultset /// public override int VisibleFieldCount { @@ -359,11 +330,11 @@ private TypeAffinity VerifyType(int i, DbType typ) { CheckClosed(); CheckValidRow(); - TypeAffinity affinity = GetSQLiteType(SQLiteCommand.GetFlags(_command), i).Affinity; + TypeAffinity affinity = GetSQLiteType(i).Affinity; switch (affinity) { case TypeAffinity.Int64: if (typ == DbType.Int16) return affinity; @@ -504,11 +475,11 @@ CheckDisposed(); if (i >= VisibleFieldCount && _keyInfo != null) return _keyInfo.GetDataTypeName(i - VisibleFieldCount); - SQLiteType typ = GetSQLiteType(SQLiteCommand.GetFlags(_command), i); + SQLiteType typ = GetSQLiteType(i); if (typ.Type == DbType.Object) return SQLiteConvert.SQLiteTypeToType(typ).Name; return _activeStatement._sql.ColumnType(_activeStatement, i, out typ.Affinity); } /// @@ -569,11 +540,11 @@ CheckDisposed(); if (i >= VisibleFieldCount && _keyInfo != null) return _keyInfo.GetFieldType(i - VisibleFieldCount); - return SQLiteConvert.SQLiteTypeToType(GetSQLiteType(SQLiteCommand.GetFlags(_command), i)); + return SQLiteConvert.SQLiteTypeToType(GetSQLiteType(i)); } /// /// Returns a column as a float value /// @@ -918,15 +889,13 @@ tbl.Columns.Add(SchemaTableOptionalColumn.DefaultValue, typeof(object)); tbl.Columns.Add("DataTypeName", typeof(string)); tbl.Columns.Add("CollationType", typeof(string)); tbl.BeginLoadData(); - SQLiteConnectionFlags flags = SQLiteCommand.GetFlags(_command); - for (int n = 0; n < _fieldCount; n++) { - SQLiteType sqlType = GetSQLiteType(flags, n); + SQLiteType sqlType = GetSQLiteType(n); row = tbl.NewRow(); DbType typ = sqlType.Type; @@ -989,12 +958,13 @@ { dataType = arSize[0]; arSize = arSize[1].Split(')'); if (arSize.Length > 1) { - arSize = arSize[0].Split(',', '.'); - if (sqlType.Type == DbType.Binary || SQLiteConvert.IsStringDbType(sqlType.Type)) + arSize = arSize[0].Split(',', '.'); + if (sqlType.Type == DbType.Binary || sqlType.Type == DbType.String || + sqlType.Type == DbType.AnsiStringFixedLength || sqlType.Type == DbType.StringFixedLength) { row[SchemaTableColumn.ColumnSize] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture); } else { @@ -1131,27 +1101,14 @@ CheckValidRow(); if (i >= VisibleFieldCount && _keyInfo != null) return _keyInfo.GetValue(i - VisibleFieldCount); - SQLiteConnectionFlags flags = SQLiteCommand.GetFlags(_command); - SQLiteType typ = GetSQLiteType(flags, i); - - if (((flags & SQLiteConnectionFlags.DetectTextAffinity) == SQLiteConnectionFlags.DetectTextAffinity) && - ((typ == null) || (typ.Affinity == TypeAffinity.Text))) - { - typ = GetSQLiteType( - typ, _activeStatement._sql.GetText(_activeStatement, i)); - } - else if (((flags & SQLiteConnectionFlags.DetectStringType) == SQLiteConnectionFlags.DetectStringType) && - ((typ == null) || SQLiteConvert.IsStringDbType(typ.Type))) - { - typ = GetSQLiteType( - typ, _activeStatement._sql.GetText(_activeStatement, i)); - } - - return _activeStatement._sql.GetValue(_activeStatement, flags, i, typ); + SQLiteType typ = GetSQLiteType(i); + + return _activeStatement._sql.GetValue( + _activeStatement, SQLiteCommand.GetFlags(_command), i, typ); } /// /// Retreives the values of multiple columns, up to the size of the supplied array /// @@ -1210,28 +1167,10 @@ { get { CheckDisposed(); CheckClosed(); - - // - // NOTE: If the "sticky" flag has been set, use the new behavior, - // which returns non-zero if there were ever any rows in - // the associated result sets. Generally, this flag is only - // useful when it is necessary to retain compatibility with - // other ADO.NET providers that use these same semantics for - // the HasRows property. - // - if ((GetFlags(this) & SQLiteConnectionFlags.StickyHasRows) == SQLiteConnectionFlags.StickyHasRows) - return ((_readingState != 1) || (_stepCount > 0)); - - // - // NOTE: This is the default behavior. It returns non-zero only if - // more rows are available (i.e. a call to the Read method is - // expected to succeed). Prior to the introduction of the - // "sticky" flag, this is how this property has always worked. - // return (_readingState != 1); } } /// @@ -1286,11 +1225,11 @@ { stmt = _command.GetStatement(_activeStatementIndex + 1); if (stmt == null) break; _activeStatementIndex++; - if (!schemaOnly && stmt._sql.Step(stmt)) _stepCount++; + if (!schemaOnly) stmt._sql.Step(stmt); if (stmt._sql.ColumnCount(stmt) == 0) { if (_rowsAffected == -1) _rowsAffected = 0; int changes = 0; if (stmt.TryGetChanges(ref changes)) @@ -1322,11 +1261,10 @@ // If the statement is not a select statement or we're not retrieving schema only, then perform the initial step if (!schemaOnly || (fieldCount == 0)) { if (!schemaOnly && stmt._sql.Step(stmt)) { - _stepCount++; _readingState = -1; } else if (fieldCount == 0) // No rows returned, if fieldCount is zero, skip to the next statement { if (_rowsAffected == -1) _rowsAffected = 0; @@ -1423,52 +1361,16 @@ } return SQLiteConnectionFlags.Default; } - /// - /// Retrieves the SQLiteType for a given column and row value. - /// - /// - /// The original SQLiteType structure, based only on the column. - /// - /// - /// The textual value of the column for a given row. - /// - /// - /// The SQLiteType structure. - /// - private SQLiteType GetSQLiteType( - SQLiteType oldType, /* PASS-THROUGH */ - string text - ) - { - if (SQLiteConvert.LooksLikeNull(text)) - return new SQLiteType(TypeAffinity.Null, DbType.Object); - - if (SQLiteConvert.LooksLikeInt64(text)) - return new SQLiteType(TypeAffinity.Int64, DbType.Int64); - - if (SQLiteConvert.LooksLikeDouble(text)) - return new SQLiteType(TypeAffinity.Double, DbType.Double); - - if ((_activeStatement != null) && - SQLiteConvert.LooksLikeDateTime(_activeStatement._sql, text)) - { - return new SQLiteType(TypeAffinity.DateTime, DbType.DateTime); - } - - return oldType; - } - /// /// Retrieves the SQLiteType for a given column, and caches it to avoid repetetive interop calls. /// - /// The flags associated with the parent connection object. /// The index of the column to retrieve /// A SQLiteType structure - private SQLiteType GetSQLiteType(SQLiteConnectionFlags flags, int i) + private SQLiteType GetSQLiteType(int i) { SQLiteType typ; // Initialize the field types array if not already initialized if (_fieldTypeArray == null) @@ -1480,11 +1382,11 @@ typ = _fieldTypeArray[i]; // If not initialized, then fetch the declared column datatype and attempt to convert it // to a known DbType. if (typ.Affinity == TypeAffinity.Uninitialized) - typ.Type = SQLiteConvert.TypeNameToDbType(GetConnection(this), _activeStatement._sql.ColumnType(_activeStatement, i, out typ.Affinity), flags); + typ.Type = SQLiteConvert.TypeNameToDbType(GetConnection(this), _activeStatement._sql.ColumnType(_activeStatement, i, out typ.Affinity), GetFlags(this)); else typ.Affinity = _activeStatement._sql.ColumnAffinity(_activeStatement, i); return typ; } @@ -1512,12 +1414,10 @@ // Don't read a new row if the command behavior dictates SingleRow. We've already read the first row. if ((_commandBehavior & CommandBehavior.SingleRow) == 0) { if (_activeStatement._sql.Step(_activeStatement) == true) { - _stepCount++; - if (_keyInfo != null) _keyInfo.Reset(); return true; } Index: System.Data.SQLite/SQLiteDefineConstants.cs ================================================================== --- System.Data.SQLite/SQLiteDefineConstants.cs +++ System.Data.SQLite/SQLiteDefineConstants.cs @@ -102,14 +102,10 @@ #if TRACE_CONNECTION "TRACE_CONNECTION", #endif -#if TRACE_DETECTION - "TRACE_DETECTION", -#endif - #if TRACE_HANDLE "TRACE_HANDLE", #endif #if TRACE_PRELOAD Index: System.Data.SQLite/SQLiteEnlistment.cs ================================================================== --- System.Data.SQLite/SQLiteEnlistment.cs +++ System.Data.SQLite/SQLiteEnlistment.cs @@ -6,30 +6,22 @@ ********************************************************/ #if !PLATFORM_COMPACTFRAMEWORK namespace System.Data.SQLite { - using System.Globalization; - using System.Transactions; + using System.Transactions; internal sealed class SQLiteEnlistment : IDisposable, IEnlistmentNotification { internal SQLiteTransaction _transaction; internal Transaction _scope; internal bool _disposeConnection; - internal SQLiteEnlistment( - SQLiteConnection cnn, - Transaction scope, - System.Data.IsolationLevel defaultIsolationLevel, - bool throwOnUnavailable, - bool throwOnUnsupported - ) + internal SQLiteEnlistment(SQLiteConnection cnn, Transaction scope) { _transaction = cnn.BeginTransaction(GetSystemDataIsolationLevel( - cnn, scope, defaultIsolationLevel, throwOnUnavailable, - throwOnUnsupported)); + cnn, scope)); _scope = scope; _scope.EnlistVolatile(this, System.Transactions.EnlistmentOptions.None); } @@ -37,33 +29,22 @@ /////////////////////////////////////////////////////////////////////////// #region Private Methods private System.Data.IsolationLevel GetSystemDataIsolationLevel( SQLiteConnection connection, - Transaction transaction, - System.Data.IsolationLevel defaultIsolationLevel, - bool throwOnUnavailable, - bool throwOnUnsupported + Transaction transaction ) { if (transaction == null) { // - // NOTE: If neither the transaction nor connection isolation - // level is available, throw an exception if instructed - // by the caller. + // TODO: Perhaps throw an exception here if the connection + // is null? // - if (connection != null) - return connection.GetDefaultIsolationLevel(); - - if (throwOnUnavailable) - { - throw new InvalidOperationException( - "isolation level is unavailable"); - } - - return defaultIsolationLevel; + return (connection != null) ? + connection.GetDefaultIsolationLevel() : + SQLiteConnection.GetFallbackDefaultIsolationLevel(); } System.Transactions.IsolationLevel isolationLevel = transaction.IsolationLevel; @@ -70,39 +51,30 @@ // // TODO: Are these isolation level mappings actually correct? // switch (isolationLevel) { - case IsolationLevel.Unspecified: - return System.Data.IsolationLevel.Unspecified; case IsolationLevel.Chaos: return System.Data.IsolationLevel.Chaos; + case IsolationLevel.ReadCommitted: + return System.Data.IsolationLevel.ReadCommitted; case IsolationLevel.ReadUncommitted: return System.Data.IsolationLevel.ReadUncommitted; - case IsolationLevel.ReadCommitted: - return System.Data.IsolationLevel.ReadCommitted; case IsolationLevel.RepeatableRead: return System.Data.IsolationLevel.RepeatableRead; case IsolationLevel.Serializable: return System.Data.IsolationLevel.Serializable; case IsolationLevel.Snapshot: return System.Data.IsolationLevel.Snapshot; + case IsolationLevel.Unspecified: + return System.Data.IsolationLevel.Unspecified; } // - // NOTE: When in "strict" mode, throw an exception if the isolation - // level is not recognized; otherwise, fallback to the default - // isolation level specified by the caller. + // TODO: Perhaps throw an exception here? // - if (throwOnUnsupported) - { - throw new InvalidOperationException( - String.Format(CultureInfo.InvariantCulture, - "unsupported isolation level {0}", isolationLevel)); - } - - return defaultIsolationLevel; + return SQLiteConnection.GetFallbackDefaultIsolationLevel(); } /////////////////////////////////////////////////////////////////////////// private void Cleanup(SQLiteConnection cnn) Index: System.Data.SQLite/SQLiteLog.cs ================================================================== --- System.Data.SQLite/SQLiteLog.cs +++ System.Data.SQLite/SQLiteLog.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 { @@ -92,10 +92,11 @@ /// /// Member variable to store the application log handler to call. /// private static event SQLiteLogEventHandler _handlers; + /////////////////////////////////////////////////////////////////////// /// /// The default log event handler. @@ -102,11 +103,10 @@ /// private static SQLiteLogEventHandler _defaultHandler; /////////////////////////////////////////////////////////////////////// -#if !INTEROP_LOG /// /// 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; @@ -115,11 +115,10 @@ /// /// The base SQLite object to interop with. /// private static SQLiteBase _sql; -#endif /////////////////////////////////////////////////////////////////////// /// /// This will be non-zero if logging is currently enabled. @@ -176,11 +175,10 @@ _domainUnload = new EventHandler(DomainUnload); AppDomain.CurrentDomain.DomainUnload += _domainUnload; } #endif -#if !INTEROP_LOG // // NOTE: Create an instance of the SQLite wrapper class. // if (_sql == null) { @@ -203,11 +201,10 @@ if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "Failed to initialize logging."); } -#endif // // NOTE: Logging is enabled by default. // _enabled = true; @@ -243,11 +240,10 @@ // NOTE: Disable logging. If necessary, it can be re-enabled // later by the Initialize method. // _enabled = false; -#if !INTEROP_LOG // // BUGBUG: This will cause serious problems if other AppDomains // have any open SQLite connections; however, there is // currently no way around this limitation. // @@ -275,11 +271,10 @@ // if (_callback != null) { _callback = null; } -#endif // // NOTE: Remove the event handler for the DomainUnload event // that we added earlier. // @@ -549,27 +544,13 @@ (rc == SQLiteErrorCode.Done)) { type = "data"; } } - else if (errorCode == null) - { - type = "trace"; - } - - if ((errorCode != null) && - !Object.ReferenceEquals(errorCode, String.Empty)) - { - Trace.WriteLine(String.Format( - CultureInfo.CurrentCulture, "SQLite {0} ({1}): {2}", - type, errorCode, message)); - } - else - { - Trace.WriteLine(String.Format( - CultureInfo.CurrentCulture, "SQLite {0}: {1}", - type, message)); - } + + Trace.WriteLine(String.Format( + CultureInfo.CurrentCulture, "SQLite {0} ({1}): {2}", + type, errorCode, message)); #endif } } } Index: System.Data.SQLite/SQLiteModule.cs ================================================================== --- System.Data.SQLite/SQLiteModule.cs +++ System.Data.SQLite/SQLiteModule.cs @@ -4604,19 +4604,10 @@ /// private const bool DefaultLogErrors = true; /////////////////////////////////////////////////////////////////// - /// - /// This is the value that is always used for the "logExceptions" - /// parameter to the various static error handling methods provided - /// by the class. - /// - private const bool DefaultLogExceptions = true; - - /////////////////////////////////////////////////////////////////// - /// /// This is the error message text used when the contained /// object instance is not available /// for any reason. /// @@ -4670,11 +4661,11 @@ private static SQLiteErrorCode ModuleNotAvailableTableError( IntPtr pVtab ) { SetTableError(null, pVtab, DefaultLogErrors, - DefaultLogExceptions, ModuleNotAvailableErrorMessage); + ModuleNotAvailableErrorMessage); return SQLiteErrorCode.Error; } /////////////////////////////////////////////////////////////////// @@ -4693,11 +4684,11 @@ private static SQLiteErrorCode ModuleNotAvailableCursorError( IntPtr pCursor ) { SetCursorError(null, pCursor, DefaultLogErrors, - DefaultLogExceptions, ModuleNotAvailableErrorMessage); + ModuleNotAvailableErrorMessage); return SQLiteErrorCode.Error; } #endregion @@ -6168,14 +6159,10 @@ /// /// /// Non-zero if this error message should also be logged using the /// class. /// - /// - /// Non-zero if caught exceptions should be logged using the - /// class. - /// /// /// The error message. /// /// /// Non-zero upon success. @@ -6182,11 +6169,10 @@ /// private static bool SetTableError( SQLiteModule module, IntPtr pVtab, bool logErrors, - bool logExceptions, string error ) { try { @@ -6199,65 +6185,47 @@ } catch { // do nothing. } + + if (pVtab == IntPtr.Zero) + return false; + + int offset = 0; + + offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size, + sizeof(int)); + + offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int), + IntPtr.Size); + + IntPtr pError = SQLiteMarshal.ReadIntPtr(pVtab, offset); + + if (pError != IntPtr.Zero) + { + SQLiteMemory.Free(pError); pError = IntPtr.Zero; + SQLiteMarshal.WriteIntPtr(pVtab, offset, pError); + } + + if (error == null) + return true; bool success = false; - IntPtr pNewError = IntPtr.Zero; - - try - { - if (pVtab == IntPtr.Zero) - return false; - - int offset = 0; - - offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size, - sizeof(int)); - - offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int), - IntPtr.Size); - - IntPtr pOldError = SQLiteMarshal.ReadIntPtr(pVtab, offset); - - if (pOldError != IntPtr.Zero) - { - SQLiteMemory.Free(pOldError); pOldError = IntPtr.Zero; - SQLiteMarshal.WriteIntPtr(pVtab, offset, pOldError); - } - - if (error == null) - return true; - - pNewError = SQLiteString.Utf8IntPtrFromString(error); - SQLiteMarshal.WriteIntPtr(pVtab, offset, pNewError); - success = true; - } - catch (Exception e) /* NOTE: Must catch ALL. */ - { - try - { - if (logExceptions) - { - SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION, - String.Format(CultureInfo.CurrentCulture, - "Caught exception in \"SetTableError\" method: {0}", - e)); /* throw */ - } - } - catch - { - // do nothing. - } + + try + { + pError = SQLiteString.Utf8IntPtrFromString(error); + SQLiteMarshal.WriteIntPtr(pVtab, offset, pError); + success = true; } finally { - if (!success && (pNewError != IntPtr.Zero)) + if (!success && (pError != IntPtr.Zero)) { - SQLiteMemory.Free(pNewError); - pNewError = IntPtr.Zero; + SQLiteMemory.Free(pError); + pError = IntPtr.Zero; } } return success; } @@ -6278,14 +6246,10 @@ /// /// /// Non-zero if this error message should also be logged using the /// class. /// - /// - /// Non-zero if caught exceptions should be logged using the - /// class. - /// /// /// The error message. /// /// /// Non-zero upon success. @@ -6292,11 +6256,10 @@ /// private static bool SetTableError( SQLiteModule module, SQLiteVirtualTable table, bool logErrors, - bool logExceptions, string error ) { if (table == null) return false; @@ -6304,12 +6267,11 @@ IntPtr pVtab = table.NativeHandle; if (pVtab == IntPtr.Zero) return false; - return SetTableError( - module, pVtab, logErrors, logExceptions, error); + return SetTableError(module, pVtab, logErrors, error); } /////////////////////////////////////////////////////////////////////// /// @@ -6327,14 +6289,10 @@ /// /// /// Non-zero if this error message should also be logged using the /// class. /// - /// - /// Non-zero if caught exceptions should be logged using the - /// class. - /// /// /// The error message. /// /// /// Non-zero upon success. @@ -6341,11 +6299,10 @@ /// private static bool SetCursorError( SQLiteModule module, IntPtr pCursor, bool logErrors, - bool logExceptions, string error ) { if (pCursor == IntPtr.Zero) return false; @@ -6353,12 +6310,11 @@ IntPtr pVtab = TableFromCursor(module, pCursor); if (pVtab == IntPtr.Zero) return false; - return SetTableError( - module, pVtab, logErrors, logExceptions, error); + return SetTableError(module, pVtab, logErrors, error); } /////////////////////////////////////////////////////////////////////// /// @@ -6375,14 +6331,10 @@ /// /// /// Non-zero if this error message should also be logged using the /// class. /// - /// - /// Non-zero if caught exceptions should be logged using the - /// class. - /// /// /// The error message. /// /// /// Non-zero upon success. @@ -6389,11 +6341,10 @@ /// private static bool SetCursorError( SQLiteModule module, SQLiteVirtualTableCursor cursor, bool logErrors, - bool logExceptions, string error ) { if (cursor == null) return false; @@ -6401,12 +6352,11 @@ IntPtr pCursor = cursor.NativeHandle; if (pCursor == IntPtr.Zero) return false; - return SetCursorError( - module, pCursor, logErrors, logExceptions, error); + return SetCursorError(module, pCursor, logErrors, error); } #endregion #endregion /////////////////////////////////////////////////////////////////////// @@ -6951,14 +6901,12 @@ private bool logExceptions; /// /// Returns or sets a boolean value indicating whether exceptions /// caught in the /// method, - /// the method, - /// the method, - /// the method, - /// and the method should be logged using the + /// method, and the + /// method should be logged using the /// class. /// protected virtual bool LogExceptionsNoThrow { get { return logExceptions; } @@ -6986,12 +6934,11 @@ protected virtual bool SetTableError( IntPtr pVtab, string error ) { - return SetTableError( - this, pVtab, LogErrorsNoThrow, LogExceptionsNoThrow, error); + return SetTableError(this, pVtab, LogErrorsNoThrow, error); } /////////////////////////////////////////////////////////////////////// /// @@ -7012,12 +6959,11 @@ protected virtual bool SetTableError( SQLiteVirtualTable table, string error ) { - return SetTableError( - this, table, LogErrorsNoThrow, LogExceptionsNoThrow, error); + return SetTableError(this, table, LogErrorsNoThrow, error); } /////////////////////////////////////////////////////////////////////// /// @@ -7038,12 +6984,11 @@ protected virtual bool SetCursorError( SQLiteVirtualTableCursor cursor, string error ) { - return SetCursorError( - this, cursor, LogErrorsNoThrow, LogExceptionsNoThrow, error); + return SetCursorError(this, cursor, LogErrorsNoThrow, error); } #endregion /////////////////////////////////////////////////////////////////////// Index: System.Data.SQLite/SQLiteStatement.cs ================================================================== --- System.Data.SQLite/SQLiteStatement.cs +++ System.Data.SQLite/SQLiteStatement.cs @@ -226,10 +226,66 @@ for (int n = 0; n < x; n++) { BindParameter(n + 1, _paramValues[n]); } } + + /// + /// Attempts to convert an arbitrary object to the Boolean data type. + /// Null object values are converted to false. Throws a SQLiteException + /// upon failure. + /// + /// The object value to convert. + /// The format provider to use. + /// The converted boolean value. + private static bool ToBoolean(object obj, IFormatProvider provider) + { + if (obj == null) + return false; + + TypeCode typeCode = Type.GetTypeCode(obj.GetType()); + + switch (typeCode) + { + case TypeCode.Empty: + case TypeCode.DBNull: + return false; + case TypeCode.Boolean: + return (bool)obj; + case TypeCode.Char: + return ((char)obj) != (char)0 ? true : false; + case TypeCode.SByte: + return ((sbyte)obj) != (sbyte)0 ? true : false; + case TypeCode.Byte: + return ((byte)obj) != (byte)0 ? true : false; + case TypeCode.Int16: + return ((short)obj) != (short)0 ? true : false; + case TypeCode.UInt16: + return ((ushort)obj) != (ushort)0 ? true : false; + case TypeCode.Int32: + return ((int)obj) != (int)0 ? true : false; + case TypeCode.UInt32: + return ((uint)obj) != (uint)0 ? true : false; + case TypeCode.Int64: + return ((long)obj) != (long)0 ? true : false; + case TypeCode.UInt64: + return ((ulong)obj) != (ulong)0 ? true : false; + case TypeCode.Single: + return ((float)obj) != (float)0.0 ? true : false; + case TypeCode.Double: + return ((double)obj) != (double)0.0 ? true : false; + case TypeCode.Decimal: + return ((decimal)obj) != Decimal.Zero ? true : false; + case TypeCode.String: + return Convert.ToBoolean(obj, provider); + default: + throw new SQLiteException(String.Format( + CultureInfo.CurrentCulture, + "Cannot convert type {0} to boolean", + typeCode)); + } + } /// /// Perform the bind operation for an individual parameter /// /// The index of the parameter to bind @@ -296,11 +352,11 @@ // _sql.Bind_DateTime(this, index, Convert.ToDateTime(obj, cultureInfo)); _sql.Bind_DateTime(this, _flags, index, (obj is string) ? _sql.ToDateTime((string)obj) : Convert.ToDateTime(obj, cultureInfo)); break; case DbType.Boolean: - _sql.Bind_Int32(this, _flags, index, SQLiteConvert.ToBoolean(obj, cultureInfo, true) ? 1 : 0); + _sql.Bind_Int32(this, _flags, index, ToBoolean(obj, cultureInfo) ? 1 : 0); break; case DbType.SByte: _sql.Bind_Int32(this, _flags, index, Convert.ToSByte(obj, cultureInfo)); break; case DbType.Int16: Index: System.Data.SQLite/SQLiteTransaction.cs ================================================================== --- System.Data.SQLite/SQLiteTransaction.cs +++ System.Data.SQLite/SQLiteTransaction.cs @@ -32,13 +32,11 @@ internal SQLiteTransaction(SQLiteConnection connection, bool deferredLock) { _cnn = connection; _version = _cnn._version; - _level = (deferredLock == true) ? - SQLiteConnection.DeferredIsolationLevel : - SQLiteConnection.ImmediateIsolationLevel; + _level = (deferredLock == true) ? IsolationLevel.ReadCommitted : IsolationLevel.Serializable; if (_cnn._transactionLevel++ == 0) { try { ADDED System.Data.SQLite/SR.Designer.cs Index: System.Data.SQLite/SR.Designer.cs ================================================================== --- /dev/null +++ System.Data.SQLite/SR.Designer.cs @@ -0,0 +1,121 @@ +/******************************************************** + * 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! + ********************************************************/ + +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace System.Data.SQLite { + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] +#if !NET_COMPACT_20 + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] +#endif + internal sealed class SR { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal SR() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Data.SQLite.SR", typeof(SR).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" standalone="yes"?> + ///<DocumentElement> + /// <DataTypes> + /// <TypeName>smallint</TypeName> + /// <ProviderDbType>10</ProviderDbType> + /// <ColumnSize>5</ColumnSize> + /// <DataType>System.Int16</DataType> + /// <CreateFormat>smallint</CreateFormat> + /// <IsAutoIncrementable>false</IsAutoIncrementable> + /// <IsCaseSensitive>false</IsCaseSensitive> + /// <IsFixedLength>true</IsFixedLength> + /// <IsFixedPrecisionScale>true</IsFixedPrecisionScale> + /// <IsLong>false</IsLong> + /// <IsNullable>true</ [rest of string was truncated]";. + /// + internal static string DataTypes { + get { + return ResourceManager.GetString("DataTypes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ALL,ALTER,AND,AS,AUTOINCREMENT,BETWEEN,BY,CASE,CHECK,COLLATE,COMMIT,CONSTRAINT,CREATE,CROSS,DEFAULT,DEFERRABLE,DELETE,DISTINCT,DROP,ELSE,ESCAPE,EXCEPT,FOREIGN,FROM,FULL,GROUP,HAVING,IN,INDEX,INNER,INSERT,INTERSECT,INTO,IS,ISNULL,JOIN,LEFT,LIMIT,NATURAL,NOT,NOTNULL,NULL,ON,OR,ORDER,OUTER,PRIMARY,REFERENCES,RIGHT,ROLLBACK,SELECT,SET,TABLE,THEN,TO,TRANSACTION,UNION,UNIQUE,UPDATE,USING,VALUES,WHEN,WHERE. + /// + internal static string Keywords { + get { + return ResourceManager.GetString("Keywords", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + ///<DocumentElement> + /// <MetaDataCollections> + /// <CollectionName>MetaDataCollections</CollectionName> + /// <NumberOfRestrictions>0</NumberOfRestrictions> + /// <NumberOfIdentifierParts>0</NumberOfIdentifierParts> + /// </MetaDataCollections> + /// <MetaDataCollections> + /// <CollectionName>DataSourceInformation</CollectionName> + /// <NumberOfRestrictions>0</NumberOfRestrictions> + /// <NumberOfIdentifierParts>0</NumberOfIdentifierParts> + /// </MetaDataCollections> + /// <MetaDataC [rest of string was truncated]";. + /// + internal static string MetaDataCollections { + get { + return ResourceManager.GetString("MetaDataCollections", resourceCulture); + } + } + } +} ADDED System.Data.SQLite/SR.resx Index: System.Data.SQLite/SR.resx ================================================================== --- /dev/null +++ System.Data.SQLite/SR.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + DataTypes.xml;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ALL,ALTER,AND,AS,AUTOINCREMENT,BETWEEN,BY,CASE,CHECK,COLLATE,COMMIT,CONSTRAINT,CREATE,CROSS,DEFAULT,DEFERRABLE,DELETE,DISTINCT,DROP,ELSE,ESCAPE,EXCEPT,FOREIGN,FROM,FULL,GROUP,HAVING,IN,INDEX,INNER,INSERT,INTERSECT,INTO,IS,ISNULL,JOIN,LEFT,LIMIT,NATURAL,NOT,NOTNULL,NULL,ON,OR,ORDER,OUTER,PRIMARY,REFERENCES,RIGHT,ROLLBACK,SELECT,SET,TABLE,THEN,TO,TRANSACTION,UNION,UNIQUE,UPDATE,USING,VALUES,WHEN,WHERE + + + MetaDataCollections.xml;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + Index: System.Data.SQLite/System.Data.SQLite.2005.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.2005.csproj +++ System.Data.SQLite/System.Data.SQLite.2005.csproj @@ -20,12 +20,11 @@ System.Data.SQLite $(MSBuildProjectDirectory)\.. true 2005 - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -39,27 +38,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.2008.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.2008.csproj +++ System.Data.SQLite/System.Data.SQLite.2008.csproj @@ -21,12 +21,11 @@ 2.0 $(MSBuildProjectDirectory)\.. true 2008 - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -40,27 +39,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.2010.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.2010.csproj +++ System.Data.SQLite/System.Data.SQLite.2010.csproj @@ -22,12 +22,11 @@ Client $(MSBuildProjectDirectory)\.. true 2010 - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -41,27 +40,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.2012.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.2012.csproj +++ System.Data.SQLite/System.Data.SQLite.2012.csproj @@ -20,12 +20,11 @@ $(MSBuildProjectDirectory)\.. true 2012 v4.5 - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -39,27 +38,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.2013.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.2013.csproj +++ System.Data.SQLite/System.Data.SQLite.2013.csproj @@ -20,12 +20,11 @@ $(MSBuildProjectDirectory)\.. true 2013 v4.5.1 - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -39,27 +38,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - ADDED System.Data.SQLite/System.Data.SQLite.CF.snk Index: System.Data.SQLite/System.Data.SQLite.CF.snk ================================================================== --- /dev/null +++ System.Data.SQLite/System.Data.SQLite.CF.snk cannot compute difference between binary files Index: System.Data.SQLite/System.Data.SQLite.Compact.2005.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.Compact.2005.csproj +++ System.Data.SQLite/System.Data.SQLite.Compact.2005.csproj @@ -31,12 +31,11 @@ false true 2005 Compact - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -56,29 +55,19 @@ true true prompt off - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.Compact.2008.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.Compact.2008.csproj +++ System.Data.SQLite/System.Data.SQLite.Compact.2008.csproj @@ -32,12 +32,11 @@ false true 2008 Compact - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -57,29 +56,19 @@ true true prompt off - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.Compact.2012.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.Compact.2012.csproj +++ System.Data.SQLite/System.Data.SQLite.Compact.2012.csproj @@ -28,12 +28,11 @@ false true 2012 Compact - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -53,30 +52,20 @@ true true prompt off - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - ADDED System.Data.SQLite/System.Data.SQLite.Files.targets Index: System.Data.SQLite/System.Data.SQLite.Files.targets ================================================================== --- /dev/null +++ System.Data.SQLite/System.Data.SQLite.Files.targets @@ -0,0 +1,107 @@ + + + + + + + Always + + + + + + + + + + Component + + + Component + + + Component + + + + + + Component + + + + + + + + + + + + + + + + + SR.resx + True + True + + + + Designer + ResXFileCodeGenerator + SR.Designer.cs + + + + + + + + + Component + + + Code + + + + + + + + + + + + + + Index: System.Data.SQLite/System.Data.SQLite.Module.2005.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.Module.2005.csproj +++ System.Data.SQLite/System.Data.SQLite.Module.2005.csproj @@ -24,12 +24,11 @@ 2005 Module false false - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -43,27 +42,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.Module.2008.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.Module.2008.csproj +++ System.Data.SQLite/System.Data.SQLite.Module.2008.csproj @@ -25,12 +25,11 @@ 2008 Module false false - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -44,27 +43,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.Module.2010.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.Module.2010.csproj +++ System.Data.SQLite/System.Data.SQLite.Module.2010.csproj @@ -26,12 +26,11 @@ 2010 Module false false - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -45,27 +44,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.Module.2012.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.Module.2012.csproj +++ System.Data.SQLite/System.Data.SQLite.Module.2012.csproj @@ -24,12 +24,11 @@ v4.5 Module false false - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -43,27 +42,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - Index: System.Data.SQLite/System.Data.SQLite.Module.2013.csproj ================================================================== --- System.Data.SQLite/System.Data.SQLite.Module.2013.csproj +++ System.Data.SQLite/System.Data.SQLite.Module.2013.csproj @@ -24,12 +24,11 @@ v4.5.1 Module false false - - + $(BinaryOutputPath) $(BinaryOutputPath)System.Data.SQLite.xml @@ -43,27 +42,17 @@ pdbonly true TRACE prompt - - - + + + - - - $(BuildDependsOn); - CopyConfigurations; - - - $(CleanDependsOn); - CleanConfigurations; - - ADDED System.Data.SQLite/System.Data.SQLite.Properties.targets Index: System.Data.SQLite/System.Data.SQLite.Properties.targets ================================================================== --- /dev/null +++ System.Data.SQLite/System.Data.SQLite.Properties.targets @@ -0,0 +1,249 @@ + + + + + $(DefineConstants);NET_20 + + + + + $(DefineConstants);NET_35 + + + + + $(DefineConstants);NET_40 + + + + + $(DefineConstants);NET_45 + + + + + $(DefineConstants);NET_451 + + + + + $(DefineConstants);NET_COMPACT_20 + + + + + $(DefineConstants);CHECK_STATE + + + + + $(DefineConstants);COUNT_HANDLE + + + + + $(DefineConstants);TRACK_MEMORY_BYTES + + + + + $(DefineConstants);USE_INTEROP_DLL + + + + + $(DefineConstants);USE_PREPARE_V2 + + + + + $(DefineConstants);SQLITE_STANDARD + + + + + $(DefineConstants);PLATFORM_COMPACTFRAMEWORK + + + + + $(DefineConstants);RETARGETABLE + + + + + $(DefineConstants);THROW_ON_DISPOSED + + + + + $(DefineConstants);PRELOAD_NATIVE_LIBRARY + + + + + $(DefineConstants);INTEROP_CODEC + + + + + $(DefineConstants);INTEROP_DEBUG + + + + + $(DefineConstants);INTEROP_EXTENSION_FUNCTIONS + + + + + $(DefineConstants);INTEROP_LEGACY_CLOSE + + + + + $(DefineConstants);INTEROP_LOG + + + + + $(DefineConstants);INTEROP_TEST_EXTENSION + + + + + $(DefineConstants);INTEROP_VIRTUAL_TABLE + + + + + $(DefineConstants);TRACE_CONNECTION + + + + $(DefineConstants);TRACE_HANDLE + + + + $(DefineConstants);TRACE_PRELOAD + + + + $(DefineConstants);TRACE_SHARED + + + + $(DefineConstants);TRACE_STATEMENT + + + + $(DefineConstants);TRACE_WARNING + + + + + $(DefineConstants);WINDOWS + + + + + $(DefineConstants);USE_ENTITY_FRAMEWORK_6 + + ADDED System.Data.SQLite/System.Data.SQLite.References.targets Index: System.Data.SQLite/System.Data.SQLite.References.targets ================================================================== --- /dev/null +++ System.Data.SQLite/System.Data.SQLite.References.targets @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + False + + + False + + + False + + + ADDED System.Data.SQLite/System.Data.SQLite.dll.config Index: System.Data.SQLite/System.Data.SQLite.dll.config ================================================================== --- /dev/null +++ System.Data.SQLite/System.Data.SQLite.dll.config @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED System.Data.SQLite/System.Data.SQLite.snk Index: System.Data.SQLite/System.Data.SQLite.snk ================================================================== --- /dev/null +++ System.Data.SQLite/System.Data.SQLite.snk cannot compute difference between binary files DELETED System.Data.SQLite/Targets/System.Data.SQLite.Files.targets Index: System.Data.SQLite/Targets/System.Data.SQLite.Files.targets ================================================================== --- System.Data.SQLite/Targets/System.Data.SQLite.Files.targets +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - Component - - - Component - - - Component - - - - - - Component - - - - - - - - - - - - - - - - - - SR.resx - True - True - - - Designer - ResXFileCodeGenerator - SR.Designer.cs - System.Data.SQLite.SR.resources - - - - - - - - - - Component - - - Code - - - - - - - - - - - - - - DELETED System.Data.SQLite/Targets/System.Data.SQLite.Properties.targets Index: System.Data.SQLite/Targets/System.Data.SQLite.Properties.targets ================================================================== --- System.Data.SQLite/Targets/System.Data.SQLite.Properties.targets +++ /dev/null @@ -1,253 +0,0 @@ - - - - - $(DefineConstants);NET_20 - - - - - $(DefineConstants);NET_35 - - - - - $(DefineConstants);NET_40 - - - - - $(DefineConstants);NET_45 - - - - - $(DefineConstants);NET_451 - - - - - $(DefineConstants);NET_COMPACT_20 - - - - - $(DefineConstants);CHECK_STATE - - - - - $(DefineConstants);COUNT_HANDLE - - - - - $(DefineConstants);TRACK_MEMORY_BYTES - - - - - $(DefineConstants);USE_INTEROP_DLL - - - - - $(DefineConstants);USE_PREPARE_V2 - - - - - $(DefineConstants);SQLITE_STANDARD - - - - - $(DefineConstants);PLATFORM_COMPACTFRAMEWORK - - - - - $(DefineConstants);RETARGETABLE - - - - - $(DefineConstants);THROW_ON_DISPOSED - - - - - $(DefineConstants);PRELOAD_NATIVE_LIBRARY - - - - - $(DefineConstants);INTEROP_CODEC - - - - - $(DefineConstants);INTEROP_DEBUG - - - - - $(DefineConstants);INTEROP_EXTENSION_FUNCTIONS - - - - - $(DefineConstants);INTEROP_LEGACY_CLOSE - - - - - $(DefineConstants);INTEROP_LOG - - - - - $(DefineConstants);INTEROP_TEST_EXTENSION - - - - - $(DefineConstants);INTEROP_VIRTUAL_TABLE - - - - - $(DefineConstants);TRACE_CONNECTION - - - - $(DefineConstants);TRACE_DETECTION - - - - $(DefineConstants);TRACE_HANDLE - - - - $(DefineConstants);TRACE_PRELOAD - - - - $(DefineConstants);TRACE_SHARED - - - - $(DefineConstants);TRACE_STATEMENT - - - - $(DefineConstants);TRACE_WARNING - - - - - $(DefineConstants);WINDOWS - - - - - $(DefineConstants);USE_ENTITY_FRAMEWORK_6 - - DELETED System.Data.SQLite/Targets/System.Data.SQLite.References.targets Index: System.Data.SQLite/Targets/System.Data.SQLite.References.targets ================================================================== --- System.Data.SQLite/Targets/System.Data.SQLite.References.targets +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - False - - - False - - - False - - - Index: System.Data.SQLite/UnsafeNativeMethods.cs ================================================================== --- System.Data.SQLite/UnsafeNativeMethods.cs +++ System.Data.SQLite/UnsafeNativeMethods.cs @@ -8,11 +8,11 @@ namespace System.Data.SQLite { using System; using System.Globalization; -#if !NET_COMPACT_20 && (TRACE_DETECTION || TRACE_SHARED || TRACE_PRELOAD || TRACE_HANDLE) +#if !NET_COMPACT_20 && (TRACE_PRELOAD || TRACE_HANDLE) using System.Diagnostics; #endif #if PRELOAD_NATIVE_LIBRARY using System.Collections.Generic; @@ -424,11 +424,11 @@ string xmlConfigFileName = Path.Combine( directory, XmlConfigFileName); if (File.Exists(xmlConfigFileName)) { -#if !NET_COMPACT_20 && TRACE_DETECTION +#if !NET_COMPACT_20 && TRACE_SHARED try { Trace.WriteLine(String.Format( CultureInfo.CurrentCulture, "Native library pre-loader found XML configuration file " + @@ -447,11 +447,11 @@ List matches = null; if (CheckForArchitecturesAndPlatforms(directory, ref matches) > 0) { -#if !NET_COMPACT_20 && TRACE_DETECTION +#if !NET_COMPACT_20 && TRACE_SHARED try { Trace.WriteLine(String.Format( CultureInfo.CurrentCulture, "Native library pre-loader found native sub-directories " + @@ -891,11 +891,11 @@ // if ((IntPtr.Size == sizeof(int)) && String.Equals(processorArchitecture, "AMD64", StringComparison.OrdinalIgnoreCase)) { -#if !NET_COMPACT_20 && TRACE_DETECTION +#if !NET_COMPACT_20 && TRACE_PRELOAD // // NOTE: When tracing is enabled, save the originally detected // processor architecture before changing it. // string savedProcessorArchitecture = processorArchitecture; @@ -907,11 +907,11 @@ // the "x86" processor architecture; therefore, return // "x86" when the pointer size is 32-bits. // processorArchitecture = "x86"; -#if !NET_COMPACT_20 && TRACE_DETECTION +#if !NET_COMPACT_20 && TRACE_PRELOAD try { // // NOTE: Show that we hit a fairly unusual situation (i.e. // the "wrong" processor architecture was detected). @@ -1202,11 +1202,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.093.dll"; + internal const string SQLITE_DLL = "SQLite.Interop.091.dll"; #elif SQLITE_STANDARD // // NOTE: Otherwise, if the standard SQLite library is enabled, use it. // internal const string SQLITE_DLL = "sqlite3"; DELETED Targets/SQLite.NET.Settings.targets Index: Targets/SQLite.NET.Settings.targets ================================================================== --- Targets/SQLite.NET.Settings.targets +++ /dev/null @@ -1,580 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - false - - - true - - - false - - - - - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - - - - - false - - - false - - - false - - - true - - - true - - - false - - - false - - - false - - - true - - - true - - - true - - - true - false - - - true - - - true - false - - - false - - - true - false - - - true - - - true - - - false - - - - - - - false - - - false - - - false - - - true - - - true - - - false - - - true - - - - - - - 4 - 618,1591;3001 - - - - - 4 - 618,1591;3001 - - - - - - - - - - - - - - $(SQLiteNetDir)\obj\$(ConfigurationYear)\ - $(SQLiteNetDir)\obj\$(ConfigurationYear)\$(ConfigurationSuffix)\ - - - - - - - $(SQLiteNetDir)\bin\$(ConfigurationYear)\$(Configuration)$(ConfigurationSuffix)\bin\ - - - - - - - true - - - false - - - $(SQLiteNetDir)\Keys\System.Data.SQLite.snk - $(SQLiteNetDir)\Keys\System.Data.SQLite.CF.snk - - DELETED Targets/SQLite.NET.Settings.targets.netFx35 Index: Targets/SQLite.NET.Settings.targets.netFx35 ================================================================== --- Targets/SQLite.NET.Settings.targets.netFx35 +++ /dev/null @@ -1,23 +0,0 @@ - - - - true - true - false - false - false - v3.5 - - false - v110 - - DELETED Targets/SQLite.NET.targets Index: Targets/SQLite.NET.targets ================================================================== --- Targets/SQLite.NET.targets +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Index: Tests/basic.eagle ================================================================== --- Tests/basic.eagle +++ Tests/basic.eagle @@ -1071,31 +1071,28 @@ BinaryGUID "Data Source" Uri FullUri "Default Timeout" \ Enlist FailIfMissing "Legacy Format" "Read Only" \ Password "Page Size" "Max Page Count" "Cache Size" \ DateTimeFormat DateTimeKind DateTimeFormatString \ BaseSchemaName "Journal Mode" "Default IsolationLevel" \ - "Foreign Keys" Flags SetDefaults ToFullPath HexPassword \ - DefaultDbType DefaultTypeName NoSharedFlags] + "Foreign Keys" Flags SetDefaults ToFullPath HexPassword] 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 yyyy-MM-dd sqlite_schema \ Memory Serializable False \ - Default False False 736563726574 String \ - TEXT True] + Default False False 736563726574] set propertyNames [list null Version SyncMode UseUTF16Encoding Pooling \ BinaryGUID DataSource Uri FullUri DefaultTimeout \ Enlist FailIfMissing LegacyFormat ReadOnly \ Password PageSize MaxPageCount CacheSize \ DateTimeFormat DateTimeKind DateTimeFormatString \ BaseSchemaName JournalMode DefaultIsolationLevel \ ForeignKeys Flags SetDefaults ToFullPath \ - HexPassword DefaultDbType DefaultTypeName \ - NoSharedFlags] + HexPassword] foreach key $keys value $values propertyName $propertyNames { set code [catch { object invoke _Dynamic${id}.Test${id} GetConnectionString \ $key $value $propertyName @@ -1123,13 +1120,11 @@ DateTimeFormatString=yyyy-MM-dd\} 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} 0\ -\{String, DefaultDbType=String\} 0 \{TEXT, DefaultTypeName=TEXT\} 0 \{True,\ -NoSharedFlags=True\}$}} +\{False, ToFullPath=False\} 0 {736563726574, HexPassword=736563726574}$}} ############################################################################### runTest {test data-1.18 {SQLiteConvert ToDateTime (Julian Day)} -body { set dateTime [object invoke -create System.Data.SQLite.SQLiteConvert \ @@ -1844,11 +1839,11 @@ tputs $test_channel [appendArgs "---- created temporary directory \"" \ $directory(temp) \"\n] proc threadStart {} { - while {$::i < 1000} { + while {$::i < 100} { set ::found(temp) [expr \ {[llength [file list $::directory(temp) etilqs_*]] > 0}] if {$::found(temp)} then { return @@ -2959,216 +2954,10 @@ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ {1 {} {} 2 {} 1 3 {} 0 4 {} 1 5 {} 0 6 1 {} 7 1 1 8 1 0 9 1 1 10 1 0 11 0 {} 12\ 0 1 13 0 0 14 0 1 15 0 0 16 1 {} 17 1 1 18 1 0 19 1 1 20 1 0 21 0 {} 22 0 1 23\ 0 0 24 0 1 25 0 0}} -############################################################################### - -runTest {test data-1.63 {SQLiteDataReader HasRows property} -setup { - setupDb [set fileName data-1.63.db] -} -body { - sql execute $db { - CREATE TABLE t1(x); - CREATE TABLE t2(x); - INSERT INTO t2 (x) VALUES(1); - CREATE TABLE t3(x); - INSERT INTO t3 (x) VALUES(1); - INSERT INTO t3 (x) VALUES(2); - } - - set reader(1) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t1;"] - - set reader(2) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t2;"] - - set reader(3) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t3;"] - - set noRow "*: No current row*" - - list [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] -} -cleanup { - unset -nocomplain reader - - cleanupDb $fileName - - unset -nocomplain error noRow db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{False True True False True True False True True 1 True 0 False 0 False False\ -True True False False True False False True 1 True 1 True 0 False False False\ -True False False False False False False 1 True 1 True 1 True}} - -############################################################################### - -runTest {test data-1.64 {SQLiteDataReader sticky HasRows property} -setup { - setupDb [set fileName data-1.64.db] "" "" "" StickyHasRows -} -body { - sql execute $db { - CREATE TABLE t1(x); - CREATE TABLE t2(x); - INSERT INTO t2 (x) VALUES(1); - CREATE TABLE t3(x); - INSERT INTO t3 (x) VALUES(1); - INSERT INTO t3 (x) VALUES(2); - } - - set reader(1) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t1;"] - - set reader(2) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t2;"] - - set reader(3) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t3;"] - - set noRow "*: No current row*" - - list [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) HasRows] [$reader(2) HasRows] [$reader(3) HasRows] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] -} -cleanup { - unset -nocomplain reader - - cleanupDb $fileName - - unset -nocomplain error noRow db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{False True True False True True False True True 1 True 0 False 0 False False\ -True True False False True False True True 1 True 1 True 0 False False True\ -True False False False False True True 1 True 1 True 1 True}} - -############################################################################### - -runTest {test data-1.65 {SQLiteDataReader StepCount property} -setup { - setupDb [set fileName data-1.65.db] -} -body { - sql execute $db { - CREATE TABLE t1(x); - CREATE TABLE t2(x); - INSERT INTO t2 (x) VALUES(1); - CREATE TABLE t3(x); - INSERT INTO t3 (x) VALUES(1); - INSERT INTO t3 (x) VALUES(2); - } - - set reader(1) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t1;"] - - set reader(2) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t2;"] - - set reader(3) [sql execute -execute reader -format datareader -alias \ - $db "SELECT * FROM t3;"] - - set noRow "*: No current row*" - - list [$reader(1) StepCount] [$reader(2) StepCount] [$reader(3) StepCount] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) StepCount] [$reader(2) StepCount] [$reader(3) StepCount] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] \ - [$reader(1) StepCount] [$reader(2) StepCount] [$reader(3) StepCount] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) StepCount] [$reader(2) StepCount] [$reader(3) StepCount] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] \ - [$reader(1) StepCount] [$reader(2) StepCount] [$reader(3) StepCount] \ - [$reader(1) Read] [$reader(2) Read] [$reader(3) Read] \ - [$reader(1) StepCount] [$reader(2) StepCount] [$reader(3) StepCount] \ - [catch {$reader(1) Item x} error] [string match $noRow $error] \ - [catch {$reader(2) Item x} error] [string match $noRow $error] \ - [catch {$reader(3) Item x} error] [string match $noRow $error] -} -cleanup { - unset -nocomplain reader - - cleanupDb $fileName - - unset -nocomplain error noRow db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{0 1 1 False True True 0 1 1 1 True 0 False 0 False 0 1 1 False False True 0 1\ -2 1 True 1 True 0 False 0 1 2 False False False 0 1 2 1 True 1 True 1 True}} - -############################################################################### - -runTest {test data-1.66 {SQLiteConnection.SetChunkSize default} -setup { - setupDb [set fileName data-1.66.db] -} -body { - sql execute $db { - CREATE TABLE t1(a, b); - } - - file size [file join [getDatabaseDirectory] $fileName] -} -cleanup { - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{2048}} - -############################################################################### - -runTest {test data-1.67 {SQLiteConnection.SetChunkSize method} -setup { - setupDb [set fileName data-1.67.db] -} -body { - set connection [getDbConnection] - - lappend result [$connection SetChunkSize [expr {32 * 1024}]] - - sql execute $db { - CREATE TABLE t1(a, b); - } - - lappend result [file size [file join [getDatabaseDirectory] $fileName]] -} -cleanup { - cleanupDb $fileName - - freeDbConnection - - unset -nocomplain result connection db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{Ok 32768}} - ############################################################################### reportSQLiteResources $test_channel ############################################################################### Index: Tests/common.eagle ================================================================== --- Tests/common.eagle +++ Tests/common.eagle @@ -1145,11 +1145,11 @@ # NOTE: Manually override all the build directory selection # related test settings in order to force this build # of System.Data.SQLite to be used. # object invoke Interpreter.GetActive [expr {$native ? \ - "AddRuntimeOption" : "RemoveRuntimeOption"}] native + "AddRuntimeOption" : "RemoveRuntimeOption"}] native set ::test_year $year set ::test_platform $platform set ::test_configuration $configuration @@ -1558,29 +1558,10 @@ "---- local connection flags for " $database \ " are: " [expr {[string length $flags] > 0 ? \ [appendArgs \" $flags \"] : ""}] \n] } - # - # NOTE: Show (and log) the shared connection flags. - # - if {!$quiet} then { - if {[catch { - object invoke System.Data.SQLite.SQLiteConnection SharedFlags - } sharedFlags] == 0} then { - tputs $::test_channel [appendArgs \ - "---- shared connection flags for " $database \ - " are: " [expr {[string length $sharedFlags] > 0 && \ - $sharedFlags ne "None" ? \ - [appendArgs \" $sharedFlags \"] : ""}] \n] - } else { - tputs $::test_channel [appendArgs \ - "---- shared connection flags for " $database \ - " are: \n"] - } - } - # # NOTE: If there are any global (per test run) connection flags currently # set, use them now (i.e. by combining them with the ones for this # connection). # @@ -2965,14 +2946,14 @@ CHECK_STATE COUNT_HANDLE DEBUG INTEROP_CODEC INTEROP_DEBUG \ INTEROP_EXTENSION_FUNCTIONS INTEROP_LEGACY_CLOSE INTEROP_LOG \ INTEROP_TEST_EXTENSION INTEROP_VIRTUAL_TABLE NET_20 NET_35 \ NET_40 NET_45 NET_451 NET_COMPACT_20 PLATFORM_COMPACTFRAMEWORK \ PRELOAD_NATIVE_LIBRARY RETARGETABLE SQLITE_STANDARD \ - THROW_ON_DISPOSED TRACE TRACE_CONNECTION TRACE_DETECTION \ - TRACE_HANDLE TRACE_PRELOAD TRACE_SHARED TRACE_STATEMENT \ - TRACE_WARNING TRACK_MEMORY_BYTES USE_ENTITY_FRAMEWORK_6 \ - USE_INTEROP_DLL USE_PREPARE_V2 WINDOWS] { + THROW_ON_DISPOSED TRACE TRACE_CONNECTION TRACE_HANDLE \ + TRACE_PRELOAD TRACE_SHARED TRACE_STATEMENT TRACE_WARNING \ + TRACK_MEMORY_BYTES USE_ENTITY_FRAMEWORK_6 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 @@ -3141,16 +3122,10 @@ # tputs $::test_channel [appendArgs \ "---- System.Data.SQLite tests ended at " \ [clock format [clock seconds]] \n] - # - # NOTE: Load the "epilogue" custom per-user and/or per-host test - # settings now. - # - uplevel 1 [list loadSQLiteTestSettings $::test_channel .epilogue] - # # 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 DELETED Tests/speed.eagle Index: Tests/speed.eagle ================================================================== --- Tests/speed.eagle +++ /dev/null @@ -1,172 +0,0 @@ -############################################################################### -# -# speed.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: 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 speed-1.1 {SQLiteDataReader speed testing} -setup { - setupDb [set fileName [appendArgs speed-1.1- [pid] .db]] - - sql execute $db "CREATE TABLE t1(w INTEGER);" - sql execute $db "CREATE TABLE t2(x REAL);" - sql execute $db "CREATE TABLE t3(y TEXT);" - sql execute $db "CREATE TABLE t4(z BLOB);" - - sql execute $db "INSERT INTO t1 (w) VALUES(NULL);" - sql execute $db "INSERT INTO t1 (w) VALUES(-9223372036854775808);" - sql execute $db "INSERT INTO t1 (w) VALUES(0);" - sql execute $db "INSERT INTO t1 (w) VALUES(9223372036854775807);" - - sql execute $db "INSERT INTO t2 (x) VALUES(NULL);" - sql execute $db "INSERT INTO t2 (x) VALUES(-1.7976931348623157e+308);" - sql execute $db "INSERT INTO t2 (x) VALUES(0.0);" - sql execute $db "INSERT INTO t2 (x) VALUES(1.7976931348623157e+308);" - - sql execute $db "INSERT INTO t3 (y) VALUES(NULL);" - sql execute $db "INSERT INTO t3 (y) VALUES('1');" - sql execute $db "INSERT INTO t3 (y) VALUES('1.1');" - - sql execute $db [appendArgs \ - "INSERT INTO t3 (y) VALUES('" [string repeat \ - [format %c [expr {int(rand() * 0x80)}]] 1048576] "');"] - - sql execute $db "INSERT INTO t4 (z) VALUES(NULL);" - sql execute $db "INSERT INTO t4 (z) VALUES(X'01');" - sql execute $db "INSERT INTO t4 (z) VALUES(X'0123456789');" - sql execute $db "INSERT INTO t4 (z) VALUES(randomblob(1048576));" -} -body { - set result [list] - - foreach sql [list \ - {SELECT CASE length(w) = 1048576 - WHEN 1 THEN length(w) ELSE w END FROM t1;} \ - {SELECT CASE length(x) = 1048576 - WHEN 1 THEN length(x) ELSE x END FROM t2;} \ - {SELECT CASE length(y) = 1048576 - WHEN 1 THEN length(y) ELSE y END FROM t3;} \ - {SELECT CASE length(z) = 1048576 - WHEN 1 THEN length(z) ELSE z END FROM t4;}] { - tputs $test_channel [appendArgs \ - "---- executed query \"" \ - [string map [list "\n " " "] $sql] "\" in " [time { - lappend result [sql execute -execute reader -format list $db $sql] - }] \n] - } - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain sql table column result db fileName -} -time true -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ -System.Data.SQLite} -result {{-9223372036854775808 0 9223372036854775807}\ -{-Infinity 0 Infinity} {1 1.1 1048576} {1 {1 35 69 103 137} 1048576}}} - -############################################################################### - -runTest {test speed-1.2 {SQLiteDataReader speed testing} -setup { - setupDb [set fileName [appendArgs speed-1.2- [pid] .db]] - - sql execute $db "CREATE TABLE t1(w INTEGER);" - sql execute $db "CREATE TABLE t2(x REAL);" - sql execute $db "CREATE TABLE t3(y TEXT);" - sql execute $db "CREATE TABLE t4(z BLOB);" - - sql execute $db "INSERT INTO t1 (w) VALUES(NULL);" - sql execute $db "INSERT INTO t1 (w) VALUES(-9223372036854775808);" - sql execute $db "INSERT INTO t1 (w) VALUES(0);" - sql execute $db "INSERT INTO t1 (w) VALUES(9223372036854775807);" - - sql execute $db "INSERT INTO t2 (x) VALUES(NULL);" - sql execute $db "INSERT INTO t2 (x) VALUES(-1.7976931348623157e+308);" - sql execute $db "INSERT INTO t2 (x) VALUES(0.0);" - sql execute $db "INSERT INTO t2 (x) VALUES(1.7976931348623157e+308);" - - sql execute $db "INSERT INTO t3 (y) VALUES(NULL);" - sql execute $db "INSERT INTO t3 (y) VALUES('1');" - sql execute $db "INSERT INTO t3 (y) VALUES('1.1');" - - sql execute $db [appendArgs \ - "INSERT INTO t3 (y) VALUES('" [string repeat \ - [format %c [expr {int(rand() * 0x80)}]] 1048576] "');"] - - sql execute $db "INSERT INTO t4 (z) VALUES(NULL);" - sql execute $db "INSERT INTO t4 (z) VALUES(X'01');" - sql execute $db "INSERT INTO t4 (z) VALUES(X'0123456789');" - sql execute $db "INSERT INTO t4 (z) VALUES(randomblob(1048576));" -} -body { - set result [list] - - foreach {column table} [list w t1 x t2 y t3 z t4] { - set sql [appendArgs "SELECT " $column " FROM " $table \;] - - tputs $test_channel [appendArgs \ - "---- executed query \"" $sql "\" in " [time { - lappend result [llength [sql execute \ - -execute reader -format list $db $sql]] - }] \n] - } - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain sql table column result db fileName -} -time true -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ -System.Data.SQLite} -result {3 3 3 3}} - -############################################################################### - -# -# NOTE: Report after test. -# -checkForSQLiteDirectories $test_channel -getSQLiteHandleCounts $test_channel -reportSQLiteResources $test_channel - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/tkt-3113734605.eagle ================================================================== --- Tests/tkt-3113734605.eagle +++ Tests/tkt-3113734605.eagle @@ -25,16 +25,11 @@ } -body { set connection [getDbConnection] set result [list] - sql execute $db { - CREATE TABLE t1( - v BINARY(12), w CHAR(23), x NCHAR(34), y VARCHAR(45), z NVARCHAR(56) - ); - } - + sql execute $db "CREATE TABLE t1 (x CHAR(3));" sql execute $db "CREATE VIEW v1 AS SELECT * FROM t1;" foreach collectionName [list TABLECOLUMNS VIEWCOLUMNS] { set dataTable [object invoke -alias $connection GetSchema $collectionName] @@ -58,16 +53,12 @@ unset -nocomplain value dataRow dataRows dataTable collectionName result \ connection db fileName } -constraints \ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \ -regexp -result {^t1 v 12 System#DBNull#\d+ t1 w 23 System#DBNull#\d+ t1 x 34\ -System#DBNull#\d+ t1 y 45 System#DBNull#\d+ t1 z 56 System#DBNull#\d+ v1 v 12\ -System#DBNull#\d+ v1 w 23 System#DBNull#\d+ v1 x 34 System#DBNull#\d+ v1 y 45\ -System#DBNull#\d+ v1 z 56 System#DBNull#\d+ t1 v 12 System#DBNull#\d+ t1 w 23\ -System#DBNull#\d+ t1 x 34 System#DBNull#\d+ t1 y 45 System#DBNull#\d+ t1 z 56\ +regexp -result {^t1 x 3 System#DBNull#\d+ v1 x 3 System#DBNull#\d+ t1 x 3\ System#DBNull#\d+$}} ############################################################################### runSQLiteTestEpilogue runTestEpilogue DELETED Tests/tkt-3c00ec5b52.eagle Index: Tests/tkt-3c00ec5b52.eagle ================================================================== --- Tests/tkt-3c00ec5b52.eagle +++ /dev/null @@ -1,217 +0,0 @@ -############################################################################### -# -# tkt-3c00ec5b52.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 - -############################################################################### - -proc saveSQLiteConvertEnvironment {} { - foreach name [list \ - Use_SQLiteConvert_DefaultDbType Use_SQLiteConvert_DefaultTypeName] { - # - # NOTE: Does the live environment variable exist? If so, save the value - # for later; otherwise, make sure the saved value does not exist - # either. The live environment variables ARE NOT changed by this - # procedure. - # - if {[uplevel 1 [list info exists env($name)]]} then { - uplevel 1 [list set savedEnv($name) [uplevel 1 [list set env($name)]]] - } else { - uplevel 1 [list unset -nocomplain savedEnv($name)] - } - } -} - -proc restoreSQLiteConvertEnvironment {} { - foreach name [list \ - Use_SQLiteConvert_DefaultDbType Use_SQLiteConvert_DefaultTypeName] { - # - # NOTE: Does the saved environment variable exist? If so, restore the - # saved value and then unset it; otherwise, make sure the live - # environment variable does not exist either (i.e. it was not set - # to begin with). Both the saved and live environment variables - # ARE changed by this procedure. - # - if {[uplevel 1 [list info exists savedEnv($name)]]} then { - uplevel 1 [list set env($name) [uplevel 1 [list set savedEnv($name)]]] - uplevel 1 [list unset -nocomplain savedEnv($name)] - } else { - uplevel 1 [list unset -nocomplain env($name)] - } - } -} - -############################################################################### - -runTest {test tkt-3c00ec5b52-1.1 {default types, via connection} -setup { - setupDb [set fileName tkt-3c00ec5b52-1.1.db] "" "" "" UseConnectionTypes \ - "DefaultDbType=String;DefaultTypeName=TEXT;" -} -body { - set connection [getDbConnection] - set result [list] - - lappend result [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConvert TypeNameToDbType $connection "" None] - - lappend result [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConvert DbTypeToTypeName $connection Object None] - - set result -} -cleanup { - freeDbConnection - - unset -nocomplain result connection - - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{String TEXT}} - -############################################################################### - -runTest {test tkt-3c00ec5b52-1.2 {fallback default types w/flag} -setup { - setupDb [set fileName tkt-3c00ec5b52-1.2.db] "" "" "" UseConnectionTypes -} -body { - set connection [getDbConnection] - set result [list] - - lappend result [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConvert TypeNameToDbType $connection "" None] - - lappend result [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConvert DbTypeToTypeName $connection Object None] - - set result -} -cleanup { - freeDbConnection - - unset -nocomplain result connection - - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{Object {}}} - -############################################################################### - -runTest {test tkt-3c00ec5b52-1.3 {fallback default types w/o flag} -setup { - setupDb [set fileName tkt-3c00ec5b52-1.3.db] -} -body { - set connection [getDbConnection] - set result [list] - - lappend result [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConvert TypeNameToDbType $connection "" None] - - lappend result [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConvert DbTypeToTypeName $connection Object None] - - set result -} -cleanup { - freeDbConnection - - unset -nocomplain result connection - - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{Object {}}} - -############################################################################### - -runTest {test tkt-3c00ec5b52-1.4 {default types, via environment} -setup { - saveSQLiteConvertEnvironment - - set env(Use_SQLiteConvert_DefaultDbType) String - set env(Use_SQLiteConvert_DefaultTypeName) TEXT - - setupDb [set fileName tkt-3c00ec5b52-1.4.db] -} -body { - set connection [getDbConnection] - set result [list] - - lappend result [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConvert TypeNameToDbType $connection "" None] - - lappend result [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConvert DbTypeToTypeName $connection Object None] - - set result -} -cleanup { - freeDbConnection - - unset -nocomplain result connection - - cleanupDb $fileName - restoreSQLiteConvertEnvironment - - unset -nocomplain db fileName savedEnv -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{String TEXT}} - -############################################################################### - -runTest {test tkt-3c00ec5b52-1.5 {default types, with unique index} -setup { - saveSQLiteConvertEnvironment - - set env(Use_SQLiteConvert_DefaultDbType) String - set env(Use_SQLiteConvert_DefaultTypeName) TEXT - - setupDb [set fileName tkt-3c00ec5b52-1.5.db] -} -body { - sql execute $db "CREATE TABLE t1(x UNIQUE);" - - set connection [getDbConnection] - set dataTable [$connection -alias GetSchema INDEXES] - set results [list] - - object foreach -alias dataRow [set dataRows [$dataTable -alias Rows]] { - lappend results [list [$dataRow Item TABLE_NAME] \ - [$dataRow Item INDEX_NAME] [$dataRow Item UNIQUE]] - } - - set results -} -cleanup { - freeDbConnection - - unset -nocomplain results dataRow dataRows dataTable connection - - cleanupDb $fileName - restoreSQLiteConvertEnvironment - - unset -nocomplain db fileName savedEnv -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{{t1 sqlite_autoindex_t1_1 True}}} - -############################################################################### - -rename restoreSQLiteConvertEnvironment "" -rename saveSQLiteConvertEnvironment "" - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/tkt-56b42d99c1.eagle ================================================================== --- Tests/tkt-56b42d99c1.eagle +++ Tests/tkt-56b42d99c1.eagle @@ -173,11 +173,11 @@ 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 + unset -nocomplain result results errors code dataSource id db fileName } -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ System.Data.SQLite compileCSharp} -match regexp -result {^Ok\ System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 0$}} ############################################################################### @@ -250,11 +250,11 @@ 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 + unset -nocomplain result results errors code dataSource id db fileName } -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ System.Data.SQLite compileCSharp} -match regexp -result {^Ok\ System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 1$}} ############################################################################### @@ -327,11 +327,11 @@ 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 + unset -nocomplain result results errors code dataSource id db fileName } -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ System.Data.SQLite compileCSharp} -match regexp -result {^Ok\ System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 0$}} ############################################################################### @@ -404,415 +404,14 @@ 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 compileCSharp} -match regexp -result {^Ok\ -System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 1$}} - -############################################################################### - -set flags MapIsolationLevels - -############################################################################### - -runTest {test tkt-56b42d99c1-1.6 {enlisted transaction isolation} -setup { - setupDb [set fileName tkt-56b42d99c1-1.6.db] -} -body { - 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; - using System.Reflection; - using System.Transactions; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static bool TryEnlistInTransaction() - { - TransactionOptions transactionOptions = new TransactionOptions(); - transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted; - - using (TransactionScope transactionScope = new TransactionScope( - TransactionScopeOption.Required, transactionOptions)) - { - using (SQLiteConnection connection1 = new SQLiteConnection( - "Data Source=${dataSource};[getFlagsProperty $flags]")) - { - connection1.Open(); - - using (SQLiteConnection connection2 = new SQLiteConnection( - "Data Source=${dataSource};[getFlagsProperty $flags]")) - { - connection2.Open(); - - BindingFlags bindingFlags = BindingFlags.Instance | - BindingFlags.NonPublic | BindingFlags.GetField; - - FieldInfo fieldInfo1 = connection1.GetType().GetField( - "_enlistment", bindingFlags); - - object enlistment1 = fieldInfo1.GetValue(connection1); - object enlistment2 = fieldInfo1.GetValue(connection2); - - FieldInfo fieldInfo2 = enlistment1.GetType().GetField( - "_transaction", bindingFlags); - - SQLiteTransaction transaction1 = - (SQLiteTransaction)fieldInfo2.GetValue(enlistment1); - - SQLiteTransaction transaction2 = - (SQLiteTransaction)fieldInfo2.GetValue(enlistment2); - - return (transaction1.IsolationLevel == - transaction2.IsolationLevel); - } - } - } - } - - /////////////////////////////////////////////////////////////////////// - - public static void Main() - { - // do nothing. - } - } - } - }] 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} TryEnlistInTransaction - } 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 compileCSharp} -match regexp -result {^Ok\ -System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 True$}} - -############################################################################### - -runTest {test tkt-56b42d99c1-1.7 {enlisted transaction isolation} -setup { - setupDb [set fileName tkt-56b42d99c1-1.7.db] -} -body { - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - - unset -nocomplain results errors - - set sql(1) { \ - CREATE TABLE t1(x); \ - INSERT INTO t1 (x) VALUES(1); \ - } - - set sql(2) { \ - SELECT COUNT(*) FROM sqlite_master WHERE type = 'table'; \ - } - - set code [compileCSharpWith [subst { - using System.Data.SQLite; - using System.Transactions; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static int Main() - { - TransactionOptions transactionOptions = new TransactionOptions(); - transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted; - - using (TransactionScope transactionScope = new TransactionScope( - TransactionScopeOption.Required, transactionOptions)) - { - using (SQLiteConnection connection1 = new SQLiteConnection( - "Data Source=${dataSource};[getFlagsProperty $flags]")) - { - connection1.Open(); - - using (SQLiteConnection connection2 = new SQLiteConnection( - "Data Source=${dataSource};[getFlagsProperty $flags]")) - { - connection2.Open(); - - using (SQLiteCommand command1 = connection1.CreateCommand()) - { - command1.CommandText = "${sql(1)}"; - command1.ExecuteNonQuery(); - - using (SQLiteCommand command2 = connection2.CreateCommand()) - { - command2.CommandText = "${sql(2)}"; - return (int)(long)command2.ExecuteScalar(); - } - } - } - } - } - } - } - } - }] 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 compileCSharp} -match regexp -result {^Ok\ -System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 0$}} - -############################################################################### - -runTest {test tkt-56b42d99c1-1.8 {enlisted transaction isolation} -setup { - setupDb [set fileName tkt-56b42d99c1-1.8.db] -} -body { - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - - unset -nocomplain results errors - - set sql(1) { \ - CREATE TABLE t1(x); \ - INSERT INTO t1 (x) VALUES(1); \ - } - - set sql(2) { \ - SELECT COUNT(*) FROM sqlite_master WHERE type = 'table'; \ - } - - set code [compileCSharpWith [subst { - using System.Data.SQLite; - using System.Transactions; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static int Main() - { - TransactionOptions transactionOptions = new TransactionOptions(); - transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted; - - using (TransactionScope transactionScope = new TransactionScope( - TransactionScopeOption.Required, transactionOptions)) - { - using (SQLiteConnection connection1 = new SQLiteConnection( - "Data Source=${dataSource};Enlist=False;[getFlagsProperty $flags]")) - { - connection1.Open(); - - using (SQLiteConnection connection2 = new SQLiteConnection( - "Data Source=${dataSource};Enlist=False;[getFlagsProperty $flags]")) - { - connection2.Open(); - - using (SQLiteCommand command1 = connection1.CreateCommand()) - { - command1.CommandText = "${sql(1)}"; - command1.ExecuteNonQuery(); - - using (SQLiteCommand command2 = connection2.CreateCommand()) - { - command2.CommandText = "${sql(2)}"; - return (int)(long)command2.ExecuteScalar(); - } - } - } - } - } - } - } - } - }] 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 compileCSharp} -match regexp -result {^Ok\ -System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 1$}} - -############################################################################### - -runTest {test tkt-56b42d99c1-1.9 {enlisted transaction isolation} -setup { - setupDb [set fileName tkt-56b42d99c1-1.9.db] -} -body { - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - - unset -nocomplain results errors - - set sql(1) { \ - CREATE TABLE t1(x); \ - INSERT INTO t1 (x) VALUES(1); \ - } - - set sql(2) { \ - SELECT COUNT(*) FROM sqlite_master WHERE type = 'table'; \ - } - - set code [compileCSharpWith [subst { - using System.Data.SQLite; - using System.Transactions; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static int Main() - { - TransactionOptions transactionOptions = new TransactionOptions(); - transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted; - - using (TransactionScope transactionScope = new TransactionScope( - TransactionScopeOption.Required, transactionOptions)) - { - using (SQLiteConnection connection1 = new SQLiteConnection( - "Data Source=${dataSource};[getFlagsProperty $flags]")) - { - connection1.Open(); - - using (SQLiteConnection connection2 = new SQLiteConnection( - "Data Source=${dataSource};Enlist=False;[getFlagsProperty $flags]")) - { - connection2.Open(); - - using (SQLiteCommand command1 = connection1.CreateCommand()) - { - command1.CommandText = "${sql(1)}"; - command1.ExecuteNonQuery(); - - using (SQLiteCommand command2 = connection2.CreateCommand()) - { - command2.CommandText = "${sql(2)}"; - return (int)(long)command2.ExecuteScalar(); - } - } - } - } - } - } - } - } - }] 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 compileCSharp} -match regexp -result {^Ok\ -System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 0$}} - -############################################################################### - -runTest {test tkt-56b42d99c1-1.10 {enlisted transaction isolation} -setup { - setupDb [set fileName tkt-56b42d99c1-1.10.db] -} -body { - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - - unset -nocomplain results errors - - set sql(1) { \ - CREATE TABLE t1(x); \ - INSERT INTO t1 (x) VALUES(1); \ - } - - set sql(2) { \ - SELECT COUNT(*) FROM sqlite_master WHERE type = 'table'; \ - } - - set code [compileCSharpWith [subst { - using System.Data.SQLite; - using System.Transactions; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static int Main() - { - TransactionOptions transactionOptions = new TransactionOptions(); - transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted; - - using (TransactionScope transactionScope = new TransactionScope( - TransactionScopeOption.Required, transactionOptions)) - { - using (SQLiteConnection connection1 = new SQLiteConnection( - "Data Source=${dataSource};Enlist=False;[getFlagsProperty $flags]")) - { - connection1.Open(); - - using (SQLiteConnection connection2 = new SQLiteConnection( - "Data Source=${dataSource};[getFlagsProperty $flags]")) - { - connection2.Open(); - - using (SQLiteCommand command1 = connection1.CreateCommand()) - { - command1.CommandText = "${sql(1)}"; - command1.ExecuteNonQuery(); - - using (SQLiteCommand command2 = connection2.CreateCommand()) - { - command2.CommandText = "${sql(2)}"; - return (int)(long)command2.ExecuteScalar(); - } - } - } - } - } - } - } - } - }] 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 compileCSharp} -match regexp -result {^Ok\ -System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 1$}} - -############################################################################### - -unset -nocomplain flags + unset -nocomplain result results errors code dataSource id db fileName +} -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ +System.Data.SQLite compileCSharp} -match regexp -result {^Ok\ +System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 1$}} ############################################################################### runSQLiteTestEpilogue runTestEpilogue Index: Tests/tkt-72905c9a77.eagle ================================================================== --- Tests/tkt-72905c9a77.eagle +++ Tests/tkt-72905c9a77.eagle @@ -94,12 +94,12 @@ // under test is private and cannot normally be executed from // C# directly. If this fails, the following statement will // throw a NullReferenceException, which is fine as that will // cause the whole test to fail. // - Type type = Type.GetType( - "System.Data.SQLite.SQLite3, System.Data.SQLite"); + Type type = Type.GetType("System.Data.SQLite.SQLite3, " + + "System.Data.SQLite"); // // NOTE: Attempt to lookup the method object for the private method // we need for this test. If this fails, the first attempt // to invoke the method using this variable will throw a @@ -124,10 +124,17 @@ // machine with 4 processors, limit the total number of // threads to 16. // int count = Math.Min(4 * Environment.ProcessorCount, 16); + // + // NOTE: Create a random number generator suitable for waiting a + // random number of milliseconds between each attempt to + // cause the race condition on a given thread. + // + Random random = new Random(); + // // NOTE: Create a (reusable) delegate that will contain the code // that each created thread is to execute. // ThreadStart threadStart = delegate() @@ -138,18 +145,10 @@ // NOTE: Wait forever for the "GO" signal so that all threads // can start working at approximately the same time. // goEvent.WaitOne(); - // - // NOTE: Create a pseudorandom number generator suitable for - // waiting a random number of milliseconds between each - // attempt to cause the race condition being tested on - // a given thread. - // - Random random = new Random(); - // // NOTE: Force the SQLiteLog.StaticIsInitialized method to // be repeatedly called on every thread right away to // thoroughly test its locking semantics. Also, use a // random delay, in milliseconds, between zero and the @@ -274,12 +273,11 @@ } result] : [set result ""]}] [string map [list \r\n \n] $result] } -cleanup { cleanupDb $fileName unset -nocomplain result code results errors dataSource fileName -} -constraints \ -[fixConstraints {fail.false eagle monoBug28 configuration.Release\ +} -constraints [fixConstraints {eagle monoBug28 configuration.Release\ !defineConstant.System.Data.SQLite.INTEROP_LOG command.sql compile.DATA\ SQLite System.Data.SQLite compileCSharp}] -match regexp -result [appendArgs \ "^Ok System#CodeDom#Compiler#CompilerResults#\\d+ \\{\\} 0 \\{" [string repeat \ "SQLite message \\(0\\): TEST $id " [expr {min(4 * [info processors], 16)}]] "\\}\$"]} Index: Tests/tkt-aba4549801.eagle ================================================================== --- Tests/tkt-aba4549801.eagle +++ Tests/tkt-aba4549801.eagle @@ -68,74 +68,44 @@ \{System#Data#SQLite#SQLiteConnection#\d+ ConnectionString \{\} \{\} \{\}\ \{\}\} \{System#Object#\d+ NewCriticalHandle \{\} \{\} \{\}\ System#Data#SQLite#SQLiteConnectionHandle#\d+\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewCommand \{\}\ System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ -\{System#Data#SQLite#SQLiteConnection#\d+ DisposingCommand \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ Opened \{\} \{\} \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewCommand \{\}\ System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewDataReader \{\}\ System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ \{\}\} \{System#Object#\d+ NewCriticalHandle \{\} \{\} \{\}\ System#Data#SQLite#SQLiteStatementHandle#\d+\}\ -\{System#Data#SQLite#SQLiteConnection#\d+ DisposingDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ ClosingDataReader \{\}\ +\{System#Data#SQLite#SQLiteConnection#\d+ NewCommand \{\}\ +System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ +\{System#Data#SQLite#SQLiteConnection#\d+ NewDataReader \{\}\ System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ DisposingCommand \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ +\{\}\} \{System#Object#\d+ NewCriticalHandle \{\} \{\} \{\}\ +System#Data#SQLite#SQLiteStatementHandle#\d+\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewCommand \{\}\ System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewDataReader \{\}\ System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ \{\}\} \{System#Object#\d+ NewCriticalHandle \{\} \{\} \{\}\ System#Data#SQLite#SQLiteStatementHandle#\d+\}\ -\{System#Data#SQLite#SQLiteConnection#\d+ DisposingDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ ClosingDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ DisposingCommand \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ -\{System#Data#SQLite#SQLiteConnection#\d+ NewCommand \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ -\{System#Data#SQLite#SQLiteConnection#\d+ NewDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Object#\d+ NewCriticalHandle \{\} \{\} \{\}\ -System#Data#SQLite#SQLiteStatementHandle#\d+\}\ -\{System#Data#SQLite#SQLiteConnection#\d+ DisposingDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ ClosingDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ DisposingCommand \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewTransaction\ System#Data#SQLite#SQLiteTransaction#\d+ \{\} \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewCommand \{\}\ System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewDataReader \{\}\ System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ \{\}\} \{System#Object#\d+ NewCriticalHandle \{\} \{\} \{\}\ System#Data#SQLite#SQLiteStatementHandle#\d+\} \{System#Object#\d+\ NewCriticalHandle \{\} \{\} \{\} System#Data#SQLite#SQLiteStatementHandle#\d+\}\ -\{System#Data#SQLite#SQLiteConnection#\d+ ClosingDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ DisposingCommand \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewCommand \{\}\ System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ NewDataReader \{\}\ System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ \{\}\} \{System#Object#\d+ NewCriticalHandle \{\} \{\} \{\}\ System#Data#SQLite#SQLiteStatementHandle#\d+\}\ -\{System#Data#SQLite#SQLiteConnection#\d+ DisposingDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ ClosingDataReader \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ System#Data#SQLite#SQLiteDataReader#\d+\ -\{\}\} \{System#Data#SQLite#SQLiteConnection#\d+ DisposingCommand \{\}\ -System#Data#SQLite#SQLiteCommand#\d+ \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ Closing \{\} \{\} \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ Closed \{\} \{\} \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ Closing \{\} \{\} \{\} \{\}\}\ \{System#Data#SQLite#SQLiteConnection#\d+ Closed \{\} \{\} \{\} \{\}\}$}} DELETED Tests/tkt-da9f18d039.eagle Index: Tests/tkt-da9f18d039.eagle ================================================================== --- Tests/tkt-da9f18d039.eagle +++ /dev/null @@ -1,150 +0,0 @@ -############################################################################### -# -# tkt-da9f18d039.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: Setup the variables that refer to the various files required by the -# tests in this file. -# -set systemDataSQLiteDllFile [getBuildFileName System.Data.SQLite.dll] -set systemDataSQLiteLinqDllFile [getBuildFileName System.Data.SQLite.Linq.dll] -set systemDataSQLiteEf6DllFile [getBuildFileName System.Data.SQLite.EF6.dll] -set testLinqExeFile [getBuildFileName testlinq.exe] -set testEf6ExeFile [getBuildFileName testef6.exe] -set northwindEfDbFile [file nativename [file join [file dirname $path] \ - testlinq northwindEF.db]] - -# -# NOTE: Setup the test constraints specific to the tests in this file. -# -if {![haveConstraint [appendArgs file_ \ - [file tail $systemDataSQLiteDllFile]]]} then { - checkForFile $test_channel $systemDataSQLiteDllFile -} - -if {![haveConstraint [appendArgs file_ \ - [file tail $systemDataSQLiteLinqDllFile]]]} then { - checkForFile $test_channel $systemDataSQLiteLinqDllFile -} - -if {![haveConstraint [appendArgs file_ \ - [file tail $systemDataSQLiteEf6DllFile]]]} then { - checkForFile $test_channel $systemDataSQLiteEf6DllFile -} - -if {![haveConstraint [appendArgs file_ [file tail $testLinqExeFile]]]} then { - checkForFile $test_channel $testLinqExeFile testlinq.exe -} - -if {![haveConstraint [appendArgs file_ [file tail $testEf6ExeFile]]]} then { - checkForFile $test_channel $testEf6ExeFile testef6.exe -} - -if {![haveConstraint [appendArgs file_ [file tail $northwindEfDbFile]]]} then { - checkForFile $test_channel $northwindEfDbFile -} - -############################################################################### - -runTest {test tkt-da9f18d039-1.1 {LINQ DateTime handling} -body { - # - # NOTE: Re-copy the reference database file used for this unit test to the - # build directory in case it has been changed by a previous test run. - # - file copy -force $northwindEfDbFile \ - [file join [getBuildDirectory] [file tail $northwindEfDbFile]] - - set result [list] - set output "" - - set code [catch { - testClrExec $testLinqExeFile [list -eventflags Wait -directory \ - [file dirname $testLinqExeFile] -nocarriagereturns -stdout output \ - -success 0] -datetime - } error] - - tlog "---- BEGIN STDOUT OUTPUT\n" - tlog $output - tlog "\n---- END STDOUT OUTPUT\n" - - lappend result $code - - if {$code == 0} then { - lappend result [string trim $output] - } else { - lappend result [string trim $error] - } - - set result -} -cleanup { - unset -nocomplain code output error result -} -constraints {eagle monoToDo SQLite file_System.Data.SQLite.dll testExec\ -file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} \ --result {0 {}}} - -############################################################################### - -runTest {test tkt-da9f18d039-1.2 {EF6 DateTime handling} -body { - # - # NOTE: Re-copy the reference database file used for this unit test to the - # build directory in case it has been changed by a previous test run. - # - file copy -force $northwindEfDbFile \ - [file join [getBuildDirectory] [file tail $northwindEfDbFile]] - - set result [list] - set output "" - - set code [catch { - testClrExec $testEf6ExeFile [list -eventflags Wait -directory \ - [file dirname $testEf6ExeFile] -nocarriagereturns -stdout output \ - -success 0] -datetime - } error] - - tlog "---- BEGIN STDOUT OUTPUT\n" - tlog $output - tlog "\n---- END STDOUT OUTPUT\n" - - lappend result $code - - if {$code == 0} then { - lappend result [string trim $output] - } else { - lappend result [string trim $error] - } - - set result -} -cleanup { - unset -nocomplain code output error result -} -constraints {eagle monoToDo SQLite file_System.Data.SQLite.dll testExec\ -file_System.Data.SQLite.EF6.dll file_testef6.exe file_northwindEF.db} \ --result {0 {}}} - -############################################################################### - -unset -nocomplain northwindEfDbFile testEf6ExeFile testLinqExeFile \ - systemDataSQLiteEf6DllFile systemDataSQLiteLinqDllFile \ - systemDataSQLiteDllFile - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/version.eagle ================================================================== --- Tests/version.eagle +++ Tests/version.eagle @@ -24,15 +24,14 @@ # # NOTE: For these unit tests to be useful and accurate, the following version # numbers must be manually kept synchronized with the version numbers for # the source code files, the built binaries, and the release packages. -# The revision number is reserved for NuGet package versioning. # set version(major) 1 set version(minor) 0 -set version(build) 93; # NOTE: Incremented with each release. +set version(build) 91; # NOTE: Incremented with each release. set version(revision) 0 ############################################################################### # ********************* END VOLATILE VERSION INFORMATION ********************** ############################################################################### @@ -42,20 +41,10 @@ # should not have to be changed. # set version(full) [appendArgs $version(major) . $version(minor) . \ $version(build) . $version(revision)] -############################################################################### - -# -# NOTE: Build the version number used for the NuGet packages. This should -# be the same as the above version number, with the exception of the -# revision, which may differ. -# -set version(nuget) [appendArgs $version(major) . $version(minor) . \ - $version(build) . \\d+] - ############################################################################### # # NOTE: Setup the variables that refer to the various files required by the # tests in this file. @@ -267,148 +256,22 @@ {^(?:|[0-9a-f]{40} \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} UTC)$}} ############################################################################### set patterns [list \ - [appendArgs Version " " [string map [list . \\.] $version(full)] " "] \ - [appendArgs [string map [list . \\.] $version(full)] " - "] \ [appendArgs Version= [string map [list . \\.] $version(full)] ,] \ [appendArgs Version= [string map [list . \\.] $version(full)] ,] \ - [appendArgs [string map [list . \\.] $version(full)] " - "] \ - [appendArgs "\; [format %03d $version(build)] "\;] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs " targetFramework=\"net20\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net20\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs " targetFramework=\"net20\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net20\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs " targetFramework=\"net40\".*?\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*?\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*?\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs " targetFramework=\"net20\".*?\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*?\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*?\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*?\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs " targetFramework=\"net20\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net20\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net40\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net45\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs " targetFramework=\"net451\".*? " \ - "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \ - "\" "] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ - ] \ - [appendArgs [string map [list . \\.] $version(nuget)] \ + [appendArgs "\; [format %03d $version(build)] "\;] \ + [appendArgs [string map [list . \\.] $version(full)] \ + ] \ + [appendArgs [string map [list . \\.] $version(full)] \ + ] \ + [appendArgs [string map [list . \\.] $version(full)] \ + ] \ + [appendArgs [string map [list . \\.] $version(full)] \ + ] \ + [appendArgs [string map [list . \\.] $version(full)] \ ] \ [appendArgs AssemblyVersion\\(\" [string map [list . \\.] \ $version(full)] \"\\)] \ [appendArgs AssemblyFileVersion\\(\" [string map [list . \\.] \ $version(full)] \"\\)] \ @@ -451,35 +314,47 @@ [appendArgs AssemblyVersion\\(\" [string map [list . \\.] \ $version(full)] \"\\)] \ [appendArgs AssemblyFileVersion\\(\" [string map [list . \\.] \ $version(full)] \"\\)] \ [appendArgs \ + "SQLiteFactory, System\\.Data\\.SQLite, " \ + "Version=" [string map [list . \\.] $version(full)] ,] \ + [appendArgs \ + "SQLiteProviderFactory, System\\.Data\\.SQLite\\.Linq, " \ + "Version=" [string map [list . \\.] $version(full)] ,] \ + [appendArgs \ + "SQLiteProviderFactory, System\\.Data\\.SQLite\\.EF6, " \ + "Version=" [string map [list . \\.] $version(full)] ,] \ + [appendArgs \ + "SQLiteProviderServices, System\\.Data\\.SQLite\\.EF6, " \ + "Version=" [string map [list . \\.] $version(full)] ,] \ + [appendArgs \ + "SQLiteFactory, System\\.Data\\.SQLite, " \ + "Version=" [string map [list . \\.] $version(full)] ,] \ + [appendArgs \ "SQLiteProviderFactory, System\\.Data\\.SQLite\\.Linq, " \ "Version=" [string map [list . \\.] $version(full)] ,] \ [appendArgs \ "SQLiteProviderFactory, System\\.Data\\.SQLite\\.EF6, " \ "Version=" [string map [list . \\.] $version(full)] ,] \ [appendArgs \ "SQLiteProviderServices, System\\.Data\\.SQLite\\.EF6, " \ "Version=" [string map [list . \\.] $version(full)] ,] \ [appendArgs \ + "SQLiteFactory, System\\.Data\\.SQLite, " \ + "Version=" [string map [list . \\.] $version(full)] ,] \ + [appendArgs \ "SQLiteProviderFactory, System\\.Data\\.SQLite\\.Linq, " \ "Version=" [string map [list . \\.] $version(full)] ,] \ [appendArgs \ "SQLiteProviderFactory, System\\.Data\\.SQLite\\.EF6, " \ "Version=" [string map [list . \\.] $version(full)] ,] \ [appendArgs \ "SQLiteProviderServices, System\\.Data\\.SQLite\\.EF6, " \ "Version=" [string map [list . \\.] $version(full)] ,] \ [appendArgs \ - "SQLiteProviderFactory, System\\.Data\\.SQLite\\.Linq, " \ - "Version=" [string map [list . \\.] $version(full)] ,] \ - [appendArgs \ - "SQLiteProviderFactory, System\\.Data\\.SQLite\\.EF6, " \ - "Version=" [string map [list . \\.] $version(full)] ,] \ - [appendArgs \ - "SQLiteProviderServices, System\\.Data\\.SQLite\\.EF6, " \ + "SQLiteFactory, System\\.Data\\.SQLite, " \ "Version=" [string map [list . \\.] $version(full)] ,] \ [appendArgs \ "SQLiteProviderFactory, System\\.Data\\.SQLite\\.Linq, " \ "Version=" [string map [list . \\.] $version(full)] ,] \ [appendArgs AssemblyVersion\\(\" [string map [list . \\.] \ @@ -487,68 +362,19 @@ [appendArgs AssemblyFileVersion\\(\" [string map [list . \\.] \ $version(full)] \"\\)] \ [appendArgs AssemblyVersion\\(\" [string map [list . \\.] \ $version(full)] \"\\)] \ [appendArgs AssemblyFileVersion\\(\" [string map [list . \\.] \ - $version(full)] \"\\)] \ - [appendArgs [string map [list . \\.] $version(full)] " - "]] + $version(full)] \"\\)]] set fileNames [list \ readme.htm \ - readme.htm \ - readme.htm \ - [file join Doc Extra Provider dbfactorysupport.html] \ - [file join Doc Extra Provider version.html] \ - [file join Doc Extra Provider welcome.html] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Beta.nuspec] \ - [file join NuGet SQLite.Core.nuspec] \ - [file join NuGet SQLite.Core.MSIL.nuspec] \ - [file join NuGet SQLite.EF6.nuspec] \ - [file join NuGet SQLite.EF6.nuspec] \ - [file join NuGet SQLite.EF6.nuspec] \ - [file join NuGet SQLite.EF6.nuspec] \ - [file join NuGet SQLite.Linq.nuspec] \ - [file join NuGet SQLite.Linq.nuspec] \ - [file join NuGet SQLite.Linq.nuspec] \ - [file join NuGet SQLite.Linq.nuspec] \ - [file join NuGet SQLite.Linq.nuspec] \ - [file join NuGet SQLite.MSIL.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ - [file join NuGet SQLite.Test.nuspec] \ + [file join Doc Extra dbfactorysupport.html] \ + [file join Doc Extra welcome.html] \ + [file join NuGet SQLite.nuspec] \ + [file join NuGet SQLite.Beta.nuspec] \ + [file join NuGet SQLite.MSIL.nuspec] \ [file join NuGet SQLite.x64.nuspec] \ [file join NuGet SQLite.x86.nuspec] \ [file join SQLite.Designer AssemblyInfo.cs] \ [file join SQLite.Designer AssemblyInfo.cs] \ [file join SQLite.Designer source.extension.vsixmanifest] \ @@ -575,30 +401,27 @@ [file join test AssemblyInfo.cs] \ [file join test app.config] \ [file join testce AssemblyInfo.cs] \ [file join testce AssemblyInfo.cs] \ [file join testlinq 2008 LINQ App.config] \ + [file join testlinq 2008 LINQ App.config] \ [file join testlinq 2010 EF6 App.config] \ [file join testlinq 2010 EF6 App.config] \ + [file join testlinq 2010 LINQ App.config] \ [file join testlinq 2010 LINQ App.config] \ [file join testlinq 2012 EF6 App.config] \ [file join testlinq 2012 EF6 App.config] \ [file join testlinq 2012 LINQ App.config] \ + [file join testlinq 2012 LINQ App.config] \ [file join testlinq 2013 EF6 App.config] \ [file join testlinq 2013 EF6 App.config] \ + [file join testlinq 2013 LINQ App.config] \ [file join testlinq 2013 LINQ App.config] \ [file join testlinq Properties AssemblyInfo.cs] \ [file join testlinq Properties AssemblyInfo.cs] \ [file join tools install Properties AssemblyInfo.cs] \ - [file join tools install Properties AssemblyInfo.cs] \ - [file join www news.wiki]] - -if {[llength $patterns] != [llength $fileNames]} then { - error [appendArgs \ - "number of regular expression patterns " [llength $patterns] \ - " does not match number of file names " [llength $fileNames]] -} + [file join tools install Properties AssemblyInfo.cs]] for {set i 1} {$i <= [llength $fileNames]} {incr i} { set pattern [lindex $patterns [expr {$i - 1}]] set fileName [lindex $fileNames [expr {$i - 1}]] set constraint [string map [list / _ \\ _] $fileName] @@ -608,15 +431,10 @@ checkForFile $test_channel $fileName $constraint } runTest {test [appendArgs version-1.21. $i] \ [appendArgs "pattern {" $pattern "} in file \"" $fileName \"] -body { - if {[hasRuntimeOption verbose]} then { - tputs $test_channel [appendArgs \ - "---- checking pattern {" $pattern "} against file \"" $fileName \ - \"...\n] - } regexp -- $pattern [readFile $fileName] } -constraints [list eagle [appendArgs file_ $constraint]] -result {1}} } ############################################################################### Index: Tests/vtab.eagle ================================================================== --- Tests/vtab.eagle +++ Tests/vtab.eagle @@ -1695,12 +1695,12 @@ unset -nocomplain result code results errors sql dataSource id fileName } -constraints \ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\ defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE compileCSharp} -match \ regexp -result [string map [list \n \r\n] {^Ok\ -System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{-?\d+ one -?\d+ two -?\d+\ -three -?\d+ 4 -?\d+ 5\.0\}$}]} +System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\d+ one \d+ two \d+ three\ +\d+ 4 \d+ 5\.0\}$}]} ############################################################################### runSQLiteTestEpilogue runTestEpilogue DELETED data/exclude_bin.txt Index: data/exclude_bin.txt ================================================================== --- data/exclude_bin.txt +++ /dev/null @@ -1,12 +0,0 @@ -*.done -*.exp -*.lib -*.manifest -*.map -*.mda.config -*.txt -*32.exe -*32.exe.config -*EntityFramework.* -*EnvDTE.* -*Microsoft.* DELETED data/exclude_src.txt Index: data/exclude_src.txt ================================================================== --- data/exclude_src.txt +++ /dev/null @@ -1,57 +0,0 @@ -*.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 -Externals/Eagle/bin/EagleShell32.exe -Externals/Eagle/bin/EntityFramework.* -Externals/Eagle/bin/SQLite.Interop.* -Externals/Eagle/bin/sqlite3.* -Externals/Eagle/bin/System.* -Externals/Eagle/bin/Win32/* -Externals/Eagle/bin/x64/* -Externals/Eagle/bin/x86/* -Externals/Eagle/lib/Eagle1.0/embed.eagle -Externals/Eagle/lib/Eagle1.0/init.eagle -Externals/Eagle/lib/Eagle1.0/pkgIndex.eagle -Externals/Eagle/lib/Eagle1.0/pkgIndex.tcl -Externals/Eagle/lib/Eagle1.0/safe.eagle -Externals/Eagle/lib/Eagle1.0/shell.eagle -Externals/Eagle/lib/Eagle1.0/test.eagle -Externals/Eagle/lib/Eagle1.0/word.tcl -Externals/Eagle/lib/Test1.0/all.eagle -Externals/Eagle/lib/Test1.0/constraints.eagle -Externals/Eagle/lib/Test1.0/epilogue.eagle -Externals/Eagle/lib/Test1.0/pkgIndex.eagle -Externals/Eagle/lib/Test1.0/pkgIndex.tcl -Externals/Eagle/lib/Test1.0/prologue.eagle -Externals/EntityFramework/* -Externals/HtmlHelp/* -Externals/MSVCPP/* -Externals/NDoc3/* -obj/* -Setup/Output/* -Setup/set_user_*.bat -SQLite.Designer/obj/* -SQLite.Designer/Properties/* -SQLite.Designer/VSDesign/* -System.Data.SQLite.Linq/obj/* -System.Data.SQLite/obj/* -System.Data.SQLite/Properties/* -test/obj/* -testce/obj/* -testlinq/obj/* -tools/install/obj/* -www/* ADDED exclude_bin.txt Index: exclude_bin.txt ================================================================== --- /dev/null +++ exclude_bin.txt @@ -0,0 +1,12 @@ +*.done +*.exp +*.lib +*.manifest +*.map +*.mda.config +*.txt +*32.exe +*32.exe.config +*EntityFramework.* +*EnvDTE.* +*Microsoft.* ADDED exclude_src.txt Index: exclude_src.txt ================================================================== --- /dev/null +++ exclude_src.txt @@ -0,0 +1,57 @@ +*.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 +Externals/Eagle/bin/EagleShell32.exe +Externals/Eagle/bin/EntityFramework.* +Externals/Eagle/bin/SQLite.Interop.* +Externals/Eagle/bin/sqlite3.* +Externals/Eagle/bin/System.* +Externals/Eagle/bin/Win32/* +Externals/Eagle/bin/x64/* +Externals/Eagle/bin/x86/* +Externals/Eagle/lib/Eagle1.0/embed.eagle +Externals/Eagle/lib/Eagle1.0/init.eagle +Externals/Eagle/lib/Eagle1.0/pkgIndex.eagle +Externals/Eagle/lib/Eagle1.0/pkgIndex.tcl +Externals/Eagle/lib/Eagle1.0/safe.eagle +Externals/Eagle/lib/Eagle1.0/shell.eagle +Externals/Eagle/lib/Eagle1.0/test.eagle +Externals/Eagle/lib/Eagle1.0/word.tcl +Externals/Eagle/lib/Test1.0/all.eagle +Externals/Eagle/lib/Test1.0/constraints.eagle +Externals/Eagle/lib/Test1.0/epilogue.eagle +Externals/Eagle/lib/Test1.0/pkgIndex.eagle +Externals/Eagle/lib/Test1.0/pkgIndex.tcl +Externals/Eagle/lib/Test1.0/prologue.eagle +Externals/EntityFramework/* +Externals/HtmlHelp/* +Externals/MSVCPP/* +Externals/NDoc3/* +obj/* +Setup/Output/* +Setup/set_user_*.bat +SQLite.Designer/obj/* +SQLite.Designer/Properties/* +SQLite.Designer/VSDesign/* +System.Data.SQLite.Linq/obj/* +System.Data.SQLite/obj/* +System.Data.SQLite/Properties/* +test/obj/* +testce/obj/* +testlinq/obj/* +tools/install/obj/* +www/* Index: readme.htm ================================================================== --- readme.htm +++ readme.htm @@ -3,12 +3,12 @@ ADO.NET SQLite Data Provider
    -Version 1.0.93.0 June 23, 2014
    -Using SQLite 3.8.5
    +Version 1.0.91.0 February XX, 2014 (release scheduled)
    +Using SQLite 3.8.3
    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/

    @@ -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.93.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" /> + type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.91.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" /> </DbProviderFactories> </system.data> </configuration>

    @@ -207,43 +207,14 @@

    Version History

    - 1.0.93.0 - June 23, 2014 -

    -
      -
    • Updated to SQLite 3.8.5.
    • -
    • Updated to Entity Framework 6.1.
    • -
    • Add support for mapping transaction isolation levels to their legacy default values. Pursuant to [56b42d99c1].
    • -
    • Add support for setting the default DbType and type name used for mappings on a per-connection basis. Pursuant to [3c00ec5b52].
    • -
    • Add DetectTextAffinity and DetectStringType connection flags to enable automatic detection of column types, when necessary. Pursuant to [3c00ec5b52].
    • -
    • Add SetChunkSize method to the SQLiteConnection class. Pursuant to [d1c008fa0a].
    • -
    • Add SharedFlags static property to the SQLiteConnection class.
    • -
    • Make the ISQLiteSchemaExtensions interface public. ** Potentially Incompatible Change **
    • -
    • Have the SQLiteProviderFactory class (in the System.Data.SQLite.Linq assembly) implement the IServiceProvider interface.
    • -
    • Fix bug in documentation generator automation that prevented some internal documentation links from working.
    • -
    • Fix DateTime constant handling in the LINQ assembly. Fix for [da9f18d039]. ** Potentially Incompatible Change **
    • -
    -

    - 1.0.92.0 - March 19, 2014 -

    -
      -
    • Updated to SQLite 3.8.4.1.
    • -
    • Update the list of keywords returned by SQLiteConnection.GetSchema("ReservedWords"). ** Potentially Incompatible Change **
    • -
    • Raise the static SQLiteConnection.Changed event when any SQLiteCommand or SQLiteDataReader object is closed or disposed.
    • -
    • Add the SQLiteDataReader.StepCount property to return the number of rows seen so far.
    • -
    • Add StickyHasRows connection flag to cause the SQLiteDataReader.HasRows property to return non-zero if there were ever any rows in the associated result sets.
    • -
    • When the TraceWarning connection flag is set, issue warnings about possibly malformed UNC paths. Pursuant to [283344397b].
    • -
    • Convert the primary NuGet package, "System.Data.SQLite", into a meta-package.
    • -
    • Enhancements to the NuGet packages, including the new "modular" packages.
    • -
    -

    - 1.0.91.0 - February 12, 2014 -

    -
      -
    • Updated to SQLite 3.8.3.1.
    • + 1.0.91.0 - February XX, 2014 (release scheduled) +

      +
        +
      • Updated to SQLite 3.8.3.
      • Refresh all included SQLite core library documentation (e.g. SQL syntax).
      • Add support for Entity Framework 6.
      • Add support for per-connection mappings between type names and DbType values. Pursuant to [e87af1d06a].
      • Modify the namespace used for all internal classes in the System.Data.SQLite.Linq assembly. ** Potentially Incompatible Change **
      • Add SQLiteCompileOptions and InteropCompileOptions properties to the SQLiteConnection class to return the compile-time options for the SQLite core library and interop assembly, respectively.
      • @@ -251,11 +222,10 @@
      • Add NoConnectionPool and UseConnectionPool connection flags to disable or enable connection pooling by default.
      • Modify handling of the design-time components installer to run Visual Studio devenv.exe /setup after installing the package. This appears to be necessary in some circumstances for Visual Studio 2013. Pursuant to [a47eff2c71].
      • Modify the native library pre-loader to support reading settings from an XML configuration file and to be capable of checking more than one directory. Persuant to [f0246d1817].
      • Support detecting when the native library pre-loader should use the CodeBase property instead of the Location property as the basis for locating the interop assembly.
      • Change the default behavior for the native library pre-loader so it first searches the executing (i.e. System.Data.SQLite) assembly directory and then the application domain directory. Pursuant to [f0246d1817]. ** Potentially Incompatible Change **
      • -
      • Include DbType.AnsiString in the list of types that need special ColumnSize handling. Fix for [0550f0326e].

      1.0.90.0 - December 23, 2013

        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.93.0")] -[assembly: AssemblyFileVersion("1.0.93.0")] +[assembly: AssemblyVersion("1.0.91.0")] +[assembly: AssemblyFileVersion("1.0.91.0")] 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 @@ -20,12 +20,12 @@ test $(MSBuildProjectDirectory)\.. true 2005 - - + + $(BinaryOutputPath) true @@ -81,11 +81,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: test/test.2008.csproj ================================================================== --- test/test.2008.csproj +++ test/test.2008.csproj @@ -21,12 +21,12 @@ 2.0 $(MSBuildProjectDirectory)\.. true 2008 - - + + $(BinaryOutputPath) true @@ -82,11 +82,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: test/test.2010.csproj ================================================================== --- test/test.2010.csproj +++ test/test.2010.csproj @@ -22,12 +22,12 @@ Client $(MSBuildProjectDirectory)\.. true 2010 - - + + $(BinaryOutputPath) true @@ -83,11 +83,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: test/test.2012.csproj ================================================================== --- test/test.2012.csproj +++ test/test.2012.csproj @@ -21,12 +21,12 @@ true 2012 v4.5 false - - + + $(BinaryOutputPath) true @@ -82,11 +82,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: test/test.2013.csproj ================================================================== --- test/test.2013.csproj +++ test/test.2013.csproj @@ -21,12 +21,12 @@ true 2013 v4.5.1 false - - + + $(BinaryOutputPath) true @@ -82,11 +82,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: testce/AssemblyInfo.cs ================================================================== --- testce/AssemblyInfo.cs +++ testce/AssemblyInfo.cs @@ -36,8 +36,8 @@ // Major Version // Minor Version // Build Number // Revision // -[assembly: AssemblyVersion("1.0.93.0")] -// [assembly: AssemblyFileVersion("1.0.93.0")] +[assembly: AssemblyVersion("1.0.91.0")] +// [assembly: AssemblyFileVersion("1.0.91.0")] Index: testce/testce.2005.csproj ================================================================== --- testce/testce.2005.csproj +++ testce/testce.2005.csproj @@ -30,11 +30,11 @@ 2005 Compact testce %25CSIDL_PROGRAM_FILES%25 - + $(BinaryOutputPath) true Index: testce/testce.2008.csproj ================================================================== --- testce/testce.2008.csproj +++ testce/testce.2008.csproj @@ -31,11 +31,11 @@ 2008 Compact testce %25CSIDL_PROGRAM_FILES%25 - + $(BinaryOutputPath) true Index: testce/testce.2012.csproj ================================================================== --- testce/testce.2012.csproj +++ testce/testce.2012.csproj @@ -25,11 +25,11 @@ true false 2012 Compact - + $(BinaryOutputPath) true Index: testlinq/2008/LINQ/App.config ================================================================== --- testlinq/2008/LINQ/App.config +++ testlinq/2008/LINQ/App.config @@ -1,13 +1,14 @@ + - + - + Index: testlinq/2010/EF6/App.config ================================================================== --- testlinq/2010/EF6/App.config +++ testlinq/2010/EF6/App.config @@ -4,18 +4,19 @@
        + - + - + Index: testlinq/2010/LINQ/App.config ================================================================== --- testlinq/2010/LINQ/App.config +++ testlinq/2010/LINQ/App.config @@ -1,13 +1,14 @@ + - + - + Index: testlinq/2012/EF6/App.config ================================================================== --- testlinq/2012/EF6/App.config +++ testlinq/2012/EF6/App.config @@ -4,18 +4,19 @@
        + - + - + - + Index: testlinq/2012/LINQ/App.config ================================================================== --- testlinq/2012/LINQ/App.config +++ testlinq/2012/LINQ/App.config @@ -1,13 +1,14 @@ + - + - + Index: testlinq/2013/EF6/App.config ================================================================== --- testlinq/2013/EF6/App.config +++ testlinq/2013/EF6/App.config @@ -4,18 +4,19 @@
        + - + - + - + Index: testlinq/2013/LINQ/App.config ================================================================== --- testlinq/2013/LINQ/App.config +++ testlinq/2013/LINQ/App.config @@ -1,13 +1,14 @@ + - + - + Index: testlinq/NorthwindModel.Linq.2008.edmx ================================================================== --- testlinq/NorthwindModel.Linq.2008.edmx +++ testlinq/NorthwindModel.Linq.2008.edmx @@ -12,11 +12,11 @@ - + Index: testlinq/NorthwindModel.Linq.2010.edmx ================================================================== --- testlinq/NorthwindModel.Linq.2010.edmx +++ testlinq/NorthwindModel.Linq.2010.edmx @@ -12,11 +12,11 @@ - + Index: testlinq/NorthwindModel.Linq.2012.edmx ================================================================== --- testlinq/NorthwindModel.Linq.2012.edmx +++ testlinq/NorthwindModel.Linq.2012.edmx @@ -12,11 +12,11 @@ - + Index: testlinq/NorthwindModel.Linq.2013.edmx ================================================================== --- testlinq/NorthwindModel.Linq.2013.edmx +++ testlinq/NorthwindModel.Linq.2013.edmx @@ -12,11 +12,11 @@ - + Index: testlinq/Program.cs ================================================================== --- testlinq/Program.cs +++ testlinq/Program.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! ********************************************************/ using System; using System.Diagnostics; @@ -56,14 +56,10 @@ case "": // String.Empty case "old": { return OldTests(); } - case "datetime": - { - return DateTimeTest(); - } case "skip": { int pageSize = 0; if (args.Length > 1) @@ -328,21 +324,10 @@ } return 0; } - private static int DateTimeTest() - { - using (northwindEFEntities db = new northwindEFEntities()) - { - DateTime dateTime = new DateTime(1997, 1, 1, 0, 0, 0, DateTimeKind.Local); - int c1 = db.Orders.Where(i => i.OrderDate == new DateTime(1997, 1, 1, 0, 0, 0, DateTimeKind.Local)).Count(); - int c2 = db.Orders.Where(i => i.OrderDate == dateTime).Count(); - return c1 == c2 ? 0 : 1; - } - } - private static int OldTests() { using (northwindEFEntities db = new northwindEFEntities()) { { Index: testlinq/Properties/AssemblyInfo.cs ================================================================== --- testlinq/Properties/AssemblyInfo.cs +++ testlinq/Properties/AssemblyInfo.cs @@ -1,50 +1,50 @@ -/******************************************************** - * 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! - ********************************************************/ - -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information +/******************************************************** + * 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! + ********************************************************/ + +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information // associated with an assembly. #if USE_ENTITY_FRAMEWORK_6 [assembly: AssemblyTitle("System.Data.SQLite Tester for Entity Framework 6")] #else [assembly: AssemblyTitle("System.Data.SQLite Tester for LINQ")] #endif - -[assembly: AssemblyDescription("ADO.NET Data Provider for SQLite")] -[assembly: AssemblyCompany("http://system.data.sqlite.org/")] -[assembly: AssemblyProduct("System.Data.SQLite")] -[assembly: AssemblyCopyright("Public Domain")] - -#if DEBUG -[assembly: AssemblyConfiguration("Debug")] -#else -[assembly: AssemblyConfiguration("Release")] -#endif - -// 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)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("8fd19c43-2fa6-487c-9201-47dd59eed056")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// 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.93.0")] -[assembly: AssemblyFileVersion("1.0.93.0")] + +[assembly: AssemblyDescription("ADO.NET Data Provider for SQLite")] +[assembly: AssemblyCompany("http://system.data.sqlite.org/")] +[assembly: AssemblyProduct("System.Data.SQLite")] +[assembly: AssemblyCopyright("Public Domain")] + +#if DEBUG +[assembly: AssemblyConfiguration("Debug")] +#else +[assembly: AssemblyConfiguration("Release")] +#endif + +// 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)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8fd19c43-2fa6-487c-9201-47dd59eed056")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// 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.91.0")] +[assembly: AssemblyFileVersion("1.0.91.0")] Index: testlinq/test.2010.csproj ================================================================== --- testlinq/test.2010.csproj +++ testlinq/test.2010.csproj @@ -25,12 +25,12 @@ Client $(MSBuildProjectDirectory)\.. true 2010 - - + + $(BinaryOutputPath) true @@ -115,11 +115,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: testlinq/test.2012.csproj ================================================================== --- testlinq/test.2012.csproj +++ testlinq/test.2012.csproj @@ -23,12 +23,12 @@ true 2012 v4.5 false - - + + $(BinaryOutputPath) true @@ -119,11 +119,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: testlinq/test.2013.csproj ================================================================== --- testlinq/test.2013.csproj +++ testlinq/test.2013.csproj @@ -23,12 +23,12 @@ true 2013 v4.5.1 false - - + + $(BinaryOutputPath) true @@ -125,11 +125,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: testlinq/testlinq.2008.csproj ================================================================== --- testlinq/testlinq.2008.csproj +++ testlinq/testlinq.2008.csproj @@ -22,12 +22,12 @@ 2.0 $(MSBuildProjectDirectory)\.. true 2008 - - + + $(BinaryOutputPath) true @@ -71,11 +71,11 @@ - + $(BuildDependsOn); CloneAndMark32BitOnlyFrameworkTargetName32; Index: tools/install/Installer.2005.csproj ================================================================== --- tools/install/Installer.2005.csproj +++ tools/install/Installer.2005.csproj @@ -21,12 +21,12 @@ true $(MSBuildProjectDirectory)\..\.. true 2005 - - + + $(BinaryOutputPath) true @@ -52,11 +52,11 @@ - + $(BuildDependsOn); EmbedExeManifest; Index: tools/install/Installer.2008.csproj ================================================================== --- tools/install/Installer.2008.csproj +++ tools/install/Installer.2008.csproj @@ -22,12 +22,12 @@ 2.0 $(MSBuildProjectDirectory)\..\.. true 2008 - - + + $(BinaryOutputPath) true @@ -53,11 +53,11 @@ - + $(BuildDependsOn); EmbedExeManifest; Index: tools/install/Installer.2010.csproj ================================================================== --- tools/install/Installer.2010.csproj +++ tools/install/Installer.2010.csproj @@ -23,12 +23,12 @@ Client $(MSBuildProjectDirectory)\..\.. true 2010 - - + + $(BinaryOutputPath) true @@ -54,11 +54,11 @@ - + $(BuildDependsOn); EmbedExeManifest; Index: tools/install/Installer.2012.csproj ================================================================== --- tools/install/Installer.2012.csproj +++ tools/install/Installer.2012.csproj @@ -21,12 +21,12 @@ true 2012 v4.5 false - - + + $(BinaryOutputPath) true @@ -52,11 +52,11 @@ - + $(BuildDependsOn); EmbedExeManifest; Index: tools/install/Installer.2013.csproj ================================================================== --- tools/install/Installer.2013.csproj +++ tools/install/Installer.2013.csproj @@ -21,12 +21,12 @@ true 2013 v4.5.1 false - - + + $(BinaryOutputPath) true @@ -52,11 +52,11 @@ - + $(BuildDependsOn); EmbedExeManifest; Index: tools/install/Properties/AssemblyInfo.cs ================================================================== --- tools/install/Properties/AssemblyInfo.cs +++ tools/install/Properties/AssemblyInfo.cs @@ -26,7 +26,7 @@ // Major Version // Minor Version // Build Number // Revision // -[assembly: AssemblyVersion("1.0.93.0")] -[assembly: AssemblyFileVersion("1.0.93.0")] +[assembly: AssemblyVersion("1.0.91.0")] +[assembly: AssemblyFileVersion("1.0.91.0")] DELETED www/art/nocopy.gif Index: www/art/nocopy.gif ================================================================== --- www/art/nocopy.gif +++ /dev/null cannot compute difference between binary files DELETED www/art/sqlite128.png Index: www/art/sqlite128.png ================================================================== --- www/art/sqlite128.png +++ /dev/null cannot compute difference between binary files Index: www/build.wiki ================================================================== --- www/build.wiki +++ www/build.wiki @@ -106,12 +106,11 @@

        All Builds

        1. Make sure the version information is correct for SQLite in all of the - following files (this step should not be necessary when using source - code checked out from the official repository): + following files:
          • <root>\SQLite.Interop\props\sqlite3.vsprops
          • <root>\SQLite.Interop\props\sqlite3.props
          @@ -121,25 +120,19 @@ SQLite (i.e. 3.7.x).
        2. Make sure the version information is correct for System.Data.SQLite in the - following files (this step should not be necessary when using source - code checked out from the official repository): + following files:
          • <root>\readme.htm
          • -
          • <root>\Doc\Extra\Provider\dbfactorysupport.html
          • -
          • <root>\Doc\Extra\Provider\welcome.html
          • +
          • <root>\Doc\Extra\dbfactorysupport.html
          • +
          • <root>\Doc\Extra\welcome.html
          • <root>\NuGet\SQLite.nuspec
          • <root>\NuGet\SQLite.Beta.nuspec
          • -
          • <root>\NuGet\SQLite.Core.nuspec
          • -
          • <root>\NuGet\SQLite.Core.MSIL.nuspec
          • -
          • <root>\NuGet\SQLite.EF6.nuspec
          • -
          • <root>\NuGet\SQLite.Linq.nuspec
          • <root>\NuGet\SQLite.MSIL.nuspec
          • -
          • <root>\NuGet\SQLite.Test.nuspec
          • <root>\NuGet\SQLite.x86.nuspec
          • <root>\NuGet\SQLite.x64.nuspec
          • <root>\SQLite.Designer\AssemblyInfo.cs
          • <root>\SQLite.Designer\source.extension.vsixmanifest
          • <root>\SQLite.Interop\props\SQLite.Interop.2005.vsprops
          • @@ -179,12 +172,12 @@

            Manual Build

            1. - Complete the applicable steps outlined in the All Builds - section (above). + Complete the steps outlined in the All Builds section + (above).
            2. Open the appropriate solution for your build platform. @@ -262,12 +255,12 @@

              Automated Build

              1. - Complete the applicable steps outlined in the All Builds - section (above). + Complete the steps outlined in the All Builds section + (above).
              2. Make sure the "<root>\bin" and "<root>\obj" directories are completely free of all output files. In theory, you should @@ -354,12 +347,12 @@

                Mono Build

                1. - Complete the applicable steps outlined in the All Builds - section (above). + Complete the steps outlined in the All Builds section + (above).
                2. Make sure the "<root>\bin" and "<root>\obj" directories are completely free of all output files. In theory, you should DELETED www/copyright.wiki Index: www/copyright.wiki ================================================================== --- www/copyright.wiki +++ /dev/null @@ -1,104 +0,0 @@ -Copyright -

                  System.Data.SQLite Copyright

                  - -

                  -All files in the -"System.Data.SQLite.Linq/SQL Generation" -directory (within the source tree) are covered by the -Microsoft Public License (MS-PL). -These files end up being compiled into both the "System.Data.SQLite.Linq" -and "System.Data.SQLite.EF6" assemblies. -

                  - - - -
                  -
                  -System.Data.SQLite is in the
                  -Public Domain -
                  - -

                  -All other code and documentation in System.Data.SQLite has been dedicated to -the public domain -by the authors. -All code authors, and representatives of the companies they work for, have -signed affidavits dedicating their contributions to the public domain and -originals of those signed affidavits are stored in a firesafe at the main -offices of Hwaci. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute -the original System.Data.SQLite code, either in source code form or as a -compiled binary, for any purpose, commercial or non-commercial, and by any -means. -

                  - -

                  Obtaining An Explicit License To Use System.Data.SQLite

                  - -

                  -Even though System.Data.SQLite is in the public domain and does not require -a license, some users want to obtain a license anyway. Some reasons -for obtaining a license include: -

                  - -
                    -
                  • You are using System.Data.SQLite in a jurisdiction that does not recognize - the public domain.
                  • -
                  • You are using System.Data.SQLite in a jurisdiction that does not recognize - the right of an author to dedicate their work to the public - domain.
                  • -
                  • You want to hold a tangible legal document - as evidence that you have the legal right to use and distribute - System.Data.SQLite.
                  • -
                  • Your legal department tells you that you have to purchase a license. -
                  • -
                  - -

                  -If you feel like you really have to purchase a license for System.Data.SQLite, -Hwaci, the company that employs -the architect and principal developers of System.Data.SQLite, will -sell you -one. -

                  - -

                  Contributed Code

                  - -

                  -In order to keep System.Data.SQLite completely free and unencumbered by -copyright, all new contributors to the System.Data.SQLite code base are asked -to dedicate their contributions to the public domain. -If you want to send a patch or enhancement for possible inclusion in the -System.Data.SQLite source tree, please accompany the patch with the following -statement: -

                  - -
                  -The author or authors of this code dedicate any and all copyright interest -in this code to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and successors. -We intend this dedication to be an overt act of relinquishment in -perpetuity of all present and future rights to this code under copyright law. -
                  - -

                  -We are not able to accept patches or changes to -System.Data.SQLite that are not accompanied by a statement such as the above. -In addition, if you make -changes or enhancements as an employee, then a simple statement such as the -above is insufficient. You must also send by surface mail a copyright release -signed by a company officer. -A signed original of the copyright release should be mailed to:

                  - -
                  -Hwaci
                  -6200 Maple Cove Lane
                  -Charlotte, NC 28269
                  -USA -
                  - -

                  -A template copyright release is available -in PDF or -HTML. -You can use this release to make future changes. -

                  Index: www/downloads.wiki ================================================================== --- www/downloads.wiki +++ www/downloads.wiki @@ -322,11 +322,11 @@ environment, it can be disabled by setting the "No_PreLoadSQLite" environment variable (i.e. to anything) prior to loading and/or using the System.Data.SQLite assembly. There are several more environment variables that can be used to influence the behavior of the native library pre-loading feature, documented - here. + here.

                  Use of environment variables for configuration settings is not supported by the .NET Compact Framework builds of System.Data.SQLite, due to limitations imposed by the platform itself.

                  @@ -431,20 +431,20 @@   - sqlite-netFx-source-1.0.93.0.zip + sqlite-netFx-source-1.0.90.0.zip
                  - (4.89 MiB) + (3.39 MiB) This ZIP archive contains all current source code for System.Data.SQLite - 1.0.93.0 (3.8.5) combined into a single archive file. + 1.0.90.0 (3.8.2) combined into a single archive file.
                  - (sha1: 4b6b7f42a27bfa2221480e7ed7cca4ac4b995726) + (sha1: d6595a8f9a41571f8d9a4593bd3b66a31b043ec9) @@ -454,45 +454,45 @@   - sqlite-netFx20-setup-bundle-x86-2005-1.0.93.0.exe + sqlite-netFx20-setup-bundle-x86-2005-1.0.90.0.exe
                  - (5.01 MiB) + (4.39 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.93.0 (3.8.5) package. The Visual C++ 2005 + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2005 SP1 runtime for x86 is included. The .NET Framework 2.0 SP2 is required.
                  This is the only setup package that is capable of installing the design-time components for Visual Studio 2005.
                  - (sha1: 76de1cf3056ada1b582d0591a1882a74be3af25c) + (sha1: a9e417e8bdf8b086460510b4b0fd7d74121d9fa8)   - sqlite-netFx20-setup-x86-2005-1.0.93.0.exe + sqlite-netFx20-setup-x86-2005-1.0.90.0.exe
                  - (5.00 MiB) + (4.38 MiB) This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2005 SP1 runtime for x86 is included. + dependencies for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2005 SP1 runtime for x86 is included. The .NET Framework 2.0 SP2 is required.
                  - (sha1: 0c44f4c217c9a202bc46379bc0c0c2cbfb47a3d8) + (sha1: defa7f85be795f258418c6214d4cecebc7971cdb) @@ -502,42 +502,42 @@   - sqlite-netFx20-setup-bundle-x64-2005-1.0.93.0.exe + sqlite-netFx20-setup-bundle-x64-2005-1.0.90.0.exe
                  - (5.60 MiB) + (4.97 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.93.0 (3.8.5) package. The Visual C++ 2005 + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2005 SP1 runtime for x64 is included. The .NET Framework 2.0 SP2 is required.
                  - (sha1: 1bf2e8fdbc521af5000379bc52a3b6e13d27cbc3) + (sha1: 867da04bd61cf2f4c98dca996ba16762ff6d0862)   - sqlite-netFx20-setup-x64-2005-1.0.93.0.exe + sqlite-netFx20-setup-x64-2005-1.0.90.0.exe
                  - (5.60 MiB) + (4.96 MiB) This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2005 SP1 runtime for x64 is included. + dependencies for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2005 SP1 runtime for x64 is included. The .NET Framework 2.0 SP2 is required.
                  - (sha1: e9ad36276264f4c75cb93e148989ecca2b49326c) + (sha1: 709744ca60b934d3102be162585d08cf6e5d46d2) @@ -547,45 +547,45 @@   - sqlite-netFx35-setup-bundle-x86-2008-1.0.93.0.exe + sqlite-netFx35-setup-bundle-x86-2008-1.0.90.0.exe
                  - (7.05 MiB) + (6.42 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.93.0 (3.8.5) package. The Visual C++ 2008 + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2008 SP1 runtime for x86 is included. The .NET Framework 3.5 SP1 is required.
                  This is the only setup package that is capable of installing the design-time components for Visual Studio 2008.
                  - (sha1: 3c062488edad63907f080f5eab36c61b0535859b) + (sha1: 1b89dcda04afbd5b38085fe62af08d87365e1ee8)   - sqlite-netFx35-setup-x86-2008-1.0.93.0.exe + sqlite-netFx35-setup-x86-2008-1.0.90.0.exe
                  - (7.04 MiB) + (6.41 MiB) This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2008 SP1 runtime for x86 is included. + dependencies for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2008 SP1 runtime for x86 is included. The .NET Framework 3.5 SP1 is required.
                  - (sha1: b2d060bda3a8c0e07fa9699d893fa36bb25a252b) + (sha1: df9602c379850b9d59e20012a57109dd5c5f6202) @@ -595,42 +595,42 @@   - sqlite-netFx35-setup-bundle-x64-2008-1.0.93.0.exe + sqlite-netFx35-setup-bundle-x64-2008-1.0.90.0.exe
                  - (7.79 MiB) + (7.16 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.93.0 (3.8.5) package. The Visual C++ 2008 + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2008 SP1 runtime for x64 is included. The .NET Framework 3.5 SP1 is required.
                  - (sha1: 30df9f5f137daa9e32494bec3a636d03277a4ff9) + (sha1: b77a7dff3e23eb5c7e5269a8ff1e4ca515858a42)   - sqlite-netFx35-setup-x64-2008-1.0.93.0.exe + sqlite-netFx35-setup-x64-2008-1.0.90.0.exe
                  - (7.78 MiB) + (7.15 MiB) This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2008 SP1 runtime for x64 is included. + dependencies for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2008 SP1 runtime for x64 is included. The .NET Framework 3.5 SP1 is required.
                  - (sha1: 007097afb53bf7bbb13dd904f944de558aeae868) + (sha1: 93b0476307981f8c8097b44e3505dc529341ce4d) @@ -640,44 +640,44 @@   - sqlite-netFx40-setup-bundle-x86-2010-1.0.93.0.exe + sqlite-netFx40-setup-bundle-x86-2010-1.0.90.0.exe
                  - (12.60 MiB) + (10.75 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.93.0 (3.8.5) package. The Visual C++ 2010 + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2010 SP1 runtime for x86 is included. The .NET Framework 4.0 is required.
                  This is the only setup package that is capable of installing the design-time components for Visual Studio 2010.
                  - (sha1: a2f6f834bb4ada0e484d797087c462cbd97d421b) + (sha1: 16d657f0327553927b30a84a924fef8242a316f7)   - sqlite-netFx40-setup-x86-2010-1.0.93.0.exe + sqlite-netFx40-setup-x86-2010-1.0.90.0.exe
                  - (12.60 MiB) + (10.74 MiB) This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2010 SP1 runtime for x86 is included. + dependencies for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2010 SP1 runtime for x86 is included. The .NET Framework 4.0 is required.
                  - (sha1: 1ee2101bf267304803bbdcfca6e1524852ecca3a) + (sha1: 1f8824c658fb5d6a3301244a91922c54fdf8a0ed) @@ -687,41 +687,41 @@   - sqlite-netFx40-setup-bundle-x64-2010-1.0.93.0.exe + sqlite-netFx40-setup-bundle-x64-2010-1.0.90.0.exe
                  - (13.85 MiB) + (12.00 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.93.0 (3.8.5) package. The Visual C++ 2010 + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2010 SP1 runtime for x64 is included. The .NET Framework 4.0 is required.
                  - (sha1: 4e0f6bc904d0dda2e5ebe346f710726e64494932) + (sha1: 518be2c4029f7602dd01b6bb24939a5da861e2aa)   - sqlite-netFx40-setup-x64-2010-1.0.93.0.exe + sqlite-netFx40-setup-x64-2010-1.0.90.0.exe
                  - (13.84 MiB) + (11.99 MiB) This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2010 SP1 runtime for x64 is included. + dependencies for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2010 SP1 runtime for x64 is included. The .NET Framework 4.0 is required.
                  - (sha1: d85bc4b042136fcea0aac52f8e29bd8849fc15ab) + (sha1: 823685f16ca5bbc8068805588fb0a4c76109956f) @@ -731,45 +731,45 @@   - sqlite-netFx45-setup-bundle-x86-2012-1.0.93.0.exe + sqlite-netFx45-setup-bundle-x86-2012-1.0.90.0.exe
                  - (10.04 MiB) + (8.15 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.93.0 (3.8.5) package. The Visual C++ 2012 + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x86 is included. The .NET Framework 4.5 is required.
                  This is the only setup package that is capable of installing the design-time components for Visual Studio 2012.
                  - (sha1: 934116fd6dcd9c4071c1e9f4e482e96ffe784b60) + (sha1: 237f9f54b9e8758133a94f6af49ccf23215082fe)   - sqlite-netFx45-setup-x86-2012-1.0.93.0.exe + sqlite-netFx45-setup-x86-2012-1.0.90.0.exe
                  - (10.07 MiB) + (8.18 MiB) This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2012 Update 3 runtime for x86 is + dependencies for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x86 is included. The .NET Framework 4.5 is required.
                  - (sha1: c599782d1965b5fcb470b1896a255ef688869bf1) + (sha1: 4c13a2723840abaa641ff5a969eeb04bb41f801c) @@ -779,42 +779,42 @@   - sqlite-netFx45-setup-bundle-x64-2012-1.0.93.0.exe + sqlite-netFx45-setup-bundle-x64-2012-1.0.90.0.exe
                  - (10.69 MiB) + (8.80 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.93.0 (3.8.5) package. The Visual C++ 2012 + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x64 is included. The .NET Framework 4.5 is required.
                  - (sha1: 00a18ce857f6ea4d37d87993daa0f2f12280848b) + (sha1: 19b572fabdfbf52f8c5d80572deb9a97d49e778a)   - sqlite-netFx45-setup-x64-2012-1.0.93.0.exe + sqlite-netFx45-setup-x64-2012-1.0.90.0.exe
                  - (10.74 MiB) + (8.85 MiB) This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2012 Update 3 runtime for x64 is + dependencies for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x64 is included. The .NET Framework 4.5 is required.
                  - (sha1: dfee560e80ec811e8ea5c1d56c539a7f446112fe) + (sha1: aa0780be097dfde5986a2b3de0c96e7c20d72b19) @@ -824,45 +824,45 @@   - sqlite-netFx451-setup-bundle-x86-2013-1.0.93.0.exe + sqlite-netFx451-setup-bundle-x86-2013-1.0.90.0.exe
                  - (10.00 MiB) + (8.10 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.93.0 (3.8.5) package. The Visual C++ 2013 - Update 2 runtime for x86 is included. The .NET Framework 4.5.1 is + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2013 + RTM runtime for x86 is included. The .NET Framework 4.5.1 is required.
                  This is the only setup package that is capable of installing the design-time components for Visual Studio 2013.
                  - (sha1: 8034fcd2b477bcff54af2b9ccf69472b672825ff) + (sha1: c2bff0cab37ecfea9f58cded8770e46c6cafbcd8)   - sqlite-netFx451-setup-x86-2013-1.0.93.0.exe + sqlite-netFx451-setup-x86-2013-1.0.90.0.exe
                  - (10.02 MiB) + (8.13 MiB) This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2013 Update 2 runtime for x86 is - included. The .NET Framework 4.5.1 is required. + dependencies for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2013 RTM runtime for x86 is included. + The .NET Framework 4.5.1 is required.
                  - (sha1: e4e96075a611a1858d767f8995acecb6bbbe16a0) + (sha1: 5f4c1398c2c1cf950a094a114533056b903afa19) @@ -872,42 +872,42 @@   - sqlite-netFx451-setup-bundle-x64-2013-1.0.93.0.exe + sqlite-netFx451-setup-bundle-x64-2013-1.0.90.0.exe
                  - (10.68 MiB) + (8.78 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.93.0 (3.8.5) package. The Visual C++ 2013 - Update 2 runtime for x64 is included. The .NET Framework 4.5.1 is + the System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2013 + RTM runtime for x64 is included. The .NET Framework 4.5.1 is required.
                  - (sha1: 0d28d49ee0296ec29aaa22aaa95da573eb7c31d4) + (sha1: 02c24a152497a7b031082b2c0371bb4e3e32098a)   - sqlite-netFx451-setup-x64-2013-1.0.93.0.exe + sqlite-netFx451-setup-x64-2013-1.0.90.0.exe
                  - (10.72 MiB) + (8.83 MiB) This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.93.0 - (3.8.5) package. The Visual C++ 2013 Update 2 runtime for x64 is - included. The .NET Framework 4.5.1 is required. + dependencies for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2013 RTM runtime for x64 is included. + The .NET Framework 4.5.1 is required.
                  - (sha1: fbcea471b5f85d02e34974c711302f0102614a75) + (sha1: 4f9651867b44a726c028d48775585a7f6a842262) @@ -917,40 +917,40 @@   - sqlite-netFx20-binary-bundle-Win32-2005-1.0.93.0.zip + sqlite-netFx20-binary-bundle-Win32-2005-1.0.90.0.zip
                  - (1.43 MiB) + (1.39 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.93.0 - (3.8.5) package. The Visual C++ 2005 SP1 runtime for x86 and the .NET + the binaries for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2005 SP1 runtime for x86 and the .NET Framework 2.0 SP2 are required.
                  - (sha1: 0c731b8de5f8645bad76510627904e30c2e2a04d) + (sha1: d4c0b7a1403d8d5f255c38fb01164b3580997cd2)   - sqlite-netFx20-binary-Win32-2005-1.0.93.0.zip + sqlite-netFx20-binary-Win32-2005-1.0.90.0.zip
                  - (1.42 MiB) + (1.38 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2005 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2005 SP1 runtime for x86 and the .NET Framework 2.0 SP2 are required.
                  - (sha1: b1ea6dde44e3bb19fc140c565d366e29270ff963) + (sha1: 38e76395aacd87413fcf30138def6a5c4288c772) @@ -960,40 +960,40 @@   - sqlite-netFx20-binary-bundle-x64-2005-1.0.93.0.zip + sqlite-netFx20-binary-bundle-x64-2005-1.0.90.0.zip
                  - (1.64 MiB) + (1.60 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.93.0 - (3.8.5) package. The Visual C++ 2005 SP1 runtime for x64 and the .NET + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2005 SP1 runtime for x64 and the .NET Framework 2.0 SP2 are required.
                  - (sha1: a01bdb7eefb4e2b85fe7fb9f347a5989f838e07a) + (sha1: 29f84a7b1f59d5380d65fc908789d19663cb4f17)   - sqlite-netFx20-binary-x64-2005-1.0.93.0.zip + sqlite-netFx20-binary-x64-2005-1.0.90.0.zip
                  - (1.64 MiB) + (1.59 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2005 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2005 SP1 runtime for x64 and the .NET Framework 2.0 SP2 are required.
                  - (sha1: 68b34d8f3ff90657b229d5655cb90233aa391ad1) + (sha1: e4b5420f0dd7014bd75f7e2f740d8681ad461767) @@ -1003,40 +1003,40 @@   - sqlite-netFx35-binary-bundle-Win32-2008-1.0.93.0.zip + sqlite-netFx35-binary-bundle-Win32-2008-1.0.90.0.zip
                  - (1.87 MiB) + (1.84 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.93.0 - (3.8.5) 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.90.0 + (3.8.2) package. The Visual C++ 2008 SP1 runtime for x86 and the .NET Framework 3.5 SP1 are required.
                  - (sha1: 639d669a183863aa27545772532cf206b9aeea8c) + (sha1: d24e8097a9da455bddc2f404aa3d0c3677aba124)   - sqlite-netFx35-binary-Win32-2008-1.0.93.0.zip + sqlite-netFx35-binary-Win32-2008-1.0.90.0.zip
                  - (1.86 MiB) + (1.83 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2008 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2008 SP1 runtime for x86 and the .NET Framework 3.5 SP1 are required.
                  - (sha1: 3fcc21d5df79de1a86b746dc08238ca9e7bfa3ba) + (sha1: e71de9d49b20143d910f3f5436e7e6c4f41eaa3c) @@ -1046,40 +1046,40 @@   - sqlite-netFx35-binary-bundle-x64-2008-1.0.93.0.zip + sqlite-netFx35-binary-bundle-x64-2008-1.0.90.0.zip
                  - (1.95 MiB) + (1.91 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.93.0 - (3.8.5) 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.90.0 + (3.8.2) package. The Visual C++ 2008 SP1 runtime for x64 and the .NET Framework 3.5 SP1 are required.
                  - (sha1: 5d1649422a199ca22bb4eade80a393b6e9b2238d) + (sha1: a9ec00f55d90332098d6ca4f0c920c11d4ab04ab)   - sqlite-netFx35-binary-x64-2008-1.0.93.0.zip + sqlite-netFx35-binary-x64-2008-1.0.90.0.zip
                  - (1.94 MiB) + (1.90 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2008 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2008 SP1 runtime for x64 and the .NET Framework 3.5 SP1 are required.
                  - (sha1: eb31581d8c489d77aa2ac402b4f1aec8bc2181bf) + (sha1: 88dc6ba392c460fd11b98ceb555e290597494f72) @@ -1089,40 +1089,40 @@   - sqlite-netFx40-binary-bundle-Win32-2010-1.0.93.0.zip + sqlite-netFx40-binary-bundle-Win32-2010-1.0.90.0.zip
                  - (2.09 MiB) + (1.89 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.93.0 - (3.8.5) 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.90.0 + (3.8.2) package. The Visual C++ 2010 SP1 runtime for x86 and the .NET Framework 4.0 are required.
                  - (sha1: 4cfad756f761eeae7309ef16c2ee6c2145cc7eaf) + (sha1: 9c35e510e35ff822e45aabc0db2c29df8dab020a)   - sqlite-netFx40-binary-Win32-2010-1.0.93.0.zip + sqlite-netFx40-binary-Win32-2010-1.0.90.0.zip
                  - (2.08 MiB) + (1.88 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2010 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2010 SP1 runtime for x86 and the .NET Framework 4.0 are required.
                  - (sha1: f858693a5951162a66e08cccceabaf82abce6928) + (sha1: 1a975eee941a197d909fcd841594d3631beda137) @@ -1132,40 +1132,40 @@   - sqlite-netFx40-binary-bundle-x64-2010-1.0.93.0.zip + sqlite-netFx40-binary-bundle-x64-2010-1.0.90.0.zip
                  - (2.11 MiB) + (1.91 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.93.0 - (3.8.5) package. The Visual C++ 2010 SP1 runtime for x64 and the .NET + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2010 SP1 runtime for x64 and the .NET Framework 4.0 are required.
                  - (sha1: bca8c7c22aa3494df2019f67547f76c8089a1302) + (sha1: 16d17013e66159cd16740697ae11dc667d7b6c70)   - sqlite-netFx40-binary-x64-2010-1.0.93.0.zip + sqlite-netFx40-binary-x64-2010-1.0.90.0.zip
                  - (2.10 MiB) + (1.91 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2010 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2010 SP1 runtime for x64 and the .NET Framework 4.0 are required.
                  - (sha1: aeb85d56b3b2c76e33dee86976a753f97e45474c) + (sha1: c44a1b190ead7ae274c5eb8277adeba4ba234545) @@ -1175,40 +1175,40 @@   - sqlite-netFx45-binary-bundle-Win32-2012-1.0.93.0.zip + sqlite-netFx45-binary-bundle-Win32-2012-1.0.90.0.zip
                  - (2.01 MiB) + (1.82 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.93.0 - (3.8.5) package. The Visual C++ 2012 Update 3 runtime for x86 and + the binaries for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x86 and the .NET Framework 4.5 are required.
                  - (sha1: e42431a3f0343716440cda90cdf65c5349794980) + (sha1: f90aca7a213ae63f42048f3e84e7fc63dc680126)   - sqlite-netFx45-binary-Win32-2012-1.0.93.0.zip + sqlite-netFx45-binary-Win32-2012-1.0.90.0.zip
                  - (2.06 MiB) + (1.87 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2012 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x86 and the .NET Framework 4.5 are required.
                  - (sha1: a75734504cb5679a8ca537e0511e7d259a9fb680) + (sha1: e349b734d6c7e46303e53cb6ad4ddea0f74eb7dd) @@ -1218,40 +1218,40 @@   - sqlite-netFx45-binary-bundle-x64-2012-1.0.93.0.zip + sqlite-netFx45-binary-bundle-x64-2012-1.0.90.0.zip
                  - (2.04 MiB) + (1.85 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.93.0 - (3.8.5) package. The Visual C++ 2012 Update 3 runtime for x64 and + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x64 and the .NET Framework 4.5 are required.
                  - (sha1: b4f9e8d528385168df8b6796f51e06f09bef2fa7) + (sha1: 49e1dc8ceb05a00d60e0699895a21b35fc2c40b6)   - sqlite-netFx45-binary-x64-2012-1.0.93.0.zip + sqlite-netFx45-binary-x64-2012-1.0.90.0.zip
                  - (2.11 MiB) + (1.92 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2012 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x64 and the .NET Framework 4.5 are required.
                  - (sha1: d52b2c51d75da660052adf5ff7c1d84ee017f9d9) + (sha1: 07f1cec08bafa0d6c5f7cda9cacbc71ee23bb812) @@ -1261,40 +1261,40 @@   - sqlite-netFx451-binary-bundle-Win32-2013-1.0.93.0.zip + sqlite-netFx451-binary-bundle-Win32-2013-1.0.90.0.zip
                  - (2.02 MiB) + (1.82 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.93.0 - (3.8.5) package. The Visual C++ 2013 Update 2 runtime for x86 and the - .NET Framework 4.5.1 are required. + the binaries for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2013 RTM runtime for x86 and the .NET + Framework 4.5.1 are required.
                  - (sha1: 0138445b142e34c32dceaafbd663517d7d9f1aa7) + (sha1: 416b5799b348327dc0f52241c3f637e647ee189a)   - sqlite-netFx451-binary-Win32-2013-1.0.93.0.zip + sqlite-netFx451-binary-Win32-2013-1.0.90.0.zip
                  - (2.06 MiB) + (1.87 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2013 - Update 2 runtime for x86 and the .NET Framework 4.5.1 are required. + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2013 RTM + runtime for x86 and the .NET Framework 4.5.1 are required.
                  - (sha1: c44767700432cd86ff7e6248adfcaaad7ad7a5a2) + (sha1: 5984ab24134b7e1f06ab6dce687857de0d025c29) @@ -1304,40 +1304,40 @@   - sqlite-netFx451-binary-bundle-x64-2013-1.0.93.0.zip + sqlite-netFx451-binary-bundle-x64-2013-1.0.90.0.zip
                  - (2.05 MiB) + (1.85 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.93.0 - (3.8.5) package. The Visual C++ 2013 Update 2 runtime for x64 and the - .NET Framework 4.5.1 are required. + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2013 RTM runtime for x64 and the .NET + Framework 4.5.1 are required.
                  - (sha1: bfc8295d96a88d31bd1e61801031e1a0a0d2aa78) + (sha1: 8ee751a8f9c76bdf91bd69af71de906999077254)   - sqlite-netFx451-binary-x64-2013-1.0.93.0.zip + sqlite-netFx451-binary-x64-2013-1.0.90.0.zip
                  - (2.11 MiB) + (1.92 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2013 - Update 2 runtime for x64 and the .NET Framework 4.5.1 are required. + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2013 RTM + runtime for x64 and the .NET Framework 4.5.1 are required.
                  - (sha1: 913fafa8edad9933232f74edf46958b8fbd3cbeb) + (sha1: 026e9ed800761379dd28120cc0bbc932d9f197d3) @@ -1347,41 +1347,41 @@   - sqlite-netFx20-static-binary-bundle-Win32-2005-1.0.93.0.zip + sqlite-netFx20-static-binary-bundle-Win32-2005-1.0.90.0.zip
                  - (1.63 MiB) + (1.60 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.93.0 - (3.8.5) package. The Visual C++ 2005 SP1 runtime for x86 is statically + the binaries for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2005 SP1 runtime for x86 is statically linked. The .NET Framework 2.0 SP2 is required.
                  - (sha1: 2f211b90e3aa92a67d4b2a3a0e0749192c2a0e99) + (sha1: fb659a16f85b0494e7b930c26681e03061085eb3)   - sqlite-netFx20-static-binary-Win32-2005-1.0.93.0.zip + sqlite-netFx20-static-binary-Win32-2005-1.0.90.0.zip
                  - (1.63 MiB) + (1.59 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2005 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2005 SP1 runtime for x86 is statically linked. The .NET Framework 2.0 SP2 is required.
                  - (sha1: c1e0c169cf63f0f7aedc7ee67bb56ed59b7a2cf8) + (sha1: 88ca290f9d42b3e57f661d23438d59b43af7f7a5) @@ -1391,41 +1391,41 @@   - sqlite-netFx20-static-binary-bundle-x64-2005-1.0.93.0.zip + sqlite-netFx20-static-binary-bundle-x64-2005-1.0.90.0.zip
                  - (1.80 MiB) + (1.75 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.93.0 - (3.8.5) package. The Visual C++ 2005 SP1 runtime for x64 is statically + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2005 SP1 runtime for x64 is statically linked. The .NET Framework 2.0 SP2 is required.
                  - (sha1: b43181632c84766f5561d06a933f95d701804dde) + (sha1: a85d2b612a18b88abd36fc9ace14e7067c7b3868)   - sqlite-netFx20-static-binary-x64-2005-1.0.93.0.zip + sqlite-netFx20-static-binary-x64-2005-1.0.90.0.zip
                  - (1.79 MiB) + (1.74 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2005 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2005 SP1 runtime for x64 is statically linked. The .NET Framework 2.0 SP2 is required.
                  - (sha1: fd0369db4ec8c10e44789922211dff11aff21bb0) + (sha1: 3e8849995d980734f0930cfced4a8d8406a781c6) @@ -1435,41 +1435,41 @@   - sqlite-netFx35-static-binary-bundle-Win32-2008-1.0.93.0.zip + sqlite-netFx35-static-binary-bundle-Win32-2008-1.0.90.0.zip
                  - (2.09 MiB) + (2.05 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.93.0 - (3.8.5) package. The Visual C++ 2008 SP1 runtime for x86 is statically + the binaries for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2008 SP1 runtime for x86 is statically linked. The .NET Framework 3.5 SP1 is required.
                  - (sha1: 8525b8ef6fc3821beeae6170dce62143657aef01) + (sha1: 742f24991df821f6479ad58f6895a7bfd125251b)   - sqlite-netFx35-static-binary-Win32-2008-1.0.93.0.zip + sqlite-netFx35-static-binary-Win32-2008-1.0.90.0.zip
                  - (2.08 MiB) + (2.05 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2008 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2008 SP1 runtime for x86 is statically linked. The .NET Framework 3.5 SP1 is required.
                  - (sha1: 69d6ae9b50f97bb9af116e0dbe2f9a9c6d2b17b8) + (sha1: 8e205f33968515d4757bbb8836fdce7c0d00f118) @@ -1479,41 +1479,41 @@   - sqlite-netFx35-static-binary-bundle-x64-2008-1.0.93.0.zip + sqlite-netFx35-static-binary-bundle-x64-2008-1.0.90.0.zip
                  - (2.12 MiB) + (2.09 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.93.0 - (3.8.5) package. The Visual C++ 2008 SP1 runtime for x64 is statically + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2008 SP1 runtime for x64 is statically linked. The .NET Framework 3.5 SP1 is required.
                  - (sha1: d8f1482d4b47d6d491c90e80113fcad4fb93d762) + (sha1: fe5c66cb873eecab67b74a9db9404ba126f7acab)   - sqlite-netFx35-static-binary-x64-2008-1.0.93.0.zip + sqlite-netFx35-static-binary-x64-2008-1.0.90.0.zip
                  - (2.11 MiB) + (2.08 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2008 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2008 SP1 runtime for x64 is statically linked. The .NET Framework 3.5 SP1 is required.
                  - (sha1: 0fd0e3f607bf9242a254c28828bc65d0e2276be9) + (sha1: 88e9585364a51e49b3cd3be13cd9467f9d6aa62b) @@ -1523,41 +1523,41 @@   - sqlite-netFx40-static-binary-bundle-Win32-2010-1.0.93.0.zip + sqlite-netFx40-static-binary-bundle-Win32-2010-1.0.90.0.zip
                  - (2.30 MiB) + (2.11 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.93.0 - (3.8.5) package. The Visual C++ 2010 SP1 runtime for x86 is statically + the binaries for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2010 SP1 runtime for x86 is statically linked. The .NET Framework 4.0 is required.
                  - (sha1: dce0e8859f4defeb872dc71c17ebd6c769845309) + (sha1: 5539a0c27db8ac0b48378f909f8bafc2b43ef392)   - sqlite-netFx40-static-binary-Win32-2010-1.0.93.0.zip + sqlite-netFx40-static-binary-Win32-2010-1.0.90.0.zip
                  - (2.30 MiB) + (2.10 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2010 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2010 SP1 runtime for x86 is statically linked. The .NET Framework 4.0 is required.
                  - (sha1: f9b7bd228a3d0985a94daeabf6fd2eddf90e15cb) + (sha1: 25034a9d483ba0a2a7a63c18c6797294c7a77c44) @@ -1567,41 +1567,41 @@   - sqlite-netFx40-static-binary-bundle-x64-2010-1.0.93.0.zip + sqlite-netFx40-static-binary-bundle-x64-2010-1.0.90.0.zip
                  - (2.30 MiB) + (2.11 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.93.0 - (3.8.5) package. The Visual C++ 2010 SP1 runtime for x64 is statically + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2010 SP1 runtime for x64 is statically linked. The .NET Framework 4.0 is required.
                  - (sha1: ea2586f27430d8395b531c43e10495790cd3cefc) + (sha1: e63934d8ff95a70382a225d4cf6b6fb28c1e7081)   - sqlite-netFx40-static-binary-x64-2010-1.0.93.0.zip + sqlite-netFx40-static-binary-x64-2010-1.0.90.0.zip
                  - (2.30 MiB) + (2.10 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2010 SP1 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2010 SP1 runtime for x64 is statically linked. The .NET Framework 4.0 is required.
                  - (sha1: 525dd05053c3d11e5224142506eca9ee0569b131) + (sha1: 7da8eb7d3ceeebb803ac3d8385c4287c526cdf12) @@ -1611,41 +1611,41 @@   - sqlite-netFx45-static-binary-bundle-Win32-2012-1.0.93.0.zip + sqlite-netFx45-static-binary-bundle-Win32-2012-1.0.90.0.zip
                  - (2.34 MiB) + (2.14 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.93.0 - (3.8.5) package. The Visual C++ 2012 Update 3 runtime for x86 is + the binaries for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x86 is statically linked. The .NET Framework 4.5 is required.
                  - (sha1: 5faf703ea1a37a337dc25c4f57c9c5c4f05949dd) + (sha1: 22a8af8296a394ff8acc3e79dec18ea980c64b16)   - sqlite-netFx45-static-binary-Win32-2012-1.0.93.0.zip + sqlite-netFx45-static-binary-Win32-2012-1.0.90.0.zip
                  - (2.39 MiB) + (2.19 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2012 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x86 is statically linked. The .NET Framework 4.5 is required.
                  - (sha1: 61199f87437954c662e15108a50983562aecfaec) + (sha1: 3a27e07b415550be7397e2c6df5378427db974d6) @@ -1655,41 +1655,41 @@   - sqlite-netFx45-static-binary-bundle-x64-2012-1.0.93.0.zip + sqlite-netFx45-static-binary-bundle-x64-2012-1.0.90.0.zip
                  - (2.30 MiB) + (2.11 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.93.0 - (3.8.5) package. The Visual C++ 2012 Update 3 runtime for x64 is + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x64 is statically linked. The .NET Framework 4.5 is required.
                  - (sha1: 4e828eb7c23c03e95a58ca96b90258559bb731fe) + (sha1: 4a6c0ba1e6709e252d7238391326907ec40cf2ee)   - sqlite-netFx45-static-binary-x64-2012-1.0.93.0.zip + sqlite-netFx45-static-binary-x64-2012-1.0.90.0.zip
                  - (2.37 MiB) + (2.18 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2012 + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2012 Update 3 runtime for x64 is statically linked. The .NET Framework 4.5 is required.
                  - (sha1: afbbf6f28b8fdfb2943bbe6081d930b9e8db1867) + (sha1: ccbed6182689dd9dbaa326abfd66dff99ae5f86a) @@ -1699,41 +1699,41 @@   - sqlite-netFx451-static-binary-bundle-Win32-2013-1.0.93.0.zip + sqlite-netFx451-static-binary-bundle-Win32-2013-1.0.90.0.zip
                  - (2.37 MiB) + (2.16 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.93.0 - (3.8.5) package. The Visual C++ 2013 Update 2 runtime for x86 is - statically linked. The .NET Framework 4.5.1 is required. + the binaries for the x86 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2013 RTM runtime for x86 is statically + linked. The .NET Framework 4.5.1 is required.
                  - (sha1: 4ccb18179fd0eacf0577fab94a22781d767b631b) + (sha1: abf22b1499da05d4625e7e9fe0f3f608fd3cfcea)   - sqlite-netFx451-static-binary-Win32-2013-1.0.93.0.zip + sqlite-netFx451-static-binary-Win32-2013-1.0.90.0.zip
                  - (2.41 MiB) + (2.21 MiB) This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2013 - Update 2 runtime for x86 is statically linked. The .NET Framework 4.5.1 - is required. + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2013 RTM + runtime for x86 is statically linked. The .NET Framework 4.5.1 is + required.
                  - (sha1: 17925fdd41fe11fe0bf0a14dedd2f2e9d8e21b7d) + (sha1: 85e74729d8e1c5ff84c6fb1724d733bad1388580) @@ -1743,41 +1743,41 @@   - sqlite-netFx451-static-binary-bundle-x64-2013-1.0.93.0.zip + sqlite-netFx451-static-binary-bundle-x64-2013-1.0.90.0.zip
                  - (2.34 MiB) + (2.14 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.93.0 - (3.8.5) package. The Visual C++ 2013 Update 2 runtime for x64 is - statically linked. The .NET Framework 4.5.1 is required. + the binaries for the x64 version of the System.Data.SQLite 1.0.90.0 + (3.8.2) package. The Visual C++ 2013 RTM runtime for x64 is statically + linked. The .NET Framework 4.5.1 is required.
                  - (sha1: c9b6a4f444abb13545fb4c6759121b9adedd16c4) + (sha1: 6d8e80a0867e38aca9be1e2c82d495cc447436e3)   - sqlite-netFx451-static-binary-x64-2013-1.0.93.0.zip + sqlite-netFx451-static-binary-x64-2013-1.0.90.0.zip
                  - (2.40 MiB) + (2.20 MiB) This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.93.0 (3.8.5) package. The Visual C++ 2013 - Update 2 runtime for x64 is statically linked. The .NET Framework 4.5.1 - is required. + System.Data.SQLite 1.0.90.0 (3.8.2) package. The Visual C++ 2013 RTM + runtime for x64 is statically linked. The .NET Framework 4.5.1 is + required.
                  - (sha1: d12646f976f3da508c65b75dd209fad7376480a4) + (sha1: 5c0b3fe2c61a0721d2e9b01fd137422aac1a5ccd) @@ -1787,278 +1787,158 @@   - sqlite-netFx35-binary-PocketPC-ARM-2008-1.0.93.0.zip + sqlite-netFx35-binary-PocketPC-ARM-2008-1.0.90.0.zip
                  - (1.06 MiB) + (1.03 MiB) This binary package contains all the binaries for the PocketPC version - of the System.Data.SQLite 1.0.93.0 (3.8.5) package. The included native + of the System.Data.SQLite 1.0.90.0 (3.8.2) package. The included native binaries should work on all supported ARM versions of Windows CE prior to Windows Embedded Compact 2013. The .NET Compact Framework 3.5 is required.
                  - (sha1: 607ced9c65aae92e36f03f0d84f9973c3d8ac721) + (sha1: 19130889ed37cae2cb74ca13f2d0d28b07fd614d)   - sqlite-netFx39-binary-WinCE-ARM-2012-1.0.93.0.zip + sqlite-netFx39-binary-WinCE-ARM-2012-1.0.90.0.zip
                  - (1.17 MiB) + (1.14 MiB) This binary package contains all the binaries for the Windows Embedded - Compact 2013 (ARM) version of the System.Data.SQLite 1.0.93.0 (3.8.5) + Compact 2013 (ARM) version of the System.Data.SQLite 1.0.90.0 (3.8.2) package. The .NET Compact Framework 3.9 is required.
                  - (sha1: 6cfa5cd7dd3c13cf2c770c065771d870837a90d9) + (sha1: b8d8aa88dc8b724ffad88ad17fd0c81c1f142b3d)   - sqlite-netFx39-binary-WinCE-x86-2012-1.0.93.0.zip + sqlite-netFx39-binary-WinCE-x86-2012-1.0.90.0.zip
                  - (1.21 MiB) + (1.19 MiB) This binary package contains all the binaries for the Windows Embedded - Compact 2013 (x86) version of the System.Data.SQLite 1.0.93.0 (3.8.5) + Compact 2013 (x86) version of the System.Data.SQLite 1.0.90.0 (3.8.2) package. The .NET Compact Framework 3.9 is required.
                  - (sha1: 3231e952081f34b4ee17342514d75af14724208e) + (sha1: be3c8f5806e0637bcb56e06f4c091db9ea191ff8) - Official NuGet Packages   - System.Data.SQLite.1.0.93.0.nupkg + System.Data.SQLite.1.0.90.0.nupkg
                  - (0.00 MiB) + (4.92 MiB) - This NuGet package includes all the binaries for both the x86 and x64 - versions of System.Data.SQLite 1.0.93.0 (3.8.5). The .NET Framework + This NuGet package contains all the binaries for both the x86 and x64 + versions of System.Data.SQLite 1.0.90.0 (3.8.2). The .NET Framework 3.5 SP1, 4.0, 4.5, or 4.5.1 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.
                  - This package depends on the "EntityFramework" - package. -
                  -
                  - As of version 1.0.92.0, this package will not directly - contain any of the required binaries. Instead, this package will - depend on the "System.Data.SQLite.Core", - "System.Data.SQLite.Linq", and - "System.Data.SQLite.EF6" packages. -
                  -
                  - (sha1: 08a0821fa6b6001bc6408f91637d3dad461bb100) + (sha1: 23a3de95f68c5f42b26fb3f7fb5566344e1f31ee) + + + + +   + + System.Data.SQLite.MSIL.1.0.90.0.nupkg +
                  + (0.81 MiB) + + + + This NuGet package contains the managed binaries for System.Data.SQLite + 1.0.90.0. The .NET Framework 3.5 SP1, 4.0, 4.5, or 4.5.1 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: 1939d2f0aee38e6bb4fd3a61d77fcb2273ac81e6)   - System.Data.SQLite.Core.1.0.93.0.nupkg -
                  - (4.85 MiB) - - - - This NuGet package contains all the binaries for both the x86 and x64 - versions of System.Data.SQLite 1.0.93.0 (3.8.5), except those - needed to support LINQ and Entity Framework 6. The .NET - Framework 3.5 SP1, 4.0, 4.5, or 4.5.1 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. -
                  - This package does not depend on any other package. -
                  - (sha1: fd208192c6dc49e4051e348904ea75bc307f3384) - - - - -   - - System.Data.SQLite.Core.MSIL.1.0.93.0.nupkg -
                  - (0.68 MiB) - - - - This NuGet package contains the managed binaries for System.Data.SQLite - 1.0.93.0. The .NET Framework 3.5 SP1, 4.0, 4.5, or 4.5.1 is required. -
                  - This package does not depend on any other package. -
                  -
                  - 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: 8543f8c8460ee1898873e1b1384a6ecced819f2b) + System.Data.SQLite.x86.1.0.90.0.nupkg +
                  + (2.60 MiB) + + + + This NuGet package contains all the binaries for the x86 version of + System.Data.SQLite 1.0.90.0 (3.8.2). The .NET Framework 3.5 SP1, + 4.0, 4.5, or 4.5.1 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: a12ef10b7931d6149d7dfd496a5769375491ccd2)   - System.Data.SQLite.EF6.1.0.93.0.nupkg -
                  - (0.13 MiB) - - - - This NuGet package contains just the binaries to support Entity - Framework 6 using System.Data.SQLite 1.0.93.0 (3.8.5). The .NET - Framework 4.0, 4.5, or 4.5.1 is required. -
                  - This package depends on both the - "System.Data.SQLite.Core" and "EntityFramework" - packages. -
                  - (sha1: e4f5c3e78e87f6da97fc9c8ca1d7ad7d9d4f5fee) - - - - -   - - System.Data.SQLite.Linq.1.0.93.0.nupkg -
                  - (0.17 MiB) - - - - This NuGet package contains just the binaries to support LINQ using - System.Data.SQLite 1.0.93.0 (3.8.5). The .NET Framework 3.5 SP1, 4.0, - 4.5, or 4.5.1 is required. -
                  - This package depends on the "System.Data.SQLite.Core" - package. -
                  - (sha1: ef48466d3b736035834eecee4178a6ed973e9797) - - - - -   - - System.Data.SQLite.MSIL.1.0.93.0.nupkg -
                  - (0.98 MiB) - - - - This NuGet package contains the managed binaries for System.Data.SQLite - 1.0.93.0. The .NET Framework 3.5 SP1, 4.0, 4.5, or 4.5.1 is required. -
                  - This is a legacy package; if possible, please use either the - "System.Data.SQLite" or "System.Data.SQLite.Core" - package instead. This package depends on the "EntityFramework" - package. -
                  -
                  - 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: b2a6688d51ba3a847ba1d893a9b0ab554adc7cb8) - - - - -   - - System.Data.SQLite.x86.1.0.93.0.nupkg -
                  - (2.80 MiB) - - - - This NuGet package contains all the binaries for the x86 version of - System.Data.SQLite 1.0.93.0 (3.8.5). The .NET Framework 3.5 SP1, - 4.0, 4.5, or 4.5.1 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. -
                  - This is a legacy package; if possible, please use either the - "System.Data.SQLite" or "System.Data.SQLite.Core" - package instead. This package depends on the "EntityFramework" - package. -
                  - (sha1: 060d2ec16e33437a803ac75ee5c26950cbda62f4) - - - - -   - - System.Data.SQLite.x64.1.0.93.0.nupkg -
                  - (3.08 MiB) - - - - This NuGet package contains all the binaries for the x64 version of - System.Data.SQLite 1.0.93.0 (3.8.5). The .NET Framework 3.5 SP1, - 4.0, 4.5, or 4.5.1 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. -
                  - This is a legacy package; if possible, please use either the - "System.Data.SQLite" or "System.Data.SQLite.Core" - package instead. This package depends on the - "EntityFramework" package. -
                  - (sha1: 426ac67705599ca93658482efdf15b36ab55ed0d) + System.Data.SQLite.x64.1.0.90.0.nupkg +
                  + (2.88 MiB) + + + + This NuGet package contains all the binaries for the x64 version of + System.Data.SQLite 1.0.90.0 (3.8.2). The .NET Framework 3.5 SP1, + 4.0, 4.5, or 4.5.1 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: ae2d099ea8ccaa996845fead6a1d9cfafc30e985) - Legacy Versions   - SQLite-1.0.66.0-setup.exe + SQLite-1.0.66.0-setup.exe
                  (3.2 MiB) Index: www/faq.wiki ================================================================== --- www/faq.wiki +++ www/faq.wiki @@ -227,72 +227,31 @@
                  • System.Data.SQLite: The SQLite database engine for both x86 and x64 - along with the ADO.NET provider, including support for LINQ and Entity - Framework 6. -
                  • - -
                  • - - System.Data.SQLite.Beta: The SQLite database engine for both x86 - and x64 along with the ADO.NET provider, including support for LINQ - and Entity Framework 6. This package may contain beta code and - is not intended for production use. -
                  • - -
                  • - - System.Data.SQLite.Core: The SQLite database engine for both x86 and - x64 along with the ADO.NET provider. -
                  • - -
                  • - - System.Data.SQLite.Core.MSIL: Just the managed ADO.NET provider for - SQLite. -
                  • - -
                  • - - System.Data.SQLite.EF6: Just support for Entity Framework 6 using - System.Data.SQLite. -
                  • - -
                  • - - System.Data.SQLite.Linq: Just support for LINQ using - System.Data.SQLite. -
                  • - -
                  • - - System.Data.SQLite.MSIL: Just the managed ADO.NET provider for - SQLite. -
                  • - -
                  • - - System.Data.SQLite.Test: The SQLite database engine for both x86 - and x64 along with the ADO.NET provider, including support for LINQ - and Entity Framework 6. This package may contain untested code - and is not intended for production use. + along with the ADO.NET provider.
                  • System.Data.SQLite.x86: The SQLite database engine combined with a - complete ADO.NET provider all rolled into a single mixed-mode assembly - for x86. + complete ADO.NET provider all rolled into a single mixed-mode assembly for + x86.
                  • System.Data.SQLite.x64: The SQLite database engine combined with a - complete ADO.NET provider all rolled into a single mixed-mode assembly - for x64. + complete ADO.NET provider all rolled into a single mixed-mode assembly for + x64. +
                  • + +
                  • + + System.Data.SQLite.MSIL: Just the ADO.NET provider for SQLite + (managed-only).


                  @@ -389,11 +348,11 @@


                  - (11) Why do I get a DllNotFoundException (for "sqlite3.dll" + (11) Why do I get a DllNotFoundException (for "sqlite3.dll" or "SQLite.Interop.dll") when trying to run my application?

                  Either the named dynamic link library (DLL) cannot be located or it cannot be Index: www/index.wiki ================================================================== --- www/index.wiki +++ www/index.wiki @@ -1,17 +1,16 @@ -Home +About
                    -

                  About System.Data.SQLite

                  - System.Data.SQLite is an ADO.NET provider for + System.Data.SQLite is an ADO.NET adapter for SQLite.

                  System.Data.SQLite was started by Robert Simpson. Robert still has commit privileges on this repository but is no longer an active @@ -33,21 +32,18 @@

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

                  -

                  Documentation for System.Data.SQLite

                  - The documentation corresponding to the most recently released version - of System.Data.SQLite, which contains detailed information for all - public types, methods, properties, and events is checked into the - repository in + 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. + downloaded directly via the web interface to the repository.

                  @@ -61,14 +57,13 @@
                3. Contributing
                4. Source Code
                5. Build Procedures
                6. Test Procedures
                7. Release Procedures
                8. -
                9. Copyright
                10. Index: www/news.wiki ================================================================== --- www/news.wiki +++ www/news.wiki @@ -1,43 +1,14 @@ News Version History

                  - 1.0.93.0 - June 23, 2014 -

                  -
                    -
                  • Updated to [http://www.sqlite.org/releaselog/3_8_5.html|SQLite 3.8.5].
                  • -
                  • Updated to [http://www.nuget.org/packages/EntityFramework/6.1|Entity Framework 6.1].
                  • -
                  • Add support for mapping transaction isolation levels to their legacy default values. Pursuant to [56b42d99c1].
                  • -
                  • Add support for setting the default DbType and type name used for mappings on a per-connection basis. Pursuant to [3c00ec5b52].
                  • -
                  • Add DetectTextAffinity and DetectStringType connection flags to enable automatic detection of column types, when necessary. Pursuant to [3c00ec5b52].
                  • -
                  • Add SetChunkSize method to the SQLiteConnection class. Pursuant to [d1c008fa0a].
                  • -
                  • Add SharedFlags static property to the SQLiteConnection class.
                  • -
                  • Make the ISQLiteSchemaExtensions interface public. ** Potentially Incompatible Change **
                  • -
                  • Have the SQLiteProviderFactory class (in the System.Data.SQLite.Linq assembly) implement the IServiceProvider interface.
                  • -
                  • Fix bug in documentation generator automation that prevented some internal documentation links from working.
                  • -
                  • Fix DateTime constant handling in the LINQ assembly. Fix for [da9f18d039]. ** Potentially Incompatible Change **
                  • -
                  -

                  - 1.0.92.0 - March 19, 2014 -

                  -
                    -
                  • Updated to [http://www.sqlite.org/releaselog/3_8_4_1.html|SQLite 3.8.4.1].
                  • -
                  • Update the list of keywords returned by SQLiteConnection.GetSchema("ReservedWords"). ** Potentially Incompatible Change **
                  • -
                  • Raise the static SQLiteConnection.Changed event when any SQLiteCommand or SQLiteDataReader object is closed or disposed.
                  • -
                  • Add the SQLiteDataReader.StepCount property to return the number of rows seen so far.
                  • -
                  • Add StickyHasRows connection flag to cause the SQLiteDataReader.HasRows property to return non-zero if there were ever any rows in the associated result sets.
                  • -
                  • When the TraceWarning connection flag is set, issue warnings about possibly malformed UNC paths. Pursuant to [283344397b].
                  • -
                  • Convert the primary NuGet package, "System.Data.SQLite", into a meta-package.
                  • -
                  • Enhancements to the NuGet packages, including the new "modular" packages.
                  • -
                  -

                  - 1.0.91.0 - February 12, 2014 -

                  -
                    -
                  • Updated to [http://www.sqlite.org/releaselog/3_8_3_1.html|SQLite 3.8.3.1].
                  • + 1.0.91.0 - February XX, 2014 (release scheduled) +

                    +
                      +
                    • Updated to [http://www.sqlite.org/releaselog/3_8_3.html|SQLite 3.8.3].
                    • Refresh all included SQLite core library documentation (e.g. SQL syntax).
                    • Add support for [http://entityframework.codeplex.com/|Entity Framework 6].
                    • Add support for per-connection mappings between type names and DbType values. Pursuant to [e87af1d06a].
                    • Modify the namespace used for all internal classes in the System.Data.SQLite.Linq assembly. ** Potentially Incompatible Change **
                    • Add SQLiteCompileOptions and InteropCompileOptions properties to the SQLiteConnection class to return the compile-time options for the SQLite core library and interop assembly, respectively.
                    • @@ -45,11 +16,10 @@
                    • Add NoConnectionPool and UseConnectionPool connection flags to disable or enable connection pooling by default.
                    • Modify handling of the design-time components installer to run Visual Studio devenv.exe /setup after installing the package. This appears to be necessary in some circumstances for Visual Studio 2013. Pursuant to [a47eff2c71].
                    • Modify the native library pre-loader to support reading settings from an XML configuration file and to be capable of checking more than one directory. Persuant to [f0246d1817].
                    • Support detecting when the native library pre-loader should use the CodeBase property instead of the Location property as the basis for locating the interop assembly.
                    • Change the default behavior for the native library pre-loader so it first searches the executing (i.e. System.Data.SQLite) assembly directory and then the application domain directory. Pursuant to [f0246d1817]. ** Potentially Incompatible Change **
                    • -
                    • Include DbType.AnsiString in the list of types that need special ColumnSize handling. Fix for [0550f0326e].

                    1.0.90.0 - December 23, 2013

                      Index: www/release.wiki ================================================================== --- www/release.wiki +++ www/release.wiki @@ -21,15 +21,13 @@
                    • Open a normal command prompt window with "cmd.exe".
                    • Change the current directory to "<root>\Setup".
                    • - Enter the following commands to build all the x86 and x64 binaries: + Enter the following command to build all the x86 and x64 binaries:

                      - SET BUILD_DEBUG=1 -
                      build_all.bat
                @@ -45,16 +43,14 @@
              3. Open a normal command prompt window with "cmd.exe".
              4. Change the current directory to "<root>\Setup".
              5. - Enter the following commands to test all the x86 or x64 binaries, depending + Enter the following command to test all the x86 or x64 binaries, depending on the processor architecture of the current machine:

                - SET TEST_DEBUG=1 -
                test_all.bat
              6. Locate a machine with a processor architecture different from the one tested @@ -185,13 +181,12 @@ Update the "<root>\readme.htm" file with information about all the major changes since the last released version.
              7. - Copy those changes to the - "<root>\Doc\Extra\Provider\version.html" and - "<root>\www\news.wiki" files, reformatting as necessary + Copy those changes to the "<root>\Doc\Extra\version.html" + and "<root>\www\news.wiki" files, reformatting as necessary to fit with the existing document conventions.
              @@ -343,59 +338,10 @@ Enter the following command to build the "default" NuGet package:

              nuget.exe pack NuGet\SQLite.nuspec
              -
              - This assumes that the NuGet binary is available somewhere along the - [http://en.wikipedia.org/wiki/PATH_%28variable%29 | PATH].
              Please refer - to [http://docs.nuget.org/ | NuGet Documentation] for further details.
              -
            3. - -
            4. - Enter the following command to build the "core" NuGet package: -
              -
              - nuget.exe pack NuGet\SQLite.Core.nuspec -
              -
              - This assumes that the NuGet binary is available somewhere along the - [http://en.wikipedia.org/wiki/PATH_%28variable%29 | PATH].
              Please refer - to [http://docs.nuget.org/ | NuGet Documentation] for further details.
              -
            5. - -
            6. - Enter the following command to build the "core managed-only" - NuGet package: -
              -
              - nuget.exe pack NuGet\SQLite.Core.MSIL.nuspec -
              -
              - This assumes that the NuGet binary is available somewhere along the - [http://en.wikipedia.org/wiki/PATH_%28variable%29 | PATH].
              Please refer - to [http://docs.nuget.org/ | NuGet Documentation] for further details.
              -
            7. - -
            8. - Enter the following command to build the "EF6" NuGet package: -
              -
              - nuget.exe pack NuGet\SQLite.EF6.nuspec -
              -
              - This assumes that the NuGet binary is available somewhere along the - [http://en.wikipedia.org/wiki/PATH_%28variable%29 | PATH].
              Please refer - to [http://docs.nuget.org/ | NuGet Documentation] for further details.
              -
            9. - -
            10. - Enter the following command to build the "LINQ" NuGet package: -
              -
              - nuget.exe pack NuGet\SQLite.Linq.nuspec -

              This assumes that the NuGet binary is available somewhere along the [http://en.wikipedia.org/wiki/PATH_%28variable%29 | PATH].
              Please refer to [http://docs.nuget.org/ | NuGet Documentation] for further details.