dbda8d6ce9 2007-07-21 drh: /****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** This file is an amalgamation of many separate C source files from SQLite c287665ba8 2007-09-14 drh: ** version 3.5.0. By combining all the individual C code files into this dbda8d6ce9 2007-07-21 drh: ** single large file, the entire code can be compiled as a one translation dbda8d6ce9 2007-07-21 drh: ** unit. This allows many compilers to do optimizations that would not be dbda8d6ce9 2007-07-21 drh: ** possible if the files were compiled separately. Performance improvements dbda8d6ce9 2007-07-21 drh: ** of 5% are more are commonly seen when SQLite is compiled as a single dbda8d6ce9 2007-07-21 drh: ** translation unit. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file is all you need to compile SQLite. To use SQLite in other dbda8d6ce9 2007-07-21 drh: ** programs, you need this file and the "sqlite3.h" header file that defines dbda8d6ce9 2007-07-21 drh: ** the programming interface to the SQLite library. (If you do not have dbda8d6ce9 2007-07-21 drh: ** the "sqlite3.h" header file at hand, you will find a copy in the first c287665ba8 2007-09-14 drh: ** 3539 lines past this header comment.) Additional code files may be dbda8d6ce9 2007-07-21 drh: ** needed if you want a wrapper to interface SQLite with your choice of dbda8d6ce9 2007-07-21 drh: ** programming language. The code for the "sqlite3" command-line shell dbda8d6ce9 2007-07-21 drh: ** is also in a separate file. This file contains only code for the core dbda8d6ce9 2007-07-21 drh: ** SQLite library. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** This amalgamation was generated on 2007-09-14 14:58:10 UTC. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_AMALGAMATION 1 dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_PRIVATE dbda8d6ce9 2007-07-21 drh: # define SQLITE_PRIVATE static dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_API dbda8d6ce9 2007-07-21 drh: # define SQLITE_API dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: /************** Begin file sqlite3.h *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This header file defines the interface that the SQLite library dbda8d6ce9 2007-07-21 drh: ** presents to client programs. If a C-function, structure, datatype, dbda8d6ce9 2007-07-21 drh: ** or constant definition does not appear in this file, then it is dbda8d6ce9 2007-07-21 drh: ** not a published API of SQLite, is subject to change without dbda8d6ce9 2007-07-21 drh: ** notice, and should not be referenced by programs that use SQLite. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Some of the definitions that are in this file are marked as dbda8d6ce9 2007-07-21 drh: ** "experimental". Experimental interfaces are normally new dbda8d6ce9 2007-07-21 drh: ** features recently added to SQLite. We do not anticipate changes dbda8d6ce9 2007-07-21 drh: ** to experimental interfaces but reserve to make minor changes if dbda8d6ce9 2007-07-21 drh: ** experience from use "in the wild" suggest such changes are prudent. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The official C-language API documentation for SQLite is derived dbda8d6ce9 2007-07-21 drh: ** from comments in this file. This file is the authoritative source dbda8d6ce9 2007-07-21 drh: ** on how SQLite interfaces are suppose to operate. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The name of this file under configuration management is "sqlite.h.in". dbda8d6ce9 2007-07-21 drh: ** The makefile makes some minor changes to this file (such as inserting dbda8d6ce9 2007-07-21 drh: ** the version number) and changes its name to "sqlite3.h" as dbda8d6ce9 2007-07-21 drh: ** part of the build process. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: sqlite.h.in,v 1.259 2007/09/04 22:31:37 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef _SQLITE3_H_ dbda8d6ce9 2007-07-21 drh: #define _SQLITE3_H_ dbda8d6ce9 2007-07-21 drh: #include <stdarg.h> /* Needed for the definition of va_list */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make sure we can call this stuff from C++. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if 0 dbda8d6ce9 2007-07-21 drh: extern "C" { c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Add the ability to override 'extern' c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef SQLITE_EXTERN c287665ba8 2007-09-14 drh: # define SQLITE_EXTERN extern dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make sure these symbols where not defined by some previous header dbda8d6ce9 2007-07-21 drh: ** file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_VERSION dbda8d6ce9 2007-07-21 drh: # undef SQLITE_VERSION dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_VERSION_NUMBER dbda8d6ce9 2007-07-21 drh: # undef SQLITE_VERSION_NUMBER dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Compile-Time Library Version Numbers dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The version of the SQLite library is contained in the sqlite3.h dbda8d6ce9 2007-07-21 drh: ** header file in a #define named SQLITE_VERSION. The SQLITE_VERSION dbda8d6ce9 2007-07-21 drh: ** macro resolves to a string constant. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The format of the version string is "X.Y.Z", where dbda8d6ce9 2007-07-21 drh: ** X is the major version number, Y is the minor version number and Z dbda8d6ce9 2007-07-21 drh: ** is the release number. The X.Y.Z might be followed by "alpha" or "beta". dbda8d6ce9 2007-07-21 drh: ** For example "3.1.1beta". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The X value is always 3 in SQLite. The X value only changes when dbda8d6ce9 2007-07-21 drh: ** backwards compatibility is broken and we intend to never break dbda8d6ce9 2007-07-21 drh: ** backwards compatibility. The Y value only changes when dbda8d6ce9 2007-07-21 drh: ** there are major feature enhancements that are forwards compatible dbda8d6ce9 2007-07-21 drh: ** but not backwards compatible. The Z value is incremented with dbda8d6ce9 2007-07-21 drh: ** each release but resets back to 0 when Y is incremented. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The SQLITE_VERSION_NUMBER is an integer with the value dbda8d6ce9 2007-07-21 drh: ** (X*1000000 + Y*1000 + Z). For example, for version "3.1.1beta", dbda8d6ce9 2007-07-21 drh: ** SQLITE_VERSION_NUMBER is set to 3001001. To detect if they are using dbda8d6ce9 2007-07-21 drh: ** version 3.1.1 or greater at compile time, programs may use the test dbda8d6ce9 2007-07-21 drh: ** (SQLITE_VERSION_NUMBER>=3001001). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: [sqlite3_libversion()] and [sqlite3_libversion_number()]. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_VERSION "3.5.0" c287665ba8 2007-09-14 drh: #define SQLITE_VERSION_NUMBER 3005000 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Run-Time Library Version Numbers dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines return values equivalent to the header constants dbda8d6ce9 2007-07-21 drh: ** [SQLITE_VERSION] and [SQLITE_VERSION_NUMBER]. The values returned dbda8d6ce9 2007-07-21 drh: ** by this routines should only be different from the header values dbda8d6ce9 2007-07-21 drh: ** if you compile your program using an sqlite3.h header from a dbda8d6ce9 2007-07-21 drh: ** different version of SQLite that the version of the library you dbda8d6ce9 2007-07-21 drh: ** link against. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_version[] string constant contains the text of the dbda8d6ce9 2007-07-21 drh: ** [SQLITE_VERSION] string. The sqlite3_libversion() function returns dbda8d6ce9 2007-07-21 drh: ** a poiner to the sqlite3_version[] string constant. The function dbda8d6ce9 2007-07-21 drh: ** is provided for DLL users who can only access functions and not dbda8d6ce9 2007-07-21 drh: ** constants within the DLL. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_EXTERN const char sqlite3_version[]; dbda8d6ce9 2007-07-21 drh: SQLITE_API const char *sqlite3_libversion(void); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_libversion_number(void); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Test To See If The Library Is Threadsafe c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine returns TRUE (nonzero) if SQLite was compiled with c287665ba8 2007-09-14 drh: ** all of its mutexes enabled and is thus threadsafe. It returns c287665ba8 2007-09-14 drh: ** zero if the particular build is for single-threaded operation c287665ba8 2007-09-14 drh: ** only. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Really all this routine does is return true if SQLite was compiled c287665ba8 2007-09-14 drh: ** with the -DSQLITE_THREADSAFE=1 option and false if c287665ba8 2007-09-14 drh: ** compiled with -DSQLITE_THREADSAFE=0. If SQLite uses an c287665ba8 2007-09-14 drh: ** application-defined mutex subsystem, malloc subsystem, collating c287665ba8 2007-09-14 drh: ** sequence, VFS, SQL function, progress callback, commit hook, c287665ba8 2007-09-14 drh: ** extension, or other accessories and these add-ons are not c287665ba8 2007-09-14 drh: ** threadsafe, then clearly the combination will not be threadsafe c287665ba8 2007-09-14 drh: ** either. Hence, this routine never reports that the library c287665ba8 2007-09-14 drh: ** is guaranteed to be threadsafe, only when it is guaranteed not c287665ba8 2007-09-14 drh: ** to be. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This is an experimental API and may go away or change in future c287665ba8 2007-09-14 drh: ** releases. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_threadsafe(void); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Database Connection Handle dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each open SQLite database is represented by pointer to an instance of the dbda8d6ce9 2007-07-21 drh: ** opaque structure named "sqlite3". It is useful to think of an sqlite3 c287665ba8 2007-09-14 drh: ** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and c287665ba8 2007-09-14 drh: ** [sqlite3_open_v2()] interfaces are its constructors c287665ba8 2007-09-14 drh: ** and [sqlite3_close()] is its destructor. There are many other interfaces c287665ba8 2007-09-14 drh: ** (such as [sqlite3_prepare_v2()], [sqlite3_create_function()], and c287665ba8 2007-09-14 drh: ** [sqlite3_busy_timeout()] to name but three) that are methods on this dbda8d6ce9 2007-07-21 drh: ** object. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3 sqlite3; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: 64-Bit Integer Types dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Some compilers do not support the "long long" datatype. So we have dbda8d6ce9 2007-07-21 drh: ** to do compiler-specific typedefs for 64-bit signed and unsigned integers. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Many SQLite interface functions require a 64-bit integer arguments. dbda8d6ce9 2007-07-21 drh: ** Those interfaces are declared using this typedef. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_INT64_TYPE dbda8d6ce9 2007-07-21 drh: typedef SQLITE_INT64_TYPE sqlite_int64; dbda8d6ce9 2007-07-21 drh: typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; dbda8d6ce9 2007-07-21 drh: #elif defined(_MSC_VER) || defined(__BORLANDC__) dbda8d6ce9 2007-07-21 drh: typedef __int64 sqlite_int64; dbda8d6ce9 2007-07-21 drh: typedef unsigned __int64 sqlite_uint64; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: typedef long long int sqlite_int64; dbda8d6ce9 2007-07-21 drh: typedef unsigned long long int sqlite_uint64; dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: typedef sqlite_int64 sqlite3_int64; c287665ba8 2007-09-14 drh: typedef sqlite_uint64 sqlite3_uint64; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If compiling for a processor that lacks floating point support, dbda8d6ce9 2007-07-21 drh: ** substitute integer for floating-point dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_FLOATING_POINT c287665ba8 2007-09-14 drh: # define double sqlite3_int64 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Closing A Database Connection dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Call this function with a pointer to a structure that was previously c287665ba8 2007-09-14 drh: ** returned from [sqlite3_open()], [sqlite3_open16()], or c287665ba8 2007-09-14 drh: ** [sqlite3_open_v2()] and the corresponding database will by dbda8d6ce9 2007-07-21 drh: ** closed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All SQL statements prepared using [sqlite3_prepare_v2()] or dbda8d6ce9 2007-07-21 drh: ** [sqlite3_prepare16_v2()] must be destroyed using [sqlite3_finalize()] dbda8d6ce9 2007-07-21 drh: ** before this routine is called. Otherwise, SQLITE_BUSY is returned and the dbda8d6ce9 2007-07-21 drh: ** database connection remains open. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Passing this routine a database connection that has already been c287665ba8 2007-09-14 drh: ** closed results in undefined behavior. If other interfaces that c287665ba8 2007-09-14 drh: ** reference the same database connection are pending (either in the c287665ba8 2007-09-14 drh: ** same thread or in different threads) when this routine is called, c287665ba8 2007-09-14 drh: ** then the behavior is undefined and is almost certainly undesirable. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_close(sqlite3 *); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The type for a callback function. dbda8d6ce9 2007-07-21 drh: ** This is legacy and deprecated. It is included for historical dbda8d6ce9 2007-07-21 drh: ** compatibility and is not documented. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef int (*sqlite3_callback)(void*,int,char**, char**); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: One-Step Query Execution Interface dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This interface is used to do a one-time evaluatation of zero dbda8d6ce9 2007-07-21 drh: ** or more SQL statements. UTF-8 text of the SQL statements to dbda8d6ce9 2007-07-21 drh: ** be evaluted is passed in as the second parameter. The statements dbda8d6ce9 2007-07-21 drh: ** are prepared one by one using [sqlite3_prepare()], evaluated dbda8d6ce9 2007-07-21 drh: ** using [sqlite3_step()], then destroyed using [sqlite3_finalize()]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If one or more of the SQL statements are queries, then dbda8d6ce9 2007-07-21 drh: ** the callback function specified by the 3rd parameter is dbda8d6ce9 2007-07-21 drh: ** invoked once for each row of the query result. This callback dbda8d6ce9 2007-07-21 drh: ** should normally return 0. If the callback returns a non-zero dbda8d6ce9 2007-07-21 drh: ** value then the query is aborted, all subsequent SQL statements c287665ba8 2007-09-14 drh: ** are skipped and the sqlite3_exec() function returns the [SQLITE_ABORT]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The 4th parameter to this interface is an arbitrary pointer that is dbda8d6ce9 2007-07-21 drh: ** passed through to the callback function as its first parameter. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The 2nd parameter to the callback function is the number of dbda8d6ce9 2007-07-21 drh: ** columns in the query result. The 3rd parameter to the callback dbda8d6ce9 2007-07-21 drh: ** is an array of strings holding the values for each column dbda8d6ce9 2007-07-21 drh: ** as extracted using [sqlite3_column_text()]. dbda8d6ce9 2007-07-21 drh: ** The 4th parameter to the callback is an array of strings dbda8d6ce9 2007-07-21 drh: ** obtained using [sqlite3_column_name()] and holding dbda8d6ce9 2007-07-21 drh: ** the names of each column. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The callback function may be NULL, even for queries. A NULL dbda8d6ce9 2007-07-21 drh: ** callback is not an error. It just means that no callback dbda8d6ce9 2007-07-21 drh: ** will be invoked. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an error occurs while parsing or evaluating the SQL (but dbda8d6ce9 2007-07-21 drh: ** not while executing the callback) then an appropriate error dbda8d6ce9 2007-07-21 drh: ** message is written into memory obtained from [sqlite3_malloc()] and dbda8d6ce9 2007-07-21 drh: ** *errmsg is made to point to that message. The calling function c287665ba8 2007-09-14 drh: ** is responsible for freeing the memory using [sqlite3_free()]. c287665ba8 2007-09-14 drh: ** If errmsg==NULL, then no error message is ever written. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The return value is is SQLITE_OK if there are no errors and dbda8d6ce9 2007-07-21 drh: ** some other [SQLITE_OK | return code] if there is an error. dbda8d6ce9 2007-07-21 drh: ** The particular return value depends on the type of error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_exec( dbda8d6ce9 2007-07-21 drh: sqlite3*, /* An open database */ dbda8d6ce9 2007-07-21 drh: const char *sql, /* SQL to be evaluted */ dbda8d6ce9 2007-07-21 drh: int (*callback)(void*,int,char**,char**), /* Callback function */ dbda8d6ce9 2007-07-21 drh: void *, /* 1st argument to callback */ dbda8d6ce9 2007-07-21 drh: char **errmsg /* Error msg written here */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Result Codes dbda8d6ce9 2007-07-21 drh: ** KEYWORDS: SQLITE_OK dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Many SQLite functions return an integer result code from the set shown dbda8d6ce9 2007-07-21 drh: ** above in order to indicates success or failure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The result codes above are the only ones returned by SQLite in its dbda8d6ce9 2007-07-21 drh: ** default configuration. However, the [sqlite3_extended_result_codes()] dbda8d6ce9 2007-07-21 drh: ** API can be used to set a database connectoin to return more detailed dbda8d6ce9 2007-07-21 drh: ** result codes. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: [SQLITE_IOERR_READ | extended result codes] dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_OK 0 /* Successful result */ dbda8d6ce9 2007-07-21 drh: /* beginning-of-error-codes */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ERROR 1 /* SQL error or missing database */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_INTERNAL 2 /* NOT USED. Internal logic error in SQLite */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_PERM 3 /* Access permission denied */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ABORT 4 /* Callback routine requested an abort */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_BUSY 5 /* The database file is locked */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_LOCKED 6 /* A table in the database is locked */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_NOMEM 7 /* A malloc() failed */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_READONLY 8 /* Attempt to write a readonly database */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CORRUPT 11 /* The database disk image is malformed */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_FULL 13 /* Insertion failed because database is full */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_EMPTY 16 /* Database is empty */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_SCHEMA 17 /* The database schema changed */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_MISMATCH 20 /* Data type mismatch */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_MISUSE 21 /* Library used incorrectly */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_AUTH 23 /* Authorization denied */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_FORMAT 24 /* Auxiliary database format error */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_NOTADB 26 /* File opened that is not a database file */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ dbda8d6ce9 2007-07-21 drh: /* end-of-error-codes */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Extended Result Codes dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In its default configuration, SQLite API routines return one of 26 integer dbda8d6ce9 2007-07-21 drh: ** result codes described at result-codes. However, experience has shown that dbda8d6ce9 2007-07-21 drh: ** many of these result codes are too course-grained. They do not provide as dbda8d6ce9 2007-07-21 drh: ** much information about problems as users might like. In an effort to dbda8d6ce9 2007-07-21 drh: ** address this, newer versions of SQLite (version 3.3.8 and later) include dbda8d6ce9 2007-07-21 drh: ** support for additional result codes that provide more detailed information dbda8d6ce9 2007-07-21 drh: ** about errors. The extended result codes are enabled (or disabled) for dbda8d6ce9 2007-07-21 drh: ** each database dbda8d6ce9 2007-07-21 drh: ** connection using the [sqlite3_extended_result_codes()] API. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Some of the available extended result codes are listed above. dbda8d6ce9 2007-07-21 drh: ** We expect the number of extended result codes will be expand dbda8d6ce9 2007-07-21 drh: ** over time. Software that uses extended result codes should expect dbda8d6ce9 2007-07-21 drh: ** to see new result codes in future releases of SQLite. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The symbolic name for an extended result code always contains a related dbda8d6ce9 2007-07-21 drh: ** primary result code as a prefix. Primary result codes contain a single dbda8d6ce9 2007-07-21 drh: ** "_" character. Extended result codes contain two or more "_" characters. dbda8d6ce9 2007-07-21 drh: ** The numeric value of an extended result code can be converted to its dbda8d6ce9 2007-07-21 drh: ** corresponding primary result code by masking off the lower 8 bytes. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The SQLITE_OK result code will never be extended. It will always dbda8d6ce9 2007-07-21 drh: ** be exactly zero. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) dbda8d6ce9 2007-07-21 drh: #define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Flags For File Open Operations c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Combination of the following bit values are used as the c287665ba8 2007-09-14 drh: ** third argument to the [sqlite3_open_v2()] interface and c287665ba8 2007-09-14 drh: ** as fourth argument to the xOpen method of the c287665ba8 2007-09-14 drh: ** [sqlite3_vfs] object. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_READONLY 0x00000001 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_READWRITE 0x00000002 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_CREATE 0x00000004 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_EXCLUSIVE 0x00000010 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_MAIN_DB 0x00000100 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_TEMP_DB 0x00000200 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_SUBJOURNAL 0x00002000 c287665ba8 2007-09-14 drh: #define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Device Characteristics c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The xDeviceCapabilities method of the [sqlite3_io_methods] c287665ba8 2007-09-14 drh: ** object returns an integer which is a vector of the following c287665ba8 2007-09-14 drh: ** bit values expressing I/O characteristics of the mass storage c287665ba8 2007-09-14 drh: ** device that holds the file that the [sqlite3_io_methods] c287665ba8 2007-09-14 drh: ** refers to. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The SQLITE_IOCAP_ATOMIC property means that all writes of c287665ba8 2007-09-14 drh: ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values c287665ba8 2007-09-14 drh: ** mean that writes of blocks that are nnn bytes in size and c287665ba8 2007-09-14 drh: ** are aligned to an address which is an integer multiple of c287665ba8 2007-09-14 drh: ** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means c287665ba8 2007-09-14 drh: ** that when data is appended to a file, the data is appended c287665ba8 2007-09-14 drh: ** first then the size of the file is extended, never the other c287665ba8 2007-09-14 drh: ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that c287665ba8 2007-09-14 drh: ** information is written to disk in the same order as calls c287665ba8 2007-09-14 drh: ** to xWrite(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC 0x00000001 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC512 0x00000002 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC1K 0x00000004 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC2K 0x00000008 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC4K 0x00000010 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC8K 0x00000020 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC16K 0x00000040 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC32K 0x00000080 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_ATOMIC64K 0x00000100 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_SAFE_APPEND 0x00000200 c287665ba8 2007-09-14 drh: #define SQLITE_IOCAP_SEQUENTIAL 0x00000400 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: File Locking Levels c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLite uses one of the following integer values as the second c287665ba8 2007-09-14 drh: ** argument to calls it makes to the xLock() and xUnlock() methods c287665ba8 2007-09-14 drh: ** of an [sqlite3_io_methods] object. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_LOCK_NONE 0 c287665ba8 2007-09-14 drh: #define SQLITE_LOCK_SHARED 1 c287665ba8 2007-09-14 drh: #define SQLITE_LOCK_RESERVED 2 c287665ba8 2007-09-14 drh: #define SQLITE_LOCK_PENDING 3 c287665ba8 2007-09-14 drh: #define SQLITE_LOCK_EXCLUSIVE 4 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Synchronization Type Flags c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** When SQLite invokes the xSync() method of an [sqlite3_io_methods] c287665ba8 2007-09-14 drh: ** object it uses a combination of the following integer values as c287665ba8 2007-09-14 drh: ** the second argument. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** When the SQLITE_SYNC_DATAONLY flag is used, it means that the c287665ba8 2007-09-14 drh: ** sync operation only needs to flush data to mass storage. Inode c287665ba8 2007-09-14 drh: ** information need not be flushed. The SQLITE_SYNC_NORMAL means c287665ba8 2007-09-14 drh: ** to use normal fsync() semantics. The SQLITE_SYNC_FULL flag means c287665ba8 2007-09-14 drh: ** to use Mac OS-X style fullsync instead of fsync(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_SYNC_NORMAL 0x00002 c287665ba8 2007-09-14 drh: #define SQLITE_SYNC_FULL 0x00003 c287665ba8 2007-09-14 drh: #define SQLITE_SYNC_DATAONLY 0x00010 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: OS Interface Open File Handle c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** An [sqlite3_file] object represents an open file in the OS c287665ba8 2007-09-14 drh: ** interface layer. Individual OS interface implementations will c287665ba8 2007-09-14 drh: ** want to subclass this object by appending additional fields c287665ba8 2007-09-14 drh: ** for their own use. The pMethods entry is a pointer to an c287665ba8 2007-09-14 drh: ** [sqlite3_io_methods] object that defines methods for performing c287665ba8 2007-09-14 drh: ** I/O operations on the open file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: typedef struct sqlite3_file sqlite3_file; c287665ba8 2007-09-14 drh: struct sqlite3_file { c287665ba8 2007-09-14 drh: const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: OS Interface File Virtual Methods Object c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Every file opened by the [sqlite3_vfs] xOpen method contains a pointer to c287665ba8 2007-09-14 drh: ** an instance of the this object. This object defines the c287665ba8 2007-09-14 drh: ** methods used to perform various operations against the open file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or c287665ba8 2007-09-14 drh: ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). c287665ba8 2007-09-14 drh: * The second choice is an c287665ba8 2007-09-14 drh: ** OS-X style fullsync. The SQLITE_SYNC_DATA flag may be ORed in to c287665ba8 2007-09-14 drh: ** indicate that only the data of the file and not its inode needs to be c287665ba8 2007-09-14 drh: ** synced. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The integer values to xLock() and xUnlock() are one of c287665ba8 2007-09-14 drh: ** <ul> c287665ba8 2007-09-14 drh: ** <li> [SQLITE_LOCK_NONE], c287665ba8 2007-09-14 drh: ** <li> [SQLITE_LOCK_SHARED], c287665ba8 2007-09-14 drh: ** <li> [SQLITE_LOCK_RESERVED], c287665ba8 2007-09-14 drh: ** <li> [SQLITE_LOCK_PENDING], or c287665ba8 2007-09-14 drh: ** <li> [SQLITE_LOCK_EXCLUSIVE]. c287665ba8 2007-09-14 drh: ** </ul> c287665ba8 2007-09-14 drh: ** xLock() increases the lock. xUnlock() decreases the lock. c287665ba8 2007-09-14 drh: ** The xCheckReservedLock() method looks c287665ba8 2007-09-14 drh: ** to see if any database connection, either in this c287665ba8 2007-09-14 drh: ** process or in some other process, is holding an RESERVED, c287665ba8 2007-09-14 drh: ** PENDING, or EXCLUSIVE lock on the file. It returns true c287665ba8 2007-09-14 drh: ** if such a lock exists and false if not. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The xFileControl() method is a generic interface that allows custom c287665ba8 2007-09-14 drh: ** VFS implementations to directly control an open file using the c287665ba8 2007-09-14 drh: ** [sqlite3_file_control()] interface. The second "op" argument c287665ba8 2007-09-14 drh: ** is an integer opcode. The third c287665ba8 2007-09-14 drh: ** argument is a generic pointer which is intended to be a pointer c287665ba8 2007-09-14 drh: ** to a structure that may contain arguments or space in which to c287665ba8 2007-09-14 drh: ** write return values. Potential uses for xFileControl() might be c287665ba8 2007-09-14 drh: ** functions to enable blocking locks with timeouts, to change the c287665ba8 2007-09-14 drh: ** locking strategy (for example to use dot-file locks), to inquire c287665ba8 2007-09-14 drh: ** about the status of a lock, or to break stale locks. The SQLite c287665ba8 2007-09-14 drh: ** core reserves opcodes less than 100 for its own use. c287665ba8 2007-09-14 drh: ** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available. c287665ba8 2007-09-14 drh: ** Applications that define a custom xFileControl method should use opcodes c287665ba8 2007-09-14 drh: ** greater than 100 to avoid conflicts. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The xSectorSize() method returns the sector size of the c287665ba8 2007-09-14 drh: ** device that underlies the file. The sector size is the c287665ba8 2007-09-14 drh: ** minimum write that can be performed without disturbing c287665ba8 2007-09-14 drh: ** other bytes in the file. The xDeviceCharacteristics() c287665ba8 2007-09-14 drh: ** method returns a bit vector describing behaviors of the c287665ba8 2007-09-14 drh: ** underlying device: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <ul> c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC512] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC1K] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC2K] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC4K] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC8K] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC16K] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC32K] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_ATOMIC64K] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_SAFE_APPEND] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_IOCAP_SEQUENTIAL] c287665ba8 2007-09-14 drh: ** </ul> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The SQLITE_IOCAP_ATOMIC property means that all writes of c287665ba8 2007-09-14 drh: ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values c287665ba8 2007-09-14 drh: ** mean that writes of blocks that are nnn bytes in size and c287665ba8 2007-09-14 drh: ** are aligned to an address which is an integer multiple of c287665ba8 2007-09-14 drh: ** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means c287665ba8 2007-09-14 drh: ** that when data is appended to a file, the data is appended c287665ba8 2007-09-14 drh: ** first then the size of the file is extended, never the other c287665ba8 2007-09-14 drh: ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that c287665ba8 2007-09-14 drh: ** information is written to disk in the same order as calls c287665ba8 2007-09-14 drh: ** to xWrite(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: typedef struct sqlite3_io_methods sqlite3_io_methods; c287665ba8 2007-09-14 drh: struct sqlite3_io_methods { c287665ba8 2007-09-14 drh: int iVersion; c287665ba8 2007-09-14 drh: int (*xClose)(sqlite3_file*); c287665ba8 2007-09-14 drh: int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); c287665ba8 2007-09-14 drh: int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); c287665ba8 2007-09-14 drh: int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); c287665ba8 2007-09-14 drh: int (*xSync)(sqlite3_file*, int flags); c287665ba8 2007-09-14 drh: int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); c287665ba8 2007-09-14 drh: int (*xLock)(sqlite3_file*, int); c287665ba8 2007-09-14 drh: int (*xUnlock)(sqlite3_file*, int); c287665ba8 2007-09-14 drh: int (*xCheckReservedLock)(sqlite3_file*); c287665ba8 2007-09-14 drh: int (*xFileControl)(sqlite3_file*, int op, void *pArg); c287665ba8 2007-09-14 drh: int (*xSectorSize)(sqlite3_file*); c287665ba8 2007-09-14 drh: int (*xDeviceCharacteristics)(sqlite3_file*); c287665ba8 2007-09-14 drh: /* Additional methods may be added in future releases */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Standard File Control Opcodes c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** These integer constants are opcodes for the xFileControl method c287665ba8 2007-09-14 drh: ** of the [sqlite3_io_methods] object and to the [sqlite3_file_control()] c287665ba8 2007-09-14 drh: ** interface. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This c287665ba8 2007-09-14 drh: ** opcode cases the xFileControl method to write the current state of c287665ba8 2007-09-14 drh: ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], c287665ba8 2007-09-14 drh: ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) c287665ba8 2007-09-14 drh: ** into an integer that the pArg argument points to. This capability c287665ba8 2007-09-14 drh: ** is used during testing and only needs to be supported when SQLITE_TEST c287665ba8 2007-09-14 drh: ** is defined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_FCNTL_LOCKSTATE 1 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Mutex Handle c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The mutex module within SQLite defines [sqlite3_mutex] to be an c287665ba8 2007-09-14 drh: ** abstract type for a mutex object. The SQLite core never looks c287665ba8 2007-09-14 drh: ** at the internal representation of an [sqlite3_mutex]. It only c287665ba8 2007-09-14 drh: ** deals with pointers to the [sqlite3_mutex] object. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Mutexes are created using [sqlite3_mutex_alloc()]. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: typedef struct sqlite3_mutex sqlite3_mutex; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: OS Interface Object c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** An instance of this object defines the interface between the c287665ba8 2007-09-14 drh: ** SQLite core and the underlying operating system. The "vfs" c287665ba8 2007-09-14 drh: ** in the name of the object stands for "virtual file system". c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The iVersion field is initially 1 but may be larger for future c287665ba8 2007-09-14 drh: ** versions of SQLite. Additional fields may be appended to this c287665ba8 2007-09-14 drh: ** object when the iVersion value is increased. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The szOsFile field is the size of the subclassed [sqlite3_file] c287665ba8 2007-09-14 drh: ** structure used by this VFS. mxPathname is the maximum length of c287665ba8 2007-09-14 drh: ** a pathname in this VFS. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Registered vfs modules are kept on a linked list formed by c287665ba8 2007-09-14 drh: ** the pNext pointer. The [sqlite3_vfs_register()] c287665ba8 2007-09-14 drh: ** and [sqlite3_vfs_unregister()] interfaces manage this list c287665ba8 2007-09-14 drh: ** in a thread-safe way. The [sqlite3_vfs_find()] interface c287665ba8 2007-09-14 drh: ** searches the list. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The pNext field is the only fields in the sqlite3_vfs c287665ba8 2007-09-14 drh: ** structure that SQLite will ever modify. SQLite will only access c287665ba8 2007-09-14 drh: ** or modify this field while holding a particular static mutex. c287665ba8 2007-09-14 drh: ** The application should never modify anything within the sqlite3_vfs c287665ba8 2007-09-14 drh: ** object once the object has been registered. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The zName field holds the name of the VFS module. The name must c287665ba8 2007-09-14 drh: ** be unique across all VFS modules. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLite will guarantee that the zFilename string passed to c287665ba8 2007-09-14 drh: ** xOpen() is a full pathname as generated by xFullPathname() and c287665ba8 2007-09-14 drh: ** that the string will be valid and unchanged until xClose() is c287665ba8 2007-09-14 drh: ** called. So the [sqlite3_file] can store a pointer to the c287665ba8 2007-09-14 drh: ** filename if it needs to remember the filename for some reason. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The flags argument to xOpen() is a copy of the flags argument c287665ba8 2007-09-14 drh: ** to [sqlite3_open_v2()]. If [sqlite3_open()] or [sqlite3_open16()] c287665ba8 2007-09-14 drh: ** is used, then flags is [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. c287665ba8 2007-09-14 drh: ** If xOpen() opens a file read-only then it sets *pOutFlags to c287665ba8 2007-09-14 drh: ** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be c287665ba8 2007-09-14 drh: ** set. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLite will also add one of the following flags to the xOpen() c287665ba8 2007-09-14 drh: ** call, depending on the object being opened: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <ul> c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_MAIN_DB] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_MAIN_JOURNAL] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_TEMP_DB] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_TEMP_JOURNAL] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_TRANSIENT_DB] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_SUBJOURNAL] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_MASTER_JOURNAL] c287665ba8 2007-09-14 drh: ** </ul> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The file I/O implementation can use the object type flags to c287665ba8 2007-09-14 drh: ** changes the way it deals with files. For example, an application c287665ba8 2007-09-14 drh: ** that does not care about crash recovery or rollback, might make c287665ba8 2007-09-14 drh: ** the open of a journal file a no-op. Writes to this journal are c287665ba8 2007-09-14 drh: ** also a no-op. Any attempt to read the journal return SQLITE_IOERR. c287665ba8 2007-09-14 drh: ** Or the implementation might recognize the a database file will c287665ba8 2007-09-14 drh: ** be doing page-aligned sector reads and writes in a random order c287665ba8 2007-09-14 drh: ** and set up its I/O subsystem accordingly. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLite might also add one of the following flags to the xOpen c287665ba8 2007-09-14 drh: ** method: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <ul> c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_DELETEONCLOSE] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_EXCLUSIVE] c287665ba8 2007-09-14 drh: ** </ul> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be c287665ba8 2007-09-14 drh: ** deleted when it is closed. This will always be set for TEMP c287665ba8 2007-09-14 drh: ** databases and journals and for subjournals. The c287665ba8 2007-09-14 drh: ** [SQLITE_OPEN_EXCLUSIVE] flag means the file should be opened c287665ba8 2007-09-14 drh: ** for exclusive access. This flag is set for all files except c287665ba8 2007-09-14 drh: ** for the main database file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Space to hold the [sqlite3_file] structure passed as the third c287665ba8 2007-09-14 drh: ** argument to xOpen is allocated by caller (the SQLite core). c287665ba8 2007-09-14 drh: ** szOsFile bytes are allocated for this object. The xOpen method c287665ba8 2007-09-14 drh: ** fills in the allocated space. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] c287665ba8 2007-09-14 drh: ** to test for the existance of a file, c287665ba8 2007-09-14 drh: ** or [SQLITE_ACCESS_READWRITE] to test to see c287665ba8 2007-09-14 drh: ** if a file is readable and writable, or [SQLITE_ACCESS_READ] c287665ba8 2007-09-14 drh: ** to test to see if a file is at least readable. The file can be a c287665ba8 2007-09-14 drh: ** directory. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLite will always allocate at least mxPathname+1 byte for c287665ba8 2007-09-14 drh: ** the output buffers for xGetTempName and xFullPathname. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The xRandomness(), xSleep(), and xCurrentTime() interfaces c287665ba8 2007-09-14 drh: ** are not strictly a part of the filesystem, but they are c287665ba8 2007-09-14 drh: ** included in the VFS structure for completeness. c287665ba8 2007-09-14 drh: ** The xRandomness() function attempts to return nBytes bytes c287665ba8 2007-09-14 drh: ** of good-quality randomness into zOut. The return value is c287665ba8 2007-09-14 drh: ** the actual number of bytes of randomness obtained. The c287665ba8 2007-09-14 drh: ** xSleep() method cause the calling thread to sleep for at c287665ba8 2007-09-14 drh: ** least the number of microseconds given. The xCurrentTime() c287665ba8 2007-09-14 drh: ** method returns a Julian Day Number for the current date and c287665ba8 2007-09-14 drh: ** time. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: typedef struct sqlite3_vfs sqlite3_vfs; c287665ba8 2007-09-14 drh: struct sqlite3_vfs { c287665ba8 2007-09-14 drh: int iVersion; /* Structure version number */ c287665ba8 2007-09-14 drh: int szOsFile; /* Size of subclassed sqlite3_file */ c287665ba8 2007-09-14 drh: int mxPathname; /* Maximum file pathname length */ c287665ba8 2007-09-14 drh: sqlite3_vfs *pNext; /* Next registered VFS */ c287665ba8 2007-09-14 drh: const char *zName; /* Name of this virtual file system */ c287665ba8 2007-09-14 drh: void *pAppData; /* Pointer to application-specific data */ c287665ba8 2007-09-14 drh: int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, c287665ba8 2007-09-14 drh: int flags, int *pOutFlags); c287665ba8 2007-09-14 drh: int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); c287665ba8 2007-09-14 drh: int (*xAccess)(sqlite3_vfs*, const char *zName, int flags); c287665ba8 2007-09-14 drh: int (*xGetTempName)(sqlite3_vfs*, char *zOut); c287665ba8 2007-09-14 drh: int (*xFullPathname)(sqlite3_vfs*, const char *zName, char *zOut); c287665ba8 2007-09-14 drh: void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); c287665ba8 2007-09-14 drh: void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); c287665ba8 2007-09-14 drh: void *(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol); c287665ba8 2007-09-14 drh: void (*xDlClose)(sqlite3_vfs*, void*); c287665ba8 2007-09-14 drh: int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); c287665ba8 2007-09-14 drh: int (*xSleep)(sqlite3_vfs*, int microseconds); c287665ba8 2007-09-14 drh: int (*xCurrentTime)(sqlite3_vfs*, double*); c287665ba8 2007-09-14 drh: /* New fields may be appended in figure versions. The iVersion c287665ba8 2007-09-14 drh: ** value will increment whenever this happens. */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Flags for the xAccess VFS method c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** These integer constants can be used as the third parameter to c287665ba8 2007-09-14 drh: ** the xAccess method of an [sqlite3_vfs] object. They determine c287665ba8 2007-09-14 drh: ** the kind of what kind of permissions the xAccess method is c287665ba8 2007-09-14 drh: ** looking for. With SQLITE_ACCESS_EXISTS, the xAccess method c287665ba8 2007-09-14 drh: ** simply checks to see if the file exists. With SQLITE_ACCESS_READWRITE, c287665ba8 2007-09-14 drh: ** the xAccess method checks to see if the file is both readable c287665ba8 2007-09-14 drh: ** and writable. With SQLITE_ACCESS_READ the xAccess method c287665ba8 2007-09-14 drh: ** checks to see if the file is readable. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_ACCESS_EXISTS 0 c287665ba8 2007-09-14 drh: #define SQLITE_ACCESS_READWRITE 1 c287665ba8 2007-09-14 drh: #define SQLITE_ACCESS_READ 2 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Enable Or Disable Extended Result Codes dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine enables or disables the dbda8d6ce9 2007-07-21 drh: ** [SQLITE_IOERR_READ | extended result codes] feature. dbda8d6ce9 2007-07-21 drh: ** By default, SQLite API routines return one of only 26 integer dbda8d6ce9 2007-07-21 drh: ** [SQLITE_OK | result codes]. When extended result codes dbda8d6ce9 2007-07-21 drh: ** are enabled by this routine, the repetoire of result codes can be dbda8d6ce9 2007-07-21 drh: ** much larger and can (hopefully) provide more detailed information dbda8d6ce9 2007-07-21 drh: ** about the cause of an error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The second argument is a boolean value that turns extended result dbda8d6ce9 2007-07-21 drh: ** codes on and off. Extended result codes are off by default for dbda8d6ce9 2007-07-21 drh: ** backwards compatibility with older versions of SQLite. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Last Insert Rowid dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each entry in an SQLite table has a unique 64-bit signed integer key dbda8d6ce9 2007-07-21 drh: ** called the "rowid". The rowid is always available as an undeclared dbda8d6ce9 2007-07-21 drh: ** column named ROWID, OID, or _ROWID_. If the table has a column of dbda8d6ce9 2007-07-21 drh: ** type INTEGER PRIMARY KEY then that column is another an alias for the dbda8d6ce9 2007-07-21 drh: ** rowid. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns the rowid of the most recent INSERT into dbda8d6ce9 2007-07-21 drh: ** the database from the database connection given in the first dbda8d6ce9 2007-07-21 drh: ** argument. If no inserts have ever occurred on this database dbda8d6ce9 2007-07-21 drh: ** connection, zero is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an INSERT occurs within a trigger, then the rowid of the dbda8d6ce9 2007-07-21 drh: ** inserted row is returned by this routine as long as the trigger dbda8d6ce9 2007-07-21 drh: ** is running. But once the trigger terminates, the value returned dbda8d6ce9 2007-07-21 drh: ** by this routine reverts to the last value inserted before the dbda8d6ce9 2007-07-21 drh: ** trigger fired. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If another thread does a new insert on the same database connection c287665ba8 2007-09-14 drh: ** while this routine is running and thus changes the last insert rowid, c287665ba8 2007-09-14 drh: ** then the return value of this routine is undefined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Count The Number Of Rows Modified dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function returns the number of database rows that were changed dbda8d6ce9 2007-07-21 drh: ** (or inserted or deleted) by the most recent SQL statement. Only dbda8d6ce9 2007-07-21 drh: ** changes that are directly specified by the INSERT, UPDATE, or dbda8d6ce9 2007-07-21 drh: ** DELETE statement are counted. Auxiliary changes caused by dbda8d6ce9 2007-07-21 drh: ** triggers are not counted. Use the [sqlite3_total_changes()] function dbda8d6ce9 2007-07-21 drh: ** to find the total number of changes including changes caused by triggers. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Within the body of a trigger, the sqlite3_changes() interface can be dbda8d6ce9 2007-07-21 drh: ** called to find the number of dbda8d6ce9 2007-07-21 drh: ** changes in the most recently completed INSERT, UPDATE, or DELETE dbda8d6ce9 2007-07-21 drh: ** statement within the body of the trigger. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All changes are counted, even if they were later undone by a dbda8d6ce9 2007-07-21 drh: ** ROLLBACK or ABORT. Except, changes associated with creating and dbda8d6ce9 2007-07-21 drh: ** dropping tables are not counted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If a callback invokes [sqlite3_exec()] or [sqlite3_step()] recursively, dbda8d6ce9 2007-07-21 drh: ** then the changes in the inner, recursive call are counted together dbda8d6ce9 2007-07-21 drh: ** with the changes in the outer call. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite implements the command "DELETE FROM table" without a WHERE clause dbda8d6ce9 2007-07-21 drh: ** by dropping and recreating the table. (This is much faster than going dbda8d6ce9 2007-07-21 drh: ** through and deleting individual elements from the table.) Because of dbda8d6ce9 2007-07-21 drh: ** this optimization, the change count for "DELETE FROM table" will be dbda8d6ce9 2007-07-21 drh: ** zero regardless of the number of elements that were originally in the dbda8d6ce9 2007-07-21 drh: ** table. To get an accurate count of the number of rows deleted, use dbda8d6ce9 2007-07-21 drh: ** "DELETE FROM table WHERE 1" instead. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If another thread makes changes on the same database connection c287665ba8 2007-09-14 drh: ** while this routine is running then the return value of this routine c287665ba8 2007-09-14 drh: ** is undefined. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_changes(sqlite3*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Total Number Of Rows Modified dbda8d6ce9 2007-07-21 drh: *** dbda8d6ce9 2007-07-21 drh: ** This function returns the number of database rows that have been dbda8d6ce9 2007-07-21 drh: ** modified by INSERT, UPDATE or DELETE statements since the database handle dbda8d6ce9 2007-07-21 drh: ** was opened. This includes UPDATE, INSERT and DELETE statements executed dbda8d6ce9 2007-07-21 drh: ** as part of trigger programs. All changes are counted as soon as the dbda8d6ce9 2007-07-21 drh: ** statement that makes them is completed (when the statement handle is c287665ba8 2007-09-14 drh: ** passed to [sqlite3_reset()] or [sqlite3_finalize()]). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also the [sqlite3_change()] interface. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite implements the command "DELETE FROM table" without a WHERE clause dbda8d6ce9 2007-07-21 drh: ** by dropping and recreating the table. (This is much faster than going dbda8d6ce9 2007-07-21 drh: ** through and deleting individual elements form the table.) Because of dbda8d6ce9 2007-07-21 drh: ** this optimization, the change count for "DELETE FROM table" will be dbda8d6ce9 2007-07-21 drh: ** zero regardless of the number of elements that were originally in the dbda8d6ce9 2007-07-21 drh: ** table. To get an accurate count of the number of rows deleted, use dbda8d6ce9 2007-07-21 drh: ** "DELETE FROM table WHERE 1" instead. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If another thread makes changes on the same database connection c287665ba8 2007-09-14 drh: ** while this routine is running then the return value of this routine c287665ba8 2007-09-14 drh: ** is undefined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_total_changes(sqlite3*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Interrupt A Long-Running Query dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function causes any pending database operation to abort and dbda8d6ce9 2007-07-21 drh: ** return at its earliest opportunity. This routine is typically dbda8d6ce9 2007-07-21 drh: ** called in response to a user action such as pressing "Cancel" dbda8d6ce9 2007-07-21 drh: ** or Ctrl-C where the user wants a long query operation to halt dbda8d6ce9 2007-07-21 drh: ** immediately. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is safe to call this routine from a thread different from the c287665ba8 2007-09-14 drh: ** thread that is currently running the database operation. But it c287665ba8 2007-09-14 drh: ** is not safe to call this routine with a database connection that c287665ba8 2007-09-14 drh: ** is closed or might close before sqlite3_interrupt() returns. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The SQL operation that is interrupted will return [SQLITE_INTERRUPT]. dbda8d6ce9 2007-07-21 drh: ** If an interrupted operation was an update that is inside an dbda8d6ce9 2007-07-21 drh: ** explicit transaction, then the entire transaction will be rolled dbda8d6ce9 2007-07-21 drh: ** back automatically. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API void sqlite3_interrupt(sqlite3*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Determine If An SQL Statement Is Complete dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These functions return true if the given input string comprises dbda8d6ce9 2007-07-21 drh: ** one or more complete SQL statements. For the sqlite3_complete() call, dbda8d6ce9 2007-07-21 drh: ** the parameter must be a nul-terminated UTF-8 string. For dbda8d6ce9 2007-07-21 drh: ** sqlite3_complete16(), a nul-terminated machine byte order UTF-16 string dbda8d6ce9 2007-07-21 drh: ** is required. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines are useful for command-line input to determine if the dbda8d6ce9 2007-07-21 drh: ** currently entered text forms one or more complete SQL statements or dbda8d6ce9 2007-07-21 drh: ** if additional input is needed before sending the statements into dbda8d6ce9 2007-07-21 drh: ** SQLite for parsing. The algorithm is simple. If the dbda8d6ce9 2007-07-21 drh: ** last token other than spaces and comments is a semicolon, then return dbda8d6ce9 2007-07-21 drh: ** true. Actually, the algorithm is a little more complicated than that dbda8d6ce9 2007-07-21 drh: ** in order to deal with triggers, but the basic idea is the same: the dbda8d6ce9 2007-07-21 drh: ** statement is not complete unless it ends in a semicolon. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_complete(const char *sql); dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_complete16(const void *sql); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine identifies a callback function that might be invoked dbda8d6ce9 2007-07-21 drh: ** whenever an attempt is made to open a database table dbda8d6ce9 2007-07-21 drh: ** that another thread or process has locked. dbda8d6ce9 2007-07-21 drh: ** If the busy callback is NULL, then [SQLITE_BUSY] dbda8d6ce9 2007-07-21 drh: ** (or sometimes [SQLITE_IOERR_BLOCKED]) dbda8d6ce9 2007-07-21 drh: ** is returned immediately upon encountering the lock. dbda8d6ce9 2007-07-21 drh: ** If the busy callback is not NULL, then the dbda8d6ce9 2007-07-21 drh: ** callback will be invoked with two arguments. The dbda8d6ce9 2007-07-21 drh: ** first argument to the handler is a copy of the void* pointer which dbda8d6ce9 2007-07-21 drh: ** is the third argument to this routine. The second argument to dbda8d6ce9 2007-07-21 drh: ** the handler is the number of times that the busy handler has dbda8d6ce9 2007-07-21 drh: ** been invoked for this locking event. If the dbda8d6ce9 2007-07-21 drh: ** busy callback returns 0, then no additional attempts are made to dbda8d6ce9 2007-07-21 drh: ** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned. dbda8d6ce9 2007-07-21 drh: ** If the callback returns non-zero, then another attempt is made to open the dbda8d6ce9 2007-07-21 drh: ** database for reading and the cycle repeats. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The presence of a busy handler does not guarantee that dbda8d6ce9 2007-07-21 drh: ** it will be invoked when there is lock contention. dbda8d6ce9 2007-07-21 drh: ** If SQLite determines that invoking the busy handler could result in dbda8d6ce9 2007-07-21 drh: ** a deadlock, it will return [SQLITE_BUSY] instead. dbda8d6ce9 2007-07-21 drh: ** Consider a scenario where one process is holding a read lock that dbda8d6ce9 2007-07-21 drh: ** it is trying to promote to a reserved lock and dbda8d6ce9 2007-07-21 drh: ** a second process is holding a reserved lock that it is trying dbda8d6ce9 2007-07-21 drh: ** to promote to an exclusive lock. The first process cannot proceed dbda8d6ce9 2007-07-21 drh: ** because it is blocked by the second and the second process cannot dbda8d6ce9 2007-07-21 drh: ** proceed because it is blocked by the first. If both processes dbda8d6ce9 2007-07-21 drh: ** invoke the busy handlers, neither will make any progress. Therefore, dbda8d6ce9 2007-07-21 drh: ** SQLite returns [SQLITE_BUSY] for the first process, hoping that this dbda8d6ce9 2007-07-21 drh: ** will induce the first process to release its read lock and allow dbda8d6ce9 2007-07-21 drh: ** the second process to proceed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The default busy callback is NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED] when dbda8d6ce9 2007-07-21 drh: ** SQLite is in the middle of a large transaction where all the dbda8d6ce9 2007-07-21 drh: ** changes will not fit into the in-memory cache. SQLite will dbda8d6ce9 2007-07-21 drh: ** already hold a RESERVED lock on the database file, but it needs dbda8d6ce9 2007-07-21 drh: ** to promote this lock to EXCLUSIVE so that it can spill cache dbda8d6ce9 2007-07-21 drh: ** pages into the database file without harm to concurrent dbda8d6ce9 2007-07-21 drh: ** readers. If it is unable to promote the lock, then the in-memory dbda8d6ce9 2007-07-21 drh: ** cache will be left in an inconsistent state and so the error dbda8d6ce9 2007-07-21 drh: ** code is promoted from the relatively benign [SQLITE_BUSY] to dbda8d6ce9 2007-07-21 drh: ** the more severe [SQLITE_IOERR_BLOCKED]. This error code promotion dbda8d6ce9 2007-07-21 drh: ** forces an automatic rollback of the changes. See the dbda8d6ce9 2007-07-21 drh: ** <a href="http://www.sqlite.org/cvstrac/wiki?p=CorruptionFollowingBusyError"> dbda8d6ce9 2007-07-21 drh: ** CorruptionFollowingBusyError</a> wiki page for a discussion of why dbda8d6ce9 2007-07-21 drh: ** this is important. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Sqlite is re-entrant, so the busy handler may start a new query. dbda8d6ce9 2007-07-21 drh: ** (It is not clear why anyone would every want to do this, but it dbda8d6ce9 2007-07-21 drh: ** is allowed, in theory.) But the busy handler may not close the dbda8d6ce9 2007-07-21 drh: ** database. Closing the database from a busy handler will delete dbda8d6ce9 2007-07-21 drh: ** data structures out from under the executing query and will dbda8d6ce9 2007-07-21 drh: ** probably result in a segmentation fault or other runtime error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There can only be a single busy handler defined for each database dbda8d6ce9 2007-07-21 drh: ** connection. Setting a new busy handler clears any previous one. dbda8d6ce9 2007-07-21 drh: ** Note that calling [sqlite3_busy_timeout()] will also set or clear dbda8d6ce9 2007-07-21 drh: ** the busy handler. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** When operating in [sqlite3_enable_shared_cache | shared cache mode], c287665ba8 2007-09-14 drh: ** only a single busy handler can be defined for each database file. c287665ba8 2007-09-14 drh: ** So if two database connections share a single cache, then changing c287665ba8 2007-09-14 drh: ** the busy handler on one connection will also change the busy c287665ba8 2007-09-14 drh: ** handler in the other connection. The busy handler is invoked c287665ba8 2007-09-14 drh: ** in the thread that was running when the SQLITE_BUSY was hit. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Set A Busy Timeout dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine sets a busy handler that sleeps for a while when a dbda8d6ce9 2007-07-21 drh: ** table is locked. The handler will sleep multiple times until dbda8d6ce9 2007-07-21 drh: ** at least "ms" milliseconds of sleeping have been done. After dbda8d6ce9 2007-07-21 drh: ** "ms" milliseconds of sleeping, the handler returns 0 which dbda8d6ce9 2007-07-21 drh: ** causes [sqlite3_step()] to return [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Calling this routine with an argument less than or equal to zero dbda8d6ce9 2007-07-21 drh: ** turns off all busy handlers. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There can only be a single busy handler for a particular database dbda8d6ce9 2007-07-21 drh: ** connection. If another busy handler was defined dbda8d6ce9 2007-07-21 drh: ** (using [sqlite3_busy_handler()]) prior to calling dbda8d6ce9 2007-07-21 drh: ** this routine, that other busy handler is cleared. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Convenience Routines For Running Queries dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This next routine is a convenience wrapper around [sqlite3_exec()]. dbda8d6ce9 2007-07-21 drh: ** Instead of invoking a user-supplied callback for each row of the dbda8d6ce9 2007-07-21 drh: ** result, this routine remembers each row of the result in memory dbda8d6ce9 2007-07-21 drh: ** obtained from [sqlite3_malloc()], then returns all of the result after the dbda8d6ce9 2007-07-21 drh: ** query has finished. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** As an example, suppose the query result where this table: dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** <blockquote><pre> dbda8d6ce9 2007-07-21 drh: ** Name | Age dbda8d6ce9 2007-07-21 drh: ** ----------------------- dbda8d6ce9 2007-07-21 drh: ** Alice | 43 dbda8d6ce9 2007-07-21 drh: ** Bob | 28 dbda8d6ce9 2007-07-21 drh: ** Cindy | 21 c287665ba8 2007-09-14 drh: ** </pre></blockquote> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the 3rd argument were &azResult then after the function returns dbda8d6ce9 2007-07-21 drh: ** azResult will contain the following data: dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** <blockquote><pre> c287665ba8 2007-09-14 drh: ** azResult[0] = "Name"; c287665ba8 2007-09-14 drh: ** azResult[1] = "Age"; c287665ba8 2007-09-14 drh: ** azResult[2] = "Alice"; c287665ba8 2007-09-14 drh: ** azResult[3] = "43"; c287665ba8 2007-09-14 drh: ** azResult[4] = "Bob"; c287665ba8 2007-09-14 drh: ** azResult[5] = "28"; c287665ba8 2007-09-14 drh: ** azResult[6] = "Cindy"; c287665ba8 2007-09-14 drh: ** azResult[7] = "21"; c287665ba8 2007-09-14 drh: ** </pre></blockquote> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Notice that there is an extra row of data containing the column dbda8d6ce9 2007-07-21 drh: ** headers. But the *nrow return value is still 3. *ncolumn is dbda8d6ce9 2007-07-21 drh: ** set to 2. In general, the number of values inserted into azResult dbda8d6ce9 2007-07-21 drh: ** will be ((*nrow) + 1)*(*ncolumn). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After the calling function has finished using the result, it should dbda8d6ce9 2007-07-21 drh: ** pass the result data pointer to sqlite3_free_table() in order to dbda8d6ce9 2007-07-21 drh: ** release the memory that was malloc-ed. Because of the way the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_malloc()] happens, the calling function must not try to call dbda8d6ce9 2007-07-21 drh: ** [sqlite3_free()] directly. Only [sqlite3_free_table()] is able to release dbda8d6ce9 2007-07-21 drh: ** the memory properly and safely. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The return value of this routine is the same as from [sqlite3_exec()]. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_get_table( dbda8d6ce9 2007-07-21 drh: sqlite3*, /* An open database */ dbda8d6ce9 2007-07-21 drh: const char *sql, /* SQL to be executed */ dbda8d6ce9 2007-07-21 drh: char ***resultp, /* Result written to a char *[] that this points to */ dbda8d6ce9 2007-07-21 drh: int *nrow, /* Number of result rows written here */ dbda8d6ce9 2007-07-21 drh: int *ncolumn, /* Number of result columns written here */ dbda8d6ce9 2007-07-21 drh: char **errmsg /* Error msg written here */ dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_free_table(char **result); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Formatted String Printing Functions dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines are workalikes of the "printf()" family of functions dbda8d6ce9 2007-07-21 drh: ** from the standard C library. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_mprintf() and sqlite3_vmprintf() routines write their c287665ba8 2007-09-14 drh: ** results into memory obtained from [sqlite3_malloc()]. dbda8d6ce9 2007-07-21 drh: ** The strings returned by these two routines should be dbda8d6ce9 2007-07-21 drh: ** released by [sqlite3_free()]. Both routines return a dbda8d6ce9 2007-07-21 drh: ** NULL pointer if [sqlite3_malloc()] is unable to allocate enough dbda8d6ce9 2007-07-21 drh: ** memory to hold the resulting string. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In sqlite3_snprintf() routine is similar to "snprintf()" from dbda8d6ce9 2007-07-21 drh: ** the standard C library. The result is written into the dbda8d6ce9 2007-07-21 drh: ** buffer supplied as the second parameter whose size is given by dbda8d6ce9 2007-07-21 drh: ** the first parameter. Note that the order of the dbda8d6ce9 2007-07-21 drh: ** first two parameters is reversed from snprintf(). This is an dbda8d6ce9 2007-07-21 drh: ** historical accident that cannot be fixed without breaking dbda8d6ce9 2007-07-21 drh: ** backwards compatibility. Note also that sqlite3_snprintf() dbda8d6ce9 2007-07-21 drh: ** returns a pointer to its buffer instead of the number of dbda8d6ce9 2007-07-21 drh: ** characters actually written into the buffer. We admit that dbda8d6ce9 2007-07-21 drh: ** the number of characters written would be a more useful return dbda8d6ce9 2007-07-21 drh: ** value but we cannot change the implementation of sqlite3_snprintf() dbda8d6ce9 2007-07-21 drh: ** now without breaking compatibility. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** As long as the buffer size is greater than zero, sqlite3_snprintf() dbda8d6ce9 2007-07-21 drh: ** guarantees that the buffer is always zero-terminated. The first dbda8d6ce9 2007-07-21 drh: ** parameter "n" is the total size of the buffer, including space for dbda8d6ce9 2007-07-21 drh: ** the zero terminator. So the longest string that can be completely dbda8d6ce9 2007-07-21 drh: ** written will be n-1 characters. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines all implement some additional formatting dbda8d6ce9 2007-07-21 drh: ** options that are useful for constructing SQL statements. dbda8d6ce9 2007-07-21 drh: ** All of the usual printf formatting options apply. In addition, there c287665ba8 2007-09-14 drh: ** is are "%q", "%Q", and "%z" options. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The %q option works like %s in that it substitutes a null-terminated dbda8d6ce9 2007-07-21 drh: ** string from the argument list. But %q also doubles every '\'' character. dbda8d6ce9 2007-07-21 drh: ** %q is designed for use inside a string literal. By doubling each '\'' dbda8d6ce9 2007-07-21 drh: ** character it escapes that character and allows it to be inserted into dbda8d6ce9 2007-07-21 drh: ** the string. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For example, so some string variable contains text as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <blockquote><pre> dbda8d6ce9 2007-07-21 drh: ** char *zText = "It's a happy day!"; dbda8d6ce9 2007-07-21 drh: ** </pre></blockquote> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** One can use this text in an SQL statement as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <blockquote><pre> dbda8d6ce9 2007-07-21 drh: ** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText); dbda8d6ce9 2007-07-21 drh: ** sqlite3_exec(db, zSQL, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: ** sqlite3_free(zSQL); dbda8d6ce9 2007-07-21 drh: ** </pre></blockquote> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Because the %q format string is used, the '\'' character in zText dbda8d6ce9 2007-07-21 drh: ** is escaped and the SQL generated is as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <blockquote><pre> dbda8d6ce9 2007-07-21 drh: ** INSERT INTO table1 VALUES('It''s a happy day!') dbda8d6ce9 2007-07-21 drh: ** </pre></blockquote> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is correct. Had we used %s instead of %q, the generated SQL dbda8d6ce9 2007-07-21 drh: ** would have looked like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <blockquote><pre> dbda8d6ce9 2007-07-21 drh: ** INSERT INTO table1 VALUES('It's a happy day!'); dbda8d6ce9 2007-07-21 drh: ** </pre></blockquote> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This second example is an SQL syntax error. As a general rule you dbda8d6ce9 2007-07-21 drh: ** should always use %q instead of %s when inserting text into a string dbda8d6ce9 2007-07-21 drh: ** literal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The %Q option works like %q except it also adds single quotes around dbda8d6ce9 2007-07-21 drh: ** the outside of the total string. Or if the parameter in the argument dbda8d6ce9 2007-07-21 drh: ** list is a NULL pointer, %Q substitutes the text "NULL" (without single dbda8d6ce9 2007-07-21 drh: ** quotes) in place of the %Q option. So, for example, one could say: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <blockquote><pre> dbda8d6ce9 2007-07-21 drh: ** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText); dbda8d6ce9 2007-07-21 drh: ** sqlite3_exec(db, zSQL, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: ** sqlite3_free(zSQL); dbda8d6ce9 2007-07-21 drh: ** </pre></blockquote> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code above will render a correct SQL statement in the zSQL dbda8d6ce9 2007-07-21 drh: ** variable even if the zText variable is a NULL pointer. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The "%z" formatting option works exactly like "%s" with the c287665ba8 2007-09-14 drh: ** addition that after the string has been read and copied into c287665ba8 2007-09-14 drh: ** the result, [sqlite3_free()] is called on the input string. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API char *sqlite3_mprintf(const char*,...); dbda8d6ce9 2007-07-21 drh: SQLITE_API char *sqlite3_vmprintf(const char*, va_list); dbda8d6ce9 2007-07-21 drh: SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Memory Allocation Subsystem c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The SQLite core uses these three routines for all of its own c287665ba8 2007-09-14 drh: ** internal memory allocation needs. (See the exception below.) c287665ba8 2007-09-14 drh: ** The default implementation c287665ba8 2007-09-14 drh: ** of the memory allocation subsystem uses the malloc(), realloc() c287665ba8 2007-09-14 drh: ** and free() provided by the standard C library. However, if c287665ba8 2007-09-14 drh: ** SQLite is compiled with the following C preprocessor macro c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <blockquote> SQLITE_OMIT_MEMORY_ALLOCATION </blockquote> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** then no implementation is provided for these routines by c287665ba8 2007-09-14 drh: ** SQLite. The application that links against SQLite is c287665ba8 2007-09-14 drh: ** expected to provide its own implementation. If the application c287665ba8 2007-09-14 drh: ** does provide its own implementation for these routines, then c287665ba8 2007-09-14 drh: ** it must also provide an implementations for c287665ba8 2007-09-14 drh: ** [sqlite3_memory_alarm()], [sqlite3_memory_used()], and c287665ba8 2007-09-14 drh: ** [sqlite3_memory_highwater()]. The alternative implementations c287665ba8 2007-09-14 drh: ** for these last three routines need not actually work, but c287665ba8 2007-09-14 drh: ** stub functions at least are needed to statisfy the linker. c287665ba8 2007-09-14 drh: ** SQLite never calls [sqlite3_memory_highwater()] itself, but c287665ba8 2007-09-14 drh: ** the symbol is included in a table as part of the c287665ba8 2007-09-14 drh: ** [sqlite3_load_extension()] interface. The c287665ba8 2007-09-14 drh: ** [sqlite3_memory_alarm()] and [sqlite3_memory_used()] interfaces c287665ba8 2007-09-14 drh: ** are called by [sqlite3_soft_heap_limit()] and working implementations c287665ba8 2007-09-14 drh: ** of both routines must be provided if [sqlite3_soft_heap_limit()] c287665ba8 2007-09-14 drh: ** is to operate correctly. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <b>Exception:</b> The windows OS interface layer calls c287665ba8 2007-09-14 drh: ** the system malloc() and free() directly when converting c287665ba8 2007-09-14 drh: ** filenames between the UTF-8 encoding used by SQLite c287665ba8 2007-09-14 drh: ** and whatever filename encoding is used by the particular windows c287665ba8 2007-09-14 drh: ** installation. Memory allocation errors are detected, but c287665ba8 2007-09-14 drh: ** they are reported back as [SQLITE_CANTOPEN] or c287665ba8 2007-09-14 drh: ** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API void *sqlite3_malloc(int); dbda8d6ce9 2007-07-21 drh: SQLITE_API void *sqlite3_realloc(void*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_API void sqlite3_free(void*); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Memory Allocator Statistics c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** In addition to the basic three allocation routines c287665ba8 2007-09-14 drh: ** [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()], c287665ba8 2007-09-14 drh: ** the memory allocation subsystem included with the SQLite c287665ba8 2007-09-14 drh: ** sources provides the interfaces shown below. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The first of these two routines returns the amount of memory c287665ba8 2007-09-14 drh: ** currently outstanding (malloced but not freed). The second c287665ba8 2007-09-14 drh: ** returns the largest instantaneous amount of outstanding c287665ba8 2007-09-14 drh: ** memory. The highwater mark is reset if the argument is c287665ba8 2007-09-14 drh: ** true. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The implementation of these routines in the SQLite core c287665ba8 2007-09-14 drh: ** is omitted if the application is compiled with the c287665ba8 2007-09-14 drh: ** SQLITE_OMIT_MEMORY_ALLOCATION macro defined. In that case, c287665ba8 2007-09-14 drh: ** the application that links SQLite must provide its own c287665ba8 2007-09-14 drh: ** alternative implementation. See the documentation on c287665ba8 2007-09-14 drh: ** [sqlite3_malloc()] for additional information. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_memory_used(void); c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Memory Allocation Alarms c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The [sqlite3_memory_alarm] routine is used to register c287665ba8 2007-09-14 drh: ** a callback on memory allocation events. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine registers or clears a callbacks that fires when c287665ba8 2007-09-14 drh: ** the amount of memory allocated exceeds iThreshold. Only c287665ba8 2007-09-14 drh: ** a single callback can be registered at a time. Each call c287665ba8 2007-09-14 drh: ** to [sqlite3_memory_alarm()] overwrites the previous callback. c287665ba8 2007-09-14 drh: ** The callback is disabled by setting xCallback to a NULL c287665ba8 2007-09-14 drh: ** pointer. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The parameters to the callback are the pArg value, the c287665ba8 2007-09-14 drh: ** amount of memory currently in use, and the size of the c287665ba8 2007-09-14 drh: ** allocation that provoked the callback. The callback will c287665ba8 2007-09-14 drh: ** presumably invoke [sqlite3_free()] to free up memory space. c287665ba8 2007-09-14 drh: ** The callback may invoke [sqlite3_malloc()] or [sqlite3_realloc()] c287665ba8 2007-09-14 drh: ** but if it does, no additional callbacks will be invoked by c287665ba8 2007-09-14 drh: ** the recursive calls. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The [sqlite3_soft_heap_limit()] interface works by registering c287665ba8 2007-09-14 drh: ** a memory alarm at the soft heap limit and invoking c287665ba8 2007-09-14 drh: ** [sqlite3_release_memory()] in the alarm callback. Application c287665ba8 2007-09-14 drh: ** programs should not attempt to use the [sqlite3_memory_alarm()] c287665ba8 2007-09-14 drh: ** interface because doing so will interfere with the c287665ba8 2007-09-14 drh: ** [sqlite3_soft_heap_limit()] module. This interface is exposed c287665ba8 2007-09-14 drh: ** only so that applications can provide their own c287665ba8 2007-09-14 drh: ** alternative implementation when the SQLite core is c287665ba8 2007-09-14 drh: ** compiled with SQLITE_OMIT_MEMORY_ALLOCATION. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_memory_alarm( c287665ba8 2007-09-14 drh: void(*xCallback)(void *pArg, sqlite3_int64 used, int N), c287665ba8 2007-09-14 drh: void *pArg, c287665ba8 2007-09-14 drh: sqlite3_int64 iThreshold c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Compile-Time Authorization Callbacks dbda8d6ce9 2007-07-21 drh: *** dbda8d6ce9 2007-07-21 drh: ** This routine registers a authorizer callback with the SQLite library. dbda8d6ce9 2007-07-21 drh: ** The authorizer callback is invoked as SQL statements are being compiled dbda8d6ce9 2007-07-21 drh: ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], dbda8d6ce9 2007-07-21 drh: ** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. At various dbda8d6ce9 2007-07-21 drh: ** points during the compilation process, as logic is being created dbda8d6ce9 2007-07-21 drh: ** to perform various actions, the authorizer callback is invoked to dbda8d6ce9 2007-07-21 drh: ** see if those actions are allowed. The authorizer callback should dbda8d6ce9 2007-07-21 drh: ** return SQLITE_OK to allow the action, [SQLITE_IGNORE] to disallow the dbda8d6ce9 2007-07-21 drh: ** specific action but allow the SQL statement to continue to be dbda8d6ce9 2007-07-21 drh: ** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be dbda8d6ce9 2007-07-21 drh: ** rejected with an error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Depending on the action, the [SQLITE_IGNORE] and [SQLITE_DENY] return dbda8d6ce9 2007-07-21 drh: ** codes might mean something different or they might mean the same dbda8d6ce9 2007-07-21 drh: ** thing. If the action is, for example, to perform a delete opertion, dbda8d6ce9 2007-07-21 drh: ** then [SQLITE_IGNORE] and [SQLITE_DENY] both cause the statement compilation dbda8d6ce9 2007-07-21 drh: ** to fail with an error. But if the action is to read a specific column dbda8d6ce9 2007-07-21 drh: ** from a specific table, then [SQLITE_DENY] will cause the entire dbda8d6ce9 2007-07-21 drh: ** statement to fail but [SQLITE_IGNORE] will cause a NULL value to be dbda8d6ce9 2007-07-21 drh: ** read instead of the actual column value. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first parameter to the authorizer callback is a copy of dbda8d6ce9 2007-07-21 drh: ** the third parameter to the sqlite3_set_authorizer() interface. dbda8d6ce9 2007-07-21 drh: ** The second parameter to the callback is an integer dbda8d6ce9 2007-07-21 drh: ** [SQLITE_COPY | action code] that specifies the particular action dbda8d6ce9 2007-07-21 drh: ** to be authorized. The available action codes are dbda8d6ce9 2007-07-21 drh: ** [SQLITE_COPY | documented separately]. The third through sixth dbda8d6ce9 2007-07-21 drh: ** parameters to the callback are strings that contain additional dbda8d6ce9 2007-07-21 drh: ** details about the action to be authorized. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An authorizer is used when preparing SQL statements from an untrusted dbda8d6ce9 2007-07-21 drh: ** source, to ensure that the SQL statements do not try to access data dbda8d6ce9 2007-07-21 drh: ** that they are not allowed to see, or that they do not try to dbda8d6ce9 2007-07-21 drh: ** execute malicious statements that damage the database. For dbda8d6ce9 2007-07-21 drh: ** example, an application may allow a user to enter arbitrary dbda8d6ce9 2007-07-21 drh: ** SQL queries for evaluation by a database. But the application does dbda8d6ce9 2007-07-21 drh: ** not want the user to be able to make arbitrary changes to the dbda8d6ce9 2007-07-21 drh: ** database. An authorizer could then be put in place while the dbda8d6ce9 2007-07-21 drh: ** user-entered SQL is being prepared that disallows everything dbda8d6ce9 2007-07-21 drh: ** except SELECT statements. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Only a single authorizer can be in place on a database connection dbda8d6ce9 2007-07-21 drh: ** at a time. Each call to sqlite3_set_authorizer overrides the dbda8d6ce9 2007-07-21 drh: ** previous call. A NULL authorizer means that no authorization dbda8d6ce9 2007-07-21 drh: ** callback is invoked. The default authorizer is NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that the authorizer callback is invoked only during dbda8d6ce9 2007-07-21 drh: ** [sqlite3_prepare()] or its variants. Authorization is not dbda8d6ce9 2007-07-21 drh: ** performed during statement evaluation in [sqlite3_step()]. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_set_authorizer( dbda8d6ce9 2007-07-21 drh: sqlite3*, dbda8d6ce9 2007-07-21 drh: int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), dbda8d6ce9 2007-07-21 drh: void *pUserData dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Authorizer Return Codes dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The [sqlite3_set_authorizer | authorizer callback function] must dbda8d6ce9 2007-07-21 drh: ** return either [SQLITE_OK] or one of these two constants in order dbda8d6ce9 2007-07-21 drh: ** to signal SQLite whether or not the action is permitted. See the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_set_authorizer | authorizer documentation] for additional dbda8d6ce9 2007-07-21 drh: ** information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Authorizer Action Codes dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The [sqlite3_set_authorizer()] interface registers a callback function dbda8d6ce9 2007-07-21 drh: ** that is invoked to authorizer certain SQL statement actions. The dbda8d6ce9 2007-07-21 drh: ** second parameter to the callback is an integer code that specifies dbda8d6ce9 2007-07-21 drh: ** what action is being authorized. These are the integer action codes that dbda8d6ce9 2007-07-21 drh: ** the authorizer callback may be passed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These action code values signify what kind of operation is to be dbda8d6ce9 2007-07-21 drh: ** authorized. The 3rd and 4th parameters to the authorization callback dbda8d6ce9 2007-07-21 drh: ** function will be parameters or NULL depending on which of these dbda8d6ce9 2007-07-21 drh: ** codes is used as the second parameter. The 5th parameter to the dbda8d6ce9 2007-07-21 drh: ** authorizer callback is the name of the database ("main", "temp", dbda8d6ce9 2007-07-21 drh: ** etc.) if applicable. The 6th parameter to the authorizer callback dbda8d6ce9 2007-07-21 drh: ** is the name of the inner-most trigger or view that is responsible for dbda8d6ce9 2007-07-21 drh: ** the access attempt or NULL if this access attempt is directly from dbda8d6ce9 2007-07-21 drh: ** top-level SQL code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /******************************************* 3rd ************ 4th ***********/ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_VIEW 8 /* View Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DELETE 9 /* Table Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_TABLE 11 /* Table Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_VIEW 17 /* View Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_INSERT 18 /* Table Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_READ 20 /* Table Name Column Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_SELECT 21 /* NULL NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_TRANSACTION 22 /* NULL NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_UPDATE 23 /* Table Name Column Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ATTACH 24 /* Filename NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DETACH 25 /* Database Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_REINDEX 27 /* Index Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ANALYZE 28 /* Table Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_FUNCTION 31 /* Function Name NULL */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_COPY 0 /* No longer used */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Tracing And Profiling Functions dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines register callback functions that can be used for dbda8d6ce9 2007-07-21 drh: ** tracing and profiling the execution of SQL statements. dbda8d6ce9 2007-07-21 drh: ** The callback function registered by sqlite3_trace() is invoked dbda8d6ce9 2007-07-21 drh: ** at the first [sqlite3_step()] for the evaluation of an SQL statement. dbda8d6ce9 2007-07-21 drh: ** The callback function registered by sqlite3_profile() is invoked dbda8d6ce9 2007-07-21 drh: ** as each SQL statement finishes and includes dbda8d6ce9 2007-07-21 drh: ** information on how long that statement ran. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_profile() API is currently considered experimental and dbda8d6ce9 2007-07-21 drh: ** is subject to change. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); dbda8d6ce9 2007-07-21 drh: SQLITE_API void *sqlite3_profile(sqlite3*, c287665ba8 2007-09-14 drh: void(*xProfile)(void*,const char*,sqlite3_uint64), void*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Query Progress Callbacks dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine configures a callback function - the progress callback - that dbda8d6ce9 2007-07-21 drh: ** is invoked periodically during long running calls to [sqlite3_exec()], dbda8d6ce9 2007-07-21 drh: ** [sqlite3_step()] and [sqlite3_get_table()]. An example use for this dbda8d6ce9 2007-07-21 drh: ** interface is to keep a GUI updated during a large query. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The progress callback is invoked once for every N virtual machine opcodes, dbda8d6ce9 2007-07-21 drh: ** where N is the second argument to this function. The progress callback dbda8d6ce9 2007-07-21 drh: ** itself is identified by the third argument to this function. The fourth dbda8d6ce9 2007-07-21 drh: ** argument to this function is a void pointer passed to the progress callback dbda8d6ce9 2007-07-21 drh: ** function each time it is invoked. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If a call to [sqlite3_exec()], [sqlite3_step()], or [sqlite3_get_table()] dbda8d6ce9 2007-07-21 drh: ** results in fewer than N opcodes being executed, then the progress dbda8d6ce9 2007-07-21 drh: ** callback is never invoked. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Only a single progress callback function may be registered for each dbda8d6ce9 2007-07-21 drh: ** open database connection. Every call to sqlite3_progress_handler() dbda8d6ce9 2007-07-21 drh: ** overwrites the results of the previous call. dbda8d6ce9 2007-07-21 drh: ** To remove the progress callback altogether, pass NULL as the third dbda8d6ce9 2007-07-21 drh: ** argument to this function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the progress callback returns a result other than 0, then the current dbda8d6ce9 2007-07-21 drh: ** query is immediately terminated and any database changes rolled back. dbda8d6ce9 2007-07-21 drh: ** The containing [sqlite3_exec()], [sqlite3_step()], or dbda8d6ce9 2007-07-21 drh: ** [sqlite3_get_table()] call returns SQLITE_INTERRUPT. This feature dbda8d6ce9 2007-07-21 drh: ** can be used, for example, to implement the "Cancel" button on a dbda8d6ce9 2007-07-21 drh: ** progress dialog box in a GUI. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Opening A New Database Connection dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Open the sqlite database file "filename". The "filename" is UTF-8 c287665ba8 2007-09-14 drh: ** encoded for [sqlite3_open()] and [sqlite3_open_v2()] and UTF-16 encoded c287665ba8 2007-09-14 drh: ** in the native byte order for [sqlite3_open16()]. c287665ba8 2007-09-14 drh: ** An [sqlite3*] handle is returned in *ppDb, even dbda8d6ce9 2007-07-21 drh: ** if an error occurs. If the database is opened (or created) successfully, c287665ba8 2007-09-14 drh: ** then [SQLITE_OK] is returned. Otherwise an error code is returned. The c287665ba8 2007-09-14 drh: ** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain dbda8d6ce9 2007-07-21 drh: ** an English language description of the error. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** The default encoding for the database will be UTF-8 if c287665ba8 2007-09-14 drh: ** [sqlite3_open()] or [sqlite3_open_v2()] is called and c287665ba8 2007-09-14 drh: ** UTF-16 if [sqlite3_open16()] is used. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Whether or not an error occurs when it is opened, resources associated dbda8d6ce9 2007-07-21 drh: ** with the [sqlite3*] handle should be released by passing it to c287665ba8 2007-09-14 drh: ** [sqlite3_close()] when it is no longer required. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The [sqlite3_open_v2()] interface works like [sqlite3_open()] except that c287665ba8 2007-09-14 drh: ** provides two additional parameters for additional control over the c287665ba8 2007-09-14 drh: ** new database connection. The flags parameter can be one of: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <ol> c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_READONLY] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_READWRITE] c287665ba8 2007-09-14 drh: ** <li> [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE] c287665ba8 2007-09-14 drh: ** </ol> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The first value opens the database read-only. If the database does c287665ba8 2007-09-14 drh: ** not previously exist, an error is returned. The second option opens c287665ba8 2007-09-14 drh: ** the database for reading and writing if possible, or reading only if c287665ba8 2007-09-14 drh: ** if the file is write protected. In either case the database must already c287665ba8 2007-09-14 drh: ** exist or an error is returned. The third option opens the database c287665ba8 2007-09-14 drh: ** for reading and writing and creates it if it does not already exist. c287665ba8 2007-09-14 drh: ** The third options is behavior that is always used for [sqlite3_open()] c287665ba8 2007-09-14 drh: ** and [sqlite3_open16()]. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If the filename is ":memory:", then an private c287665ba8 2007-09-14 drh: ** in-memory database is created for the connection. This in-memory c287665ba8 2007-09-14 drh: ** database will vanish when the database connection is closed. Future c287665ba8 2007-09-14 drh: ** version of SQLite might make use of additional special filenames c287665ba8 2007-09-14 drh: ** that begin with the ":" character. It is recommended that c287665ba8 2007-09-14 drh: ** when a database filename really does begin with c287665ba8 2007-09-14 drh: ** ":" that you prefix the filename with a pathname like "./" to c287665ba8 2007-09-14 drh: ** avoid ambiguity. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If the filename is an empty string, then a private temporary c287665ba8 2007-09-14 drh: ** on-disk database will be created. This private database will be c287665ba8 2007-09-14 drh: ** automatically deleted as soon as the database connection is closed. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The fourth parameter to sqlite3_open_v2() is the name of the c287665ba8 2007-09-14 drh: ** [sqlite3_vfs] object that defines the operating system c287665ba8 2007-09-14 drh: ** interface that the new database connection should use. If the c287665ba8 2007-09-14 drh: ** fourth parameter is a NULL pointer then the default [sqlite3_vfs] c287665ba8 2007-09-14 drh: ** object is used. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <b>Note to windows users:</b> The encoding used for the filename argument c287665ba8 2007-09-14 drh: ** of [sqlite3_open()] and [sqlite3_open_v2()] must be UTF-8, not whatever c287665ba8 2007-09-14 drh: ** codepage is currently defined. Filenames containing international c287665ba8 2007-09-14 drh: ** characters must be converted to UTF-8 prior to passing them into c287665ba8 2007-09-14 drh: ** [sqlite3_open()] or [sqlite3_open_v2()]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_open( dbda8d6ce9 2007-07-21 drh: const char *filename, /* Database filename (UTF-8) */ dbda8d6ce9 2007-07-21 drh: sqlite3 **ppDb /* OUT: SQLite db handle */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_open16( dbda8d6ce9 2007-07-21 drh: const void *filename, /* Database filename (UTF-16) */ dbda8d6ce9 2007-07-21 drh: sqlite3 **ppDb /* OUT: SQLite db handle */ c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_open_v2( c287665ba8 2007-09-14 drh: const char *filename, /* Database filename (UTF-8) */ c287665ba8 2007-09-14 drh: sqlite3 **ppDb, /* OUT: SQLite db handle */ c287665ba8 2007-09-14 drh: int flags, /* Flags */ c287665ba8 2007-09-14 drh: const char *zVfs /* Name of VFS module to use */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Error Codes And Messages dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_errcode() interface returns the numeric dbda8d6ce9 2007-07-21 drh: ** [SQLITE_OK | result code] or [SQLITE_IOERR_READ | extended result code] dbda8d6ce9 2007-07-21 drh: ** for the most recent failed sqlite3_* API call associated dbda8d6ce9 2007-07-21 drh: ** with [sqlite3] handle 'db'. If a prior API call failed but the dbda8d6ce9 2007-07-21 drh: ** most recent API call succeeded, the return value from sqlite3_errcode() dbda8d6ce9 2007-07-21 drh: ** is undefined. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_errmsg() and sqlite3_errmsg16() return English-langauge dbda8d6ce9 2007-07-21 drh: ** text that describes the error, as either UTF8 or UTF16 respectively. dbda8d6ce9 2007-07-21 drh: ** Memory to hold the error message string is managed internally. The dbda8d6ce9 2007-07-21 drh: ** string may be overwritten or deallocated by subsequent calls to SQLite dbda8d6ce9 2007-07-21 drh: ** interface functions. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Calls to many sqlite3_* functions set the error code and string returned dbda8d6ce9 2007-07-21 drh: ** by [sqlite3_errcode()], [sqlite3_errmsg()], and [sqlite3_errmsg16()] dbda8d6ce9 2007-07-21 drh: ** (overwriting the previous values). Note that calls to [sqlite3_errcode()], dbda8d6ce9 2007-07-21 drh: ** [sqlite3_errmsg()], and [sqlite3_errmsg16()] themselves do not affect the dbda8d6ce9 2007-07-21 drh: ** results of future invocations. Calls to API routines that do not return c287665ba8 2007-09-14 drh: ** an error code (example: [sqlite3_data_count()]) do not c287665ba8 2007-09-14 drh: ** change the error code returned by this routine. Interfaces that are c287665ba8 2007-09-14 drh: ** not associated with a specific database connection (examples: c287665ba8 2007-09-14 drh: ** [sqlite3_mprintf()] or [sqlite3_enable_shared_cache()] do not change c287665ba8 2007-09-14 drh: ** the return code. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Assuming no other intervening sqlite3_* API calls are made, the error dbda8d6ce9 2007-07-21 drh: ** code returned by this function is associated with the same error as dbda8d6ce9 2007-07-21 drh: ** the strings returned by [sqlite3_errmsg()] and [sqlite3_errmsg16()]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_errcode(sqlite3 *db); dbda8d6ce9 2007-07-21 drh: SQLITE_API const char *sqlite3_errmsg(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_API const void *sqlite3_errmsg16(sqlite3*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: SQL Statement Object dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Instance of this object represent single SQL statements. This dbda8d6ce9 2007-07-21 drh: ** is variously known as a "prepared statement" or a dbda8d6ce9 2007-07-21 drh: ** "compiled SQL statement" or simply as a "statement". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The life of a statement object goes something like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <ol> dbda8d6ce9 2007-07-21 drh: ** <li> Create the object using [sqlite3_prepare_v2()] or a related dbda8d6ce9 2007-07-21 drh: ** function. dbda8d6ce9 2007-07-21 drh: ** <li> Bind values to host parameters using dbda8d6ce9 2007-07-21 drh: ** [sqlite3_bind_blob | sqlite3_bind_* interfaces]. dbda8d6ce9 2007-07-21 drh: ** <li> Run the SQL by calling [sqlite3_step()] one or more times. dbda8d6ce9 2007-07-21 drh: ** <li> Reset the statement using [sqlite3_reset()] then go back dbda8d6ce9 2007-07-21 drh: ** to step 2. Do this zero or more times. dbda8d6ce9 2007-07-21 drh: ** <li> Destroy the object using [sqlite3_finalize()]. dbda8d6ce9 2007-07-21 drh: ** </ol> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Refer to documentation on individual methods above for additional dbda8d6ce9 2007-07-21 drh: ** information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3_stmt sqlite3_stmt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Compiling An SQL Statement dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To execute an SQL query, it must first be compiled into a byte-code dbda8d6ce9 2007-07-21 drh: ** program using one of these routines. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first argument "db" is an [sqlite3 | SQLite database handle] c287665ba8 2007-09-14 drh: ** obtained from a prior call to [sqlite3_open()], [sqlite3_open_v2()] c287665ba8 2007-09-14 drh: ** or [sqlite3_open16()]. dbda8d6ce9 2007-07-21 drh: ** The second argument "zSql" is the statement to be compiled, encoded dbda8d6ce9 2007-07-21 drh: ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() dbda8d6ce9 2007-07-21 drh: ** interfaces uses UTF-8 and sqlite3_prepare16() and sqlite3_prepare16_v2() d8590e093f 2007-07-24 drh: ** use UTF-16. d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** If the nByte argument is less dbda8d6ce9 2007-07-21 drh: ** than zero, then zSql is read up to the first zero terminator. If d8590e093f 2007-07-24 drh: ** nByte is non-negative, then it is the maximum number of d8590e093f 2007-07-24 drh: ** bytes read from zSql. When nByte is non-negative, the d8590e093f 2007-07-24 drh: ** zSql string ends at either the first '\000' character or d8590e093f 2007-07-24 drh: ** until the nByte-th byte, whichever comes first. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** *pzTail is made to point to the first byte past the end of the first dbda8d6ce9 2007-07-21 drh: ** SQL statement in zSql. This routine only compiles the first statement dbda8d6ce9 2007-07-21 drh: ** in zSql, so *pzTail is left pointing to what remains uncompiled. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** *ppStmt is left pointing to a compiled dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | SQL statement structure] that can be dbda8d6ce9 2007-07-21 drh: ** executed using [sqlite3_step()]. Or if there is an error, *ppStmt may be dbda8d6ce9 2007-07-21 drh: ** set to NULL. If the input text contained no SQL (if the input is and dbda8d6ce9 2007-07-21 drh: ** empty string or a comment) then *ppStmt is set to NULL. The calling dbda8d6ce9 2007-07-21 drh: ** procedure is responsible for deleting the compiled SQL statement dbda8d6ce9 2007-07-21 drh: ** using [sqlite3_finalize()] after it has finished with it. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On success, [SQLITE_OK] is returned. Otherwise an dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR | error code] is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are dbda8d6ce9 2007-07-21 drh: ** recommended for all new programs. The two older interfaces are retained dbda8d6ce9 2007-07-21 drh: ** for backwards compatibility, but their use is discouraged. dbda8d6ce9 2007-07-21 drh: ** In the "v2" interfaces, the prepared statement dbda8d6ce9 2007-07-21 drh: ** that is returned (the [sqlite3_stmt] object) contains a copy of the dbda8d6ce9 2007-07-21 drh: ** original SQL text. This causes the [sqlite3_step()] interface to dbda8d6ce9 2007-07-21 drh: ** behave a differently in two ways: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <ol> dbda8d6ce9 2007-07-21 drh: ** <li> dbda8d6ce9 2007-07-21 drh: ** If the database schema changes, instead of returning [SQLITE_SCHEMA] as it dbda8d6ce9 2007-07-21 drh: ** always used to do, [sqlite3_step()] will automatically recompile the SQL dbda8d6ce9 2007-07-21 drh: ** statement and try to run it again. If the schema has changed in a way dbda8d6ce9 2007-07-21 drh: ** that makes the statement no longer valid, [sqlite3_step()] will still dbda8d6ce9 2007-07-21 drh: ** return [SQLITE_SCHEMA]. But unlike the legacy behavior, [SQLITE_SCHEMA] is dbda8d6ce9 2007-07-21 drh: ** now a fatal error. Calling [sqlite3_prepare_v2()] again will not make the dbda8d6ce9 2007-07-21 drh: ** error go away. Note: use [sqlite3_errmsg()] to find the text of the parsing dbda8d6ce9 2007-07-21 drh: ** error that results in an [SQLITE_SCHEMA] return. dbda8d6ce9 2007-07-21 drh: ** </li> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <li> dbda8d6ce9 2007-07-21 drh: ** When an error occurs, dbda8d6ce9 2007-07-21 drh: ** [sqlite3_step()] will return one of the detailed dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR | result codes] or dbda8d6ce9 2007-07-21 drh: ** [SQLITE_IOERR_READ | extended result codes] such as directly. dbda8d6ce9 2007-07-21 drh: ** The legacy behavior was that [sqlite3_step()] would only return a generic dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR] result code and you would have to make a second call to dbda8d6ce9 2007-07-21 drh: ** [sqlite3_reset()] in order to find the underlying cause of the problem. dbda8d6ce9 2007-07-21 drh: ** With the "v2" prepare interfaces, the underlying reason for the error is dbda8d6ce9 2007-07-21 drh: ** returned immediately. dbda8d6ce9 2007-07-21 drh: ** </li> dbda8d6ce9 2007-07-21 drh: ** </ol> dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_prepare( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle */ dbda8d6ce9 2007-07-21 drh: const char *zSql, /* SQL statement, UTF-8 encoded */ d8590e093f 2007-07-24 drh: int nByte, /* Maximum length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: Statement handle */ dbda8d6ce9 2007-07-21 drh: const char **pzTail /* OUT: Pointer to unused portion of zSql */ dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_prepare_v2( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle */ dbda8d6ce9 2007-07-21 drh: const char *zSql, /* SQL statement, UTF-8 encoded */ d8590e093f 2007-07-24 drh: int nByte, /* Maximum length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: Statement handle */ dbda8d6ce9 2007-07-21 drh: const char **pzTail /* OUT: Pointer to unused portion of zSql */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_prepare16( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle */ dbda8d6ce9 2007-07-21 drh: const void *zSql, /* SQL statement, UTF-16 encoded */ d8590e093f 2007-07-24 drh: int nByte, /* Maximum length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: Statement handle */ dbda8d6ce9 2007-07-21 drh: const void **pzTail /* OUT: Pointer to unused portion of zSql */ dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_prepare16_v2( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle */ dbda8d6ce9 2007-07-21 drh: const void *zSql, /* SQL statement, UTF-16 encoded */ d8590e093f 2007-07-24 drh: int nByte, /* Maximum length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: Statement handle */ dbda8d6ce9 2007-07-21 drh: const void **pzTail /* OUT: Pointer to unused portion of zSql */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Dynamically Typed Value Object dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite uses dynamic typing for the values it stores. Values can dbda8d6ce9 2007-07-21 drh: ** be integers, floating point values, strings, BLOBs, or NULL. When dbda8d6ce9 2007-07-21 drh: ** passing around values internally, each value is represented as dbda8d6ce9 2007-07-21 drh: ** an instance of the sqlite3_value object. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct Mem sqlite3_value; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: SQL Function Context Object dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The context in which an SQL function executes is stored in an dbda8d6ce9 2007-07-21 drh: ** sqlite3_context object. A pointer to such an object is the dbda8d6ce9 2007-07-21 drh: ** first parameter to user-defined SQL functions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3_context sqlite3_context; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Binding Values To Prepared Statements dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the SQL strings input to [sqlite3_prepare_v2()] and its variants, dbda8d6ce9 2007-07-21 drh: ** one or more literals can be replace by a parameter in one of these dbda8d6ce9 2007-07-21 drh: ** forms: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <ul> dbda8d6ce9 2007-07-21 drh: ** <li> ? dbda8d6ce9 2007-07-21 drh: ** <li> ?NNN dbda8d6ce9 2007-07-21 drh: ** <li> :AAA dbda8d6ce9 2007-07-21 drh: ** <li> @AAA dbda8d6ce9 2007-07-21 drh: ** <li> $VVV dbda8d6ce9 2007-07-21 drh: ** </ul> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the parameter forms shown above NNN is an integer literal, dbda8d6ce9 2007-07-21 drh: ** AAA is an alphanumeric identifier and VVV is a variable name according dbda8d6ce9 2007-07-21 drh: ** to the syntax rules of the TCL programming language. dbda8d6ce9 2007-07-21 drh: ** The values of these parameters (also called "host parameter names") dbda8d6ce9 2007-07-21 drh: ** can be set using the sqlite3_bind_*() routines defined here. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first argument to the sqlite3_bind_*() routines always is a pointer dbda8d6ce9 2007-07-21 drh: ** to the [sqlite3_stmt] object returned from [sqlite3_prepare_v2()] or dbda8d6ce9 2007-07-21 drh: ** its variants. The second dbda8d6ce9 2007-07-21 drh: ** argument is the index of the parameter to be set. The first parameter has dbda8d6ce9 2007-07-21 drh: ** an index of 1. When the same named parameter is used more than once, second dbda8d6ce9 2007-07-21 drh: ** and subsequent dbda8d6ce9 2007-07-21 drh: ** occurrences have the same index as the first occurrence. The index for dbda8d6ce9 2007-07-21 drh: ** named parameters can be looked up using the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_bind_parameter_name()] API if desired. The index for "?NNN" dbda8d6ce9 2007-07-21 drh: ** parametes is the value of NNN. dbda8d6ce9 2007-07-21 drh: ** The NNN value must be between 1 and the compile-time dbda8d6ce9 2007-07-21 drh: ** parameter SQLITE_MAX_VARIABLE_NUMBER (default value: 999). dbda8d6ce9 2007-07-21 drh: ** See <a href="limits.html">limits.html</a> for additional information. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The third argument is the value to bind to the parameter. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In those dbda8d6ce9 2007-07-21 drh: ** routines that have a fourth argument, its value is the number of bytes dbda8d6ce9 2007-07-21 drh: ** in the parameter. To be clear: the value is the number of bytes in the dbda8d6ce9 2007-07-21 drh: ** string, not the number of characters. The number dbda8d6ce9 2007-07-21 drh: ** of bytes does not include the zero-terminator at the end of strings. dbda8d6ce9 2007-07-21 drh: ** If the fourth parameter is negative, the length of the string is dbda8d6ce9 2007-07-21 drh: ** number of bytes up to the first zero terminator. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and dbda8d6ce9 2007-07-21 drh: ** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or dbda8d6ce9 2007-07-21 drh: ** text after SQLite has finished with it. If the fifth argument is the dbda8d6ce9 2007-07-21 drh: ** special value [SQLITE_STATIC], then the library assumes that the information dbda8d6ce9 2007-07-21 drh: ** is in static, unmanaged space and does not need to be freed. If the dbda8d6ce9 2007-07-21 drh: ** fifth argument has the value [SQLITE_TRANSIENT], then SQLite makes its dbda8d6ce9 2007-07-21 drh: ** own private copy of the data immediately, before the sqlite3_bind_*() dbda8d6ce9 2007-07-21 drh: ** routine returns. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_bind_zeroblob() routine binds a BLOB of length n that dbda8d6ce9 2007-07-21 drh: ** is filled with zeros. A zeroblob uses a fixed amount of memory dbda8d6ce9 2007-07-21 drh: ** (just an integer to hold it size) while it is being processed. dbda8d6ce9 2007-07-21 drh: ** Zeroblobs are intended to serve as place-holders for BLOBs whose dbda8d6ce9 2007-07-21 drh: ** content is later written using c287665ba8 2007-09-14 drh: ** [sqlite3_blob_open | increment BLOB I/O] routines. A negative c287665ba8 2007-09-14 drh: ** value for the zeroblob results in a zero-length BLOB. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_bind_*() routines must be called after dbda8d6ce9 2007-07-21 drh: ** [sqlite3_prepare_v2()] (and its variants) or [sqlite3_reset()] and dbda8d6ce9 2007-07-21 drh: ** before [sqlite3_step()]. dbda8d6ce9 2007-07-21 drh: ** Bindings are not cleared by the [sqlite3_reset()] routine. dbda8d6ce9 2007-07-21 drh: ** Unbound parameters are interpreted as NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines return [SQLITE_OK] on success or an error code if dbda8d6ce9 2007-07-21 drh: ** anything goes wrong. [SQLITE_RANGE] is returned if the parameter dbda8d6ce9 2007-07-21 drh: ** index is out of range. [SQLITE_NOMEM] is returned if malloc fails. dbda8d6ce9 2007-07-21 drh: ** [SQLITE_MISUSE] is returned if these routines are called on a virtual dbda8d6ce9 2007-07-21 drh: ** machine that is the wrong state or which has already been finalized. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Number Of Host Parameters dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the largest host parameter index in the precompiled statement given dbda8d6ce9 2007-07-21 drh: ** as the argument. When the host parameters are of the forms like ":AAA" dbda8d6ce9 2007-07-21 drh: ** or "?", then they are assigned sequential increasing numbers beginning dbda8d6ce9 2007-07-21 drh: ** with one, so the value returned is the number of parameters. However dbda8d6ce9 2007-07-21 drh: ** if the same host parameter name is used multiple times, each occurrance dbda8d6ce9 2007-07-21 drh: ** is given the same number, so the value returned in that case is the number dbda8d6ce9 2007-07-21 drh: ** of unique host parameter names. If host parameters of the form "?NNN" dbda8d6ce9 2007-07-21 drh: ** are used (where NNN is an integer) then there might be gaps in the dbda8d6ce9 2007-07-21 drh: ** numbering and the value returned by this interface is the index of the dbda8d6ce9 2007-07-21 drh: ** host parameter with the largest index value. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The prepared statement must not be [sqlite3_finalize | finalized] c287665ba8 2007-09-14 drh: ** prior to this routine returnning. Otherwise the results are undefined c287665ba8 2007-09-14 drh: ** and probably undesirable. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Name Of A Host Parameter dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns a pointer to the name of the n-th parameter in a dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | prepared statement]. dbda8d6ce9 2007-07-21 drh: ** Host parameters of the form ":AAA" or "@AAA" or "$VVV" have a name dbda8d6ce9 2007-07-21 drh: ** which is the string ":AAA" or "@AAA" or "$VVV". dbda8d6ce9 2007-07-21 drh: ** In other words, the initial ":" or "$" or "@" dbda8d6ce9 2007-07-21 drh: ** is included as part of the name. dbda8d6ce9 2007-07-21 drh: ** Parameters of the form "?" or "?NNN" have no name. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first bound parameter has an index of 1, not 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the value n is out of range or if the n-th parameter is nameless, dbda8d6ce9 2007-07-21 drh: ** then NULL is returned. The returned string is always in the dbda8d6ce9 2007-07-21 drh: ** UTF-8 encoding even if the named parameter was originally specified dbda8d6ce9 2007-07-21 drh: ** as UTF-16 in [sqlite3_prepare16()] or [sqlite3_prepare16_v2()]. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Index Of A Parameter With A Given Name dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns the index of a host parameter with the given name. dbda8d6ce9 2007-07-21 drh: ** The name must match exactly. If no parameter with the given name is dbda8d6ce9 2007-07-21 drh: ** found, return 0. Parameter names must be UTF8. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Reset All Bindings On A Prepared Statement dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Contrary to the intuition of many, [sqlite3_reset()] does not dbda8d6ce9 2007-07-21 drh: ** reset the [sqlite3_bind_blob | bindings] on a dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | prepared statement]. Use this routine to dbda8d6ce9 2007-07-21 drh: ** reset all host parameters to NULL. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Number Of Columns In A Result Set dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the number of columns in the result set returned by the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | compiled SQL statement]. This routine returns 0 dbda8d6ce9 2007-07-21 drh: ** if pStmt is an SQL statement that does not return data (for dbda8d6ce9 2007-07-21 drh: ** example an UPDATE). dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Column Names In A Result Set dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines return the name assigned to a particular column dbda8d6ce9 2007-07-21 drh: ** in the result set of a SELECT statement. The sqlite3_column_name() dbda8d6ce9 2007-07-21 drh: ** interface returns a pointer to a UTF8 string and sqlite3_column_name16() dbda8d6ce9 2007-07-21 drh: ** returns a pointer to a UTF16 string. The first parameter is the c287665ba8 2007-09-14 drh: ** [sqlite3_stmt | prepared statement] that implements the SELECT statement. dbda8d6ce9 2007-07-21 drh: ** The second parameter is the column number. The left-most column is dbda8d6ce9 2007-07-21 drh: ** number 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The returned string pointer is valid until either the c287665ba8 2007-09-14 drh: ** [sqlite3_stmt | prepared statement] is destroyed by [sqlite3_finalize()] dbda8d6ce9 2007-07-21 drh: ** or until the next call sqlite3_column_name() or sqlite3_column_name16() dbda8d6ce9 2007-07-21 drh: ** on the same column. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If sqlite3_malloc() fails during the processing of either routine c287665ba8 2007-09-14 drh: ** (for example during a conversion from UTF-8 to UTF-16) then a c287665ba8 2007-09-14 drh: ** NULL pointer is returned. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Source Of Data In A Query Result dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines provide a means to determine what column of what dbda8d6ce9 2007-07-21 drh: ** table in which database a result of a SELECT statement comes from. dbda8d6ce9 2007-07-21 drh: ** The name of the database or table or column can be returned as dbda8d6ce9 2007-07-21 drh: ** either a UTF8 or UTF16 string. The _database_ routines return dbda8d6ce9 2007-07-21 drh: ** the database name, the _table_ routines return the table name, and dbda8d6ce9 2007-07-21 drh: ** the origin_ routines return the column name. dbda8d6ce9 2007-07-21 drh: ** The returned string is valid until dbda8d6ce9 2007-07-21 drh: ** the [sqlite3_stmt | prepared statement] is destroyed using dbda8d6ce9 2007-07-21 drh: ** [sqlite3_finalize()] or until the same information is requested dbda8d6ce9 2007-07-21 drh: ** again in a different encoding. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The names returned are the original un-aliased names of the dbda8d6ce9 2007-07-21 drh: ** database, table, and column. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first argument to the following calls is a dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | compiled SQL statement]. dbda8d6ce9 2007-07-21 drh: ** These functions return information about the Nth column returned by dbda8d6ce9 2007-07-21 drh: ** the statement, where N is the second function argument. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the Nth column returned by the statement is an expression dbda8d6ce9 2007-07-21 drh: ** or subquery and is not a column value, then all of these functions dbda8d6ce9 2007-07-21 drh: ** return NULL. Otherwise, they return the dbda8d6ce9 2007-07-21 drh: ** name of the attached database, table and column that query result dbda8d6ce9 2007-07-21 drh: ** column was extracted from. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** As with all other SQLite APIs, those postfixed with "16" return UTF-16 dbda8d6ce9 2007-07-21 drh: ** encoded strings, the other functions return UTF-8. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These APIs are only available if the library was compiled with the dbda8d6ce9 2007-07-21 drh: ** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If two or more threads call one or more of these routines against the same c287665ba8 2007-09-14 drh: ** prepared statement and column at the same time then the results are c287665ba8 2007-09-14 drh: ** undefined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Declared Datatype Of A Query Result dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first parameter is a [sqlite3_stmt | compiled SQL statement]. dbda8d6ce9 2007-07-21 drh: ** If this statement is a SELECT statement and the Nth column of the dbda8d6ce9 2007-07-21 drh: ** returned result set of that SELECT is a table column (not an dbda8d6ce9 2007-07-21 drh: ** expression or subquery) then the declared type of the table dbda8d6ce9 2007-07-21 drh: ** column is returned. If the Nth column of the result set is an dbda8d6ce9 2007-07-21 drh: ** expression or subquery, then a NULL pointer is returned. dbda8d6ce9 2007-07-21 drh: ** The returned string is always UTF-8 encoded. For example, in dbda8d6ce9 2007-07-21 drh: ** the database schema: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE t1(c1 VARIANT); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** And the following statement compiled: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT c1 + 1, c1 FROM t1; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then this routine would return the string "VARIANT" for the second dbda8d6ce9 2007-07-21 drh: ** result column (i==1), and a NULL pointer for the first result column dbda8d6ce9 2007-07-21 drh: ** (i==0). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite uses dynamic run-time typing. So just because a column dbda8d6ce9 2007-07-21 drh: ** is declared to contain a particular type does not mean that the dbda8d6ce9 2007-07-21 drh: ** data stored in that column is of the declared type. SQLite is dbda8d6ce9 2007-07-21 drh: ** strongly typed, but the typing is dynamic not static. Type dbda8d6ce9 2007-07-21 drh: ** is associated with individual values, not with the containers dbda8d6ce9 2007-07-21 drh: ** used to hold those values. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *, int i); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Evaluate An SQL Statement dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After an [sqlite3_stmt | SQL statement] has been prepared with a call dbda8d6ce9 2007-07-21 drh: ** to either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or to one of dbda8d6ce9 2007-07-21 drh: ** the legacy interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], dbda8d6ce9 2007-07-21 drh: ** then this function must be called one or more times to evaluate the dbda8d6ce9 2007-07-21 drh: ** statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The details of the behavior of this sqlite3_step() interface depend dbda8d6ce9 2007-07-21 drh: ** on whether the statement was prepared using the newer "v2" interface dbda8d6ce9 2007-07-21 drh: ** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy dbda8d6ce9 2007-07-21 drh: ** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the dbda8d6ce9 2007-07-21 drh: ** new "v2" interface is recommended for new applications but the legacy dbda8d6ce9 2007-07-21 drh: ** interface will continue to be supported. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the lagacy interface, the return value will be either [SQLITE_BUSY], dbda8d6ce9 2007-07-21 drh: ** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. dbda8d6ce9 2007-07-21 drh: ** With the "v2" interface, any of the other [SQLITE_OK | result code] dbda8d6ce9 2007-07-21 drh: ** or [SQLITE_IOERR_READ | extended result code] might be returned as dbda8d6ce9 2007-07-21 drh: ** well. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** [SQLITE_BUSY] means that the database engine was unable to acquire the dbda8d6ce9 2007-07-21 drh: ** database locks it needs to do its job. If the statement is a COMMIT dbda8d6ce9 2007-07-21 drh: ** or occurs outside of an explicit transaction, then you can retry the dbda8d6ce9 2007-07-21 drh: ** statement. If the statement is not a COMMIT and occurs within a dbda8d6ce9 2007-07-21 drh: ** explicit transaction then you should rollback the transaction before dbda8d6ce9 2007-07-21 drh: ** continuing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** [SQLITE_DONE] means that the statement has finished executing dbda8d6ce9 2007-07-21 drh: ** successfully. sqlite3_step() should not be called again on this virtual dbda8d6ce9 2007-07-21 drh: ** machine without first calling [sqlite3_reset()] to reset the virtual dbda8d6ce9 2007-07-21 drh: ** machine back to its initial state. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the SQL statement being executed returns any data, then dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ROW] is returned each time a new row of data is ready dbda8d6ce9 2007-07-21 drh: ** for processing by the caller. The values may be accessed using dbda8d6ce9 2007-07-21 drh: ** the [sqlite3_column_int | column access functions]. dbda8d6ce9 2007-07-21 drh: ** sqlite3_step() is called again to retrieve the next row of data. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR] means that a run-time error (such as a constraint dbda8d6ce9 2007-07-21 drh: ** violation) has occurred. sqlite3_step() should not be called again on dbda8d6ce9 2007-07-21 drh: ** the VM. More information may be found by calling [sqlite3_errmsg()]. dbda8d6ce9 2007-07-21 drh: ** With the legacy interface, a more specific error code (example: dbda8d6ce9 2007-07-21 drh: ** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) dbda8d6ce9 2007-07-21 drh: ** can be obtained by calling [sqlite3_reset()] on the c287665ba8 2007-09-14 drh: ** [sqlite3_stmt | prepared statement]. In the "v2" interface, dbda8d6ce9 2007-07-21 drh: ** the more specific error code is returned directly by sqlite3_step(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** [SQLITE_MISUSE] means that the this routine was called inappropriately. c287665ba8 2007-09-14 drh: ** Perhaps it was called on a [sqlite3_stmt | prepared statement] that has dbda8d6ce9 2007-07-21 drh: ** already been [sqlite3_finalize | finalized] or on one that had dbda8d6ce9 2007-07-21 drh: ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could dbda8d6ce9 2007-07-21 drh: ** be the case that the same database connection is being used by two or dbda8d6ce9 2007-07-21 drh: ** more threads at the same moment in time. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <b>Goofy Interface Alert:</b> dbda8d6ce9 2007-07-21 drh: ** In the legacy interface, dbda8d6ce9 2007-07-21 drh: ** the sqlite3_step() API always returns a generic error code, dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR], following any error other than [SQLITE_BUSY] dbda8d6ce9 2007-07-21 drh: ** and [SQLITE_MISUSE]. You must call [sqlite3_reset()] or dbda8d6ce9 2007-07-21 drh: ** [sqlite3_finalize()] in order to find one of the specific dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR | result codes] that better describes the error. dbda8d6ce9 2007-07-21 drh: ** We admit that this is a goofy design. The problem has been fixed dbda8d6ce9 2007-07-21 drh: ** with the "v2" interface. If you prepare all of your SQL statements dbda8d6ce9 2007-07-21 drh: ** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead dbda8d6ce9 2007-07-21 drh: ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()], then the dbda8d6ce9 2007-07-21 drh: ** more specific [SQLITE_ERROR | result codes] are returned directly dbda8d6ce9 2007-07-21 drh: ** by sqlite3_step(). The use of the "v2" interface is recommended. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_step(sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the number of values in the current row of the result set. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After a call to [sqlite3_step()] that returns [SQLITE_ROW], this routine dbda8d6ce9 2007-07-21 drh: ** will return the same value as the [sqlite3_column_count()] function. dbda8d6ce9 2007-07-21 drh: ** After [sqlite3_step()] has returned an [SQLITE_DONE], [SQLITE_BUSY], or dbda8d6ce9 2007-07-21 drh: ** a [SQLITE_ERROR | error code], or before [sqlite3_step()] has been c287665ba8 2007-09-14 drh: ** called on the [sqlite3_stmt | prepared statement] for the first time, dbda8d6ce9 2007-07-21 drh: ** this routine returns zero. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Fundamental Datatypes dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Every value in SQLite has one of five fundamental datatypes: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <ul> dbda8d6ce9 2007-07-21 drh: ** <li> 64-bit signed integer dbda8d6ce9 2007-07-21 drh: ** <li> 64-bit IEEE floating point number dbda8d6ce9 2007-07-21 drh: ** <li> string dbda8d6ce9 2007-07-21 drh: ** <li> BLOB dbda8d6ce9 2007-07-21 drh: ** <li> NULL dbda8d6ce9 2007-07-21 drh: ** </ul> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These constants are codes for each of those types. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that the SQLITE_TEXT constant was also used in SQLite version 2 dbda8d6ce9 2007-07-21 drh: ** for a completely different meaning. Software that links against both dbda8d6ce9 2007-07-21 drh: ** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT not dbda8d6ce9 2007-07-21 drh: ** SQLITE_TEXT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_INTEGER 1 dbda8d6ce9 2007-07-21 drh: #define SQLITE_FLOAT 2 dbda8d6ce9 2007-07-21 drh: #define SQLITE_BLOB 4 dbda8d6ce9 2007-07-21 drh: #define SQLITE_NULL 5 dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEXT dbda8d6ce9 2007-07-21 drh: # undef SQLITE_TEXT dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define SQLITE_TEXT 3 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #define SQLITE3_TEXT 3 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Results Values From A Query dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** These routines return information about c287665ba8 2007-09-14 drh: ** a single column of the current result row of a query. In every dbda8d6ce9 2007-07-21 drh: ** case the first argument is a pointer to the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | SQL statement] that is being c287665ba8 2007-09-14 drh: ** evaluated (the [sqlite3_stmt*] that was returned from dbda8d6ce9 2007-07-21 drh: ** [sqlite3_prepare_v2()] or one of its variants) and dbda8d6ce9 2007-07-21 drh: ** the second argument is the index of the column for which information c287665ba8 2007-09-14 drh: ** should be returned. The left-most column of the result set c287665ba8 2007-09-14 drh: ** has an index of 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the SQL statement is not currently point to a valid row, or if the dbda8d6ce9 2007-07-21 drh: ** the column index is out of range, the result is undefined. c287665ba8 2007-09-14 drh: ** These routines may only be called when the most recent call to c287665ba8 2007-09-14 drh: ** [sqlite3_step()] has returned [SQLITE_ROW] and neither c287665ba8 2007-09-14 drh: ** [sqlite3_reset()] nor [sqlite3_finalize()] has been call subsequently. c287665ba8 2007-09-14 drh: ** If any of these routines are called after [sqlite3_reset()] or c287665ba8 2007-09-14 drh: ** [sqlite3_finalize()] or after [sqlite3_step()] has returned c287665ba8 2007-09-14 drh: ** something other than [SQLITE_ROW], the results are undefined. c287665ba8 2007-09-14 drh: ** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] c287665ba8 2007-09-14 drh: ** are called from a different thread while any of these routines c287665ba8 2007-09-14 drh: ** are pending, then the results are undefined. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_column_type() routine returns dbda8d6ce9 2007-07-21 drh: ** [SQLITE_INTEGER | datatype code] for the initial data type dbda8d6ce9 2007-07-21 drh: ** of the result column. The returned value is one of [SQLITE_INTEGER], dbda8d6ce9 2007-07-21 drh: ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value dbda8d6ce9 2007-07-21 drh: ** returned by sqlite3_column_type() is only meaningful if no type dbda8d6ce9 2007-07-21 drh: ** conversions have occurred as described below. After a type conversion, dbda8d6ce9 2007-07-21 drh: ** the value returned by sqlite3_column_type() is undefined. Future dbda8d6ce9 2007-07-21 drh: ** versions of SQLite may change the behavior of sqlite3_column_type() dbda8d6ce9 2007-07-21 drh: ** following a type conversion. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() dbda8d6ce9 2007-07-21 drh: ** routine returns the number of bytes in that BLOB or string. dbda8d6ce9 2007-07-21 drh: ** If the result is a UTF-16 string, then sqlite3_column_bytes() converts dbda8d6ce9 2007-07-21 drh: ** the string to UTF-8 and then returns the number of bytes. dbda8d6ce9 2007-07-21 drh: ** If the result is a numeric value then sqlite3_column_bytes() uses dbda8d6ce9 2007-07-21 drh: ** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns dbda8d6ce9 2007-07-21 drh: ** the number of bytes in that string. dbda8d6ce9 2007-07-21 drh: ** The value returned does not include the zero terminator at the end dbda8d6ce9 2007-07-21 drh: ** of the string. For clarity: the value returned is the number of dbda8d6ce9 2007-07-21 drh: ** bytes in the string, not the number of characters. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Strings returned by sqlite3_column_text() and sqlite3_column_text16(), c287665ba8 2007-09-14 drh: ** even zero-length strings, are always zero terminated. The return c287665ba8 2007-09-14 drh: ** value from sqlite3_column_blob() for a zero-length blob is an arbitrary c287665ba8 2007-09-14 drh: ** pointer, possibly even a NULL pointer. c287665ba8 2007-09-14 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes() dbda8d6ce9 2007-07-21 drh: ** but leaves the result in UTF-16 instead of UTF-8. dbda8d6ce9 2007-07-21 drh: ** The zero terminator is not included in this count. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines attempt to convert the value where appropriate. For dbda8d6ce9 2007-07-21 drh: ** example, if the internal representation is FLOAT and a text result dbda8d6ce9 2007-07-21 drh: ** is requested, [sqlite3_snprintf()] is used internally to do the conversion dbda8d6ce9 2007-07-21 drh: ** automatically. The following table details the conversions that dbda8d6ce9 2007-07-21 drh: ** are applied: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <blockquote> dbda8d6ce9 2007-07-21 drh: ** <table border="1"> c287665ba8 2007-09-14 drh: ** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <tr><td> NULL <td> INTEGER <td> Result is 0 dbda8d6ce9 2007-07-21 drh: ** <tr><td> NULL <td> FLOAT <td> Result is 0.0 dbda8d6ce9 2007-07-21 drh: ** <tr><td> NULL <td> TEXT <td> Result is NULL pointer dbda8d6ce9 2007-07-21 drh: ** <tr><td> NULL <td> BLOB <td> Result is NULL pointer dbda8d6ce9 2007-07-21 drh: ** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float dbda8d6ce9 2007-07-21 drh: ** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer dbda8d6ce9 2007-07-21 drh: ** <tr><td> INTEGER <td> BLOB <td> Same as for INTEGER->TEXT dbda8d6ce9 2007-07-21 drh: ** <tr><td> FLOAT <td> INTEGER <td> Convert from float to integer dbda8d6ce9 2007-07-21 drh: ** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float dbda8d6ce9 2007-07-21 drh: ** <tr><td> FLOAT <td> BLOB <td> Same as FLOAT->TEXT dbda8d6ce9 2007-07-21 drh: ** <tr><td> TEXT <td> INTEGER <td> Use atoi() dbda8d6ce9 2007-07-21 drh: ** <tr><td> TEXT <td> FLOAT <td> Use atof() dbda8d6ce9 2007-07-21 drh: ** <tr><td> TEXT <td> BLOB <td> No change dbda8d6ce9 2007-07-21 drh: ** <tr><td> BLOB <td> INTEGER <td> Convert to TEXT then use atoi() dbda8d6ce9 2007-07-21 drh: ** <tr><td> BLOB <td> FLOAT <td> Convert to TEXT then use atof() dbda8d6ce9 2007-07-21 drh: ** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed dbda8d6ce9 2007-07-21 drh: ** </table> dbda8d6ce9 2007-07-21 drh: ** </blockquote> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The table above makes reference to standard C library functions atoi() dbda8d6ce9 2007-07-21 drh: ** and atof(). SQLite does not really use these functions. It has its dbda8d6ce9 2007-07-21 drh: ** on equavalent internal routines. The atoi() and atof() names are dbda8d6ce9 2007-07-21 drh: ** used in the table for brevity and because they are familiar to most dbda8d6ce9 2007-07-21 drh: ** C programmers. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that when type conversions occur, pointers returned by prior dbda8d6ce9 2007-07-21 drh: ** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_text16() may be invalidated. dbda8d6ce9 2007-07-21 drh: ** Type conversions and pointer invalidations might occur dbda8d6ce9 2007-07-21 drh: ** in the following cases: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <ul> dbda8d6ce9 2007-07-21 drh: ** <li><p> The initial content is a BLOB and sqlite3_column_text() dbda8d6ce9 2007-07-21 drh: ** or sqlite3_column_text16() is called. A zero-terminator might dbda8d6ce9 2007-07-21 drh: ** need to be added to the string.</p></li> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <li><p> The initial content is UTF-8 text and sqlite3_column_bytes16() or dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_text16() is called. The content must be converted dbda8d6ce9 2007-07-21 drh: ** to UTF-16.</p></li> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <li><p> The initial content is UTF-16 text and sqlite3_column_bytes() or dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_text() is called. The content must be converted dbda8d6ce9 2007-07-21 drh: ** to UTF-8.</p></li> dbda8d6ce9 2007-07-21 drh: ** </ul> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Conversions between UTF-16be and UTF-16le are always done in place and do dbda8d6ce9 2007-07-21 drh: ** not invalidate a prior pointer, though of course the content of the buffer dbda8d6ce9 2007-07-21 drh: ** that the prior pointer points to will have been modified. Other kinds dbda8d6ce9 2007-07-21 drh: ** of conversion are done in place when it is possible, but sometime it is dbda8d6ce9 2007-07-21 drh: ** not possible and in those cases prior pointers are invalidated. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The safest and easiest to remember policy is to invoke these routines dbda8d6ce9 2007-07-21 drh: ** in one of the following ways: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <ul> dbda8d6ce9 2007-07-21 drh: ** <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li> dbda8d6ce9 2007-07-21 drh: ** <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li> dbda8d6ce9 2007-07-21 drh: ** <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li> dbda8d6ce9 2007-07-21 drh: ** </ul> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In other words, you should call sqlite3_column_text(), sqlite3_column_blob(), dbda8d6ce9 2007-07-21 drh: ** or sqlite3_column_text16() first to force the result into the desired dbda8d6ce9 2007-07-21 drh: ** format, then invoke sqlite3_column_bytes() or sqlite3_column_bytes16() to dbda8d6ce9 2007-07-21 drh: ** find the size of the result. Do not mix call to sqlite3_column_text() or dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_blob() with calls to sqlite3_column_bytes16(). And do not dbda8d6ce9 2007-07-21 drh: ** mix calls to sqlite3_column_text16() with calls to sqlite3_column_bytes(). c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The pointers returned are valid until a type conversion occurs as c287665ba8 2007-09-14 drh: ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or c287665ba8 2007-09-14 drh: ** [sqlite3_finalize()] is called. The memory space used to hold strings c287665ba8 2007-09-14 drh: ** and blobs is freed automatically. Do <b>not</b> pass the pointers returned c287665ba8 2007-09-14 drh: ** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into c287665ba8 2007-09-14 drh: ** [sqlite3_free()]. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If a memory allocation error occurs during the evaluation of any c287665ba8 2007-09-14 drh: ** of these routines, a default value is returned. The default value c287665ba8 2007-09-14 drh: ** is either the integer 0, the floating point number 0.0, or a NULL c287665ba8 2007-09-14 drh: ** pointer. Subsequent calls to [sqlite3_errcode()] will return c287665ba8 2007-09-14 drh: ** [SQLITE_NOMEM]. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Destroy A Prepared Statement Object dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_finalize() function is called to delete a dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | compiled SQL statement]. If the statement was dbda8d6ce9 2007-07-21 drh: ** executed successfully, or not executed at all, then SQLITE_OK is returned. dbda8d6ce9 2007-07-21 drh: ** If execution of the statement failed then an dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR | error code] or [SQLITE_IOERR_READ | extended error code] dbda8d6ce9 2007-07-21 drh: ** is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine can be called at any point during the execution of the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | virtual machine]. If the virtual machine has not dbda8d6ce9 2007-07-21 drh: ** completed execution when this routine is called, that is like dbda8d6ce9 2007-07-21 drh: ** encountering an error or an interrupt. (See [sqlite3_interrupt()].) dbda8d6ce9 2007-07-21 drh: ** Incomplete updates may be rolled back and transactions cancelled, dbda8d6ce9 2007-07-21 drh: ** depending on the circumstances, and the dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR | result code] returned will be [SQLITE_ABORT]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Reset A Prepared Statement Object dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_reset() function is called to reset a c287665ba8 2007-09-14 drh: ** [sqlite3_stmt | compiled SQL statement] object. dbda8d6ce9 2007-07-21 drh: ** back to it's initial state, ready to be re-executed. dbda8d6ce9 2007-07-21 drh: ** Any SQL statement variables that had values bound to them using dbda8d6ce9 2007-07-21 drh: ** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. dbda8d6ce9 2007-07-21 drh: ** Use [sqlite3_clear_bindings()] to reset the bindings. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Create Or Redefine SQL Functions dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following two functions are used to add SQL functions or aggregates dbda8d6ce9 2007-07-21 drh: ** or to redefine the behavior of existing SQL functions or aggregates. The dbda8d6ce9 2007-07-21 drh: ** difference only between the two is that the second parameter, the dbda8d6ce9 2007-07-21 drh: ** name of the (scalar) function or aggregate, is encoded in UTF-8 for dbda8d6ce9 2007-07-21 drh: ** sqlite3_create_function() and UTF-16 for sqlite3_create_function16(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first argument is the [sqlite3 | database handle] that holds the dbda8d6ce9 2007-07-21 drh: ** SQL function or aggregate is to be added or redefined. If a single dbda8d6ce9 2007-07-21 drh: ** program uses more than one database handle internally, then SQL dbda8d6ce9 2007-07-21 drh: ** functions or aggregates must be added individually to each database dbda8d6ce9 2007-07-21 drh: ** handle with which they will be used. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The second parameter is the name of the SQL function to be created dbda8d6ce9 2007-07-21 drh: ** or redefined. dbda8d6ce9 2007-07-21 drh: ** The length of the name is limited to 255 bytes, exclusive of the dbda8d6ce9 2007-07-21 drh: ** zero-terminator. Note that the name length limit is in bytes, not dbda8d6ce9 2007-07-21 drh: ** characters. Any attempt to create a function with a longer name dbda8d6ce9 2007-07-21 drh: ** will result in an SQLITE_ERROR error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The third parameter is the number of arguments that the SQL function or dbda8d6ce9 2007-07-21 drh: ** aggregate takes. If this parameter is negative, then the SQL function or dbda8d6ce9 2007-07-21 drh: ** aggregate may take any number of arguments. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The fourth parameter, eTextRep, specifies what dbda8d6ce9 2007-07-21 drh: ** [SQLITE_UTF8 | text encoding] this SQL function prefers for dbda8d6ce9 2007-07-21 drh: ** its parameters. Any SQL function implementation should be able to work dbda8d6ce9 2007-07-21 drh: ** work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be dbda8d6ce9 2007-07-21 drh: ** more efficient with one encoding than another. It is allowed to c287665ba8 2007-09-14 drh: ** invoke sqlite3_create_function() or sqlite3_create_function16() multiple dbda8d6ce9 2007-07-21 drh: ** times with the same function but with different values of eTextRep. dbda8d6ce9 2007-07-21 drh: ** When multiple implementations of the same function are available, SQLite dbda8d6ce9 2007-07-21 drh: ** will pick the one that involves the least amount of data conversion. dbda8d6ce9 2007-07-21 drh: ** If there is only a single implementation which does not care what dbda8d6ce9 2007-07-21 drh: ** text encoding is used, then the fourth argument should be dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ANY]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The fifth parameter is an arbitrary pointer. The implementation dbda8d6ce9 2007-07-21 drh: ** of the function can gain access to this pointer using c287665ba8 2007-09-14 drh: ** [sqlite3_user_data()]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are dbda8d6ce9 2007-07-21 drh: ** pointers to C-language functions that implement the SQL dbda8d6ce9 2007-07-21 drh: ** function or aggregate. A scalar SQL function requires an implementation of dbda8d6ce9 2007-07-21 drh: ** the xFunc callback only, NULL pointers should be passed as the xStep dbda8d6ce9 2007-07-21 drh: ** and xFinal parameters. An aggregate SQL function requires an implementation dbda8d6ce9 2007-07-21 drh: ** of xStep and xFinal and NULL should be passed for xFunc. To delete an dbda8d6ce9 2007-07-21 drh: ** existing SQL function or aggregate, pass NULL for all three function dbda8d6ce9 2007-07-21 drh: ** callback. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is permitted to register multiple implementations of the same dbda8d6ce9 2007-07-21 drh: ** functions with the same name but with either differing numbers of dbda8d6ce9 2007-07-21 drh: ** arguments or differing perferred text encodings. SQLite will use dbda8d6ce9 2007-07-21 drh: ** the implementation most closely matches the way in which the dbda8d6ce9 2007-07-21 drh: ** SQL function is used. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_function( dbda8d6ce9 2007-07-21 drh: sqlite3 *, dbda8d6ce9 2007-07-21 drh: const char *zFunctionName, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: int eTextRep, dbda8d6ce9 2007-07-21 drh: void*, dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value**), dbda8d6ce9 2007-07-21 drh: void (*xStep)(sqlite3_context*,int,sqlite3_value**), dbda8d6ce9 2007-07-21 drh: void (*xFinal)(sqlite3_context*) dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_function16( dbda8d6ce9 2007-07-21 drh: sqlite3*, dbda8d6ce9 2007-07-21 drh: const void *zFunctionName, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: int eTextRep, dbda8d6ce9 2007-07-21 drh: void*, dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value**), dbda8d6ce9 2007-07-21 drh: void (*xStep)(sqlite3_context*,int,sqlite3_value**), dbda8d6ce9 2007-07-21 drh: void (*xFinal)(sqlite3_context*) dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Text Encodings dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These constant define integer codes that represent the various dbda8d6ce9 2007-07-21 drh: ** text encodings supported by SQLite. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_UTF8 1 dbda8d6ce9 2007-07-21 drh: #define SQLITE_UTF16LE 2 dbda8d6ce9 2007-07-21 drh: #define SQLITE_UTF16BE 3 dbda8d6ce9 2007-07-21 drh: #define SQLITE_UTF16 4 /* Use native byte order */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ANY 5 /* sqlite3_create_function only */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Obsolete Functions dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These functions are all now obsolete. In order to maintain dbda8d6ce9 2007-07-21 drh: ** backwards compatibility with older code, we continue to support dbda8d6ce9 2007-07-21 drh: ** these functions. However, new development projects should avoid dbda8d6ce9 2007-07-21 drh: ** the use of these functions. To help encourage people to avoid dbda8d6ce9 2007-07-21 drh: ** using these functions, we are not going to tell you want they do. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_aggregate_count(sqlite3_context*); dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_expired(sqlite3_stmt*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_global_recover(void); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_thread_cleanup(void); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Obtaining SQL Function Parameter Values dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The C-language implementation of SQL functions and aggregates uses dbda8d6ce9 2007-07-21 drh: ** this set of interface routines to access the parameter values on dbda8d6ce9 2007-07-21 drh: ** the function or aggregate. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The xFunc (for scalar functions) or xStep (for aggregates) parameters dbda8d6ce9 2007-07-21 drh: ** to [sqlite3_create_function()] and [sqlite3_create_function16()] dbda8d6ce9 2007-07-21 drh: ** define callbacks that implement the SQL functions and aggregates. dbda8d6ce9 2007-07-21 drh: ** The 4th parameter to these callbacks is an array of pointers to dbda8d6ce9 2007-07-21 drh: ** [sqlite3_value] objects. There is one [sqlite3_value] object for dbda8d6ce9 2007-07-21 drh: ** each parameter to the SQL function. These routines are used to dbda8d6ce9 2007-07-21 drh: ** extract values from the [sqlite3_value] objects. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines work just like the corresponding dbda8d6ce9 2007-07-21 drh: ** [sqlite3_column_blob | sqlite3_column_* routines] except that dbda8d6ce9 2007-07-21 drh: ** these routines take a single [sqlite3_value*] pointer instead dbda8d6ce9 2007-07-21 drh: ** of an [sqlite3_stmt*] pointer and an integer column number. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_value_text16() interface extracts a UTF16 string dbda8d6ce9 2007-07-21 drh: ** in the native byte-order of the host machine. The dbda8d6ce9 2007-07-21 drh: ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces dbda8d6ce9 2007-07-21 drh: ** extract UTF16 strings as big-endian and little-endian respectively. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_value_numeric_type() interface attempts to apply dbda8d6ce9 2007-07-21 drh: ** numeric affinity to the value. This means that an attempt is dbda8d6ce9 2007-07-21 drh: ** made to convert the value to an integer or floating point. If dbda8d6ce9 2007-07-21 drh: ** such a conversion is possible without loss of information (in order dbda8d6ce9 2007-07-21 drh: ** words if the value is original a string that looks like a number) dbda8d6ce9 2007-07-21 drh: ** then it is done. Otherwise no conversion occurs. The dbda8d6ce9 2007-07-21 drh: ** [SQLITE_INTEGER | datatype] after conversion is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Please pay particular attention to the fact that the pointer that dbda8d6ce9 2007-07-21 drh: ** is returned from [sqlite3_value_blob()], [sqlite3_value_text()], or dbda8d6ce9 2007-07-21 drh: ** [sqlite3_value_text16()] can be invalidated by a subsequent call to c287665ba8 2007-09-14 drh: ** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], dbda8d6ce9 2007-07-21 drh: ** or [sqlite3_value_text16()]. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** These routines must be called from the same thread as c287665ba8 2007-09-14 drh: ** the SQL function that supplied the sqlite3_value* parameters. c287665ba8 2007-09-14 drh: ** Or, if the sqlite3_value* argument comes from the [sqlite3_column_value()] c287665ba8 2007-09-14 drh: ** interface, then these routines should be called from the same thread c287665ba8 2007-09-14 drh: ** that ran [sqlite3_column_value()]. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_bytes(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API double sqlite3_value_double(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_int(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_type(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Obtain Aggregate Function Context dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The implementation of aggregate SQL functions use this routine to allocate dbda8d6ce9 2007-07-21 drh: ** a structure for storing their state. The first time this routine dbda8d6ce9 2007-07-21 drh: ** is called for a particular aggregate, a new structure of size nBytes dbda8d6ce9 2007-07-21 drh: ** is allocated, zeroed, and returned. On subsequent calls (for the dbda8d6ce9 2007-07-21 drh: ** same aggregate instance) the same buffer is returned. The implementation dbda8d6ce9 2007-07-21 drh: ** of the aggregate can use the returned buffer to accumulate data. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The buffer allocated is freed automatically by SQLite whan the aggregate dbda8d6ce9 2007-07-21 drh: ** query concludes. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first parameter should be a copy of the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_context | SQL function context] that is the first dbda8d6ce9 2007-07-21 drh: ** parameter to the callback routine that implements the aggregate dbda8d6ce9 2007-07-21 drh: ** function. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine must be called from the same thread in which c287665ba8 2007-09-14 drh: ** the aggregate SQL function is running. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: User Data For Functions dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pUserData parameter to the [sqlite3_create_function()] dbda8d6ce9 2007-07-21 drh: ** and [sqlite3_create_function16()] routines dbda8d6ce9 2007-07-21 drh: ** used to register user functions is available to dbda8d6ce9 2007-07-21 drh: ** the implementation of the function using this call. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine must be called from the same thread in which c287665ba8 2007-09-14 drh: ** the SQL function is running. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_user_data(sqlite3_context*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Function Auxiliary Data dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following two functions may be used by scalar SQL functions to dbda8d6ce9 2007-07-21 drh: ** associate meta-data with argument values. If the same value is passed to dbda8d6ce9 2007-07-21 drh: ** multiple invocations of the same SQL function during query execution, under dbda8d6ce9 2007-07-21 drh: ** some circumstances the associated meta-data may be preserved. This may dbda8d6ce9 2007-07-21 drh: ** be used, for example, to add a regular-expression matching scalar dbda8d6ce9 2007-07-21 drh: ** function. The compiled version of the regular expression is stored as dbda8d6ce9 2007-07-21 drh: ** meta-data associated with the SQL value passed as the regular expression dbda8d6ce9 2007-07-21 drh: ** pattern. The compiled regular expression can be reused on multiple dbda8d6ce9 2007-07-21 drh: ** invocations of the same function so that the original pattern string dbda8d6ce9 2007-07-21 drh: ** does not need to be recompiled on each invocation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_get_auxdata() interface returns a pointer to the meta-data dbda8d6ce9 2007-07-21 drh: ** associated with the Nth argument value to the current SQL function dbda8d6ce9 2007-07-21 drh: ** call, where N is the second parameter. If no meta-data has been set for dbda8d6ce9 2007-07-21 drh: ** that value, then a NULL pointer is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_set_auxdata() is used to associate meta-data with an SQL dbda8d6ce9 2007-07-21 drh: ** function argument. The third parameter is a pointer to the meta-data dbda8d6ce9 2007-07-21 drh: ** to be associated with the Nth user function argument value. The fourth dbda8d6ce9 2007-07-21 drh: ** parameter specifies a destructor that will be called on the meta- dbda8d6ce9 2007-07-21 drh: ** data pointer to release it when it is no longer required. If the dbda8d6ce9 2007-07-21 drh: ** destructor is NULL, it is not invoked. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In practice, meta-data is preserved between function calls for dbda8d6ce9 2007-07-21 drh: ** expressions that are constant at compile time. This includes literal dbda8d6ce9 2007-07-21 drh: ** values and SQL variables. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** These routines must be called from the same thread in which c287665ba8 2007-09-14 drh: ** the SQL function is running. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Constants Defining Special Destructor Behavior dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These are special value for the destructor that is passed in as the dbda8d6ce9 2007-07-21 drh: ** final argument to routines like [sqlite3_result_blob()]. If the destructor dbda8d6ce9 2007-07-21 drh: ** argument is SQLITE_STATIC, it means that the content pointer is constant dbda8d6ce9 2007-07-21 drh: ** and will never change. It does not need to be destroyed. The dbda8d6ce9 2007-07-21 drh: ** SQLITE_TRANSIENT value means that the content will likely change in dbda8d6ce9 2007-07-21 drh: ** the near future and that SQLite should make its own private copy of dbda8d6ce9 2007-07-21 drh: ** the content before returning. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The typedef is necessary to work around problems in certain dbda8d6ce9 2007-07-21 drh: ** C++ compilers. See ticket #2191. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef void (*sqlite3_destructor_type)(void*); dbda8d6ce9 2007-07-21 drh: #define SQLITE_STATIC ((sqlite3_destructor_type)0) dbda8d6ce9 2007-07-21 drh: #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Setting The Result Of An SQL Function dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines are used by the xFunc or xFinal callbacks that dbda8d6ce9 2007-07-21 drh: ** implement SQL functions and aggregates. See dbda8d6ce9 2007-07-21 drh: ** [sqlite3_create_function()] and [sqlite3_create_function16()] dbda8d6ce9 2007-07-21 drh: ** for additional information. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These functions work very much like the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_bind_blob | sqlite3_bind_*] family of functions used dbda8d6ce9 2007-07-21 drh: ** to bind values to host parameters in prepared statements. dbda8d6ce9 2007-07-21 drh: ** Refer to the dbda8d6ce9 2007-07-21 drh: ** [sqlite3_bind_blob | sqlite3_bind_* documentation] for dbda8d6ce9 2007-07-21 drh: ** additional information. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_result_error() and sqlite3_result_error16() functions dbda8d6ce9 2007-07-21 drh: ** cause the implemented SQL function to throw an exception. The dbda8d6ce9 2007-07-21 drh: ** parameter to sqlite3_result_error() or sqlite3_result_error16() dbda8d6ce9 2007-07-21 drh: ** is the text of an error message. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_result_toobig() cause the function implementation dbda8d6ce9 2007-07-21 drh: ** to throw and error indicating that a string or BLOB is to long dbda8d6ce9 2007-07-21 drh: ** to represent. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** These routines must be called from within the same thread as c287665ba8 2007-09-14 drh: ** the SQL function associated with the [sqlite3_context] pointer. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_double(sqlite3_context*, double); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_int(sqlite3_context*, int); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_null(sqlite3_context*); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Define New Collating Sequences dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These functions are used to add new collation sequences to the dbda8d6ce9 2007-07-21 drh: ** [sqlite3*] handle specified as the first argument. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The name of the new collation sequence is specified as a UTF-8 string dbda8d6ce9 2007-07-21 drh: ** for sqlite3_create_collation() and sqlite3_create_collation_v2() dbda8d6ce9 2007-07-21 drh: ** and a UTF-16 string for sqlite3_create_collation16(). In all cases dbda8d6ce9 2007-07-21 drh: ** the name is passed as the second function argument. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The third argument must be one of the constants [SQLITE_UTF8], dbda8d6ce9 2007-07-21 drh: ** [SQLITE_UTF16LE] or [SQLITE_UTF16BE], indicating that the user-supplied dbda8d6ce9 2007-07-21 drh: ** routine expects to be passed pointers to strings encoded using UTF-8, dbda8d6ce9 2007-07-21 drh: ** UTF-16 little-endian or UTF-16 big-endian respectively. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A pointer to the user supplied routine must be passed as the fifth dbda8d6ce9 2007-07-21 drh: ** argument. If it is NULL, this is the same as deleting the collation dbda8d6ce9 2007-07-21 drh: ** sequence (so that SQLite cannot call it anymore). Each time the user dbda8d6ce9 2007-07-21 drh: ** supplied function is invoked, it is passed a copy of the void* passed as dbda8d6ce9 2007-07-21 drh: ** the fourth argument to sqlite3_create_collation() or dbda8d6ce9 2007-07-21 drh: ** sqlite3_create_collation16() as its first parameter. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The remaining arguments to the user-supplied routine are two strings, dbda8d6ce9 2007-07-21 drh: ** each represented by a [length, data] pair and encoded in the encoding dbda8d6ce9 2007-07-21 drh: ** that was passed as the third argument when the collation sequence was dbda8d6ce9 2007-07-21 drh: ** registered. The user routine should return negative, zero or positive if dbda8d6ce9 2007-07-21 drh: ** the first string is less than, equal to, or greater than the second dbda8d6ce9 2007-07-21 drh: ** string. i.e. (STRING1 - STRING2). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_create_collation_v2() works like sqlite3_create_collation() dbda8d6ce9 2007-07-21 drh: ** excapt that it takes an extra argument which is a destructor for dbda8d6ce9 2007-07-21 drh: ** the collation. The destructor is called when the collation is dbda8d6ce9 2007-07-21 drh: ** destroyed and is passed a copy of the fourth parameter void* pointer dbda8d6ce9 2007-07-21 drh: ** of the sqlite3_create_collation_v2(). Collations are destroyed when dbda8d6ce9 2007-07-21 drh: ** they are overridden by later calls to the collation creation functions dbda8d6ce9 2007-07-21 drh: ** or when the [sqlite3*] database handle is closed using [sqlite3_close()]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_create_collation_v2() interface is experimental and dbda8d6ce9 2007-07-21 drh: ** subject to change in future releases. The other collation creation dbda8d6ce9 2007-07-21 drh: ** functions are stable. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_collation( dbda8d6ce9 2007-07-21 drh: sqlite3*, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int eTextRep, dbda8d6ce9 2007-07-21 drh: void*, dbda8d6ce9 2007-07-21 drh: int(*xCompare)(void*,int,const void*,int,const void*) dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_collation_v2( dbda8d6ce9 2007-07-21 drh: sqlite3*, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int eTextRep, dbda8d6ce9 2007-07-21 drh: void*, dbda8d6ce9 2007-07-21 drh: int(*xCompare)(void*,int,const void*,int,const void*), dbda8d6ce9 2007-07-21 drh: void(*xDestroy)(void*) dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_collation16( dbda8d6ce9 2007-07-21 drh: sqlite3*, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int eTextRep, dbda8d6ce9 2007-07-21 drh: void*, dbda8d6ce9 2007-07-21 drh: int(*xCompare)(void*,int,const void*,int,const void*) dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Collation Needed Callbacks dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To avoid having to register all collation sequences before a database dbda8d6ce9 2007-07-21 drh: ** can be used, a single callback function may be registered with the dbda8d6ce9 2007-07-21 drh: ** database handle to be called whenever an undefined collation sequence is dbda8d6ce9 2007-07-21 drh: ** required. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the function is registered using the sqlite3_collation_needed() API, dbda8d6ce9 2007-07-21 drh: ** then it is passed the names of undefined collation sequences as strings dbda8d6ce9 2007-07-21 drh: ** encoded in UTF-8. If sqlite3_collation_needed16() is used, the names dbda8d6ce9 2007-07-21 drh: ** are passed as UTF-16 in machine native byte order. A call to either dbda8d6ce9 2007-07-21 drh: ** function replaces any existing callback. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When the callback is invoked, the first argument passed is a copy dbda8d6ce9 2007-07-21 drh: ** of the second argument to sqlite3_collation_needed() or dbda8d6ce9 2007-07-21 drh: ** sqlite3_collation_needed16(). The second argument is the database dbda8d6ce9 2007-07-21 drh: ** handle. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE], or dbda8d6ce9 2007-07-21 drh: ** [SQLITE_UTF16LE], indicating the most desirable form of the collation dbda8d6ce9 2007-07-21 drh: ** sequence function required. The fourth parameter is the name of the dbda8d6ce9 2007-07-21 drh: ** required collation sequence. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The callback function should register the desired collation using dbda8d6ce9 2007-07-21 drh: ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or dbda8d6ce9 2007-07-21 drh: ** [sqlite3_create_collation_v2()]. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_collation_needed( dbda8d6ce9 2007-07-21 drh: sqlite3*, dbda8d6ce9 2007-07-21 drh: void*, dbda8d6ce9 2007-07-21 drh: void(*)(void*,sqlite3*,int eTextRep,const char*) dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_collation_needed16( dbda8d6ce9 2007-07-21 drh: sqlite3*, dbda8d6ce9 2007-07-21 drh: void*, dbda8d6ce9 2007-07-21 drh: void(*)(void*,sqlite3*,int eTextRep,const void*) dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Specify the key for an encrypted database. This routine should be dbda8d6ce9 2007-07-21 drh: ** called right after sqlite3_open(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code to implement this API is not available in the public release dbda8d6ce9 2007-07-21 drh: ** of SQLite. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_key( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database to be rekeyed */ dbda8d6ce9 2007-07-21 drh: const void *pKey, int nKey /* The key */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the key on an open database. If the current database is not dbda8d6ce9 2007-07-21 drh: ** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the dbda8d6ce9 2007-07-21 drh: ** database is decrypted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code to implement this API is not available in the public release dbda8d6ce9 2007-07-21 drh: ** of SQLite. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_rekey( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database to be rekeyed */ dbda8d6ce9 2007-07-21 drh: const void *pKey, int nKey /* The new key */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Suspend Execution For A Short Time dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function causes the current thread to suspend execution dbda8d6ce9 2007-07-21 drh: ** a number of milliseconds specified in its parameter. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the operating system does not support sleep requests with dbda8d6ce9 2007-07-21 drh: ** millisecond time resolution, then the time will be rounded up to dbda8d6ce9 2007-07-21 drh: ** the nearest second. The number of milliseconds of sleep actually dbda8d6ce9 2007-07-21 drh: ** requested from the operating system is returned. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLite implements this interface by calling the xSleep() c287665ba8 2007-09-14 drh: ** method of the default [sqlite3_vfs] object. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_sleep(int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Name Of The Folder Holding Temporary Files dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If this global variable is made to point to a string which is dbda8d6ce9 2007-07-21 drh: ** the name of a folder (a.ka. directory), then all temporary files dbda8d6ce9 2007-07-21 drh: ** created by SQLite will be placed in that directory. If this variable dbda8d6ce9 2007-07-21 drh: ** is NULL pointer, then SQLite does a search for an appropriate temporary dbda8d6ce9 2007-07-21 drh: ** file directory. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** It is not safe to modify this variable once a database connection c287665ba8 2007-09-14 drh: ** has been opened. It is intended that this variable be set once c287665ba8 2007-09-14 drh: ** as part of process initialization and before any SQLite interface c287665ba8 2007-09-14 drh: ** routines have been call and remain unchanged thereafter. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_EXTERN char *sqlite3_temp_directory; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Test To See If The Database Is In Auto-Commit Mode dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Test to see whether or not the database connection is in autocommit dbda8d6ce9 2007-07-21 drh: ** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on dbda8d6ce9 2007-07-21 drh: ** by default. Autocommit is disabled by a BEGIN statement and reenabled dbda8d6ce9 2007-07-21 drh: ** by the next COMMIT or ROLLBACK. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If another thread changes the autocommit status of the database c287665ba8 2007-09-14 drh: ** connection while this routine is running, then the return value c287665ba8 2007-09-14 drh: ** is undefined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_get_autocommit(sqlite3*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Find The Database Handle Associated With A Prepared Statement dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the [sqlite3*] database handle to which a dbda8d6ce9 2007-07-21 drh: ** [sqlite3_stmt | prepared statement] belongs. dbda8d6ce9 2007-07-21 drh: ** This is the same database handle that was dbda8d6ce9 2007-07-21 drh: ** the first argument to the [sqlite3_prepare_v2()] or its variants dbda8d6ce9 2007-07-21 drh: ** that was used to create the statement in the first place. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Commit And Rollback Notification Callbacks dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines dbda8d6ce9 2007-07-21 drh: ** register callback functions to be invoked whenever a transaction dbda8d6ce9 2007-07-21 drh: ** is committed or rolled back. The pArg argument is passed through dbda8d6ce9 2007-07-21 drh: ** to the callback. If the callback on a commit hook function dbda8d6ce9 2007-07-21 drh: ** returns non-zero, then the commit is converted into a rollback. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If another function was previously registered, its pArg value is returned. dbda8d6ce9 2007-07-21 drh: ** Otherwise NULL is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Registering a NULL function disables the callback. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For the purposes of this API, a transaction is said to have been dbda8d6ce9 2007-07-21 drh: ** rolled back if an explicit "ROLLBACK" statement is executed, or dbda8d6ce9 2007-07-21 drh: ** an error or constraint causes an implicit rollback to occur. The dbda8d6ce9 2007-07-21 drh: ** callback is not invoked if a transaction is automatically rolled dbda8d6ce9 2007-07-21 drh: ** back because the database connection is closed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These are experimental interfaces and are subject to change. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Data Change Notification Callbacks dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Register a callback function with the database connection identified by the dbda8d6ce9 2007-07-21 drh: ** first argument to be invoked whenever a row is updated, inserted or deleted. dbda8d6ce9 2007-07-21 drh: ** Any callback set by a previous call to this function for the same dbda8d6ce9 2007-07-21 drh: ** database connection is overridden. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The second argument is a pointer to the function to invoke when a dbda8d6ce9 2007-07-21 drh: ** row is updated, inserted or deleted. The first argument to the callback is dbda8d6ce9 2007-07-21 drh: ** a copy of the third argument to sqlite3_update_hook(). The second callback dbda8d6ce9 2007-07-21 drh: ** argument is one of SQLITE_INSERT, SQLITE_DELETE or SQLITE_UPDATE, depending dbda8d6ce9 2007-07-21 drh: ** on the operation that caused the callback to be invoked. The third and dbda8d6ce9 2007-07-21 drh: ** fourth arguments to the callback contain pointers to the database and dbda8d6ce9 2007-07-21 drh: ** table name containing the affected row. The final callback parameter is dbda8d6ce9 2007-07-21 drh: ** the rowid of the row. In the case of an update, this is the rowid after dbda8d6ce9 2007-07-21 drh: ** the update takes place. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The update hook is not invoked when internal system tables are dbda8d6ce9 2007-07-21 drh: ** modified (i.e. sqlite_master and sqlite_sequence). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If another function was previously registered, its pArg value is returned. dbda8d6ce9 2007-07-21 drh: ** Otherwise NULL is returned. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_update_hook( dbda8d6ce9 2007-07-21 drh: sqlite3*, c287665ba8 2007-09-14 drh: void(*)(void *,int ,char const *,char const *,sqlite3_int64), dbda8d6ce9 2007-07-21 drh: void* dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Enable Or Disable Shared Pager Cache dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine enables or disables the sharing of the database cache dbda8d6ce9 2007-07-21 drh: ** and schema data structures between connections to the same database. dbda8d6ce9 2007-07-21 drh: ** Sharing is enabled if the argument is true and disabled if the argument dbda8d6ce9 2007-07-21 drh: ** is false. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Beginning in SQLite version 3.5.0, cache sharing is enabled and disabled c287665ba8 2007-09-14 drh: ** for an entire process. In prior versions of SQLite, sharing was c287665ba8 2007-09-14 drh: ** enabled or disabled for each thread separately. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The cache sharing mode set by this interface effects all subsequent c287665ba8 2007-09-14 drh: ** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. c287665ba8 2007-09-14 drh: ** Existing database connections continue use the sharing mode that was c287665ba8 2007-09-14 drh: ** in effect at the time they were opened. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Virtual tables cannot be used with a shared cache. When shared c287665ba8 2007-09-14 drh: ** cache is enabled, the [sqlite3_create_module()] API used to register dbda8d6ce9 2007-07-21 drh: ** virtual tables will always return an error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns [SQLITE_OK] if shared cache was dbda8d6ce9 2007-07-21 drh: ** enabled or disabled successfully. An [SQLITE_ERROR | error code] dbda8d6ce9 2007-07-21 drh: ** is returned otherwise. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Shared cache is disabled by default. But this might change in c287665ba8 2007-09-14 drh: ** future releases of SQLite. Applications that care about shared c287665ba8 2007-09-14 drh: ** cache setting should set it explicitly. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_enable_shared_cache(int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Attempt To Free Heap Memory dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Attempt to free N bytes of heap memory by deallocating non-essential dbda8d6ce9 2007-07-21 drh: ** memory allocations held by the database library (example: memory dbda8d6ce9 2007-07-21 drh: ** used to cache database pages to improve performance). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_release_memory(int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Impose A Limit On Heap Size dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Place a "soft" limit on the amount of heap memory that may be allocated c287665ba8 2007-09-14 drh: ** by SQLite. If an internal allocation is requested c287665ba8 2007-09-14 drh: ** that would exceed the specified limit, [sqlite3_release_memory()] is c287665ba8 2007-09-14 drh: ** invoked one or more times to free up some space before the allocation c287665ba8 2007-09-14 drh: ** is made. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The limit is called "soft", because if [sqlite3_release_memory()] cannot c287665ba8 2007-09-14 drh: ** free sufficient memory to prevent the limit from being exceeded, c287665ba8 2007-09-14 drh: ** the memory is allocated anyway and the current operation proceeds. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A negative or zero value for N means that there is no soft heap limit and c287665ba8 2007-09-14 drh: ** [sqlite3_release_memory()] will only be called when memory is exhausted. dbda8d6ce9 2007-07-21 drh: ** The default value for the soft heap limit is zero. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite makes a best effort to honor the soft heap limit. But if it dbda8d6ce9 2007-07-21 drh: ** is unable to reduce memory usage below the soft limit, execution will dbda8d6ce9 2007-07-21 drh: ** continue without error or notification. This is why the limit is dbda8d6ce9 2007-07-21 drh: ** called a "soft" limit. It is advisory only. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** The soft heap limit is implemented using the [sqlite3_memory_alarm()] c287665ba8 2007-09-14 drh: ** interface. Only a single memory alarm is available in the default c287665ba8 2007-09-14 drh: ** implementation. This means that if the application also uses the c287665ba8 2007-09-14 drh: ** memory alarm interface it will interfere with the operation of the c287665ba8 2007-09-14 drh: ** soft heap limit and undefined behavior will result. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Prior to SQLite version 3.5.0, this routine only constrained the memory c287665ba8 2007-09-14 drh: ** allocated by a single thread - the same thread in which this routine c287665ba8 2007-09-14 drh: ** runs. Beginning with SQLite version 3.5.0, the soft heap limit is c287665ba8 2007-09-14 drh: ** applied to all threads. The value specified for the soft heap limit c287665ba8 2007-09-14 drh: ** is an upper bound on the total memory allocation for all threads. In c287665ba8 2007-09-14 drh: ** version 3.5.0 there is no mechanism for limiting the heap usage for c287665ba8 2007-09-14 drh: ** individual threads. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_soft_heap_limit(int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Extract Metadata About A Column Of A Table dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine dbda8d6ce9 2007-07-21 drh: ** returns meta-data about a specific column of a specific database dbda8d6ce9 2007-07-21 drh: ** table accessible using the connection handle passed as the first function dbda8d6ce9 2007-07-21 drh: ** argument. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The column is identified by the second, third and fourth parameters to dbda8d6ce9 2007-07-21 drh: ** this function. The second parameter is either the name of the database dbda8d6ce9 2007-07-21 drh: ** (i.e. "main", "temp" or an attached database) containing the specified dbda8d6ce9 2007-07-21 drh: ** table or NULL. If it is NULL, then all attached databases are searched dbda8d6ce9 2007-07-21 drh: ** for the table using the same algorithm as the database engine uses to dbda8d6ce9 2007-07-21 drh: ** resolve unqualified table references. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The third and fourth parameters to this function are the table and column dbda8d6ce9 2007-07-21 drh: ** name of the desired column, respectively. Neither of these parameters dbda8d6ce9 2007-07-21 drh: ** may be NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Meta information is returned by writing to the memory locations passed as dbda8d6ce9 2007-07-21 drh: ** the 5th and subsequent parameters to this function. Any of these dbda8d6ce9 2007-07-21 drh: ** arguments may be NULL, in which case the corresponding element of meta dbda8d6ce9 2007-07-21 drh: ** information is ommitted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <pre> dbda8d6ce9 2007-07-21 drh: ** Parameter Output Type Description dbda8d6ce9 2007-07-21 drh: ** ----------------------------------- dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 5th const char* Data type dbda8d6ce9 2007-07-21 drh: ** 6th const char* Name of the default collation sequence dbda8d6ce9 2007-07-21 drh: ** 7th int True if the column has a NOT NULL constraint dbda8d6ce9 2007-07-21 drh: ** 8th int True if the column is part of the PRIMARY KEY dbda8d6ce9 2007-07-21 drh: ** 9th int True if the column is AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: ** </pre> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The memory pointed to by the character pointers returned for the dbda8d6ce9 2007-07-21 drh: ** declaration type and collation sequence is valid only until the next dbda8d6ce9 2007-07-21 drh: ** call to any sqlite API function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the specified table is actually a view, then an error is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the specified column is "rowid", "oid" or "_rowid_" and an dbda8d6ce9 2007-07-21 drh: ** INTEGER PRIMARY KEY column has been explicitly declared, then the output dbda8d6ce9 2007-07-21 drh: ** parameters are set for the explicitly declared column. If there is no dbda8d6ce9 2007-07-21 drh: ** explicitly declared IPK column, then the output parameters are set as dbda8d6ce9 2007-07-21 drh: ** follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <pre> dbda8d6ce9 2007-07-21 drh: ** data type: "INTEGER" dbda8d6ce9 2007-07-21 drh: ** collation sequence: "BINARY" dbda8d6ce9 2007-07-21 drh: ** not null: 0 dbda8d6ce9 2007-07-21 drh: ** primary key: 1 dbda8d6ce9 2007-07-21 drh: ** auto increment: 0 dbda8d6ce9 2007-07-21 drh: ** </pre> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function may load one or more schemas from database files. If an dbda8d6ce9 2007-07-21 drh: ** error occurs during this process, or if the requested table or column dbda8d6ce9 2007-07-21 drh: ** cannot be found, an SQLITE error code is returned and an error message dbda8d6ce9 2007-07-21 drh: ** left in the database handle (to be retrieved using sqlite3_errmsg()). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This API is only available if the library was compiled with the dbda8d6ce9 2007-07-21 drh: ** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_table_column_metadata( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Connection handle */ dbda8d6ce9 2007-07-21 drh: const char *zDbName, /* Database name or NULL */ dbda8d6ce9 2007-07-21 drh: const char *zTableName, /* Table name */ dbda8d6ce9 2007-07-21 drh: const char *zColumnName, /* Column name */ dbda8d6ce9 2007-07-21 drh: char const **pzDataType, /* OUTPUT: Declared data type */ dbda8d6ce9 2007-07-21 drh: char const **pzCollSeq, /* OUTPUT: Collation sequence name */ dbda8d6ce9 2007-07-21 drh: int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ dbda8d6ce9 2007-07-21 drh: int *pPrimaryKey, /* OUTPUT: True if column part of PK */ dbda8d6ce9 2007-07-21 drh: int *pAutoinc /* OUTPUT: True if colums is auto-increment */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Load An Extension dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Attempt to load an SQLite extension library contained in the file dbda8d6ce9 2007-07-21 drh: ** zFile. The entry point is zProc. zProc may be 0 in which case the dbda8d6ce9 2007-07-21 drh: ** name of the entry point defaults to "sqlite3_extension_init". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with dbda8d6ce9 2007-07-21 drh: ** error message text. The calling function should free this memory dbda8d6ce9 2007-07-21 drh: ** by calling [sqlite3_free()]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Extension loading must be enabled using [sqlite3_enable_load_extension()] dbda8d6ce9 2007-07-21 drh: ** prior to calling this API or an error will be returned. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_load_extension( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Load the extension into this database connection */ dbda8d6ce9 2007-07-21 drh: const char *zFile, /* Name of the shared library containing extension */ dbda8d6ce9 2007-07-21 drh: const char *zProc, /* Entry point. Derived from zFile if 0 */ dbda8d6ce9 2007-07-21 drh: char **pzErrMsg /* Put error message here if not 0 */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Enable Or Disable Extension Loading dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** So as not to open security holes in older applications that are dbda8d6ce9 2007-07-21 drh: ** unprepared to deal with extension loading, and as a means of disabling dbda8d6ce9 2007-07-21 drh: ** extension loading while evaluating user-entered SQL, the following dbda8d6ce9 2007-07-21 drh: ** API is provided to turn the [sqlite3_load_extension()] mechanism on and dbda8d6ce9 2007-07-21 drh: ** off. It is off by default. See ticket #1863. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Call this routine with onoff==1 to turn extension loading on dbda8d6ce9 2007-07-21 drh: ** and call it with onoff==0 to turn it back off again. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Make Arrangements To Automatically Load An Extension dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Register an extension entry point that is automatically invoked dbda8d6ce9 2007-07-21 drh: ** whenever a new database connection is opened using c287665ba8 2007-09-14 drh: ** [sqlite3_open()], [sqlite3_open16()], or [sqlite3_open_v2()]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This API can be invoked at program startup in order to register dbda8d6ce9 2007-07-21 drh: ** one or more statically linked extensions that will be available dbda8d6ce9 2007-07-21 drh: ** to all new database connections. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Duplicate extensions are detected so calling this routine multiple dbda8d6ce9 2007-07-21 drh: ** times with the same extension is harmless. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine stores a pointer to the extension in an array dbda8d6ce9 2007-07-21 drh: ** that is obtained from malloc(). If you run a memory leak dbda8d6ce9 2007-07-21 drh: ** checker on your program and it reports a leak because of this dbda8d6ce9 2007-07-21 drh: ** array, then invoke [sqlite3_automatic_extension_reset()] prior dbda8d6ce9 2007-07-21 drh: ** to shutdown to free the memory. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Automatic extensions apply across all threads. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This interface is experimental and is subject to change or dbda8d6ce9 2007-07-21 drh: ** removal in future releases of SQLite. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_auto_extension(void *xEntryPoint); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Reset Automatic Extension Loading dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Disable all previously registered automatic extensions. This dbda8d6ce9 2007-07-21 drh: ** routine undoes the effect of all prior [sqlite3_automatic_extension()] dbda8d6ce9 2007-07-21 drh: ** calls. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This call disabled automatic extensions in all threads. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This interface is experimental and is subject to change or dbda8d6ce9 2007-07-21 drh: ** removal in future releases of SQLite. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_reset_auto_extension(void); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ****** EXPERIMENTAL - subject to change without notice ************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The interface to the virtual-table mechanism is currently considered dbda8d6ce9 2007-07-21 drh: ** to be experimental. The interface might change in incompatible ways. dbda8d6ce9 2007-07-21 drh: ** If this is a problem for you, do not use the interface at this time. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When the virtual-table mechanism stablizes, we will declare the dbda8d6ce9 2007-07-21 drh: ** interface fixed, support it indefinitely, and remove this comment. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Structures used by the virtual table interface dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3_vtab sqlite3_vtab; dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3_index_info sqlite3_index_info; dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3_module sqlite3_module; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A module is a class of virtual tables. Each module is defined dbda8d6ce9 2007-07-21 drh: ** by an instance of the following structure. This structure consists dbda8d6ce9 2007-07-21 drh: ** mostly of methods for the module. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct sqlite3_module { dbda8d6ce9 2007-07-21 drh: int iVersion; dbda8d6ce9 2007-07-21 drh: int (*xCreate)(sqlite3*, void *pAux, dbda8d6ce9 2007-07-21 drh: int argc, const char *const*argv, dbda8d6ce9 2007-07-21 drh: sqlite3_vtab **ppVTab, char**); dbda8d6ce9 2007-07-21 drh: int (*xConnect)(sqlite3*, void *pAux, dbda8d6ce9 2007-07-21 drh: int argc, const char *const*argv, dbda8d6ce9 2007-07-21 drh: sqlite3_vtab **ppVTab, char**); dbda8d6ce9 2007-07-21 drh: int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); dbda8d6ce9 2007-07-21 drh: int (*xDisconnect)(sqlite3_vtab *pVTab); dbda8d6ce9 2007-07-21 drh: int (*xDestroy)(sqlite3_vtab *pVTab); dbda8d6ce9 2007-07-21 drh: int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); dbda8d6ce9 2007-07-21 drh: int (*xClose)(sqlite3_vtab_cursor*); dbda8d6ce9 2007-07-21 drh: int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, dbda8d6ce9 2007-07-21 drh: int argc, sqlite3_value **argv); dbda8d6ce9 2007-07-21 drh: int (*xNext)(sqlite3_vtab_cursor*); dbda8d6ce9 2007-07-21 drh: int (*xEof)(sqlite3_vtab_cursor*); dbda8d6ce9 2007-07-21 drh: int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); c287665ba8 2007-09-14 drh: int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); c287665ba8 2007-09-14 drh: int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); dbda8d6ce9 2007-07-21 drh: int (*xBegin)(sqlite3_vtab *pVTab); dbda8d6ce9 2007-07-21 drh: int (*xSync)(sqlite3_vtab *pVTab); dbda8d6ce9 2007-07-21 drh: int (*xCommit)(sqlite3_vtab *pVTab); dbda8d6ce9 2007-07-21 drh: int (*xRollback)(sqlite3_vtab *pVTab); dbda8d6ce9 2007-07-21 drh: int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, dbda8d6ce9 2007-07-21 drh: void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), dbda8d6ce9 2007-07-21 drh: void **ppArg); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The sqlite3_index_info structure and its substructures is used to dbda8d6ce9 2007-07-21 drh: ** pass information into and receive the reply from the xBestIndex dbda8d6ce9 2007-07-21 drh: ** method of an sqlite3_module. The fields under **Inputs** are the dbda8d6ce9 2007-07-21 drh: ** inputs to xBestIndex and are read-only. xBestIndex inserts its dbda8d6ce9 2007-07-21 drh: ** results into the **Outputs** fields. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The aConstraint[] array records WHERE clause constraints of the dbda8d6ce9 2007-07-21 drh: ** form: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** column OP expr dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Where OP is =, <, <=, >, or >=. The particular operator is stored dbda8d6ce9 2007-07-21 drh: ** in aConstraint[].op. The index of the column is stored in dbda8d6ce9 2007-07-21 drh: ** aConstraint[].iColumn. aConstraint[].usable is TRUE if the dbda8d6ce9 2007-07-21 drh: ** expr on the right-hand side can be evaluated (and thus the constraint dbda8d6ce9 2007-07-21 drh: ** is usable) and false if it cannot. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The optimizer automatically inverts terms of the form "expr OP column" dbda8d6ce9 2007-07-21 drh: ** and makes other simplificatinos to the WHERE clause in an attempt to dbda8d6ce9 2007-07-21 drh: ** get as many WHERE clause terms into the form shown above as possible. dbda8d6ce9 2007-07-21 drh: ** The aConstraint[] array only reports WHERE clause terms in the correct dbda8d6ce9 2007-07-21 drh: ** form that refer to the particular virtual table being queried. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Information about the ORDER BY clause is stored in aOrderBy[]. dbda8d6ce9 2007-07-21 drh: ** Each term of aOrderBy records a column of the ORDER BY clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The xBestIndex method must fill aConstraintUsage[] with information dbda8d6ce9 2007-07-21 drh: ** about what parameters to pass to xFilter. If argvIndex>0 then dbda8d6ce9 2007-07-21 drh: ** the right-hand side of the corresponding aConstraint[] is evaluated dbda8d6ce9 2007-07-21 drh: ** and becomes the argvIndex-th entry in argv. If aConstraintUsage[].omit dbda8d6ce9 2007-07-21 drh: ** is true, then the constraint is assumed to be fully handled by the dbda8d6ce9 2007-07-21 drh: ** virtual table and is not checked again by SQLite. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The idxNum and idxPtr values are recorded and passed into xFilter. dbda8d6ce9 2007-07-21 drh: ** sqlite3_free() is used to free idxPtr if needToFreeIdxPtr is true. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The orderByConsumed means that output from xFilter will occur in dbda8d6ce9 2007-07-21 drh: ** the correct order to satisfy the ORDER BY clause so that no separate dbda8d6ce9 2007-07-21 drh: ** sorting step is required. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The estimatedCost value is an estimate of the cost of doing the dbda8d6ce9 2007-07-21 drh: ** particular lookup. A full scan of a table with N entries should have dbda8d6ce9 2007-07-21 drh: ** a cost of N. A binary search of a table of N entries should have a dbda8d6ce9 2007-07-21 drh: ** cost of approximately log(N). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct sqlite3_index_info { dbda8d6ce9 2007-07-21 drh: /* Inputs */ dbda8d6ce9 2007-07-21 drh: const int nConstraint; /* Number of entries in aConstraint */ dbda8d6ce9 2007-07-21 drh: const struct sqlite3_index_constraint { dbda8d6ce9 2007-07-21 drh: int iColumn; /* Column on left-hand side of constraint */ dbda8d6ce9 2007-07-21 drh: unsigned char op; /* Constraint operator */ dbda8d6ce9 2007-07-21 drh: unsigned char usable; /* True if this constraint is usable */ dbda8d6ce9 2007-07-21 drh: int iTermOffset; /* Used internally - xBestIndex should ignore */ dbda8d6ce9 2007-07-21 drh: } *const aConstraint; /* Table of WHERE clause constraints */ dbda8d6ce9 2007-07-21 drh: const int nOrderBy; /* Number of terms in the ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: const struct sqlite3_index_orderby { dbda8d6ce9 2007-07-21 drh: int iColumn; /* Column number */ dbda8d6ce9 2007-07-21 drh: unsigned char desc; /* True for DESC. False for ASC. */ dbda8d6ce9 2007-07-21 drh: } *const aOrderBy; /* The ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Outputs */ dbda8d6ce9 2007-07-21 drh: struct sqlite3_index_constraint_usage { dbda8d6ce9 2007-07-21 drh: int argvIndex; /* if >0, constraint is part of argv to xFilter */ dbda8d6ce9 2007-07-21 drh: unsigned char omit; /* Do not code a test for this constraint */ dbda8d6ce9 2007-07-21 drh: } *const aConstraintUsage; dbda8d6ce9 2007-07-21 drh: int idxNum; /* Number used to identify the index */ dbda8d6ce9 2007-07-21 drh: char *idxStr; /* String, possibly obtained from sqlite3_malloc */ dbda8d6ce9 2007-07-21 drh: int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ dbda8d6ce9 2007-07-21 drh: int orderByConsumed; /* True if output is already ordered */ dbda8d6ce9 2007-07-21 drh: double estimatedCost; /* Estimated cost of using this index */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #define SQLITE_INDEX_CONSTRAINT_EQ 2 dbda8d6ce9 2007-07-21 drh: #define SQLITE_INDEX_CONSTRAINT_GT 4 dbda8d6ce9 2007-07-21 drh: #define SQLITE_INDEX_CONSTRAINT_LE 8 dbda8d6ce9 2007-07-21 drh: #define SQLITE_INDEX_CONSTRAINT_LT 16 dbda8d6ce9 2007-07-21 drh: #define SQLITE_INDEX_CONSTRAINT_GE 32 dbda8d6ce9 2007-07-21 drh: #define SQLITE_INDEX_CONSTRAINT_MATCH 64 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is used to register a new module name with an SQLite dbda8d6ce9 2007-07-21 drh: ** connection. Module names must be registered before creating new dbda8d6ce9 2007-07-21 drh: ** virtual tables on the module, or before using preexisting virtual dbda8d6ce9 2007-07-21 drh: ** tables of the module. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_module( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* SQLite connection to register module with */ dbda8d6ce9 2007-07-21 drh: const char *zName, /* Name of the module */ dbda8d6ce9 2007-07-21 drh: const sqlite3_module *, /* Methods for the module */ dbda8d6ce9 2007-07-21 drh: void * /* Client data for xCreate/xConnect */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is identical to the sqlite3_create_module() method above, dbda8d6ce9 2007-07-21 drh: ** except that it allows a destructor function to be specified. It is dbda8d6ce9 2007-07-21 drh: ** even more experimental than the rest of the virtual tables API. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_module_v2( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* SQLite connection to register module with */ dbda8d6ce9 2007-07-21 drh: const char *zName, /* Name of the module */ dbda8d6ce9 2007-07-21 drh: const sqlite3_module *, /* Methods for the module */ dbda8d6ce9 2007-07-21 drh: void *, /* Client data for xCreate/xConnect */ dbda8d6ce9 2007-07-21 drh: void(*xDestroy)(void*) /* Module destructor function */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Every module implementation uses a subclass of the following structure dbda8d6ce9 2007-07-21 drh: ** to describe a particular instance of the module. Each subclass will dbda8d6ce9 2007-07-21 drh: ** be taylored to the specific needs of the module implementation. The dbda8d6ce9 2007-07-21 drh: ** purpose of this superclass is to define certain fields that are common dbda8d6ce9 2007-07-21 drh: ** to all module implementations. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Virtual tables methods can set an error message by assigning a dbda8d6ce9 2007-07-21 drh: ** string obtained from sqlite3_mprintf() to zErrMsg. The method should dbda8d6ce9 2007-07-21 drh: ** take care that any prior string is freed by a call to sqlite3_free() dbda8d6ce9 2007-07-21 drh: ** prior to assigning a new string to zErrMsg. After the error message dbda8d6ce9 2007-07-21 drh: ** is delivered up to the client application, the string will be automatically dbda8d6ce9 2007-07-21 drh: ** freed by sqlite3_free() and the zErrMsg field will be zeroed. Note dbda8d6ce9 2007-07-21 drh: ** that sqlite3_mprintf() and sqlite3_free() are used on the zErrMsg field dbda8d6ce9 2007-07-21 drh: ** since virtual tables are commonly implemented in loadable extensions which dbda8d6ce9 2007-07-21 drh: ** do not have access to sqlite3MPrintf() or sqlite3Free(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct sqlite3_vtab { dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule; /* The module for this virtual table */ dbda8d6ce9 2007-07-21 drh: int nRef; /* Used internally */ dbda8d6ce9 2007-07-21 drh: char *zErrMsg; /* Error message from sqlite3_mprintf() */ dbda8d6ce9 2007-07-21 drh: /* Virtual table implementations will typically add additional fields */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Every module implementation uses a subclass of the following structure dbda8d6ce9 2007-07-21 drh: ** to describe cursors that point into the virtual table and are used dbda8d6ce9 2007-07-21 drh: ** to loop through the virtual table. Cursors are created using the dbda8d6ce9 2007-07-21 drh: ** xOpen method of the module. Each module implementation will define dbda8d6ce9 2007-07-21 drh: ** the content of a cursor structure to suit its own needs. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This superclass exists in order to define fields of the cursor that dbda8d6ce9 2007-07-21 drh: ** are common to all implementations. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct sqlite3_vtab_cursor { dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab; /* Virtual table of this cursor */ dbda8d6ce9 2007-07-21 drh: /* Virtual table implementations will typically add additional fields */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The xCreate and xConnect methods of a module use the following API dbda8d6ce9 2007-07-21 drh: ** to declare the format (the names and datatypes of the columns) of dbda8d6ce9 2007-07-21 drh: ** the virtual tables they implement. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Virtual tables can provide alternative implementations of functions dbda8d6ce9 2007-07-21 drh: ** using the xFindFunction method. But global versions of those functions dbda8d6ce9 2007-07-21 drh: ** must exist in order to be overloaded. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This API makes sure a global version of a function with a particular dbda8d6ce9 2007-07-21 drh: ** name and number of parameters exists. If no such function exists dbda8d6ce9 2007-07-21 drh: ** before this API is called, a new function is created. The implementation dbda8d6ce9 2007-07-21 drh: ** of the new function always causes an exception to be thrown. So dbda8d6ce9 2007-07-21 drh: ** the new function is not good for anything by itself. Its only dbda8d6ce9 2007-07-21 drh: ** purpose is to be a place-holder function that can be overloaded dbda8d6ce9 2007-07-21 drh: ** by virtual tables. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This API should be considered part of the virtual table interface, dbda8d6ce9 2007-07-21 drh: ** which is experimental and subject to change. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The interface to the virtual-table mechanism defined above (back up dbda8d6ce9 2007-07-21 drh: ** to a comment remarkably similar to this one) is currently considered dbda8d6ce9 2007-07-21 drh: ** to be experimental. The interface might change in incompatible ways. dbda8d6ce9 2007-07-21 drh: ** If this is a problem for you, do not use the interface at this time. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When the virtual-table mechanism stablizes, we will declare the dbda8d6ce9 2007-07-21 drh: ** interface fixed, support it indefinitely, and remove this comment. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****** EXPERIMENTAL - subject to change without notice ************** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: A Handle To An Open BLOB dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An instance of the following opaque structure is used to dbda8d6ce9 2007-07-21 drh: ** represent an blob-handle. A blob-handle is created by dbda8d6ce9 2007-07-21 drh: ** [sqlite3_blob_open()] and destroyed by [sqlite3_blob_close()]. dbda8d6ce9 2007-07-21 drh: ** The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces dbda8d6ce9 2007-07-21 drh: ** can be used to read or write small subsections of the blob. c287665ba8 2007-09-14 drh: ** The [sqlite3_blob_bytes()] interface returns the size of the dbda8d6ce9 2007-07-21 drh: ** blob in bytes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3_blob sqlite3_blob; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Open A BLOB For Incremental I/O dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Open a handle to the blob located in row iRow,, column zColumn, dbda8d6ce9 2007-07-21 drh: ** table zTable in database zDb. i.e. the same blob that would dbda8d6ce9 2007-07-21 drh: ** be selected by: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** <pre> dbda8d6ce9 2007-07-21 drh: ** SELECT zColumn FROM zDb.zTable WHERE rowid = iRow; dbda8d6ce9 2007-07-21 drh: ** </pre> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the flags parameter is non-zero, the blob is opened for dbda8d6ce9 2007-07-21 drh: ** read and write access. If it is zero, the blob is opened for read dbda8d6ce9 2007-07-21 drh: ** access. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On success, [SQLITE_OK] is returned and the new dbda8d6ce9 2007-07-21 drh: ** [sqlite3_blob | blob handle] is written to *ppBlob. dbda8d6ce9 2007-07-21 drh: ** Otherwise an error code is returned and dbda8d6ce9 2007-07-21 drh: ** any value written to *ppBlob should not be used by the caller. dbda8d6ce9 2007-07-21 drh: ** This function sets the database-handle error code and message dbda8d6ce9 2007-07-21 drh: ** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()]. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_open( dbda8d6ce9 2007-07-21 drh: sqlite3*, dbda8d6ce9 2007-07-21 drh: const char *zDb, dbda8d6ce9 2007-07-21 drh: const char *zTable, dbda8d6ce9 2007-07-21 drh: const char *zColumn, c287665ba8 2007-09-14 drh: sqlite3_int64 iRow, dbda8d6ce9 2007-07-21 drh: int flags, dbda8d6ce9 2007-07-21 drh: sqlite3_blob **ppBlob dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Close A BLOB Handle dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Close an open [sqlite3_blob | blob handle]. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_close(sqlite3_blob *); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Return The Size Of An Open BLOB dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the size in bytes of the blob accessible via the open dbda8d6ce9 2007-07-21 drh: ** [sqlite3_blob | blob-handle] passed as an argument. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Read Data From A BLOB Incrementally dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function is used to read data from an open dbda8d6ce9 2007-07-21 drh: ** [sqlite3_blob | blob-handle] into a caller supplied buffer. dbda8d6ce9 2007-07-21 drh: ** n bytes of data are copied into buffer dbda8d6ce9 2007-07-21 drh: ** z from the open blob, starting at offset iOffset. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On success, SQLITE_OK is returned. Otherwise, an dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR | SQLite error code] or an dbda8d6ce9 2007-07-21 drh: ** [SQLITE_IOERR_READ | extended error code] is returned. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *z, int n, int iOffset); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** CAPI3REF: Write Data Into A BLOB Incrementally dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function is used to write data into an open dbda8d6ce9 2007-07-21 drh: ** [sqlite3_blob | blob-handle] from a user supplied buffer. dbda8d6ce9 2007-07-21 drh: ** n bytes of data are copied from the buffer dbda8d6ce9 2007-07-21 drh: ** pointed to by z into the open blob, starting at offset iOffset. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the [sqlite3_blob | blob-handle] passed as the first argument dbda8d6ce9 2007-07-21 drh: ** was not opened for writing (the flags parameter to [sqlite3_blob_open()] dbda8d6ce9 2007-07-21 drh: *** was zero), this function returns [SQLITE_READONLY]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function may only modify the contents of the blob, it is dbda8d6ce9 2007-07-21 drh: ** not possible to increase the size of a blob using this API. If dbda8d6ce9 2007-07-21 drh: ** offset iOffset is less than n bytes from the end of the blob, dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR] is returned and no data is written. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On success, SQLITE_OK is returned. Otherwise, an dbda8d6ce9 2007-07-21 drh: ** [SQLITE_ERROR | SQLite error code] or an dbda8d6ce9 2007-07-21 drh: ** [SQLITE_IOERR_READ | extended error code] is returned. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Virtual File System Objects c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** A virtual filesystem (VFS) is an [sqlite3_vfs] object c287665ba8 2007-09-14 drh: ** that SQLite uses to interact c287665ba8 2007-09-14 drh: ** with the underlying operating system. Most builds come with a c287665ba8 2007-09-14 drh: ** single default VFS that is appropriate for the host computer. c287665ba8 2007-09-14 drh: ** New VFSes can be registered and existing VFSes can be unregistered. c287665ba8 2007-09-14 drh: ** The following interfaces are provided. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The sqlite3_vfs_find() interface returns a pointer to a VFS given its c287665ba8 2007-09-14 drh: ** name. Names are case sensitive. If there is no match, a NULL c287665ba8 2007-09-14 drh: ** pointer is returned. If zVfsName is NULL then the default c287665ba8 2007-09-14 drh: ** VFS is returned. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** New VFSes are registered with sqlite3_vfs_register(). Each c287665ba8 2007-09-14 drh: ** new VFS becomes the default VFS if the makeDflt flag is set. c287665ba8 2007-09-14 drh: ** The same VFS can be registered multiple times without injury. c287665ba8 2007-09-14 drh: ** To make an existing VFS into the default VFS, register it again c287665ba8 2007-09-14 drh: ** with the makeDflt flag set. If two different VFSes with the c287665ba8 2007-09-14 drh: ** same name are registered, the behavior is undefined. If a c287665ba8 2007-09-14 drh: ** VFS is registered with a name that is NULL or an empty string, c287665ba8 2007-09-14 drh: ** then the behavior is undefined. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Unregister a VFS with the sqlite3_vfs_unregister() interface. c287665ba8 2007-09-14 drh: ** If the default VFS is unregistered, another VFS is chosen as c287665ba8 2007-09-14 drh: ** the default. The choice for the new VFS is arbitrary. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Mutexes c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The SQLite core uses these routines for thread c287665ba8 2007-09-14 drh: ** synchronization. Though they are intended for internal c287665ba8 2007-09-14 drh: ** use by SQLite, code that links against SQLite is c287665ba8 2007-09-14 drh: ** permitted to use any of these routines. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The SQLite source code contains multiple implementations c287665ba8 2007-09-14 drh: ** of these mutex routines. An appropriate implementation c287665ba8 2007-09-14 drh: ** is selected automatically at compile-time. The following c287665ba8 2007-09-14 drh: ** implementations are available in the SQLite core: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <ul> c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_OS2 c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_PTHREAD c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_W32 c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_NOOP c287665ba8 2007-09-14 drh: ** </ul> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The SQLITE_MUTEX_NOOP implementation is a set of routines c287665ba8 2007-09-14 drh: ** that does no real locking and is appropriate for use in c287665ba8 2007-09-14 drh: ** a single-threaded application. The SQLITE_MUTEX_OS2, c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations c287665ba8 2007-09-14 drh: ** are appropriate for use on os/2, unix, and windows. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor c287665ba8 2007-09-14 drh: ** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex c287665ba8 2007-09-14 drh: ** implementation is included with the library. The c287665ba8 2007-09-14 drh: ** mutex interface routines defined here become external c287665ba8 2007-09-14 drh: ** references in the SQLite library for which implementations c287665ba8 2007-09-14 drh: ** must be provided by the application. This facility allows an c287665ba8 2007-09-14 drh: ** application that links against SQLite to provide its own mutex c287665ba8 2007-09-14 drh: ** implementation without having to modify the SQLite core. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_alloc() routine allocates a new c287665ba8 2007-09-14 drh: ** mutex and returns a pointer to it. If it returns NULL c287665ba8 2007-09-14 drh: ** that means that a mutex could not be allocated. SQLite c287665ba8 2007-09-14 drh: ** will unwind its stack and return an error. The argument c287665ba8 2007-09-14 drh: ** to sqlite3_mutex_alloc() is one of these integer constants: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <ul> c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_FAST c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_RECURSIVE c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_MASTER c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_MEM c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_MEM2 c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_PRNG c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_LRU c287665ba8 2007-09-14 drh: ** </ul> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The first two constants cause sqlite3_mutex_alloc() to create c287665ba8 2007-09-14 drh: ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE c287665ba8 2007-09-14 drh: ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. c287665ba8 2007-09-14 drh: ** The mutex implementation does not need to make a distinction c287665ba8 2007-09-14 drh: ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does c287665ba8 2007-09-14 drh: ** not want to. But SQLite will only request a recursive mutex in c287665ba8 2007-09-14 drh: ** cases where it really needs one. If a faster non-recursive mutex c287665ba8 2007-09-14 drh: ** implementation is available on the host platform, the mutex subsystem c287665ba8 2007-09-14 drh: ** might return such a mutex in response to SQLITE_MUTEX_FAST. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The other allowed parameters to sqlite3_mutex_alloc() each return c287665ba8 2007-09-14 drh: ** a pointer to a static preexisting mutex. Four static mutexes are c287665ba8 2007-09-14 drh: ** used by the current version of SQLite. Future versions of SQLite c287665ba8 2007-09-14 drh: ** may add additional static mutexes. Static mutexes are for internal c287665ba8 2007-09-14 drh: ** use by SQLite only. Applications that use SQLite mutexes should c287665ba8 2007-09-14 drh: ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_RECURSIVE. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST c287665ba8 2007-09-14 drh: ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() c287665ba8 2007-09-14 drh: ** returns a different mutex on every call. But for the static c287665ba8 2007-09-14 drh: ** mutex types, the same mutex is returned on every call that has c287665ba8 2007-09-14 drh: ** the same type number. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_free() routine deallocates a previously c287665ba8 2007-09-14 drh: ** allocated dynamic mutex. SQLite is careful to deallocate every c287665ba8 2007-09-14 drh: ** dynamic mutex that it allocates. The dynamic mutexes must not be in c287665ba8 2007-09-14 drh: ** use when they are deallocated. Attempting to deallocate a static c287665ba8 2007-09-14 drh: ** mutex results in undefined behavior. SQLite never deallocates c287665ba8 2007-09-14 drh: ** a static mutex. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt c287665ba8 2007-09-14 drh: ** to enter a mutex. If another thread is already within the mutex, c287665ba8 2007-09-14 drh: ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return c287665ba8 2007-09-14 drh: ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK c287665ba8 2007-09-14 drh: ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can c287665ba8 2007-09-14 drh: ** be entered multiple times by the same thread. In such cases the, c287665ba8 2007-09-14 drh: ** mutex must be exited an equal number of times before another thread c287665ba8 2007-09-14 drh: ** can enter. If the same thread tries to enter any other kind of mutex c287665ba8 2007-09-14 drh: ** more than once, the behavior is undefined. SQLite will never exhibit c287665ba8 2007-09-14 drh: ** such behavior in its own use of mutexes. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Some systems (ex: windows95) do not the operation implemented by c287665ba8 2007-09-14 drh: ** sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() will c287665ba8 2007-09-14 drh: ** always return SQLITE_BUSY. The SQLite core only ever uses c287665ba8 2007-09-14 drh: ** sqlite3_mutex_try() as an optimization so this is acceptable behavior. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_leave() routine exits a mutex that was c287665ba8 2007-09-14 drh: ** previously entered by the same thread. The behavior c287665ba8 2007-09-14 drh: ** is undefined if the mutex is not currently entered by the c287665ba8 2007-09-14 drh: ** calling thread or is not currently allocated. SQLite will c287665ba8 2007-09-14 drh: ** never do either. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Mutex Verifcation Routines c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines c287665ba8 2007-09-14 drh: ** are intended for use inside assert() statements. The SQLite core c287665ba8 2007-09-14 drh: ** never uses these routines except inside an assert() and applications c287665ba8 2007-09-14 drh: ** are advised to follow the lead of the core. The core only c287665ba8 2007-09-14 drh: ** provides implementations for these routines when it is compiled c287665ba8 2007-09-14 drh: ** with the SQLITE_DEBUG flag. External mutex implementations c287665ba8 2007-09-14 drh: ** are only required to provide these routines if SQLITE_DEBUG is c287665ba8 2007-09-14 drh: ** defined and if NDEBUG is not defined. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** These routines should return true if the mutex in their argument c287665ba8 2007-09-14 drh: ** is held or not held, respectively, by the calling thread. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The implementation is not required to provided versions of these c287665ba8 2007-09-14 drh: ** routines that actually work. c287665ba8 2007-09-14 drh: ** If the implementation does not provide working c287665ba8 2007-09-14 drh: ** versions of these routines, it should at least provide stubs c287665ba8 2007-09-14 drh: ** that always return true so that one does not get spurious c287665ba8 2007-09-14 drh: ** assertion failures. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If the argument to sqlite3_mutex_held() is a NULL pointer then c287665ba8 2007-09-14 drh: ** the routine should return 1. This seems counter-intuitive since c287665ba8 2007-09-14 drh: ** clearly the mutex cannot be held if it does not exist. But the c287665ba8 2007-09-14 drh: ** the reason the mutex does not exist is because the build is not c287665ba8 2007-09-14 drh: ** using mutexes. And we do not want the assert() containing the c287665ba8 2007-09-14 drh: ** call to sqlite3_mutex_held() to fail, so a non-zero return is c287665ba8 2007-09-14 drh: ** the appropriate thing to do. The sqlite3_mutex_notheld() c287665ba8 2007-09-14 drh: ** interface should also return 1 when given a NULL pointer. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Mutex Types c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The [sqlite3_mutex_alloc()] interface takes a single argument c287665ba8 2007-09-14 drh: ** which is one of these integer constants. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_MUTEX_FAST 0 c287665ba8 2007-09-14 drh: #define SQLITE_MUTEX_RECURSIVE 1 c287665ba8 2007-09-14 drh: #define SQLITE_MUTEX_STATIC_MASTER 2 c287665ba8 2007-09-14 drh: #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ c287665ba8 2007-09-14 drh: #define SQLITE_MUTEX_STATIC_MEM2 4 /* sqlite3_release_memory() */ c287665ba8 2007-09-14 drh: #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ c287665ba8 2007-09-14 drh: #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** CAPI3REF: Low-Level Control Of Database Files c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The [sqlite3_file_control()] interface makes a direct call to the c287665ba8 2007-09-14 drh: ** xFileControl method for the [sqlite3_io_methods] object associated c287665ba8 2007-09-14 drh: ** with a particular database identified by the second argument. The c287665ba8 2007-09-14 drh: ** name of the database is the name assigned to the database by the c287665ba8 2007-09-14 drh: ** <a href="lang_attach.html">ATTACH</a> SQL command that opened the c287665ba8 2007-09-14 drh: ** database. To control the main database file, use the name "main" c287665ba8 2007-09-14 drh: ** or a NULL pointer. The third and fourth parameters to this routine c287665ba8 2007-09-14 drh: ** are passed directly through to the second and third parameters of c287665ba8 2007-09-14 drh: ** the xFileControl method. The return value of the xFileControl c287665ba8 2007-09-14 drh: ** method becomes the return value of this routine. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If the second parameter (zDbName) does not match the name of any c287665ba8 2007-09-14 drh: ** open database file, then SQLITE_ERROR is returned. This error c287665ba8 2007-09-14 drh: ** code is not remembered and will not be recalled by [sqlite3_errcode()] c287665ba8 2007-09-14 drh: ** or [sqlite3_errmsg()]. The underlying xFileControl method might c287665ba8 2007-09-14 drh: ** also return SQLITE_ERROR. There is no way to distinguish between c287665ba8 2007-09-14 drh: ** an incorrect zDbName and an SQLITE_ERROR return from the underlying c287665ba8 2007-09-14 drh: ** xFileControl method. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** See also: [SQLITE_FCNTL_LOCKSTATE] c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Undo the hack that converts floating point types to integer for dbda8d6ce9 2007-07-21 drh: ** builds on processors without floating point support. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: # undef double dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if 0 dbda8d6ce9 2007-07-21 drh: } /* End of the 'extern "C"' block */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of sqlite3.h *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file date.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2003 October 31 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains the C functions that implement date and time dbda8d6ce9 2007-07-21 drh: ** functions for SQLite. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There is only one exported symbol in this file - the function dbda8d6ce9 2007-07-21 drh: ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. dbda8d6ce9 2007-07-21 drh: ** All other code has file scope. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: date.c,v 1.73 2007/09/12 17:01:45 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite processes all times and dates as Julian Day numbers. The dbda8d6ce9 2007-07-21 drh: ** dates and times are stored as the number of days since noon dbda8d6ce9 2007-07-21 drh: ** in Greenwich on November 24, 4714 B.C. according to the Gregorian dbda8d6ce9 2007-07-21 drh: ** calendar system. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1970-01-01 00:00:00 is JD 2440587.5 dbda8d6ce9 2007-07-21 drh: ** 2000-01-01 00:00:00 is JD 2451544.5 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This implemention requires years to be expressed as a 4-digit number dbda8d6ce9 2007-07-21 drh: ** which means that only dates between 0000-01-01 and 9999-12-31 can dbda8d6ce9 2007-07-21 drh: ** be represented, even though julian day numbers allow a much wider dbda8d6ce9 2007-07-21 drh: ** range of dates. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The Gregorian calendar system is used for all dates and times, dbda8d6ce9 2007-07-21 drh: ** even those that predate the Gregorian calendar. Historians usually dbda8d6ce9 2007-07-21 drh: ** use the Julian calendar for dates prior to 1582-10-15 and for some dbda8d6ce9 2007-07-21 drh: ** dates afterwards, depending on locale. Beware of this difference. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The conversion algorithms are implemented based on descriptions dbda8d6ce9 2007-07-21 drh: ** in the following text: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Jean Meeus dbda8d6ce9 2007-07-21 drh: ** Astronomical Algorithms, 2nd Edition, 1998 dbda8d6ce9 2007-07-21 drh: ** ISBM 0-943396-61-1 dbda8d6ce9 2007-07-21 drh: ** Willmann-Bell, Inc dbda8d6ce9 2007-07-21 drh: ** Richmond, Virginia (USA) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /************** Include sqliteInt.h in the middle of date.c ******************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file sqliteInt.h ***************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** Internal interface definitions for SQLite. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: sqliteInt.h,v 1.608 2007/09/03 15:19:35 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef _SQLITEINT_H_ dbda8d6ce9 2007-07-21 drh: #define _SQLITEINT_H_ dbda8d6ce9 2007-07-21 drh: /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/ dbda8d6ce9 2007-07-21 drh: /************** Begin file sqliteLimit.h *************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2007 May 7 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file defines various limits of what SQLite can process. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: sqliteLimit.h,v 1.2 2007/08/24 11:52:29 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum length of a TEXT or BLOB in bytes. This also dbda8d6ce9 2007-07-21 drh: ** limits the size of a row in a table or index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The hard limit is the ability of a 32-bit signed integer dbda8d6ce9 2007-07-21 drh: ** to count the size: 2^31-1 or 2147483647. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_LENGTH dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_LENGTH 1000000000 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is the maximum number of dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Columns in a table dbda8d6ce9 2007-07-21 drh: ** * Columns in an index dbda8d6ce9 2007-07-21 drh: ** * Columns in a view dbda8d6ce9 2007-07-21 drh: ** * Terms in the SET clause of an UPDATE statement dbda8d6ce9 2007-07-21 drh: ** * Terms in the result set of a SELECT statement dbda8d6ce9 2007-07-21 drh: ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. dbda8d6ce9 2007-07-21 drh: ** * Terms in the VALUES clause of an INSERT statement dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The hard upper limit here is 32676. Most database people will dbda8d6ce9 2007-07-21 drh: ** tell you that in a well-normalized database, you usually should dbda8d6ce9 2007-07-21 drh: ** not have more than a dozen or so columns in any table. And if dbda8d6ce9 2007-07-21 drh: ** that is the case, there is no point in having more than a few dbda8d6ce9 2007-07-21 drh: ** dozen values in any of the other situations described above. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_COLUMN dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_COLUMN 2000 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum length of a single SQL statement in bytes. dbda8d6ce9 2007-07-21 drh: ** The hard limit here is the same as SQLITE_MAX_LENGTH. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_SQL_LENGTH dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_SQL_LENGTH 1000000 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum depth of an expression tree. This is limited to dbda8d6ce9 2007-07-21 drh: ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might dbda8d6ce9 2007-07-21 drh: ** want to place more severe limits on the complexity of an dbda8d6ce9 2007-07-21 drh: ** expression. A value of 0 (the default) means do not enforce dbda8d6ce9 2007-07-21 drh: ** any limitation on expression tree depth. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_EXPR_DEPTH dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_EXPR_DEPTH 1000 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum number of terms in a compound SELECT statement. dbda8d6ce9 2007-07-21 drh: ** The code generator for compound SELECT statements does one dbda8d6ce9 2007-07-21 drh: ** level of recursion for each term. A stack overflow can result dbda8d6ce9 2007-07-21 drh: ** if the number of terms is too large. In practice, most SQL dbda8d6ce9 2007-07-21 drh: ** never has more than 3 or 4 terms. Use a value of 0 to disable dbda8d6ce9 2007-07-21 drh: ** any limit on the number of terms in a compount SELECT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_COMPOUND_SELECT dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_COMPOUND_SELECT 500 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum number of opcodes in a VDBE program. dbda8d6ce9 2007-07-21 drh: ** Not currently enforced. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_VDBE_OP dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_VDBE_OP 25000 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum number of arguments to an SQL function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_FUNCTION_ARG dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_FUNCTION_ARG 100 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum number of in-memory pages to use for the main database dbda8d6ce9 2007-07-21 drh: ** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DEFAULT_CACHE_SIZE dbda8d6ce9 2007-07-21 drh: # define SQLITE_DEFAULT_CACHE_SIZE 2000 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE dbda8d6ce9 2007-07-21 drh: # define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum number of attached databases. This must be at least 2 dbda8d6ce9 2007-07-21 drh: ** in order to support the main database file (0) and the file used to dbda8d6ce9 2007-07-21 drh: ** hold temporary tables (1). And it must be less than 32 because dbda8d6ce9 2007-07-21 drh: ** we use a bitmask of databases with a u32 in places (for example dbda8d6ce9 2007-07-21 drh: ** the Parse.cookieMask field). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_ATTACHED dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_ATTACHED 10 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum value of a ?nnn wildcard that the parser will accept. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_VARIABLE_NUMBER dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_VARIABLE_NUMBER 999 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The default size of a database page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DEFAULT_PAGE_SIZE dbda8d6ce9 2007-07-21 drh: # define SQLITE_DEFAULT_PAGE_SIZE 1024 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Ordinarily, if no value is explicitly provided, SQLite creates databases c287665ba8 2007-09-14 drh: ** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain c287665ba8 2007-09-14 drh: ** device characteristics (sector-size and atomic write() support), c287665ba8 2007-09-14 drh: ** SQLite may choose a larger value. This constant is the maximum value c287665ba8 2007-09-14 drh: ** SQLite will choose on it's own. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE c287665ba8 2007-09-14 drh: # define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* Maximum page size. The upper bound on this value is 32768. This a limit dbda8d6ce9 2007-07-21 drh: ** imposed by the necessity of storing the value in a 2-byte unsigned integer dbda8d6ce9 2007-07-21 drh: ** and the fact that the page size must be a power of 2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_PAGE_SIZE dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_PAGE_SIZE 32768 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Maximum number of pages in one database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is really just the default value for the max_page_count pragma. dbda8d6ce9 2007-07-21 drh: ** This value can be lowered (or raised) at run-time using that the dbda8d6ce9 2007-07-21 drh: ** max_page_count macro. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_PAGE_COUNT dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_PAGE_COUNT 1073741823 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Maximum length (in bytes) of the pattern in a LIKE or GLOB dbda8d6ce9 2007-07-21 drh: ** operator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH dbda8d6ce9 2007-07-21 drh: # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of sqliteLimit.h *****************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** For testing purposes, the various size limit constants are really c287665ba8 2007-09-14 drh: ** variables that we can modify in the testfixture. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_LENGTH c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_COLUMN c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_SQL_LENGTH c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_EXPR_DEPTH c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_COMPOUND_SELECT c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_VDBE_OP c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_FUNCTION_ARG c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_VARIABLE_NUMBER c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_PAGE_SIZE c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_PAGE_COUNT c287665ba8 2007-09-14 drh: #undef SQLITE_MAX_LIKE_PATTERN_LENGTH c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #define SQLITE_MAX_LENGTH sqlite3MAX_LENGTH c287665ba8 2007-09-14 drh: #define SQLITE_MAX_COLUMN sqlite3MAX_COLUMN c287665ba8 2007-09-14 drh: #define SQLITE_MAX_SQL_LENGTH sqlite3MAX_SQL_LENGTH c287665ba8 2007-09-14 drh: #define SQLITE_MAX_EXPR_DEPTH sqlite3MAX_EXPR_DEPTH c287665ba8 2007-09-14 drh: #define SQLITE_MAX_COMPOUND_SELECT sqlite3MAX_COMPOUND_SELECT c287665ba8 2007-09-14 drh: #define SQLITE_MAX_VDBE_OP sqlite3MAX_VDBE_OP c287665ba8 2007-09-14 drh: #define SQLITE_MAX_FUNCTION_ARG sqlite3MAX_FUNCTION_ARG c287665ba8 2007-09-14 drh: #define SQLITE_MAX_VARIABLE_NUMBER sqlite3MAX_VARIABLE_NUMBER c287665ba8 2007-09-14 drh: #define SQLITE_MAX_PAGE_SIZE sqlite3MAX_PAGE_SIZE c287665ba8 2007-09-14 drh: #define SQLITE_MAX_PAGE_COUNT sqlite3MAX_PAGE_COUNT c287665ba8 2007-09-14 drh: #define SQLITE_MAX_LIKE_PATTERN_LENGTH sqlite3MAX_LIKE_PATTERN_LENGTH c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: extern int sqlite3MAX_LENGTH; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_COLUMN; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_SQL_LENGTH; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_EXPR_DEPTH; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_COMPOUND_SELECT; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_VDBE_OP; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_FUNCTION_ARG; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_VARIABLE_NUMBER; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_PAGE_SIZE; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_PAGE_COUNT; c287665ba8 2007-09-14 drh: extern int sqlite3MAX_LIKE_PATTERN_LENGTH; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_TCL) || defined(TCLSH) dbda8d6ce9 2007-07-21 drh: # include <tcl.h> dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Many people are failing to set -DNDEBUG=1 when compiling SQLite. dbda8d6ce9 2007-07-21 drh: ** Setting NDEBUG makes the code smaller and run faster. So the following dbda8d6ce9 2007-07-21 drh: ** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1 dbda8d6ce9 2007-07-21 drh: ** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out dbda8d6ce9 2007-07-21 drh: ** feature. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) dbda8d6ce9 2007-07-21 drh: # define NDEBUG 1 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The SQLITE_THREADSAFE macro must be defined as either 0 or 1. c287665ba8 2007-09-14 drh: ** Older versions of SQLite used an optional THREADSAFE macro. c287665ba8 2007-09-14 drh: ** We support that for legacy c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #if !defined(SQLITE_THREADSAFE) c287665ba8 2007-09-14 drh: #if defined(THREADSAFE) c287665ba8 2007-09-14 drh: # define SQLITE_THREADSAFE THREADSAFE c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: # define SQLITE_THREADSAFE 1 c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** These #defines should enable >2GB file support on Posix if the dbda8d6ce9 2007-07-21 drh: ** underlying operating system supports it. If the OS lacks dbda8d6ce9 2007-07-21 drh: ** large file support, or if the OS is windows, these should be no-ops. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch dbda8d6ce9 2007-07-21 drh: ** on the compiler command line. This is necessary if you are compiling dbda8d6ce9 2007-07-21 drh: ** on a recent machine (ex: RedHat 7.2) but you want your code to work dbda8d6ce9 2007-07-21 drh: ** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 dbda8d6ce9 2007-07-21 drh: ** without this option, LFS is enable. But LFS does not exist in the kernel dbda8d6ce9 2007-07-21 drh: ** in RedHat 6.0, so the code won't work. Hence, for maximum binary dbda8d6ce9 2007-07-21 drh: ** portability you should omit LFS. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Similar is true for MacOS. LFS is only supported on MacOS 9 and later. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DISABLE_LFS dbda8d6ce9 2007-07-21 drh: # define _LARGE_FILE 1 dbda8d6ce9 2007-07-21 drh: # ifndef _FILE_OFFSET_BITS dbda8d6ce9 2007-07-21 drh: # define _FILE_OFFSET_BITS 64 dbda8d6ce9 2007-07-21 drh: # endif dbda8d6ce9 2007-07-21 drh: # define _LARGEFILE_SOURCE 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** Include hash.h in the middle of sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file hash.h ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 22 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This is the header file for the generic hash-table implemenation dbda8d6ce9 2007-07-21 drh: ** used in SQLite. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: hash.h,v 1.11 2007/09/04 14:31:47 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef _SQLITE_HASH_H_ dbda8d6ce9 2007-07-21 drh: #define _SQLITE_HASH_H_ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward declarations of structures. */ dbda8d6ce9 2007-07-21 drh: typedef struct Hash Hash; dbda8d6ce9 2007-07-21 drh: typedef struct HashElem HashElem; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A complete hash table is an instance of the following structure. dbda8d6ce9 2007-07-21 drh: ** The internals of this structure are intended to be opaque -- client dbda8d6ce9 2007-07-21 drh: ** code should not attempt to access or modify the fields of this structure dbda8d6ce9 2007-07-21 drh: ** directly. Change this structure only by using the routines below. dbda8d6ce9 2007-07-21 drh: ** However, many of the "procedures" and "functions" for modifying and dbda8d6ce9 2007-07-21 drh: ** accessing this structure are really macros, so we can't really make dbda8d6ce9 2007-07-21 drh: ** this structure opaque. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Hash { dbda8d6ce9 2007-07-21 drh: char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */ dbda8d6ce9 2007-07-21 drh: char copyKey; /* True if copy of key made on insert */ dbda8d6ce9 2007-07-21 drh: int count; /* Number of entries in this table */ dbda8d6ce9 2007-07-21 drh: int htsize; /* Number of buckets in the hash table */ c287665ba8 2007-09-14 drh: HashElem *first; /* The first element of the array */ dbda8d6ce9 2007-07-21 drh: struct _ht { /* the hash table */ dbda8d6ce9 2007-07-21 drh: int count; /* Number of entries with this hash */ dbda8d6ce9 2007-07-21 drh: HashElem *chain; /* Pointer to first entry with this hash */ dbda8d6ce9 2007-07-21 drh: } *ht; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Each element in the hash table is an instance of the following dbda8d6ce9 2007-07-21 drh: ** structure. All elements are stored on a single doubly-linked list. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Again, this structure is intended to be opaque, but it can't really dbda8d6ce9 2007-07-21 drh: ** be opaque because it is used by macros. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct HashElem { dbda8d6ce9 2007-07-21 drh: HashElem *next, *prev; /* Next and previous elements in the table */ dbda8d6ce9 2007-07-21 drh: void *data; /* Data associated with this element */ dbda8d6ce9 2007-07-21 drh: void *pKey; int nKey; /* Key associated with this element */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** There are 4 different modes of operation for a hash table: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_HASH_INT nKey is used as the key and pKey is ignored. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_HASH_POINTER pKey is used as the key and nKey is ignored. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_HASH_STRING pKey points to a string that is nKey bytes long dbda8d6ce9 2007-07-21 drh: ** (including the null-terminator, if any). Case dbda8d6ce9 2007-07-21 drh: ** is ignored in comparisons. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_HASH_BINARY pKey points to binary data nKey bytes long. dbda8d6ce9 2007-07-21 drh: ** memcmp() is used to compare keys. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A copy of the key is made for SQLITE_HASH_STRING and SQLITE_HASH_BINARY dbda8d6ce9 2007-07-21 drh: ** if the copyKey parameter to HashInit is 1. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* #define SQLITE_HASH_INT 1 // NOT USED */ dbda8d6ce9 2007-07-21 drh: /* #define SQLITE_HASH_POINTER 2 // NOT USED */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_HASH_STRING 3 dbda8d6ce9 2007-07-21 drh: #define SQLITE_HASH_BINARY 4 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Access routines. To delete, insert a NULL pointer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3HashInit(Hash*, int keytype, int copyKey); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3HashFind(const Hash*, const void *pKey, int nKey); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE HashElem *sqlite3HashFindElem(const Hash*, const void *pKey, int nKey); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3HashClear(Hash*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Macros for looping over all elements of a hash table. The idiom is dbda8d6ce9 2007-07-21 drh: ** like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Hash h; dbda8d6ce9 2007-07-21 drh: ** HashElem *p; dbda8d6ce9 2007-07-21 drh: ** ... dbda8d6ce9 2007-07-21 drh: ** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){ dbda8d6ce9 2007-07-21 drh: ** SomeStructure *pData = sqliteHashData(p); dbda8d6ce9 2007-07-21 drh: ** // do something with pData dbda8d6ce9 2007-07-21 drh: ** } dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define sqliteHashFirst(H) ((H)->first) dbda8d6ce9 2007-07-21 drh: #define sqliteHashNext(E) ((E)->next) dbda8d6ce9 2007-07-21 drh: #define sqliteHashData(E) ((E)->data) dbda8d6ce9 2007-07-21 drh: #define sqliteHashKey(E) ((E)->pKey) dbda8d6ce9 2007-07-21 drh: #define sqliteHashKeysize(E) ((E)->nKey) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Number of entries in a hash table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define sqliteHashCount(H) ((H)->count) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* _SQLITE_HASH_H_ */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of hash.h ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: /************** Include parse.h in the middle of sqliteInt.h *****************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file parse.h *******************************************/ dbda8d6ce9 2007-07-21 drh: #define TK_SEMI 1 dbda8d6ce9 2007-07-21 drh: #define TK_EXPLAIN 2 dbda8d6ce9 2007-07-21 drh: #define TK_QUERY 3 dbda8d6ce9 2007-07-21 drh: #define TK_PLAN 4 dbda8d6ce9 2007-07-21 drh: #define TK_BEGIN 5 dbda8d6ce9 2007-07-21 drh: #define TK_TRANSACTION 6 dbda8d6ce9 2007-07-21 drh: #define TK_DEFERRED 7 dbda8d6ce9 2007-07-21 drh: #define TK_IMMEDIATE 8 dbda8d6ce9 2007-07-21 drh: #define TK_EXCLUSIVE 9 dbda8d6ce9 2007-07-21 drh: #define TK_COMMIT 10 dbda8d6ce9 2007-07-21 drh: #define TK_END 11 dbda8d6ce9 2007-07-21 drh: #define TK_ROLLBACK 12 dbda8d6ce9 2007-07-21 drh: #define TK_CREATE 13 dbda8d6ce9 2007-07-21 drh: #define TK_TABLE 14 dbda8d6ce9 2007-07-21 drh: #define TK_IF 15 dbda8d6ce9 2007-07-21 drh: #define TK_NOT 16 dbda8d6ce9 2007-07-21 drh: #define TK_EXISTS 17 dbda8d6ce9 2007-07-21 drh: #define TK_TEMP 18 dbda8d6ce9 2007-07-21 drh: #define TK_LP 19 dbda8d6ce9 2007-07-21 drh: #define TK_RP 20 dbda8d6ce9 2007-07-21 drh: #define TK_AS 21 dbda8d6ce9 2007-07-21 drh: #define TK_COMMA 22 dbda8d6ce9 2007-07-21 drh: #define TK_ID 23 dbda8d6ce9 2007-07-21 drh: #define TK_ABORT 24 dbda8d6ce9 2007-07-21 drh: #define TK_AFTER 25 dbda8d6ce9 2007-07-21 drh: #define TK_ANALYZE 26 dbda8d6ce9 2007-07-21 drh: #define TK_ASC 27 dbda8d6ce9 2007-07-21 drh: #define TK_ATTACH 28 dbda8d6ce9 2007-07-21 drh: #define TK_BEFORE 29 dbda8d6ce9 2007-07-21 drh: #define TK_CASCADE 30 dbda8d6ce9 2007-07-21 drh: #define TK_CAST 31 dbda8d6ce9 2007-07-21 drh: #define TK_CONFLICT 32 dbda8d6ce9 2007-07-21 drh: #define TK_DATABASE 33 dbda8d6ce9 2007-07-21 drh: #define TK_DESC 34 dbda8d6ce9 2007-07-21 drh: #define TK_DETACH 35 dbda8d6ce9 2007-07-21 drh: #define TK_EACH 36 dbda8d6ce9 2007-07-21 drh: #define TK_FAIL 37 dbda8d6ce9 2007-07-21 drh: #define TK_FOR 38 dbda8d6ce9 2007-07-21 drh: #define TK_IGNORE 39 dbda8d6ce9 2007-07-21 drh: #define TK_INITIALLY 40 dbda8d6ce9 2007-07-21 drh: #define TK_INSTEAD 41 dbda8d6ce9 2007-07-21 drh: #define TK_LIKE_KW 42 dbda8d6ce9 2007-07-21 drh: #define TK_MATCH 43 dbda8d6ce9 2007-07-21 drh: #define TK_KEY 44 dbda8d6ce9 2007-07-21 drh: #define TK_OF 45 dbda8d6ce9 2007-07-21 drh: #define TK_OFFSET 46 dbda8d6ce9 2007-07-21 drh: #define TK_PRAGMA 47 dbda8d6ce9 2007-07-21 drh: #define TK_RAISE 48 dbda8d6ce9 2007-07-21 drh: #define TK_REPLACE 49 dbda8d6ce9 2007-07-21 drh: #define TK_RESTRICT 50 dbda8d6ce9 2007-07-21 drh: #define TK_ROW 51 dbda8d6ce9 2007-07-21 drh: #define TK_TRIGGER 52 dbda8d6ce9 2007-07-21 drh: #define TK_VACUUM 53 dbda8d6ce9 2007-07-21 drh: #define TK_VIEW 54 dbda8d6ce9 2007-07-21 drh: #define TK_VIRTUAL 55 dbda8d6ce9 2007-07-21 drh: #define TK_REINDEX 56 dbda8d6ce9 2007-07-21 drh: #define TK_RENAME 57 dbda8d6ce9 2007-07-21 drh: #define TK_CTIME_KW 58 dbda8d6ce9 2007-07-21 drh: #define TK_ANY 59 dbda8d6ce9 2007-07-21 drh: #define TK_OR 60 dbda8d6ce9 2007-07-21 drh: #define TK_AND 61 dbda8d6ce9 2007-07-21 drh: #define TK_IS 62 dbda8d6ce9 2007-07-21 drh: #define TK_BETWEEN 63 dbda8d6ce9 2007-07-21 drh: #define TK_IN 64 dbda8d6ce9 2007-07-21 drh: #define TK_ISNULL 65 dbda8d6ce9 2007-07-21 drh: #define TK_NOTNULL 66 dbda8d6ce9 2007-07-21 drh: #define TK_NE 67 dbda8d6ce9 2007-07-21 drh: #define TK_EQ 68 dbda8d6ce9 2007-07-21 drh: #define TK_GT 69 dbda8d6ce9 2007-07-21 drh: #define TK_LE 70 dbda8d6ce9 2007-07-21 drh: #define TK_LT 71 dbda8d6ce9 2007-07-21 drh: #define TK_GE 72 dbda8d6ce9 2007-07-21 drh: #define TK_ESCAPE 73 dbda8d6ce9 2007-07-21 drh: #define TK_BITAND 74 dbda8d6ce9 2007-07-21 drh: #define TK_BITOR 75 dbda8d6ce9 2007-07-21 drh: #define TK_LSHIFT 76 dbda8d6ce9 2007-07-21 drh: #define TK_RSHIFT 77 dbda8d6ce9 2007-07-21 drh: #define TK_PLUS 78 dbda8d6ce9 2007-07-21 drh: #define TK_MINUS 79 dbda8d6ce9 2007-07-21 drh: #define TK_STAR 80 dbda8d6ce9 2007-07-21 drh: #define TK_SLASH 81 dbda8d6ce9 2007-07-21 drh: #define TK_REM 82 dbda8d6ce9 2007-07-21 drh: #define TK_CONCAT 83 dbda8d6ce9 2007-07-21 drh: #define TK_COLLATE 84 dbda8d6ce9 2007-07-21 drh: #define TK_UMINUS 85 dbda8d6ce9 2007-07-21 drh: #define TK_UPLUS 86 dbda8d6ce9 2007-07-21 drh: #define TK_BITNOT 87 dbda8d6ce9 2007-07-21 drh: #define TK_STRING 88 dbda8d6ce9 2007-07-21 drh: #define TK_JOIN_KW 89 dbda8d6ce9 2007-07-21 drh: #define TK_CONSTRAINT 90 dbda8d6ce9 2007-07-21 drh: #define TK_DEFAULT 91 dbda8d6ce9 2007-07-21 drh: #define TK_NULL 92 dbda8d6ce9 2007-07-21 drh: #define TK_PRIMARY 93 dbda8d6ce9 2007-07-21 drh: #define TK_UNIQUE 94 dbda8d6ce9 2007-07-21 drh: #define TK_CHECK 95 dbda8d6ce9 2007-07-21 drh: #define TK_REFERENCES 96 dbda8d6ce9 2007-07-21 drh: #define TK_AUTOINCR 97 dbda8d6ce9 2007-07-21 drh: #define TK_ON 98 dbda8d6ce9 2007-07-21 drh: #define TK_DELETE 99 dbda8d6ce9 2007-07-21 drh: #define TK_UPDATE 100 dbda8d6ce9 2007-07-21 drh: #define TK_INSERT 101 dbda8d6ce9 2007-07-21 drh: #define TK_SET 102 dbda8d6ce9 2007-07-21 drh: #define TK_DEFERRABLE 103 dbda8d6ce9 2007-07-21 drh: #define TK_FOREIGN 104 dbda8d6ce9 2007-07-21 drh: #define TK_DROP 105 dbda8d6ce9 2007-07-21 drh: #define TK_UNION 106 dbda8d6ce9 2007-07-21 drh: #define TK_ALL 107 dbda8d6ce9 2007-07-21 drh: #define TK_EXCEPT 108 dbda8d6ce9 2007-07-21 drh: #define TK_INTERSECT 109 dbda8d6ce9 2007-07-21 drh: #define TK_SELECT 110 dbda8d6ce9 2007-07-21 drh: #define TK_DISTINCT 111 dbda8d6ce9 2007-07-21 drh: #define TK_DOT 112 dbda8d6ce9 2007-07-21 drh: #define TK_FROM 113 dbda8d6ce9 2007-07-21 drh: #define TK_JOIN 114 dbda8d6ce9 2007-07-21 drh: #define TK_USING 115 dbda8d6ce9 2007-07-21 drh: #define TK_ORDER 116 dbda8d6ce9 2007-07-21 drh: #define TK_BY 117 dbda8d6ce9 2007-07-21 drh: #define TK_GROUP 118 dbda8d6ce9 2007-07-21 drh: #define TK_HAVING 119 dbda8d6ce9 2007-07-21 drh: #define TK_LIMIT 120 dbda8d6ce9 2007-07-21 drh: #define TK_WHERE 121 dbda8d6ce9 2007-07-21 drh: #define TK_INTO 122 dbda8d6ce9 2007-07-21 drh: #define TK_VALUES 123 dbda8d6ce9 2007-07-21 drh: #define TK_INTEGER 124 dbda8d6ce9 2007-07-21 drh: #define TK_FLOAT 125 dbda8d6ce9 2007-07-21 drh: #define TK_BLOB 126 dbda8d6ce9 2007-07-21 drh: #define TK_REGISTER 127 dbda8d6ce9 2007-07-21 drh: #define TK_VARIABLE 128 dbda8d6ce9 2007-07-21 drh: #define TK_CASE 129 dbda8d6ce9 2007-07-21 drh: #define TK_WHEN 130 dbda8d6ce9 2007-07-21 drh: #define TK_THEN 131 dbda8d6ce9 2007-07-21 drh: #define TK_ELSE 132 dbda8d6ce9 2007-07-21 drh: #define TK_INDEX 133 dbda8d6ce9 2007-07-21 drh: #define TK_ALTER 134 dbda8d6ce9 2007-07-21 drh: #define TK_TO 135 dbda8d6ce9 2007-07-21 drh: #define TK_ADD 136 dbda8d6ce9 2007-07-21 drh: #define TK_COLUMNKW 137 dbda8d6ce9 2007-07-21 drh: #define TK_TO_TEXT 138 dbda8d6ce9 2007-07-21 drh: #define TK_TO_BLOB 139 dbda8d6ce9 2007-07-21 drh: #define TK_TO_NUMERIC 140 dbda8d6ce9 2007-07-21 drh: #define TK_TO_INT 141 dbda8d6ce9 2007-07-21 drh: #define TK_TO_REAL 142 dbda8d6ce9 2007-07-21 drh: #define TK_END_OF_FILE 143 dbda8d6ce9 2007-07-21 drh: #define TK_ILLEGAL 144 dbda8d6ce9 2007-07-21 drh: #define TK_SPACE 145 dbda8d6ce9 2007-07-21 drh: #define TK_UNCLOSED_STRING 146 dbda8d6ce9 2007-07-21 drh: #define TK_COMMENT 147 dbda8d6ce9 2007-07-21 drh: #define TK_FUNCTION 148 dbda8d6ce9 2007-07-21 drh: #define TK_COLUMN 149 dbda8d6ce9 2007-07-21 drh: #define TK_AGG_FUNCTION 150 dbda8d6ce9 2007-07-21 drh: #define TK_AGG_COLUMN 151 dbda8d6ce9 2007-07-21 drh: #define TK_CONST_FUNC 152 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of parse.h ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: #include <stdio.h> dbda8d6ce9 2007-07-21 drh: #include <stdlib.h> dbda8d6ce9 2007-07-21 drh: #include <string.h> dbda8d6ce9 2007-07-21 drh: #include <assert.h> dbda8d6ce9 2007-07-21 drh: #include <stddef.h> dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define sqlite3_isnan(X) ((X)!=(X)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If compiling for a processor that lacks floating point support, dbda8d6ce9 2007-07-21 drh: ** substitute integer for floating-point dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: # define double sqlite_int64 dbda8d6ce9 2007-07-21 drh: # define LONGDOUBLE_TYPE sqlite_int64 dbda8d6ce9 2007-07-21 drh: # ifndef SQLITE_BIG_DBL dbda8d6ce9 2007-07-21 drh: # define SQLITE_BIG_DBL (0x7fffffffffffffff) dbda8d6ce9 2007-07-21 drh: # endif dbda8d6ce9 2007-07-21 drh: # define SQLITE_OMIT_DATETIME_FUNCS 1 dbda8d6ce9 2007-07-21 drh: # define SQLITE_OMIT_TRACE 1 dbda8d6ce9 2007-07-21 drh: # undef SQLITE_MIXED_ENDIAN_64BIT_FLOAT dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_BIG_DBL dbda8d6ce9 2007-07-21 drh: # define SQLITE_BIG_DBL (1e99) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0 dbda8d6ce9 2007-07-21 drh: ** afterward. Having this macro allows us to cause the C compiler dbda8d6ce9 2007-07-21 drh: ** to omit code used by TEMP tables without messy #ifndef statements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_TEMPDB dbda8d6ce9 2007-07-21 drh: #define OMIT_TEMPDB 1 dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define OMIT_TEMPDB 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the following macro is set to 1, then NULL values are considered dbda8d6ce9 2007-07-21 drh: ** distinct when determining whether or not two entries are the same dbda8d6ce9 2007-07-21 drh: ** in a UNIQUE index. This is the way PostgreSQL, Oracle, DB2, MySQL, dbda8d6ce9 2007-07-21 drh: ** OCELOT, and Firebird all work. The SQL92 spec explicitly says this dbda8d6ce9 2007-07-21 drh: ** is the way things are suppose to work. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the following macro is set to 0, the NULLs are indistinct for dbda8d6ce9 2007-07-21 drh: ** a UNIQUE index. In this mode, you can only have a single NULL entry dbda8d6ce9 2007-07-21 drh: ** for a column declared UNIQUE. This is the way Informix and SQL Server dbda8d6ce9 2007-07-21 drh: ** work. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define NULL_DISTINCT_FOR_UNIQUE 1 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The "file format" number is an integer that is incremented whenever dbda8d6ce9 2007-07-21 drh: ** the VDBE-level file format changes. The following macros define the dbda8d6ce9 2007-07-21 drh: ** the default file format for new databases and the maximum file format dbda8d6ce9 2007-07-21 drh: ** that the library can read. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_MAX_FILE_FORMAT 4 dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DEFAULT_FILE_FORMAT dbda8d6ce9 2007-07-21 drh: # define SQLITE_DEFAULT_FILE_FORMAT 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Provide a default value for TEMP_STORE in case it is not specified dbda8d6ce9 2007-07-21 drh: ** on the command-line dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef TEMP_STORE dbda8d6ce9 2007-07-21 drh: # define TEMP_STORE 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** GCC does not define the offsetof() macro so we'll have to do it dbda8d6ce9 2007-07-21 drh: ** ourselves. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef offsetof dbda8d6ce9 2007-07-21 drh: #define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if this machine uses EBCDIC. (Yes, believe it or dbda8d6ce9 2007-07-21 drh: ** not, there are still machines out there that use EBCDIC.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if 'A' == '\301' dbda8d6ce9 2007-07-21 drh: # define SQLITE_EBCDIC 1 dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define SQLITE_ASCII 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Integers of known sizes. These typedefs might change for architectures dbda8d6ce9 2007-07-21 drh: ** where the sizes very. Preprocessor macros are available so that the dbda8d6ce9 2007-07-21 drh: ** types can be conveniently redefined at compile-type. Like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** cc '-DUINTPTR_TYPE=long long int' ... dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef UINT32_TYPE dbda8d6ce9 2007-07-21 drh: # define UINT32_TYPE unsigned int dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef UINT16_TYPE dbda8d6ce9 2007-07-21 drh: # define UINT16_TYPE unsigned short int dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef INT16_TYPE dbda8d6ce9 2007-07-21 drh: # define INT16_TYPE short int dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef UINT8_TYPE dbda8d6ce9 2007-07-21 drh: # define UINT8_TYPE unsigned char dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef INT8_TYPE dbda8d6ce9 2007-07-21 drh: # define INT8_TYPE signed char dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef LONGDOUBLE_TYPE dbda8d6ce9 2007-07-21 drh: # define LONGDOUBLE_TYPE long double dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: typedef sqlite_int64 i64; /* 8-byte signed integer */ dbda8d6ce9 2007-07-21 drh: typedef sqlite_uint64 u64; /* 8-byte unsigned integer */ dbda8d6ce9 2007-07-21 drh: typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ dbda8d6ce9 2007-07-21 drh: typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ dbda8d6ce9 2007-07-21 drh: typedef INT16_TYPE i16; /* 2-byte signed integer */ dbda8d6ce9 2007-07-21 drh: typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ dbda8d6ce9 2007-07-21 drh: typedef UINT8_TYPE i8; /* 1-byte signed integer */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Macros to determine whether the machine is big or little endian, dbda8d6ce9 2007-07-21 drh: ** evaluated at runtime. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_AMALGAMATION c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const int sqlite3One; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const int sqlite3one; c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: #if defined(i386) || defined(__i386__) || defined(_M_IX86) dbda8d6ce9 2007-07-21 drh: # define SQLITE_BIGENDIAN 0 dbda8d6ce9 2007-07-21 drh: # define SQLITE_LITTLEENDIAN 1 dbda8d6ce9 2007-07-21 drh: # define SQLITE_UTF16NATIVE SQLITE_UTF16LE dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) dbda8d6ce9 2007-07-21 drh: # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) dbda8d6ce9 2007-07-21 drh: # define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure is used to store the busy-handler dbda8d6ce9 2007-07-21 drh: ** callback for a given sqlite handle. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite.busyHandler member of the sqlite struct contains the busy dbda8d6ce9 2007-07-21 drh: ** callback for the database handle. Each pager opened via the sqlite dbda8d6ce9 2007-07-21 drh: ** handle is passed a pointer to sqlite.busyHandler. The busy-handler dbda8d6ce9 2007-07-21 drh: ** callback is currently invoked only from within pager.c. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct BusyHandler BusyHandler; dbda8d6ce9 2007-07-21 drh: struct BusyHandler { dbda8d6ce9 2007-07-21 drh: int (*xFunc)(void *,int); /* The busy callback */ dbda8d6ce9 2007-07-21 drh: void *pArg; /* First arg to busy callback */ dbda8d6ce9 2007-07-21 drh: int nBusy; /* Incremented with each busy call */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Defer sourcing vdbe.h and btree.h until after the "u8" and dbda8d6ce9 2007-07-21 drh: ** "BusyHandler typedefs. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: /************** Include btree.h in the middle of sqliteInt.h *****************/ c287665ba8 2007-09-14 drh: /************** Begin file btree.h *******************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2001 September 15 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** This header file defines the interface that the sqlite B-Tree file c287665ba8 2007-09-14 drh: ** subsystem. See comments in the source code for a detailed description c287665ba8 2007-09-14 drh: ** of what each interface routine does. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: btree.h,v 1.93 2007/09/03 15:19:35 drh Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef _BTREE_H_ c287665ba8 2007-09-14 drh: #define _BTREE_H_ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* TODO: This definition is just included so other modules compile. It c287665ba8 2007-09-14 drh: ** needs to be revisited. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_N_BTREE_META 10 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** If defined as non-zero, auto-vacuum is enabled by default. Otherwise c287665ba8 2007-09-14 drh: ** it must be turned on for each database using "PRAGMA auto_vacuum = 1". c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef SQLITE_DEFAULT_AUTOVACUUM c287665ba8 2007-09-14 drh: #define SQLITE_DEFAULT_AUTOVACUUM 0 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #define BTREE_AUTOVACUUM_NONE 0 /* Do not do auto-vacuum */ c287665ba8 2007-09-14 drh: #define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */ c287665ba8 2007-09-14 drh: #define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Forward declarations of structure c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: typedef struct Btree Btree; c287665ba8 2007-09-14 drh: typedef struct BtCursor BtCursor; c287665ba8 2007-09-14 drh: typedef struct BtShared BtShared; c287665ba8 2007-09-14 drh: typedef struct BtreeMutexArray BtreeMutexArray; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This structure records all of the Btrees that need to hold c287665ba8 2007-09-14 drh: ** a mutex before we enter sqlite3VdbeExec(). The Btrees are c287665ba8 2007-09-14 drh: ** are placed in aBtree[] in order of aBtree[]->pBt. That way, c287665ba8 2007-09-14 drh: ** we can always lock and unlock them all quickly. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: struct BtreeMutexArray { c287665ba8 2007-09-14 drh: int nMutex; c287665ba8 2007-09-14 drh: Btree *aBtree[SQLITE_MAX_ATTACHED+1]; c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeOpen( c287665ba8 2007-09-14 drh: const char *zFilename, /* Name of database file to open */ c287665ba8 2007-09-14 drh: sqlite3 *db, /* Associated database connection */ c287665ba8 2007-09-14 drh: Btree **, /* Return open Btree* here */ c287665ba8 2007-09-14 drh: int flags, /* Flags */ c287665ba8 2007-09-14 drh: int vfsFlags /* Flags passed through to VFS open */ c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the c287665ba8 2007-09-14 drh: ** following values. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** NOTE: These values must match the corresponding PAGER_ values in c287665ba8 2007-09-14 drh: ** pager.h. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */ c287665ba8 2007-09-14 drh: #define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */ c287665ba8 2007-09-14 drh: #define BTREE_MEMORY 4 /* In-memory DB. No argument */ c287665ba8 2007-09-14 drh: #define BTREE_READONLY 8 /* Open the database in read-only mode */ c287665ba8 2007-09-14 drh: #define BTREE_READWRITE 16 /* Open for both reading and writing */ c287665ba8 2007-09-14 drh: #define BTREE_CREATE 32 /* Create the database if it does not exist */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Additional values for the 4th argument of sqlite3BtreeOpen that c287665ba8 2007-09-14 drh: ** are not associated with PAGER_ values. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define BTREE_PRIVATE 64 /* Never share with other connections */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree*,int,int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCommitStmt(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeRollbackStmt(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeIsInStmt(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *, int, u8); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char *sqlite3BtreeGetDirname(Btree *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR c287665ba8 2007-09-14 drh: ** of the following flags: c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ c287665ba8 2007-09-14 drh: #define BTREE_ZERODATA 2 /* Table has keys only - no data */ c287665ba8 2007-09-14 drh: #define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCursor( c287665ba8 2007-09-14 drh: Btree*, /* BTree containing table to open */ c287665ba8 2007-09-14 drh: int iTable, /* Index of root page */ c287665ba8 2007-09-14 drh: int wrFlag, /* 1 for writing. 0 for read-only */ c287665ba8 2007-09-14 drh: int(*)(void*,int,const void*,int,const void*), /* Key comparison function */ c287665ba8 2007-09-14 drh: void*, /* First argument to compare function */ c287665ba8 2007-09-14 drh: BtCursor **ppCursor /* Returned cursor */ c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, c287665ba8 2007-09-14 drh: const void *pData, int nData, c287665ba8 2007-09-14 drh: int nZero, int bias); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeFlags(BtCursor*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor*, i64 *pSize); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3 *sqlite3BtreeCursorDb(const BtCursor*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreePageDump(Btree*, int, int recursive); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** If we are not using shared cache, then there is no need to c287665ba8 2007-09-14 drh: ** use mutexes to access the BtShared structures. So make the c287665ba8 2007-09-14 drh: ** Enter and Leave procedures no-ops. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeMutexArrayEnter(BtreeMutexArray*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeMutexArrayLeave(BtreeMutexArray*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeMutexArrayInsert(BtreeMutexArray*, Btree*); c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: # define sqlite3BtreeEnter(X) c287665ba8 2007-09-14 drh: # define sqlite3BtreeLeave(X) c287665ba8 2007-09-14 drh: # define sqlite3BtreeHoldsMutex(X) 1 c287665ba8 2007-09-14 drh: # define sqlite3BtreeEnterCursor(X) c287665ba8 2007-09-14 drh: # define sqlite3BtreeLeaveCursor(X) c287665ba8 2007-09-14 drh: # define sqlite3BtreeEnterAll(X) c287665ba8 2007-09-14 drh: # define sqlite3BtreeLeaveAll(X) c287665ba8 2007-09-14 drh: # define sqlite3BtreeHoldsAllMutexes(X) 1 c287665ba8 2007-09-14 drh: # define sqlite3BtreeMutexArrayEnter(X) c287665ba8 2007-09-14 drh: # define sqlite3BtreeMutexArrayLeave(X) c287665ba8 2007-09-14 drh: # define sqlite3BtreeMutexArrayInsert(X,Y) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #endif /* _BTREE_H_ */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of btree.h ***********************************************/ c287665ba8 2007-09-14 drh: /************** Continuing where we left off in sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: /************** Include vdbe.h in the middle of sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vdbe.h ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** Header file for the Virtual DataBase Engine (VDBE) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This header defines the interface to the virtual database engine dbda8d6ce9 2007-07-21 drh: ** or VDBE. The VDBE implements an abstract machine that runs a dbda8d6ce9 2007-07-21 drh: ** simple program to access and modify the underlying database. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: vdbe.h,v 1.113 2007/08/30 01:19:59 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef _SQLITE_VDBE_H_ dbda8d6ce9 2007-07-21 drh: #define _SQLITE_VDBE_H_ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A single VDBE is an opaque structure named "Vdbe". Only routines dbda8d6ce9 2007-07-21 drh: ** in the source file sqliteVdbe.c are allowed to see the insides dbda8d6ce9 2007-07-21 drh: ** of this structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct Vdbe Vdbe; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A single instruction of the virtual machine has an opcode dbda8d6ce9 2007-07-21 drh: ** and as many as three operands. The instruction is recorded dbda8d6ce9 2007-07-21 drh: ** as an instance of the following structure: dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct VdbeOp { dbda8d6ce9 2007-07-21 drh: u8 opcode; /* What operation to perform */ dbda8d6ce9 2007-07-21 drh: int p1; /* First operand */ dbda8d6ce9 2007-07-21 drh: int p2; /* Second parameter (often the jump destination) */ dbda8d6ce9 2007-07-21 drh: char *p3; /* Third parameter */ dbda8d6ce9 2007-07-21 drh: int p3type; /* One of the P3_xxx constants defined below */ dbda8d6ce9 2007-07-21 drh: #ifdef VDBE_PROFILE dbda8d6ce9 2007-07-21 drh: int cnt; /* Number of times this instruction was executed */ dbda8d6ce9 2007-07-21 drh: long long cycles; /* Total time spend executing this instruction */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: typedef struct VdbeOp VdbeOp; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A smaller version of VdbeOp used for the VdbeAddOpList() function because dbda8d6ce9 2007-07-21 drh: ** it takes up less space. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct VdbeOpList { dbda8d6ce9 2007-07-21 drh: u8 opcode; /* What operation to perform */ dbda8d6ce9 2007-07-21 drh: signed char p1; /* First operand */ dbda8d6ce9 2007-07-21 drh: short int p2; /* Second parameter (often the jump destination) */ dbda8d6ce9 2007-07-21 drh: char *p3; /* Third parameter */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: typedef struct VdbeOpList VdbeOpList; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allowed values of VdbeOp.p3type dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define P3_NOTUSED 0 /* The P3 parameter is not used */ dbda8d6ce9 2007-07-21 drh: #define P3_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ dbda8d6ce9 2007-07-21 drh: #define P3_STATIC (-2) /* Pointer to a static string */ dbda8d6ce9 2007-07-21 drh: #define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */ dbda8d6ce9 2007-07-21 drh: #define P3_FUNCDEF (-5) /* P3 is a pointer to a FuncDef structure */ dbda8d6ce9 2007-07-21 drh: #define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */ dbda8d6ce9 2007-07-21 drh: #define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */ dbda8d6ce9 2007-07-21 drh: #define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */ dbda8d6ce9 2007-07-21 drh: #define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */ dbda8d6ce9 2007-07-21 drh: #define P3_VTAB (-10) /* P3 is a pointer to an sqlite3_vtab structure */ dbda8d6ce9 2007-07-21 drh: #define P3_MPRINTF (-11) /* P3 is a string obtained from sqlite3_mprintf() */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure dbda8d6ce9 2007-07-21 drh: ** is made. That copy is freed when the Vdbe is finalized. But if the dbda8d6ce9 2007-07-21 drh: ** argument is P3_KEYINFO_HANDOFF, the passed in pointer is used. It still dbda8d6ce9 2007-07-21 drh: ** gets freed when the Vdbe is finalized so it still should be obtained dbda8d6ce9 2007-07-21 drh: ** from a single sqliteMalloc(). But no copy is made and the calling dbda8d6ce9 2007-07-21 drh: ** function should *not* try to free the KeyInfo. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define P3_KEYINFO_HANDOFF (-9) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The Vdbe.aColName array contains 5n Mem structures, where n is the dbda8d6ce9 2007-07-21 drh: ** number of columns of data returned by the statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define COLNAME_NAME 0 dbda8d6ce9 2007-07-21 drh: #define COLNAME_DECLTYPE 1 dbda8d6ce9 2007-07-21 drh: #define COLNAME_DATABASE 2 dbda8d6ce9 2007-07-21 drh: #define COLNAME_TABLE 3 dbda8d6ce9 2007-07-21 drh: #define COLNAME_COLUMN 4 dbda8d6ce9 2007-07-21 drh: #define COLNAME_N 5 /* Number of COLNAME_xxx symbols */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following macro converts a relative address in the p2 field dbda8d6ce9 2007-07-21 drh: ** of a VdbeOp structure into a negative number so that dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeAddOpList() knows that the address is relative. Calling dbda8d6ce9 2007-07-21 drh: ** the macro again restores the address. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define ADDR(X) (-1-(X)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The makefile scans the vdbe.c source file and creates the "opcodes.h" dbda8d6ce9 2007-07-21 drh: ** header file that defines a number for each opcode used by the VDBE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /************** Include opcodes.h in the middle of vdbe.h ********************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file opcodes.h *****************************************/ dbda8d6ce9 2007-07-21 drh: /* Automatically generated. Do not edit */ dbda8d6ce9 2007-07-21 drh: /* See the mkopcodeh.awk script for details */ dbda8d6ce9 2007-07-21 drh: #define OP_MemLoad 1 dbda8d6ce9 2007-07-21 drh: #define OP_VNext 2 dbda8d6ce9 2007-07-21 drh: #define OP_HexBlob 126 /* same as TK_BLOB */ dbda8d6ce9 2007-07-21 drh: #define OP_Column 3 dbda8d6ce9 2007-07-21 drh: #define OP_SetCookie 4 dbda8d6ce9 2007-07-21 drh: #define OP_IfMemPos 5 dbda8d6ce9 2007-07-21 drh: #define OP_Real 125 /* same as TK_FLOAT */ dbda8d6ce9 2007-07-21 drh: #define OP_Sequence 6 dbda8d6ce9 2007-07-21 drh: #define OP_MoveGt 7 dbda8d6ce9 2007-07-21 drh: #define OP_Ge 72 /* same as TK_GE */ dbda8d6ce9 2007-07-21 drh: #define OP_RowKey 8 dbda8d6ce9 2007-07-21 drh: #define OP_Eq 68 /* same as TK_EQ */ dbda8d6ce9 2007-07-21 drh: #define OP_OpenWrite 9 dbda8d6ce9 2007-07-21 drh: #define OP_NotNull 66 /* same as TK_NOTNULL */ dbda8d6ce9 2007-07-21 drh: #define OP_If 10 dbda8d6ce9 2007-07-21 drh: #define OP_ToInt 141 /* same as TK_TO_INT */ dbda8d6ce9 2007-07-21 drh: #define OP_String8 88 /* same as TK_STRING */ dbda8d6ce9 2007-07-21 drh: #define OP_Pop 11 dbda8d6ce9 2007-07-21 drh: #define OP_VRowid 12 dbda8d6ce9 2007-07-21 drh: #define OP_CollSeq 13 dbda8d6ce9 2007-07-21 drh: #define OP_OpenRead 14 dbda8d6ce9 2007-07-21 drh: #define OP_Expire 15 dbda8d6ce9 2007-07-21 drh: #define OP_AutoCommit 17 dbda8d6ce9 2007-07-21 drh: #define OP_Gt 69 /* same as TK_GT */ dbda8d6ce9 2007-07-21 drh: #define OP_IntegrityCk 18 dbda8d6ce9 2007-07-21 drh: #define OP_Sort 19 dbda8d6ce9 2007-07-21 drh: #define OP_Function 20 dbda8d6ce9 2007-07-21 drh: #define OP_And 61 /* same as TK_AND */ dbda8d6ce9 2007-07-21 drh: #define OP_Subtract 79 /* same as TK_MINUS */ dbda8d6ce9 2007-07-21 drh: #define OP_Noop 21 dbda8d6ce9 2007-07-21 drh: #define OP_Return 22 dbda8d6ce9 2007-07-21 drh: #define OP_Remainder 82 /* same as TK_REM */ dbda8d6ce9 2007-07-21 drh: #define OP_NewRowid 23 dbda8d6ce9 2007-07-21 drh: #define OP_Multiply 80 /* same as TK_STAR */ dbda8d6ce9 2007-07-21 drh: #define OP_IfMemNeg 24 dbda8d6ce9 2007-07-21 drh: #define OP_Variable 25 dbda8d6ce9 2007-07-21 drh: #define OP_String 26 dbda8d6ce9 2007-07-21 drh: #define OP_RealAffinity 27 dbda8d6ce9 2007-07-21 drh: #define OP_VRename 28 dbda8d6ce9 2007-07-21 drh: #define OP_ParseSchema 29 dbda8d6ce9 2007-07-21 drh: #define OP_VOpen 30 dbda8d6ce9 2007-07-21 drh: #define OP_Close 31 dbda8d6ce9 2007-07-21 drh: #define OP_CreateIndex 32 dbda8d6ce9 2007-07-21 drh: #define OP_IsUnique 33 dbda8d6ce9 2007-07-21 drh: #define OP_NotFound 34 dbda8d6ce9 2007-07-21 drh: #define OP_Int64 35 dbda8d6ce9 2007-07-21 drh: #define OP_MustBeInt 36 dbda8d6ce9 2007-07-21 drh: #define OP_Halt 37 dbda8d6ce9 2007-07-21 drh: #define OP_Rowid 38 dbda8d6ce9 2007-07-21 drh: #define OP_IdxLT 39 dbda8d6ce9 2007-07-21 drh: #define OP_AddImm 40 dbda8d6ce9 2007-07-21 drh: #define OP_Statement 41 dbda8d6ce9 2007-07-21 drh: #define OP_RowData 42 dbda8d6ce9 2007-07-21 drh: #define OP_MemMax 43 dbda8d6ce9 2007-07-21 drh: #define OP_Push 44 dbda8d6ce9 2007-07-21 drh: #define OP_Or 60 /* same as TK_OR */ dbda8d6ce9 2007-07-21 drh: #define OP_NotExists 45 dbda8d6ce9 2007-07-21 drh: #define OP_MemIncr 46 dbda8d6ce9 2007-07-21 drh: #define OP_Gosub 47 dbda8d6ce9 2007-07-21 drh: #define OP_Divide 81 /* same as TK_SLASH */ dbda8d6ce9 2007-07-21 drh: #define OP_Integer 48 dbda8d6ce9 2007-07-21 drh: #define OP_ToNumeric 140 /* same as TK_TO_NUMERIC*/ dbda8d6ce9 2007-07-21 drh: #define OP_MemInt 49 dbda8d6ce9 2007-07-21 drh: #define OP_Prev 50 dbda8d6ce9 2007-07-21 drh: #define OP_Concat 83 /* same as TK_CONCAT */ dbda8d6ce9 2007-07-21 drh: #define OP_BitAnd 74 /* same as TK_BITAND */ dbda8d6ce9 2007-07-21 drh: #define OP_VColumn 51 dbda8d6ce9 2007-07-21 drh: #define OP_CreateTable 52 dbda8d6ce9 2007-07-21 drh: #define OP_Last 53 dbda8d6ce9 2007-07-21 drh: #define OP_IsNull 65 /* same as TK_ISNULL */ dbda8d6ce9 2007-07-21 drh: #define OP_IncrVacuum 54 dbda8d6ce9 2007-07-21 drh: #define OP_IdxRowid 55 dbda8d6ce9 2007-07-21 drh: #define OP_MakeIdxRec 56 dbda8d6ce9 2007-07-21 drh: #define OP_ShiftRight 77 /* same as TK_RSHIFT */ dbda8d6ce9 2007-07-21 drh: #define OP_ResetCount 57 dbda8d6ce9 2007-07-21 drh: #define OP_FifoWrite 58 dbda8d6ce9 2007-07-21 drh: #define OP_Callback 59 dbda8d6ce9 2007-07-21 drh: #define OP_ContextPush 62 dbda8d6ce9 2007-07-21 drh: #define OP_DropTrigger 63 dbda8d6ce9 2007-07-21 drh: #define OP_DropIndex 64 dbda8d6ce9 2007-07-21 drh: #define OP_IdxGE 73 dbda8d6ce9 2007-07-21 drh: #define OP_IdxDelete 84 dbda8d6ce9 2007-07-21 drh: #define OP_Vacuum 86 dbda8d6ce9 2007-07-21 drh: #define OP_MoveLe 89 dbda8d6ce9 2007-07-21 drh: #define OP_IfNot 90 dbda8d6ce9 2007-07-21 drh: #define OP_DropTable 91 dbda8d6ce9 2007-07-21 drh: #define OP_MakeRecord 92 dbda8d6ce9 2007-07-21 drh: #define OP_ToBlob 139 /* same as TK_TO_BLOB */ dbda8d6ce9 2007-07-21 drh: #define OP_Delete 93 dbda8d6ce9 2007-07-21 drh: #define OP_AggFinal 94 dbda8d6ce9 2007-07-21 drh: #define OP_ShiftLeft 76 /* same as TK_LSHIFT */ dbda8d6ce9 2007-07-21 drh: #define OP_Dup 95 dbda8d6ce9 2007-07-21 drh: #define OP_Goto 96 dbda8d6ce9 2007-07-21 drh: #define OP_TableLock 97 dbda8d6ce9 2007-07-21 drh: #define OP_FifoRead 98 dbda8d6ce9 2007-07-21 drh: #define OP_Clear 99 dbda8d6ce9 2007-07-21 drh: #define OP_IdxGT 100 dbda8d6ce9 2007-07-21 drh: #define OP_MoveLt 101 dbda8d6ce9 2007-07-21 drh: #define OP_Le 70 /* same as TK_LE */ dbda8d6ce9 2007-07-21 drh: #define OP_VerifyCookie 102 dbda8d6ce9 2007-07-21 drh: #define OP_AggStep 103 dbda8d6ce9 2007-07-21 drh: #define OP_Pull 104 dbda8d6ce9 2007-07-21 drh: #define OP_ToText 138 /* same as TK_TO_TEXT */ dbda8d6ce9 2007-07-21 drh: #define OP_Not 16 /* same as TK_NOT */ dbda8d6ce9 2007-07-21 drh: #define OP_ToReal 142 /* same as TK_TO_REAL */ dbda8d6ce9 2007-07-21 drh: #define OP_SetNumColumns 105 dbda8d6ce9 2007-07-21 drh: #define OP_AbsValue 106 dbda8d6ce9 2007-07-21 drh: #define OP_Transaction 107 dbda8d6ce9 2007-07-21 drh: #define OP_VFilter 108 dbda8d6ce9 2007-07-21 drh: #define OP_Negative 85 /* same as TK_UMINUS */ dbda8d6ce9 2007-07-21 drh: #define OP_Ne 67 /* same as TK_NE */ dbda8d6ce9 2007-07-21 drh: #define OP_VDestroy 109 dbda8d6ce9 2007-07-21 drh: #define OP_ContextPop 110 dbda8d6ce9 2007-07-21 drh: #define OP_BitOr 75 /* same as TK_BITOR */ dbda8d6ce9 2007-07-21 drh: #define OP_Next 111 dbda8d6ce9 2007-07-21 drh: #define OP_IdxInsert 112 dbda8d6ce9 2007-07-21 drh: #define OP_Distinct 113 dbda8d6ce9 2007-07-21 drh: #define OP_Lt 71 /* same as TK_LT */ dbda8d6ce9 2007-07-21 drh: #define OP_Insert 114 dbda8d6ce9 2007-07-21 drh: #define OP_Destroy 115 dbda8d6ce9 2007-07-21 drh: #define OP_ReadCookie 116 dbda8d6ce9 2007-07-21 drh: #define OP_ForceInt 117 dbda8d6ce9 2007-07-21 drh: #define OP_LoadAnalysis 118 dbda8d6ce9 2007-07-21 drh: #define OP_Explain 119 dbda8d6ce9 2007-07-21 drh: #define OP_IfMemZero 120 dbda8d6ce9 2007-07-21 drh: #define OP_OpenPseudo 121 dbda8d6ce9 2007-07-21 drh: #define OP_OpenEphemeral 122 dbda8d6ce9 2007-07-21 drh: #define OP_Null 123 dbda8d6ce9 2007-07-21 drh: #define OP_Blob 124 dbda8d6ce9 2007-07-21 drh: #define OP_Add 78 /* same as TK_PLUS */ dbda8d6ce9 2007-07-21 drh: #define OP_MemStore 127 dbda8d6ce9 2007-07-21 drh: #define OP_Rewind 128 dbda8d6ce9 2007-07-21 drh: #define OP_MoveGe 129 dbda8d6ce9 2007-07-21 drh: #define OP_VBegin 130 dbda8d6ce9 2007-07-21 drh: #define OP_VUpdate 131 dbda8d6ce9 2007-07-21 drh: #define OP_BitNot 87 /* same as TK_BITNOT */ dbda8d6ce9 2007-07-21 drh: #define OP_VCreate 132 dbda8d6ce9 2007-07-21 drh: #define OP_MemMove 133 dbda8d6ce9 2007-07-21 drh: #define OP_MemNull 134 dbda8d6ce9 2007-07-21 drh: #define OP_Found 135 dbda8d6ce9 2007-07-21 drh: #define OP_NullRow 136 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following opcode values are never used */ dbda8d6ce9 2007-07-21 drh: #define OP_NotUsed_137 137 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcodes that are guaranteed to never push a value onto the stack dbda8d6ce9 2007-07-21 drh: ** contain a 1 their corresponding position of the following mask dbda8d6ce9 2007-07-21 drh: ** set. See the opcodeNoPush() function in vdbeaux.c */ dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_0 0xeeb4 dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_1 0xf96b dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_2 0xfbb6 dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_3 0xfe64 dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_4 0xffff dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_5 0x6ef7 dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_6 0xfbfb dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_7 0x8767 dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_8 0x7d9f dbda8d6ce9 2007-07-21 drh: #define NOPUSH_MASK_9 0x0000 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of opcodes.h *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in vdbe.h ***********************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Prototypes for the VDBE interface. See comments on the implementation dbda8d6ce9 2007-07-21 drh: ** for a description of what each of these routines does. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeAddOp(Vdbe*,int,int,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*); dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeTrace(Vdbe*,FILE*); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3VdbeGetSql(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe*, const char*, ...); dbda8d6ce9 2007-07-21 drh: # define VdbeComment(X) sqlite3VdbeComment X dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define VdbeComment(X) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vdbe.h ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: /************** Include pager.h in the middle of sqliteInt.h *****************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file pager.h *******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This header file defines the interface that the sqlite page cache dbda8d6ce9 2007-07-21 drh: ** subsystem. The page cache subsystem reads and writes a file a page dbda8d6ce9 2007-07-21 drh: ** at a time and provides a journal for rollback. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: pager.h,v 1.67 2007/09/03 15:19:35 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef _PAGER_H_ dbda8d6ce9 2007-07-21 drh: #define _PAGER_H_ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The type used to represent a page number. The first page in a file dbda8d6ce9 2007-07-21 drh: ** is called page 1. 0 is used to represent "not a page". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef unsigned int Pgno; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each open file is managed by a separate instance of the "Pager" structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct Pager Pager; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Handle type for pages. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct PgHdr DbPage; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allowed values for the flags parameter to sqlite3PagerOpen(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** NOTE: This values must match the corresponding BTREE_ values in btree.h. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ dbda8d6ce9 2007-07-21 drh: #define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Valid values for the second argument to sqlite3PagerLockingMode(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define PAGER_LOCKINGMODE_QUERY -1 dbda8d6ce9 2007-07-21 drh: #define PAGER_LOCKINGMODE_NORMAL 0 dbda8d6ce9 2007-07-21 drh: #define PAGER_LOCKINGMODE_EXCLUSIVE 1 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** See source code comments for a detailed description of the following dbda8d6ce9 2007-07-21 drh: ** routines: dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetDestructor(Pager*, void(*)(DbPage*,int)); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int)); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u16*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); dbda8d6ce9 2007-07-21 drh: #define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0) dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerRef(DbPage*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerUnref(DbPage*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerPagecount(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerTruncate(Pager*,Pgno); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerBegin(DbPage*, int exFlag); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, Pgno); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerRollback(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerIsreadonly(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerStmtBegin(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerStmtCommit(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerStmtRollback(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerDontRollback(DbPage*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3PagerDirname(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerNosync(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerReleaseMemory(int); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_HAS_CODEC dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(NDEBUG) || defined(SQLITE_TEST) dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int *sqlite3PagerStats(Pager*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); dbda8d6ce9 2007-07-21 drh: int pager3_refinfo_enable; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: void disable_simulated_io_errors(void); dbda8d6ce9 2007-07-21 drh: void enable_simulated_io_errors(void); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define disable_simulated_io_errors() dbda8d6ce9 2007-07-21 drh: # define enable_simulated_io_errors() dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* _PAGER_H_ */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of pager.h ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Name of the master database table. The master database table dbda8d6ce9 2007-07-21 drh: ** is a special table that holds the names and attributes of all dbda8d6ce9 2007-07-21 drh: ** user tables and indices. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define MASTER_NAME "sqlite_master" dbda8d6ce9 2007-07-21 drh: #define TEMP_MASTER_NAME "sqlite_temp_master" dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The root-page of the master database table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define MASTER_ROOT 1 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The name of the schema table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A convenience macro that returns the number of elements in dbda8d6ce9 2007-07-21 drh: ** an array. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define ArraySize(X) (sizeof(X)/sizeof(X[0])) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Forward references to structures dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct AggInfo AggInfo; dbda8d6ce9 2007-07-21 drh: typedef struct AuthContext AuthContext; dbda8d6ce9 2007-07-21 drh: typedef struct CollSeq CollSeq; dbda8d6ce9 2007-07-21 drh: typedef struct Column Column; dbda8d6ce9 2007-07-21 drh: typedef struct Db Db; dbda8d6ce9 2007-07-21 drh: typedef struct Schema Schema; dbda8d6ce9 2007-07-21 drh: typedef struct Expr Expr; dbda8d6ce9 2007-07-21 drh: typedef struct ExprList ExprList; dbda8d6ce9 2007-07-21 drh: typedef struct FKey FKey; dbda8d6ce9 2007-07-21 drh: typedef struct FuncDef FuncDef; dbda8d6ce9 2007-07-21 drh: typedef struct IdList IdList; dbda8d6ce9 2007-07-21 drh: typedef struct Index Index; dbda8d6ce9 2007-07-21 drh: typedef struct KeyClass KeyClass; dbda8d6ce9 2007-07-21 drh: typedef struct KeyInfo KeyInfo; dbda8d6ce9 2007-07-21 drh: typedef struct Module Module; dbda8d6ce9 2007-07-21 drh: typedef struct NameContext NameContext; dbda8d6ce9 2007-07-21 drh: typedef struct Parse Parse; dbda8d6ce9 2007-07-21 drh: typedef struct Select Select; dbda8d6ce9 2007-07-21 drh: typedef struct SrcList SrcList; dbda8d6ce9 2007-07-21 drh: typedef struct Table Table; dbda8d6ce9 2007-07-21 drh: typedef struct TableLock TableLock; dbda8d6ce9 2007-07-21 drh: typedef struct Token Token; dbda8d6ce9 2007-07-21 drh: typedef struct TriggerStack TriggerStack; dbda8d6ce9 2007-07-21 drh: typedef struct TriggerStep TriggerStep; dbda8d6ce9 2007-07-21 drh: typedef struct Trigger Trigger; dbda8d6ce9 2007-07-21 drh: typedef struct WhereInfo WhereInfo; dbda8d6ce9 2007-07-21 drh: typedef struct WhereLevel WhereLevel; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** Include os.h in the middle of sqliteInt.h ********************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file os.h **********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 16 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This header file (together with is companion C source-code file dbda8d6ce9 2007-07-21 drh: ** "os.c") attempt to abstract the underlying operating system so that dbda8d6ce9 2007-07-21 drh: ** the SQLite library will work on both POSIX and windows systems. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This header file is #include-ed by sqliteInt.h and thus ends up c287665ba8 2007-09-14 drh: ** being included by every source file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef _SQLITE_OS_H_ dbda8d6ce9 2007-07-21 drh: #define _SQLITE_OS_H_ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Figure out if we are dealing with Unix, Windows, or some other c287665ba8 2007-09-14 drh: ** operating system. After the following block of preprocess macros, c287665ba8 2007-09-14 drh: ** all of OS_UNIX, OS_WIN, OS_OS2, and OS_OTHER will defined to either c287665ba8 2007-09-14 drh: ** 1 or 0. One of the four will be 1. The other three will be 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if defined(OS_OTHER) dbda8d6ce9 2007-07-21 drh: # if OS_OTHER==1 dbda8d6ce9 2007-07-21 drh: # undef OS_UNIX dbda8d6ce9 2007-07-21 drh: # define OS_UNIX 0 dbda8d6ce9 2007-07-21 drh: # undef OS_WIN dbda8d6ce9 2007-07-21 drh: # define OS_WIN 0 dbda8d6ce9 2007-07-21 drh: # undef OS_OS2 dbda8d6ce9 2007-07-21 drh: # define OS_OS2 0 dbda8d6ce9 2007-07-21 drh: # else dbda8d6ce9 2007-07-21 drh: # undef OS_OTHER dbda8d6ce9 2007-07-21 drh: # endif dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #if !defined(OS_UNIX) && !defined(OS_OTHER) dbda8d6ce9 2007-07-21 drh: # define OS_OTHER 0 dbda8d6ce9 2007-07-21 drh: # ifndef OS_WIN dbda8d6ce9 2007-07-21 drh: # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) dbda8d6ce9 2007-07-21 drh: # define OS_WIN 1 dbda8d6ce9 2007-07-21 drh: # define OS_UNIX 0 dbda8d6ce9 2007-07-21 drh: # define OS_OS2 0 dbda8d6ce9 2007-07-21 drh: # elif defined(__EMX__) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__) dbda8d6ce9 2007-07-21 drh: # define OS_WIN 0 dbda8d6ce9 2007-07-21 drh: # define OS_UNIX 0 dbda8d6ce9 2007-07-21 drh: # define OS_OS2 1 dbda8d6ce9 2007-07-21 drh: # else dbda8d6ce9 2007-07-21 drh: # define OS_WIN 0 dbda8d6ce9 2007-07-21 drh: # define OS_UNIX 1 dbda8d6ce9 2007-07-21 drh: # define OS_OS2 0 dbda8d6ce9 2007-07-21 drh: # endif dbda8d6ce9 2007-07-21 drh: # else dbda8d6ce9 2007-07-21 drh: # define OS_UNIX 0 dbda8d6ce9 2007-07-21 drh: # define OS_OS2 0 dbda8d6ce9 2007-07-21 drh: # endif dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # ifndef OS_WIN dbda8d6ce9 2007-07-21 drh: # define OS_WIN 0 dbda8d6ce9 2007-07-21 drh: # endif dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Define the maximum size of a temporary filename dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if OS_WIN dbda8d6ce9 2007-07-21 drh: # include <windows.h> dbda8d6ce9 2007-07-21 drh: # define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) dbda8d6ce9 2007-07-21 drh: #elif OS_OS2 dbda8d6ce9 2007-07-21 drh: # if (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 3) && defined(OS2_HIGH_MEMORY) dbda8d6ce9 2007-07-21 drh: # include <os2safe.h> /* has to be included before os2.h for linking to work */ dbda8d6ce9 2007-07-21 drh: # endif dbda8d6ce9 2007-07-21 drh: # define INCL_DOSDATETIME dbda8d6ce9 2007-07-21 drh: # define INCL_DOSFILEMGR dbda8d6ce9 2007-07-21 drh: # define INCL_DOSERRORS dbda8d6ce9 2007-07-21 drh: # define INCL_DOSMISC dbda8d6ce9 2007-07-21 drh: # define INCL_DOSPROCESS dbda8d6ce9 2007-07-21 drh: # define INCL_DOSMODULEMGR dbda8d6ce9 2007-07-21 drh: # include <os2.h> dbda8d6ce9 2007-07-21 drh: # define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define SQLITE_TEMPNAME_SIZE 200 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the SET_FULLSYNC macro is not defined above, then make it dbda8d6ce9 2007-07-21 drh: ** a no-op dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SET_FULLSYNC dbda8d6ce9 2007-07-21 drh: # define SET_FULLSYNC(x,y) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The default size of a disk sector dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DEFAULT_SECTOR_SIZE dbda8d6ce9 2007-07-21 drh: # define SQLITE_DEFAULT_SECTOR_SIZE 512 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Temporary files are named starting with this prefix followed by 16 random dbda8d6ce9 2007-07-21 drh: ** alphanumeric characters, and no file extension. They are stored in the dbda8d6ce9 2007-07-21 drh: ** OS's standard temporary file directory, and are deleted prior to exit. dbda8d6ce9 2007-07-21 drh: ** If sqlite is being embedded in another program, you may wish to change the dbda8d6ce9 2007-07-21 drh: ** prefix to reflect your program's name, so that if your program exits dbda8d6ce9 2007-07-21 drh: ** prematurely, old temporary files can be easily identified. This can be done c287665ba8 2007-09-14 drh: ** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2006-10-31: The default prefix used to be "sqlite_". But then dbda8d6ce9 2007-07-21 drh: ** Mcafee started using SQLite in their anti-virus product and it dbda8d6ce9 2007-07-21 drh: ** started putting files with the "sqlite" name in the c:/temp folder. dbda8d6ce9 2007-07-21 drh: ** This annoyed many windows users. Those users would then do a dbda8d6ce9 2007-07-21 drh: ** Google search for "sqlite", find the telephone numbers of the dbda8d6ce9 2007-07-21 drh: ** developers and call to wake them up at night and complain. dbda8d6ce9 2007-07-21 drh: ** For this reason, the default name prefix is changed to be "sqlite" dbda8d6ce9 2007-07-21 drh: ** spelled backwards. So the temp files are still identified, but dbda8d6ce9 2007-07-21 drh: ** anybody smart enough to figure out the code is also likely smart dbda8d6ce9 2007-07-21 drh: ** enough to know that calling the developer will not help get rid dbda8d6ce9 2007-07-21 drh: ** of the file. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #ifndef SQLITE_TEMP_FILE_PREFIX c287665ba8 2007-09-14 drh: # define SQLITE_TEMP_FILE_PREFIX "etilqs_" c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If using an alternative OS interface, then we must have an "os_other.h" dbda8d6ce9 2007-07-21 drh: ** header file available for that interface. Presumably the "os_other.h" dbda8d6ce9 2007-07-21 drh: ** header file contains #defines similar to those above. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if OS_OTHER dbda8d6ce9 2007-07-21 drh: # include "os_other.h" dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following values may be passed as the second argument to dbda8d6ce9 2007-07-21 drh: ** sqlite3OsLock(). The various locks exhibit the following semantics: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SHARED: Any number of processes may hold a SHARED lock simultaneously. dbda8d6ce9 2007-07-21 drh: ** RESERVED: A single process may hold a RESERVED lock on a file at dbda8d6ce9 2007-07-21 drh: ** any time. Other processes may hold and obtain new SHARED locks. dbda8d6ce9 2007-07-21 drh: ** PENDING: A single process may hold a PENDING lock on a file at dbda8d6ce9 2007-07-21 drh: ** any one time. Existing SHARED locks may persist, but no new dbda8d6ce9 2007-07-21 drh: ** SHARED locks may be obtained by other processes. dbda8d6ce9 2007-07-21 drh: ** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a dbda8d6ce9 2007-07-21 drh: ** process that requests an EXCLUSIVE lock may actually obtain a PENDING dbda8d6ce9 2007-07-21 drh: ** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to dbda8d6ce9 2007-07-21 drh: ** sqlite3OsLock(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define NO_LOCK 0 dbda8d6ce9 2007-07-21 drh: #define SHARED_LOCK 1 dbda8d6ce9 2007-07-21 drh: #define RESERVED_LOCK 2 dbda8d6ce9 2007-07-21 drh: #define PENDING_LOCK 3 dbda8d6ce9 2007-07-21 drh: #define EXCLUSIVE_LOCK 4 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** File Locking Notes: (Mostly about windows but also some info for Unix) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because dbda8d6ce9 2007-07-21 drh: ** those functions are not available. So we use only LockFile() and dbda8d6ce9 2007-07-21 drh: ** UnlockFile(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** LockFile() prevents not just writing but also reading by other processes. dbda8d6ce9 2007-07-21 drh: ** A SHARED_LOCK is obtained by locking a single randomly-chosen dbda8d6ce9 2007-07-21 drh: ** byte out of a specific range of bytes. The lock byte is obtained at dbda8d6ce9 2007-07-21 drh: ** random so two separate readers can probably access the file at the dbda8d6ce9 2007-07-21 drh: ** same time, unless they are unlucky and choose the same lock byte. dbda8d6ce9 2007-07-21 drh: ** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range. dbda8d6ce9 2007-07-21 drh: ** There can only be one writer. A RESERVED_LOCK is obtained by locking dbda8d6ce9 2007-07-21 drh: ** a single byte of the file that is designated as the reserved lock byte. dbda8d6ce9 2007-07-21 drh: ** A PENDING_LOCK is obtained by locking a designated byte different from dbda8d6ce9 2007-07-21 drh: ** the RESERVED_LOCK byte. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available, dbda8d6ce9 2007-07-21 drh: ** which means we can use reader/writer locks. When reader/writer locks dbda8d6ce9 2007-07-21 drh: ** are used, the lock is placed on the same range of bytes that is used dbda8d6ce9 2007-07-21 drh: ** for probabilistic locking in Win95/98/ME. Hence, the locking scheme dbda8d6ce9 2007-07-21 drh: ** will support two or more Win95 readers or two or more WinNT readers. dbda8d6ce9 2007-07-21 drh: ** But a single Win95 reader will lock out all WinNT readers and a single dbda8d6ce9 2007-07-21 drh: ** WinNT reader will lock out all other Win95 readers. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following #defines specify the range of bytes used for locking. dbda8d6ce9 2007-07-21 drh: ** SHARED_SIZE is the number of bytes available in the pool from which dbda8d6ce9 2007-07-21 drh: ** a random byte is selected for a shared lock. The pool of bytes for dbda8d6ce9 2007-07-21 drh: ** shared locks begins at SHARED_FIRST. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These #defines are available in sqlite_aux.h so that adaptors for dbda8d6ce9 2007-07-21 drh: ** connecting SQLite to other operating systems can use the same byte dbda8d6ce9 2007-07-21 drh: ** ranges for locking. In particular, the same locking strategy and dbda8d6ce9 2007-07-21 drh: ** byte ranges are used for Unix. This leaves open the possiblity of having dbda8d6ce9 2007-07-21 drh: ** clients on win95, winNT, and unix all talking to the same shared file dbda8d6ce9 2007-07-21 drh: ** and all locking correctly. To do so would require that samba (or whatever dbda8d6ce9 2007-07-21 drh: ** tool is being used for file sharing) implements locks correctly between dbda8d6ce9 2007-07-21 drh: ** windows and unix. I'm guessing that isn't likely to happen, but by dbda8d6ce9 2007-07-21 drh: ** using the same locking range we are at least open to the possibility. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Locking in windows is manditory. For this reason, we cannot store dbda8d6ce9 2007-07-21 drh: ** actual data in the bytes used for locking. The pager never allocates dbda8d6ce9 2007-07-21 drh: ** the pages involved in locking therefore. SHARED_SIZE is selected so dbda8d6ce9 2007-07-21 drh: ** that all locks will fit on a single page even at the minimum page size. dbda8d6ce9 2007-07-21 drh: ** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE dbda8d6ce9 2007-07-21 drh: ** is set high so that we don't have to allocate an unused page except dbda8d6ce9 2007-07-21 drh: ** for very large databases. But one should test the page skipping logic dbda8d6ce9 2007-07-21 drh: ** by setting PENDING_BYTE low and running the entire regression suite. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Changing the value of PENDING_BYTE results in a subtly incompatible dbda8d6ce9 2007-07-21 drh: ** file format. Depending on how it is changed, you might not notice dbda8d6ce9 2007-07-21 drh: ** the incompatibility right away, even running a full regression test. dbda8d6ce9 2007-07-21 drh: ** The default location of PENDING_BYTE is the first byte past the dbda8d6ce9 2007-07-21 drh: ** 1GB boundary. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: #define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */ dbda8d6ce9 2007-07-21 drh: #else c287665ba8 2007-09-14 drh: SQLITE_API extern unsigned int sqlite3_pending_byte; dbda8d6ce9 2007-07-21 drh: #define PENDING_BYTE sqlite3_pending_byte dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define RESERVED_BYTE (PENDING_BYTE+1) dbda8d6ce9 2007-07-21 drh: #define SHARED_FIRST (PENDING_BYTE+2) dbda8d6ce9 2007-07-21 drh: #define SHARED_SIZE 510 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Functions for accessing sqlite3_file methods c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Functions for accessing sqlite3_vfs methods c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsGetTempName(sqlite3_vfs *, char *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, char *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3OsDlSym(sqlite3_vfs *, void *, const char *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsCurrentTime(sqlite3_vfs *, double*); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Convenience functions for opening and closing files using c287665ba8 2007-09-14 drh: ** sqlite3_malloc() to obtain space for the file-handle structure. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Each OS-specific backend defines an instance of the following c287665ba8 2007-09-14 drh: ** structure for returning a pointer to its sqlite3_vfs. If OS_OTHER c287665ba8 2007-09-14 drh: ** is defined (meaning that the application-defined OS interface layer c287665ba8 2007-09-14 drh: ** is used) then there is no default VFS. The application must c287665ba8 2007-09-14 drh: ** register one or more VFS structures using sqlite3_vfs_register() c287665ba8 2007-09-14 drh: ** before attempting to use SQLite. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #if OS_UNIX || OS_WIN || OS_OS2 c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3_vfs *sqlite3OsDefaultVfs(void); c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: # define sqlite3OsDefaultVfs(X) 0 c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* _SQLITE_OS_H_ */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of os.h **************************************************/ c287665ba8 2007-09-14 drh: /************** Continuing where we left off in sqliteInt.h ******************/ c287665ba8 2007-09-14 drh: /************** Include mutex.h in the middle of sqliteInt.h *****************/ c287665ba8 2007-09-14 drh: /************** Begin file mutex.h *******************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 28 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This file contains the common header for all mutex implementations. c287665ba8 2007-09-14 drh: ** The sqliteInt.h header #includes this file so that it is available c287665ba8 2007-09-14 drh: ** to all source files. We break it out in an effort to keep the code c287665ba8 2007-09-14 drh: ** better organized. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** NOTE: source files should *not* #include this header file directly. c287665ba8 2007-09-14 drh: ** Source files should #include the sqliteInt.h file and let that file c287665ba8 2007-09-14 drh: ** include this one indirectly. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: mutex.h,v 1.2 2007/08/30 14:10:30 drh Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_MUTEX_APPDEF c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** If SQLITE_MUTEX_APPDEF is defined, then this whole module is c287665ba8 2007-09-14 drh: ** omitted and equivalent functionality must be provided by the c287665ba8 2007-09-14 drh: ** application that links against the SQLite library. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Figure out what version of the code to use. The choices are c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_NOOP For single-threaded applications that c287665ba8 2007-09-14 drh: ** do not desire error checking. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_NOOP_DEBUG For single-threaded applications with c287665ba8 2007-09-14 drh: ** error checking to help verify that mutexes c287665ba8 2007-09-14 drh: ** are being used correctly even though they c287665ba8 2007-09-14 drh: ** are not needed. Used when SQLITE_DEBUG is c287665ba8 2007-09-14 drh: ** defined on single-threaded builds. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_PTHREADS For multi-threaded applications on Unix. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_W32 For multi-threaded applications on Win32. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_OS2 For multi-threaded applications on OS/2. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define SQLITE_MUTEX_NOOP 1 /* The default */ c287665ba8 2007-09-14 drh: #if defined(SQLITE_DEBUG) && !SQLITE_THREADSAFE c287665ba8 2007-09-14 drh: # undef SQLITE_MUTEX_NOOP c287665ba8 2007-09-14 drh: # define SQLITE_MUTEX_NOOP_DEBUG c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: #if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_UNIX c287665ba8 2007-09-14 drh: # undef SQLITE_MUTEX_NOOP c287665ba8 2007-09-14 drh: # define SQLITE_MUTEX_PTHREADS c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: #if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_WIN c287665ba8 2007-09-14 drh: # undef SQLITE_MUTEX_NOOP c287665ba8 2007-09-14 drh: # define SQLITE_MUTEX_W32 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: #if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_OS2 c287665ba8 2007-09-14 drh: # undef SQLITE_MUTEX_NOOP c287665ba8 2007-09-14 drh: # define SQLITE_MUTEX_OS2 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_MUTEX_NOOP c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** If this is a no-op implementation, implement everything as macros. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) c287665ba8 2007-09-14 drh: #define sqlite3_mutex_free(X) c287665ba8 2007-09-14 drh: #define sqlite3_mutex_enter(X) c287665ba8 2007-09-14 drh: #define sqlite3_mutex_try(X) SQLITE_OK c287665ba8 2007-09-14 drh: #define sqlite3_mutex_leave(X) c287665ba8 2007-09-14 drh: #define sqlite3_mutex_held(X) 1 c287665ba8 2007-09-14 drh: #define sqlite3_mutex_notheld(X) 1 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #endif /* SQLITE_MUTEX_APPDEF */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of mutex.h ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in sqliteInt.h ******************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each database file to be accessed by the system is an instance dbda8d6ce9 2007-07-21 drh: ** of the following structure. There are normally two of these structures dbda8d6ce9 2007-07-21 drh: ** in the sqlite.aDb[] array. aDb[0] is the main database file and dbda8d6ce9 2007-07-21 drh: ** aDb[1] is the database file used to hold temporary tables. Additional dbda8d6ce9 2007-07-21 drh: ** databases may be attached. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Db { dbda8d6ce9 2007-07-21 drh: char *zName; /* Name of this database */ dbda8d6ce9 2007-07-21 drh: Btree *pBt; /* The B*Tree structure for this database file */ dbda8d6ce9 2007-07-21 drh: u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ dbda8d6ce9 2007-07-21 drh: u8 safety_level; /* How aggressive at synching data to disk */ dbda8d6ce9 2007-07-21 drh: void *pAux; /* Auxiliary data. Usually NULL */ dbda8d6ce9 2007-07-21 drh: void (*xFreeAux)(void*); /* Routine to free pAux */ dbda8d6ce9 2007-07-21 drh: Schema *pSchema; /* Pointer to database schema (possibly shared) */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure stores a database schema. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If there are no virtual tables configured in this schema, the dbda8d6ce9 2007-07-21 drh: ** Schema.db variable is set to NULL. After the first virtual table dbda8d6ce9 2007-07-21 drh: ** has been added, it is set to point to the database connection dbda8d6ce9 2007-07-21 drh: ** used to create the connection. Once a virtual table has been dbda8d6ce9 2007-07-21 drh: ** added to the Schema structure and the Schema.db variable populated, dbda8d6ce9 2007-07-21 drh: ** only that database connection may use the Schema to prepare dbda8d6ce9 2007-07-21 drh: ** statements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Schema { dbda8d6ce9 2007-07-21 drh: int schema_cookie; /* Database schema version number for this file */ dbda8d6ce9 2007-07-21 drh: Hash tblHash; /* All tables indexed by name */ dbda8d6ce9 2007-07-21 drh: Hash idxHash; /* All (named) indices indexed by name */ dbda8d6ce9 2007-07-21 drh: Hash trigHash; /* All triggers indexed by name */ dbda8d6ce9 2007-07-21 drh: Hash aFKey; /* Foreign keys indexed by to-table */ dbda8d6ce9 2007-07-21 drh: Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ dbda8d6ce9 2007-07-21 drh: u8 file_format; /* Schema format version for this file */ dbda8d6ce9 2007-07-21 drh: u8 enc; /* Text encoding used by this database */ dbda8d6ce9 2007-07-21 drh: u16 flags; /* Flags associated with this schema */ dbda8d6ce9 2007-07-21 drh: int cache_size; /* Number of pages to use in the cache */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: sqlite3 *db; /* "Owner" connection. See comment above */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** These macros can be used to test, set, or clear bits in the dbda8d6ce9 2007-07-21 drh: ** Db.flags field. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P)) dbda8d6ce9 2007-07-21 drh: #define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0) dbda8d6ce9 2007-07-21 drh: #define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P) dbda8d6ce9 2007-07-21 drh: #define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allowed values for the DB.flags field. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The DB_SchemaLoaded flag is set after the database schema has been dbda8d6ce9 2007-07-21 drh: ** read into internal hash tables. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** DB_UnresetViews means that one or more views have column names that dbda8d6ce9 2007-07-21 drh: ** have been filled out. If the schema changes, these column names might dbda8d6ce9 2007-07-21 drh: ** changes and so the view will need to be reset. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ dbda8d6ce9 2007-07-21 drh: #define DB_UnresetViews 0x0002 /* Some views have defined column names */ dbda8d6ce9 2007-07-21 drh: #define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each database is an instance of the following structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite.lastRowid records the last insert rowid generated by an dbda8d6ce9 2007-07-21 drh: ** insert statement. Inserts on views do not affect its value. Each dbda8d6ce9 2007-07-21 drh: ** trigger has its own context, so that lastRowid can be updated inside dbda8d6ce9 2007-07-21 drh: ** triggers as usual. The previous value will be restored once the trigger dbda8d6ce9 2007-07-21 drh: ** exits. Upon entering a before or instead of trigger, lastRowid is no dbda8d6ce9 2007-07-21 drh: ** longer (since after version 2.8.12) reset to -1. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite.nChange does not count changes within triggers and keeps no dbda8d6ce9 2007-07-21 drh: ** context. It is reset at start of sqlite3_exec. dbda8d6ce9 2007-07-21 drh: ** The sqlite.lsChange represents the number of changes made by the last dbda8d6ce9 2007-07-21 drh: ** insert, update, or delete statement. It remains constant throughout the dbda8d6ce9 2007-07-21 drh: ** length of a statement and is then updated by OP_SetCounts. It keeps a dbda8d6ce9 2007-07-21 drh: ** context stack just like lastRowid so that the count of changes dbda8d6ce9 2007-07-21 drh: ** within a trigger is not seen outside the trigger. Changes to views do not dbda8d6ce9 2007-07-21 drh: ** affect the value of lsChange. dbda8d6ce9 2007-07-21 drh: ** The sqlite.csChange keeps track of the number of current changes (since dbda8d6ce9 2007-07-21 drh: ** the last statement) and is used to update sqlite_lsChange. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The member variables sqlite.errCode, sqlite.zErrMsg and sqlite.zErrMsg16 dbda8d6ce9 2007-07-21 drh: ** store the most recent error code and, if applicable, string. The dbda8d6ce9 2007-07-21 drh: ** internal function sqlite3Error() is used to set these variables dbda8d6ce9 2007-07-21 drh: ** consistently. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct sqlite3 { c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs; /* OS Interface */ dbda8d6ce9 2007-07-21 drh: int nDb; /* Number of backends currently in use */ dbda8d6ce9 2007-07-21 drh: Db *aDb; /* All backends */ dbda8d6ce9 2007-07-21 drh: int flags; /* Miscellanous flags. See below */ c287665ba8 2007-09-14 drh: int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ dbda8d6ce9 2007-07-21 drh: int errCode; /* Most recent error code (SQLITE_*) */ dbda8d6ce9 2007-07-21 drh: int errMask; /* & result codes with this before returning */ dbda8d6ce9 2007-07-21 drh: u8 autoCommit; /* The auto-commit flag. */ dbda8d6ce9 2007-07-21 drh: u8 temp_store; /* 1: file 2: memory 0: default */ c287665ba8 2007-09-14 drh: u8 mallocFailed; /* True if we have seen a malloc failure */ dbda8d6ce9 2007-07-21 drh: int nTable; /* Number of tables in the database */ dbda8d6ce9 2007-07-21 drh: CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ dbda8d6ce9 2007-07-21 drh: i64 lastRowid; /* ROWID of most recent insert (see above) */ dbda8d6ce9 2007-07-21 drh: i64 priorNewRowid; /* Last randomly generated ROWID */ dbda8d6ce9 2007-07-21 drh: int magic; /* Magic number for detect library misuse */ dbda8d6ce9 2007-07-21 drh: int nChange; /* Value returned by sqlite3_changes() */ dbda8d6ce9 2007-07-21 drh: int nTotalChange; /* Value returned by sqlite3_total_changes() */ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex; /* Connection mutex */ dbda8d6ce9 2007-07-21 drh: struct sqlite3InitInfo { /* Information used during initialization */ dbda8d6ce9 2007-07-21 drh: int iDb; /* When back is being initialized */ dbda8d6ce9 2007-07-21 drh: int newTnum; /* Rootpage of table being initialized */ dbda8d6ce9 2007-07-21 drh: u8 busy; /* TRUE if currently initializing */ dbda8d6ce9 2007-07-21 drh: } init; dbda8d6ce9 2007-07-21 drh: int nExtension; /* Number of loaded extensions */ dbda8d6ce9 2007-07-21 drh: void **aExtension; /* Array of shared libraray handles */ dbda8d6ce9 2007-07-21 drh: struct Vdbe *pVdbe; /* List of active virtual machines */ dbda8d6ce9 2007-07-21 drh: int activeVdbeCnt; /* Number of vdbes currently executing */ dbda8d6ce9 2007-07-21 drh: void (*xTrace)(void*,const char*); /* Trace function */ dbda8d6ce9 2007-07-21 drh: void *pTraceArg; /* Argument to the trace function */ dbda8d6ce9 2007-07-21 drh: void (*xProfile)(void*,const char*,u64); /* Profiling function */ dbda8d6ce9 2007-07-21 drh: void *pProfileArg; /* Argument to profile function */ dbda8d6ce9 2007-07-21 drh: void *pCommitArg; /* Argument to xCommitCallback() */ dbda8d6ce9 2007-07-21 drh: int (*xCommitCallback)(void*); /* Invoked at every commit. */ dbda8d6ce9 2007-07-21 drh: void *pRollbackArg; /* Argument to xRollbackCallback() */ dbda8d6ce9 2007-07-21 drh: void (*xRollbackCallback)(void*); /* Invoked at every commit. */ dbda8d6ce9 2007-07-21 drh: void *pUpdateArg; dbda8d6ce9 2007-07-21 drh: void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); dbda8d6ce9 2007-07-21 drh: void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); dbda8d6ce9 2007-07-21 drh: void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); dbda8d6ce9 2007-07-21 drh: void *pCollNeededArg; dbda8d6ce9 2007-07-21 drh: sqlite3_value *pErr; /* Most recent error message */ dbda8d6ce9 2007-07-21 drh: char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ dbda8d6ce9 2007-07-21 drh: char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ dbda8d6ce9 2007-07-21 drh: union { dbda8d6ce9 2007-07-21 drh: int isInterrupted; /* True if sqlite3_interrupt has been called */ dbda8d6ce9 2007-07-21 drh: double notUsed1; /* Spacer */ dbda8d6ce9 2007-07-21 drh: } u1; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); dbda8d6ce9 2007-07-21 drh: /* Access authorization function */ dbda8d6ce9 2007-07-21 drh: void *pAuthArg; /* 1st argument to the access auth function */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PROGRESS_CALLBACK dbda8d6ce9 2007-07-21 drh: int (*xProgress)(void *); /* The progress callback */ dbda8d6ce9 2007-07-21 drh: void *pProgressArg; /* Argument to the progress callback */ dbda8d6ce9 2007-07-21 drh: int nProgressOps; /* Number of opcodes for progress callback */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: Hash aModule; /* populated by sqlite3_create_module() */ dbda8d6ce9 2007-07-21 drh: Table *pVTab; /* vtab with active Connect/Create method */ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab **aVTrans; /* Virtual tables with open transactions */ dbda8d6ce9 2007-07-21 drh: int nVTrans; /* Allocated size of aVTrans */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: Hash aFunc; /* All functions that can be in SQL exprs */ dbda8d6ce9 2007-07-21 drh: Hash aCollSeq; /* All collating sequences */ dbda8d6ce9 2007-07-21 drh: BusyHandler busyHandler; /* Busy callback */ dbda8d6ce9 2007-07-21 drh: int busyTimeout; /* Busy handler timeout, in msec */ dbda8d6ce9 2007-07-21 drh: Db aDbStatic[2]; /* Static space for the 2 default backends */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SSE dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: u8 dfltLockMode; /* Default locking-mode for attached dbs */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A macro to discover the encoding of a database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define ENC(db) ((db)->aDb[0].pSchema->enc) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Possible values for the sqlite.flags and or Db.flags fields. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On sqlite.flags, the SQLITE_InTrans value means that we have dbda8d6ce9 2007-07-21 drh: ** executed a BEGIN. On Db.flags, SQLITE_InTrans means a statement dbda8d6ce9 2007-07-21 drh: ** transaction is active on that particular database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_InTrans 0x00000008 /* True if in a transaction */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ShortColNames 0x00000040 /* Show short columns names */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */ dbda8d6ce9 2007-07-21 drh: /* DELETE, or UPDATE and return */ dbda8d6ce9 2007-07-21 drh: /* the count using a callback. */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ dbda8d6ce9 2007-07-21 drh: /* result set is empty */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_NoReadlock 0x00001000 /* Readlocks are omitted when dbda8d6ce9 2007-07-21 drh: ** accessing read-only databases */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */ c287665ba8 2007-09-14 drh: #define SQLITE_SharedCache 0x00080000 /* Cache sharing is enabled */ c287665ba8 2007-09-14 drh: #define SQLITE_Vtab 0x00100000 /* There exists a virtual table */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Possible values for the sqlite.magic field. dbda8d6ce9 2007-07-21 drh: ** The numbers are obtained at random and have no special meaning, other dbda8d6ce9 2007-07-21 drh: ** than being distinct from one another. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each SQL function is defined by an instance of the following dbda8d6ce9 2007-07-21 drh: ** structure. A pointer to this structure is stored in the sqlite.aFunc dbda8d6ce9 2007-07-21 drh: ** hash table. When multiple functions have the same name, the hash table dbda8d6ce9 2007-07-21 drh: ** points to a linked list of these structures. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct FuncDef { dbda8d6ce9 2007-07-21 drh: i16 nArg; /* Number of arguments. -1 means unlimited */ dbda8d6ce9 2007-07-21 drh: u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */ dbda8d6ce9 2007-07-21 drh: u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */ dbda8d6ce9 2007-07-21 drh: u8 flags; /* Some combination of SQLITE_FUNC_* */ dbda8d6ce9 2007-07-21 drh: void *pUserData; /* User data parameter */ dbda8d6ce9 2007-07-21 drh: FuncDef *pNext; /* Next function with same name */ dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */ dbda8d6ce9 2007-07-21 drh: void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */ dbda8d6ce9 2007-07-21 drh: void (*xFinalize)(sqlite3_context*); /* Aggregate finializer */ dbda8d6ce9 2007-07-21 drh: char zName[1]; /* SQL name of the function. MUST BE LAST */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each SQLite module (virtual table definition) is defined by an dbda8d6ce9 2007-07-21 drh: ** instance of the following structure, stored in the sqlite3.aModule dbda8d6ce9 2007-07-21 drh: ** hash table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Module { dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule; /* Callback pointers */ dbda8d6ce9 2007-07-21 drh: const char *zName; /* Name passed to create_module() */ dbda8d6ce9 2007-07-21 drh: void *pAux; /* pAux passed to create_module() */ dbda8d6ce9 2007-07-21 drh: void (*xDestroy)(void *); /* Module destructor function */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Possible values for FuncDef.flags dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_FUNC_EPHEM 0x04 /* Ephermeral. Delete with VDBE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** information about each column of an SQL table is held in an instance dbda8d6ce9 2007-07-21 drh: ** of this structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Column { dbda8d6ce9 2007-07-21 drh: char *zName; /* Name of this column */ dbda8d6ce9 2007-07-21 drh: Expr *pDflt; /* Default value of this column */ dbda8d6ce9 2007-07-21 drh: char *zType; /* Data type for this column */ dbda8d6ce9 2007-07-21 drh: char *zColl; /* Collating sequence. If NULL, use the default */ dbda8d6ce9 2007-07-21 drh: u8 notNull; /* True if there is a NOT NULL constraint */ dbda8d6ce9 2007-07-21 drh: u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */ dbda8d6ce9 2007-07-21 drh: char affinity; /* One of the SQLITE_AFF_... values */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: u8 isHidden; /* True if this column is 'hidden' */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A "Collating Sequence" is defined by an instance of the following dbda8d6ce9 2007-07-21 drh: ** structure. Conceptually, a collating sequence consists of a name and dbda8d6ce9 2007-07-21 drh: ** a comparison routine that defines the order of that sequence. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There may two seperate implementations of the collation function, one dbda8d6ce9 2007-07-21 drh: ** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that dbda8d6ce9 2007-07-21 drh: ** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine dbda8d6ce9 2007-07-21 drh: ** native byte order. When a collation sequence is invoked, SQLite selects dbda8d6ce9 2007-07-21 drh: ** the version that will require the least expensive encoding dbda8d6ce9 2007-07-21 drh: ** translations, if any. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The CollSeq.pUser member variable is an extra parameter that passed in dbda8d6ce9 2007-07-21 drh: ** as the first argument to the UTF-8 comparison function, xCmp. dbda8d6ce9 2007-07-21 drh: ** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function, dbda8d6ce9 2007-07-21 drh: ** xCmp16. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If both CollSeq.xCmp and CollSeq.xCmp16 are NULL, it means that the dbda8d6ce9 2007-07-21 drh: ** collating sequence is undefined. Indices built on an undefined dbda8d6ce9 2007-07-21 drh: ** collating sequence may not be read or written. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct CollSeq { dbda8d6ce9 2007-07-21 drh: char *zName; /* Name of the collating sequence, UTF-8 encoded */ dbda8d6ce9 2007-07-21 drh: u8 enc; /* Text encoding handled by xCmp() */ dbda8d6ce9 2007-07-21 drh: u8 type; /* One of the SQLITE_COLL_... values below */ dbda8d6ce9 2007-07-21 drh: void *pUser; /* First argument to xCmp() */ dbda8d6ce9 2007-07-21 drh: int (*xCmp)(void*,int, const void*, int, const void*); dbda8d6ce9 2007-07-21 drh: void (*xDel)(void*); /* Destructor for pUser */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allowed values of CollSeq flags: dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_COLL_BINARY 1 /* The default memcmp() collating sequence */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_COLL_NOCASE 2 /* The built-in NOCASE collating sequence */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_COLL_REVERSE 3 /* The built-in REVERSE collating sequence */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_COLL_USER 0 /* Any other user-defined collating sequence */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A sort order can be either ASC or DESC. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_SO_ASC 0 /* Sort in ascending order */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_SO_DESC 1 /* Sort in ascending order */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Column affinity types. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and dbda8d6ce9 2007-07-21 drh: ** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve dbda8d6ce9 2007-07-21 drh: ** the speed a little by number the values consecutively. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** But rather than start with 0 or 1, we begin with 'a'. That way, dbda8d6ce9 2007-07-21 drh: ** when multiple affinity types are concatenated into a string and dbda8d6ce9 2007-07-21 drh: ** used as the P3 operand, they will be more readable. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note also that the numeric types are grouped together so that testing dbda8d6ce9 2007-07-21 drh: ** for a numeric type is a single comparison. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_AFF_TEXT 'a' dbda8d6ce9 2007-07-21 drh: #define SQLITE_AFF_NONE 'b' dbda8d6ce9 2007-07-21 drh: #define SQLITE_AFF_NUMERIC 'c' dbda8d6ce9 2007-07-21 drh: #define SQLITE_AFF_INTEGER 'd' dbda8d6ce9 2007-07-21 drh: #define SQLITE_AFF_REAL 'e' dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each SQL table is represented in memory by an instance of the dbda8d6ce9 2007-07-21 drh: ** following structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Table.zName is the name of the table. The case of the original dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE statement is stored, but case is not significant for dbda8d6ce9 2007-07-21 drh: ** comparisons. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Table.nCol is the number of columns in this table. Table.aCol is a dbda8d6ce9 2007-07-21 drh: ** pointer to an array of Column structures, one for each column. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of dbda8d6ce9 2007-07-21 drh: ** the column that is that key. Otherwise Table.iPKey is negative. Note dbda8d6ce9 2007-07-21 drh: ** that the datatype of the PRIMARY KEY must be INTEGER for this field to dbda8d6ce9 2007-07-21 drh: ** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of dbda8d6ce9 2007-07-21 drh: ** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid dbda8d6ce9 2007-07-21 drh: ** is generated for each row of the table. Table.hasPrimKey is true if dbda8d6ce9 2007-07-21 drh: ** the table has any PRIMARY KEY, INTEGER or otherwise. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Table.tnum is the page number for the root BTree page of the table in the dbda8d6ce9 2007-07-21 drh: ** database file. If Table.iDb is the index of the database table backend dbda8d6ce9 2007-07-21 drh: ** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that dbda8d6ce9 2007-07-21 drh: ** holds temporary tables and indices. If Table.isEphem dbda8d6ce9 2007-07-21 drh: ** is true, then the table is stored in a file that is automatically deleted dbda8d6ce9 2007-07-21 drh: ** when the VDBE cursor to the table is closed. In this case Table.tnum dbda8d6ce9 2007-07-21 drh: ** refers VDBE cursor number that holds the table open, not to the root dbda8d6ce9 2007-07-21 drh: ** page number. Transient tables are used to hold the results of a dbda8d6ce9 2007-07-21 drh: ** sub-query that appears instead of a real table name in the FROM clause dbda8d6ce9 2007-07-21 drh: ** of a SELECT statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Table { dbda8d6ce9 2007-07-21 drh: char *zName; /* Name of the table */ dbda8d6ce9 2007-07-21 drh: int nCol; /* Number of columns in this table */ dbda8d6ce9 2007-07-21 drh: Column *aCol; /* Information about each column */ dbda8d6ce9 2007-07-21 drh: int iPKey; /* If not less then 0, use aCol[iPKey] as the primary key */ dbda8d6ce9 2007-07-21 drh: Index *pIndex; /* List of SQL indexes on this table. */ dbda8d6ce9 2007-07-21 drh: int tnum; /* Root BTree node for this table (see note above) */ dbda8d6ce9 2007-07-21 drh: Select *pSelect; /* NULL for tables. Points to definition if a view. */ dbda8d6ce9 2007-07-21 drh: int nRef; /* Number of pointers to this Table */ dbda8d6ce9 2007-07-21 drh: Trigger *pTrigger; /* List of SQL triggers on this table */ dbda8d6ce9 2007-07-21 drh: FKey *pFKey; /* Linked list of all foreign keys in this table */ dbda8d6ce9 2007-07-21 drh: char *zColAff; /* String defining the affinity of each column */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: Expr *pCheck; /* The AND of all CHECK constraints */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_ALTERTABLE dbda8d6ce9 2007-07-21 drh: int addColOffset; /* Offset in CREATE TABLE statement to add a new column */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: u8 readOnly; /* True if this table should not be written by the user */ dbda8d6ce9 2007-07-21 drh: u8 isEphem; /* True if created using OP_OpenEphermeral */ dbda8d6ce9 2007-07-21 drh: u8 hasPrimKey; /* True if there exists a primary key */ dbda8d6ce9 2007-07-21 drh: u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ dbda8d6ce9 2007-07-21 drh: u8 autoInc; /* True if the integer primary key is autoincrement */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: u8 isVirtual; /* True if this is a virtual table */ dbda8d6ce9 2007-07-21 drh: u8 isCommit; /* True once the CREATE TABLE has been committed */ dbda8d6ce9 2007-07-21 drh: Module *pMod; /* Pointer to the implementation of the module */ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab; /* Pointer to the module instance */ dbda8d6ce9 2007-07-21 drh: int nModuleArg; /* Number of arguments to the module */ dbda8d6ce9 2007-07-21 drh: char **azModuleArg; /* Text of all module args. [0] is module name */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: Schema *pSchema; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Test to see whether or not a table is a virtual table. This is dbda8d6ce9 2007-07-21 drh: ** done as a macro so that it will be optimized out when virtual dbda8d6ce9 2007-07-21 drh: ** table support is omitted from the build. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: # define IsVirtual(X) ((X)->isVirtual) dbda8d6ce9 2007-07-21 drh: # define IsHiddenColumn(X) ((X)->isHidden) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define IsVirtual(X) 0 dbda8d6ce9 2007-07-21 drh: # define IsHiddenColumn(X) 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each foreign key constraint is an instance of the following structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A foreign key is associated with two tables. The "from" table is dbda8d6ce9 2007-07-21 drh: ** the table that contains the REFERENCES clause that creates the foreign dbda8d6ce9 2007-07-21 drh: ** key. The "to" table is the table that is named in the REFERENCES clause. dbda8d6ce9 2007-07-21 drh: ** Consider this example: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE ex1( dbda8d6ce9 2007-07-21 drh: ** a INTEGER PRIMARY KEY, dbda8d6ce9 2007-07-21 drh: ** b INTEGER CONSTRAINT fk1 REFERENCES ex2(x) dbda8d6ce9 2007-07-21 drh: ** ); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each REFERENCES clause generates an instance of the following structure dbda8d6ce9 2007-07-21 drh: ** which is attached to the from-table. The to-table need not exist when dbda8d6ce9 2007-07-21 drh: ** the from-table is created. The existance of the to-table is not checked dbda8d6ce9 2007-07-21 drh: ** until an attempt is made to insert data into the from-table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite.aFKey hash table stores pointers to this structure dbda8d6ce9 2007-07-21 drh: ** given the name of a to-table. For each to-table, all foreign keys dbda8d6ce9 2007-07-21 drh: ** associated with that table are on a linked list using the FKey.pNextTo dbda8d6ce9 2007-07-21 drh: ** field. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct FKey { dbda8d6ce9 2007-07-21 drh: Table *pFrom; /* The table that constains the REFERENCES clause */ dbda8d6ce9 2007-07-21 drh: FKey *pNextFrom; /* Next foreign key in pFrom */ dbda8d6ce9 2007-07-21 drh: char *zTo; /* Name of table that the key points to */ dbda8d6ce9 2007-07-21 drh: FKey *pNextTo; /* Next foreign key that points to zTo */ dbda8d6ce9 2007-07-21 drh: int nCol; /* Number of columns in this key */ dbda8d6ce9 2007-07-21 drh: struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ dbda8d6ce9 2007-07-21 drh: int iFrom; /* Index of column in pFrom */ dbda8d6ce9 2007-07-21 drh: char *zCol; /* Name of column in zTo. If 0 use PRIMARY KEY */ dbda8d6ce9 2007-07-21 drh: } *aCol; /* One entry for each of nCol column s */ dbda8d6ce9 2007-07-21 drh: u8 isDeferred; /* True if constraint checking is deferred till COMMIT */ dbda8d6ce9 2007-07-21 drh: u8 updateConf; /* How to resolve conflicts that occur on UPDATE */ dbda8d6ce9 2007-07-21 drh: u8 deleteConf; /* How to resolve conflicts that occur on DELETE */ dbda8d6ce9 2007-07-21 drh: u8 insertConf; /* How to resolve conflicts that occur on INSERT */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** SQLite supports many different ways to resolve a contraint dbda8d6ce9 2007-07-21 drh: ** error. ROLLBACK processing means that a constraint violation dbda8d6ce9 2007-07-21 drh: ** causes the operation in process to fail and for the current transaction dbda8d6ce9 2007-07-21 drh: ** to be rolled back. ABORT processing means the operation in process dbda8d6ce9 2007-07-21 drh: ** fails and any prior changes from that one operation are backed out, dbda8d6ce9 2007-07-21 drh: ** but the transaction is not rolled back. FAIL processing means that dbda8d6ce9 2007-07-21 drh: ** the operation in progress stops and returns an error code. But prior dbda8d6ce9 2007-07-21 drh: ** changes due to the same operation are not backed out and no rollback dbda8d6ce9 2007-07-21 drh: ** occurs. IGNORE means that the particular row that caused the constraint dbda8d6ce9 2007-07-21 drh: ** error is not inserted or updated. Processing continues and no error dbda8d6ce9 2007-07-21 drh: ** is returned. REPLACE means that preexisting database rows that caused dbda8d6ce9 2007-07-21 drh: ** a UNIQUE constraint violation are removed so that the new insert or dbda8d6ce9 2007-07-21 drh: ** update can proceed. Processing continues and no error is reported. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys. dbda8d6ce9 2007-07-21 drh: ** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the dbda8d6ce9 2007-07-21 drh: ** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign dbda8d6ce9 2007-07-21 drh: ** key is set to NULL. CASCADE means that a DELETE or UPDATE of the dbda8d6ce9 2007-07-21 drh: ** referenced table row is propagated into the row that holds the dbda8d6ce9 2007-07-21 drh: ** foreign key. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following symbolic values are used to record which type dbda8d6ce9 2007-07-21 drh: ** of action to take. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define OE_None 0 /* There is no constraint to check */ dbda8d6ce9 2007-07-21 drh: #define OE_Rollback 1 /* Fail the operation and rollback the transaction */ dbda8d6ce9 2007-07-21 drh: #define OE_Abort 2 /* Back out changes but do no rollback transaction */ dbda8d6ce9 2007-07-21 drh: #define OE_Fail 3 /* Stop the operation but leave all prior changes */ dbda8d6ce9 2007-07-21 drh: #define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ dbda8d6ce9 2007-07-21 drh: #define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ dbda8d6ce9 2007-07-21 drh: #define OE_SetNull 7 /* Set the foreign key value to NULL */ dbda8d6ce9 2007-07-21 drh: #define OE_SetDflt 8 /* Set the foreign key value to its default */ dbda8d6ce9 2007-07-21 drh: #define OE_Cascade 9 /* Cascade the changes */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define OE_Default 99 /* Do whatever the default action is */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure is passed as the first dbda8d6ce9 2007-07-21 drh: ** argument to sqlite3VdbeKeyCompare and is used to control the dbda8d6ce9 2007-07-21 drh: ** comparison of the two index keys. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the KeyInfo.incrKey value is true and the comparison would dbda8d6ce9 2007-07-21 drh: ** otherwise be equal, then return a result as if the second key dbda8d6ce9 2007-07-21 drh: ** were larger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct KeyInfo { c287665ba8 2007-09-14 drh: sqlite3 *db; /* The database connection */ dbda8d6ce9 2007-07-21 drh: u8 enc; /* Text encoding - one of the TEXT_Utf* values */ dbda8d6ce9 2007-07-21 drh: u8 incrKey; /* Increase 2nd key by epsilon before comparison */ dbda8d6ce9 2007-07-21 drh: int nField; /* Number of entries in aColl[] */ dbda8d6ce9 2007-07-21 drh: u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */ dbda8d6ce9 2007-07-21 drh: CollSeq *aColl[1]; /* Collating sequence for each term of the key */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each SQL index is represented in memory by an dbda8d6ce9 2007-07-21 drh: ** instance of the following structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The columns of the table that are to be indexed are described dbda8d6ce9 2007-07-21 drh: ** by the aiColumn[] field of this structure. For example, suppose dbda8d6ce9 2007-07-21 drh: ** we have the following table and index: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE Ex1(c1 int, c2 int, c3 text); dbda8d6ce9 2007-07-21 drh: ** CREATE INDEX Ex2 ON Ex1(c3,c1); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the Table structure describing Ex1, nCol==3 because there are dbda8d6ce9 2007-07-21 drh: ** three columns in the table. In the Index structure describing dbda8d6ce9 2007-07-21 drh: ** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed. dbda8d6ce9 2007-07-21 drh: ** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the dbda8d6ce9 2007-07-21 drh: ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. dbda8d6ce9 2007-07-21 drh: ** The second column to be indexed (c1) has an index of 0 in dbda8d6ce9 2007-07-21 drh: ** Ex1.aCol[], hence Ex2.aiColumn[1]==0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The Index.onError field determines whether or not the indexed columns dbda8d6ce9 2007-07-21 drh: ** must be unique and what to do if they are not. When Index.onError=OE_None, dbda8d6ce9 2007-07-21 drh: ** it means this is not a unique index. Otherwise it is a unique index dbda8d6ce9 2007-07-21 drh: ** and the value of Index.onError indicate the which conflict resolution dbda8d6ce9 2007-07-21 drh: ** algorithm to employ whenever an attempt is made to insert a non-unique dbda8d6ce9 2007-07-21 drh: ** element. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Index { dbda8d6ce9 2007-07-21 drh: char *zName; /* Name of this index */ dbda8d6ce9 2007-07-21 drh: int nColumn; /* Number of columns in the table used by this index */ dbda8d6ce9 2007-07-21 drh: int *aiColumn; /* Which columns are used by this index. 1st is 0 */ dbda8d6ce9 2007-07-21 drh: unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ dbda8d6ce9 2007-07-21 drh: Table *pTable; /* The SQL table being indexed */ dbda8d6ce9 2007-07-21 drh: int tnum; /* Page containing root of this index in database file */ dbda8d6ce9 2007-07-21 drh: u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ dbda8d6ce9 2007-07-21 drh: u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ dbda8d6ce9 2007-07-21 drh: char *zColAff; /* String defining the affinity of each column */ dbda8d6ce9 2007-07-21 drh: Index *pNext; /* The next index associated with the same table */ dbda8d6ce9 2007-07-21 drh: Schema *pSchema; /* Schema containing this index */ dbda8d6ce9 2007-07-21 drh: u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ dbda8d6ce9 2007-07-21 drh: char **azColl; /* Array of collation sequence names for index */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each token coming out of the lexer is an instance of dbda8d6ce9 2007-07-21 drh: ** this structure. Tokens are also used as part of an expression. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note if Token.z==0 then Token.dyn and Token.n are undefined and dbda8d6ce9 2007-07-21 drh: ** may contain random values. Do not make any assuptions about Token.dyn dbda8d6ce9 2007-07-21 drh: ** and Token.n when Token.z==0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Token { dbda8d6ce9 2007-07-21 drh: const unsigned char *z; /* Text of the token. Not NULL-terminated! */ dbda8d6ce9 2007-07-21 drh: unsigned dyn : 1; /* True for malloced memory, false for static */ dbda8d6ce9 2007-07-21 drh: unsigned n : 31; /* Number of characters in this token */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of this structure contains information needed to generate dbda8d6ce9 2007-07-21 drh: ** code for a SELECT that contains aggregate functions. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a dbda8d6ce9 2007-07-21 drh: ** pointer to this structure. The Expr.iColumn field is the index in dbda8d6ce9 2007-07-21 drh: ** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate dbda8d6ce9 2007-07-21 drh: ** code for that node. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the dbda8d6ce9 2007-07-21 drh: ** original Select structure that describes the SELECT statement. These dbda8d6ce9 2007-07-21 drh: ** fields do not need to be freed when deallocating the AggInfo structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct AggInfo { dbda8d6ce9 2007-07-21 drh: u8 directMode; /* Direct rendering mode means take data directly dbda8d6ce9 2007-07-21 drh: ** from source tables rather than from accumulators */ dbda8d6ce9 2007-07-21 drh: u8 useSortingIdx; /* In direct mode, reference the sorting index rather dbda8d6ce9 2007-07-21 drh: ** than the source table */ dbda8d6ce9 2007-07-21 drh: int sortingIdx; /* Cursor number of the sorting index */ dbda8d6ce9 2007-07-21 drh: ExprList *pGroupBy; /* The group by clause */ dbda8d6ce9 2007-07-21 drh: int nSortingColumn; /* Number of columns in the sorting index */ dbda8d6ce9 2007-07-21 drh: struct AggInfo_col { /* For each column used in source tables */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* Source table */ dbda8d6ce9 2007-07-21 drh: int iTable; /* Cursor number of the source table */ dbda8d6ce9 2007-07-21 drh: int iColumn; /* Column number within the source table */ dbda8d6ce9 2007-07-21 drh: int iSorterColumn; /* Column number in the sorting index */ dbda8d6ce9 2007-07-21 drh: int iMem; /* Memory location that acts as accumulator */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr; /* The original expression */ dbda8d6ce9 2007-07-21 drh: } *aCol; dbda8d6ce9 2007-07-21 drh: int nColumn; /* Number of used entries in aCol[] */ dbda8d6ce9 2007-07-21 drh: int nColumnAlloc; /* Number of slots allocated for aCol[] */ dbda8d6ce9 2007-07-21 drh: int nAccumulator; /* Number of columns that show through to the output. dbda8d6ce9 2007-07-21 drh: ** Additional columns are used only as parameters to dbda8d6ce9 2007-07-21 drh: ** aggregate functions */ dbda8d6ce9 2007-07-21 drh: struct AggInfo_func { /* For each aggregate function */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr; /* Expression encoding the function */ dbda8d6ce9 2007-07-21 drh: FuncDef *pFunc; /* The aggregate function implementation */ dbda8d6ce9 2007-07-21 drh: int iMem; /* Memory location that acts as accumulator */ dbda8d6ce9 2007-07-21 drh: int iDistinct; /* Ephermeral table used to enforce DISTINCT */ dbda8d6ce9 2007-07-21 drh: } *aFunc; dbda8d6ce9 2007-07-21 drh: int nFunc; /* Number of entries in aFunc[] */ dbda8d6ce9 2007-07-21 drh: int nFuncAlloc; /* Number of slots allocated for aFunc[] */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each node of an expression in the parse tree is an instance dbda8d6ce9 2007-07-21 drh: ** of this structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Expr.op is the opcode. The integer parser token codes are reused dbda8d6ce9 2007-07-21 drh: ** as opcodes here. For example, the parser defines TK_GE to be an integer dbda8d6ce9 2007-07-21 drh: ** code representing the ">=" operator. This same integer code is reused dbda8d6ce9 2007-07-21 drh: ** to represent the greater-than-or-equal-to operator in the expression dbda8d6ce9 2007-07-21 drh: ** tree. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list dbda8d6ce9 2007-07-21 drh: ** of argument if the expression is a function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Expr.token is the operator token for this node. For some expressions dbda8d6ce9 2007-07-21 drh: ** that have subexpressions, Expr.token can be the complete text that gave dbda8d6ce9 2007-07-21 drh: ** rise to the Expr. In the latter case, the token is marked as being dbda8d6ce9 2007-07-21 drh: ** a compound token. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An expression of the form ID or ID.ID refers to a column in a table. dbda8d6ce9 2007-07-21 drh: ** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is dbda8d6ce9 2007-07-21 drh: ** the integer cursor number of a VDBE cursor pointing to that table and dbda8d6ce9 2007-07-21 drh: ** Expr.iColumn is the column number for the specific column. If the dbda8d6ce9 2007-07-21 drh: ** expression is used as a result in an aggregate SELECT, then the dbda8d6ce9 2007-07-21 drh: ** value is also stored in the Expr.iAgg column in the aggregate so that dbda8d6ce9 2007-07-21 drh: ** it can be accessed after all aggregates are computed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the expression is a function, the Expr.iTable is an integer code dbda8d6ce9 2007-07-21 drh: ** representing which function. If the expression is an unbound variable dbda8d6ce9 2007-07-21 drh: ** marker (a question mark character '?' in the original SQL) then the dbda8d6ce9 2007-07-21 drh: ** Expr.iTable holds the index number for that variable. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the expression is a subquery then Expr.iColumn holds an integer dbda8d6ce9 2007-07-21 drh: ** register number containing the result of the subquery. If the dbda8d6ce9 2007-07-21 drh: ** subquery gives a constant result, then iTable is -1. If the subquery dbda8d6ce9 2007-07-21 drh: ** gives a different answer at different times during statement processing dbda8d6ce9 2007-07-21 drh: ** then iTable is the address of a subroutine that computes the subquery. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The Expr.pSelect field points to a SELECT statement. The SELECT might dbda8d6ce9 2007-07-21 drh: ** be the right operand of an IN operator. Or, if a scalar SELECT appears dbda8d6ce9 2007-07-21 drh: ** in an expression the opcode is TK_SELECT and Expr.pSelect is the only dbda8d6ce9 2007-07-21 drh: ** operand. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the Expr is of type OP_Column, and the table it is selecting from dbda8d6ce9 2007-07-21 drh: ** is a disk table or the "old.*" pseudo-table, then pTab points to the dbda8d6ce9 2007-07-21 drh: ** corresponding table definition. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Expr { dbda8d6ce9 2007-07-21 drh: u8 op; /* Operation performed by this node */ dbda8d6ce9 2007-07-21 drh: char affinity; /* The affinity of the column or 0 if not a column */ dbda8d6ce9 2007-07-21 drh: u16 flags; /* Various flags. See below */ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; /* The collation type of the column or 0 */ dbda8d6ce9 2007-07-21 drh: Expr *pLeft, *pRight; /* Left and right subnodes */ dbda8d6ce9 2007-07-21 drh: ExprList *pList; /* A list of expressions used as function arguments dbda8d6ce9 2007-07-21 drh: ** or in "<expr> IN (<expr-list)" */ dbda8d6ce9 2007-07-21 drh: Token token; /* An operand token */ dbda8d6ce9 2007-07-21 drh: Token span; /* Complete text of the expression */ dbda8d6ce9 2007-07-21 drh: int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the dbda8d6ce9 2007-07-21 drh: ** iColumn-th field of the iTable-th table. */ dbda8d6ce9 2007-07-21 drh: AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ dbda8d6ce9 2007-07-21 drh: int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ dbda8d6ce9 2007-07-21 drh: int iRightJoinTable; /* If EP_FromJoin, the right table of the join */ dbda8d6ce9 2007-07-21 drh: Select *pSelect; /* When the expression is a sub-select. Also the dbda8d6ce9 2007-07-21 drh: ** right side of "<expr> IN (<select>)" */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* Table for OP_Column expressions. */ dbda8d6ce9 2007-07-21 drh: Schema *pSchema; c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 dbda8d6ce9 2007-07-21 drh: int nHeight; /* Height of the tree headed by this node */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following are the meanings of bits in the Expr.flags field. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define EP_FromJoin 0x01 /* Originated in ON or USING clause of a join */ dbda8d6ce9 2007-07-21 drh: #define EP_Agg 0x02 /* Contains one or more aggregate functions */ dbda8d6ce9 2007-07-21 drh: #define EP_Resolved 0x04 /* IDs have been resolved to COLUMNs */ dbda8d6ce9 2007-07-21 drh: #define EP_Error 0x08 /* Expression contains one or more errors */ dbda8d6ce9 2007-07-21 drh: #define EP_Distinct 0x10 /* Aggregate function with DISTINCT keyword */ dbda8d6ce9 2007-07-21 drh: #define EP_VarSelect 0x20 /* pSelect is correlated, not constant */ dbda8d6ce9 2007-07-21 drh: #define EP_Dequoted 0x40 /* True if the string has been dequoted */ dbda8d6ce9 2007-07-21 drh: #define EP_InfixFunc 0x80 /* True for an infix function: LIKE, GLOB, etc */ dbda8d6ce9 2007-07-21 drh: #define EP_ExpCollate 0x100 /* Collating sequence specified explicitly */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** These macros can be used to test, set, or clear bits in the dbda8d6ce9 2007-07-21 drh: ** Expr.flags field. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define ExprHasProperty(E,P) (((E)->flags&(P))==(P)) dbda8d6ce9 2007-07-21 drh: #define ExprHasAnyProperty(E,P) (((E)->flags&(P))!=0) dbda8d6ce9 2007-07-21 drh: #define ExprSetProperty(E,P) (E)->flags|=(P) dbda8d6ce9 2007-07-21 drh: #define ExprClearProperty(E,P) (E)->flags&=~(P) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A list of expressions. Each expression may optionally have a dbda8d6ce9 2007-07-21 drh: ** name. An expr/name combination can be used in several ways, such dbda8d6ce9 2007-07-21 drh: ** as the list of "expr AS ID" fields following a "SELECT" or in the dbda8d6ce9 2007-07-21 drh: ** list of "ID = expr" items in an UPDATE. A list of expressions can dbda8d6ce9 2007-07-21 drh: ** also be used as the argument to a function, in which case the a.zName dbda8d6ce9 2007-07-21 drh: ** field is not used. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct ExprList { dbda8d6ce9 2007-07-21 drh: int nExpr; /* Number of expressions on the list */ dbda8d6ce9 2007-07-21 drh: int nAlloc; /* Number of entries allocated below */ dbda8d6ce9 2007-07-21 drh: int iECursor; /* VDBE Cursor associated with this ExprList */ dbda8d6ce9 2007-07-21 drh: struct ExprList_item { dbda8d6ce9 2007-07-21 drh: Expr *pExpr; /* The list of expressions */ dbda8d6ce9 2007-07-21 drh: char *zName; /* Token associated with this expression */ dbda8d6ce9 2007-07-21 drh: u8 sortOrder; /* 1 for DESC or 0 for ASC */ dbda8d6ce9 2007-07-21 drh: u8 isAgg; /* True if this is an aggregate like count(*) */ dbda8d6ce9 2007-07-21 drh: u8 done; /* A flag to indicate when processing is finished */ dbda8d6ce9 2007-07-21 drh: } *a; /* One entry for each expression */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of this structure can hold a simple list of identifiers, dbda8d6ce9 2007-07-21 drh: ** such as the list "a,b,c" in the following statements: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** INSERT INTO t(a,b,c) VALUES ...; dbda8d6ce9 2007-07-21 drh: ** CREATE INDEX idx ON t(a,b,c); dbda8d6ce9 2007-07-21 drh: ** CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The IdList.a.idx field is used when the IdList represents the list of dbda8d6ce9 2007-07-21 drh: ** column names after a table name in an INSERT statement. In the statement dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** INSERT INTO t(a,b,c) ... dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If "a" is the k-th column of table "t", then IdList.a[0].idx==k. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct IdList { dbda8d6ce9 2007-07-21 drh: struct IdList_item { dbda8d6ce9 2007-07-21 drh: char *zName; /* Name of the identifier */ dbda8d6ce9 2007-07-21 drh: int idx; /* Index in some Table.aCol[] of a column named zName */ dbda8d6ce9 2007-07-21 drh: } *a; dbda8d6ce9 2007-07-21 drh: int nId; /* Number of identifiers on the list */ dbda8d6ce9 2007-07-21 drh: int nAlloc; /* Number of entries allocated for a[] below */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The bitmask datatype defined below is used for various optimizations. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Changing this from a 64-bit to a 32-bit type limits the number of dbda8d6ce9 2007-07-21 drh: ** tables in a join to 32 instead of 64. But it also reduces the size dbda8d6ce9 2007-07-21 drh: ** of the library by 738 bytes on ix86. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef u64 Bitmask; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following structure describes the FROM clause of a SELECT statement. dbda8d6ce9 2007-07-21 drh: ** Each table or subquery in the FROM clause is a separate element of dbda8d6ce9 2007-07-21 drh: ** the SrcList.a[] array. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** With the addition of multiple database support, the following structure dbda8d6ce9 2007-07-21 drh: ** can also be used to describe a particular table such as the table that dbda8d6ce9 2007-07-21 drh: ** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL, dbda8d6ce9 2007-07-21 drh: ** such a table must be a simple name: ID. But in SQLite, the table can dbda8d6ce9 2007-07-21 drh: ** now be identified by a database name, a dot, then the table name: ID.ID. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The jointype starts out showing the join type between the current table dbda8d6ce9 2007-07-21 drh: ** and the next table on the list. The parser builds the list this way. dbda8d6ce9 2007-07-21 drh: ** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each dbda8d6ce9 2007-07-21 drh: ** jointype expresses the join between the table and the previous table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct SrcList { dbda8d6ce9 2007-07-21 drh: i16 nSrc; /* Number of tables or subqueries in the FROM clause */ dbda8d6ce9 2007-07-21 drh: i16 nAlloc; /* Number of entries allocated in a[] below */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item { dbda8d6ce9 2007-07-21 drh: char *zDatabase; /* Name of database holding this table */ dbda8d6ce9 2007-07-21 drh: char *zName; /* Name of the table */ dbda8d6ce9 2007-07-21 drh: char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* An SQL table corresponding to zName */ dbda8d6ce9 2007-07-21 drh: Select *pSelect; /* A SELECT statement used in place of a table name */ dbda8d6ce9 2007-07-21 drh: u8 isPopulated; /* Temporary table associated with SELECT is populated */ dbda8d6ce9 2007-07-21 drh: u8 jointype; /* Type of join between this able and the previous */ dbda8d6ce9 2007-07-21 drh: int iCursor; /* The VDBE cursor number used to access this table */ dbda8d6ce9 2007-07-21 drh: Expr *pOn; /* The ON clause of a join */ dbda8d6ce9 2007-07-21 drh: IdList *pUsing; /* The USING clause of a join */ dbda8d6ce9 2007-07-21 drh: Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */ dbda8d6ce9 2007-07-21 drh: } a[1]; /* One entry for each identifier on the list */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Permitted values of the SrcList.a.jointype field dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define JT_INNER 0x0001 /* Any kind of inner or cross join */ dbda8d6ce9 2007-07-21 drh: #define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */ dbda8d6ce9 2007-07-21 drh: #define JT_NATURAL 0x0004 /* True for a "natural" join */ dbda8d6ce9 2007-07-21 drh: #define JT_LEFT 0x0008 /* Left outer join */ dbda8d6ce9 2007-07-21 drh: #define JT_RIGHT 0x0010 /* Right outer join */ dbda8d6ce9 2007-07-21 drh: #define JT_OUTER 0x0020 /* The "OUTER" keyword is present */ dbda8d6ce9 2007-07-21 drh: #define JT_ERROR 0x0040 /* unknown or unsupported join type */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** For each nested loop in a WHERE clause implementation, the WhereInfo dbda8d6ce9 2007-07-21 drh: ** structure contains a single instance of this structure. This structure dbda8d6ce9 2007-07-21 drh: ** is intended to be private the the where.c module and should not be dbda8d6ce9 2007-07-21 drh: ** access or modified by other modules. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pIdxInfo and pBestIdx fields are used to help pick the best dbda8d6ce9 2007-07-21 drh: ** index on a virtual table. The pIdxInfo pointer contains indexing dbda8d6ce9 2007-07-21 drh: ** information for the i-th table in the FROM clause before reordering. dbda8d6ce9 2007-07-21 drh: ** All the pIdxInfo pointers are freed by whereInfoFree() in where.c. dbda8d6ce9 2007-07-21 drh: ** The pBestIdx pointer is a copy of pIdxInfo for the i-th table after dbda8d6ce9 2007-07-21 drh: ** FROM clause ordering. This is a little confusing so I will repeat dbda8d6ce9 2007-07-21 drh: ** it in different words. WhereInfo.a[i].pIdxInfo is index information dbda8d6ce9 2007-07-21 drh: ** for WhereInfo.pTabList.a[i]. WhereInfo.a[i].pBestInfo is the dbda8d6ce9 2007-07-21 drh: ** index information for the i-th loop of the join. pBestInfo is always dbda8d6ce9 2007-07-21 drh: ** either NULL or a copy of some pIdxInfo. So for cleanup it is dbda8d6ce9 2007-07-21 drh: ** sufficient to free all of the pIdxInfo pointers. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct WhereLevel { dbda8d6ce9 2007-07-21 drh: int iFrom; /* Which entry in the FROM clause */ dbda8d6ce9 2007-07-21 drh: int flags; /* Flags associated with this level */ dbda8d6ce9 2007-07-21 drh: int iMem; /* First memory cell used by this level */ dbda8d6ce9 2007-07-21 drh: int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */ dbda8d6ce9 2007-07-21 drh: Index *pIdx; /* Index used. NULL if no index */ dbda8d6ce9 2007-07-21 drh: int iTabCur; /* The VDBE cursor used to access the table */ dbda8d6ce9 2007-07-21 drh: int iIdxCur; /* The VDBE cursor used to acesss pIdx */ dbda8d6ce9 2007-07-21 drh: int brk; /* Jump here to break out of the loop */ dbda8d6ce9 2007-07-21 drh: int nxt; /* Jump here to start the next IN combination */ dbda8d6ce9 2007-07-21 drh: int cont; /* Jump here to continue with the next loop cycle */ dbda8d6ce9 2007-07-21 drh: int top; /* First instruction of interior of the loop */ dbda8d6ce9 2007-07-21 drh: int op, p1, p2; /* Opcode used to terminate the loop */ dbda8d6ce9 2007-07-21 drh: int nEq; /* Number of == or IN constraints on this loop */ dbda8d6ce9 2007-07-21 drh: int nIn; /* Number of IN operators constraining this loop */ dbda8d6ce9 2007-07-21 drh: struct InLoop { dbda8d6ce9 2007-07-21 drh: int iCur; /* The VDBE cursor used by this IN operator */ dbda8d6ce9 2007-07-21 drh: int topAddr; /* Top of the IN loop */ dbda8d6ce9 2007-07-21 drh: } *aInLoop; /* Information about each nested IN operator */ dbda8d6ce9 2007-07-21 drh: sqlite3_index_info *pBestIdx; /* Index information for this level */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following field is really not part of the current level. But dbda8d6ce9 2007-07-21 drh: ** we need a place to cache index information for each table in the dbda8d6ce9 2007-07-21 drh: ** FROM clause and the WhereLevel structure is a convenient place. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The WHERE clause processing routine has two halves. The dbda8d6ce9 2007-07-21 drh: ** first part does the start of the WHERE loop and the second dbda8d6ce9 2007-07-21 drh: ** half does the tail of the WHERE loop. An instance of dbda8d6ce9 2007-07-21 drh: ** this structure is returned by the first half and passed dbda8d6ce9 2007-07-21 drh: ** into the second half to give some continuity. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct WhereInfo { dbda8d6ce9 2007-07-21 drh: Parse *pParse; dbda8d6ce9 2007-07-21 drh: SrcList *pTabList; /* List of tables in the join */ dbda8d6ce9 2007-07-21 drh: int iTop; /* The very beginning of the WHERE loop */ dbda8d6ce9 2007-07-21 drh: int iContinue; /* Jump here to continue with next record */ dbda8d6ce9 2007-07-21 drh: int iBreak; /* Jump here to break out of the loop */ dbda8d6ce9 2007-07-21 drh: int nLevel; /* Number of nested loop */ dbda8d6ce9 2007-07-21 drh: sqlite3_index_info **apInfo; /* Array of pointers to index info structures */ dbda8d6ce9 2007-07-21 drh: WhereLevel a[1]; /* Information about each nest loop in the WHERE */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A NameContext defines a context in which to resolve table and column dbda8d6ce9 2007-07-21 drh: ** names. The context consists of a list of tables (the pSrcList) field and dbda8d6ce9 2007-07-21 drh: ** a list of named expression (pEList). The named expression list may dbda8d6ce9 2007-07-21 drh: ** be NULL. The pSrc corresponds to the FROM clause of a SELECT or dbda8d6ce9 2007-07-21 drh: ** to the table being operated on by INSERT, UPDATE, or DELETE. The dbda8d6ce9 2007-07-21 drh: ** pEList corresponds to the result set of a SELECT and is NULL for dbda8d6ce9 2007-07-21 drh: ** other statements. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** NameContexts can be nested. When resolving names, the inner-most dbda8d6ce9 2007-07-21 drh: ** context is searched first. If no match is found, the next outer dbda8d6ce9 2007-07-21 drh: ** context is checked. If there is still no match, the next context dbda8d6ce9 2007-07-21 drh: ** is checked. This process continues until either a match is found dbda8d6ce9 2007-07-21 drh: ** or all contexts are check. When a match is found, the nRef member of dbda8d6ce9 2007-07-21 drh: ** the context containing the match is incremented. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each subquery gets a new NameContext. The pNext field points to the dbda8d6ce9 2007-07-21 drh: ** NameContext in the parent query. Thus the process of scanning the dbda8d6ce9 2007-07-21 drh: ** NameContext list corresponds to searching through successively outer dbda8d6ce9 2007-07-21 drh: ** subqueries looking for a match. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct NameContext { dbda8d6ce9 2007-07-21 drh: Parse *pParse; /* The parser */ dbda8d6ce9 2007-07-21 drh: SrcList *pSrcList; /* One or more tables used to resolve names */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList; /* Optional list of named expressions */ dbda8d6ce9 2007-07-21 drh: int nRef; /* Number of names resolved by this context */ dbda8d6ce9 2007-07-21 drh: int nErr; /* Number of errors encountered while resolving names */ dbda8d6ce9 2007-07-21 drh: u8 allowAgg; /* Aggregate functions allowed here */ dbda8d6ce9 2007-07-21 drh: u8 hasAgg; /* True if aggregates are seen */ dbda8d6ce9 2007-07-21 drh: u8 isCheck; /* True if resolving names in a CHECK constraint */ dbda8d6ce9 2007-07-21 drh: int nDepth; /* Depth of subquery recursion. 1 for no recursion */ dbda8d6ce9 2007-07-21 drh: AggInfo *pAggInfo; /* Information about aggregates at this level */ dbda8d6ce9 2007-07-21 drh: NameContext *pNext; /* Next outer name context. NULL for outermost */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure contains all information dbda8d6ce9 2007-07-21 drh: ** needed to generate code for a single SELECT statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. dbda8d6ce9 2007-07-21 drh: ** If there is a LIMIT clause, the parser sets nLimit to the value of the dbda8d6ce9 2007-07-21 drh: ** limit and nOffset to the value of the offset (or 0 if there is not dbda8d6ce9 2007-07-21 drh: ** offset). But later on, nLimit and nOffset become the memory locations dbda8d6ce9 2007-07-21 drh: ** in the VDBE that record the limit and offset counters. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. dbda8d6ce9 2007-07-21 drh: ** These addresses must be stored so that we can go back and fill in dbda8d6ce9 2007-07-21 drh: ** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor dbda8d6ce9 2007-07-21 drh: ** the number of columns in P2 can be computed at the same time dbda8d6ce9 2007-07-21 drh: ** as the OP_OpenEphm instruction is coded because not dbda8d6ce9 2007-07-21 drh: ** enough information about the compound query is known at that point. dbda8d6ce9 2007-07-21 drh: ** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences dbda8d6ce9 2007-07-21 drh: ** for the result set. The KeyInfo for addrOpenTran[2] contains collating dbda8d6ce9 2007-07-21 drh: ** sequences for the ORDER BY clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Select { dbda8d6ce9 2007-07-21 drh: ExprList *pEList; /* The fields of the result */ dbda8d6ce9 2007-07-21 drh: u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ dbda8d6ce9 2007-07-21 drh: u8 isDistinct; /* True if the DISTINCT keyword is present */ dbda8d6ce9 2007-07-21 drh: u8 isResolved; /* True once sqlite3SelectResolve() has run. */ dbda8d6ce9 2007-07-21 drh: u8 isAgg; /* True if this is an aggregate query */ dbda8d6ce9 2007-07-21 drh: u8 usesEphm; /* True if uses an OpenEphemeral opcode */ dbda8d6ce9 2007-07-21 drh: u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */ dbda8d6ce9 2007-07-21 drh: char affinity; /* MakeRecord with this affinity for SRT_Set */ dbda8d6ce9 2007-07-21 drh: SrcList *pSrc; /* The FROM clause */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere; /* The WHERE clause */ dbda8d6ce9 2007-07-21 drh: ExprList *pGroupBy; /* The GROUP BY clause */ dbda8d6ce9 2007-07-21 drh: Expr *pHaving; /* The HAVING clause */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy; /* The ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: Select *pPrior; /* Prior select in a compound select statement */ dbda8d6ce9 2007-07-21 drh: Select *pRightmost; /* Right-most select in a compound select statement */ dbda8d6ce9 2007-07-21 drh: Expr *pLimit; /* LIMIT expression. NULL means not used. */ dbda8d6ce9 2007-07-21 drh: Expr *pOffset; /* OFFSET expression. NULL means not used. */ dbda8d6ce9 2007-07-21 drh: int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ dbda8d6ce9 2007-07-21 drh: int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The results of a select can be distributed in several ways. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SRT_Union 1 /* Store result as keys in an index */ dbda8d6ce9 2007-07-21 drh: #define SRT_Except 2 /* Remove result from a UNION index */ dbda8d6ce9 2007-07-21 drh: #define SRT_Discard 3 /* Do not save the results anywhere */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The ORDER BY clause is ignored for all of the above */ dbda8d6ce9 2007-07-21 drh: #define IgnorableOrderby(X) (X<=SRT_Discard) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define SRT_Callback 4 /* Invoke a callback with each row of result */ dbda8d6ce9 2007-07-21 drh: #define SRT_Mem 5 /* Store result in a memory cell */ dbda8d6ce9 2007-07-21 drh: #define SRT_Set 6 /* Store non-null results as keys in an index */ dbda8d6ce9 2007-07-21 drh: #define SRT_Table 7 /* Store result as data with an automatic rowid */ dbda8d6ce9 2007-07-21 drh: #define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */ dbda8d6ce9 2007-07-21 drh: #define SRT_Subroutine 9 /* Call a subroutine to handle results */ dbda8d6ce9 2007-07-21 drh: #define SRT_Exists 10 /* Store 1 if the result is not empty */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An SQL parser context. A copy of this structure is passed through dbda8d6ce9 2007-07-21 drh: ** the parser and down into all the parser action routine in order to dbda8d6ce9 2007-07-21 drh: ** carry around information that is global to the entire parse. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The structure is divided into two parts. When the parser and code dbda8d6ce9 2007-07-21 drh: ** generate call themselves recursively, the first part of the structure dbda8d6ce9 2007-07-21 drh: ** is constant but the second part is reset at the beginning and end of dbda8d6ce9 2007-07-21 drh: ** each recursion. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The nTableLock and aTableLock variables are only used if the shared-cache dbda8d6ce9 2007-07-21 drh: ** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are dbda8d6ce9 2007-07-21 drh: ** used to store the set of table-locks required by the statement being dbda8d6ce9 2007-07-21 drh: ** compiled. Function sqlite3TableLock() is used to add entries to the dbda8d6ce9 2007-07-21 drh: ** list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Parse { dbda8d6ce9 2007-07-21 drh: sqlite3 *db; /* The main database structure */ dbda8d6ce9 2007-07-21 drh: int rc; /* Return code from execution */ dbda8d6ce9 2007-07-21 drh: char *zErrMsg; /* An error message */ dbda8d6ce9 2007-07-21 drh: Vdbe *pVdbe; /* An engine for executing database bytecode */ dbda8d6ce9 2007-07-21 drh: u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ dbda8d6ce9 2007-07-21 drh: u8 nameClash; /* A permanent table name clashes with temp table name */ dbda8d6ce9 2007-07-21 drh: u8 checkSchema; /* Causes schema cookie check after an error */ dbda8d6ce9 2007-07-21 drh: u8 nested; /* Number of nested calls to the parser/code generator */ dbda8d6ce9 2007-07-21 drh: u8 parseError; /* True after a parsing error. Ticket #1794 */ dbda8d6ce9 2007-07-21 drh: int nErr; /* Number of errors seen */ dbda8d6ce9 2007-07-21 drh: int nTab; /* Number of previously allocated VDBE cursors */ dbda8d6ce9 2007-07-21 drh: int nMem; /* Number of memory cells used so far */ dbda8d6ce9 2007-07-21 drh: int nSet; /* Number of sets used so far */ dbda8d6ce9 2007-07-21 drh: int ckOffset; /* Stack offset to data used by CHECK constraints */ dbda8d6ce9 2007-07-21 drh: u32 writeMask; /* Start a write transaction on these databases */ dbda8d6ce9 2007-07-21 drh: u32 cookieMask; /* Bitmask of schema verified databases */ dbda8d6ce9 2007-07-21 drh: int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ dbda8d6ce9 2007-07-21 drh: int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: int nTableLock; /* Number of locks in aTableLock */ dbda8d6ce9 2007-07-21 drh: TableLock *aTableLock; /* Required table locks for shared-cache mode */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Above is constant between recursions. Below is reset before and after dbda8d6ce9 2007-07-21 drh: ** each recursion */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int nVar; /* Number of '?' variables seen in the SQL so far */ dbda8d6ce9 2007-07-21 drh: int nVarExpr; /* Number of used slots in apVarExpr[] */ dbda8d6ce9 2007-07-21 drh: int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */ dbda8d6ce9 2007-07-21 drh: Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */ dbda8d6ce9 2007-07-21 drh: u8 explain; /* True if the EXPLAIN flag is found on the query */ dbda8d6ce9 2007-07-21 drh: Token sErrToken; /* The token at which the error occurred */ dbda8d6ce9 2007-07-21 drh: Token sNameToken; /* Token with unqualified schema object name */ dbda8d6ce9 2007-07-21 drh: Token sLastToken; /* The last token parsed */ dbda8d6ce9 2007-07-21 drh: const char *zSql; /* All SQL text */ dbda8d6ce9 2007-07-21 drh: const char *zTail; /* All SQL text past the last semicolon parsed */ dbda8d6ce9 2007-07-21 drh: Table *pNewTable; /* A table being constructed by CREATE TABLE */ dbda8d6ce9 2007-07-21 drh: Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ dbda8d6ce9 2007-07-21 drh: TriggerStack *trigStack; /* Trigger actions being coded */ dbda8d6ce9 2007-07-21 drh: const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: Token sArg; /* Complete text of a module argument */ dbda8d6ce9 2007-07-21 drh: u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ dbda8d6ce9 2007-07-21 drh: Table *pVirtualLock; /* Require virtual table lock on this table */ dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 dbda8d6ce9 2007-07-21 drh: int nHeight; /* Expression tree height of current sub-select */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: #define IN_DECLARE_VTAB 0 dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define IN_DECLARE_VTAB (pParse->declareVtab) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure can be declared on a stack and used dbda8d6ce9 2007-07-21 drh: ** to save the Parse.zAuthContext value so that it can be restored later. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct AuthContext { dbda8d6ce9 2007-07-21 drh: const char *zAuthContext; /* Put saved Parse.zAuthContext here */ dbda8d6ce9 2007-07-21 drh: Parse *pParse; /* The Parse structure */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Bitfield flags for P2 value in OP_Insert and OP_Delete dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define OPFLAG_NCHANGE 1 /* Set to update db->nChange */ dbda8d6ce9 2007-07-21 drh: #define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */ dbda8d6ce9 2007-07-21 drh: #define OPFLAG_ISUPDATE 4 /* This OP_Insert is an sql UPDATE */ dbda8d6ce9 2007-07-21 drh: #define OPFLAG_APPEND 8 /* This is likely to be an append */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * Each trigger present in the database schema is stored as an instance of dbda8d6ce9 2007-07-21 drh: * struct Trigger. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * Pointers to instances of struct Trigger are stored in two ways. dbda8d6ce9 2007-07-21 drh: * 1. In the "trigHash" hash table (part of the sqlite3* that represents the dbda8d6ce9 2007-07-21 drh: * database). This allows Trigger structures to be retrieved by name. dbda8d6ce9 2007-07-21 drh: * 2. All triggers associated with a single table form a linked list, using the dbda8d6ce9 2007-07-21 drh: * pNext member of struct Trigger. A pointer to the first element of the dbda8d6ce9 2007-07-21 drh: * linked list is stored as the "pTrigger" member of the associated dbda8d6ce9 2007-07-21 drh: * struct Table. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * The "step_list" member points to the first element of a linked list dbda8d6ce9 2007-07-21 drh: * containing the SQL statements specified as the trigger program. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Trigger { dbda8d6ce9 2007-07-21 drh: char *name; /* The name of the trigger */ dbda8d6ce9 2007-07-21 drh: char *table; /* The table or view to which the trigger applies */ dbda8d6ce9 2007-07-21 drh: u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ dbda8d6ce9 2007-07-21 drh: u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ dbda8d6ce9 2007-07-21 drh: Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */ dbda8d6ce9 2007-07-21 drh: IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger, dbda8d6ce9 2007-07-21 drh: the <column-list> is stored here */ dbda8d6ce9 2007-07-21 drh: Token nameToken; /* Token containing zName. Use during parsing only */ dbda8d6ce9 2007-07-21 drh: Schema *pSchema; /* Schema containing the trigger */ dbda8d6ce9 2007-07-21 drh: Schema *pTabSchema; /* Schema containing the table */ dbda8d6ce9 2007-07-21 drh: TriggerStep *step_list; /* Link list of trigger program steps */ dbda8d6ce9 2007-07-21 drh: Trigger *pNext; /* Next trigger associated with the table */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A trigger is either a BEFORE or an AFTER trigger. The following constants dbda8d6ce9 2007-07-21 drh: ** determine which. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If there are multiple triggers, you might of some BEFORE and some AFTER. dbda8d6ce9 2007-07-21 drh: ** In that cases, the constants below can be ORed together. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define TRIGGER_BEFORE 1 dbda8d6ce9 2007-07-21 drh: #define TRIGGER_AFTER 2 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * An instance of struct TriggerStep is used to store a single SQL statement dbda8d6ce9 2007-07-21 drh: * that is a part of a trigger-program. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * Instances of struct TriggerStep are stored in a singly linked list (linked dbda8d6ce9 2007-07-21 drh: * using the "pNext" member) referenced by the "step_list" member of the dbda8d6ce9 2007-07-21 drh: * associated struct Trigger instance. The first element of the linked list is dbda8d6ce9 2007-07-21 drh: * the first step of the trigger-program. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or dbda8d6ce9 2007-07-21 drh: * "SELECT" statement. The meanings of the other members is determined by the dbda8d6ce9 2007-07-21 drh: * value of "op" as follows: dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * (op == TK_INSERT) dbda8d6ce9 2007-07-21 drh: * orconf -> stores the ON CONFLICT algorithm dbda8d6ce9 2007-07-21 drh: * pSelect -> If this is an INSERT INTO ... SELECT ... statement, then dbda8d6ce9 2007-07-21 drh: * this stores a pointer to the SELECT statement. Otherwise NULL. dbda8d6ce9 2007-07-21 drh: * target -> A token holding the name of the table to insert into. dbda8d6ce9 2007-07-21 drh: * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then dbda8d6ce9 2007-07-21 drh: * this stores values to be inserted. Otherwise NULL. dbda8d6ce9 2007-07-21 drh: * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ... dbda8d6ce9 2007-07-21 drh: * statement, then this stores the column-names to be dbda8d6ce9 2007-07-21 drh: * inserted into. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * (op == TK_DELETE) dbda8d6ce9 2007-07-21 drh: * target -> A token holding the name of the table to delete from. dbda8d6ce9 2007-07-21 drh: * pWhere -> The WHERE clause of the DELETE statement if one is specified. dbda8d6ce9 2007-07-21 drh: * Otherwise NULL. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * (op == TK_UPDATE) dbda8d6ce9 2007-07-21 drh: * target -> A token holding the name of the table to update rows of. dbda8d6ce9 2007-07-21 drh: * pWhere -> The WHERE clause of the UPDATE statement if one is specified. dbda8d6ce9 2007-07-21 drh: * Otherwise NULL. dbda8d6ce9 2007-07-21 drh: * pExprList -> A list of the columns to update and the expressions to update dbda8d6ce9 2007-07-21 drh: * them to. See sqlite3Update() documentation of "pChanges" dbda8d6ce9 2007-07-21 drh: * argument. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct TriggerStep { dbda8d6ce9 2007-07-21 drh: int op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ dbda8d6ce9 2007-07-21 drh: int orconf; /* OE_Rollback etc. */ dbda8d6ce9 2007-07-21 drh: Trigger *pTrig; /* The trigger that this step is a part of */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: Select *pSelect; /* Valid for SELECT and sometimes c287665ba8 2007-09-14 drh: INSERT steps (when pExprList == 0) */ dbda8d6ce9 2007-07-21 drh: Token target; /* Valid for DELETE, UPDATE, INSERT steps */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere; /* Valid for DELETE, UPDATE steps */ dbda8d6ce9 2007-07-21 drh: ExprList *pExprList; /* Valid for UPDATE statements and sometimes c287665ba8 2007-09-14 drh: INSERT steps (when pSelect == 0) */ dbda8d6ce9 2007-07-21 drh: IdList *pIdList; /* Valid for INSERT statements only */ dbda8d6ce9 2007-07-21 drh: TriggerStep *pNext; /* Next in the link-list */ dbda8d6ce9 2007-07-21 drh: TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * An instance of struct TriggerStack stores information required during code dbda8d6ce9 2007-07-21 drh: * generation of a single trigger program. While the trigger program is being dbda8d6ce9 2007-07-21 drh: * coded, its associated TriggerStack instance is pointed to by the dbda8d6ce9 2007-07-21 drh: * "pTriggerStack" member of the Parse structure. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * The pTab member points to the table that triggers are being coded on. The dbda8d6ce9 2007-07-21 drh: * newIdx member contains the index of the vdbe cursor that points at the temp dbda8d6ce9 2007-07-21 drh: * table that stores the new.* references. If new.* references are not valid dbda8d6ce9 2007-07-21 drh: * for the trigger being coded (for example an ON DELETE trigger), then newIdx dbda8d6ce9 2007-07-21 drh: * is set to -1. The oldIdx member is analogous to newIdx, for old.* references. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * The ON CONFLICT policy to be used for the trigger program steps is stored dbda8d6ce9 2007-07-21 drh: * as the orconf member. If this is OE_Default, then the ON CONFLICT clause dbda8d6ce9 2007-07-21 drh: * specified for individual triggers steps is used. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * struct TriggerStack has a "pNext" member, to allow linked lists to be dbda8d6ce9 2007-07-21 drh: * constructed. When coding nested triggers (triggers fired by other triggers) dbda8d6ce9 2007-07-21 drh: * each nested trigger stores its parent trigger's TriggerStack as the "pNext" dbda8d6ce9 2007-07-21 drh: * pointer. Once the nested trigger has been coded, the pNext value is restored dbda8d6ce9 2007-07-21 drh: * to the pTriggerStack member of the Parse stucture and coding of the parent dbda8d6ce9 2007-07-21 drh: * trigger continues. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * Before a nested trigger is coded, the linked list pointed to by the dbda8d6ce9 2007-07-21 drh: * pTriggerStack is scanned to ensure that the trigger is not about to be coded dbda8d6ce9 2007-07-21 drh: * recursively. If this condition is detected, the nested trigger is not coded. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct TriggerStack { dbda8d6ce9 2007-07-21 drh: Table *pTab; /* Table that triggers are currently being coded on */ dbda8d6ce9 2007-07-21 drh: int newIdx; /* Index of vdbe cursor to "new" temp table */ dbda8d6ce9 2007-07-21 drh: int oldIdx; /* Index of vdbe cursor to "old" temp table */ dbda8d6ce9 2007-07-21 drh: int orconf; /* Current orconf policy */ dbda8d6ce9 2007-07-21 drh: int ignoreJump; /* where to jump to for a RAISE(IGNORE) */ dbda8d6ce9 2007-07-21 drh: Trigger *pTrigger; /* The trigger currently being coded */ dbda8d6ce9 2007-07-21 drh: TriggerStack *pNext; /* Next trigger down on the trigger stack */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following structure contains information used by the sqliteFix... dbda8d6ce9 2007-07-21 drh: ** routines as they walk the parse tree to make database references dbda8d6ce9 2007-07-21 drh: ** explicit. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct DbFixer DbFixer; dbda8d6ce9 2007-07-21 drh: struct DbFixer { dbda8d6ce9 2007-07-21 drh: Parse *pParse; /* The parsing context. Error messages written here */ dbda8d6ce9 2007-07-21 drh: const char *zDb; /* Make sure all objects are contained in this database */ dbda8d6ce9 2007-07-21 drh: const char *zType; /* Type of the container - used for error messages */ dbda8d6ce9 2007-07-21 drh: const Token *pName; /* Name of the container - used for error messages */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A pointer to this structure is used to communicate information dbda8d6ce9 2007-07-21 drh: ** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct { dbda8d6ce9 2007-07-21 drh: sqlite3 *db; /* The database being initialized */ dbda8d6ce9 2007-07-21 drh: int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ dbda8d6ce9 2007-07-21 drh: char **pzErrMsg; /* Error message stored here */ dbda8d6ce9 2007-07-21 drh: int rc; /* Result code stored here */ dbda8d6ce9 2007-07-21 drh: } InitData; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* d8590e093f 2007-07-24 drh: ** Assuming zIn points to the first byte of a UTF-8 character, d8590e093f 2007-07-24 drh: ** advance zIn to point to the first byte of the next UTF-8 character. d8590e093f 2007-07-24 drh: */ dbda8d6ce9 2007-07-21 drh: #define SQLITE_SKIP_UTF8(zIn) { \ dbda8d6ce9 2007-07-21 drh: if( (*(zIn++))>=0xc0 ){ \ dbda8d6ce9 2007-07-21 drh: while( (*zIn & 0xc0)==0x80 ){ zIn++; } \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The SQLITE_CORRUPT_BKPT macro can be either a constant (for production dbda8d6ce9 2007-07-21 drh: ** builds) or a function call (for debugging). If it is a function call, dbda8d6ce9 2007-07-21 drh: ** it allows the operator to set a breakpoint at the spot where database dbda8d6ce9 2007-07-21 drh: ** corruption is first detected. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Corrupt(void); dbda8d6ce9 2007-07-21 drh: # define SQLITE_CORRUPT_BKPT sqlite3Corrupt() dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Internal function prototypes dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3StrNICmp(const char *, const char *, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IsNumber(const char*, int*, u8); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3MallocZero(unsigned); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, unsigned); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, unsigned); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char *sqlite3StrDup(const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char *sqlite3StrNDup(const char*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, int); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list); dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DebugPrintf(const char*, ...); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3TextToPtr(const char*); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SetString(char **, ...); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ErrorClear(Parse*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Dequote(char*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3DequoteExpr(sqlite3*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3FinishCoding(Parse*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*, int, Expr*, Expr*, const Token*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Expr *sqlite3RegisterExpr(Parse*,Token*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprSpan(Expr*,Token*,Token*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprDelete(Expr*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*,Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprListDelete(ExprList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ResetInternalSchema(sqlite3*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, const char*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define sqlite3ViewGetColumnNames(A,B) 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeleteTable(Table*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int,int*,int*,int*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, dbda8d6ce9 2007-07-21 drh: Select*, Expr*, IdList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3IdListDelete(IdList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SrcListDelete(SrcList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, dbda8d6ce9 2007-07-21 drh: Token*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, c287665ba8 2007-09-14 drh: Expr*,ExprList*,int,Expr*,Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SelectDelete(Select*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,const char*, const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Vacuum(Parse*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprResolveNames(NameContext *, Expr *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3CreateIdExpr(Parse *, const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Randomness(int, void*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IsRowid(const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3GenerateIndexKey(Vdbe*, Index*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3OpenTableAndIndices(Parse*, Table*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3TokenCopy(sqlite3*,Token*, Token*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SafetyOn(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SafetyOff(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SafetyCheck(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ChangeCookie(sqlite3*, Vdbe*, int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*, dbda8d6ce9 2007-07-21 drh: Expr*,int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DropTrigger(Parse*, SrcList*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse*, Trigger*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3TriggersExist(Parse*, Table*, int, ExprList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int, dbda8d6ce9 2007-07-21 drh: int, int); dbda8d6ce9 2007-07-21 drh: void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeleteTriggerStep(TriggerStep*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*, c287665ba8 2007-09-14 drh: ExprList*,Select*,int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeleteTrigger(Trigger*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define sqlite3TriggersExist(A,B,C,D,E,F) 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3DeleteTrigger(A) dbda8d6ce9 2007-07-21 drh: # define sqlite3DropTriggerPtr(A,B) dbda8d6ce9 2007-07-21 drh: # define sqlite3UnlinkAndDeleteTrigger(A,B,C) dbda8d6ce9 2007-07-21 drh: # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse*, int); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AuthRead(Parse*,Expr*,SrcList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3AuthCheck(Parse*,int, const char*, const char*, const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AuthContextPush(Parse*, AuthContext*, const char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext*); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define sqlite3AuthRead(a,b,c) dbda8d6ce9 2007-07-21 drh: # define sqlite3AuthCheck(a,b,c,d,e) SQLITE_OK dbda8d6ce9 2007-07-21 drh: # define sqlite3AuthContextPush(a,b,c) dbda8d6ce9 2007-07-21 drh: # define sqlite3AuthContextPop(a) ((void)(a)) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeFactory(const sqlite3 *db, const char *zFilename, c287665ba8 2007-09-14 drh: int omitJournal, int nCache, int flags, Btree **ppBtree); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*); dbda8d6ce9 2007-07-21 drh: SQLITE_API char *sqlite3_snprintf(int,char*,const char*,...); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); d8590e093f 2007-07-24 drh: SQLITE_PRIVATE int sqlite3Utf8Read(const u8*, const u8*, const u8**); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *, u64); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3GetVarint(const unsigned char *, u64 *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3GetVarint32(const unsigned char *, u32 *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VarintLen(u64 v); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3IndexAffinityStr(Vdbe *, Index *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3ErrStr(int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char *,int,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Expr *sqlite3ExprSetColl(Parse *pParse, Expr *, Token *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, c287665ba8 2007-09-14 drh: void(*)(void*)); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); c287665ba8 2007-09-14 drh: #ifndef SQLITE_AMALGAMATION c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[]; c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RootPageMoved(Db*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AlterFunctions(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CodeSubselect(Parse *, Expr *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SelectResolve(Parse *, Select *, NameContext *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(sqlite3*, CollSeq *, const char *, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char sqlite3AffinityType(const Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AttachFunctions(sqlite3 *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse*, int, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SchemaFree(void *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, dbda8d6ce9 2007-07-21 drh: void (*)(sqlite3_context*,int,sqlite3_value **), dbda8d6ce9 2007-07-21 drh: void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*)); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); c287665ba8 2007-09-14 drh: d8590e093f 2007-07-24 drh: d8590e093f 2007-07-24 drh: /* d8590e093f 2007-07-24 drh: ** The interface to the LEMON-generated parser d8590e093f 2007-07-24 drh: */ d8590e093f 2007-07-24 drh: SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(size_t)); d8590e093f 2007-07-24 drh: SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*)); d8590e093f 2007-07-24 drh: SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_LOAD_EXTENSION dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3AutoLoadExtensions(sqlite3*); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define sqlite3CloseExtensions(X) dbda8d6ce9 2007-07-21 drh: # define sqlite3AutoLoadExtensions(X) SQLITE_OK dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, int, u8, const char *); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define sqlite3TableLock(v,w,x,y,z) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The MallocDisallow() and MallocAllow() routines are like asserts. c287665ba8 2007-09-14 drh: ** Call them around a section of code that you do not expect to do c287665ba8 2007-09-14 drh: ** any memory allocation. c287665ba8 2007-09-14 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_MEMDEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3MallocDisallow(void); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3MallocAllow(void); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3MallocBenignFailure(int); c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: # define sqlite3MallocDisallow() c287665ba8 2007-09-14 drh: # define sqlite3MallocAllow() c287665ba8 2007-09-14 drh: # define sqlite3MallocBenignFailure(x) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: # define sqlite3VtabClear(X) dbda8d6ce9 2007-07-21 drh: # define sqlite3VtabSync(X,Y) (Y) dbda8d6ce9 2007-07-21 drh: # define sqlite3VtabRollback(X) dbda8d6ce9 2007-07-21 drh: # define sqlite3VtabCommit(X) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabClear(Table*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, int rc); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabLock(sqlite3_vtab*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabUnlock(sqlite3*, sqlite3_vtab*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabArgInit(Parse*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse*, Token*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, int, const char*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_ATOMIC_WRITE c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *); c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprSetHeight(Expr *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define sqlite3ExprSetHeight(x) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Put4byte(u8*, u32); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SSE dbda8d6ce9 2007-07-21 drh: #include "sseInt.h" dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the SQLITE_ENABLE IOTRACE exists then the global variable dbda8d6ce9 2007-07-21 drh: ** sqlite3_io_trace is a pointer to a printf-like routine used to dbda8d6ce9 2007-07-21 drh: ** print I/O tracing messages. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_IOTRACE dbda8d6ce9 2007-07-21 drh: # define IOTRACE(A) if( sqlite3_io_trace ){ sqlite3_io_trace A; } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe*); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define IOTRACE(A) dbda8d6ce9 2007-07-21 drh: # define sqlite3VdbeIOTraceSql(X) dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: SQLITE_EXTERN void (*sqlite3_io_trace)(const char*,...); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of sqliteInt.h *******************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in date.c ***********************/ dbda8d6ce9 2007-07-21 drh: #include <ctype.h> dbda8d6ce9 2007-07-21 drh: #include <time.h> dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_DATETIME_FUNCS dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A structure for holding a single date and time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct DateTime DateTime; dbda8d6ce9 2007-07-21 drh: struct DateTime { dbda8d6ce9 2007-07-21 drh: double rJD; /* The julian day number */ dbda8d6ce9 2007-07-21 drh: int Y, M, D; /* Year, month, and day */ dbda8d6ce9 2007-07-21 drh: int h, m; /* Hour and minutes */ dbda8d6ce9 2007-07-21 drh: int tz; /* Timezone offset in minutes */ dbda8d6ce9 2007-07-21 drh: double s; /* Seconds */ dbda8d6ce9 2007-07-21 drh: char validYMD; /* True if Y,M,D are valid */ dbda8d6ce9 2007-07-21 drh: char validHMS; /* True if h,m,s are valid */ dbda8d6ce9 2007-07-21 drh: char validJD; /* True if rJD is valid */ dbda8d6ce9 2007-07-21 drh: char validTZ; /* True if tz is valid */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert zDate into one or more integers. Additional arguments dbda8d6ce9 2007-07-21 drh: ** come in groups of 5 as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** N number of digits in the integer dbda8d6ce9 2007-07-21 drh: ** min minimum allowed value of the integer dbda8d6ce9 2007-07-21 drh: ** max maximum allowed value of the integer dbda8d6ce9 2007-07-21 drh: ** nextC first character after the integer dbda8d6ce9 2007-07-21 drh: ** pVal where to write the integers value. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Conversions continue until one with nextC==0 is encountered. dbda8d6ce9 2007-07-21 drh: ** The function returns the number of successful conversions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getDigits(const char *zDate, ...){ dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: int val; dbda8d6ce9 2007-07-21 drh: int N; dbda8d6ce9 2007-07-21 drh: int min; dbda8d6ce9 2007-07-21 drh: int max; dbda8d6ce9 2007-07-21 drh: int nextC; dbda8d6ce9 2007-07-21 drh: int *pVal; dbda8d6ce9 2007-07-21 drh: int cnt = 0; dbda8d6ce9 2007-07-21 drh: va_start(ap, zDate); dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: N = va_arg(ap, int); dbda8d6ce9 2007-07-21 drh: min = va_arg(ap, int); dbda8d6ce9 2007-07-21 drh: max = va_arg(ap, int); dbda8d6ce9 2007-07-21 drh: nextC = va_arg(ap, int); dbda8d6ce9 2007-07-21 drh: pVal = va_arg(ap, int*); dbda8d6ce9 2007-07-21 drh: val = 0; dbda8d6ce9 2007-07-21 drh: while( N-- ){ dbda8d6ce9 2007-07-21 drh: if( !isdigit(*(u8*)zDate) ){ dbda8d6ce9 2007-07-21 drh: goto end_getDigits; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: val = val*10 + *zDate - '0'; dbda8d6ce9 2007-07-21 drh: zDate++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){ dbda8d6ce9 2007-07-21 drh: goto end_getDigits; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pVal = val; dbda8d6ce9 2007-07-21 drh: zDate++; dbda8d6ce9 2007-07-21 drh: cnt++; dbda8d6ce9 2007-07-21 drh: }while( nextC ); dbda8d6ce9 2007-07-21 drh: end_getDigits: dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: return cnt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read text from z[] and convert into a floating point number. Return dbda8d6ce9 2007-07-21 drh: ** the number of digits converted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define getValue sqlite3AtoF dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Parse a timezone extension on the end of a date-time. dbda8d6ce9 2007-07-21 drh: ** The extension is of the form: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (+/-)HH:MM dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the parse is successful, write the number of minutes dbda8d6ce9 2007-07-21 drh: ** of change in *pnMin and return 0. If a parser error occurs, dbda8d6ce9 2007-07-21 drh: ** return 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A missing specifier is not considered an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int parseTimezone(const char *zDate, DateTime *p){ dbda8d6ce9 2007-07-21 drh: int sgn = 0; dbda8d6ce9 2007-07-21 drh: int nHr, nMn; dbda8d6ce9 2007-07-21 drh: while( isspace(*(u8*)zDate) ){ zDate++; } dbda8d6ce9 2007-07-21 drh: p->tz = 0; dbda8d6ce9 2007-07-21 drh: if( *zDate=='-' ){ dbda8d6ce9 2007-07-21 drh: sgn = -1; dbda8d6ce9 2007-07-21 drh: }else if( *zDate=='+' ){ dbda8d6ce9 2007-07-21 drh: sgn = +1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return *zDate!=0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zDate++; dbda8d6ce9 2007-07-21 drh: if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zDate += 5; dbda8d6ce9 2007-07-21 drh: p->tz = sgn*(nMn + nHr*60); dbda8d6ce9 2007-07-21 drh: while( isspace(*(u8*)zDate) ){ zDate++; } dbda8d6ce9 2007-07-21 drh: return *zDate!=0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF. dbda8d6ce9 2007-07-21 drh: ** The HH, MM, and SS must each be exactly 2 digits. The dbda8d6ce9 2007-07-21 drh: ** fractional seconds FFFF can be one or more digits. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return 1 if there is a parsing error and 0 on success. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int parseHhMmSs(const char *zDate, DateTime *p){ dbda8d6ce9 2007-07-21 drh: int h, m, s; dbda8d6ce9 2007-07-21 drh: double ms = 0.0; dbda8d6ce9 2007-07-21 drh: if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zDate += 5; dbda8d6ce9 2007-07-21 drh: if( *zDate==':' ){ dbda8d6ce9 2007-07-21 drh: zDate++; dbda8d6ce9 2007-07-21 drh: if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zDate += 2; dbda8d6ce9 2007-07-21 drh: if( *zDate=='.' && isdigit((u8)zDate[1]) ){ dbda8d6ce9 2007-07-21 drh: double rScale = 1.0; dbda8d6ce9 2007-07-21 drh: zDate++; dbda8d6ce9 2007-07-21 drh: while( isdigit(*(u8*)zDate) ){ dbda8d6ce9 2007-07-21 drh: ms = ms*10.0 + *zDate - '0'; dbda8d6ce9 2007-07-21 drh: rScale *= 10.0; dbda8d6ce9 2007-07-21 drh: zDate++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: ms /= rScale; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: s = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->validJD = 0; dbda8d6ce9 2007-07-21 drh: p->validHMS = 1; dbda8d6ce9 2007-07-21 drh: p->h = h; dbda8d6ce9 2007-07-21 drh: p->m = m; dbda8d6ce9 2007-07-21 drh: p->s = s + ms; dbda8d6ce9 2007-07-21 drh: if( parseTimezone(zDate, p) ) return 1; dbda8d6ce9 2007-07-21 drh: p->validTZ = p->tz!=0; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume dbda8d6ce9 2007-07-21 drh: ** that the YYYY-MM-DD is according to the Gregorian calendar. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Reference: Meeus page 61 dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void computeJD(DateTime *p){ dbda8d6ce9 2007-07-21 drh: int Y, M, D, A, B, X1, X2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( p->validJD ) return; dbda8d6ce9 2007-07-21 drh: if( p->validYMD ){ dbda8d6ce9 2007-07-21 drh: Y = p->Y; dbda8d6ce9 2007-07-21 drh: M = p->M; dbda8d6ce9 2007-07-21 drh: D = p->D; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */ dbda8d6ce9 2007-07-21 drh: M = 1; dbda8d6ce9 2007-07-21 drh: D = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( M<=2 ){ dbda8d6ce9 2007-07-21 drh: Y--; dbda8d6ce9 2007-07-21 drh: M += 12; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: A = Y/100; dbda8d6ce9 2007-07-21 drh: B = 2 - A + (A/4); dbda8d6ce9 2007-07-21 drh: X1 = 365.25*(Y+4716); dbda8d6ce9 2007-07-21 drh: X2 = 30.6001*(M+1); dbda8d6ce9 2007-07-21 drh: p->rJD = X1 + X2 + D + B - 1524.5; dbda8d6ce9 2007-07-21 drh: p->validJD = 1; dbda8d6ce9 2007-07-21 drh: if( p->validHMS ){ dbda8d6ce9 2007-07-21 drh: p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0; dbda8d6ce9 2007-07-21 drh: if( p->validTZ ){ dbda8d6ce9 2007-07-21 drh: p->rJD -= p->tz*60/86400.0; dbda8d6ce9 2007-07-21 drh: p->validYMD = 0; dbda8d6ce9 2007-07-21 drh: p->validHMS = 0; dbda8d6ce9 2007-07-21 drh: p->validTZ = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Parse dates of the form dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** YYYY-MM-DD HH:MM:SS.FFF dbda8d6ce9 2007-07-21 drh: ** YYYY-MM-DD HH:MM:SS dbda8d6ce9 2007-07-21 drh: ** YYYY-MM-DD HH:MM dbda8d6ce9 2007-07-21 drh: ** YYYY-MM-DD dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Write the result into the DateTime structure and return 0 dbda8d6ce9 2007-07-21 drh: ** on success and 1 if the input string is not a well-formed dbda8d6ce9 2007-07-21 drh: ** date. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int parseYyyyMmDd(const char *zDate, DateTime *p){ dbda8d6ce9 2007-07-21 drh: int Y, M, D, neg; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( zDate[0]=='-' ){ dbda8d6ce9 2007-07-21 drh: zDate++; dbda8d6ce9 2007-07-21 drh: neg = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: neg = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zDate += 10; dbda8d6ce9 2007-07-21 drh: while( isspace(*(u8*)zDate) || 'T'==*(u8*)zDate ){ zDate++; } dbda8d6ce9 2007-07-21 drh: if( parseHhMmSs(zDate, p)==0 ){ dbda8d6ce9 2007-07-21 drh: /* We got the time */ dbda8d6ce9 2007-07-21 drh: }else if( *zDate==0 ){ dbda8d6ce9 2007-07-21 drh: p->validHMS = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->validJD = 0; dbda8d6ce9 2007-07-21 drh: p->validYMD = 1; dbda8d6ce9 2007-07-21 drh: p->Y = neg ? -Y : Y; dbda8d6ce9 2007-07-21 drh: p->M = M; dbda8d6ce9 2007-07-21 drh: p->D = D; dbda8d6ce9 2007-07-21 drh: if( p->validTZ ){ dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to parse the given string into a Julian Day Number. Return dbda8d6ce9 2007-07-21 drh: ** the number of errors. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following are acceptable forms for the input string: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM dbda8d6ce9 2007-07-21 drh: ** DDDD.DD dbda8d6ce9 2007-07-21 drh: ** now dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the first form, the +/-HH:MM is always optional. The fractional dbda8d6ce9 2007-07-21 drh: ** seconds extension (the ".FFF") is optional. The seconds portion dbda8d6ce9 2007-07-21 drh: ** (":SS.FFF") is option. The year and date can be omitted as long dbda8d6ce9 2007-07-21 drh: ** as there is a time string. The time string can be omitted as long dbda8d6ce9 2007-07-21 drh: ** as there is a year and date. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int parseDateOrTime( c287665ba8 2007-09-14 drh: sqlite3_context *context, c287665ba8 2007-09-14 drh: const char *zDate, c287665ba8 2007-09-14 drh: DateTime *p c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: memset(p, 0, sizeof(*p)); dbda8d6ce9 2007-07-21 drh: if( parseYyyyMmDd(zDate,p)==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else if( parseHhMmSs(zDate, p)==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else if( sqlite3StrICmp(zDate,"now")==0){ dbda8d6ce9 2007-07-21 drh: double r; c287665ba8 2007-09-14 drh: sqlite3OsCurrentTime((sqlite3_vfs *)sqlite3_user_data(context), &r); dbda8d6ce9 2007-07-21 drh: p->rJD = r; dbda8d6ce9 2007-07-21 drh: p->validJD = 1; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){ dbda8d6ce9 2007-07-21 drh: getValue(zDate, &p->rJD); dbda8d6ce9 2007-07-21 drh: p->validJD = 1; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the Year, Month, and Day from the julian day number. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void computeYMD(DateTime *p){ dbda8d6ce9 2007-07-21 drh: int Z, A, B, C, D, E, X1; dbda8d6ce9 2007-07-21 drh: if( p->validYMD ) return; dbda8d6ce9 2007-07-21 drh: if( !p->validJD ){ dbda8d6ce9 2007-07-21 drh: p->Y = 2000; dbda8d6ce9 2007-07-21 drh: p->M = 1; dbda8d6ce9 2007-07-21 drh: p->D = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Z = p->rJD + 0.5; dbda8d6ce9 2007-07-21 drh: A = (Z - 1867216.25)/36524.25; dbda8d6ce9 2007-07-21 drh: A = Z + 1 + A - (A/4); dbda8d6ce9 2007-07-21 drh: B = A + 1524; dbda8d6ce9 2007-07-21 drh: C = (B - 122.1)/365.25; dbda8d6ce9 2007-07-21 drh: D = 365.25*C; dbda8d6ce9 2007-07-21 drh: E = (B-D)/30.6001; dbda8d6ce9 2007-07-21 drh: X1 = 30.6001*E; dbda8d6ce9 2007-07-21 drh: p->D = B - D - X1; dbda8d6ce9 2007-07-21 drh: p->M = E<14 ? E-1 : E-13; dbda8d6ce9 2007-07-21 drh: p->Y = p->M>2 ? C - 4716 : C - 4715; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->validYMD = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the Hour, Minute, and Seconds from the julian day number. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void computeHMS(DateTime *p){ dbda8d6ce9 2007-07-21 drh: int Z, s; dbda8d6ce9 2007-07-21 drh: if( p->validHMS ) return; dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: Z = p->rJD + 0.5; dbda8d6ce9 2007-07-21 drh: s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5; dbda8d6ce9 2007-07-21 drh: p->s = 0.001*s; dbda8d6ce9 2007-07-21 drh: s = p->s; dbda8d6ce9 2007-07-21 drh: p->s -= s; dbda8d6ce9 2007-07-21 drh: p->h = s/3600; dbda8d6ce9 2007-07-21 drh: s -= p->h*3600; dbda8d6ce9 2007-07-21 drh: p->m = s/60; dbda8d6ce9 2007-07-21 drh: p->s += s - p->m*60; dbda8d6ce9 2007-07-21 drh: p->validHMS = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute both YMD and HMS dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void computeYMD_HMS(DateTime *p){ dbda8d6ce9 2007-07-21 drh: computeYMD(p); dbda8d6ce9 2007-07-21 drh: computeHMS(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear the YMD and HMS and the TZ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void clearYMD_HMS_TZ(DateTime *p){ dbda8d6ce9 2007-07-21 drh: p->validYMD = 0; dbda8d6ce9 2007-07-21 drh: p->validHMS = 0; dbda8d6ce9 2007-07-21 drh: p->validTZ = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the difference (in days) between localtime and UTC (a.k.a. GMT) dbda8d6ce9 2007-07-21 drh: ** for the time value p where p is in UTC. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static double localtimeOffset(DateTime *p){ dbda8d6ce9 2007-07-21 drh: DateTime x, y; dbda8d6ce9 2007-07-21 drh: time_t t; dbda8d6ce9 2007-07-21 drh: x = *p; dbda8d6ce9 2007-07-21 drh: computeYMD_HMS(&x); dbda8d6ce9 2007-07-21 drh: if( x.Y<1971 || x.Y>=2038 ){ dbda8d6ce9 2007-07-21 drh: x.Y = 2000; dbda8d6ce9 2007-07-21 drh: x.M = 1; dbda8d6ce9 2007-07-21 drh: x.D = 1; dbda8d6ce9 2007-07-21 drh: x.h = 0; dbda8d6ce9 2007-07-21 drh: x.m = 0; dbda8d6ce9 2007-07-21 drh: x.s = 0.0; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: int s = x.s + 0.5; dbda8d6ce9 2007-07-21 drh: x.s = s; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: x.tz = 0; dbda8d6ce9 2007-07-21 drh: x.validJD = 0; dbda8d6ce9 2007-07-21 drh: computeJD(&x); dbda8d6ce9 2007-07-21 drh: t = (x.rJD-2440587.5)*86400.0 + 0.5; dbda8d6ce9 2007-07-21 drh: #ifdef HAVE_LOCALTIME_R dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: struct tm sLocal; dbda8d6ce9 2007-07-21 drh: localtime_r(&t, &sLocal); dbda8d6ce9 2007-07-21 drh: y.Y = sLocal.tm_year + 1900; dbda8d6ce9 2007-07-21 drh: y.M = sLocal.tm_mon + 1; dbda8d6ce9 2007-07-21 drh: y.D = sLocal.tm_mday; dbda8d6ce9 2007-07-21 drh: y.h = sLocal.tm_hour; dbda8d6ce9 2007-07-21 drh: y.m = sLocal.tm_min; dbda8d6ce9 2007-07-21 drh: y.s = sLocal.tm_sec; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: struct tm *pTm; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); dbda8d6ce9 2007-07-21 drh: pTm = localtime(&t); dbda8d6ce9 2007-07-21 drh: y.Y = pTm->tm_year + 1900; dbda8d6ce9 2007-07-21 drh: y.M = pTm->tm_mon + 1; dbda8d6ce9 2007-07-21 drh: y.D = pTm->tm_mday; dbda8d6ce9 2007-07-21 drh: y.h = pTm->tm_hour; dbda8d6ce9 2007-07-21 drh: y.m = pTm->tm_min; dbda8d6ce9 2007-07-21 drh: y.s = pTm->tm_sec; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: y.validYMD = 1; dbda8d6ce9 2007-07-21 drh: y.validHMS = 1; dbda8d6ce9 2007-07-21 drh: y.validJD = 0; dbda8d6ce9 2007-07-21 drh: y.validTZ = 0; dbda8d6ce9 2007-07-21 drh: computeJD(&y); dbda8d6ce9 2007-07-21 drh: return y.rJD - x.rJD; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Process a modifier to a date-time stamp. The modifiers are dbda8d6ce9 2007-07-21 drh: ** as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** NNN days dbda8d6ce9 2007-07-21 drh: ** NNN hours dbda8d6ce9 2007-07-21 drh: ** NNN minutes dbda8d6ce9 2007-07-21 drh: ** NNN.NNNN seconds dbda8d6ce9 2007-07-21 drh: ** NNN months dbda8d6ce9 2007-07-21 drh: ** NNN years dbda8d6ce9 2007-07-21 drh: ** start of month dbda8d6ce9 2007-07-21 drh: ** start of year dbda8d6ce9 2007-07-21 drh: ** start of week dbda8d6ce9 2007-07-21 drh: ** start of day dbda8d6ce9 2007-07-21 drh: ** weekday N dbda8d6ce9 2007-07-21 drh: ** unixepoch dbda8d6ce9 2007-07-21 drh: ** localtime dbda8d6ce9 2007-07-21 drh: ** utc dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return 0 on success and 1 if there is any kind of error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int parseModifier(const char *zMod, DateTime *p){ dbda8d6ce9 2007-07-21 drh: int rc = 1; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: double r; dbda8d6ce9 2007-07-21 drh: char *z, zBuf[30]; dbda8d6ce9 2007-07-21 drh: z = zBuf; dbda8d6ce9 2007-07-21 drh: for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){ dbda8d6ce9 2007-07-21 drh: z[n] = tolower(zMod[n]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: z[n] = 0; dbda8d6ce9 2007-07-21 drh: switch( z[0] ){ dbda8d6ce9 2007-07-21 drh: case 'l': { dbda8d6ce9 2007-07-21 drh: /* localtime dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Assuming the current time value is UTC (a.k.a. GMT), shift it to dbda8d6ce9 2007-07-21 drh: ** show local time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( strcmp(z, "localtime")==0 ){ dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: p->rJD += localtimeOffset(p); dbda8d6ce9 2007-07-21 drh: clearYMD_HMS_TZ(p); dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 'u': { dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** unixepoch dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Treat the current value of p->rJD as the number of dbda8d6ce9 2007-07-21 drh: ** seconds since 1970. Convert to a real julian day number. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( strcmp(z, "unixepoch")==0 && p->validJD ){ dbda8d6ce9 2007-07-21 drh: p->rJD = p->rJD/86400.0 + 2440587.5; dbda8d6ce9 2007-07-21 drh: clearYMD_HMS_TZ(p); dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: }else if( strcmp(z, "utc")==0 ){ dbda8d6ce9 2007-07-21 drh: double c1; dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: c1 = localtimeOffset(p); dbda8d6ce9 2007-07-21 drh: p->rJD -= c1; dbda8d6ce9 2007-07-21 drh: clearYMD_HMS_TZ(p); dbda8d6ce9 2007-07-21 drh: p->rJD += c1 - localtimeOffset(p); dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 'w': { dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** weekday N dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Move the date to the same time on the next occurrence of dbda8d6ce9 2007-07-21 drh: ** weekday N where 0==Sunday, 1==Monday, and so forth. If the dbda8d6ce9 2007-07-21 drh: ** date is already on the appropriate weekday, this is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0 dbda8d6ce9 2007-07-21 drh: && (n=r)==r && n>=0 && r<7 ){ dbda8d6ce9 2007-07-21 drh: int Z; dbda8d6ce9 2007-07-21 drh: computeYMD_HMS(p); dbda8d6ce9 2007-07-21 drh: p->validTZ = 0; dbda8d6ce9 2007-07-21 drh: p->validJD = 0; dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: Z = p->rJD + 1.5; dbda8d6ce9 2007-07-21 drh: Z %= 7; dbda8d6ce9 2007-07-21 drh: if( Z>n ) Z -= 7; dbda8d6ce9 2007-07-21 drh: p->rJD += n - Z; dbda8d6ce9 2007-07-21 drh: clearYMD_HMS_TZ(p); dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 's': { dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** start of TTTTT dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Move the date backwards to the beginning of the current day, dbda8d6ce9 2007-07-21 drh: ** or month or year. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( strncmp(z, "start of ", 9)!=0 ) break; dbda8d6ce9 2007-07-21 drh: z += 9; dbda8d6ce9 2007-07-21 drh: computeYMD(p); dbda8d6ce9 2007-07-21 drh: p->validHMS = 1; dbda8d6ce9 2007-07-21 drh: p->h = p->m = 0; dbda8d6ce9 2007-07-21 drh: p->s = 0.0; dbda8d6ce9 2007-07-21 drh: p->validTZ = 0; dbda8d6ce9 2007-07-21 drh: p->validJD = 0; dbda8d6ce9 2007-07-21 drh: if( strcmp(z,"month")==0 ){ dbda8d6ce9 2007-07-21 drh: p->D = 1; dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: }else if( strcmp(z,"year")==0 ){ dbda8d6ce9 2007-07-21 drh: computeYMD(p); dbda8d6ce9 2007-07-21 drh: p->M = 1; dbda8d6ce9 2007-07-21 drh: p->D = 1; dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: }else if( strcmp(z,"day")==0 ){ dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '+': dbda8d6ce9 2007-07-21 drh: case '-': dbda8d6ce9 2007-07-21 drh: case '0': dbda8d6ce9 2007-07-21 drh: case '1': dbda8d6ce9 2007-07-21 drh: case '2': dbda8d6ce9 2007-07-21 drh: case '3': dbda8d6ce9 2007-07-21 drh: case '4': dbda8d6ce9 2007-07-21 drh: case '5': dbda8d6ce9 2007-07-21 drh: case '6': dbda8d6ce9 2007-07-21 drh: case '7': dbda8d6ce9 2007-07-21 drh: case '8': dbda8d6ce9 2007-07-21 drh: case '9': { dbda8d6ce9 2007-07-21 drh: n = getValue(z, &r); dbda8d6ce9 2007-07-21 drh: assert( n>=1 ); dbda8d6ce9 2007-07-21 drh: if( z[n]==':' ){ dbda8d6ce9 2007-07-21 drh: /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the dbda8d6ce9 2007-07-21 drh: ** specified number of hours, minutes, seconds, and fractional seconds dbda8d6ce9 2007-07-21 drh: ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be dbda8d6ce9 2007-07-21 drh: ** omitted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: const char *z2 = z; dbda8d6ce9 2007-07-21 drh: DateTime tx; dbda8d6ce9 2007-07-21 drh: int day; dbda8d6ce9 2007-07-21 drh: if( !isdigit(*(u8*)z2) ) z2++; dbda8d6ce9 2007-07-21 drh: memset(&tx, 0, sizeof(tx)); dbda8d6ce9 2007-07-21 drh: if( parseHhMmSs(z2, &tx) ) break; dbda8d6ce9 2007-07-21 drh: computeJD(&tx); dbda8d6ce9 2007-07-21 drh: tx.rJD -= 0.5; dbda8d6ce9 2007-07-21 drh: day = (int)tx.rJD; dbda8d6ce9 2007-07-21 drh: tx.rJD -= day; dbda8d6ce9 2007-07-21 drh: if( z[0]=='-' ) tx.rJD = -tx.rJD; dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: clearYMD_HMS_TZ(p); dbda8d6ce9 2007-07-21 drh: p->rJD += tx.rJD; dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: z += n; dbda8d6ce9 2007-07-21 drh: while( isspace(*(u8*)z) ) z++; dbda8d6ce9 2007-07-21 drh: n = strlen(z); dbda8d6ce9 2007-07-21 drh: if( n>10 || n<3 ) break; dbda8d6ce9 2007-07-21 drh: if( z[n-1]=='s' ){ z[n-1] = 0; n--; } dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: if( n==3 && strcmp(z,"day")==0 ){ dbda8d6ce9 2007-07-21 drh: p->rJD += r; dbda8d6ce9 2007-07-21 drh: }else if( n==4 && strcmp(z,"hour")==0 ){ dbda8d6ce9 2007-07-21 drh: p->rJD += r/24.0; dbda8d6ce9 2007-07-21 drh: }else if( n==6 && strcmp(z,"minute")==0 ){ dbda8d6ce9 2007-07-21 drh: p->rJD += r/(24.0*60.0); dbda8d6ce9 2007-07-21 drh: }else if( n==6 && strcmp(z,"second")==0 ){ dbda8d6ce9 2007-07-21 drh: p->rJD += r/(24.0*60.0*60.0); dbda8d6ce9 2007-07-21 drh: }else if( n==5 && strcmp(z,"month")==0 ){ dbda8d6ce9 2007-07-21 drh: int x, y; dbda8d6ce9 2007-07-21 drh: computeYMD_HMS(p); dbda8d6ce9 2007-07-21 drh: p->M += r; dbda8d6ce9 2007-07-21 drh: x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; dbda8d6ce9 2007-07-21 drh: p->Y += x; dbda8d6ce9 2007-07-21 drh: p->M -= x*12; dbda8d6ce9 2007-07-21 drh: p->validJD = 0; dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: y = r; dbda8d6ce9 2007-07-21 drh: if( y!=r ){ dbda8d6ce9 2007-07-21 drh: p->rJD += (r - y)*30.0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( n==4 && strcmp(z,"year")==0 ){ dbda8d6ce9 2007-07-21 drh: computeYMD_HMS(p); dbda8d6ce9 2007-07-21 drh: p->Y += r; dbda8d6ce9 2007-07-21 drh: p->validJD = 0; dbda8d6ce9 2007-07-21 drh: computeJD(p); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: clearYMD_HMS_TZ(p); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Process time function arguments. argv[0] is a date-time stamp. dbda8d6ce9 2007-07-21 drh: ** argv[1] and following are modifiers. Parse them all and write dbda8d6ce9 2007-07-21 drh: ** the resulting time into the DateTime structure p. Return 0 dbda8d6ce9 2007-07-21 drh: ** on success and 1 if there are any errors. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int isDate( c287665ba8 2007-09-14 drh: sqlite3_context *context, c287665ba8 2007-09-14 drh: int argc, c287665ba8 2007-09-14 drh: sqlite3_value **argv, c287665ba8 2007-09-14 drh: DateTime *p c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: const unsigned char *z; dbda8d6ce9 2007-07-21 drh: if( argc==0 ) return 1; c287665ba8 2007-09-14 drh: z = sqlite3_value_text(argv[0]); c287665ba8 2007-09-14 drh: if( !z || parseDateOrTime(context, (char*)z, p) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=1; i<argc; i++){ dbda8d6ce9 2007-07-21 drh: if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following routines implement the various date and time functions dbda8d6ce9 2007-07-21 drh: ** of SQLite. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** julianday( TIMESTRING, MOD, MOD, ...) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the julian day number of the date specified in the arguments dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void juliandayFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: DateTime x; c287665ba8 2007-09-14 drh: if( isDate(context, argc, argv, &x)==0 ){ dbda8d6ce9 2007-07-21 drh: computeJD(&x); dbda8d6ce9 2007-07-21 drh: sqlite3_result_double(context, x.rJD); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** datetime( TIMESTRING, MOD, MOD, ...) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return YYYY-MM-DD HH:MM:SS dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void datetimeFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: DateTime x; c287665ba8 2007-09-14 drh: if( isDate(context, argc, argv, &x)==0 ){ dbda8d6ce9 2007-07-21 drh: char zBuf[100]; dbda8d6ce9 2007-07-21 drh: computeYMD_HMS(&x); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", dbda8d6ce9 2007-07-21 drh: x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** time( TIMESTRING, MOD, MOD, ...) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return HH:MM:SS dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void timeFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: DateTime x; c287665ba8 2007-09-14 drh: if( isDate(context, argc, argv, &x)==0 ){ dbda8d6ce9 2007-07-21 drh: char zBuf[100]; dbda8d6ce9 2007-07-21 drh: computeHMS(&x); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** date( TIMESTRING, MOD, MOD, ...) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return YYYY-MM-DD dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void dateFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: DateTime x; c287665ba8 2007-09-14 drh: if( isDate(context, argc, argv, &x)==0 ){ dbda8d6ce9 2007-07-21 drh: char zBuf[100]; dbda8d6ce9 2007-07-21 drh: computeYMD(&x); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return a string described by FORMAT. Conversions as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** %d day of month dbda8d6ce9 2007-07-21 drh: ** %f ** fractional seconds SS.SSS dbda8d6ce9 2007-07-21 drh: ** %H hour 00-24 dbda8d6ce9 2007-07-21 drh: ** %j day of year 000-366 dbda8d6ce9 2007-07-21 drh: ** %J ** Julian day number dbda8d6ce9 2007-07-21 drh: ** %m month 01-12 dbda8d6ce9 2007-07-21 drh: ** %M minute 00-59 dbda8d6ce9 2007-07-21 drh: ** %s seconds since 1970-01-01 dbda8d6ce9 2007-07-21 drh: ** %S seconds 00-59 dbda8d6ce9 2007-07-21 drh: ** %w day of week 0-6 sunday==0 dbda8d6ce9 2007-07-21 drh: ** %W week of year 00-53 dbda8d6ce9 2007-07-21 drh: ** %Y year 0000-9999 dbda8d6ce9 2007-07-21 drh: ** %% % dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void strftimeFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: DateTime x; dbda8d6ce9 2007-07-21 drh: u64 n; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: const char *zFmt = (const char*)sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: char zBuf[100]; c287665ba8 2007-09-14 drh: if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; dbda8d6ce9 2007-07-21 drh: for(i=0, n=1; zFmt[i]; i++, n++){ dbda8d6ce9 2007-07-21 drh: if( zFmt[i]=='%' ){ dbda8d6ce9 2007-07-21 drh: switch( zFmt[i+1] ){ dbda8d6ce9 2007-07-21 drh: case 'd': dbda8d6ce9 2007-07-21 drh: case 'H': dbda8d6ce9 2007-07-21 drh: case 'm': dbda8d6ce9 2007-07-21 drh: case 'M': dbda8d6ce9 2007-07-21 drh: case 'S': dbda8d6ce9 2007-07-21 drh: case 'W': dbda8d6ce9 2007-07-21 drh: n++; dbda8d6ce9 2007-07-21 drh: /* fall thru */ dbda8d6ce9 2007-07-21 drh: case 'w': dbda8d6ce9 2007-07-21 drh: case '%': dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 'f': dbda8d6ce9 2007-07-21 drh: n += 8; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 'j': dbda8d6ce9 2007-07-21 drh: n += 3; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 'Y': dbda8d6ce9 2007-07-21 drh: n += 8; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 's': dbda8d6ce9 2007-07-21 drh: case 'J': dbda8d6ce9 2007-07-21 drh: n += 50; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: default: dbda8d6ce9 2007-07-21 drh: return; /* ERROR. return a NULL */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( n<sizeof(zBuf) ){ dbda8d6ce9 2007-07-21 drh: z = zBuf; dbda8d6ce9 2007-07-21 drh: }else if( n>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error_toobig(context); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: z = sqlite3_malloc( n ); dbda8d6ce9 2007-07-21 drh: if( z==0 ) return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: computeJD(&x); dbda8d6ce9 2007-07-21 drh: computeYMD_HMS(&x); dbda8d6ce9 2007-07-21 drh: for(i=j=0; zFmt[i]; i++){ dbda8d6ce9 2007-07-21 drh: if( zFmt[i]!='%' ){ dbda8d6ce9 2007-07-21 drh: z[j++] = zFmt[i]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: switch( zFmt[i] ){ dbda8d6ce9 2007-07-21 drh: case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; dbda8d6ce9 2007-07-21 drh: case 'f': { dbda8d6ce9 2007-07-21 drh: double s = x.s; dbda8d6ce9 2007-07-21 drh: if( s>59.999 ) s = 59.999; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(7, &z[j],"%06.3f", s); dbda8d6ce9 2007-07-21 drh: j += strlen(&z[j]); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; dbda8d6ce9 2007-07-21 drh: case 'W': /* Fall thru */ dbda8d6ce9 2007-07-21 drh: case 'j': { dbda8d6ce9 2007-07-21 drh: int nDay; /* Number of days since 1st day of year */ dbda8d6ce9 2007-07-21 drh: DateTime y = x; dbda8d6ce9 2007-07-21 drh: y.validJD = 0; dbda8d6ce9 2007-07-21 drh: y.M = 1; dbda8d6ce9 2007-07-21 drh: y.D = 1; dbda8d6ce9 2007-07-21 drh: computeJD(&y); dbda8d6ce9 2007-07-21 drh: nDay = x.rJD - y.rJD + 0.5; dbda8d6ce9 2007-07-21 drh: if( zFmt[i]=='W' ){ dbda8d6ce9 2007-07-21 drh: int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ dbda8d6ce9 2007-07-21 drh: wd = ((int)(x.rJD+0.5)) % 7; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); dbda8d6ce9 2007-07-21 drh: j += 2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(4, &z[j],"%03d",nDay+1); dbda8d6ce9 2007-07-21 drh: j += 3; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 'J': { dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(20, &z[j],"%.16g",x.rJD); dbda8d6ce9 2007-07-21 drh: j+=strlen(&z[j]); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; dbda8d6ce9 2007-07-21 drh: case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; dbda8d6ce9 2007-07-21 drh: case 's': { dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(30,&z[j],"%d", dbda8d6ce9 2007-07-21 drh: (int)((x.rJD-2440587.5)*86400.0 + 0.5)); dbda8d6ce9 2007-07-21 drh: j += strlen(&z[j]); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; dbda8d6ce9 2007-07-21 drh: case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break; dbda8d6ce9 2007-07-21 drh: case 'Y': sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=strlen(&z[j]);break; dbda8d6ce9 2007-07-21 drh: case '%': z[j++] = '%'; break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: z[j] = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: if( z!=zBuf ){ c287665ba8 2007-09-14 drh: sqlite3_free(z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** current_time() dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function returns the same value as time('now'). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void ctimeFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: sqlite3_value *pVal = sqlite3ValueNew(0); dbda8d6ce9 2007-07-21 drh: if( pVal ){ dbda8d6ce9 2007-07-21 drh: sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: timeFunc(context, 1, &pVal); dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree(pVal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** current_date() dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function returns the same value as date('now'). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void cdateFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: sqlite3_value *pVal = sqlite3ValueNew(0); dbda8d6ce9 2007-07-21 drh: if( pVal ){ dbda8d6ce9 2007-07-21 drh: sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: dateFunc(context, 1, &pVal); dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree(pVal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** current_timestamp() dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function returns the same value as datetime('now'). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void ctimestampFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: sqlite3_value *pVal = sqlite3ValueNew(0); dbda8d6ce9 2007-07-21 drh: if( pVal ){ dbda8d6ce9 2007-07-21 drh: sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: datetimeFunc(context, 1, &pVal); dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree(pVal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_DATETIME_FUNCS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the library is compiled to omit the full-scale date and time dbda8d6ce9 2007-07-21 drh: ** handling (to get a smaller binary), the following minimal version dbda8d6ce9 2007-07-21 drh: ** of the functions current_time(), current_date() and current_timestamp() dbda8d6ce9 2007-07-21 drh: ** are included instead. This is to support column declarations that dbda8d6ce9 2007-07-21 drh: ** include "DEFAULT CURRENT_TIME" etc. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function uses the C-library functions time(), gmtime() dbda8d6ce9 2007-07-21 drh: ** and strftime(). The format string to pass to strftime() is supplied dbda8d6ce9 2007-07-21 drh: ** as the user-data for the function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void currentTimeFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: time_t t; dbda8d6ce9 2007-07-21 drh: char *zFormat = (char *)sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: char zBuf[20]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: time(&t); dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: extern int sqlite3_current_time; /* See os_XXX.c */ dbda8d6ce9 2007-07-21 drh: if( sqlite3_current_time ){ dbda8d6ce9 2007-07-21 drh: t = sqlite3_current_time; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef HAVE_GMTIME_R dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: struct tm sNow; dbda8d6ce9 2007-07-21 drh: gmtime_r(&t, &sNow); dbda8d6ce9 2007-07-21 drh: strftime(zBuf, 20, zFormat, &sNow); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: struct tm *pTm; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); dbda8d6ce9 2007-07-21 drh: pTm = gmtime(&t); dbda8d6ce9 2007-07-21 drh: strftime(zBuf, 20, zFormat, pTm); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function registered all of the above C functions as SQL dbda8d6ce9 2007-07-21 drh: ** functions. This should be the only routine in this file with dbda8d6ce9 2007-07-21 drh: ** external linkage. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_DATETIME_FUNCS dbda8d6ce9 2007-07-21 drh: static const struct { dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: int nArg; dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value**); dbda8d6ce9 2007-07-21 drh: } aFuncs[] = { dbda8d6ce9 2007-07-21 drh: { "julianday", -1, juliandayFunc }, dbda8d6ce9 2007-07-21 drh: { "date", -1, dateFunc }, dbda8d6ce9 2007-07-21 drh: { "time", -1, timeFunc }, dbda8d6ce9 2007-07-21 drh: { "datetime", -1, datetimeFunc }, dbda8d6ce9 2007-07-21 drh: { "strftime", -1, strftimeFunc }, dbda8d6ce9 2007-07-21 drh: { "current_time", 0, ctimeFunc }, dbda8d6ce9 2007-07-21 drh: { "current_timestamp", 0, ctimestampFunc }, dbda8d6ce9 2007-07-21 drh: { "current_date", 0, cdateFunc }, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg, c287665ba8 2007-09-14 drh: SQLITE_UTF8, (void *)(db->pVfs), aFuncs[i].xFunc, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: static const struct { dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: char *zFormat; dbda8d6ce9 2007-07-21 drh: } aFuncs[] = { dbda8d6ce9 2007-07-21 drh: { "current_time", "%H:%M:%S" }, dbda8d6ce9 2007-07-21 drh: { "current_date", "%Y-%m-%d" }, dbda8d6ce9 2007-07-21 drh: { "current_timestamp", "%Y-%m-%d %H:%M:%S" } dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, aFuncs[i].zName, 0, SQLITE_UTF8, dbda8d6ce9 2007-07-21 drh: aFuncs[i].zFormat, currentTimeFunc, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of date.c ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file os.c **********************************************/ c287665ba8 2007-09-14 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2005 November 29 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains OS interface code that is common to all dbda8d6ce9 2007-07-21 drh: ** architectures. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define _SQLITE_OS_C_ 1 dbda8d6ce9 2007-07-21 drh: #undef _SQLITE_OS_C_ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following routines are convenience wrappers around methods c287665ba8 2007-09-14 drh: ** of the sqlite3_file object. This is mostly just syntactic sugar. All dbda8d6ce9 2007-07-21 drh: ** of this would be completely automatic if SQLite were coded using dbda8d6ce9 2007-07-21 drh: ** C++ instead of plain old C. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file *pId){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: if( pId->pMethods ){ c287665ba8 2007-09-14 drh: rc = pId->pMethods->xClose(pId); c287665ba8 2007-09-14 drh: pId->pMethods = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ c287665ba8 2007-09-14 drh: return id->pMethods->xRead(id, pBuf, amt, offset); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){ c287665ba8 2007-09-14 drh: return id->pMethods->xWrite(id, pBuf, amt, offset); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){ c287665ba8 2007-09-14 drh: return id->pMethods->xTruncate(id, size); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){ c287665ba8 2007-09-14 drh: return id->pMethods->xSync(id, flags); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ c287665ba8 2007-09-14 drh: return id->pMethods->xFileSize(id, pSize); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){ c287665ba8 2007-09-14 drh: return id->pMethods->xLock(id, lockType); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){ c287665ba8 2007-09-14 drh: return id->pMethods->xUnlock(id, lockType); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id){ c287665ba8 2007-09-14 drh: return id->pMethods->xCheckReservedLock(id); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ c287665ba8 2007-09-14 drh: return id->pMethods->xFileControl(id,op,pArg); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: /* The following two variables are used to override the values returned c287665ba8 2007-09-14 drh: ** by the xSectorSize() and xDeviceCharacteristics() vfs methods for c287665ba8 2007-09-14 drh: ** testing purposes. They are usually set by a test command implemented c287665ba8 2007-09-14 drh: ** in test6.c. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: int sqlite3_test_sector_size = 0; c287665ba8 2007-09-14 drh: int sqlite3_test_device_characteristics = 0; c287665ba8 2007-09-14 drh: int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ c287665ba8 2007-09-14 drh: int dc = id->pMethods->xDeviceCharacteristics(id); c287665ba8 2007-09-14 drh: return dc | sqlite3_test_device_characteristics; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: int sqlite3OsSectorSize(sqlite3_file *id){ c287665ba8 2007-09-14 drh: if( sqlite3_test_sector_size==0 ){ c287665ba8 2007-09-14 drh: int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; c287665ba8 2007-09-14 drh: return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return sqlite3_test_sector_size; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: int sqlite3OsSectorSize(sqlite3_file *id){ c287665ba8 2007-09-14 drh: int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; c287665ba8 2007-09-14 drh: return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ c287665ba8 2007-09-14 drh: return id->pMethods->xDeviceCharacteristics(id); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The next group of routines are convenience wrappers around the c287665ba8 2007-09-14 drh: ** VFS methods. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsOpen( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, c287665ba8 2007-09-14 drh: const char *zPath, c287665ba8 2007-09-14 drh: sqlite3_file *pFile, c287665ba8 2007-09-14 drh: int flags, c287665ba8 2007-09-14 drh: int *pFlagsOut c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: return pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ c287665ba8 2007-09-14 drh: return pVfs->xDelete(pVfs, zPath, dirSync); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){ c287665ba8 2007-09-14 drh: return pVfs->xAccess(pVfs, zPath, flags); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsGetTempName(sqlite3_vfs *pVfs, char *zBufOut){ c287665ba8 2007-09-14 drh: return pVfs->xGetTempName(pVfs, zBufOut); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *pVfs, const char *zPath, char *zPathOut){ c287665ba8 2007-09-14 drh: return pVfs->xFullPathname(pVfs, zPath, zPathOut); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ c287665ba8 2007-09-14 drh: return pVfs->xDlOpen(pVfs, zPath); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ c287665ba8 2007-09-14 drh: pVfs->xDlError(pVfs, nByte, zBufOut); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ c287665ba8 2007-09-14 drh: return pVfs->xDlSym(pVfs, pHandle, zSymbol); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ c287665ba8 2007-09-14 drh: pVfs->xDlClose(pVfs, pHandle); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ c287665ba8 2007-09-14 drh: return pVfs->xRandomness(pVfs, nByte, zBufOut); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ c287665ba8 2007-09-14 drh: return pVfs->xSleep(pVfs, nMicro); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ c287665ba8 2007-09-14 drh: return pVfs->xCurrentTime(pVfs, pTimeOut); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsOpenMalloc( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, c287665ba8 2007-09-14 drh: const char *zFile, c287665ba8 2007-09-14 drh: sqlite3_file **ppFile, c287665ba8 2007-09-14 drh: int flags, c287665ba8 2007-09-14 drh: int *pOutFlags c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int rc = SQLITE_NOMEM; c287665ba8 2007-09-14 drh: sqlite3_file *pFile; c287665ba8 2007-09-14 drh: pFile = (sqlite3_file *)sqlite3_malloc(pVfs->szOsFile); c287665ba8 2007-09-14 drh: if( pFile ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3_free(pFile); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: *ppFile = pFile; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: if( pFile ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsClose(pFile); c287665ba8 2007-09-14 drh: sqlite3_free(pFile); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The list of all registered VFS implementations. This list is c287665ba8 2007-09-14 drh: ** initialized to the single VFS returned by sqlite3OsDefaultVfs() c287665ba8 2007-09-14 drh: ** upon the first call to sqlite3_vfs_find(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static sqlite3_vfs *vfsList = 0; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Locate a VFS by name. If no name is given, simply return the c287665ba8 2007-09-14 drh: ** first VFS on the list. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs; c287665ba8 2007-09-14 drh: static int isInit = 0; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: if( !isInit ){ c287665ba8 2007-09-14 drh: vfsList = sqlite3OsDefaultVfs(); c287665ba8 2007-09-14 drh: isInit = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){ c287665ba8 2007-09-14 drh: if( zVfs==0 ) break; c287665ba8 2007-09-14 drh: if( strcmp(zVfs, pVfs->zName)==0 ) break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); c287665ba8 2007-09-14 drh: return pVfs; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Unlink a VFS from the linked list c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void vfsUnlink(sqlite3_vfs *pVfs){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) ); c287665ba8 2007-09-14 drh: if( vfsList==pVfs ){ c287665ba8 2007-09-14 drh: vfsList = pVfs->pNext; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: sqlite3_vfs *p = vfsList; c287665ba8 2007-09-14 drh: while( p->pNext && p->pNext!=pVfs ){ c287665ba8 2007-09-14 drh: p = p->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( p->pNext==pVfs ){ c287665ba8 2007-09-14 drh: p->pNext = pVfs->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Register a VFS with the system. It is harmless to register the same c287665ba8 2007-09-14 drh: ** VFS multiple times. The new VFS becomes the default if makeDflt is c287665ba8 2007-09-14 drh: ** true. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: sqlite3_vfs_find(0); /* Make sure we are initialized */ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: vfsUnlink(pVfs); c287665ba8 2007-09-14 drh: if( makeDflt || vfsList==0 ){ c287665ba8 2007-09-14 drh: pVfs->pNext = vfsList; c287665ba8 2007-09-14 drh: vfsList = pVfs; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pVfs->pNext = vfsList->pNext; c287665ba8 2007-09-14 drh: vfsList->pNext = pVfs; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert(vfsList); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Unregister a VFS so that it is no longer accessible. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: vfsUnlink(pVfs); c287665ba8 2007-09-14 drh: assert(vfsList); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of os.c **************************************************/ c287665ba8 2007-09-14 drh: /************** Begin file mem1.c ********************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 14 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** This file contains the C functions that implement a memory c287665ba8 2007-09-14 drh: ** allocation subsystem for use by SQLite. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: mem1.c,v 1.10 2007/09/02 17:50:35 drh Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This version of the memory allocator is the default. It is c287665ba8 2007-09-14 drh: ** used when no other memory allocator is specified using compile-time c287665ba8 2007-09-14 drh: ** macros. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #if !defined(SQLITE_MEMDEBUG) && !defined(SQLITE_OMIT_MEMORY_ALLOCATION) c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** We will eventually construct multiple memory allocation subsystems c287665ba8 2007-09-14 drh: ** suitable for use in various contexts: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** * Normal multi-threaded builds c287665ba8 2007-09-14 drh: ** * Normal single-threaded builds c287665ba8 2007-09-14 drh: ** * Debugging builds c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This initial version is suitable for use in normal multi-threaded c287665ba8 2007-09-14 drh: ** builds. We envision that alternative versions will be stored in c287665ba8 2007-09-14 drh: ** separate source files. #ifdefs will be used to select the code from c287665ba8 2007-09-14 drh: ** one of the various memN.c source files for use in any given build. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** All of the static variables used by this module are collected c287665ba8 2007-09-14 drh: ** into a single structure named "mem". This is to keep the c287665ba8 2007-09-14 drh: ** static variables organized and to reduce namespace pollution c287665ba8 2007-09-14 drh: ** when this module is combined with other in the amalgamation. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static struct { c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The alarm callback and its arguments. The mem.mutex lock will c287665ba8 2007-09-14 drh: ** be held while the callback is running. Recursive calls into c287665ba8 2007-09-14 drh: ** the memory subsystem are allowed, but no new callbacks will be c287665ba8 2007-09-14 drh: ** issued. The alarmBusy variable is set to prevent recursive c287665ba8 2007-09-14 drh: ** callbacks. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3_int64 alarmThreshold; c287665ba8 2007-09-14 drh: void (*alarmCallback)(void*, sqlite3_int64,int); c287665ba8 2007-09-14 drh: void *alarmArg; c287665ba8 2007-09-14 drh: int alarmBusy; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Mutex to control access to the memory allocation subsystem. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Current allocation and high-water mark. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3_int64 nowUsed; c287665ba8 2007-09-14 drh: sqlite3_int64 mxUsed; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: } mem; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Enter the mutex mem.mutex. Allocate it if it is not already allocated. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void enterMem(void){ c287665ba8 2007-09-14 drh: if( mem.mutex==0 ){ c287665ba8 2007-09-14 drh: mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return the amount of memory currently checked out. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_memory_used(void){ c287665ba8 2007-09-14 drh: sqlite3_int64 n; c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: n = mem.nowUsed; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: return n; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return the maximum amount of memory that has ever been c287665ba8 2007-09-14 drh: ** checked out since either the beginning of this process c287665ba8 2007-09-14 drh: ** or since the most recent reset. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ c287665ba8 2007-09-14 drh: sqlite3_int64 n; c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: n = mem.mxUsed; c287665ba8 2007-09-14 drh: if( resetFlag ){ c287665ba8 2007-09-14 drh: mem.mxUsed = mem.nowUsed; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: return n; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Change the alarm callback c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_memory_alarm( c287665ba8 2007-09-14 drh: void(*xCallback)(void *pArg, sqlite3_int64 used,int N), c287665ba8 2007-09-14 drh: void *pArg, c287665ba8 2007-09-14 drh: sqlite3_int64 iThreshold c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: mem.alarmCallback = xCallback; c287665ba8 2007-09-14 drh: mem.alarmArg = pArg; c287665ba8 2007-09-14 drh: mem.alarmThreshold = iThreshold; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Trigger the alarm c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void sqlite3MemsysAlarm(int nByte){ c287665ba8 2007-09-14 drh: void (*xCallback)(void*,sqlite3_int64,int); c287665ba8 2007-09-14 drh: sqlite3_int64 nowUsed; c287665ba8 2007-09-14 drh: void *pArg; c287665ba8 2007-09-14 drh: if( mem.alarmCallback==0 || mem.alarmBusy ) return; c287665ba8 2007-09-14 drh: mem.alarmBusy = 1; c287665ba8 2007-09-14 drh: xCallback = mem.alarmCallback; c287665ba8 2007-09-14 drh: nowUsed = mem.nowUsed; c287665ba8 2007-09-14 drh: pArg = mem.alarmArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: xCallback(pArg, nowUsed, nByte); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: mem.alarmBusy = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Allocate nBytes of memory c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_malloc(int nBytes){ c287665ba8 2007-09-14 drh: sqlite3_int64 *p = 0; c287665ba8 2007-09-14 drh: if( nBytes>0 ){ c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: if( mem.alarmCallback!=0 && mem.nowUsed+nBytes>=mem.alarmThreshold ){ c287665ba8 2007-09-14 drh: sqlite3MemsysAlarm(nBytes); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p = malloc(nBytes+8); c287665ba8 2007-09-14 drh: if( p==0 ){ c287665ba8 2007-09-14 drh: sqlite3MemsysAlarm(nBytes); c287665ba8 2007-09-14 drh: p = malloc(nBytes+8); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( p ){ c287665ba8 2007-09-14 drh: p[0] = nBytes; c287665ba8 2007-09-14 drh: p++; c287665ba8 2007-09-14 drh: mem.nowUsed += nBytes; c287665ba8 2007-09-14 drh: if( mem.nowUsed>mem.mxUsed ){ c287665ba8 2007-09-14 drh: mem.mxUsed = mem.nowUsed; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return (void*)p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Free memory. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_free(void *pPrior){ c287665ba8 2007-09-14 drh: sqlite3_int64 *p; c287665ba8 2007-09-14 drh: int nByte; c287665ba8 2007-09-14 drh: if( pPrior==0 ){ c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert( mem.mutex!=0 ); c287665ba8 2007-09-14 drh: p = pPrior; c287665ba8 2007-09-14 drh: p--; c287665ba8 2007-09-14 drh: nByte = (int)*p; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: mem.nowUsed -= nByte; c287665ba8 2007-09-14 drh: free(p); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Change the size of an existing memory allocation c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_realloc(void *pPrior, int nBytes){ c287665ba8 2007-09-14 drh: int nOld; c287665ba8 2007-09-14 drh: sqlite3_int64 *p; c287665ba8 2007-09-14 drh: if( pPrior==0 ){ c287665ba8 2007-09-14 drh: return sqlite3_malloc(nBytes); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( nBytes<=0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(pPrior); c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p = pPrior; c287665ba8 2007-09-14 drh: p--; c287665ba8 2007-09-14 drh: nOld = (int)p[0]; c287665ba8 2007-09-14 drh: assert( mem.mutex!=0 ); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){ c287665ba8 2007-09-14 drh: sqlite3MemsysAlarm(nBytes-nOld); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p = realloc(p, nBytes+8); c287665ba8 2007-09-14 drh: if( p==0 ){ c287665ba8 2007-09-14 drh: sqlite3MemsysAlarm(nBytes); c287665ba8 2007-09-14 drh: p = realloc(p, nBytes+8); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( p ){ c287665ba8 2007-09-14 drh: p[0] = nBytes; c287665ba8 2007-09-14 drh: p++; c287665ba8 2007-09-14 drh: mem.nowUsed += nBytes-nOld; c287665ba8 2007-09-14 drh: if( mem.nowUsed>mem.mxUsed ){ c287665ba8 2007-09-14 drh: mem.mxUsed = mem.nowUsed; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: return (void*)p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of mem1.c ************************************************/ c287665ba8 2007-09-14 drh: /************** Begin file mem2.c ********************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 15 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** This file contains the C functions that implement a memory c287665ba8 2007-09-14 drh: ** allocation subsystem for use by SQLite. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: mem2.c,v 1.13 2007/09/01 09:02:54 danielk1977 Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This version of the memory allocator is used only if the c287665ba8 2007-09-14 drh: ** SQLITE_MEMDEBUG macro is defined and SQLITE_OMIT_MEMORY_ALLOCATION c287665ba8 2007-09-14 drh: ** is not defined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #if defined(SQLITE_MEMDEBUG) && !defined(SQLITE_OMIT_MEMORY_ALLOCATION) c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** We will eventually construct multiple memory allocation subsystems c287665ba8 2007-09-14 drh: ** suitable for use in various contexts: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** * Normal multi-threaded builds c287665ba8 2007-09-14 drh: ** * Normal single-threaded builds c287665ba8 2007-09-14 drh: ** * Debugging builds c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This version is suitable for use in debugging builds. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Features: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** * Every allocate has guards at both ends. c287665ba8 2007-09-14 drh: ** * New allocations are initialized with randomness c287665ba8 2007-09-14 drh: ** * Allocations are overwritten with randomness when freed c287665ba8 2007-09-14 drh: ** * Optional logs of malloc activity generated c287665ba8 2007-09-14 drh: ** * Summary of outstanding allocations with backtraces to the c287665ba8 2007-09-14 drh: ** point of allocation. c287665ba8 2007-09-14 drh: ** * The ability to simulate memory allocation failure c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The backtrace functionality is only available with GLIBC c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef __GLIBC__ c287665ba8 2007-09-14 drh: extern int backtrace(void**,int); c287665ba8 2007-09-14 drh: extern void backtrace_symbols_fd(void*const*,int,int); c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: # define backtrace(A,B) 0 c287665ba8 2007-09-14 drh: # define backtrace_symbols_fd(A,B,C) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Each memory allocation looks like this: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** ------------------------------------------------------------------------ c287665ba8 2007-09-14 drh: ** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | c287665ba8 2007-09-14 drh: ** ------------------------------------------------------------------------ c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The application code sees only a pointer to the allocation. We have c287665ba8 2007-09-14 drh: ** to back up from the allocation pointer to find the MemBlockHdr. The c287665ba8 2007-09-14 drh: ** MemBlockHdr tells us the size of the allocation and the number of c287665ba8 2007-09-14 drh: ** backtrace pointers. There is also a guard word at the end of the c287665ba8 2007-09-14 drh: ** MemBlockHdr. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: struct MemBlockHdr { c287665ba8 2007-09-14 drh: struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ c287665ba8 2007-09-14 drh: int iSize; /* Size of this allocation */ c287665ba8 2007-09-14 drh: char nBacktrace; /* Number of backtraces on this alloc */ c287665ba8 2007-09-14 drh: char nBacktraceSlots; /* Available backtrace slots */ c287665ba8 2007-09-14 drh: short nTitle; /* Bytes of title; includes '\0' */ c287665ba8 2007-09-14 drh: int iForeGuard; /* Guard word for sanity */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Guard words c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define FOREGUARD 0x80F5E153 c287665ba8 2007-09-14 drh: #define REARGUARD 0xE4676B53 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** All of the static variables used by this module are collected c287665ba8 2007-09-14 drh: ** into a single structure named "mem". This is to keep the c287665ba8 2007-09-14 drh: ** static variables organized and to reduce namespace pollution c287665ba8 2007-09-14 drh: ** when this module is combined with other in the amalgamation. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static struct { c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The alarm callback and its arguments. The mem.mutex lock will c287665ba8 2007-09-14 drh: ** be held while the callback is running. Recursive calls into c287665ba8 2007-09-14 drh: ** the memory subsystem are allowed, but no new callbacks will be c287665ba8 2007-09-14 drh: ** issued. The alarmBusy variable is set to prevent recursive c287665ba8 2007-09-14 drh: ** callbacks. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3_int64 alarmThreshold; c287665ba8 2007-09-14 drh: void (*alarmCallback)(void*, sqlite3_int64, int); c287665ba8 2007-09-14 drh: void *alarmArg; c287665ba8 2007-09-14 drh: int alarmBusy; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Mutex to control access to the memory allocation subsystem. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Current allocation and high-water mark. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3_int64 nowUsed; c287665ba8 2007-09-14 drh: sqlite3_int64 mxUsed; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Head and tail of a linked list of all outstanding allocations c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: struct MemBlockHdr *pFirst; c287665ba8 2007-09-14 drh: struct MemBlockHdr *pLast; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The number of levels of backtrace to save in new allocations. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: int nBacktrace; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Title text to insert in front of each block c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ c287665ba8 2007-09-14 drh: char zTitle[100]; /* The title text */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** These values are used to simulate malloc failures. When c287665ba8 2007-09-14 drh: ** iFail is 1, simulate a malloc failures and reset the value c287665ba8 2007-09-14 drh: ** to iReset. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: int iFail; /* Decrement and fail malloc when this is 1 */ c287665ba8 2007-09-14 drh: int iReset; /* When malloc fails set iiFail to this value */ c287665ba8 2007-09-14 drh: int iFailCnt; /* Number of failures */ c287665ba8 2007-09-14 drh: int iBenignFailCnt; /* Number of benign failures */ c287665ba8 2007-09-14 drh: int iNextIsBenign; /* True if the next call to malloc may fail benignly */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** sqlite3MallocDisallow() increments the following counter. c287665ba8 2007-09-14 drh: ** sqlite3MallocAllow() decrements it. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: int disallow; /* Do not allow memory allocation */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: } mem; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Enter the mutex mem.mutex. Allocate it if it is not already allocated. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void enterMem(void){ c287665ba8 2007-09-14 drh: if( mem.mutex==0 ){ c287665ba8 2007-09-14 drh: mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return the amount of memory currently checked out. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_memory_used(void){ c287665ba8 2007-09-14 drh: sqlite3_int64 n; c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: n = mem.nowUsed; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: return n; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return the maximum amount of memory that has ever been c287665ba8 2007-09-14 drh: ** checked out since either the beginning of this process c287665ba8 2007-09-14 drh: ** or since the most recent reset. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ c287665ba8 2007-09-14 drh: sqlite3_int64 n; c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: n = mem.mxUsed; c287665ba8 2007-09-14 drh: if( resetFlag ){ c287665ba8 2007-09-14 drh: mem.mxUsed = mem.nowUsed; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: return n; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Change the alarm callback c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_memory_alarm( c287665ba8 2007-09-14 drh: void(*xCallback)(void *pArg, sqlite3_int64 used, int N), c287665ba8 2007-09-14 drh: void *pArg, c287665ba8 2007-09-14 drh: sqlite3_int64 iThreshold c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: mem.alarmCallback = xCallback; c287665ba8 2007-09-14 drh: mem.alarmArg = pArg; c287665ba8 2007-09-14 drh: mem.alarmThreshold = iThreshold; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Trigger the alarm c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void sqlite3MemsysAlarm(int nByte){ c287665ba8 2007-09-14 drh: void (*xCallback)(void*,sqlite3_int64,int); c287665ba8 2007-09-14 drh: sqlite3_int64 nowUsed; c287665ba8 2007-09-14 drh: void *pArg; c287665ba8 2007-09-14 drh: if( mem.alarmCallback==0 || mem.alarmBusy ) return; c287665ba8 2007-09-14 drh: mem.alarmBusy = 1; c287665ba8 2007-09-14 drh: xCallback = mem.alarmCallback; c287665ba8 2007-09-14 drh: nowUsed = mem.nowUsed; c287665ba8 2007-09-14 drh: pArg = mem.alarmArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: xCallback(pArg, nowUsed, nByte); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: mem.alarmBusy = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Given an allocation, find the MemBlockHdr for that allocation. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine checks the guards at either end of the allocation and c287665ba8 2007-09-14 drh: ** if they are incorrect it asserts. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ c287665ba8 2007-09-14 drh: struct MemBlockHdr *p; c287665ba8 2007-09-14 drh: int *pInt; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: p = (struct MemBlockHdr*)pAllocation; c287665ba8 2007-09-14 drh: p--; c287665ba8 2007-09-14 drh: assert( p->iForeGuard==FOREGUARD ); c287665ba8 2007-09-14 drh: assert( (p->iSize & 3)==0 ); c287665ba8 2007-09-14 drh: pInt = (int*)pAllocation; c287665ba8 2007-09-14 drh: assert( pInt[p->iSize/sizeof(int)]==REARGUARD ); c287665ba8 2007-09-14 drh: return p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine is called once the first time a simulated memory c287665ba8 2007-09-14 drh: ** failure occurs. The sole purpose of this routine is to provide c287665ba8 2007-09-14 drh: ** a convenient place to set a debugger breakpoint when debugging c287665ba8 2007-09-14 drh: ** errors related to malloc() failures. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void sqlite3MemsysFailed(void){ c287665ba8 2007-09-14 drh: mem.iFailCnt = 0; c287665ba8 2007-09-14 drh: mem.iBenignFailCnt = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Allocate nByte bytes of memory. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_malloc(int nByte){ c287665ba8 2007-09-14 drh: struct MemBlockHdr *pHdr; c287665ba8 2007-09-14 drh: void **pBt; dbda8d6ce9 2007-07-21 drh: char *z; c287665ba8 2007-09-14 drh: int *pInt; c287665ba8 2007-09-14 drh: void *p = 0; c287665ba8 2007-09-14 drh: int totalSize; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( nByte>0 ){ c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: assert( mem.disallow==0 ); c287665ba8 2007-09-14 drh: if( mem.alarmCallback!=0 && mem.nowUsed+nByte>=mem.alarmThreshold ){ c287665ba8 2007-09-14 drh: sqlite3MemsysAlarm(nByte); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: nByte = (nByte+3)&~3; c287665ba8 2007-09-14 drh: totalSize = nByte + sizeof(*pHdr) + sizeof(int) + c287665ba8 2007-09-14 drh: mem.nBacktrace*sizeof(void*) + mem.nTitle; c287665ba8 2007-09-14 drh: if( mem.iFail>0 ){ c287665ba8 2007-09-14 drh: if( mem.iFail==1 ){ c287665ba8 2007-09-14 drh: p = 0; c287665ba8 2007-09-14 drh: mem.iFail = mem.iReset; c287665ba8 2007-09-14 drh: if( mem.iFailCnt==0 ){ c287665ba8 2007-09-14 drh: sqlite3MemsysFailed(); /* A place to set a breakpoint */ c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: mem.iFailCnt++; c287665ba8 2007-09-14 drh: if( mem.iNextIsBenign ){ c287665ba8 2007-09-14 drh: mem.iBenignFailCnt++; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: p = malloc(totalSize); c287665ba8 2007-09-14 drh: mem.iFail--; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: p = malloc(totalSize); c287665ba8 2007-09-14 drh: if( p==0 ){ c287665ba8 2007-09-14 drh: sqlite3MemsysAlarm(nByte); c287665ba8 2007-09-14 drh: p = malloc(totalSize); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( p ){ c287665ba8 2007-09-14 drh: z = p; c287665ba8 2007-09-14 drh: pBt = (void**)&z[mem.nTitle]; c287665ba8 2007-09-14 drh: pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; c287665ba8 2007-09-14 drh: pHdr->pNext = 0; c287665ba8 2007-09-14 drh: pHdr->pPrev = mem.pLast; c287665ba8 2007-09-14 drh: if( mem.pLast ){ c287665ba8 2007-09-14 drh: mem.pLast->pNext = pHdr; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: mem.pFirst = pHdr; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: mem.pLast = pHdr; c287665ba8 2007-09-14 drh: pHdr->iForeGuard = FOREGUARD; c287665ba8 2007-09-14 drh: pHdr->nBacktraceSlots = mem.nBacktrace; c287665ba8 2007-09-14 drh: pHdr->nTitle = mem.nTitle; c287665ba8 2007-09-14 drh: if( mem.nBacktrace ){ c287665ba8 2007-09-14 drh: void *aAddr[40]; c287665ba8 2007-09-14 drh: pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; c287665ba8 2007-09-14 drh: memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pHdr->nBacktrace = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( mem.nTitle ){ c287665ba8 2007-09-14 drh: memcpy(z, mem.zTitle, mem.nTitle); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pHdr->iSize = nByte; c287665ba8 2007-09-14 drh: pInt = (int*)&pHdr[1]; c287665ba8 2007-09-14 drh: pInt[nByte/sizeof(int)] = REARGUARD; c287665ba8 2007-09-14 drh: memset(pInt, 0x65, nByte); c287665ba8 2007-09-14 drh: mem.nowUsed += nByte; c287665ba8 2007-09-14 drh: if( mem.nowUsed>mem.mxUsed ){ c287665ba8 2007-09-14 drh: mem.mxUsed = mem.nowUsed; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p = (void*)pInt; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: mem.iNextIsBenign = 0; c287665ba8 2007-09-14 drh: return p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Free memory. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_free(void *pPrior){ c287665ba8 2007-09-14 drh: struct MemBlockHdr *pHdr; c287665ba8 2007-09-14 drh: void **pBt; dbda8d6ce9 2007-07-21 drh: char *z; c287665ba8 2007-09-14 drh: if( pPrior==0 ){ c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert( mem.mutex!=0 ); c287665ba8 2007-09-14 drh: pHdr = sqlite3MemsysGetHeader(pPrior); c287665ba8 2007-09-14 drh: pBt = (void**)pHdr; c287665ba8 2007-09-14 drh: pBt -= pHdr->nBacktraceSlots; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: mem.nowUsed -= pHdr->iSize; c287665ba8 2007-09-14 drh: if( pHdr->pPrev ){ c287665ba8 2007-09-14 drh: assert( pHdr->pPrev->pNext==pHdr ); c287665ba8 2007-09-14 drh: pHdr->pPrev->pNext = pHdr->pNext; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: assert( mem.pFirst==pHdr ); c287665ba8 2007-09-14 drh: mem.pFirst = pHdr->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pHdr->pNext ){ c287665ba8 2007-09-14 drh: assert( pHdr->pNext->pPrev==pHdr ); c287665ba8 2007-09-14 drh: pHdr->pNext->pPrev = pHdr->pPrev; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: assert( mem.pLast==pHdr ); c287665ba8 2007-09-14 drh: mem.pLast = pHdr->pPrev; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: z = (char*)pBt; c287665ba8 2007-09-14 drh: z -= pHdr->nTitle; c287665ba8 2007-09-14 drh: memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + c287665ba8 2007-09-14 drh: pHdr->iSize + sizeof(int) + pHdr->nTitle); c287665ba8 2007-09-14 drh: free(z); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Change the size of an existing memory allocation. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** For this debugging implementation, we *always* make a copy of the c287665ba8 2007-09-14 drh: ** allocation into a new place in memory. In this way, if the c287665ba8 2007-09-14 drh: ** higher level code is using pointer to the old allocation, it is c287665ba8 2007-09-14 drh: ** much more likely to break and we are much more liking to find c287665ba8 2007-09-14 drh: ** the error. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_realloc(void *pPrior, int nByte){ c287665ba8 2007-09-14 drh: struct MemBlockHdr *pOldHdr; c287665ba8 2007-09-14 drh: void *pNew; c287665ba8 2007-09-14 drh: if( pPrior==0 ){ c287665ba8 2007-09-14 drh: return sqlite3_malloc(nByte); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( nByte<=0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(pPrior); c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert( mem.disallow==0 ); c287665ba8 2007-09-14 drh: pOldHdr = sqlite3MemsysGetHeader(pPrior); c287665ba8 2007-09-14 drh: pNew = sqlite3_malloc(nByte); c287665ba8 2007-09-14 drh: if( pNew ){ c287665ba8 2007-09-14 drh: memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize); c287665ba8 2007-09-14 drh: if( nByte>pOldHdr->iSize ){ c287665ba8 2007-09-14 drh: memset(&((char*)pNew)[pOldHdr->iSize], 0x2b, nByte - pOldHdr->iSize); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pPrior); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return pNew; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Set the number of backtrace levels kept for each allocation. c287665ba8 2007-09-14 drh: ** A value of zero turns of backtracing. The number is always rounded c287665ba8 2007-09-14 drh: ** up to a multiple of 2. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_memdebug_backtrace(int depth){ c287665ba8 2007-09-14 drh: if( depth<0 ){ depth = 0; } c287665ba8 2007-09-14 drh: if( depth>20 ){ depth = 20; } c287665ba8 2007-09-14 drh: depth = (depth+1)&0xfe; c287665ba8 2007-09-14 drh: mem.nBacktrace = depth; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Set the title string for subsequent allocations. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_memdebug_settitle(const char *zTitle){ c287665ba8 2007-09-14 drh: int n = strlen(zTitle) + 1; c287665ba8 2007-09-14 drh: enterMem(); c287665ba8 2007-09-14 drh: if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; c287665ba8 2007-09-14 drh: memcpy(mem.zTitle, zTitle, n); c287665ba8 2007-09-14 drh: mem.zTitle[n] = 0; c287665ba8 2007-09-14 drh: mem.nTitle = (n+3)&~3; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Open the file indicated and write a log of all unfreed memory c287665ba8 2007-09-14 drh: ** allocations into that log. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_memdebug_dump(const char *zFilename){ c287665ba8 2007-09-14 drh: FILE *out; c287665ba8 2007-09-14 drh: struct MemBlockHdr *pHdr; c287665ba8 2007-09-14 drh: void **pBt; c287665ba8 2007-09-14 drh: out = fopen(zFilename, "w"); c287665ba8 2007-09-14 drh: if( out==0 ){ c287665ba8 2007-09-14 drh: fprintf(stderr, "** Unable to output memory debug output log: %s **\n", c287665ba8 2007-09-14 drh: zFilename); c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ c287665ba8 2007-09-14 drh: char *z = (char*)pHdr; c287665ba8 2007-09-14 drh: z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; c287665ba8 2007-09-14 drh: fprintf(out, "**** %d bytes at %p from %s ****\n", c287665ba8 2007-09-14 drh: pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); c287665ba8 2007-09-14 drh: if( pHdr->nBacktrace ){ c287665ba8 2007-09-14 drh: fflush(out); c287665ba8 2007-09-14 drh: pBt = (void**)pHdr; c287665ba8 2007-09-14 drh: pBt -= pHdr->nBacktraceSlots; c287665ba8 2007-09-14 drh: backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); c287665ba8 2007-09-14 drh: fprintf(out, "\n"); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: fclose(out); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine is used to simulate malloc failures. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** After calling this routine, there will be iFail successful c287665ba8 2007-09-14 drh: ** memory allocations and then a failure. If iRepeat is 1 c287665ba8 2007-09-14 drh: ** all subsequent memory allocations will fail. If iRepeat is c287665ba8 2007-09-14 drh: ** 0, only a single allocation will fail. If iRepeat is negative c287665ba8 2007-09-14 drh: ** then the previous setting for iRepeat is unchanged. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Each call to this routine overrides the previous. To disable c287665ba8 2007-09-14 drh: ** the simulated allocation failure mechanism, set iFail to -1. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine returns the number of simulated failures that have c287665ba8 2007-09-14 drh: ** occurred since the previous call. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_memdebug_fail(int iFail, int iRepeat, int *piBenign){ c287665ba8 2007-09-14 drh: int n = mem.iFailCnt; c287665ba8 2007-09-14 drh: if( piBenign ){ c287665ba8 2007-09-14 drh: *piBenign = mem.iBenignFailCnt; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: mem.iFail = iFail+1; c287665ba8 2007-09-14 drh: if( iRepeat>=0 ){ c287665ba8 2007-09-14 drh: mem.iReset = iRepeat; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: mem.iFailCnt = 0; c287665ba8 2007-09-14 drh: mem.iBenignFailCnt = 0; c287665ba8 2007-09-14 drh: return n; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_memdebug_pending(){ c287665ba8 2007-09-14 drh: return (mem.iFail-1); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3MallocBenignFailure(int isBenign){ c287665ba8 2007-09-14 drh: if( isBenign ){ c287665ba8 2007-09-14 drh: mem.iNextIsBenign = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The following two routines are used to assert that no memory c287665ba8 2007-09-14 drh: ** allocations occur between one call and the next. The use of c287665ba8 2007-09-14 drh: ** these routines does not change the computed results in any way. c287665ba8 2007-09-14 drh: ** These routines are like asserts. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3MallocDisallow(void){ c287665ba8 2007-09-14 drh: assert( mem.mutex!=0 ); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: mem.disallow++; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3MallocAllow(void){ c287665ba8 2007-09-14 drh: assert( mem.mutex ); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mem.mutex); c287665ba8 2007-09-14 drh: assert( mem.disallow>0 ); c287665ba8 2007-09-14 drh: mem.disallow--; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mem.mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #endif /* SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of mem2.c ************************************************/ c287665ba8 2007-09-14 drh: /************** Begin file mutex.c *******************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 14 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** This file contains the C functions that implement mutexes. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The implementation in this file does not provide any mutual c287665ba8 2007-09-14 drh: ** exclusion and is thus suitable for use only in applications c287665ba8 2007-09-14 drh: ** that use SQLite in a single thread. But this implementation c287665ba8 2007-09-14 drh: ** does do a lot of error checking on mutexes to make sure they c287665ba8 2007-09-14 drh: ** are called correctly and at appropriate times. Hence, this c287665ba8 2007-09-14 drh: ** implementation is suitable for testing. c287665ba8 2007-09-14 drh: ** debugging purposes c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: mutex.c,v 1.16 2007/09/10 16:13:00 danielk1977 Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_MUTEX_NOOP_DEBUG c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** In this implementation, mutexes do not provide any mutual exclusion. c287665ba8 2007-09-14 drh: ** But the error checking is provided. This implementation is useful c287665ba8 2007-09-14 drh: ** for test purposes. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The mutex object c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: struct sqlite3_mutex { c287665ba8 2007-09-14 drh: int id; /* The mutex type */ c287665ba8 2007-09-14 drh: int cnt; /* Number of entries without a matching leave */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_alloc() routine allocates a new c287665ba8 2007-09-14 drh: ** mutex and returns a pointer to it. If it returns NULL c287665ba8 2007-09-14 drh: ** that means that a mutex could not be allocated. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){ c287665ba8 2007-09-14 drh: static sqlite3_mutex aStatic[5]; c287665ba8 2007-09-14 drh: sqlite3_mutex *pNew = 0; c287665ba8 2007-09-14 drh: switch( id ){ c287665ba8 2007-09-14 drh: case SQLITE_MUTEX_FAST: c287665ba8 2007-09-14 drh: case SQLITE_MUTEX_RECURSIVE: { c287665ba8 2007-09-14 drh: pNew = sqlite3_malloc(sizeof(*pNew)); c287665ba8 2007-09-14 drh: if( pNew ){ c287665ba8 2007-09-14 drh: pNew->id = id; c287665ba8 2007-09-14 drh: pNew->cnt = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: default: { c287665ba8 2007-09-14 drh: assert( id-2 >= 0 ); c287665ba8 2007-09-14 drh: assert( id-2 < sizeof(aStatic)/sizeof(aStatic[0]) ); c287665ba8 2007-09-14 drh: pNew = &aStatic[id-2]; c287665ba8 2007-09-14 drh: pNew->id = id; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return pNew; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine deallocates a previously allocated mutex. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->cnt==0 ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); c287665ba8 2007-09-14 drh: sqlite3_free(p); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt c287665ba8 2007-09-14 drh: ** to enter a mutex. If another thread is already within the mutex, c287665ba8 2007-09-14 drh: ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return c287665ba8 2007-09-14 drh: ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK c287665ba8 2007-09-14 drh: ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can c287665ba8 2007-09-14 drh: ** be entered multiple times by the same thread. In such cases the, c287665ba8 2007-09-14 drh: ** mutex must be exited an equal number of times before another thread c287665ba8 2007-09-14 drh: ** can enter. If the same thread tries to enter any other kind of mutex c287665ba8 2007-09-14 drh: ** more than once, the behavior is undefined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: p->cnt++; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: p->cnt++; c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_leave() routine exits a mutex that was c287665ba8 2007-09-14 drh: ** previously entered by the same thread. The behavior c287665ba8 2007-09-14 drh: ** is undefined if the mutex is not currently entered or c287665ba8 2007-09-14 drh: ** is not currently allocated. SQLite will never do either. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p) ); c287665ba8 2007-09-14 drh: p->cnt--; c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are c287665ba8 2007-09-14 drh: ** intended for use inside assert() statements. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: return p==0 || p->cnt>0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: return p==0 || p->cnt==0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif /* SQLITE_MUTEX_NOOP_DEBUG */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of mutex.c ***********************************************/ c287665ba8 2007-09-14 drh: /************** Begin file mutex_os2.c ***************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 28 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** This file contains the C functions that implement mutexes for OS/2 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: mutex_os2.c,v 1.1 2007/08/28 16:34:43 drh Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The code in this file is only used if SQLITE_MUTEX_OS2 is defined. c287665ba8 2007-09-14 drh: ** See the mutex.h file for details. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_MUTEX_OS2 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /**** FIX ME: c287665ba8 2007-09-14 drh: ***** This is currently a no-op implementation suitable for use c287665ba8 2007-09-14 drh: ***** in single-threaded applications only. Somebody please replace c287665ba8 2007-09-14 drh: ***** this with a real mutex implementation for OS/2. c287665ba8 2007-09-14 drh: ****/ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The mutex object c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: struct sqlite3_mutex { c287665ba8 2007-09-14 drh: int id; /* The mutex type */ c287665ba8 2007-09-14 drh: int cnt; /* Number of entries without a matching leave */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_alloc() routine allocates a new c287665ba8 2007-09-14 drh: ** mutex and returns a pointer to it. If it returns NULL c287665ba8 2007-09-14 drh: ** that means that a mutex could not be allocated. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){ c287665ba8 2007-09-14 drh: static sqlite3_mutex aStatic[4]; c287665ba8 2007-09-14 drh: sqlite3_mutex *pNew = 0; c287665ba8 2007-09-14 drh: switch( id ){ c287665ba8 2007-09-14 drh: case SQLITE_MUTEX_FAST: c287665ba8 2007-09-14 drh: case SQLITE_MUTEX_RECURSIVE: { c287665ba8 2007-09-14 drh: pNew = sqlite3_malloc(sizeof(*pNew)); c287665ba8 2007-09-14 drh: if( pNew ){ c287665ba8 2007-09-14 drh: pNew->id = id; c287665ba8 2007-09-14 drh: pNew->cnt = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: default: { c287665ba8 2007-09-14 drh: assert( id-2 >= 0 ); c287665ba8 2007-09-14 drh: assert( id-2 < sizeof(aStatic)/sizeof(aStatic[0]) ); c287665ba8 2007-09-14 drh: pNew = &aStatic[id-2]; c287665ba8 2007-09-14 drh: pNew->id = id; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return pNew; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine deallocates a previously allocated mutex. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->cnt==0 ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); c287665ba8 2007-09-14 drh: sqlite3_free(p); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt c287665ba8 2007-09-14 drh: ** to enter a mutex. If another thread is already within the mutex, c287665ba8 2007-09-14 drh: ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return c287665ba8 2007-09-14 drh: ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK c287665ba8 2007-09-14 drh: ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can c287665ba8 2007-09-14 drh: ** be entered multiple times by the same thread. In such cases the, c287665ba8 2007-09-14 drh: ** mutex must be exited an equal number of times before another thread c287665ba8 2007-09-14 drh: ** can enter. If the same thread tries to enter any other kind of mutex c287665ba8 2007-09-14 drh: ** more than once, the behavior is undefined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: p->cnt++; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: p->cnt++; c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_leave() routine exits a mutex that was c287665ba8 2007-09-14 drh: ** previously entered by the same thread. The behavior c287665ba8 2007-09-14 drh: ** is undefined if the mutex is not currently entered or c287665ba8 2007-09-14 drh: ** is not currently allocated. SQLite will never do either. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p) ); c287665ba8 2007-09-14 drh: p->cnt--; c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are c287665ba8 2007-09-14 drh: ** intended for use inside assert() statements. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: return p==0 || p->cnt>0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: return p==0 || p->cnt==0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif /* SQLITE_MUTEX_OS2 */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of mutex_os2.c *******************************************/ c287665ba8 2007-09-14 drh: /************** Begin file mutex_unix.c **************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 28 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** This file contains the C functions that implement mutexes for pthreads c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: mutex_unix.c,v 1.2 2007/08/28 22:24:35 drh Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The code in this file is only used if we are compiling threadsafe c287665ba8 2007-09-14 drh: ** under unix with pthreads. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Note that this implementation requires a version of pthreads that c287665ba8 2007-09-14 drh: ** supports recursive mutexes. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_MUTEX_PTHREADS c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #include <pthread.h> c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Each recursive mutex is an instance of the following structure. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: struct sqlite3_mutex { c287665ba8 2007-09-14 drh: pthread_mutex_t mutex; /* Mutex controlling the lock */ c287665ba8 2007-09-14 drh: int id; /* Mutex type */ c287665ba8 2007-09-14 drh: int nRef; /* Number of entrances */ c287665ba8 2007-09-14 drh: pthread_t owner; /* Thread that is within this mutex */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: int trace; /* True to trace changes */ c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_alloc() routine allocates a new c287665ba8 2007-09-14 drh: ** mutex and returns a pointer to it. If it returns NULL c287665ba8 2007-09-14 drh: ** that means that a mutex could not be allocated. SQLite c287665ba8 2007-09-14 drh: ** will unwind its stack and return an error. The argument c287665ba8 2007-09-14 drh: ** to sqlite3_mutex_alloc() is one of these integer constants: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <ul> c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_FAST c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_RECURSIVE c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_MASTER c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_MEM c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_MEM2 c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_PRNG c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_LRU c287665ba8 2007-09-14 drh: ** </ul> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The first two constants cause sqlite3_mutex_alloc() to create c287665ba8 2007-09-14 drh: ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE c287665ba8 2007-09-14 drh: ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. c287665ba8 2007-09-14 drh: ** The mutex implementation does not need to make a distinction c287665ba8 2007-09-14 drh: ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does c287665ba8 2007-09-14 drh: ** not want to. But SQLite will only request a recursive mutex in c287665ba8 2007-09-14 drh: ** cases where it really needs one. If a faster non-recursive mutex c287665ba8 2007-09-14 drh: ** implementation is available on the host platform, the mutex subsystem c287665ba8 2007-09-14 drh: ** might return such a mutex in response to SQLITE_MUTEX_FAST. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The other allowed parameters to sqlite3_mutex_alloc() each return c287665ba8 2007-09-14 drh: ** a pointer to a static preexisting mutex. Three static mutexes are c287665ba8 2007-09-14 drh: ** used by the current version of SQLite. Future versions of SQLite c287665ba8 2007-09-14 drh: ** may add additional static mutexes. Static mutexes are for internal c287665ba8 2007-09-14 drh: ** use by SQLite only. Applications that use SQLite mutexes should c287665ba8 2007-09-14 drh: ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_RECURSIVE. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST c287665ba8 2007-09-14 drh: ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() c287665ba8 2007-09-14 drh: ** returns a different mutex on every call. But for the static c287665ba8 2007-09-14 drh: ** mutex types, the same mutex is returned on every call that has c287665ba8 2007-09-14 drh: ** the same type number. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int iType){ c287665ba8 2007-09-14 drh: static sqlite3_mutex staticMutexes[] = { c287665ba8 2007-09-14 drh: { PTHREAD_MUTEX_INITIALIZER, }, c287665ba8 2007-09-14 drh: { PTHREAD_MUTEX_INITIALIZER, }, c287665ba8 2007-09-14 drh: { PTHREAD_MUTEX_INITIALIZER, }, c287665ba8 2007-09-14 drh: { PTHREAD_MUTEX_INITIALIZER, }, c287665ba8 2007-09-14 drh: { PTHREAD_MUTEX_INITIALIZER, }, c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: sqlite3_mutex *p; c287665ba8 2007-09-14 drh: switch( iType ){ c287665ba8 2007-09-14 drh: case SQLITE_MUTEX_RECURSIVE: { c287665ba8 2007-09-14 drh: p = sqlite3MallocZero( sizeof(*p) ); c287665ba8 2007-09-14 drh: if( p ){ c287665ba8 2007-09-14 drh: pthread_mutexattr_t recursiveAttr; c287665ba8 2007-09-14 drh: pthread_mutexattr_init(&recursiveAttr); c287665ba8 2007-09-14 drh: pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE); c287665ba8 2007-09-14 drh: pthread_mutex_init(&p->mutex, &recursiveAttr); c287665ba8 2007-09-14 drh: pthread_mutexattr_destroy(&recursiveAttr); c287665ba8 2007-09-14 drh: p->id = iType; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: case SQLITE_MUTEX_FAST: { c287665ba8 2007-09-14 drh: p = sqlite3MallocZero( sizeof(*p) ); c287665ba8 2007-09-14 drh: if( p ){ c287665ba8 2007-09-14 drh: p->id = iType; c287665ba8 2007-09-14 drh: pthread_mutex_init(&p->mutex, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: default: { c287665ba8 2007-09-14 drh: assert( iType-2 >= 0 ); c287665ba8 2007-09-14 drh: assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) ); c287665ba8 2007-09-14 drh: p = &staticMutexes[iType-2]; c287665ba8 2007-09-14 drh: p->id = iType; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine deallocates a previously c287665ba8 2007-09-14 drh: ** allocated mutex. SQLite is careful to deallocate every c287665ba8 2007-09-14 drh: ** mutex that it allocates. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->nRef==0 ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); c287665ba8 2007-09-14 drh: pthread_mutex_destroy(&p->mutex); c287665ba8 2007-09-14 drh: sqlite3_free(p); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt c287665ba8 2007-09-14 drh: ** to enter a mutex. If another thread is already within the mutex, c287665ba8 2007-09-14 drh: ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return c287665ba8 2007-09-14 drh: ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK c287665ba8 2007-09-14 drh: ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can c287665ba8 2007-09-14 drh: ** be entered multiple times by the same thread. In such cases the, c287665ba8 2007-09-14 drh: ** mutex must be exited an equal number of times before another thread c287665ba8 2007-09-14 drh: ** can enter. If the same thread tries to enter any other kind of mutex c287665ba8 2007-09-14 drh: ** more than once, the behavior is undefined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: pthread_mutex_lock(&p->mutex); c287665ba8 2007-09-14 drh: p->owner = pthread_self(); c287665ba8 2007-09-14 drh: p->nRef++; c287665ba8 2007-09-14 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: if( p->trace ){ c287665ba8 2007-09-14 drh: printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: if( pthread_mutex_trylock(&p->mutex)==0 ){ c287665ba8 2007-09-14 drh: p->owner = pthread_self(); c287665ba8 2007-09-14 drh: p->nRef++; c287665ba8 2007-09-14 drh: rc = SQLITE_OK; c287665ba8 2007-09-14 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: if( p->trace ){ c287665ba8 2007-09-14 drh: printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: rc = SQLITE_BUSY; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_leave() routine exits a mutex that was c287665ba8 2007-09-14 drh: ** previously entered by the same thread. The behavior c287665ba8 2007-09-14 drh: ** is undefined if the mutex is not currently entered or c287665ba8 2007-09-14 drh: ** is not currently allocated. SQLite will never do either. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p) ); c287665ba8 2007-09-14 drh: p->nRef--; c287665ba8 2007-09-14 drh: assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); c287665ba8 2007-09-14 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: if( p->trace ){ c287665ba8 2007-09-14 drh: printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: pthread_mutex_unlock(&p->mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are c287665ba8 2007-09-14 drh: ** intended for use only inside assert() statements. On some platforms, c287665ba8 2007-09-14 drh: ** there might be race conditions that can cause these routines to c287665ba8 2007-09-14 drh: ** deliver incorrect results. In particular, if pthread_equal() is c287665ba8 2007-09-14 drh: ** not an atomic operation, then these routines might delivery c287665ba8 2007-09-14 drh: ** incorrect results. On most platforms, pthread_equal() is a c287665ba8 2007-09-14 drh: ** comparison of two integers and is therefore atomic. But we are c287665ba8 2007-09-14 drh: ** told that HPUX is not such a platform. If so, then these routines c287665ba8 2007-09-14 drh: ** will not always work correctly on HPUX. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** On those platforms where pthread_equal() is not atomic, SQLite c287665ba8 2007-09-14 drh: ** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to c287665ba8 2007-09-14 drh: ** make sure no assert() statements are evaluated and hence these c287665ba8 2007-09-14 drh: ** routines are never called. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef NDEBUG c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: return p==0 || (p->nRef!=0 && pthread_equal(p->owner, pthread_self())); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: return p==0 || p->nRef==0 || pthread_equal(p->owner, pthread_self())==0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: #endif /* SQLITE_MUTEX_PTHREAD */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of mutex_unix.c ******************************************/ c287665ba8 2007-09-14 drh: /************** Begin file mutex_w32.c ***************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 14 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** This file contains the C functions that implement mutexes for win32 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: mutex_w32.c,v 1.4 2007/09/05 14:30:42 drh Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The code in this file is only used if we are compiling multithreaded c287665ba8 2007-09-14 drh: ** on a win32 system. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_MUTEX_W32 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Each recursive mutex is an instance of the following structure. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: struct sqlite3_mutex { c287665ba8 2007-09-14 drh: CRITICAL_SECTION mutex; /* Mutex controlling the lock */ c287665ba8 2007-09-14 drh: int id; /* Mutex type */ c287665ba8 2007-09-14 drh: int nRef; /* Number of enterances */ c287665ba8 2007-09-14 drh: DWORD owner; /* Thread holding this mutex */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, c287665ba8 2007-09-14 drh: ** or WinCE. Return false (zero) for Win95, Win98, or WinME. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Here is an interesting observation: Win95, Win98, and WinME lack c287665ba8 2007-09-14 drh: ** the LockFileEx() API. But we can still statically link against that c287665ba8 2007-09-14 drh: ** API as long as we don't call it win running Win95/98/ME. A call to c287665ba8 2007-09-14 drh: ** this routine is used to determine if the host is Win95/98/ME or c287665ba8 2007-09-14 drh: ** WinNT/2K/XP so that we will know whether or not we can safely call c287665ba8 2007-09-14 drh: ** the LockFileEx() API. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #if OS_WINCE c287665ba8 2007-09-14 drh: # define mutexIsNT() (1) c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: static int mutexIsNT(void){ c287665ba8 2007-09-14 drh: static int osType = 0; c287665ba8 2007-09-14 drh: if( osType==0 ){ c287665ba8 2007-09-14 drh: OSVERSIONINFO sInfo; c287665ba8 2007-09-14 drh: sInfo.dwOSVersionInfoSize = sizeof(sInfo); c287665ba8 2007-09-14 drh: GetVersionEx(&sInfo); c287665ba8 2007-09-14 drh: osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return osType==2; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif /* OS_WINCE */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_alloc() routine allocates a new c287665ba8 2007-09-14 drh: ** mutex and returns a pointer to it. If it returns NULL c287665ba8 2007-09-14 drh: ** that means that a mutex could not be allocated. SQLite c287665ba8 2007-09-14 drh: ** will unwind its stack and return an error. The argument c287665ba8 2007-09-14 drh: ** to sqlite3_mutex_alloc() is one of these integer constants: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** <ul> c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_FAST 0 c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_RECURSIVE 1 c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_MASTER 2 c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_MEM 3 c287665ba8 2007-09-14 drh: ** <li> SQLITE_MUTEX_STATIC_PRNG 4 c287665ba8 2007-09-14 drh: ** </ul> c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The first two constants cause sqlite3_mutex_alloc() to create c287665ba8 2007-09-14 drh: ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE c287665ba8 2007-09-14 drh: ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. c287665ba8 2007-09-14 drh: ** The mutex implementation does not need to make a distinction c287665ba8 2007-09-14 drh: ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does c287665ba8 2007-09-14 drh: ** not want to. But SQLite will only request a recursive mutex in c287665ba8 2007-09-14 drh: ** cases where it really needs one. If a faster non-recursive mutex c287665ba8 2007-09-14 drh: ** implementation is available on the host platform, the mutex subsystem c287665ba8 2007-09-14 drh: ** might return such a mutex in response to SQLITE_MUTEX_FAST. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The other allowed parameters to sqlite3_mutex_alloc() each return c287665ba8 2007-09-14 drh: ** a pointer to a static preexisting mutex. Three static mutexes are c287665ba8 2007-09-14 drh: ** used by the current version of SQLite. Future versions of SQLite c287665ba8 2007-09-14 drh: ** may add additional static mutexes. Static mutexes are for internal c287665ba8 2007-09-14 drh: ** use by SQLite only. Applications that use SQLite mutexes should c287665ba8 2007-09-14 drh: ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or c287665ba8 2007-09-14 drh: ** SQLITE_MUTEX_RECURSIVE. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST c287665ba8 2007-09-14 drh: ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() c287665ba8 2007-09-14 drh: ** returns a different mutex on every call. But for the static c287665ba8 2007-09-14 drh: ** mutex types, the same mutex is returned on every call that has c287665ba8 2007-09-14 drh: ** the same type number. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int iType){ c287665ba8 2007-09-14 drh: sqlite3_mutex *p; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: switch( iType ){ c287665ba8 2007-09-14 drh: case SQLITE_MUTEX_FAST: c287665ba8 2007-09-14 drh: case SQLITE_MUTEX_RECURSIVE: { c287665ba8 2007-09-14 drh: p = sqlite3MallocZero( sizeof(*p) ); c287665ba8 2007-09-14 drh: if( p ){ c287665ba8 2007-09-14 drh: p->id = iType; c287665ba8 2007-09-14 drh: InitializeCriticalSection(&p->mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: default: { c287665ba8 2007-09-14 drh: static sqlite3_mutex staticMutexes[5]; c287665ba8 2007-09-14 drh: static int isInit = 0; c287665ba8 2007-09-14 drh: while( !isInit ){ c287665ba8 2007-09-14 drh: static long lock = 0; c287665ba8 2007-09-14 drh: if( InterlockedIncrement(&lock)==1 ){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: for(i=0; i<sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++){ c287665ba8 2007-09-14 drh: InitializeCriticalSection(&staticMutexes[i].mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: isInit = 1; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: Sleep(1); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert( iType-2 >= 0 ); c287665ba8 2007-09-14 drh: assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) ); c287665ba8 2007-09-14 drh: p = &staticMutexes[iType-2]; c287665ba8 2007-09-14 drh: p->id = iType; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine deallocates a previously c287665ba8 2007-09-14 drh: ** allocated mutex. SQLite is careful to deallocate every c287665ba8 2007-09-14 drh: ** mutex that it allocates. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->nRef==0 ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); c287665ba8 2007-09-14 drh: DeleteCriticalSection(&p->mutex); c287665ba8 2007-09-14 drh: sqlite3_free(p); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt c287665ba8 2007-09-14 drh: ** to enter a mutex. If another thread is already within the mutex, c287665ba8 2007-09-14 drh: ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return c287665ba8 2007-09-14 drh: ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK c287665ba8 2007-09-14 drh: ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can c287665ba8 2007-09-14 drh: ** be entered multiple times by the same thread. In such cases the, c287665ba8 2007-09-14 drh: ** mutex must be exited an equal number of times before another thread c287665ba8 2007-09-14 drh: ** can enter. If the same thread tries to enter any other kind of mutex c287665ba8 2007-09-14 drh: ** more than once, the behavior is undefined. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: EnterCriticalSection(&p->mutex); c287665ba8 2007-09-14 drh: p->owner = GetCurrentThreadId(); c287665ba8 2007-09-14 drh: p->nRef++; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: assert( p ); c287665ba8 2007-09-14 drh: assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); c287665ba8 2007-09-14 drh: if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){ c287665ba8 2007-09-14 drh: p->owner = GetCurrentThreadId(); c287665ba8 2007-09-14 drh: p->nRef++; c287665ba8 2007-09-14 drh: rc = SQLITE_OK; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: rc = SQLITE_BUSY; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_leave() routine exits a mutex that was c287665ba8 2007-09-14 drh: ** previously entered by the same thread. The behavior c287665ba8 2007-09-14 drh: ** is undefined if the mutex is not currently entered or c287665ba8 2007-09-14 drh: ** is not currently allocated. SQLite will never do either. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: assert( p->nRef>0 ); c287665ba8 2007-09-14 drh: assert( p->owner==GetCurrentThreadId() ); c287665ba8 2007-09-14 drh: p->nRef--; c287665ba8 2007-09-14 drh: assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); c287665ba8 2007-09-14 drh: LeaveCriticalSection(&p->mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are c287665ba8 2007-09-14 drh: ** intended for use only inside assert() statements. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: return p==0 || (p->nRef!=0 && p->owner==GetCurrentThreadId()); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ c287665ba8 2007-09-14 drh: return p==0 || p->nRef==0 || p->owner!=GetCurrentThreadId(); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif /* SQLITE_MUTEX_W32 */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of mutex_w32.c *******************************************/ c287665ba8 2007-09-14 drh: /************** Begin file malloc.c ******************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2001 September 15 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** Memory allocation functions used throughout sqlite. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: malloc.c,v 1.13 2007/08/29 14:06:23 danielk1977 Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine runs when the memory allocator sees that the c287665ba8 2007-09-14 drh: ** total memory allocation is about to exceed the soft heap c287665ba8 2007-09-14 drh: ** limit. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void softHeapLimitEnforcer( c287665ba8 2007-09-14 drh: void *NotUsed, c287665ba8 2007-09-14 drh: sqlite3_int64 inUse, c287665ba8 2007-09-14 drh: int allocSize c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: sqlite3_release_memory(allocSize); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Set the soft heap-size limit for the current thread. Passing a c287665ba8 2007-09-14 drh: ** zero or negative value indicates no limit. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_soft_heap_limit(int n){ c287665ba8 2007-09-14 drh: sqlite3_uint64 iLimit; c287665ba8 2007-09-14 drh: int overage; c287665ba8 2007-09-14 drh: if( n<0 ){ c287665ba8 2007-09-14 drh: iLimit = 0; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: iLimit = n; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( iLimit>0 ){ c287665ba8 2007-09-14 drh: sqlite3_memory_alarm(softHeapLimitEnforcer, 0, iLimit); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: sqlite3_memory_alarm(0, 0, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: overage = sqlite3_memory_used() - n; c287665ba8 2007-09-14 drh: if( overage>0 ){ c287665ba8 2007-09-14 drh: sqlite3_release_memory(overage); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Release memory held by SQLite instances created by the current thread. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_release_memory(int n){ c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: return sqlite3PagerReleaseMemory(n); c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Allocate and zero memory. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3MallocZero(unsigned n){ c287665ba8 2007-09-14 drh: void *p = sqlite3_malloc(n); dbda8d6ce9 2007-07-21 drh: if( p ){ c287665ba8 2007-09-14 drh: memset(p, 0, n); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Allocate and zero memory. If the allocation fails, make c287665ba8 2007-09-14 drh: ** the mallocFailed flag in the connection pointer. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, unsigned n){ c287665ba8 2007-09-14 drh: void *p = sqlite3DbMallocRaw(db, n); dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: memset(p, 0, n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Allocate and zero memory. If the allocation fails, make c287665ba8 2007-09-14 drh: ** the mallocFailed flag in the connection pointer. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, unsigned n){ c287665ba8 2007-09-14 drh: void *p = 0; c287665ba8 2007-09-14 drh: if( !db || db->mallocFailed==0 ){ c287665ba8 2007-09-14 drh: p = sqlite3_malloc(n); c287665ba8 2007-09-14 drh: if( !p && db ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Resize the block of memory pointed to by p to n bytes. If the c287665ba8 2007-09-14 drh: ** resize fails, set the mallocFailed flag inthe connection object. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ c287665ba8 2007-09-14 drh: void *pNew = 0; c287665ba8 2007-09-14 drh: if( db->mallocFailed==0 ){ c287665ba8 2007-09-14 drh: pNew = sqlite3_realloc(p, n); c287665ba8 2007-09-14 drh: if( !pNew ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return pNew; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Attempt to reallocate p. If the reallocation fails, then free p c287665ba8 2007-09-14 drh: ** and set the mallocFailed flag in the database connection. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){ dbda8d6ce9 2007-07-21 drh: void *pNew; c287665ba8 2007-09-14 drh: pNew = sqlite3DbRealloc(db, p, n); dbda8d6ce9 2007-07-21 drh: if( !pNew ){ c287665ba8 2007-09-14 drh: sqlite3_free(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make a copy of a string in memory obtained from sqliteMalloc(). These dbda8d6ce9 2007-07-21 drh: ** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This dbda8d6ce9 2007-07-21 drh: ** is because when memory debugging is turned on, these two functions are dbda8d6ce9 2007-07-21 drh: ** called via macros that record the current file and line number in the dbda8d6ce9 2007-07-21 drh: ** ThreadData structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char *sqlite3StrDup(const char *z){ dbda8d6ce9 2007-07-21 drh: char *zNew; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: if( z==0 ) return 0; dbda8d6ce9 2007-07-21 drh: n = strlen(z)+1; c287665ba8 2007-09-14 drh: zNew = sqlite3_malloc(n); dbda8d6ce9 2007-07-21 drh: if( zNew ) memcpy(zNew, z, n); dbda8d6ce9 2007-07-21 drh: return zNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char *sqlite3StrNDup(const char *z, int n){ dbda8d6ce9 2007-07-21 drh: char *zNew; dbda8d6ce9 2007-07-21 drh: if( z==0 ) return 0; c287665ba8 2007-09-14 drh: zNew = sqlite3_malloc(n+1); dbda8d6ce9 2007-07-21 drh: if( zNew ){ dbda8d6ce9 2007-07-21 drh: memcpy(zNew, z, n); dbda8d6ce9 2007-07-21 drh: zNew[n] = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return zNew; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){ c287665ba8 2007-09-14 drh: char *zNew = sqlite3StrDup(z); c287665ba8 2007-09-14 drh: if( z && !zNew ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return zNew; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){ c287665ba8 2007-09-14 drh: char *zNew = sqlite3StrNDup(z, n); c287665ba8 2007-09-14 drh: if( z && !zNew ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a string from the 2nd and subsequent arguments (up to the dbda8d6ce9 2007-07-21 drh: ** first NULL argument), store the string in memory obtained from dbda8d6ce9 2007-07-21 drh: ** sqliteMalloc() and make the pointer indicated by the 1st argument dbda8d6ce9 2007-07-21 drh: ** point to that string. The 1st argument must either be NULL or dbda8d6ce9 2007-07-21 drh: ** point to memory obtained from sqliteMalloc(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SetString(char **pz, ...){ dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: int nByte; dbda8d6ce9 2007-07-21 drh: const char *z; dbda8d6ce9 2007-07-21 drh: char *zResult; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pz!=0 ); dbda8d6ce9 2007-07-21 drh: nByte = 1; dbda8d6ce9 2007-07-21 drh: va_start(ap, pz); dbda8d6ce9 2007-07-21 drh: while( (z = va_arg(ap, const char*))!=0 ){ dbda8d6ce9 2007-07-21 drh: nByte += strlen(z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: va_end(ap); c287665ba8 2007-09-14 drh: sqlite3_free(*pz); c287665ba8 2007-09-14 drh: *pz = zResult = sqlite3_malloc(nByte); dbda8d6ce9 2007-07-21 drh: if( zResult==0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *zResult = 0; dbda8d6ce9 2007-07-21 drh: va_start(ap, pz); dbda8d6ce9 2007-07-21 drh: while( (z = va_arg(ap, const char*))!=0 ){ dbda8d6ce9 2007-07-21 drh: int n = strlen(z); dbda8d6ce9 2007-07-21 drh: memcpy(zResult, z, n); dbda8d6ce9 2007-07-21 drh: zResult += n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zResult[0] = 0; dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function must be called before exiting any API function (i.e. c287665ba8 2007-09-14 drh: ** returning control to the user) that has called sqlite3_malloc or c287665ba8 2007-09-14 drh: ** sqlite3_realloc. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The returned value is normally a copy of the second argument to this dbda8d6ce9 2007-07-21 drh: ** function. However, if a malloc() failure has occured since the previous dbda8d6ce9 2007-07-21 drh: ** invocation SQLITE_NOMEM is returned instead. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the first argument, db, is not NULL and a malloc() error has occured, dbda8d6ce9 2007-07-21 drh: ** then the connection error-code (the value returned by sqlite3_errcode()) dbda8d6ce9 2007-07-21 drh: ** is set to SQLITE_NOMEM. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ c287665ba8 2007-09-14 drh: /* If the db handle is not NULL, then we must hold the connection handle c287665ba8 2007-09-14 drh: ** mutex here. Otherwise the read (and possible write) of db->mallocFailed c287665ba8 2007-09-14 drh: ** is unsafe, as is the call to sqlite3Error(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert( !db || sqlite3_mutex_held(db->mutex) ); c287665ba8 2007-09-14 drh: if( db && db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_NOMEM, 0); c287665ba8 2007-09-14 drh: db->mallocFailed = 0; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc & (db ? db->errMask : 0xff); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of malloc.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file printf.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The "printf" code that follows dates from the 1980's. It is in dbda8d6ce9 2007-07-21 drh: ** the public domain. The original comments are included here for dbda8d6ce9 2007-07-21 drh: ** completeness. They are very out-of-date but might be useful as dbda8d6ce9 2007-07-21 drh: ** an historical reference. Most of the "enhancements" have been backed dbda8d6ce9 2007-07-21 drh: ** out so that the functionality is now the same as standard printf(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following modules is an enhanced replacement for the "printf" subroutines dbda8d6ce9 2007-07-21 drh: ** found in the standard C library. The following enhancements are dbda8d6ce9 2007-07-21 drh: ** supported: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** + Additional functions. The standard set of "printf" functions dbda8d6ce9 2007-07-21 drh: ** includes printf, fprintf, sprintf, vprintf, vfprintf, and dbda8d6ce9 2007-07-21 drh: ** vsprintf. This module adds the following: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * snprintf -- Works like sprintf, but has an extra argument dbda8d6ce9 2007-07-21 drh: ** which is the size of the buffer written to. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * mprintf -- Similar to sprintf. Writes output to memory dbda8d6ce9 2007-07-21 drh: ** obtained from malloc. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * xprintf -- Calls a function to dispose of output. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * nprintf -- No output, but returns the number of characters dbda8d6ce9 2007-07-21 drh: ** that would have been output by printf. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * A v- version (ex: vsnprintf) of every function is also dbda8d6ce9 2007-07-21 drh: ** supplied. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** + A few extensions to the formatting notation are supported: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * The "=" flag (similar to "-") causes the output to be dbda8d6ce9 2007-07-21 drh: ** be centered in the appropriately sized field. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * The %b field outputs an integer in binary notation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * The %c field now accepts a precision. The character output dbda8d6ce9 2007-07-21 drh: ** is repeated by the number of times the precision specifies. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * The %' field works like %c, but takes as its character the dbda8d6ce9 2007-07-21 drh: ** next character of the format string, instead of the next dbda8d6ce9 2007-07-21 drh: ** argument. For example, printf("%.78'-") prints 78 minus dbda8d6ce9 2007-07-21 drh: ** signs, the same as printf("%.78c",'-'). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** + When compiled using GCC on a SPARC, this version of printf is dbda8d6ce9 2007-07-21 drh: ** faster than the library printf for SUN OS 4.1. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** + All functions are fully reentrant. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #include <math.h> dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Conversion types fall into various categories as defined by the dbda8d6ce9 2007-07-21 drh: ** following enumeration. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */ dbda8d6ce9 2007-07-21 drh: #define etFLOAT 2 /* Floating point. %f */ dbda8d6ce9 2007-07-21 drh: #define etEXP 3 /* Exponentional notation. %e and %E */ dbda8d6ce9 2007-07-21 drh: #define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */ dbda8d6ce9 2007-07-21 drh: #define etSIZE 5 /* Return number of characters processed so far. %n */ dbda8d6ce9 2007-07-21 drh: #define etSTRING 6 /* Strings. %s */ dbda8d6ce9 2007-07-21 drh: #define etDYNSTRING 7 /* Dynamically allocated strings. %z */ dbda8d6ce9 2007-07-21 drh: #define etPERCENT 8 /* Percent symbol. %% */ dbda8d6ce9 2007-07-21 drh: #define etCHARX 9 /* Characters. %c */ dbda8d6ce9 2007-07-21 drh: /* The rest are extensions, not normally found in printf() */ dbda8d6ce9 2007-07-21 drh: #define etCHARLIT 10 /* Literal characters. %' */ dbda8d6ce9 2007-07-21 drh: #define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */ dbda8d6ce9 2007-07-21 drh: #define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '', dbda8d6ce9 2007-07-21 drh: NULL pointers replaced by SQL NULL. %Q */ dbda8d6ce9 2007-07-21 drh: #define etTOKEN 13 /* a pointer to a Token structure */ dbda8d6ce9 2007-07-21 drh: #define etSRCLIST 14 /* a pointer to a SrcList */ dbda8d6ce9 2007-07-21 drh: #define etPOINTER 15 /* The %p conversion */ dbda8d6ce9 2007-07-21 drh: #define etSQLESCAPE3 16 /* %w -> Strings with '\"' doubled */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An "etByte" is an 8-bit unsigned value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef unsigned char etByte; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each builtin conversion character (ex: the 'd' in "%d") is described dbda8d6ce9 2007-07-21 drh: ** by an instance of the following structure dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct et_info { /* Information about each format field */ dbda8d6ce9 2007-07-21 drh: char fmttype; /* The format field code letter */ dbda8d6ce9 2007-07-21 drh: etByte base; /* The base for radix conversion */ dbda8d6ce9 2007-07-21 drh: etByte flags; /* One or more of FLAG_ constants below */ dbda8d6ce9 2007-07-21 drh: etByte type; /* Conversion paradigm */ dbda8d6ce9 2007-07-21 drh: etByte charset; /* Offset into aDigits[] of the digits string */ dbda8d6ce9 2007-07-21 drh: etByte prefix; /* Offset into aPrefix[] of the prefix string */ dbda8d6ce9 2007-07-21 drh: } et_info; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allowed values for et_info.flags dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define FLAG_SIGNED 1 /* True if the value to convert is signed */ dbda8d6ce9 2007-07-21 drh: #define FLAG_INTERN 2 /* True if for internal use only */ dbda8d6ce9 2007-07-21 drh: #define FLAG_STRING 4 /* Allow infinity precision */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following table is searched linearly, so it is good to put the dbda8d6ce9 2007-07-21 drh: ** most frequently used conversion types first. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; dbda8d6ce9 2007-07-21 drh: static const char aPrefix[] = "-x0\000X0"; dbda8d6ce9 2007-07-21 drh: static const et_info fmtinfo[] = { dbda8d6ce9 2007-07-21 drh: { 'd', 10, 1, etRADIX, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 's', 0, 4, etSTRING, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'g', 0, 1, etGENERIC, 30, 0 }, c287665ba8 2007-09-14 drh: { 'z', 0, 4, etDYNSTRING, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'q', 0, 4, etSQLESCAPE, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'c', 0, 0, etCHARX, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'o', 8, 0, etRADIX, 0, 2 }, dbda8d6ce9 2007-07-21 drh: { 'u', 10, 0, etRADIX, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'x', 16, 0, etRADIX, 16, 1 }, dbda8d6ce9 2007-07-21 drh: { 'X', 16, 0, etRADIX, 0, 4 }, dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: { 'f', 0, 1, etFLOAT, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'e', 0, 1, etEXP, 30, 0 }, dbda8d6ce9 2007-07-21 drh: { 'E', 0, 1, etEXP, 14, 0 }, dbda8d6ce9 2007-07-21 drh: { 'G', 0, 1, etGENERIC, 14, 0 }, dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: { 'i', 10, 1, etRADIX, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'n', 0, 0, etSIZE, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { '%', 0, 0, etPERCENT, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'p', 16, 0, etPOINTER, 0, 1 }, dbda8d6ce9 2007-07-21 drh: { 'T', 0, 2, etTOKEN, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { 'S', 0, 2, etSRCLIST, 0, 0 }, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0])) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point dbda8d6ce9 2007-07-21 drh: ** conversions will work. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** "*val" is a double such that 0.1 <= *val < 10.0 dbda8d6ce9 2007-07-21 drh: ** Return the ascii code for the leading digit of *val, then dbda8d6ce9 2007-07-21 drh: ** multiply "*val" by 10.0 to renormalize. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Example: dbda8d6ce9 2007-07-21 drh: ** input: *val = 3.14159 dbda8d6ce9 2007-07-21 drh: ** output: *val = 1.4159 function return = '3' dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The counter *cnt is incremented each time. After counter exceeds dbda8d6ce9 2007-07-21 drh: ** 16 (the number of significant digits in a 64-bit float) '0' is dbda8d6ce9 2007-07-21 drh: ** always returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ dbda8d6ce9 2007-07-21 drh: int digit; dbda8d6ce9 2007-07-21 drh: LONGDOUBLE_TYPE d; dbda8d6ce9 2007-07-21 drh: if( (*cnt)++ >= 16 ) return '0'; dbda8d6ce9 2007-07-21 drh: digit = (int)*val; dbda8d6ce9 2007-07-21 drh: d = digit; dbda8d6ce9 2007-07-21 drh: digit += '0'; dbda8d6ce9 2007-07-21 drh: *val = (*val - d)*10.0; dbda8d6ce9 2007-07-21 drh: return digit; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_FLOATING_POINT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** On machines with a small stack size, you can redefine the dbda8d6ce9 2007-07-21 drh: ** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for dbda8d6ce9 2007-07-21 drh: ** smaller values some %f conversions may go into an infinite loop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_PRINT_BUF_SIZE dbda8d6ce9 2007-07-21 drh: # define SQLITE_PRINT_BUF_SIZE 350 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The root program. All variations call this core. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** INPUTS: dbda8d6ce9 2007-07-21 drh: ** func This is a pointer to a function taking three arguments dbda8d6ce9 2007-07-21 drh: ** 1. A pointer to anything. Same as the "arg" parameter. dbda8d6ce9 2007-07-21 drh: ** 2. A pointer to the list of characters to be output dbda8d6ce9 2007-07-21 drh: ** (Note, this list is NOT null terminated.) dbda8d6ce9 2007-07-21 drh: ** 3. An integer number of characters to be output. dbda8d6ce9 2007-07-21 drh: ** (Note: This number might be zero.) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** arg This is the pointer to anything which will be passed as the dbda8d6ce9 2007-07-21 drh: ** first argument to "func". Use it for whatever you like. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** fmt This is the format string, as in the usual print. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ap This is a pointer to a list of arguments. Same as in dbda8d6ce9 2007-07-21 drh: ** vfprint. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** OUTPUTS: dbda8d6ce9 2007-07-21 drh: ** The return value is the total number of characters sent to dbda8d6ce9 2007-07-21 drh: ** the function "func". Returns -1 on a error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that the order in which automatic variables are declared below dbda8d6ce9 2007-07-21 drh: ** seems to make a big difference in determining how fast this beast dbda8d6ce9 2007-07-21 drh: ** will run. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int vxprintf( dbda8d6ce9 2007-07-21 drh: void (*func)(void*,const char*,int), /* Consumer of text */ dbda8d6ce9 2007-07-21 drh: void *arg, /* First argument to the consumer */ dbda8d6ce9 2007-07-21 drh: int useExtended, /* Allow extended %-conversions */ dbda8d6ce9 2007-07-21 drh: const char *fmt, /* Format string */ dbda8d6ce9 2007-07-21 drh: va_list ap /* arguments */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int c; /* Next character in the format string */ dbda8d6ce9 2007-07-21 drh: char *bufpt; /* Pointer to the conversion buffer */ dbda8d6ce9 2007-07-21 drh: int precision; /* Precision of the current field */ dbda8d6ce9 2007-07-21 drh: int length; /* Length of the field */ dbda8d6ce9 2007-07-21 drh: int idx; /* A general purpose loop counter */ dbda8d6ce9 2007-07-21 drh: int count; /* Total number of characters output */ dbda8d6ce9 2007-07-21 drh: int width; /* Width of the current field */ dbda8d6ce9 2007-07-21 drh: etByte flag_leftjustify; /* True if "-" flag is present */ dbda8d6ce9 2007-07-21 drh: etByte flag_plussign; /* True if "+" flag is present */ dbda8d6ce9 2007-07-21 drh: etByte flag_blanksign; /* True if " " flag is present */ dbda8d6ce9 2007-07-21 drh: etByte flag_alternateform; /* True if "#" flag is present */ dbda8d6ce9 2007-07-21 drh: etByte flag_altform2; /* True if "!" flag is present */ dbda8d6ce9 2007-07-21 drh: etByte flag_zeropad; /* True if field width constant starts with zero */ dbda8d6ce9 2007-07-21 drh: etByte flag_long; /* True if "l" flag is present */ dbda8d6ce9 2007-07-21 drh: etByte flag_longlong; /* True if the "ll" flag is present */ dbda8d6ce9 2007-07-21 drh: etByte done; /* Loop termination flag */ dbda8d6ce9 2007-07-21 drh: sqlite_uint64 longvalue; /* Value for integer types */ dbda8d6ce9 2007-07-21 drh: LONGDOUBLE_TYPE realvalue; /* Value for real types */ dbda8d6ce9 2007-07-21 drh: const et_info *infop; /* Pointer to the appropriate info structure */ dbda8d6ce9 2007-07-21 drh: char buf[etBUFSIZE]; /* Conversion buffer */ dbda8d6ce9 2007-07-21 drh: char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ dbda8d6ce9 2007-07-21 drh: etByte errorflag = 0; /* True if an error is encountered */ dbda8d6ce9 2007-07-21 drh: etByte xtype; /* Conversion paradigm */ dbda8d6ce9 2007-07-21 drh: char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ dbda8d6ce9 2007-07-21 drh: static const char spaces[] = dbda8d6ce9 2007-07-21 drh: " "; dbda8d6ce9 2007-07-21 drh: #define etSPACESIZE (sizeof(spaces)-1) dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: int exp, e2; /* exponent of real numbers */ dbda8d6ce9 2007-07-21 drh: double rounder; /* Used for rounding floating point values */ dbda8d6ce9 2007-07-21 drh: etByte flag_dp; /* True if decimal point should be shown */ dbda8d6ce9 2007-07-21 drh: etByte flag_rtz; /* True if trailing zeros should be removed */ dbda8d6ce9 2007-07-21 drh: etByte flag_exp; /* True to force display of the exponent */ dbda8d6ce9 2007-07-21 drh: int nsd; /* Number of significant digits returned */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: func(arg,"",0); dbda8d6ce9 2007-07-21 drh: count = length = 0; dbda8d6ce9 2007-07-21 drh: bufpt = 0; dbda8d6ce9 2007-07-21 drh: for(; (c=(*fmt))!=0; ++fmt){ dbda8d6ce9 2007-07-21 drh: if( c!='%' ){ dbda8d6ce9 2007-07-21 drh: int amt; dbda8d6ce9 2007-07-21 drh: bufpt = (char *)fmt; dbda8d6ce9 2007-07-21 drh: amt = 1; dbda8d6ce9 2007-07-21 drh: while( (c=(*++fmt))!='%' && c!=0 ) amt++; dbda8d6ce9 2007-07-21 drh: (*func)(arg,bufpt,amt); dbda8d6ce9 2007-07-21 drh: count += amt; dbda8d6ce9 2007-07-21 drh: if( c==0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (c=(*++fmt))==0 ){ dbda8d6ce9 2007-07-21 drh: errorflag = 1; dbda8d6ce9 2007-07-21 drh: (*func)(arg,"%",1); dbda8d6ce9 2007-07-21 drh: count++; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Find out what flags are present */ dbda8d6ce9 2007-07-21 drh: flag_leftjustify = flag_plussign = flag_blanksign = dbda8d6ce9 2007-07-21 drh: flag_alternateform = flag_altform2 = flag_zeropad = 0; dbda8d6ce9 2007-07-21 drh: done = 0; dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: switch( c ){ dbda8d6ce9 2007-07-21 drh: case '-': flag_leftjustify = 1; break; dbda8d6ce9 2007-07-21 drh: case '+': flag_plussign = 1; break; dbda8d6ce9 2007-07-21 drh: case ' ': flag_blanksign = 1; break; dbda8d6ce9 2007-07-21 drh: case '#': flag_alternateform = 1; break; dbda8d6ce9 2007-07-21 drh: case '!': flag_altform2 = 1; break; dbda8d6ce9 2007-07-21 drh: case '0': flag_zeropad = 1; break; dbda8d6ce9 2007-07-21 drh: default: done = 1; break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }while( !done && (c=(*++fmt))!=0 ); dbda8d6ce9 2007-07-21 drh: /* Get the field width */ dbda8d6ce9 2007-07-21 drh: width = 0; dbda8d6ce9 2007-07-21 drh: if( c=='*' ){ dbda8d6ce9 2007-07-21 drh: width = va_arg(ap,int); dbda8d6ce9 2007-07-21 drh: if( width<0 ){ dbda8d6ce9 2007-07-21 drh: flag_leftjustify = 1; dbda8d6ce9 2007-07-21 drh: width = -width; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c = *++fmt; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: while( c>='0' && c<='9' ){ dbda8d6ce9 2007-07-21 drh: width = width*10 + c - '0'; dbda8d6ce9 2007-07-21 drh: c = *++fmt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( width > etBUFSIZE-10 ){ dbda8d6ce9 2007-07-21 drh: width = etBUFSIZE-10; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Get the precision */ dbda8d6ce9 2007-07-21 drh: if( c=='.' ){ dbda8d6ce9 2007-07-21 drh: precision = 0; dbda8d6ce9 2007-07-21 drh: c = *++fmt; dbda8d6ce9 2007-07-21 drh: if( c=='*' ){ dbda8d6ce9 2007-07-21 drh: precision = va_arg(ap,int); dbda8d6ce9 2007-07-21 drh: if( precision<0 ) precision = -precision; dbda8d6ce9 2007-07-21 drh: c = *++fmt; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: while( c>='0' && c<='9' ){ dbda8d6ce9 2007-07-21 drh: precision = precision*10 + c - '0'; dbda8d6ce9 2007-07-21 drh: c = *++fmt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: precision = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Get the conversion type modifier */ dbda8d6ce9 2007-07-21 drh: if( c=='l' ){ dbda8d6ce9 2007-07-21 drh: flag_long = 1; dbda8d6ce9 2007-07-21 drh: c = *++fmt; dbda8d6ce9 2007-07-21 drh: if( c=='l' ){ dbda8d6ce9 2007-07-21 drh: flag_longlong = 1; dbda8d6ce9 2007-07-21 drh: c = *++fmt; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: flag_longlong = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: flag_long = flag_longlong = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Fetch the info entry for the field */ dbda8d6ce9 2007-07-21 drh: infop = 0; dbda8d6ce9 2007-07-21 drh: for(idx=0; idx<etNINFO; idx++){ dbda8d6ce9 2007-07-21 drh: if( c==fmtinfo[idx].fmttype ){ dbda8d6ce9 2007-07-21 drh: infop = &fmtinfo[idx]; dbda8d6ce9 2007-07-21 drh: if( useExtended || (infop->flags & FLAG_INTERN)==0 ){ dbda8d6ce9 2007-07-21 drh: xtype = infop->type; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zExtra = 0; dbda8d6ce9 2007-07-21 drh: if( infop==0 ){ dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Limit the precision to prevent overflowing buf[] during conversion */ dbda8d6ce9 2007-07-21 drh: if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){ dbda8d6ce9 2007-07-21 drh: precision = etBUFSIZE-40; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** At this point, variables are initialized as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** flag_alternateform TRUE if a '#' is present. dbda8d6ce9 2007-07-21 drh: ** flag_altform2 TRUE if a '!' is present. dbda8d6ce9 2007-07-21 drh: ** flag_plussign TRUE if a '+' is present. dbda8d6ce9 2007-07-21 drh: ** flag_leftjustify TRUE if a '-' is present or if the dbda8d6ce9 2007-07-21 drh: ** field width was negative. dbda8d6ce9 2007-07-21 drh: ** flag_zeropad TRUE if the width began with 0. dbda8d6ce9 2007-07-21 drh: ** flag_long TRUE if the letter 'l' (ell) prefixed dbda8d6ce9 2007-07-21 drh: ** the conversion character. dbda8d6ce9 2007-07-21 drh: ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed dbda8d6ce9 2007-07-21 drh: ** the conversion character. dbda8d6ce9 2007-07-21 drh: ** flag_blanksign TRUE if a ' ' is present. dbda8d6ce9 2007-07-21 drh: ** width The specified field width. This is dbda8d6ce9 2007-07-21 drh: ** always non-negative. Zero is the default. dbda8d6ce9 2007-07-21 drh: ** precision The specified precision. The default dbda8d6ce9 2007-07-21 drh: ** is -1. dbda8d6ce9 2007-07-21 drh: ** xtype The class of the conversion. dbda8d6ce9 2007-07-21 drh: ** infop Pointer to the appropriate info struct. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: switch( xtype ){ dbda8d6ce9 2007-07-21 drh: case etPOINTER: dbda8d6ce9 2007-07-21 drh: flag_longlong = sizeof(char*)==sizeof(i64); dbda8d6ce9 2007-07-21 drh: flag_long = sizeof(char*)==sizeof(long int); dbda8d6ce9 2007-07-21 drh: /* Fall through into the next case */ dbda8d6ce9 2007-07-21 drh: case etRADIX: dbda8d6ce9 2007-07-21 drh: if( infop->flags & FLAG_SIGNED ){ dbda8d6ce9 2007-07-21 drh: i64 v; dbda8d6ce9 2007-07-21 drh: if( flag_longlong ) v = va_arg(ap,i64); dbda8d6ce9 2007-07-21 drh: else if( flag_long ) v = va_arg(ap,long int); dbda8d6ce9 2007-07-21 drh: else v = va_arg(ap,int); dbda8d6ce9 2007-07-21 drh: if( v<0 ){ dbda8d6ce9 2007-07-21 drh: longvalue = -v; dbda8d6ce9 2007-07-21 drh: prefix = '-'; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: longvalue = v; dbda8d6ce9 2007-07-21 drh: if( flag_plussign ) prefix = '+'; dbda8d6ce9 2007-07-21 drh: else if( flag_blanksign ) prefix = ' '; dbda8d6ce9 2007-07-21 drh: else prefix = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( flag_longlong ) longvalue = va_arg(ap,u64); dbda8d6ce9 2007-07-21 drh: else if( flag_long ) longvalue = va_arg(ap,unsigned long int); dbda8d6ce9 2007-07-21 drh: else longvalue = va_arg(ap,unsigned int); dbda8d6ce9 2007-07-21 drh: prefix = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( longvalue==0 ) flag_alternateform = 0; dbda8d6ce9 2007-07-21 drh: if( flag_zeropad && precision<width-(prefix!=0) ){ dbda8d6ce9 2007-07-21 drh: precision = width-(prefix!=0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: bufpt = &buf[etBUFSIZE-1]; dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: register const char *cset; /* Use registers for speed */ dbda8d6ce9 2007-07-21 drh: register int base; dbda8d6ce9 2007-07-21 drh: cset = &aDigits[infop->charset]; dbda8d6ce9 2007-07-21 drh: base = infop->base; dbda8d6ce9 2007-07-21 drh: do{ /* Convert to ascii */ dbda8d6ce9 2007-07-21 drh: *(--bufpt) = cset[longvalue%base]; dbda8d6ce9 2007-07-21 drh: longvalue = longvalue/base; dbda8d6ce9 2007-07-21 drh: }while( longvalue>0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: length = &buf[etBUFSIZE-1]-bufpt; dbda8d6ce9 2007-07-21 drh: for(idx=precision-length; idx>0; idx--){ dbda8d6ce9 2007-07-21 drh: *(--bufpt) = '0'; /* Zero pad */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( prefix ) *(--bufpt) = prefix; /* Add sign */ dbda8d6ce9 2007-07-21 drh: if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ dbda8d6ce9 2007-07-21 drh: const char *pre; dbda8d6ce9 2007-07-21 drh: char x; dbda8d6ce9 2007-07-21 drh: pre = &aPrefix[infop->prefix]; dbda8d6ce9 2007-07-21 drh: if( *bufpt!=pre[0] ){ dbda8d6ce9 2007-07-21 drh: for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: length = &buf[etBUFSIZE-1]-bufpt; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case etFLOAT: dbda8d6ce9 2007-07-21 drh: case etEXP: dbda8d6ce9 2007-07-21 drh: case etGENERIC: dbda8d6ce9 2007-07-21 drh: realvalue = va_arg(ap,double); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: if( precision<0 ) precision = 6; /* Set default precision */ dbda8d6ce9 2007-07-21 drh: if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10; dbda8d6ce9 2007-07-21 drh: if( realvalue<0.0 ){ dbda8d6ce9 2007-07-21 drh: realvalue = -realvalue; dbda8d6ce9 2007-07-21 drh: prefix = '-'; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( flag_plussign ) prefix = '+'; dbda8d6ce9 2007-07-21 drh: else if( flag_blanksign ) prefix = ' '; dbda8d6ce9 2007-07-21 drh: else prefix = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( xtype==etGENERIC && precision>0 ) precision--; dbda8d6ce9 2007-07-21 drh: #if 0 dbda8d6ce9 2007-07-21 drh: /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ dbda8d6ce9 2007-07-21 drh: for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: /* It makes more sense to use 0.5 */ dbda8d6ce9 2007-07-21 drh: for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){} dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( xtype==etFLOAT ) realvalue += rounder; dbda8d6ce9 2007-07-21 drh: /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ dbda8d6ce9 2007-07-21 drh: exp = 0; dbda8d6ce9 2007-07-21 drh: if( sqlite3_isnan(realvalue) ){ dbda8d6ce9 2007-07-21 drh: bufpt = "NaN"; dbda8d6ce9 2007-07-21 drh: length = 3; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( realvalue>0.0 ){ dbda8d6ce9 2007-07-21 drh: while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; } dbda8d6ce9 2007-07-21 drh: while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } dbda8d6ce9 2007-07-21 drh: while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } dbda8d6ce9 2007-07-21 drh: while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; } dbda8d6ce9 2007-07-21 drh: while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; } dbda8d6ce9 2007-07-21 drh: if( exp>350 || exp<-350 ){ dbda8d6ce9 2007-07-21 drh: if( prefix=='-' ){ dbda8d6ce9 2007-07-21 drh: bufpt = "-Inf"; dbda8d6ce9 2007-07-21 drh: }else if( prefix=='+' ){ dbda8d6ce9 2007-07-21 drh: bufpt = "+Inf"; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: bufpt = "Inf"; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: length = strlen(bufpt); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: bufpt = buf; dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the field type is etGENERIC, then convert to either etEXP dbda8d6ce9 2007-07-21 drh: ** or etFLOAT, as appropriate. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: flag_exp = xtype==etEXP; dbda8d6ce9 2007-07-21 drh: if( xtype!=etFLOAT ){ dbda8d6ce9 2007-07-21 drh: realvalue += rounder; dbda8d6ce9 2007-07-21 drh: if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( xtype==etGENERIC ){ dbda8d6ce9 2007-07-21 drh: flag_rtz = !flag_alternateform; dbda8d6ce9 2007-07-21 drh: if( exp<-4 || exp>precision ){ dbda8d6ce9 2007-07-21 drh: xtype = etEXP; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: precision = precision - exp; dbda8d6ce9 2007-07-21 drh: xtype = etFLOAT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: flag_rtz = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( xtype==etEXP ){ dbda8d6ce9 2007-07-21 drh: e2 = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: e2 = exp; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nsd = 0; dbda8d6ce9 2007-07-21 drh: flag_dp = (precision>0) | flag_alternateform | flag_altform2; dbda8d6ce9 2007-07-21 drh: /* The sign in front of the number */ dbda8d6ce9 2007-07-21 drh: if( prefix ){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = prefix; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Digits prior to the decimal point */ dbda8d6ce9 2007-07-21 drh: if( e2<0 ){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = '0'; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(; e2>=0; e2--){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = et_getdigit(&realvalue,&nsd); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* The decimal point */ dbda8d6ce9 2007-07-21 drh: if( flag_dp ){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = '.'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* "0" digits after the decimal point but before the first dbda8d6ce9 2007-07-21 drh: ** significant digit of the number */ dbda8d6ce9 2007-07-21 drh: for(e2++; e2<0 && precision>0; precision--, e2++){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = '0'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Significant digits after the decimal point */ dbda8d6ce9 2007-07-21 drh: while( (precision--)>0 ){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = et_getdigit(&realvalue,&nsd); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Remove trailing zeros and the "." if no digits follow the "." */ dbda8d6ce9 2007-07-21 drh: if( flag_rtz && flag_dp ){ dbda8d6ce9 2007-07-21 drh: while( bufpt[-1]=='0' ) *(--bufpt) = 0; dbda8d6ce9 2007-07-21 drh: assert( bufpt>buf ); dbda8d6ce9 2007-07-21 drh: if( bufpt[-1]=='.' ){ dbda8d6ce9 2007-07-21 drh: if( flag_altform2 ){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = '0'; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *(--bufpt) = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Add the "eNNN" suffix */ dbda8d6ce9 2007-07-21 drh: if( flag_exp || (xtype==etEXP && exp) ){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = aDigits[infop->charset]; dbda8d6ce9 2007-07-21 drh: if( exp<0 ){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = '-'; exp = -exp; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = '+'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( exp>=100 ){ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = (exp/100)+'0'; /* 100's digit */ dbda8d6ce9 2007-07-21 drh: exp %= 100; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *(bufpt++) = exp/10+'0'; /* 10's digit */ dbda8d6ce9 2007-07-21 drh: *(bufpt++) = exp%10+'0'; /* 1's digit */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *bufpt = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The converted number is in buf[] and zero terminated. Output it. dbda8d6ce9 2007-07-21 drh: ** Note that the number is in the usual order, not reversed as with dbda8d6ce9 2007-07-21 drh: ** integer conversions. */ dbda8d6ce9 2007-07-21 drh: length = bufpt-buf; dbda8d6ce9 2007-07-21 drh: bufpt = buf; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Special case: Add leading zeros if the flag_zeropad flag is dbda8d6ce9 2007-07-21 drh: ** set and we are not left justified */ dbda8d6ce9 2007-07-21 drh: if( flag_zeropad && !flag_leftjustify && length < width){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nPad = width - length; dbda8d6ce9 2007-07-21 drh: for(i=width; i>=nPad; i--){ dbda8d6ce9 2007-07-21 drh: bufpt[i] = bufpt[i-nPad]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i = prefix!=0; dbda8d6ce9 2007-07-21 drh: while( nPad-- ) bufpt[i++] = '0'; dbda8d6ce9 2007-07-21 drh: length = width; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case etSIZE: dbda8d6ce9 2007-07-21 drh: *(va_arg(ap,int*)) = count; dbda8d6ce9 2007-07-21 drh: length = width = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case etPERCENT: dbda8d6ce9 2007-07-21 drh: buf[0] = '%'; dbda8d6ce9 2007-07-21 drh: bufpt = buf; dbda8d6ce9 2007-07-21 drh: length = 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case etCHARLIT: dbda8d6ce9 2007-07-21 drh: case etCHARX: dbda8d6ce9 2007-07-21 drh: c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt); dbda8d6ce9 2007-07-21 drh: if( precision>=0 ){ dbda8d6ce9 2007-07-21 drh: for(idx=1; idx<precision; idx++) buf[idx] = c; dbda8d6ce9 2007-07-21 drh: length = precision; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: length =1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: bufpt = buf; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case etSTRING: dbda8d6ce9 2007-07-21 drh: case etDYNSTRING: dbda8d6ce9 2007-07-21 drh: bufpt = va_arg(ap,char*); dbda8d6ce9 2007-07-21 drh: if( bufpt==0 ){ dbda8d6ce9 2007-07-21 drh: bufpt = ""; dbda8d6ce9 2007-07-21 drh: }else if( xtype==etDYNSTRING ){ dbda8d6ce9 2007-07-21 drh: zExtra = bufpt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: length = strlen(bufpt); dbda8d6ce9 2007-07-21 drh: if( precision>=0 && precision<length ) length = precision; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case etSQLESCAPE: dbda8d6ce9 2007-07-21 drh: case etSQLESCAPE2: dbda8d6ce9 2007-07-21 drh: case etSQLESCAPE3: { dbda8d6ce9 2007-07-21 drh: int i, j, n, ch, isnull; dbda8d6ce9 2007-07-21 drh: int needQuote; dbda8d6ce9 2007-07-21 drh: char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ dbda8d6ce9 2007-07-21 drh: char *escarg = va_arg(ap,char*); dbda8d6ce9 2007-07-21 drh: isnull = escarg==0; dbda8d6ce9 2007-07-21 drh: if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); dbda8d6ce9 2007-07-21 drh: for(i=n=0; (ch=escarg[i])!=0; i++){ dbda8d6ce9 2007-07-21 drh: if( ch==q ) n++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: needQuote = !isnull && xtype==etSQLESCAPE2; dbda8d6ce9 2007-07-21 drh: n += i + 1 + needQuote*2; dbda8d6ce9 2007-07-21 drh: if( n>etBUFSIZE ){ c287665ba8 2007-09-14 drh: bufpt = zExtra = sqlite3_malloc( n ); dbda8d6ce9 2007-07-21 drh: if( bufpt==0 ) return -1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: bufpt = buf; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: j = 0; dbda8d6ce9 2007-07-21 drh: if( needQuote ) bufpt[j++] = q; dbda8d6ce9 2007-07-21 drh: for(i=0; (ch=escarg[i])!=0; i++){ dbda8d6ce9 2007-07-21 drh: bufpt[j++] = ch; dbda8d6ce9 2007-07-21 drh: if( ch==q ) bufpt[j++] = ch; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( needQuote ) bufpt[j++] = q; dbda8d6ce9 2007-07-21 drh: bufpt[j] = 0; dbda8d6ce9 2007-07-21 drh: length = j; dbda8d6ce9 2007-07-21 drh: /* The precision is ignored on %q and %Q */ dbda8d6ce9 2007-07-21 drh: /* if( precision>=0 && precision<length ) length = precision; */ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case etTOKEN: { dbda8d6ce9 2007-07-21 drh: Token *pToken = va_arg(ap, Token*); dbda8d6ce9 2007-07-21 drh: if( pToken && pToken->z ){ dbda8d6ce9 2007-07-21 drh: (*func)(arg, (char*)pToken->z, pToken->n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: length = width = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case etSRCLIST: { dbda8d6ce9 2007-07-21 drh: SrcList *pSrc = va_arg(ap, SrcList*); dbda8d6ce9 2007-07-21 drh: int k = va_arg(ap, int); dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem = &pSrc->a[k]; dbda8d6ce9 2007-07-21 drh: assert( k>=0 && k<pSrc->nSrc ); dbda8d6ce9 2007-07-21 drh: if( pItem->zDatabase && pItem->zDatabase[0] ){ dbda8d6ce9 2007-07-21 drh: (*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase)); dbda8d6ce9 2007-07-21 drh: (*func)(arg, ".", 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: (*func)(arg, pItem->zName, strlen(pItem->zName)); dbda8d6ce9 2007-07-21 drh: length = width = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }/* End switch over the format type */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The text of the conversion is pointed to by "bufpt" and is dbda8d6ce9 2007-07-21 drh: ** "length" characters long. The field width is "width". Do dbda8d6ce9 2007-07-21 drh: ** the output. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !flag_leftjustify ){ dbda8d6ce9 2007-07-21 drh: register int nspace; dbda8d6ce9 2007-07-21 drh: nspace = width-length; dbda8d6ce9 2007-07-21 drh: if( nspace>0 ){ dbda8d6ce9 2007-07-21 drh: count += nspace; dbda8d6ce9 2007-07-21 drh: while( nspace>=etSPACESIZE ){ dbda8d6ce9 2007-07-21 drh: (*func)(arg,spaces,etSPACESIZE); dbda8d6ce9 2007-07-21 drh: nspace -= etSPACESIZE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nspace>0 ) (*func)(arg,spaces,nspace); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( length>0 ){ dbda8d6ce9 2007-07-21 drh: (*func)(arg,bufpt,length); dbda8d6ce9 2007-07-21 drh: count += length; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( flag_leftjustify ){ dbda8d6ce9 2007-07-21 drh: register int nspace; dbda8d6ce9 2007-07-21 drh: nspace = width-length; dbda8d6ce9 2007-07-21 drh: if( nspace>0 ){ dbda8d6ce9 2007-07-21 drh: count += nspace; dbda8d6ce9 2007-07-21 drh: while( nspace>=etSPACESIZE ){ dbda8d6ce9 2007-07-21 drh: (*func)(arg,spaces,etSPACESIZE); dbda8d6ce9 2007-07-21 drh: nspace -= etSPACESIZE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nspace>0 ) (*func)(arg,spaces,nspace); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zExtra ){ c287665ba8 2007-09-14 drh: sqlite3_free(zExtra); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }/* End for loop over the format string */ dbda8d6ce9 2007-07-21 drh: return errorflag ? -1 : count; dbda8d6ce9 2007-07-21 drh: } /* End of function */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This structure is used to store state information about the dbda8d6ce9 2007-07-21 drh: ** write to memory that is currently in progress. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct sgMprintf { dbda8d6ce9 2007-07-21 drh: char *zBase; /* A base allocation */ dbda8d6ce9 2007-07-21 drh: char *zText; /* The string collected so far */ dbda8d6ce9 2007-07-21 drh: int nChar; /* Length of the string so far */ dbda8d6ce9 2007-07-21 drh: int nTotal; /* Output size if unconstrained */ dbda8d6ce9 2007-07-21 drh: int nAlloc; /* Amount of space allocated in zText */ dbda8d6ce9 2007-07-21 drh: void *(*xRealloc)(void*,int); /* Function used to realloc memory */ c287665ba8 2007-09-14 drh: int iMallocFailed; /* True if xRealloc() has failed */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function implements the callback from vxprintf. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine add nNewChar characters of text in zNewText to dbda8d6ce9 2007-07-21 drh: ** the sgMprintf structure pointed to by "arg". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void mout(void *arg, const char *zNewText, int nNewChar){ dbda8d6ce9 2007-07-21 drh: struct sgMprintf *pM = (struct sgMprintf*)arg; c287665ba8 2007-09-14 drh: if( pM->iMallocFailed ) return; dbda8d6ce9 2007-07-21 drh: pM->nTotal += nNewChar; dbda8d6ce9 2007-07-21 drh: if( pM->zText ){ c287665ba8 2007-09-14 drh: if( pM->nChar + nNewChar + 1 > pM->nAlloc ){ c287665ba8 2007-09-14 drh: if( pM->xRealloc==0 ){ c287665ba8 2007-09-14 drh: nNewChar = pM->nAlloc - pM->nChar - 1; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: int nAlloc = pM->nChar + nNewChar*2 + 1; c287665ba8 2007-09-14 drh: if( pM->zText==pM->zBase ){ c287665ba8 2007-09-14 drh: pM->zText = pM->xRealloc(0, nAlloc); c287665ba8 2007-09-14 drh: if( pM->zText==0 ){ c287665ba8 2007-09-14 drh: pM->nAlloc = 0; c287665ba8 2007-09-14 drh: pM->iMallocFailed = 1; c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: }else if( pM->nChar ){ c287665ba8 2007-09-14 drh: memcpy(pM->zText, pM->zBase, pM->nChar); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: char *zNew; c287665ba8 2007-09-14 drh: zNew = pM->xRealloc(pM->zText, nAlloc); c287665ba8 2007-09-14 drh: if( zNew ){ c287665ba8 2007-09-14 drh: pM->zText = zNew; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pM->iMallocFailed = 1; c287665ba8 2007-09-14 drh: pM->xRealloc(pM->zText, 0); c287665ba8 2007-09-14 drh: pM->zText = 0; c287665ba8 2007-09-14 drh: pM->nAlloc = 0; c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pM->nAlloc = nAlloc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( nNewChar>0 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&pM->zText[pM->nChar], zNewText, nNewChar); dbda8d6ce9 2007-07-21 drh: pM->nChar += nNewChar; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pM->zText[pM->nChar] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is a wrapper around xprintf() that invokes mout() as dbda8d6ce9 2007-07-21 drh: ** the consumer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char *base_vprintf( c287665ba8 2007-09-14 drh: void *(*xRealloc)(void*, int), /* realloc() function. May be NULL */ dbda8d6ce9 2007-07-21 drh: int useInternal, /* Use internal %-conversions if true */ dbda8d6ce9 2007-07-21 drh: char *zInitBuf, /* Initially write here, before mallocing */ dbda8d6ce9 2007-07-21 drh: int nInitBuf, /* Size of zInitBuf[] */ dbda8d6ce9 2007-07-21 drh: const char *zFormat, /* format string */ dbda8d6ce9 2007-07-21 drh: va_list ap /* arguments */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: struct sgMprintf sM; dbda8d6ce9 2007-07-21 drh: sM.zBase = sM.zText = zInitBuf; dbda8d6ce9 2007-07-21 drh: sM.nChar = sM.nTotal = 0; dbda8d6ce9 2007-07-21 drh: sM.nAlloc = nInitBuf; dbda8d6ce9 2007-07-21 drh: sM.xRealloc = xRealloc; c287665ba8 2007-09-14 drh: sM.iMallocFailed = 0; dbda8d6ce9 2007-07-21 drh: vxprintf(mout, &sM, useInternal, zFormat, ap); c287665ba8 2007-09-14 drh: assert(sM.iMallocFailed==0 || sM.zText==0); c287665ba8 2007-09-14 drh: if( xRealloc && !sM.iMallocFailed ){ dbda8d6ce9 2007-07-21 drh: if( sM.zText==sM.zBase ){ dbda8d6ce9 2007-07-21 drh: sM.zText = xRealloc(0, sM.nChar+1); dbda8d6ce9 2007-07-21 drh: if( sM.zText ){ dbda8d6ce9 2007-07-21 drh: memcpy(sM.zText, sM.zBase, sM.nChar+1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( sM.nAlloc>sM.nChar+10 ){ c287665ba8 2007-09-14 drh: char *zNew; c287665ba8 2007-09-14 drh: sqlite3MallocBenignFailure(1); c287665ba8 2007-09-14 drh: zNew = xRealloc(sM.zText, sM.nChar+1); dbda8d6ce9 2007-07-21 drh: if( zNew ){ dbda8d6ce9 2007-07-21 drh: sM.zText = zNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return sM.zText; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Realloc that is a real function, not a macro. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void *printf_realloc(void *old, int size){ c287665ba8 2007-09-14 drh: return sqlite3_realloc(old, size); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print into memory obtained from sqliteMalloc(). Use the internal dbda8d6ce9 2007-07-21 drh: ** %-conversion extensions. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){ c287665ba8 2007-09-14 drh: char *z; dbda8d6ce9 2007-07-21 drh: char zBase[SQLITE_PRINT_BUF_SIZE]; c287665ba8 2007-09-14 drh: z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); c287665ba8 2007-09-14 drh: if( z==0 && db!=0 ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print into memory obtained from sqliteMalloc(). Use the internal dbda8d6ce9 2007-07-21 drh: ** %-conversion extensions. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: char zBase[SQLITE_PRINT_BUF_SIZE]; dbda8d6ce9 2007-07-21 drh: va_start(ap, zFormat); dbda8d6ce9 2007-07-21 drh: z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); dbda8d6ce9 2007-07-21 drh: va_end(ap); c287665ba8 2007-09-14 drh: if( z==0 && db!=0 ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: return z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print into memory obtained from sqlite3_malloc(). Omit the internal dbda8d6ce9 2007-07-21 drh: ** %-conversion extensions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){ dbda8d6ce9 2007-07-21 drh: char zBase[SQLITE_PRINT_BUF_SIZE]; dbda8d6ce9 2007-07-21 drh: return base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print into memory obtained from sqlite3_malloc()(). Omit the internal dbda8d6ce9 2007-07-21 drh: ** %-conversion extensions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){ dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: va_start(ap, zFormat); dbda8d6ce9 2007-07-21 drh: z = sqlite3_vmprintf(zFormat, ap); dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: return z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** sqlite3_snprintf() works like snprintf() except that it ignores the dbda8d6ce9 2007-07-21 drh: ** current locale settings. This is important for SQLite because we dbda8d6ce9 2007-07-21 drh: ** are not able to use a "," as the decimal point in place of "." as dbda8d6ce9 2007-07-21 drh: ** specified by some locales. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( n<=0 ){ dbda8d6ce9 2007-07-21 drh: return zBuf; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zBuf[0] = 0; dbda8d6ce9 2007-07-21 drh: va_start(ap,zFormat); dbda8d6ce9 2007-07-21 drh: z = base_vprintf(0, 0, zBuf, n, zFormat, ap); dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: return z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) || defined(SQLITE_MEMDEBUG) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A version of printf() that understands %lld. Used for debugging. dbda8d6ce9 2007-07-21 drh: ** The printf() built into some versions of windows does not understand %lld dbda8d6ce9 2007-07-21 drh: ** and segfaults if you give it a long long int. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ dbda8d6ce9 2007-07-21 drh: extern int getpid(void); dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: char zBuf[500]; dbda8d6ce9 2007-07-21 drh: va_start(ap, zFormat); dbda8d6ce9 2007-07-21 drh: base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap); dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: fprintf(stdout,"%s", zBuf); dbda8d6ce9 2007-07-21 drh: fflush(stdout); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of printf.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file random.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code to implement a pseudo-random number dbda8d6ce9 2007-07-21 drh: ** generator (PRNG) for SQLite. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Random numbers are used by some of the database backends in order dbda8d6ce9 2007-07-21 drh: ** to generate random integer keys for tables or random filenames. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: random.c,v 1.20 2007/08/21 13:51:23 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Get a single 8-bit random value from the RC4 PRNG. The Mutex dbda8d6ce9 2007-07-21 drh: ** must be held while executing this routine. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Why not just use a library random generator like lrand48() for this? dbda8d6ce9 2007-07-21 drh: ** Because the OP_NewRowid opcode in the VDBE depends on having a very dbda8d6ce9 2007-07-21 drh: ** good source of random numbers. The lrand48() library function may dbda8d6ce9 2007-07-21 drh: ** well be good enough. But maybe not. Or maybe lrand48() has some dbda8d6ce9 2007-07-21 drh: ** subtle problems on some systems that could cause problems. It is hard dbda8d6ce9 2007-07-21 drh: ** to know. To minimize the risk of problems due to bad lrand48() dbda8d6ce9 2007-07-21 drh: ** implementations, SQLite uses this random number generator based dbda8d6ce9 2007-07-21 drh: ** on RC4, which we know works very well. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (Later): Actually, OP_NewRowid does not depend on a good source of dbda8d6ce9 2007-07-21 drh: ** randomness any more. But we will leave this code in all the same. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int randomByte(void){ dbda8d6ce9 2007-07-21 drh: unsigned char t; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* All threads share a single random number generator. dbda8d6ce9 2007-07-21 drh: ** This structure is the current state of the generator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static struct { dbda8d6ce9 2007-07-21 drh: unsigned char isInit; /* True if initialized */ dbda8d6ce9 2007-07-21 drh: unsigned char i, j; /* State variables */ dbda8d6ce9 2007-07-21 drh: unsigned char s[256]; /* State variables */ dbda8d6ce9 2007-07-21 drh: } prng; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the state of the random number generator once, dbda8d6ce9 2007-07-21 drh: ** the first time this routine is called. The seed value does dbda8d6ce9 2007-07-21 drh: ** not need to contain a lot of randomness since we are not dbda8d6ce9 2007-07-21 drh: ** trying to do secure encryption or anything like that... dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Nothing in this file or anywhere else in SQLite does any kind of dbda8d6ce9 2007-07-21 drh: ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random dbda8d6ce9 2007-07-21 drh: ** number generator) not as an encryption device. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !prng.isInit ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: char k[256]; dbda8d6ce9 2007-07-21 drh: prng.j = 0; dbda8d6ce9 2007-07-21 drh: prng.i = 0; c287665ba8 2007-09-14 drh: sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k); dbda8d6ce9 2007-07-21 drh: for(i=0; i<256; i++){ dbda8d6ce9 2007-07-21 drh: prng.s[i] = i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<256; i++){ dbda8d6ce9 2007-07-21 drh: prng.j += prng.s[i] + k[i]; dbda8d6ce9 2007-07-21 drh: t = prng.s[prng.j]; dbda8d6ce9 2007-07-21 drh: prng.s[prng.j] = prng.s[i]; dbda8d6ce9 2007-07-21 drh: prng.s[i] = t; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: prng.isInit = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate and return single random byte dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: prng.i++; dbda8d6ce9 2007-07-21 drh: t = prng.s[prng.i]; dbda8d6ce9 2007-07-21 drh: prng.j += t; dbda8d6ce9 2007-07-21 drh: prng.s[prng.i] = prng.s[prng.j]; dbda8d6ce9 2007-07-21 drh: prng.s[prng.j] = t; dbda8d6ce9 2007-07-21 drh: t += prng.s[prng.i]; dbda8d6ce9 2007-07-21 drh: return prng.s[t]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return N random bytes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Randomness(int N, void *pBuf){ dbda8d6ce9 2007-07-21 drh: unsigned char *zBuf = pBuf; c287665ba8 2007-09-14 drh: static sqlite3_mutex *mutex = 0; c287665ba8 2007-09-14 drh: if( mutex==0 ){ c287665ba8 2007-09-14 drh: mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); dbda8d6ce9 2007-07-21 drh: while( N-- ){ dbda8d6ce9 2007-07-21 drh: *(zBuf++) = randomByte(); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of random.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file utf.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 April 13 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains routines used to translate between UTF-8, dbda8d6ce9 2007-07-21 drh: ** UTF-16, UTF-16BE, and UTF-16LE. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: utf.c,v 1.58 2007/09/12 17:01:45 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Notes on UTF-8: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Byte-0 Byte-1 Byte-2 Byte-3 Value dbda8d6ce9 2007-07-21 drh: ** 0xxxxxxx 00000000 00000000 0xxxxxxx dbda8d6ce9 2007-07-21 drh: ** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx dbda8d6ce9 2007-07-21 drh: ** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx dbda8d6ce9 2007-07-21 drh: ** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Notes on UTF-16: (with wwww+1==uuuuu) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Word-0 Word-1 Value dbda8d6ce9 2007-07-21 drh: ** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx dbda8d6ce9 2007-07-21 drh: ** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** BOM or Byte Order Mark: dbda8d6ce9 2007-07-21 drh: ** 0xff 0xfe little-endian utf-16 follows dbda8d6ce9 2007-07-21 drh: ** 0xfe 0xff big-endian utf-16 follows dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /************** Include vdbeInt.h in the middle of utf.c *********************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vdbeInt.h *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2003 September 6 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This is the header file for information that is private to the dbda8d6ce9 2007-07-21 drh: ** VDBE. This information used to all be at the top of the single dbda8d6ce9 2007-07-21 drh: ** source code file "vdbe.c". When that file became too big (over dbda8d6ce9 2007-07-21 drh: ** 6000 lines long) it was split up into several smaller files and dbda8d6ce9 2007-07-21 drh: ** this header information was factored out. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef _VDBEINT_H_ dbda8d6ce9 2007-07-21 drh: #define _VDBEINT_H_ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** intToKey() and keyToInt() used to transform the rowid. But with dbda8d6ce9 2007-07-21 drh: ** the latest versions of the design they are no-ops. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define keyToInt(X) (X) dbda8d6ce9 2007-07-21 drh: #define intToKey(X) (X) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** SQL is translated into a sequence of instructions to be dbda8d6ce9 2007-07-21 drh: ** executed by a virtual machine. Each instruction is an instance dbda8d6ce9 2007-07-21 drh: ** of the following structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct VdbeOp Op; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Boolean values dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef unsigned char Bool; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A cursor is a pointer into a single BTree within a database file. dbda8d6ce9 2007-07-21 drh: ** The cursor can seek to a BTree entry with a particular key, or dbda8d6ce9 2007-07-21 drh: ** loop over all entries of the Btree. You can also insert new BTree dbda8d6ce9 2007-07-21 drh: ** entries or retrieve the key or data from the entry that the cursor dbda8d6ce9 2007-07-21 drh: ** is currently pointing to. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Every cursor that the virtual machine has open is represented by an dbda8d6ce9 2007-07-21 drh: ** instance of the following structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the Cursor.isTriggerRow flag is set it means that this cursor is dbda8d6ce9 2007-07-21 drh: ** really a single row that represents the NEW or OLD pseudo-table of dbda8d6ce9 2007-07-21 drh: ** a row trigger. The data for the row is stored in Cursor.pData and dbda8d6ce9 2007-07-21 drh: ** the rowid is in Cursor.iKey. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Cursor { dbda8d6ce9 2007-07-21 drh: BtCursor *pCursor; /* The cursor structure of the backend */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Index of cursor database in db->aDb[] (or -1) */ dbda8d6ce9 2007-07-21 drh: i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ dbda8d6ce9 2007-07-21 drh: i64 nextRowid; /* Next rowid returned by OP_NewRowid */ dbda8d6ce9 2007-07-21 drh: Bool zeroed; /* True if zeroed out and ready for reuse */ dbda8d6ce9 2007-07-21 drh: Bool rowidIsValid; /* True if lastRowid is valid */ dbda8d6ce9 2007-07-21 drh: Bool atFirst; /* True if pointing to first entry */ dbda8d6ce9 2007-07-21 drh: Bool useRandomRowid; /* Generate new record numbers semi-randomly */ dbda8d6ce9 2007-07-21 drh: Bool nullRow; /* True if pointing to a row with no data */ dbda8d6ce9 2007-07-21 drh: Bool nextRowidValid; /* True if the nextRowid field is valid */ dbda8d6ce9 2007-07-21 drh: Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */ dbda8d6ce9 2007-07-21 drh: Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ dbda8d6ce9 2007-07-21 drh: Bool isTable; /* True if a table requiring integer keys */ dbda8d6ce9 2007-07-21 drh: Bool isIndex; /* True if an index containing keys only - no data */ dbda8d6ce9 2007-07-21 drh: u8 bogusIncrKey; /* Something for pIncrKey to point to if pKeyInfo==0 */ dbda8d6ce9 2007-07-21 drh: i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ dbda8d6ce9 2007-07-21 drh: Btree *pBt; /* Separate file holding temporary table */ dbda8d6ce9 2007-07-21 drh: int nData; /* Number of bytes in pData */ dbda8d6ce9 2007-07-21 drh: char *pData; /* Data for a NEW or OLD pseudo-table */ dbda8d6ce9 2007-07-21 drh: i64 iKey; /* Key for the NEW or OLD pseudo-table row */ dbda8d6ce9 2007-07-21 drh: u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ dbda8d6ce9 2007-07-21 drh: int nField; /* Number of fields in the header */ dbda8d6ce9 2007-07-21 drh: i64 seqCount; /* Sequence counter */ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule; /* Module for cursor pVtabCursor */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Cached information about the header for the data record that the dbda8d6ce9 2007-07-21 drh: ** cursor is currently pointing to. Only valid if cacheValid is true. dbda8d6ce9 2007-07-21 drh: ** aRow might point to (ephemeral) data for the current row, or it might dbda8d6ce9 2007-07-21 drh: ** be NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ dbda8d6ce9 2007-07-21 drh: int payloadSize; /* Total number of bytes in the record */ dbda8d6ce9 2007-07-21 drh: u32 *aType; /* Type values for all entries in the record */ dbda8d6ce9 2007-07-21 drh: u32 *aOffset; /* Cached offsets to the start of each columns data */ dbda8d6ce9 2007-07-21 drh: u8 *aRow; /* Data for the current row, if all on one page */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: typedef struct Cursor Cursor; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Number of bytes of string storage space available to each stack dbda8d6ce9 2007-07-21 drh: ** layer without having to malloc. NBFS is short for Number of Bytes dbda8d6ce9 2007-07-21 drh: ** For Strings. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define NBFS 32 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A value for Cursor.cacheValid that means the cache is always invalid. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define CACHE_STALE 0 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Internally, the vdbe manipulates nearly all SQL values as Mem dbda8d6ce9 2007-07-21 drh: ** structures. Each Mem struct may cache multiple representations (string, dbda8d6ce9 2007-07-21 drh: ** integer etc.) of the same value. A value (and therefore Mem structure) dbda8d6ce9 2007-07-21 drh: ** has the following properties: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each value has a manifest type. The manifest type of the value stored dbda8d6ce9 2007-07-21 drh: ** in a Mem struct is returned by the MemType(Mem*) macro. The type is dbda8d6ce9 2007-07-21 drh: ** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or dbda8d6ce9 2007-07-21 drh: ** SQLITE_BLOB. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Mem { dbda8d6ce9 2007-07-21 drh: union { dbda8d6ce9 2007-07-21 drh: i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */ dbda8d6ce9 2007-07-21 drh: FuncDef *pDef; /* Used only when flags==MEM_Agg */ dbda8d6ce9 2007-07-21 drh: } u; dbda8d6ce9 2007-07-21 drh: double r; /* Real value */ c287665ba8 2007-09-14 drh: sqlite3 *db; /* The associated database connection */ dbda8d6ce9 2007-07-21 drh: char *z; /* String or BLOB value */ dbda8d6ce9 2007-07-21 drh: int n; /* Number of characters in string value, including '\0' */ dbda8d6ce9 2007-07-21 drh: u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ dbda8d6ce9 2007-07-21 drh: u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */ dbda8d6ce9 2007-07-21 drh: u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ dbda8d6ce9 2007-07-21 drh: void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ dbda8d6ce9 2007-07-21 drh: char zShort[NBFS]; /* Space for short strings */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: typedef struct Mem Mem; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* One or more of the following flags are set to indicate the validOK dbda8d6ce9 2007-07-21 drh: ** representations of the value stored in the Mem struct. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the MEM_Null flag is set, then the value is an SQL NULL value. dbda8d6ce9 2007-07-21 drh: ** No other flags may be set in this case. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the MEM_Str flag is set then Mem.z points at a string representation. dbda8d6ce9 2007-07-21 drh: ** Usually this is encoded in the same unicode encoding as the main dbda8d6ce9 2007-07-21 drh: ** database (see below for exceptions). If the MEM_Term flag is also dbda8d6ce9 2007-07-21 drh: ** set, then the string is nul terminated. The MEM_Int and MEM_Real dbda8d6ce9 2007-07-21 drh: ** flags may coexist with the MEM_Str flag. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Multiple of these values can appear in Mem.flags. But only one dbda8d6ce9 2007-07-21 drh: ** at a time can appear in Mem.type. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define MEM_Null 0x0001 /* Value is NULL */ dbda8d6ce9 2007-07-21 drh: #define MEM_Str 0x0002 /* Value is a string */ dbda8d6ce9 2007-07-21 drh: #define MEM_Int 0x0004 /* Value is an integer */ dbda8d6ce9 2007-07-21 drh: #define MEM_Real 0x0008 /* Value is a real number */ dbda8d6ce9 2007-07-21 drh: #define MEM_Blob 0x0010 /* Value is a BLOB */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Whenever Mem contains a valid string or blob representation, one of dbda8d6ce9 2007-07-21 drh: ** the following flags must be set to determine the memory management dbda8d6ce9 2007-07-21 drh: ** policy for Mem.z. The MEM_Term flag tells us whether or not the dbda8d6ce9 2007-07-21 drh: ** string is \000 or \u0000 terminated dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define MEM_Term 0x0020 /* String rep is nul terminated */ dbda8d6ce9 2007-07-21 drh: #define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */ dbda8d6ce9 2007-07-21 drh: #define MEM_Static 0x0080 /* Mem.z points to a static string */ dbda8d6ce9 2007-07-21 drh: #define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ dbda8d6ce9 2007-07-21 drh: #define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */ dbda8d6ce9 2007-07-21 drh: #define MEM_Agg 0x0400 /* Mem.z points to an agg function context */ dbda8d6ce9 2007-07-21 drh: #define MEM_Zero 0x0800 /* Mem.i contains count of 0s appended to blob */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: #undef MEM_Zero dbda8d6ce9 2007-07-21 drh: #define MEM_Zero 0x0000 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains dbda8d6ce9 2007-07-21 drh: ** additional information about auxiliary information bound to arguments dbda8d6ce9 2007-07-21 drh: ** of the function. This is used to implement the sqlite3_get_auxdata() dbda8d6ce9 2007-07-21 drh: ** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data dbda8d6ce9 2007-07-21 drh: ** that can be associated with a constant argument to a function. This dbda8d6ce9 2007-07-21 drh: ** allows functions such as "regexp" to compile their constant regular dbda8d6ce9 2007-07-21 drh: ** expression argument once and reused the compiled code for multiple dbda8d6ce9 2007-07-21 drh: ** invocations. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct VdbeFunc { dbda8d6ce9 2007-07-21 drh: FuncDef *pFunc; /* The definition of the function */ dbda8d6ce9 2007-07-21 drh: int nAux; /* Number of entries allocated for apAux[] */ dbda8d6ce9 2007-07-21 drh: struct AuxData { dbda8d6ce9 2007-07-21 drh: void *pAux; /* Aux data for the i-th argument */ dbda8d6ce9 2007-07-21 drh: void (*xDelete)(void *); /* Destructor for the aux data */ dbda8d6ce9 2007-07-21 drh: } apAux[1]; /* One slot for each function argument */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: typedef struct VdbeFunc VdbeFunc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The "context" argument for a installable function. A pointer to an dbda8d6ce9 2007-07-21 drh: ** instance of this structure is the first argument to the routines used dbda8d6ce9 2007-07-21 drh: ** implement the SQL functions. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There is a typedef for this structure in sqlite.h. So all routines, dbda8d6ce9 2007-07-21 drh: ** even the public interface to SQLite, can use a pointer to this structure. dbda8d6ce9 2007-07-21 drh: ** But this file is the only place where the internal details of this dbda8d6ce9 2007-07-21 drh: ** structure are known. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This structure is defined inside of vdbeInt.h because it uses substructures dbda8d6ce9 2007-07-21 drh: ** (Mem) which are only defined there. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct sqlite3_context { dbda8d6ce9 2007-07-21 drh: FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ dbda8d6ce9 2007-07-21 drh: VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ dbda8d6ce9 2007-07-21 drh: Mem s; /* The return value is stored here */ dbda8d6ce9 2007-07-21 drh: Mem *pMem; /* Memory cell used to store aggregate context */ dbda8d6ce9 2007-07-21 drh: u8 isError; /* Set to true for an error */ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; /* Collating sequence */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A Set structure is used for quick testing to see if a value dbda8d6ce9 2007-07-21 drh: ** is part of a small set. Sets are used to implement code like dbda8d6ce9 2007-07-21 drh: ** this: dbda8d6ce9 2007-07-21 drh: ** x.y IN ('hi','hoo','hum') dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct Set Set; dbda8d6ce9 2007-07-21 drh: struct Set { dbda8d6ce9 2007-07-21 drh: Hash hash; /* A set is just a hash table */ dbda8d6ce9 2007-07-21 drh: HashElem *prev; /* Previously accessed hash elemen */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A FifoPage structure holds a single page of valves. Pages are arranged dbda8d6ce9 2007-07-21 drh: ** in a list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct FifoPage FifoPage; dbda8d6ce9 2007-07-21 drh: struct FifoPage { dbda8d6ce9 2007-07-21 drh: int nSlot; /* Number of entries aSlot[] */ dbda8d6ce9 2007-07-21 drh: int iWrite; /* Push the next value into this entry in aSlot[] */ dbda8d6ce9 2007-07-21 drh: int iRead; /* Read the next value from this entry in aSlot[] */ dbda8d6ce9 2007-07-21 drh: FifoPage *pNext; /* Next page in the fifo */ dbda8d6ce9 2007-07-21 drh: i64 aSlot[1]; /* One or more slots for rowid values */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The Fifo structure is typedef-ed in vdbeInt.h. But the implementation dbda8d6ce9 2007-07-21 drh: ** of that structure is private to this file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The Fifo structure describes the entire fifo. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct Fifo Fifo; dbda8d6ce9 2007-07-21 drh: struct Fifo { dbda8d6ce9 2007-07-21 drh: int nEntry; /* Total number of entries */ dbda8d6ce9 2007-07-21 drh: FifoPage *pFirst; /* First page on the list */ dbda8d6ce9 2007-07-21 drh: FifoPage *pLast; /* Last page on the list */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A Context stores the last insert rowid, the last statement change count, dbda8d6ce9 2007-07-21 drh: ** and the current statement change count (i.e. changes since last statement). dbda8d6ce9 2007-07-21 drh: ** The current keylist is also stored in the context. dbda8d6ce9 2007-07-21 drh: ** Elements of Context structure type make up the ContextStack, which is dbda8d6ce9 2007-07-21 drh: ** updated by the ContextPush and ContextPop opcodes (used by triggers). dbda8d6ce9 2007-07-21 drh: ** The context is pushed before executing a trigger a popped when the dbda8d6ce9 2007-07-21 drh: ** trigger finishes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct Context Context; dbda8d6ce9 2007-07-21 drh: struct Context { dbda8d6ce9 2007-07-21 drh: i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ dbda8d6ce9 2007-07-21 drh: int nChange; /* Statement changes (Vdbe.nChanges) */ dbda8d6ce9 2007-07-21 drh: Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the virtual machine. This structure contains the complete dbda8d6ce9 2007-07-21 drh: ** state of the virtual machine. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile() dbda8d6ce9 2007-07-21 drh: ** is really a pointer to an instance of this structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The Vdbe.inVtabMethod variable is set to non-zero for the duration of dbda8d6ce9 2007-07-21 drh: ** any virtual table method invocations made by the vdbe program. It is dbda8d6ce9 2007-07-21 drh: ** set to 2 for xDestroy method calls and 1 for all other methods. This dbda8d6ce9 2007-07-21 drh: ** variable is used for two purposes: to allow xDestroy methods to execute dbda8d6ce9 2007-07-21 drh: ** "DROP TABLE" statements and to prevent some nasty side effects of dbda8d6ce9 2007-07-21 drh: ** malloc failure when SQLite is invoked recursively by a virtual table dbda8d6ce9 2007-07-21 drh: ** method function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Vdbe { dbda8d6ce9 2007-07-21 drh: sqlite3 *db; /* The whole database */ dbda8d6ce9 2007-07-21 drh: Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ dbda8d6ce9 2007-07-21 drh: int nOp; /* Number of instructions in the program */ dbda8d6ce9 2007-07-21 drh: int nOpAlloc; /* Number of slots allocated for aOp[] */ dbda8d6ce9 2007-07-21 drh: Op *aOp; /* Space to hold the virtual machine's program */ dbda8d6ce9 2007-07-21 drh: int nLabel; /* Number of labels used */ dbda8d6ce9 2007-07-21 drh: int nLabelAlloc; /* Number of slots allocated in aLabel[] */ dbda8d6ce9 2007-07-21 drh: int *aLabel; /* Space to hold the labels */ dbda8d6ce9 2007-07-21 drh: Mem *aStack; /* The operand stack, except string values */ dbda8d6ce9 2007-07-21 drh: Mem *pTos; /* Top entry in the operand stack */ dbda8d6ce9 2007-07-21 drh: Mem **apArg; /* Arguments to currently executing user function */ dbda8d6ce9 2007-07-21 drh: Mem *aColName; /* Column names to return */ dbda8d6ce9 2007-07-21 drh: int nCursor; /* Number of slots in apCsr[] */ dbda8d6ce9 2007-07-21 drh: Cursor **apCsr; /* One element of this array for each open cursor */ dbda8d6ce9 2007-07-21 drh: int nVar; /* Number of entries in aVar[] */ dbda8d6ce9 2007-07-21 drh: Mem *aVar; /* Values for the OP_Variable opcode. */ dbda8d6ce9 2007-07-21 drh: char **azVar; /* Name of variables */ dbda8d6ce9 2007-07-21 drh: int okVar; /* True if azVar[] has been initialized */ dbda8d6ce9 2007-07-21 drh: int magic; /* Magic number for sanity checking */ dbda8d6ce9 2007-07-21 drh: int nMem; /* Number of memory locations currently allocated */ dbda8d6ce9 2007-07-21 drh: Mem *aMem; /* The memory locations */ dbda8d6ce9 2007-07-21 drh: int nCallback; /* Number of callbacks invoked so far */ dbda8d6ce9 2007-07-21 drh: int cacheCtr; /* Cursor row cache generation counter */ dbda8d6ce9 2007-07-21 drh: Fifo sFifo; /* A list of ROWIDs */ dbda8d6ce9 2007-07-21 drh: int contextStackTop; /* Index of top element in the context stack */ dbda8d6ce9 2007-07-21 drh: int contextStackDepth; /* The size of the "context" stack */ dbda8d6ce9 2007-07-21 drh: Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/ dbda8d6ce9 2007-07-21 drh: int pc; /* The program counter */ dbda8d6ce9 2007-07-21 drh: int rc; /* Value to return */ dbda8d6ce9 2007-07-21 drh: unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */ dbda8d6ce9 2007-07-21 drh: int errorAction; /* Recovery action to do in case of an error */ dbda8d6ce9 2007-07-21 drh: int inTempTrans; /* True if temp database is transactioned */ c287665ba8 2007-09-14 drh: int returnStack[25]; /* Return address stack for OP_Gosub & OP_Return */ dbda8d6ce9 2007-07-21 drh: int returnDepth; /* Next unused element in returnStack[] */ dbda8d6ce9 2007-07-21 drh: int nResColumn; /* Number of columns in one row of the result set */ dbda8d6ce9 2007-07-21 drh: char **azResColumn; /* Values for one row of result */ dbda8d6ce9 2007-07-21 drh: int popStack; /* Pop the stack this much on entry to VdbeExec() */ dbda8d6ce9 2007-07-21 drh: char *zErrMsg; /* Error message written here */ dbda8d6ce9 2007-07-21 drh: u8 resOnStack; /* True if there are result values on the stack */ dbda8d6ce9 2007-07-21 drh: u8 explain; /* True if EXPLAIN present on SQL command */ dbda8d6ce9 2007-07-21 drh: u8 changeCntOn; /* True to update the change-counter */ dbda8d6ce9 2007-07-21 drh: u8 aborted; /* True if ROLLBACK in another VM causes an abort */ dbda8d6ce9 2007-07-21 drh: u8 expired; /* True if the VM needs to be recompiled */ dbda8d6ce9 2007-07-21 drh: u8 minWriteFileFormat; /* Minimum file format for writable database files */ dbda8d6ce9 2007-07-21 drh: u8 inVtabMethod; /* See comments above */ dbda8d6ce9 2007-07-21 drh: int nChange; /* Number of db changes made since last reset */ dbda8d6ce9 2007-07-21 drh: i64 startTime; /* Time when query started - used for profiling */ c287665ba8 2007-09-14 drh: int btreeMask; /* Bitmask of db->aDb[] entries referenced */ c287665ba8 2007-09-14 drh: BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */ dbda8d6ce9 2007-07-21 drh: int nSql; /* Number of bytes in zSql */ dbda8d6ce9 2007-07-21 drh: char *zSql; /* Text of the SQL statement that generated this */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: FILE *trace; /* Write an execution trace here, if not NULL */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: int openedStatement; /* True if this VM has opened a statement journal */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SSE dbda8d6ce9 2007-07-21 drh: int fetchId; /* Statement number used by sqlite3_fetch_statement */ dbda8d6ce9 2007-07-21 drh: int lru; /* Counter used for LRU cache replacement */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following are allowed values for Vdbe.magic dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */ dbda8d6ce9 2007-07-21 drh: #define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ dbda8d6ce9 2007-07-21 drh: #define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */ dbda8d6ce9 2007-07-21 drh: #define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Function prototypes dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, Cursor*); dbda8d6ce9 2007-07-21 drh: void sqliteVdbePopStack(Vdbe*,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(Cursor*); dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeSerialTypeLen(u32); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(VdbeFunc*, int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(Cursor*,int,const unsigned char*,int*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeIdxRowid(BtCursor *, i64 *); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeIdxRowidLen(const u8*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemMove(Mem*, Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemDynamicify(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char *sqlite3OpcodeName(int); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSanity(Mem*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeOpcodeNoPush(u8); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeFifoInit(Fifo*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeFifoPush(Fifo*, i64); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeFifoPop(Fifo*, i64*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeFifoClear(Fifo*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* !defined(_VDBEINT_H_) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vdbeInt.h *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in utf.c ************************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following constant value is used by the SQLITE_BIGENDIAN and dbda8d6ce9 2007-07-21 drh: ** SQLITE_LITTLEENDIAN macros. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const int sqlite3one = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This lookup table is used to help decode the first byte of dbda8d6ce9 2007-07-21 drh: ** a multi-byte UTF8 character. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static const unsigned char sqlite3UtfTrans1[] = { dbda8d6ce9 2007-07-21 drh: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, dbda8d6ce9 2007-07-21 drh: 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, dbda8d6ce9 2007-07-21 drh: 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, dbda8d6ce9 2007-07-21 drh: 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, dbda8d6ce9 2007-07-21 drh: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, dbda8d6ce9 2007-07-21 drh: 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, dbda8d6ce9 2007-07-21 drh: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, dbda8d6ce9 2007-07-21 drh: 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, dbda8d6ce9 2007-07-21 drh: }; d8590e093f 2007-07-24 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define WRITE_UTF8(zOut, c) { \ dbda8d6ce9 2007-07-21 drh: if( c<0x00080 ){ \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (c&0xFF); \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: else if( c<0x00800 ){ \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0xC0 + ((c>>6)&0x1F); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0x80 + (c & 0x3F); \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: else if( c<0x10000 ){ \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0xE0 + ((c>>12)&0x0F); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0x80 + ((c>>6) & 0x3F); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0x80 + (c & 0x3F); \ dbda8d6ce9 2007-07-21 drh: }else{ \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0xF0 + ((c>>18) & 0x07); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0x80 + ((c>>12) & 0x3F); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0x80 + ((c>>6) & 0x3F); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = 0x80 + (c & 0x3F); \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define WRITE_UTF16LE(zOut, c) { \ dbda8d6ce9 2007-07-21 drh: if( c<=0xFFFF ){ \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (c&0x00FF); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = ((c>>8)&0x00FF); \ dbda8d6ce9 2007-07-21 drh: }else{ \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (c&0x00FF); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (0x00DC + ((c>>8)&0x03)); \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define WRITE_UTF16BE(zOut, c) { \ dbda8d6ce9 2007-07-21 drh: if( c<=0xFFFF ){ \ dbda8d6ce9 2007-07-21 drh: *zOut++ = ((c>>8)&0x00FF); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (c&0x00FF); \ dbda8d6ce9 2007-07-21 drh: }else{ \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (0x00DC + ((c>>8)&0x03)); \ dbda8d6ce9 2007-07-21 drh: *zOut++ = (c&0x00FF); \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define READ_UTF16LE(zIn, c){ \ dbda8d6ce9 2007-07-21 drh: c = (*zIn++); \ dbda8d6ce9 2007-07-21 drh: c += ((*zIn++)<<8); \ dbda8d6ce9 2007-07-21 drh: if( c>=0xD800 && c<0xE000 ){ \ dbda8d6ce9 2007-07-21 drh: int c2 = (*zIn++); \ dbda8d6ce9 2007-07-21 drh: c2 += ((*zIn++)<<8); \ dbda8d6ce9 2007-07-21 drh: c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ dbda8d6ce9 2007-07-21 drh: if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define READ_UTF16BE(zIn, c){ \ dbda8d6ce9 2007-07-21 drh: c = ((*zIn++)<<8); \ dbda8d6ce9 2007-07-21 drh: c += (*zIn++); \ dbda8d6ce9 2007-07-21 drh: if( c>=0xD800 && c<0xE000 ){ \ dbda8d6ce9 2007-07-21 drh: int c2 = ((*zIn++)<<8); \ dbda8d6ce9 2007-07-21 drh: c2 += (*zIn++); \ dbda8d6ce9 2007-07-21 drh: c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ dbda8d6ce9 2007-07-21 drh: if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* d8590e093f 2007-07-24 drh: ** Translate a single UTF-8 character. Return the unicode value. d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** During translation, assume that the byte that zTerm points d8590e093f 2007-07-24 drh: ** is a 0x00. d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** Write a pointer to the next unread byte back into *pzNext. d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** Notes On Invalid UTF-8: d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** * This routine never allows a 7-bit character (0x00 through 0x7f) to d8590e093f 2007-07-24 drh: ** be encoded as a multi-byte character. Any multi-byte character that d8590e093f 2007-07-24 drh: ** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd. d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** * This routine never allows a UTF16 surrogate value to be encoded. d8590e093f 2007-07-24 drh: ** If a multi-byte character attempts to encode a value between d8590e093f 2007-07-24 drh: ** 0xd800 and 0xe000 then it is rendered as 0xfffd. d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** * Bytes in the range of 0x80 through 0xbf which occur as the first d8590e093f 2007-07-24 drh: ** byte of a character are interpreted as single-byte characters d8590e093f 2007-07-24 drh: ** and rendered as themselves even though they are technically d8590e093f 2007-07-24 drh: ** invalid characters. d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** * This routine accepts an infinite number of different UTF8 encodings d8590e093f 2007-07-24 drh: ** for unicode values 0x80 and greater. It do not change over-length d8590e093f 2007-07-24 drh: ** encodings to 0xfffd as some systems recommend. d8590e093f 2007-07-24 drh: */ d8590e093f 2007-07-24 drh: SQLITE_PRIVATE int sqlite3Utf8Read( d8590e093f 2007-07-24 drh: const unsigned char *z, /* First byte of UTF-8 character */ d8590e093f 2007-07-24 drh: const unsigned char *zTerm, /* Pretend this byte is 0x00 */ d8590e093f 2007-07-24 drh: const unsigned char **pzNext /* Write first byte past UTF-8 char here */ d8590e093f 2007-07-24 drh: ){ d8590e093f 2007-07-24 drh: int c = *(z++); d8590e093f 2007-07-24 drh: if( c>=0xc0 ){ d8590e093f 2007-07-24 drh: c = sqlite3UtfTrans1[c-0xc0]; d8590e093f 2007-07-24 drh: while( z!=zTerm && (*z & 0xc0)==0x80 ){ d8590e093f 2007-07-24 drh: c = (c<<6) + (0x3f & *(z++)); d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: if( c<0x80 d8590e093f 2007-07-24 drh: || (c&0xFFFFF800)==0xD800 d8590e093f 2007-07-24 drh: || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: *pzNext = z; d8590e093f 2007-07-24 drh: return c; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: d8590e093f 2007-07-24 drh: d8590e093f 2007-07-24 drh: d8590e093f 2007-07-24 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the TRANSLATE_TRACE macro is defined, the value of each Mem is dbda8d6ce9 2007-07-21 drh: ** printed on stderr on the way into and out of sqlite3VdbeMemTranslate(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* #define TRANSLATE_TRACE 1 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine transforms the internal text encoding used by pMem to dbda8d6ce9 2007-07-21 drh: ** desiredEnc. It is an error if the string is already of the desired dbda8d6ce9 2007-07-21 drh: ** encoding, or if *pMem does not contain a string value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ dbda8d6ce9 2007-07-21 drh: unsigned char zShort[NBFS]; /* Temporary short output buffer */ dbda8d6ce9 2007-07-21 drh: int len; /* Maximum length of output string in bytes */ dbda8d6ce9 2007-07-21 drh: unsigned char *zOut; /* Output buffer */ dbda8d6ce9 2007-07-21 drh: unsigned char *zIn; /* Input iterator */ dbda8d6ce9 2007-07-21 drh: unsigned char *zTerm; /* End of input */ dbda8d6ce9 2007-07-21 drh: unsigned char *z; /* Output iterator */ dbda8d6ce9 2007-07-21 drh: unsigned int c; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: assert( pMem->flags&MEM_Str ); dbda8d6ce9 2007-07-21 drh: assert( pMem->enc!=desiredEnc ); dbda8d6ce9 2007-07-21 drh: assert( pMem->enc!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pMem->n>=0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: char zBuf[100]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemPrettyPrint(pMem, zBuf); dbda8d6ce9 2007-07-21 drh: fprintf(stderr, "INPUT: %s\n", zBuf); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the translation is between UTF-16 little and big endian, then dbda8d6ce9 2007-07-21 drh: ** all that is required is to swap the byte order. This case is handled dbda8d6ce9 2007-07-21 drh: ** differently from the others. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){ dbda8d6ce9 2007-07-21 drh: u8 temp; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemMakeWriteable(pMem); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_NOMEM ); dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zIn = (u8*)pMem->z; dbda8d6ce9 2007-07-21 drh: zTerm = &zIn[pMem->n]; dbda8d6ce9 2007-07-21 drh: while( zIn<zTerm ){ dbda8d6ce9 2007-07-21 drh: temp = *zIn; dbda8d6ce9 2007-07-21 drh: *zIn = *(zIn+1); dbda8d6ce9 2007-07-21 drh: zIn++; dbda8d6ce9 2007-07-21 drh: *zIn++ = temp; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->enc = desiredEnc; dbda8d6ce9 2007-07-21 drh: goto translate_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set len to the maximum number of bytes required in the output buffer. */ dbda8d6ce9 2007-07-21 drh: if( desiredEnc==SQLITE_UTF8 ){ dbda8d6ce9 2007-07-21 drh: /* When converting from UTF-16, the maximum growth results from dbda8d6ce9 2007-07-21 drh: ** translating a 2-byte character to a 4-byte UTF-8 character. dbda8d6ce9 2007-07-21 drh: ** A single byte is required for the output string dbda8d6ce9 2007-07-21 drh: ** nul-terminator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: len = pMem->n * 2 + 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* When converting from UTF-8 to UTF-16 the maximum growth is caused dbda8d6ce9 2007-07-21 drh: ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 dbda8d6ce9 2007-07-21 drh: ** character. Two bytes are required in the output buffer for the dbda8d6ce9 2007-07-21 drh: ** nul-terminator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: len = pMem->n * 2 + 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set zIn to point at the start of the input buffer and zTerm to point 1 dbda8d6ce9 2007-07-21 drh: ** byte past the end. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Variable zOut is set to point at the output buffer. This may be space c287665ba8 2007-09-14 drh: ** obtained from sqlite3_malloc(), or Mem.zShort, if it large enough and c287665ba8 2007-09-14 drh: ** not in use, or the zShort array on the stack (see above). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: zIn = (u8*)pMem->z; dbda8d6ce9 2007-07-21 drh: zTerm = &zIn[pMem->n]; dbda8d6ce9 2007-07-21 drh: if( len>NBFS ){ c287665ba8 2007-09-14 drh: zOut = sqlite3DbMallocRaw(pMem->db, len); c287665ba8 2007-09-14 drh: if( !zOut ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zOut = zShort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: z = zOut; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pMem->enc==SQLITE_UTF8 ){ dbda8d6ce9 2007-07-21 drh: if( desiredEnc==SQLITE_UTF16LE ){ dbda8d6ce9 2007-07-21 drh: /* UTF-8 -> UTF-16 Little-endian */ dbda8d6ce9 2007-07-21 drh: while( zIn<zTerm ){ d8590e093f 2007-07-24 drh: c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); d8590e093f 2007-07-24 drh: WRITE_UTF16LE(z, c); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( desiredEnc==SQLITE_UTF16BE ); dbda8d6ce9 2007-07-21 drh: /* UTF-8 -> UTF-16 Big-endian */ dbda8d6ce9 2007-07-21 drh: while( zIn<zTerm ){ d8590e093f 2007-07-24 drh: c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); d8590e093f 2007-07-24 drh: WRITE_UTF16BE(z, c); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->n = z - zOut; dbda8d6ce9 2007-07-21 drh: *z++ = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( desiredEnc==SQLITE_UTF8 ); dbda8d6ce9 2007-07-21 drh: if( pMem->enc==SQLITE_UTF16LE ){ dbda8d6ce9 2007-07-21 drh: /* UTF-16 Little-endian -> UTF-8 */ dbda8d6ce9 2007-07-21 drh: while( zIn<zTerm ){ dbda8d6ce9 2007-07-21 drh: READ_UTF16LE(zIn, c); dbda8d6ce9 2007-07-21 drh: WRITE_UTF8(z, c); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* UTF-16 Little-endian -> UTF-8 */ dbda8d6ce9 2007-07-21 drh: while( zIn<zTerm ){ dbda8d6ce9 2007-07-21 drh: READ_UTF16BE(zIn, c); dbda8d6ce9 2007-07-21 drh: WRITE_UTF8(z, c); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->n = z - zOut; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *z = 0; dbda8d6ce9 2007-07-21 drh: assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); dbda8d6ce9 2007-07-21 drh: pMem->enc = desiredEnc; dbda8d6ce9 2007-07-21 drh: if( zOut==zShort ){ dbda8d6ce9 2007-07-21 drh: memcpy(pMem->zShort, zOut, len); dbda8d6ce9 2007-07-21 drh: zOut = (u8*)pMem->zShort; dbda8d6ce9 2007-07-21 drh: pMem->flags |= (MEM_Term|MEM_Short); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pMem->flags |= (MEM_Term|MEM_Dyn); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->z = (char*)zOut; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: translate_out: dbda8d6ce9 2007-07-21 drh: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: char zBuf[100]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemPrettyPrint(pMem, zBuf); dbda8d6ce9 2007-07-21 drh: fprintf(stderr, "OUTPUT: %s\n", zBuf); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine checks for a byte-order mark at the beginning of the dbda8d6ce9 2007-07-21 drh: ** UTF-16 string stored in *pMem. If one is present, it is removed and dbda8d6ce9 2007-07-21 drh: ** the encoding of the Mem adjusted. This routine does not do any dbda8d6ce9 2007-07-21 drh: ** byte-swapping, it just sets Mem.enc appropriately. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The allocation (static, dynamic etc.) and encoding of the Mem may be dbda8d6ce9 2007-07-21 drh: ** changed by this function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: u8 bom = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pMem->n<0 || pMem->n>1 ){ dbda8d6ce9 2007-07-21 drh: u8 b1 = *(u8 *)pMem->z; dbda8d6ce9 2007-07-21 drh: u8 b2 = *(((u8 *)pMem->z) + 1); dbda8d6ce9 2007-07-21 drh: if( b1==0xFE && b2==0xFF ){ dbda8d6ce9 2007-07-21 drh: bom = SQLITE_UTF16BE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( b1==0xFF && b2==0xFE ){ dbda8d6ce9 2007-07-21 drh: bom = SQLITE_UTF16LE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( bom ){ dbda8d6ce9 2007-07-21 drh: /* This function is called as soon as a string is stored in a Mem*, dbda8d6ce9 2007-07-21 drh: ** from within sqlite3VdbeMemSetStr(). At that point it is not possible dbda8d6ce9 2007-07-21 drh: ** for the string to be stored in Mem.zShort, or for it to be stored dbda8d6ce9 2007-07-21 drh: ** in dynamic memory with no destructor. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( !(pMem->flags&MEM_Short) ); dbda8d6ce9 2007-07-21 drh: assert( !(pMem->flags&MEM_Dyn) || pMem->xDel ); dbda8d6ce9 2007-07-21 drh: if( pMem->flags & MEM_Dyn ){ dbda8d6ce9 2007-07-21 drh: void (*xDel)(void*) = pMem->xDel; dbda8d6ce9 2007-07-21 drh: char *z = pMem->z; dbda8d6ce9 2007-07-21 drh: pMem->z = 0; dbda8d6ce9 2007-07-21 drh: pMem->xDel = 0; c287665ba8 2007-09-14 drh: rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, c287665ba8 2007-09-14 drh: SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: xDel(z); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom, dbda8d6ce9 2007-07-21 drh: SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pZ is a UTF-8 encoded unicode string. If nByte is less than zero, dbda8d6ce9 2007-07-21 drh: ** return the number of unicode characters in pZ up to (but not including) dbda8d6ce9 2007-07-21 drh: ** the first 0x00 byte. If nByte is not less than zero, return the dbda8d6ce9 2007-07-21 drh: ** number of unicode characters in the first nByte of pZ (or up to dbda8d6ce9 2007-07-21 drh: ** the first 0x00, whichever comes first). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){ dbda8d6ce9 2007-07-21 drh: int r = 0; dbda8d6ce9 2007-07-21 drh: const u8 *z = (const u8*)zIn; dbda8d6ce9 2007-07-21 drh: const u8 *zTerm; dbda8d6ce9 2007-07-21 drh: if( nByte>=0 ){ dbda8d6ce9 2007-07-21 drh: zTerm = &z[nByte]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zTerm = (const u8*)(-1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( z<=zTerm ); dbda8d6ce9 2007-07-21 drh: while( *z!=0 && z<zTerm ){ dbda8d6ce9 2007-07-21 drh: SQLITE_SKIP_UTF8(z); dbda8d6ce9 2007-07-21 drh: r++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* This test function is not currently used by the automated test-suite. c287665ba8 2007-09-14 drh: ** Hence it is only available in debug builds. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Translate UTF-8 to UTF-8. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This has the effect of making sure that the string is well-formed c287665ba8 2007-09-14 drh: ** UTF-8. Miscoded characters are removed. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The translation is done in-place (since it is impossible for the c287665ba8 2007-09-14 drh: ** correct UTF-8 encoding to be longer than a malformed encoding). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char *zIn){ c287665ba8 2007-09-14 drh: unsigned char *zOut = zIn; c287665ba8 2007-09-14 drh: unsigned char *zStart = zIn; c287665ba8 2007-09-14 drh: unsigned char *zTerm; c287665ba8 2007-09-14 drh: u32 c; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: while( zIn[0] ){ c287665ba8 2007-09-14 drh: c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); c287665ba8 2007-09-14 drh: if( c!=0xfffd ){ c287665ba8 2007-09-14 drh: WRITE_UTF8(zOut, c); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: *zOut = 0; c287665ba8 2007-09-14 drh: return zOut - zStart; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert a UTF-16 string in the native encoding into a UTF-8 string. c287665ba8 2007-09-14 drh: ** Memory to hold the UTF-8 string is obtained from sqlite3_malloc and must c287665ba8 2007-09-14 drh: ** be freed by the calling function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** NULL is returned if there is an allocation error. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){ dbda8d6ce9 2007-07-21 drh: Mem m; dbda8d6ce9 2007-07-21 drh: memset(&m, 0, sizeof(m)); c287665ba8 2007-09-14 drh: m.db = db; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8); c287665ba8 2007-09-14 drh: assert( (m.flags & MEM_Term)!=0 || db->mallocFailed ); c287665ba8 2007-09-14 drh: assert( (m.flags & MEM_Str)!=0 || db->mallocFailed ); c287665ba8 2007-09-14 drh: return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pZ is a UTF-16 encoded unicode string. If nChar is less than zero, dbda8d6ce9 2007-07-21 drh: ** return the number of bytes up to (but not including), the first pair dbda8d6ce9 2007-07-21 drh: ** of consecutive 0x00 bytes in pZ. If nChar is not less than zero, dbda8d6ce9 2007-07-21 drh: ** then return the number of bytes in the first nChar unicode characters dbda8d6ce9 2007-07-21 drh: ** in pZ (or up until the first pair of 0x00 bytes, whichever comes first). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){ dbda8d6ce9 2007-07-21 drh: unsigned int c = 1; dbda8d6ce9 2007-07-21 drh: char const *z = zIn; dbda8d6ce9 2007-07-21 drh: int n = 0; dbda8d6ce9 2007-07-21 drh: if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){ dbda8d6ce9 2007-07-21 drh: /* Using an "if (SQLITE_UTF16NATIVE==SQLITE_UTF16BE)" construct here dbda8d6ce9 2007-07-21 drh: ** and in other parts of this file means that at one branch will dbda8d6ce9 2007-07-21 drh: ** not be covered by coverage testing on any single host. But coverage dbda8d6ce9 2007-07-21 drh: ** will be complete if the tests are run on both a little-endian and dbda8d6ce9 2007-07-21 drh: ** big-endian host. Because both the UTF16NATIVE and SQLITE_UTF16BE dbda8d6ce9 2007-07-21 drh: ** macros are constant at compile time the compiler can determine dbda8d6ce9 2007-07-21 drh: ** which branch will be followed. It is therefore assumed that no runtime dbda8d6ce9 2007-07-21 drh: ** penalty is paid for this "if" statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: while( c && ((nChar<0) || n<nChar) ){ dbda8d6ce9 2007-07-21 drh: READ_UTF16BE(z, c); dbda8d6ce9 2007-07-21 drh: n++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: while( c && ((nChar<0) || n<nChar) ){ dbda8d6ce9 2007-07-21 drh: READ_UTF16LE(z, c); dbda8d6ce9 2007-07-21 drh: n++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return (z-(char const *)zIn)-((c==0)?2:0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_TEST) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called from the TCL test function "translate_selftest". dbda8d6ce9 2007-07-21 drh: ** It checks that the primitives for serializing and deserializing dbda8d6ce9 2007-07-21 drh: ** characters in each encoding are inverses of each other. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3UtfSelfTest(){ dbda8d6ce9 2007-07-21 drh: unsigned int i, t; dbda8d6ce9 2007-07-21 drh: unsigned char zBuf[20]; dbda8d6ce9 2007-07-21 drh: unsigned char *z; d8590e093f 2007-07-24 drh: unsigned char *zTerm; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: unsigned int c; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<0x00110000; i++){ dbda8d6ce9 2007-07-21 drh: z = zBuf; dbda8d6ce9 2007-07-21 drh: WRITE_UTF8(z, i); dbda8d6ce9 2007-07-21 drh: n = z-zBuf; dbda8d6ce9 2007-07-21 drh: z[0] = 0; d8590e093f 2007-07-24 drh: zTerm = z; dbda8d6ce9 2007-07-21 drh: z = zBuf; d8590e093f 2007-07-24 drh: c = sqlite3Utf8Read(z, zTerm, (const u8**)&z); dbda8d6ce9 2007-07-21 drh: t = i; dbda8d6ce9 2007-07-21 drh: if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD; dbda8d6ce9 2007-07-21 drh: if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD; dbda8d6ce9 2007-07-21 drh: assert( c==t ); dbda8d6ce9 2007-07-21 drh: assert( (z-zBuf)==n ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<0x00110000; i++){ dbda8d6ce9 2007-07-21 drh: if( i>=0xD800 && i<0xE000 ) continue; dbda8d6ce9 2007-07-21 drh: z = zBuf; dbda8d6ce9 2007-07-21 drh: WRITE_UTF16LE(z, i); dbda8d6ce9 2007-07-21 drh: n = z-zBuf; dbda8d6ce9 2007-07-21 drh: z[0] = 0; dbda8d6ce9 2007-07-21 drh: z = zBuf; dbda8d6ce9 2007-07-21 drh: READ_UTF16LE(z, c); dbda8d6ce9 2007-07-21 drh: assert( c==i ); dbda8d6ce9 2007-07-21 drh: assert( (z-zBuf)==n ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<0x00110000; i++){ dbda8d6ce9 2007-07-21 drh: if( i>=0xD800 && i<0xE000 ) continue; dbda8d6ce9 2007-07-21 drh: z = zBuf; dbda8d6ce9 2007-07-21 drh: WRITE_UTF16BE(z, i); dbda8d6ce9 2007-07-21 drh: n = z-zBuf; dbda8d6ce9 2007-07-21 drh: z[0] = 0; dbda8d6ce9 2007-07-21 drh: z = zBuf; dbda8d6ce9 2007-07-21 drh: READ_UTF16BE(z, c); dbda8d6ce9 2007-07-21 drh: assert( c==i ); dbda8d6ce9 2007-07-21 drh: assert( (z-zBuf)==n ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_TEST */ dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of utf.c *************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file util.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** Utility functions used throughout sqlite. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains functions for allocating memory, comparing dbda8d6ce9 2007-07-21 drh: ** strings, and stuff like that. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: util.c,v 1.212 2007/09/01 10:01:13 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the most recent error code and error string for the sqlite dbda8d6ce9 2007-07-21 drh: ** handle "db". The error code is set to "err_code". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If it is not NULL, string zFormat specifies the format of the dbda8d6ce9 2007-07-21 drh: ** error string in the style of the printf functions: The following dbda8d6ce9 2007-07-21 drh: ** format characters are allowed: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** %s Insert a string dbda8d6ce9 2007-07-21 drh: ** %z A string that should be freed after use dbda8d6ce9 2007-07-21 drh: ** %d Insert an integer dbda8d6ce9 2007-07-21 drh: ** %T Insert a token dbda8d6ce9 2007-07-21 drh: ** %S Insert the first element of a SrcList dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** zFormat and any string tokens that follow it are assumed to be dbda8d6ce9 2007-07-21 drh: ** encoded in UTF-8. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To clear the most recent error for sqlite handle "db", sqlite3Error dbda8d6ce9 2007-07-21 drh: ** should be called with err_code set to SQLITE_OK and zFormat set dbda8d6ce9 2007-07-21 drh: ** to NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){ c287665ba8 2007-09-14 drh: if( db && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){ dbda8d6ce9 2007-07-21 drh: db->errCode = err_code; dbda8d6ce9 2007-07-21 drh: if( zFormat ){ dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: va_start(ap, zFormat); c287665ba8 2007-09-14 drh: z = sqlite3VMPrintf(db, zFormat, ap); dbda8d6ce9 2007-07-21 drh: va_end(ap); c287665ba8 2007-09-14 drh: sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, sqlite3_free); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add an error message to pParse->zErrMsg and increment pParse->nErr. dbda8d6ce9 2007-07-21 drh: ** The following formatting characters are allowed: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** %s Insert a string dbda8d6ce9 2007-07-21 drh: ** %z A string that should be freed after use dbda8d6ce9 2007-07-21 drh: ** %d Insert an integer dbda8d6ce9 2007-07-21 drh: ** %T Insert a token dbda8d6ce9 2007-07-21 drh: ** %S Insert the first element of a SrcList dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function should be used to report any error that occurs whilst dbda8d6ce9 2007-07-21 drh: ** compiling an SQL statement (i.e. within sqlite3_prepare()). The dbda8d6ce9 2007-07-21 drh: ** last thing the sqlite3_prepare() function does is copy the error dbda8d6ce9 2007-07-21 drh: ** stored by this function into the database handle using sqlite3Error(). dbda8d6ce9 2007-07-21 drh: ** Function sqlite3Error() should be used during statement execution dbda8d6ce9 2007-07-21 drh: ** (sqlite3_step() etc.). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: pParse->nErr++; c287665ba8 2007-09-14 drh: sqlite3_free(pParse->zErrMsg); dbda8d6ce9 2007-07-21 drh: va_start(ap, zFormat); c287665ba8 2007-09-14 drh: pParse->zErrMsg = sqlite3VMPrintf(pParse->db, zFormat, ap); dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: if( pParse->rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear the error message in pParse, if any dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ErrorClear(Parse *pParse){ c287665ba8 2007-09-14 drh: sqlite3_free(pParse->zErrMsg); dbda8d6ce9 2007-07-21 drh: pParse->zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: pParse->nErr = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert an SQL-style quoted string into a normal string by removing dbda8d6ce9 2007-07-21 drh: ** the quote characters. The conversion is done in-place. If the dbda8d6ce9 2007-07-21 drh: ** input does not begin with a quote character, then this routine dbda8d6ce9 2007-07-21 drh: ** is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2002-Feb-14: This routine is extended to remove MS-Access style dbda8d6ce9 2007-07-21 drh: ** brackets from around identifers. For example: "[a-b-c]" becomes dbda8d6ce9 2007-07-21 drh: ** "a-b-c". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Dequote(char *z){ dbda8d6ce9 2007-07-21 drh: int quote; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: if( z==0 ) return; dbda8d6ce9 2007-07-21 drh: quote = z[0]; dbda8d6ce9 2007-07-21 drh: switch( quote ){ dbda8d6ce9 2007-07-21 drh: case '\'': break; dbda8d6ce9 2007-07-21 drh: case '"': break; dbda8d6ce9 2007-07-21 drh: case '`': break; /* For MySQL compatibility */ dbda8d6ce9 2007-07-21 drh: case '[': quote = ']'; break; /* For MS SqlServer compatibility */ dbda8d6ce9 2007-07-21 drh: default: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=1, j=0; z[i]; i++){ dbda8d6ce9 2007-07-21 drh: if( z[i]==quote ){ dbda8d6ce9 2007-07-21 drh: if( z[i+1]==quote ){ dbda8d6ce9 2007-07-21 drh: z[j++] = quote; dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: z[j++] = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: z[j++] = z[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* An array to map all upper-case characters into their corresponding dbda8d6ce9 2007-07-21 drh: ** lower-case character. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = { dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ASCII dbda8d6ce9 2007-07-21 drh: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, dbda8d6ce9 2007-07-21 drh: 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, dbda8d6ce9 2007-07-21 drh: 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, dbda8d6ce9 2007-07-21 drh: 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, dbda8d6ce9 2007-07-21 drh: 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, dbda8d6ce9 2007-07-21 drh: 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, dbda8d6ce9 2007-07-21 drh: 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, dbda8d6ce9 2007-07-21 drh: 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, dbda8d6ce9 2007-07-21 drh: 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, dbda8d6ce9 2007-07-21 drh: 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, dbda8d6ce9 2007-07-21 drh: 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, dbda8d6ce9 2007-07-21 drh: 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, dbda8d6ce9 2007-07-21 drh: 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, dbda8d6ce9 2007-07-21 drh: 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, dbda8d6ce9 2007-07-21 drh: 252,253,254,255 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_EBCDIC dbda8d6ce9 2007-07-21 drh: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */ dbda8d6ce9 2007-07-21 drh: 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */ dbda8d6ce9 2007-07-21 drh: 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */ dbda8d6ce9 2007-07-21 drh: 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */ dbda8d6ce9 2007-07-21 drh: 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */ dbda8d6ce9 2007-07-21 drh: 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */ dbda8d6ce9 2007-07-21 drh: 96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */ dbda8d6ce9 2007-07-21 drh: 112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */ dbda8d6ce9 2007-07-21 drh: 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */ dbda8d6ce9 2007-07-21 drh: 144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */ dbda8d6ce9 2007-07-21 drh: 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */ dbda8d6ce9 2007-07-21 drh: 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */ dbda8d6ce9 2007-07-21 drh: 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */ dbda8d6ce9 2007-07-21 drh: 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */ dbda8d6ce9 2007-07-21 drh: 224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */ dbda8d6ce9 2007-07-21 drh: 239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #define UpperToLower sqlite3UpperToLower dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Some systems have stricmp(). Others have strcasecmp(). Because dbda8d6ce9 2007-07-21 drh: ** there is no consistency, we will define our own. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){ dbda8d6ce9 2007-07-21 drh: register unsigned char *a, *b; dbda8d6ce9 2007-07-21 drh: a = (unsigned char *)zLeft; dbda8d6ce9 2007-07-21 drh: b = (unsigned char *)zRight; dbda8d6ce9 2007-07-21 drh: while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } dbda8d6ce9 2007-07-21 drh: return UpperToLower[*a] - UpperToLower[*b]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){ dbda8d6ce9 2007-07-21 drh: register unsigned char *a, *b; dbda8d6ce9 2007-07-21 drh: a = (unsigned char *)zLeft; dbda8d6ce9 2007-07-21 drh: b = (unsigned char *)zRight; dbda8d6ce9 2007-07-21 drh: while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } dbda8d6ce9 2007-07-21 drh: return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if z is a pure numeric string. Return FALSE if the dbda8d6ce9 2007-07-21 drh: ** string contains any character which is not part of a number. If dbda8d6ce9 2007-07-21 drh: ** the string is numeric and contains the '.' character, set *realnum dbda8d6ce9 2007-07-21 drh: ** to TRUE (otherwise FALSE). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An empty string is considered non-numeric. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IsNumber(const char *z, int *realnum, u8 enc){ dbda8d6ce9 2007-07-21 drh: int incr = (enc==SQLITE_UTF8?1:2); dbda8d6ce9 2007-07-21 drh: if( enc==SQLITE_UTF16BE ) z++; dbda8d6ce9 2007-07-21 drh: if( *z=='-' || *z=='+' ) z += incr; dbda8d6ce9 2007-07-21 drh: if( !isdigit(*(u8*)z) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: z += incr; dbda8d6ce9 2007-07-21 drh: if( realnum ) *realnum = 0; dbda8d6ce9 2007-07-21 drh: while( isdigit(*(u8*)z) ){ z += incr; } dbda8d6ce9 2007-07-21 drh: if( *z=='.' ){ dbda8d6ce9 2007-07-21 drh: z += incr; dbda8d6ce9 2007-07-21 drh: if( !isdigit(*(u8*)z) ) return 0; dbda8d6ce9 2007-07-21 drh: while( isdigit(*(u8*)z) ){ z += incr; } dbda8d6ce9 2007-07-21 drh: if( realnum ) *realnum = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( *z=='e' || *z=='E' ){ dbda8d6ce9 2007-07-21 drh: z += incr; dbda8d6ce9 2007-07-21 drh: if( *z=='+' || *z=='-' ) z += incr; dbda8d6ce9 2007-07-21 drh: if( !isdigit(*(u8*)z) ) return 0; dbda8d6ce9 2007-07-21 drh: while( isdigit(*(u8*)z) ){ z += incr; } dbda8d6ce9 2007-07-21 drh: if( realnum ) *realnum = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return *z==0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The string z[] is an ascii representation of a real number. dbda8d6ce9 2007-07-21 drh: ** Convert this string to a double. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine assumes that z[] really is a valid number. If it dbda8d6ce9 2007-07-21 drh: ** is not, the result is undefined. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is used instead of the library atof() function because dbda8d6ce9 2007-07-21 drh: ** the library atof() might want to use "," as the decimal point instead dbda8d6ce9 2007-07-21 drh: ** of "." depending on how locale is set. But that would cause problems dbda8d6ce9 2007-07-21 drh: ** for SQL. So this routine always uses "." regardless of locale. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: int sign = 1; dbda8d6ce9 2007-07-21 drh: const char *zBegin = z; dbda8d6ce9 2007-07-21 drh: LONGDOUBLE_TYPE v1 = 0.0; dbda8d6ce9 2007-07-21 drh: while( isspace(*(u8*)z) ) z++; dbda8d6ce9 2007-07-21 drh: if( *z=='-' ){ dbda8d6ce9 2007-07-21 drh: sign = -1; dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: }else if( *z=='+' ){ dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( isdigit(*(u8*)z) ){ dbda8d6ce9 2007-07-21 drh: v1 = v1*10.0 + (*z - '0'); dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( *z=='.' ){ dbda8d6ce9 2007-07-21 drh: LONGDOUBLE_TYPE divisor = 1.0; dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: while( isdigit(*(u8*)z) ){ dbda8d6ce9 2007-07-21 drh: v1 = v1*10.0 + (*z - '0'); dbda8d6ce9 2007-07-21 drh: divisor *= 10.0; dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: v1 /= divisor; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( *z=='e' || *z=='E' ){ dbda8d6ce9 2007-07-21 drh: int esign = 1; dbda8d6ce9 2007-07-21 drh: int eval = 0; dbda8d6ce9 2007-07-21 drh: LONGDOUBLE_TYPE scale = 1.0; dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: if( *z=='-' ){ dbda8d6ce9 2007-07-21 drh: esign = -1; dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: }else if( *z=='+' ){ dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( isdigit(*(u8*)z) ){ dbda8d6ce9 2007-07-21 drh: eval = eval*10 + *z - '0'; dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; } dbda8d6ce9 2007-07-21 drh: while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; } dbda8d6ce9 2007-07-21 drh: while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; } dbda8d6ce9 2007-07-21 drh: while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; } dbda8d6ce9 2007-07-21 drh: if( esign<0 ){ dbda8d6ce9 2007-07-21 drh: v1 /= scale; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: v1 *= scale; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pResult = sign<0 ? -v1 : v1; dbda8d6ce9 2007-07-21 drh: return z - zBegin; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: return sqlite3Atoi64(z, pResult); dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_FLOATING_POINT */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compare the 19-character string zNum against the text representation dbda8d6ce9 2007-07-21 drh: ** value 2^63: 9223372036854775808. Return negative, zero, or positive dbda8d6ce9 2007-07-21 drh: ** if zNum is less than, equal to, or greater than the string. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Unlike memcmp() this routine is guaranteed to return the difference dbda8d6ce9 2007-07-21 drh: ** in the values of the last digit if the only difference is in the dbda8d6ce9 2007-07-21 drh: ** last digit. So, for example, dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** compare2pow63("9223372036854775800") dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** will return -8. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int compare2pow63(const char *zNum){ dbda8d6ce9 2007-07-21 drh: int c; dbda8d6ce9 2007-07-21 drh: c = memcmp(zNum,"922337203685477580",18); dbda8d6ce9 2007-07-21 drh: if( c==0 ){ dbda8d6ce9 2007-07-21 drh: c = zNum[18] - '8'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return c; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if zNum is a 64-bit signed integer and write dbda8d6ce9 2007-07-21 drh: ** the value of the integer into *pNum. If zNum is not an integer dbda8d6ce9 2007-07-21 drh: ** or is an integer that is too large to be expressed with 64 bits, dbda8d6ce9 2007-07-21 drh: ** then return false. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When this routine was originally written it dealt with only dbda8d6ce9 2007-07-21 drh: ** 32-bit numbers. At that time, it was much faster than the dbda8d6ce9 2007-07-21 drh: ** atoi() library routine in RedHat 7.2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum){ dbda8d6ce9 2007-07-21 drh: i64 v = 0; dbda8d6ce9 2007-07-21 drh: int neg; dbda8d6ce9 2007-07-21 drh: int i, c; dbda8d6ce9 2007-07-21 drh: while( isspace(*(u8*)zNum) ) zNum++; dbda8d6ce9 2007-07-21 drh: if( *zNum=='-' ){ dbda8d6ce9 2007-07-21 drh: neg = 1; dbda8d6ce9 2007-07-21 drh: zNum++; dbda8d6ce9 2007-07-21 drh: }else if( *zNum=='+' ){ dbda8d6ce9 2007-07-21 drh: neg = 0; dbda8d6ce9 2007-07-21 drh: zNum++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: neg = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */ dbda8d6ce9 2007-07-21 drh: for(i=0; (c=zNum[i])>='0' && c<='9'; i++){ dbda8d6ce9 2007-07-21 drh: v = v*10 + c - '0'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pNum = neg ? -v : v; dbda8d6ce9 2007-07-21 drh: if( c!=0 || i==0 || i>19 ){ dbda8d6ce9 2007-07-21 drh: /* zNum is empty or contains non-numeric text or is longer dbda8d6ce9 2007-07-21 drh: ** than 19 digits (thus guaranting that it is too large) */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else if( i<19 ){ dbda8d6ce9 2007-07-21 drh: /* Less than 19 digits, so we know that it fits in 64 bits */ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* 19-digit numbers must be no larger than 9223372036854775807 if positive dbda8d6ce9 2007-07-21 drh: ** or 9223372036854775808 if negative. Note that 9223372036854665808 dbda8d6ce9 2007-07-21 drh: ** is 2^63. */ dbda8d6ce9 2007-07-21 drh: return compare2pow63(zNum)<neg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The string zNum represents an integer. There might be some other dbda8d6ce9 2007-07-21 drh: ** information following the integer too, but that part is ignored. dbda8d6ce9 2007-07-21 drh: ** If the integer that the prefix of zNum represents will fit in a dbda8d6ce9 2007-07-21 drh: ** 64-bit signed integer, return TRUE. Otherwise return FALSE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns FALSE for the string -9223372036854775808 even that dbda8d6ce9 2007-07-21 drh: ** that number will, in theory fit in a 64-bit integer. Positive dbda8d6ce9 2007-07-21 drh: ** 9223373036854775808 will not fit in 64 bits. So it seems safer to return dbda8d6ce9 2007-07-21 drh: ** false. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *zNum){ dbda8d6ce9 2007-07-21 drh: int i, c; dbda8d6ce9 2007-07-21 drh: int neg = 0; dbda8d6ce9 2007-07-21 drh: if( *zNum=='-' ){ dbda8d6ce9 2007-07-21 drh: neg = 1; dbda8d6ce9 2007-07-21 drh: zNum++; dbda8d6ce9 2007-07-21 drh: }else if( *zNum=='+' ){ dbda8d6ce9 2007-07-21 drh: zNum++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( *zNum=='0' ){ dbda8d6ce9 2007-07-21 drh: zNum++; /* Skip leading zeros. Ticket #2454 */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; (c=zNum[i])>='0' && c<='9'; i++){} dbda8d6ce9 2007-07-21 drh: if( i<19 ){ dbda8d6ce9 2007-07-21 drh: /* Guaranteed to fit if less than 19 digits */ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: }else if( i>19 ){ dbda8d6ce9 2007-07-21 drh: /* Guaranteed to be too big if greater than 19 digits */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Compare against 2^63. */ dbda8d6ce9 2007-07-21 drh: return compare2pow63(zNum)<neg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If zNum represents an integer that will fit in 32-bits, then set dbda8d6ce9 2007-07-21 drh: ** *pValue to that integer and return true. Otherwise return false. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Any non-numeric characters that following zNum are ignored. dbda8d6ce9 2007-07-21 drh: ** This is different from sqlite3Atoi64() which requires the dbda8d6ce9 2007-07-21 drh: ** input number to be zero-terminated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ dbda8d6ce9 2007-07-21 drh: sqlite_int64 v = 0; dbda8d6ce9 2007-07-21 drh: int i, c; dbda8d6ce9 2007-07-21 drh: int neg = 0; dbda8d6ce9 2007-07-21 drh: if( zNum[0]=='-' ){ dbda8d6ce9 2007-07-21 drh: neg = 1; dbda8d6ce9 2007-07-21 drh: zNum++; dbda8d6ce9 2007-07-21 drh: }else if( zNum[0]=='+' ){ dbda8d6ce9 2007-07-21 drh: zNum++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( zNum[0]=='0' ) zNum++; c287665ba8 2007-09-14 drh: for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ dbda8d6ce9 2007-07-21 drh: v = v*10 + c; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* The longest decimal representation of a 32 bit integer is 10 digits: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** 1234567890 c287665ba8 2007-09-14 drh: ** 2^31 -> 2147483648 c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( i>10 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( v-neg>2147483647 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( neg ){ dbda8d6ce9 2007-07-21 drh: v = -v; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pValue = (int)v; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to make sure we have a valid db pointer. This test is not dbda8d6ce9 2007-07-21 drh: ** foolproof but it does provide some measure of protection against dbda8d6ce9 2007-07-21 drh: ** misuse of the interface such as passing in db pointers that are dbda8d6ce9 2007-07-21 drh: ** NULL or which have been previously closed. If this routine returns dbda8d6ce9 2007-07-21 drh: ** TRUE it means that the db pointer is invalid and should not be dbda8d6ce9 2007-07-21 drh: ** dereferenced for any reason. The calling function should invoke dbda8d6ce9 2007-07-21 drh: ** SQLITE_MISUSE immediately. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SafetyCheck(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: int magic; dbda8d6ce9 2007-07-21 drh: if( db==0 ) return 1; dbda8d6ce9 2007-07-21 drh: magic = db->magic; dbda8d6ce9 2007-07-21 drh: if( magic!=SQLITE_MAGIC_CLOSED && dbda8d6ce9 2007-07-21 drh: magic!=SQLITE_MAGIC_OPEN && dbda8d6ce9 2007-07-21 drh: magic!=SQLITE_MAGIC_BUSY ) return 1; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The variable-length integer encoding is as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** KEY: dbda8d6ce9 2007-07-21 drh: ** A = 0xxxxxxx 7 bits of data and one flag bit dbda8d6ce9 2007-07-21 drh: ** B = 1xxxxxxx 7 bits of data and one flag bit dbda8d6ce9 2007-07-21 drh: ** C = xxxxxxxx 8 bits of data dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 7 bits - A dbda8d6ce9 2007-07-21 drh: ** 14 bits - BA dbda8d6ce9 2007-07-21 drh: ** 21 bits - BBA dbda8d6ce9 2007-07-21 drh: ** 28 bits - BBBA dbda8d6ce9 2007-07-21 drh: ** 35 bits - BBBBA dbda8d6ce9 2007-07-21 drh: ** 42 bits - BBBBBA dbda8d6ce9 2007-07-21 drh: ** 49 bits - BBBBBBA dbda8d6ce9 2007-07-21 drh: ** 56 bits - BBBBBBBA dbda8d6ce9 2007-07-21 drh: ** 64 bits - BBBBBBBBC dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write a 64-bit variable-length integer to memory starting at p[0]. dbda8d6ce9 2007-07-21 drh: ** The length of data write will be between 1 and 9 bytes. The number dbda8d6ce9 2007-07-21 drh: ** of bytes written is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A variable-length integer consists of the lower 7 bits of each byte dbda8d6ce9 2007-07-21 drh: ** for all bytes that have the 8th bit set and one byte with the 8th dbda8d6ce9 2007-07-21 drh: ** bit clear. Except, if we get to the 9th byte, it stores the full dbda8d6ce9 2007-07-21 drh: ** 8 bits and is the last byte. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ dbda8d6ce9 2007-07-21 drh: int i, j, n; dbda8d6ce9 2007-07-21 drh: u8 buf[10]; dbda8d6ce9 2007-07-21 drh: if( v & (((u64)0xff000000)<<32) ){ dbda8d6ce9 2007-07-21 drh: p[8] = v; dbda8d6ce9 2007-07-21 drh: v >>= 8; dbda8d6ce9 2007-07-21 drh: for(i=7; i>=0; i--){ dbda8d6ce9 2007-07-21 drh: p[i] = (v & 0x7f) | 0x80; dbda8d6ce9 2007-07-21 drh: v >>= 7; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 9; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: n = 0; dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: buf[n++] = (v & 0x7f) | 0x80; dbda8d6ce9 2007-07-21 drh: v >>= 7; dbda8d6ce9 2007-07-21 drh: }while( v!=0 ); dbda8d6ce9 2007-07-21 drh: buf[0] &= 0x7f; dbda8d6ce9 2007-07-21 drh: assert( n<=9 ); dbda8d6ce9 2007-07-21 drh: for(i=0, j=n-1; j>=0; j--, i++){ dbda8d6ce9 2007-07-21 drh: p[i] = buf[j]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read a 64-bit variable-length integer from memory starting at p[0]. dbda8d6ce9 2007-07-21 drh: ** Return the number of bytes read. The value is stored in *v. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3GetVarint(const unsigned char *p, u64 *v){ dbda8d6ce9 2007-07-21 drh: u32 x; dbda8d6ce9 2007-07-21 drh: u64 x64; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: unsigned char c; dbda8d6ce9 2007-07-21 drh: if( ((c = p[0]) & 0x80)==0 ){ dbda8d6ce9 2007-07-21 drh: *v = c; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: x = c & 0x7f; dbda8d6ce9 2007-07-21 drh: if( ((c = p[1]) & 0x80)==0 ){ dbda8d6ce9 2007-07-21 drh: *v = (x<<7) | c; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: x = (x<<7) | (c&0x7f); dbda8d6ce9 2007-07-21 drh: if( ((c = p[2]) & 0x80)==0 ){ dbda8d6ce9 2007-07-21 drh: *v = (x<<7) | c; dbda8d6ce9 2007-07-21 drh: return 3; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: x = (x<<7) | (c&0x7f); dbda8d6ce9 2007-07-21 drh: if( ((c = p[3]) & 0x80)==0 ){ dbda8d6ce9 2007-07-21 drh: *v = (x<<7) | c; dbda8d6ce9 2007-07-21 drh: return 4; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: x64 = (x<<7) | (c&0x7f); dbda8d6ce9 2007-07-21 drh: n = 4; dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: c = p[n++]; dbda8d6ce9 2007-07-21 drh: if( n==9 ){ dbda8d6ce9 2007-07-21 drh: x64 = (x64<<8) | c; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: x64 = (x64<<7) | (c&0x7f); dbda8d6ce9 2007-07-21 drh: }while( (c & 0x80)!=0 ); dbda8d6ce9 2007-07-21 drh: *v = x64; dbda8d6ce9 2007-07-21 drh: return n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read a 32-bit variable-length integer from memory starting at p[0]. dbda8d6ce9 2007-07-21 drh: ** Return the number of bytes read. The value is stored in *v. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3GetVarint32(const unsigned char *p, u32 *v){ dbda8d6ce9 2007-07-21 drh: u32 x; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: unsigned char c; dbda8d6ce9 2007-07-21 drh: if( ((signed char*)p)[0]>=0 ){ dbda8d6ce9 2007-07-21 drh: *v = p[0]; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: x = p[0] & 0x7f; dbda8d6ce9 2007-07-21 drh: if( ((signed char*)p)[1]>=0 ){ dbda8d6ce9 2007-07-21 drh: *v = (x<<7) | p[1]; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: x = (x<<7) | (p[1] & 0x7f); dbda8d6ce9 2007-07-21 drh: n = 2; dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: x = (x<<7) | ((c = p[n++])&0x7f); dbda8d6ce9 2007-07-21 drh: }while( (c & 0x80)!=0 && n<9 ); dbda8d6ce9 2007-07-21 drh: *v = x; dbda8d6ce9 2007-07-21 drh: return n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of bytes that will be needed to store the given dbda8d6ce9 2007-07-21 drh: ** 64-bit integer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VarintLen(u64 v){ dbda8d6ce9 2007-07-21 drh: int i = 0; dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: v >>= 7; dbda8d6ce9 2007-07-21 drh: }while( v!=0 && i<9 ); dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read or write a four-byte big-endian integer value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ dbda8d6ce9 2007-07-21 drh: return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ dbda8d6ce9 2007-07-21 drh: p[0] = v>>24; dbda8d6ce9 2007-07-21 drh: p[1] = v>>16; dbda8d6ce9 2007-07-21 drh: p[2] = v>>8; dbda8d6ce9 2007-07-21 drh: p[3] = v; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) \ dbda8d6ce9 2007-07-21 drh: || defined(SQLITE_TEST) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Translate a single byte of Hex into an integer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int hexToInt(int h){ dbda8d6ce9 2007-07-21 drh: if( h>='0' && h<='9' ){ dbda8d6ce9 2007-07-21 drh: return h - '0'; dbda8d6ce9 2007-07-21 drh: }else if( h>='a' && h<='f' ){ dbda8d6ce9 2007-07-21 drh: return h - 'a' + 10; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( h>='A' && h<='F' ); dbda8d6ce9 2007-07-21 drh: return h - 'A' + 10; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC || SQLITE_TEST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary dbda8d6ce9 2007-07-21 drh: ** value. Return a pointer to its binary value. Space to hold the dbda8d6ce9 2007-07-21 drh: ** binary value has been obtained from malloc and must be freed by dbda8d6ce9 2007-07-21 drh: ** the calling routine. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z){ dbda8d6ce9 2007-07-21 drh: char *zBlob; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int n = strlen(z); dbda8d6ce9 2007-07-21 drh: if( n%2 ) return 0; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: zBlob = (char *)sqlite3DbMallocRaw(db, n/2); dbda8d6ce9 2007-07-21 drh: if( zBlob ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<n; i+=2){ dbda8d6ce9 2007-07-21 drh: zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zBlob; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY. dbda8d6ce9 2007-07-21 drh: ** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN dbda8d6ce9 2007-07-21 drh: ** when this routine is called. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is called when entering an SQLite API. The SQLITE_MAGIC_OPEN dbda8d6ce9 2007-07-21 drh: ** value indicates that the database connection passed into the API is dbda8d6ce9 2007-07-21 drh: ** open and is not being used by another thread. By changing the value dbda8d6ce9 2007-07-21 drh: ** to SQLITE_MAGIC_BUSY we indicate that the connection is in use. dbda8d6ce9 2007-07-21 drh: ** sqlite3SafetyOff() below will change the value back to SQLITE_MAGIC_OPEN dbda8d6ce9 2007-07-21 drh: ** when the API exits. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is a attempt to detect if two threads use the dbda8d6ce9 2007-07-21 drh: ** same sqlite* pointer at the same time. There is a race dbda8d6ce9 2007-07-21 drh: ** condition so it is possible that the error is not detected. dbda8d6ce9 2007-07-21 drh: ** But usually the problem will be seen. The result will be an dbda8d6ce9 2007-07-21 drh: ** error which can be used to debug the application that is dbda8d6ce9 2007-07-21 drh: ** using SQLite incorrectly. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Ticket #202: If db->magic is not a valid open value, take care not dbda8d6ce9 2007-07-21 drh: ** to modify the db structure at all. It could be that db is a stale dbda8d6ce9 2007-07-21 drh: ** pointer. In other words, it could be that there has been a prior dbda8d6ce9 2007-07-21 drh: ** call to sqlite3_close(db) and db has been deallocated. And we do dbda8d6ce9 2007-07-21 drh: ** not want to write into deallocated memory. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SafetyOn(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: if( db->magic==SQLITE_MAGIC_OPEN ){ dbda8d6ce9 2007-07-21 drh: db->magic = SQLITE_MAGIC_BUSY; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else if( db->magic==SQLITE_MAGIC_BUSY ){ dbda8d6ce9 2007-07-21 drh: db->magic = SQLITE_MAGIC_ERROR; dbda8d6ce9 2007-07-21 drh: db->u1.isInterrupted = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN. dbda8d6ce9 2007-07-21 drh: ** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY dbda8d6ce9 2007-07-21 drh: ** when this routine is called. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SafetyOff(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: if( db->magic==SQLITE_MAGIC_BUSY ){ dbda8d6ce9 2007-07-21 drh: db->magic = SQLITE_MAGIC_OPEN; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else { dbda8d6ce9 2007-07-21 drh: db->magic = SQLITE_MAGIC_ERROR; dbda8d6ce9 2007-07-21 drh: db->u1.isInterrupted = 1; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of util.c ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file hash.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 22 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This is the implementation of generic hash-tables dbda8d6ce9 2007-07-21 drh: ** used in SQLite. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: hash.c,v 1.24 2007/09/04 14:31:47 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Turn bulk memory into a hash table object by initializing the dbda8d6ce9 2007-07-21 drh: ** fields of the Hash structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** "pNew" is a pointer to the hash table that is to be initialized. dbda8d6ce9 2007-07-21 drh: ** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER, dbda8d6ce9 2007-07-21 drh: ** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass dbda8d6ce9 2007-07-21 drh: ** determines what kind of key the hash table will use. "copyKey" is dbda8d6ce9 2007-07-21 drh: ** true if the hash table should make its own private copy of keys and dbda8d6ce9 2007-07-21 drh: ** false if it should just use the supplied pointer. CopyKey only makes dbda8d6ce9 2007-07-21 drh: ** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored dbda8d6ce9 2007-07-21 drh: ** for other key classes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){ dbda8d6ce9 2007-07-21 drh: assert( pNew!=0 ); dbda8d6ce9 2007-07-21 drh: assert( keyClass>=SQLITE_HASH_STRING && keyClass<=SQLITE_HASH_BINARY ); dbda8d6ce9 2007-07-21 drh: pNew->keyClass = keyClass; dbda8d6ce9 2007-07-21 drh: #if 0 dbda8d6ce9 2007-07-21 drh: if( keyClass==SQLITE_HASH_POINTER || keyClass==SQLITE_HASH_INT ) copyKey = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: pNew->copyKey = copyKey; dbda8d6ce9 2007-07-21 drh: pNew->first = 0; dbda8d6ce9 2007-07-21 drh: pNew->count = 0; dbda8d6ce9 2007-07-21 drh: pNew->htsize = 0; dbda8d6ce9 2007-07-21 drh: pNew->ht = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Remove all entries from a hash table. Reclaim all memory. dbda8d6ce9 2007-07-21 drh: ** Call this routine to delete a hash table or to reset a hash table dbda8d6ce9 2007-07-21 drh: ** to the empty state. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){ dbda8d6ce9 2007-07-21 drh: HashElem *elem; /* For looping over all elements of the table */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pH!=0 ); dbda8d6ce9 2007-07-21 drh: elem = pH->first; dbda8d6ce9 2007-07-21 drh: pH->first = 0; c287665ba8 2007-09-14 drh: if( pH->ht ) sqlite3_free(pH->ht); dbda8d6ce9 2007-07-21 drh: pH->ht = 0; dbda8d6ce9 2007-07-21 drh: pH->htsize = 0; dbda8d6ce9 2007-07-21 drh: while( elem ){ dbda8d6ce9 2007-07-21 drh: HashElem *next_elem = elem->next; dbda8d6ce9 2007-07-21 drh: if( pH->copyKey && elem->pKey ){ c287665ba8 2007-09-14 drh: sqlite3_free(elem->pKey); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(elem); dbda8d6ce9 2007-07-21 drh: elem = next_elem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pH->count = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if 0 /* NOT USED */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Hash and comparison functions when the mode is SQLITE_HASH_INT dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int intHash(const void *pKey, int nKey){ dbda8d6ce9 2007-07-21 drh: return nKey ^ (nKey<<8) ^ (nKey>>8); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){ dbda8d6ce9 2007-07-21 drh: return n2 - n1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if 0 /* NOT USED */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Hash and comparison functions when the mode is SQLITE_HASH_POINTER dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int ptrHash(const void *pKey, int nKey){ dbda8d6ce9 2007-07-21 drh: uptr x = Addr(pKey); dbda8d6ce9 2007-07-21 drh: return x ^ (x<<8) ^ (x>>8); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ dbda8d6ce9 2007-07-21 drh: if( pKey1==pKey2 ) return 0; dbda8d6ce9 2007-07-21 drh: if( pKey1<pKey2 ) return -1; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Hash and comparison functions when the mode is SQLITE_HASH_STRING dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int strHash(const void *pKey, int nKey){ dbda8d6ce9 2007-07-21 drh: const char *z = (const char *)pKey; dbda8d6ce9 2007-07-21 drh: int h = 0; dbda8d6ce9 2007-07-21 drh: if( nKey<=0 ) nKey = strlen(z); dbda8d6ce9 2007-07-21 drh: while( nKey > 0 ){ dbda8d6ce9 2007-07-21 drh: h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++]; dbda8d6ce9 2007-07-21 drh: nKey--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return h & 0x7fffffff; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){ dbda8d6ce9 2007-07-21 drh: if( n1!=n2 ) return 1; dbda8d6ce9 2007-07-21 drh: return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Hash and comparison functions when the mode is SQLITE_HASH_BINARY dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int binHash(const void *pKey, int nKey){ dbda8d6ce9 2007-07-21 drh: int h = 0; dbda8d6ce9 2007-07-21 drh: const char *z = (const char *)pKey; dbda8d6ce9 2007-07-21 drh: while( nKey-- > 0 ){ dbda8d6ce9 2007-07-21 drh: h = (h<<3) ^ h ^ *(z++); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return h & 0x7fffffff; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ dbda8d6ce9 2007-07-21 drh: if( n1!=n2 ) return 1; dbda8d6ce9 2007-07-21 drh: return memcmp(pKey1,pKey2,n1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a pointer to the appropriate hash function given the key class. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The C syntax in this function definition may be unfamilar to some dbda8d6ce9 2007-07-21 drh: ** programmers, so we provide the following additional explanation: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The name of the function is "hashFunction". The function takes a dbda8d6ce9 2007-07-21 drh: ** single parameter "keyClass". The return value of hashFunction() dbda8d6ce9 2007-07-21 drh: ** is a pointer to another function. Specifically, the return value dbda8d6ce9 2007-07-21 drh: ** of hashFunction() is a pointer to a function that takes two parameters dbda8d6ce9 2007-07-21 drh: ** with types "const void*" and "int" and returns an "int". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int (*hashFunction(int keyClass))(const void*,int){ dbda8d6ce9 2007-07-21 drh: #if 0 /* HASH_INT and HASH_POINTER are never used */ dbda8d6ce9 2007-07-21 drh: switch( keyClass ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_HASH_INT: return &intHash; dbda8d6ce9 2007-07-21 drh: case SQLITE_HASH_POINTER: return &ptrHash; dbda8d6ce9 2007-07-21 drh: case SQLITE_HASH_STRING: return &strHash; dbda8d6ce9 2007-07-21 drh: case SQLITE_HASH_BINARY: return &binHash;; dbda8d6ce9 2007-07-21 drh: default: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: if( keyClass==SQLITE_HASH_STRING ){ dbda8d6ce9 2007-07-21 drh: return &strHash; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( keyClass==SQLITE_HASH_BINARY ); dbda8d6ce9 2007-07-21 drh: return &binHash; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a pointer to the appropriate hash function given the key class. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For help in interpreted the obscure C code in the function definition, dbda8d6ce9 2007-07-21 drh: ** see the header comment on the previous function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ dbda8d6ce9 2007-07-21 drh: #if 0 /* HASH_INT and HASH_POINTER are never used */ dbda8d6ce9 2007-07-21 drh: switch( keyClass ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_HASH_INT: return &intCompare; dbda8d6ce9 2007-07-21 drh: case SQLITE_HASH_POINTER: return &ptrCompare; dbda8d6ce9 2007-07-21 drh: case SQLITE_HASH_STRING: return &strCompare; dbda8d6ce9 2007-07-21 drh: case SQLITE_HASH_BINARY: return &binCompare; dbda8d6ce9 2007-07-21 drh: default: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: if( keyClass==SQLITE_HASH_STRING ){ dbda8d6ce9 2007-07-21 drh: return &strCompare; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( keyClass==SQLITE_HASH_BINARY ); dbda8d6ce9 2007-07-21 drh: return &binCompare; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Link an element into the hash table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void insertElement( dbda8d6ce9 2007-07-21 drh: Hash *pH, /* The complete hash table */ dbda8d6ce9 2007-07-21 drh: struct _ht *pEntry, /* The entry into which pNew is inserted */ dbda8d6ce9 2007-07-21 drh: HashElem *pNew /* The element to be inserted */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: HashElem *pHead; /* First element already in pEntry */ dbda8d6ce9 2007-07-21 drh: pHead = pEntry->chain; dbda8d6ce9 2007-07-21 drh: if( pHead ){ dbda8d6ce9 2007-07-21 drh: pNew->next = pHead; dbda8d6ce9 2007-07-21 drh: pNew->prev = pHead->prev; dbda8d6ce9 2007-07-21 drh: if( pHead->prev ){ pHead->prev->next = pNew; } dbda8d6ce9 2007-07-21 drh: else { pH->first = pNew; } dbda8d6ce9 2007-07-21 drh: pHead->prev = pNew; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pNew->next = pH->first; dbda8d6ce9 2007-07-21 drh: if( pH->first ){ pH->first->prev = pNew; } dbda8d6ce9 2007-07-21 drh: pNew->prev = 0; dbda8d6ce9 2007-07-21 drh: pH->first = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pEntry->count++; dbda8d6ce9 2007-07-21 drh: pEntry->chain = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Resize the hash table so that it cantains "new_size" buckets. dbda8d6ce9 2007-07-21 drh: ** "new_size" must be a power of 2. The hash table might fail c287665ba8 2007-09-14 drh: ** to resize if sqlite3_malloc() fails. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void rehash(Hash *pH, int new_size){ dbda8d6ce9 2007-07-21 drh: struct _ht *new_ht; /* The new hash table */ dbda8d6ce9 2007-07-21 drh: HashElem *elem, *next_elem; /* For looping over existing elements */ dbda8d6ce9 2007-07-21 drh: int (*xHash)(const void*,int); /* The hash function */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( (new_size & (new_size-1))==0 ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* There is a call to sqlite3_malloc() inside rehash(). If there is c287665ba8 2007-09-14 drh: ** already an allocation at pH->ht, then if this malloc() fails it c287665ba8 2007-09-14 drh: ** is benign (since failing to resize a hash table is a performance c287665ba8 2007-09-14 drh: ** hit only, not a fatal error). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3MallocBenignFailure(pH->htsize>0); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) ); dbda8d6ce9 2007-07-21 drh: if( new_ht==0 ) return; c287665ba8 2007-09-14 drh: if( pH->ht ) sqlite3_free(pH->ht); dbda8d6ce9 2007-07-21 drh: pH->ht = new_ht; dbda8d6ce9 2007-07-21 drh: pH->htsize = new_size; dbda8d6ce9 2007-07-21 drh: xHash = hashFunction(pH->keyClass); dbda8d6ce9 2007-07-21 drh: for(elem=pH->first, pH->first=0; elem; elem = next_elem){ dbda8d6ce9 2007-07-21 drh: int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); dbda8d6ce9 2007-07-21 drh: next_elem = elem->next; dbda8d6ce9 2007-07-21 drh: insertElement(pH, &new_ht[h], elem); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This function (for internal use only) locates an element in an dbda8d6ce9 2007-07-21 drh: ** hash table that matches the given key. The hash for this key has dbda8d6ce9 2007-07-21 drh: ** already been computed and is passed as the 4th parameter. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static HashElem *findElementGivenHash( dbda8d6ce9 2007-07-21 drh: const Hash *pH, /* The pH to be searched */ dbda8d6ce9 2007-07-21 drh: const void *pKey, /* The key we are searching for */ dbda8d6ce9 2007-07-21 drh: int nKey, dbda8d6ce9 2007-07-21 drh: int h /* The hash for this key. */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: HashElem *elem; /* Used to loop thru the element list */ dbda8d6ce9 2007-07-21 drh: int count; /* Number of elements left to test */ dbda8d6ce9 2007-07-21 drh: int (*xCompare)(const void*,int,const void*,int); /* comparison function */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pH->ht ){ dbda8d6ce9 2007-07-21 drh: struct _ht *pEntry = &pH->ht[h]; dbda8d6ce9 2007-07-21 drh: elem = pEntry->chain; dbda8d6ce9 2007-07-21 drh: count = pEntry->count; dbda8d6ce9 2007-07-21 drh: xCompare = compareFunction(pH->keyClass); dbda8d6ce9 2007-07-21 drh: while( count-- && elem ){ dbda8d6ce9 2007-07-21 drh: if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ dbda8d6ce9 2007-07-21 drh: return elem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: elem = elem->next; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Remove a single entry from the hash table given a pointer to that dbda8d6ce9 2007-07-21 drh: ** element and a hash on the element's key. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void removeElementGivenHash( dbda8d6ce9 2007-07-21 drh: Hash *pH, /* The pH containing "elem" */ dbda8d6ce9 2007-07-21 drh: HashElem* elem, /* The element to be removed from the pH */ dbda8d6ce9 2007-07-21 drh: int h /* Hash value for the element */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: struct _ht *pEntry; dbda8d6ce9 2007-07-21 drh: if( elem->prev ){ dbda8d6ce9 2007-07-21 drh: elem->prev->next = elem->next; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pH->first = elem->next; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( elem->next ){ dbda8d6ce9 2007-07-21 drh: elem->next->prev = elem->prev; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pEntry = &pH->ht[h]; dbda8d6ce9 2007-07-21 drh: if( pEntry->chain==elem ){ dbda8d6ce9 2007-07-21 drh: pEntry->chain = elem->next; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pEntry->count--; dbda8d6ce9 2007-07-21 drh: if( pEntry->count<=0 ){ dbda8d6ce9 2007-07-21 drh: pEntry->chain = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pH->copyKey ){ c287665ba8 2007-09-14 drh: sqlite3_free(elem->pKey); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free( elem ); dbda8d6ce9 2007-07-21 drh: pH->count--; dbda8d6ce9 2007-07-21 drh: if( pH->count<=0 ){ dbda8d6ce9 2007-07-21 drh: assert( pH->first==0 ); dbda8d6ce9 2007-07-21 drh: assert( pH->count==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3HashClear(pH); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Attempt to locate an element of the hash table pH with a key c287665ba8 2007-09-14 drh: ** that matches pKey,nKey. Return a pointer to the corresponding c287665ba8 2007-09-14 drh: ** HashElem structure for this element if it is found, or NULL c287665ba8 2007-09-14 drh: ** otherwise. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE HashElem *sqlite3HashFindElem(const Hash *pH, const void *pKey, int nKey){ dbda8d6ce9 2007-07-21 drh: int h; /* A hash on key */ dbda8d6ce9 2007-07-21 drh: HashElem *elem; /* The element that matches key */ dbda8d6ce9 2007-07-21 drh: int (*xHash)(const void*,int); /* The hash function */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pH==0 || pH->ht==0 ) return 0; dbda8d6ce9 2007-07-21 drh: xHash = hashFunction(pH->keyClass); dbda8d6ce9 2007-07-21 drh: assert( xHash!=0 ); dbda8d6ce9 2007-07-21 drh: h = (*xHash)(pKey,nKey); dbda8d6ce9 2007-07-21 drh: assert( (pH->htsize & (pH->htsize-1))==0 ); dbda8d6ce9 2007-07-21 drh: elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); c287665ba8 2007-09-14 drh: return elem; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Attempt to locate an element of the hash table pH with a key c287665ba8 2007-09-14 drh: ** that matches pKey,nKey. Return the data for this element if it is c287665ba8 2007-09-14 drh: ** found, or NULL if there is no match. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){ c287665ba8 2007-09-14 drh: HashElem *elem; /* The element that matches key */ c287665ba8 2007-09-14 drh: elem = sqlite3HashFindElem(pH, pKey, nKey); dbda8d6ce9 2007-07-21 drh: return elem ? elem->data : 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Insert an element into the hash table pH. The key is pKey,nKey dbda8d6ce9 2007-07-21 drh: ** and the data is "data". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If no element exists with a matching key, then a new dbda8d6ce9 2007-07-21 drh: ** element is created. A copy of the key is made if the copyKey dbda8d6ce9 2007-07-21 drh: ** flag is set. NULL is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If another element already exists with the same key, then the dbda8d6ce9 2007-07-21 drh: ** new data replaces the old data and the old data is returned. dbda8d6ce9 2007-07-21 drh: ** The key is not copied in this instance. If a malloc fails, then dbda8d6ce9 2007-07-21 drh: ** the new data is returned and the hash table is unchanged. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the "data" parameter to this function is NULL, then the dbda8d6ce9 2007-07-21 drh: ** element corresponding to "key" is removed from the hash table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){ dbda8d6ce9 2007-07-21 drh: int hraw; /* Raw hash value of the key */ dbda8d6ce9 2007-07-21 drh: int h; /* the hash of the key modulo hash table size */ dbda8d6ce9 2007-07-21 drh: HashElem *elem; /* Used to loop thru the element list */ dbda8d6ce9 2007-07-21 drh: HashElem *new_elem; /* New element added to the pH */ dbda8d6ce9 2007-07-21 drh: int (*xHash)(const void*,int); /* The hash function */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pH!=0 ); dbda8d6ce9 2007-07-21 drh: xHash = hashFunction(pH->keyClass); dbda8d6ce9 2007-07-21 drh: assert( xHash!=0 ); dbda8d6ce9 2007-07-21 drh: hraw = (*xHash)(pKey, nKey); dbda8d6ce9 2007-07-21 drh: assert( (pH->htsize & (pH->htsize-1))==0 ); dbda8d6ce9 2007-07-21 drh: h = hraw & (pH->htsize-1); dbda8d6ce9 2007-07-21 drh: elem = findElementGivenHash(pH,pKey,nKey,h); dbda8d6ce9 2007-07-21 drh: if( elem ){ dbda8d6ce9 2007-07-21 drh: void *old_data = elem->data; dbda8d6ce9 2007-07-21 drh: if( data==0 ){ dbda8d6ce9 2007-07-21 drh: removeElementGivenHash(pH,elem,h); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: elem->data = data; c287665ba8 2007-09-14 drh: if( !pH->copyKey ){ c287665ba8 2007-09-14 drh: elem->pKey = (void *)pKey; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert(nKey==elem->nKey); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return old_data; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( data==0 ) return 0; c287665ba8 2007-09-14 drh: new_elem = (HashElem*)sqlite3_malloc( sizeof(HashElem) ); dbda8d6ce9 2007-07-21 drh: if( new_elem==0 ) return data; dbda8d6ce9 2007-07-21 drh: if( pH->copyKey && pKey!=0 ){ c287665ba8 2007-09-14 drh: new_elem->pKey = sqlite3_malloc( nKey ); dbda8d6ce9 2007-07-21 drh: if( new_elem->pKey==0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(new_elem); dbda8d6ce9 2007-07-21 drh: return data; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy((void*)new_elem->pKey, pKey, nKey); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: new_elem->pKey = (void*)pKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: new_elem->nKey = nKey; dbda8d6ce9 2007-07-21 drh: pH->count++; dbda8d6ce9 2007-07-21 drh: if( pH->htsize==0 ){ dbda8d6ce9 2007-07-21 drh: rehash(pH,8); dbda8d6ce9 2007-07-21 drh: if( pH->htsize==0 ){ dbda8d6ce9 2007-07-21 drh: pH->count = 0; dbda8d6ce9 2007-07-21 drh: if( pH->copyKey ){ c287665ba8 2007-09-14 drh: sqlite3_free(new_elem->pKey); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(new_elem); dbda8d6ce9 2007-07-21 drh: return data; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pH->count > pH->htsize ){ dbda8d6ce9 2007-07-21 drh: rehash(pH,pH->htsize*2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pH->htsize>0 ); dbda8d6ce9 2007-07-21 drh: assert( (pH->htsize & (pH->htsize-1))==0 ); dbda8d6ce9 2007-07-21 drh: h = hraw & (pH->htsize-1); dbda8d6ce9 2007-07-21 drh: insertElement(pH, &pH->ht[h], new_elem); dbda8d6ce9 2007-07-21 drh: new_elem->data = data; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of hash.c ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file opcodes.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* Automatically generated. Do not edit */ dbda8d6ce9 2007-07-21 drh: /* See the mkopcodec.awk script for details. */ dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ c287665ba8 2007-09-14 drh: static const char *const azName[] = { "?", c287665ba8 2007-09-14 drh: /* 1 */ "MemLoad", c287665ba8 2007-09-14 drh: /* 2 */ "VNext", c287665ba8 2007-09-14 drh: /* 3 */ "Column", c287665ba8 2007-09-14 drh: /* 4 */ "SetCookie", c287665ba8 2007-09-14 drh: /* 5 */ "IfMemPos", c287665ba8 2007-09-14 drh: /* 6 */ "Sequence", c287665ba8 2007-09-14 drh: /* 7 */ "MoveGt", c287665ba8 2007-09-14 drh: /* 8 */ "RowKey", c287665ba8 2007-09-14 drh: /* 9 */ "OpenWrite", c287665ba8 2007-09-14 drh: /* 10 */ "If", c287665ba8 2007-09-14 drh: /* 11 */ "Pop", c287665ba8 2007-09-14 drh: /* 12 */ "VRowid", c287665ba8 2007-09-14 drh: /* 13 */ "CollSeq", c287665ba8 2007-09-14 drh: /* 14 */ "OpenRead", c287665ba8 2007-09-14 drh: /* 15 */ "Expire", c287665ba8 2007-09-14 drh: /* 16 */ "Not", c287665ba8 2007-09-14 drh: /* 17 */ "AutoCommit", c287665ba8 2007-09-14 drh: /* 18 */ "IntegrityCk", c287665ba8 2007-09-14 drh: /* 19 */ "Sort", c287665ba8 2007-09-14 drh: /* 20 */ "Function", c287665ba8 2007-09-14 drh: /* 21 */ "Noop", c287665ba8 2007-09-14 drh: /* 22 */ "Return", c287665ba8 2007-09-14 drh: /* 23 */ "NewRowid", c287665ba8 2007-09-14 drh: /* 24 */ "IfMemNeg", c287665ba8 2007-09-14 drh: /* 25 */ "Variable", c287665ba8 2007-09-14 drh: /* 26 */ "String", c287665ba8 2007-09-14 drh: /* 27 */ "RealAffinity", c287665ba8 2007-09-14 drh: /* 28 */ "VRename", c287665ba8 2007-09-14 drh: /* 29 */ "ParseSchema", c287665ba8 2007-09-14 drh: /* 30 */ "VOpen", c287665ba8 2007-09-14 drh: /* 31 */ "Close", c287665ba8 2007-09-14 drh: /* 32 */ "CreateIndex", c287665ba8 2007-09-14 drh: /* 33 */ "IsUnique", c287665ba8 2007-09-14 drh: /* 34 */ "NotFound", c287665ba8 2007-09-14 drh: /* 35 */ "Int64", c287665ba8 2007-09-14 drh: /* 36 */ "MustBeInt", c287665ba8 2007-09-14 drh: /* 37 */ "Halt", c287665ba8 2007-09-14 drh: /* 38 */ "Rowid", c287665ba8 2007-09-14 drh: /* 39 */ "IdxLT", c287665ba8 2007-09-14 drh: /* 40 */ "AddImm", c287665ba8 2007-09-14 drh: /* 41 */ "Statement", c287665ba8 2007-09-14 drh: /* 42 */ "RowData", c287665ba8 2007-09-14 drh: /* 43 */ "MemMax", c287665ba8 2007-09-14 drh: /* 44 */ "Push", c287665ba8 2007-09-14 drh: /* 45 */ "NotExists", c287665ba8 2007-09-14 drh: /* 46 */ "MemIncr", c287665ba8 2007-09-14 drh: /* 47 */ "Gosub", c287665ba8 2007-09-14 drh: /* 48 */ "Integer", c287665ba8 2007-09-14 drh: /* 49 */ "MemInt", c287665ba8 2007-09-14 drh: /* 50 */ "Prev", c287665ba8 2007-09-14 drh: /* 51 */ "VColumn", c287665ba8 2007-09-14 drh: /* 52 */ "CreateTable", c287665ba8 2007-09-14 drh: /* 53 */ "Last", c287665ba8 2007-09-14 drh: /* 54 */ "IncrVacuum", c287665ba8 2007-09-14 drh: /* 55 */ "IdxRowid", c287665ba8 2007-09-14 drh: /* 56 */ "MakeIdxRec", c287665ba8 2007-09-14 drh: /* 57 */ "ResetCount", c287665ba8 2007-09-14 drh: /* 58 */ "FifoWrite", c287665ba8 2007-09-14 drh: /* 59 */ "Callback", c287665ba8 2007-09-14 drh: /* 60 */ "Or", c287665ba8 2007-09-14 drh: /* 61 */ "And", c287665ba8 2007-09-14 drh: /* 62 */ "ContextPush", c287665ba8 2007-09-14 drh: /* 63 */ "DropTrigger", c287665ba8 2007-09-14 drh: /* 64 */ "DropIndex", c287665ba8 2007-09-14 drh: /* 65 */ "IsNull", c287665ba8 2007-09-14 drh: /* 66 */ "NotNull", c287665ba8 2007-09-14 drh: /* 67 */ "Ne", c287665ba8 2007-09-14 drh: /* 68 */ "Eq", c287665ba8 2007-09-14 drh: /* 69 */ "Gt", c287665ba8 2007-09-14 drh: /* 70 */ "Le", c287665ba8 2007-09-14 drh: /* 71 */ "Lt", c287665ba8 2007-09-14 drh: /* 72 */ "Ge", c287665ba8 2007-09-14 drh: /* 73 */ "IdxGE", c287665ba8 2007-09-14 drh: /* 74 */ "BitAnd", c287665ba8 2007-09-14 drh: /* 75 */ "BitOr", c287665ba8 2007-09-14 drh: /* 76 */ "ShiftLeft", c287665ba8 2007-09-14 drh: /* 77 */ "ShiftRight", c287665ba8 2007-09-14 drh: /* 78 */ "Add", c287665ba8 2007-09-14 drh: /* 79 */ "Subtract", c287665ba8 2007-09-14 drh: /* 80 */ "Multiply", c287665ba8 2007-09-14 drh: /* 81 */ "Divide", c287665ba8 2007-09-14 drh: /* 82 */ "Remainder", c287665ba8 2007-09-14 drh: /* 83 */ "Concat", c287665ba8 2007-09-14 drh: /* 84 */ "IdxDelete", c287665ba8 2007-09-14 drh: /* 85 */ "Negative", c287665ba8 2007-09-14 drh: /* 86 */ "Vacuum", c287665ba8 2007-09-14 drh: /* 87 */ "BitNot", c287665ba8 2007-09-14 drh: /* 88 */ "String8", c287665ba8 2007-09-14 drh: /* 89 */ "MoveLe", c287665ba8 2007-09-14 drh: /* 90 */ "IfNot", c287665ba8 2007-09-14 drh: /* 91 */ "DropTable", c287665ba8 2007-09-14 drh: /* 92 */ "MakeRecord", c287665ba8 2007-09-14 drh: /* 93 */ "Delete", c287665ba8 2007-09-14 drh: /* 94 */ "AggFinal", c287665ba8 2007-09-14 drh: /* 95 */ "Dup", c287665ba8 2007-09-14 drh: /* 96 */ "Goto", c287665ba8 2007-09-14 drh: /* 97 */ "TableLock", c287665ba8 2007-09-14 drh: /* 98 */ "FifoRead", c287665ba8 2007-09-14 drh: /* 99 */ "Clear", c287665ba8 2007-09-14 drh: /* 100 */ "IdxGT", c287665ba8 2007-09-14 drh: /* 101 */ "MoveLt", c287665ba8 2007-09-14 drh: /* 102 */ "VerifyCookie", c287665ba8 2007-09-14 drh: /* 103 */ "AggStep", c287665ba8 2007-09-14 drh: /* 104 */ "Pull", c287665ba8 2007-09-14 drh: /* 105 */ "SetNumColumns", c287665ba8 2007-09-14 drh: /* 106 */ "AbsValue", c287665ba8 2007-09-14 drh: /* 107 */ "Transaction", c287665ba8 2007-09-14 drh: /* 108 */ "VFilter", c287665ba8 2007-09-14 drh: /* 109 */ "VDestroy", c287665ba8 2007-09-14 drh: /* 110 */ "ContextPop", c287665ba8 2007-09-14 drh: /* 111 */ "Next", c287665ba8 2007-09-14 drh: /* 112 */ "IdxInsert", c287665ba8 2007-09-14 drh: /* 113 */ "Distinct", c287665ba8 2007-09-14 drh: /* 114 */ "Insert", c287665ba8 2007-09-14 drh: /* 115 */ "Destroy", c287665ba8 2007-09-14 drh: /* 116 */ "ReadCookie", c287665ba8 2007-09-14 drh: /* 117 */ "ForceInt", c287665ba8 2007-09-14 drh: /* 118 */ "LoadAnalysis", c287665ba8 2007-09-14 drh: /* 119 */ "Explain", c287665ba8 2007-09-14 drh: /* 120 */ "IfMemZero", c287665ba8 2007-09-14 drh: /* 121 */ "OpenPseudo", c287665ba8 2007-09-14 drh: /* 122 */ "OpenEphemeral", c287665ba8 2007-09-14 drh: /* 123 */ "Null", c287665ba8 2007-09-14 drh: /* 124 */ "Blob", c287665ba8 2007-09-14 drh: /* 125 */ "Real", c287665ba8 2007-09-14 drh: /* 126 */ "HexBlob", c287665ba8 2007-09-14 drh: /* 127 */ "MemStore", c287665ba8 2007-09-14 drh: /* 128 */ "Rewind", c287665ba8 2007-09-14 drh: /* 129 */ "MoveGe", c287665ba8 2007-09-14 drh: /* 130 */ "VBegin", c287665ba8 2007-09-14 drh: /* 131 */ "VUpdate", c287665ba8 2007-09-14 drh: /* 132 */ "VCreate", c287665ba8 2007-09-14 drh: /* 133 */ "MemMove", c287665ba8 2007-09-14 drh: /* 134 */ "MemNull", c287665ba8 2007-09-14 drh: /* 135 */ "Found", c287665ba8 2007-09-14 drh: /* 136 */ "NullRow", c287665ba8 2007-09-14 drh: /* 137 */ "NotUsed_137", c287665ba8 2007-09-14 drh: /* 138 */ "ToText", c287665ba8 2007-09-14 drh: /* 139 */ "ToBlob", c287665ba8 2007-09-14 drh: /* 140 */ "ToNumeric", c287665ba8 2007-09-14 drh: /* 141 */ "ToInt", c287665ba8 2007-09-14 drh: /* 142 */ "ToReal", c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: return azName[i]; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of opcodes.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file os_os2.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2006 Feb 14 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains code that is specific to OS/2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if OS_OS2 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Macros used to determine whether or not to use threads. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if defined(THREADSAFE) && THREADSAFE dbda8d6ce9 2007-07-21 drh: # define SQLITE_OS2_THREADS 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Include code that is common to all os_*.c files dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /************** Include os_common.h in the middle of os_os2.c ****************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file os_common.h ***************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 May 22 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains macros and a little bit of code that is common to dbda8d6ce9 2007-07-21 drh: ** all of the platform-specific files (os_*.c) and is #included into those dbda8d6ce9 2007-07-21 drh: ** files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file should be #included by the os_*.c files only. It is not a dbda8d6ce9 2007-07-21 drh: ** general purpose header file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** At least two bugs have slipped in because we changed the MEMORY_DEBUG dbda8d6ce9 2007-07-21 drh: ** macro to SQLITE_DEBUG and some older makefiles have not yet made the dbda8d6ce9 2007-07-21 drh: ** switch. The following code should catch this problem at compile-time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef MEMORY_DEBUG dbda8d6ce9 2007-07-21 drh: # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * When testing, this global variable stores the location of the dbda8d6ce9 2007-07-21 drh: * pending-byte in the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API unsigned int sqlite3_pending_byte = 0x40000000; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_os_trace = 0; dbda8d6ce9 2007-07-21 drh: #define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X) dbda8d6ce9 2007-07-21 drh: #define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y) dbda8d6ce9 2007-07-21 drh: #define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z) dbda8d6ce9 2007-07-21 drh: #define OSTRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A) dbda8d6ce9 2007-07-21 drh: #define OSTRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B) dbda8d6ce9 2007-07-21 drh: #define OSTRACE6(X,Y,Z,A,B,C) \ dbda8d6ce9 2007-07-21 drh: if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C) dbda8d6ce9 2007-07-21 drh: #define OSTRACE7(X,Y,Z,A,B,C,D) \ dbda8d6ce9 2007-07-21 drh: if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define OSTRACE1(X) dbda8d6ce9 2007-07-21 drh: #define OSTRACE2(X,Y) dbda8d6ce9 2007-07-21 drh: #define OSTRACE3(X,Y,Z) dbda8d6ce9 2007-07-21 drh: #define OSTRACE4(X,Y,Z,A) dbda8d6ce9 2007-07-21 drh: #define OSTRACE5(X,Y,Z,A,B) dbda8d6ce9 2007-07-21 drh: #define OSTRACE6(X,Y,Z,A,B,C) dbda8d6ce9 2007-07-21 drh: #define OSTRACE7(X,Y,Z,A,B,C,D) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Macros for performance tracing. Normally turned off. Only works dbda8d6ce9 2007-07-21 drh: ** on i486 hardware. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_PERFORMANCE_TRACE dbda8d6ce9 2007-07-21 drh: __inline__ unsigned long long int hwtime(void){ dbda8d6ce9 2007-07-21 drh: unsigned long long int x; dbda8d6ce9 2007-07-21 drh: __asm__("rdtsc\n\t" dbda8d6ce9 2007-07-21 drh: "mov %%edx, %%ecx\n\t" dbda8d6ce9 2007-07-21 drh: :"=A" (x)); dbda8d6ce9 2007-07-21 drh: return x; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static unsigned long long int g_start; dbda8d6ce9 2007-07-21 drh: static unsigned int elapse; dbda8d6ce9 2007-07-21 drh: #define TIMER_START g_start=hwtime() dbda8d6ce9 2007-07-21 drh: #define TIMER_END elapse=hwtime()-g_start dbda8d6ce9 2007-07-21 drh: #define TIMER_ELAPSED elapse dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define TIMER_START dbda8d6ce9 2007-07-21 drh: #define TIMER_END dbda8d6ce9 2007-07-21 drh: #define TIMER_ELAPSED 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If we compile with the SQLITE_TEST macro set, then the following block dbda8d6ce9 2007-07-21 drh: ** of code will give us the ability to simulate a disk I/O error. This dbda8d6ce9 2007-07-21 drh: ** is used for testing the I/O recovery logic. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_hit = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_pending = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_persist = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_diskfull_pending = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_diskfull = 0; dbda8d6ce9 2007-07-21 drh: #define SimulateIOError(CODE) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_io_error_pending || sqlite3_io_error_hit ) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_io_error_pending-- == 1 \ dbda8d6ce9 2007-07-21 drh: || (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \ dbda8d6ce9 2007-07-21 drh: { local_ioerr(); CODE; } dbda8d6ce9 2007-07-21 drh: static void local_ioerr(){ dbda8d6ce9 2007-07-21 drh: IOTRACE(("IOERR\n")); dbda8d6ce9 2007-07-21 drh: sqlite3_io_error_hit = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #define SimulateDiskfullError(CODE) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_diskfull_pending ){ \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_diskfull_pending == 1 ){ \ dbda8d6ce9 2007-07-21 drh: local_ioerr(); \ dbda8d6ce9 2007-07-21 drh: sqlite3_diskfull = 1; \ dbda8d6ce9 2007-07-21 drh: sqlite3_io_error_hit = 1; \ dbda8d6ce9 2007-07-21 drh: CODE; \ dbda8d6ce9 2007-07-21 drh: }else{ \ dbda8d6ce9 2007-07-21 drh: sqlite3_diskfull_pending--; \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define SimulateIOError(A) dbda8d6ce9 2007-07-21 drh: #define SimulateDiskfullError(A) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** When testing, keep a count of the number of open files. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_open_file_count = 0; dbda8d6ce9 2007-07-21 drh: #define OpenCounter(X) sqlite3_open_file_count+=(X) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define OpenCounter(X) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of os_common.h *******************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in os_os2.c *********************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The os2File structure is subclass of OsFile specific for the OS/2 dbda8d6ce9 2007-07-21 drh: ** protability layer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct os2File os2File; dbda8d6ce9 2007-07-21 drh: struct os2File { dbda8d6ce9 2007-07-21 drh: IoMethod const *pMethod; /* Always the first entry */ dbda8d6ce9 2007-07-21 drh: HFILE h; /* Handle for accessing the file */ dbda8d6ce9 2007-07-21 drh: int delOnClose; /* True if file is to be deleted on close */ dbda8d6ce9 2007-07-21 drh: char* pathToDel; /* Name of file to delete on close */ dbda8d6ce9 2007-07-21 drh: unsigned char locktype; /* Type of lock currently held on this file */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Do not include any of the File I/O interface procedures if the dbda8d6ce9 2007-07-21 drh: ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database dbda8d6ce9 2007-07-21 drh: ** will be in-memory only) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_DISKIO dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete the named file dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2Delete( const char *zFilename ){ dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = DosDelete( (PSZ)zFilename ); dbda8d6ce9 2007-07-21 drh: OSTRACE2( "DELETE \"%s\"\n", zFilename ); dbda8d6ce9 2007-07-21 drh: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the named file exists. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2FileExists( const char *zFilename ){ dbda8d6ce9 2007-07-21 drh: FILESTATUS3 fsts3ConfigInfo; dbda8d6ce9 2007-07-21 drh: memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); dbda8d6ce9 2007-07-21 drh: return DosQueryPathInfo( (PSZ)zFilename, FIL_STANDARD, dbda8d6ce9 2007-07-21 drh: &fsts3ConfigInfo, sizeof(FILESTATUS3) ) == NO_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward declaration */ dbda8d6ce9 2007-07-21 drh: int allocateOs2File( os2File *pInit, OsFile **pld ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to open a file for both reading and writing. If that dbda8d6ce9 2007-07-21 drh: ** fails, try opening it read-only. If the file does not exist, dbda8d6ce9 2007-07-21 drh: ** try to create it. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On success, a handle for the open file is written to *id dbda8d6ce9 2007-07-21 drh: ** and *pReadonly is set to 0 if the file was opened for reading and dbda8d6ce9 2007-07-21 drh: ** writing or 1 if the file was opened read-only. The function returns dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On failure, the function returns SQLITE_CANTOPEN and leaves dbda8d6ce9 2007-07-21 drh: ** *id and *pReadonly unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2OpenReadWrite( dbda8d6ce9 2007-07-21 drh: const char *zFilename, dbda8d6ce9 2007-07-21 drh: OsFile **pld, dbda8d6ce9 2007-07-21 drh: int *pReadonly dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: os2File f; dbda8d6ce9 2007-07-21 drh: HFILE hf; dbda8d6ce9 2007-07-21 drh: ULONG ulAction; dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( *pld == 0 ); dbda8d6ce9 2007-07-21 drh: rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, dbda8d6ce9 2007-07-21 drh: FILE_ARCHIVED | FILE_NORMAL, dbda8d6ce9 2007-07-21 drh: OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, dbda8d6ce9 2007-07-21 drh: OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | dbda8d6ce9 2007-07-21 drh: OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); dbda8d6ce9 2007-07-21 drh: if( rc != NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, dbda8d6ce9 2007-07-21 drh: FILE_ARCHIVED | FILE_NORMAL, dbda8d6ce9 2007-07-21 drh: OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, dbda8d6ce9 2007-07-21 drh: OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | dbda8d6ce9 2007-07-21 drh: OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); dbda8d6ce9 2007-07-21 drh: if( rc != NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CANTOPEN; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pReadonly = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: else{ dbda8d6ce9 2007-07-21 drh: *pReadonly = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: f.h = hf; dbda8d6ce9 2007-07-21 drh: f.locktype = NO_LOCK; dbda8d6ce9 2007-07-21 drh: f.delOnClose = 0; dbda8d6ce9 2007-07-21 drh: f.pathToDel = NULL; dbda8d6ce9 2007-07-21 drh: OpenCounter(+1); dbda8d6ce9 2007-07-21 drh: OSTRACE3( "OPEN R/W %d \"%s\"\n", hf, zFilename ); dbda8d6ce9 2007-07-21 drh: return allocateOs2File( &f, pld ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to open a new file for exclusive access by this process. dbda8d6ce9 2007-07-21 drh: ** The file will be opened for both reading and writing. To avoid dbda8d6ce9 2007-07-21 drh: ** a potential security problem, we do not allow the file to have dbda8d6ce9 2007-07-21 drh: ** previously existed. Nor do we allow the file to be a symbolic dbda8d6ce9 2007-07-21 drh: ** link. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If delFlag is true, then make arrangements to automatically delete dbda8d6ce9 2007-07-21 drh: ** the file when it is closed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On success, write the file handle into *id and return SQLITE_OK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On failure, return SQLITE_CANTOPEN. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2OpenExclusive( const char *zFilename, OsFile **pld, int delFlag ){ dbda8d6ce9 2007-07-21 drh: os2File f; dbda8d6ce9 2007-07-21 drh: HFILE hf; dbda8d6ce9 2007-07-21 drh: ULONG ulAction; dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( *pld == 0 ); dbda8d6ce9 2007-07-21 drh: rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_NORMAL, dbda8d6ce9 2007-07-21 drh: OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS, dbda8d6ce9 2007-07-21 drh: OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | dbda8d6ce9 2007-07-21 drh: OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); dbda8d6ce9 2007-07-21 drh: if( rc != NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CANTOPEN; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: f.h = hf; dbda8d6ce9 2007-07-21 drh: f.locktype = NO_LOCK; dbda8d6ce9 2007-07-21 drh: f.delOnClose = delFlag ? 1 : 0; dbda8d6ce9 2007-07-21 drh: f.pathToDel = delFlag ? sqlite3OsFullPathname( zFilename ) : NULL; dbda8d6ce9 2007-07-21 drh: OpenCounter( +1 ); dbda8d6ce9 2007-07-21 drh: if( delFlag ) DosForceDelete( (PSZ)sqlite3OsFullPathname( zFilename ) ); dbda8d6ce9 2007-07-21 drh: OSTRACE3( "OPEN EX %d \"%s\"\n", hf, sqlite3OsFullPathname ( zFilename ) ); dbda8d6ce9 2007-07-21 drh: return allocateOs2File( &f, pld ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to open a new file for read-only access. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On success, write the file handle into *id and return SQLITE_OK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On failure, return SQLITE_CANTOPEN. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2OpenReadOnly( const char *zFilename, OsFile **pld ){ dbda8d6ce9 2007-07-21 drh: os2File f; dbda8d6ce9 2007-07-21 drh: HFILE hf; dbda8d6ce9 2007-07-21 drh: ULONG ulAction; dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( *pld == 0 ); dbda8d6ce9 2007-07-21 drh: rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, dbda8d6ce9 2007-07-21 drh: FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, dbda8d6ce9 2007-07-21 drh: OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | dbda8d6ce9 2007-07-21 drh: OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); dbda8d6ce9 2007-07-21 drh: if( rc != NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CANTOPEN; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: f.h = hf; dbda8d6ce9 2007-07-21 drh: f.locktype = NO_LOCK; dbda8d6ce9 2007-07-21 drh: f.delOnClose = 0; dbda8d6ce9 2007-07-21 drh: f.pathToDel = NULL; dbda8d6ce9 2007-07-21 drh: OpenCounter( +1 ); dbda8d6ce9 2007-07-21 drh: OSTRACE3( "OPEN RO %d \"%s\"\n", hf, zFilename ); dbda8d6ce9 2007-07-21 drh: return allocateOs2File( &f, pld ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to open a file descriptor for the directory that contains a dbda8d6ce9 2007-07-21 drh: ** file. This file descriptor can be used to fsync() the directory dbda8d6ce9 2007-07-21 drh: ** in order to make sure the creation of a new file is actually written dbda8d6ce9 2007-07-21 drh: ** to disk. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is only meaningful for Unix. It is a no-op under dbda8d6ce9 2007-07-21 drh: ** OS/2 since OS/2 does not support hard links. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On success, a handle for a previously open file is at *id is dbda8d6ce9 2007-07-21 drh: ** updated with the new directory file descriptor and SQLITE_OK is dbda8d6ce9 2007-07-21 drh: ** returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On failure, the function returns SQLITE_CANTOPEN and leaves dbda8d6ce9 2007-07-21 drh: ** *id unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2OpenDirectory( dbda8d6ce9 2007-07-21 drh: OsFile *id, dbda8d6ce9 2007-07-21 drh: const char *zDirname dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a temporary file name in zBuf. zBuf must be big enough to dbda8d6ce9 2007-07-21 drh: ** hold at least SQLITE_TEMPNAME_SIZE characters. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2TempFileName( char *zBuf ){ dbda8d6ce9 2007-07-21 drh: static const unsigned char zChars[] = dbda8d6ce9 2007-07-21 drh: "abcdefghijklmnopqrstuvwxyz" dbda8d6ce9 2007-07-21 drh: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" dbda8d6ce9 2007-07-21 drh: "0123456789"; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: PSZ zTempPath = 0; dbda8d6ce9 2007-07-21 drh: if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){ dbda8d6ce9 2007-07-21 drh: if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){ dbda8d6ce9 2007-07-21 drh: if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){ dbda8d6ce9 2007-07-21 drh: ULONG ulDriveNum = 0, ulDriveMap = 0; dbda8d6ce9 2007-07-21 drh: DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); dbda8d6ce9 2007-07-21 drh: sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: /* strip off a trailing slashes or backslashes, otherwise we would get * c287665ba8 2007-09-14 drh: * multiple (back)slashes which causes DosOpen() to fail */ c287665ba8 2007-09-14 drh: j = strlen(zTempPath); c287665ba8 2007-09-14 drh: while( j > 0 && zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' ){ c287665ba8 2007-09-14 drh: j--; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: zTempPath[j] = '\0'; dbda8d6ce9 2007-07-21 drh: for(;;){ dbda8d6ce9 2007-07-21 drh: sprintf( zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath ); dbda8d6ce9 2007-07-21 drh: j = strlen( zBuf ); dbda8d6ce9 2007-07-21 drh: sqlite3Randomness( 15, &zBuf[j] ); dbda8d6ce9 2007-07-21 drh: for( i = 0; i < 15; i++, j++ ){ dbda8d6ce9 2007-07-21 drh: zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zBuf[j] = 0; dbda8d6ce9 2007-07-21 drh: if( !sqlite3OsFileExists( zBuf ) ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: OSTRACE2( "TEMP FILENAME: %s\n", zBuf ); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close a file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2Close( OsFile **pld ){ dbda8d6ce9 2007-07-21 drh: os2File *pFile; dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: if( pld && (pFile = (os2File*)*pld) != 0 ){ dbda8d6ce9 2007-07-21 drh: OSTRACE2( "CLOSE %d\n", pFile->h ); dbda8d6ce9 2007-07-21 drh: rc = DosClose( pFile->h ); dbda8d6ce9 2007-07-21 drh: pFile->locktype = NO_LOCK; dbda8d6ce9 2007-07-21 drh: if( pFile->delOnClose != 0 ){ dbda8d6ce9 2007-07-21 drh: rc = DosForceDelete( (PSZ)pFile->pathToDel ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pld = 0; dbda8d6ce9 2007-07-21 drh: OpenCounter( -1 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read data from a file into a buffer. Return SQLITE_OK if all dbda8d6ce9 2007-07-21 drh: ** bytes were read successfully and SQLITE_IOERR if anything goes dbda8d6ce9 2007-07-21 drh: ** wrong. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2Read( OsFile *id, void *pBuf, int amt ){ dbda8d6ce9 2007-07-21 drh: ULONG got; dbda8d6ce9 2007-07-21 drh: assert( id!=0 ); dbda8d6ce9 2007-07-21 drh: SimulateIOError( return SQLITE_IOERR ); dbda8d6ce9 2007-07-21 drh: OSTRACE3( "READ %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); dbda8d6ce9 2007-07-21 drh: DosRead( ((os2File*)id)->h, pBuf, amt, &got ); dbda8d6ce9 2007-07-21 drh: if (got == (ULONG)amt) dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: else if (got == 0) dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_READ; dbda8d6ce9 2007-07-21 drh: else { dbda8d6ce9 2007-07-21 drh: memset(&((char*)pBuf)[got], 0, amt-got); dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_SHORT_READ; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write data from a buffer into a file. Return SQLITE_OK on success dbda8d6ce9 2007-07-21 drh: ** or some other error code on failure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2Write( OsFile *id, const void *pBuf, int amt ){ dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: ULONG wrote; dbda8d6ce9 2007-07-21 drh: assert( id!=0 ); dbda8d6ce9 2007-07-21 drh: SimulateIOError( return SQLITE_IOERR ); dbda8d6ce9 2007-07-21 drh: SimulateDiskfullError( return SQLITE_FULL ); dbda8d6ce9 2007-07-21 drh: OSTRACE3( "WRITE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); dbda8d6ce9 2007-07-21 drh: while( amt > 0 && dbda8d6ce9 2007-07-21 drh: (rc = DosWrite( ((os2File*)id)->h, (PVOID)pBuf, amt, &wrote )) && wrote > 0 ){ dbda8d6ce9 2007-07-21 drh: amt -= wrote; dbda8d6ce9 2007-07-21 drh: pBuf = &((char*)pBuf)[wrote]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move the read/write pointer in a file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2Seek( OsFile *id, i64 offset ){ dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: ULONG filePointer = 0L; dbda8d6ce9 2007-07-21 drh: assert( id!=0 ); dbda8d6ce9 2007-07-21 drh: rc = DosSetFilePtr( ((os2File*)id)->h, offset, FILE_BEGIN, &filePointer ); dbda8d6ce9 2007-07-21 drh: OSTRACE3( "SEEK %d %lld\n", ((os2File*)id)->h, offset ); dbda8d6ce9 2007-07-21 drh: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make sure all writes to a particular file are committed to disk. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2Sync( OsFile *id, int dataOnly ){ dbda8d6ce9 2007-07-21 drh: assert( id!=0 ); dbda8d6ce9 2007-07-21 drh: OSTRACE3( "SYNC %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); dbda8d6ce9 2007-07-21 drh: return DosResetBuffer( ((os2File*)id)->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Sync the directory zDirname. This is a no-op on operating systems other dbda8d6ce9 2007-07-21 drh: ** than UNIX. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2SyncDirectory( const char *zDirname ){ dbda8d6ce9 2007-07-21 drh: SimulateIOError( return SQLITE_IOERR ); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Truncate an open file to a specified size dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2Truncate( OsFile *id, i64 nByte ){ dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: ULONG upperBits = nByte>>32; dbda8d6ce9 2007-07-21 drh: assert( id!=0 ); dbda8d6ce9 2007-07-21 drh: OSTRACE3( "TRUNCATE %d %lld\n", ((os2File*)id)->h, nByte ); dbda8d6ce9 2007-07-21 drh: SimulateIOError( return SQLITE_IOERR ); dbda8d6ce9 2007-07-21 drh: rc = DosSetFilePtr( ((os2File*)id)->h, nByte, FILE_BEGIN, &upperBits ); dbda8d6ce9 2007-07-21 drh: if( rc != NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = DosSetFilePtr( ((os2File*)id)->h, 0L, FILE_END, &upperBits ); dbda8d6ce9 2007-07-21 drh: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Determine the current size of a file in bytes dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2FileSize( OsFile *id, i64 *pSize ){ dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: FILESTATUS3 fsts3FileInfo; dbda8d6ce9 2007-07-21 drh: memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); dbda8d6ce9 2007-07-21 drh: assert( id!=0 ); dbda8d6ce9 2007-07-21 drh: SimulateIOError( return SQLITE_IOERR ); dbda8d6ce9 2007-07-21 drh: rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); dbda8d6ce9 2007-07-21 drh: if( rc == NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: *pSize = fsts3FileInfo.cbFile; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: else{ dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Acquire a reader lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getReadLock( os2File *id ){ dbda8d6ce9 2007-07-21 drh: FILELOCK LockArea, dbda8d6ce9 2007-07-21 drh: UnlockArea; dbda8d6ce9 2007-07-21 drh: memset(&LockArea, 0, sizeof(LockArea)); dbda8d6ce9 2007-07-21 drh: memset(&UnlockArea, 0, sizeof(UnlockArea)); dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = SHARED_FIRST; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = SHARED_SIZE; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Undo a readlock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int unlockReadLock( os2File *id ){ dbda8d6ce9 2007-07-21 drh: FILELOCK LockArea, dbda8d6ce9 2007-07-21 drh: UnlockArea; dbda8d6ce9 2007-07-21 drh: memset(&LockArea, 0, sizeof(LockArea)); dbda8d6ce9 2007-07-21 drh: memset(&UnlockArea, 0, sizeof(UnlockArea)); dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = SHARED_FIRST; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = SHARED_SIZE; dbda8d6ce9 2007-07-21 drh: return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check that a given pathname is a directory and is writable dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2IsDirWritable( char *zDirname ){ dbda8d6ce9 2007-07-21 drh: FILESTATUS3 fsts3ConfigInfo; dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); dbda8d6ce9 2007-07-21 drh: if( zDirname==0 ) return 0; dbda8d6ce9 2007-07-21 drh: if( strlen(zDirname)>CCHMAXPATH ) return 0; dbda8d6ce9 2007-07-21 drh: rc = DosQueryPathInfo( (PSZ)zDirname, FIL_STANDARD, &fsts3ConfigInfo, sizeof(FILESTATUS3) ); dbda8d6ce9 2007-07-21 drh: if( rc != NO_ERROR ) return 0; dbda8d6ce9 2007-07-21 drh: if( (fsts3ConfigInfo.attrFile & FILE_DIRECTORY) != FILE_DIRECTORY ) return 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Lock the file with the lock specified by parameter locktype - one dbda8d6ce9 2007-07-21 drh: ** of the following: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) SHARED_LOCK dbda8d6ce9 2007-07-21 drh: ** (2) RESERVED_LOCK dbda8d6ce9 2007-07-21 drh: ** (3) PENDING_LOCK dbda8d6ce9 2007-07-21 drh: ** (4) EXCLUSIVE_LOCK dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Sometimes when requesting one lock state, additional lock states dbda8d6ce9 2007-07-21 drh: ** are inserted in between. The locking might fail on one of the later dbda8d6ce9 2007-07-21 drh: ** transitions leaving the lock state different from what it started but dbda8d6ce9 2007-07-21 drh: ** still short of its goal. The following chart shows the allowed dbda8d6ce9 2007-07-21 drh: ** transitions and the inserted intermediate states: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** UNLOCKED -> SHARED dbda8d6ce9 2007-07-21 drh: ** SHARED -> RESERVED dbda8d6ce9 2007-07-21 drh: ** SHARED -> (PENDING) -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** RESERVED -> (PENDING) -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** PENDING -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine will only increase a lock. The os2Unlock() routine dbda8d6ce9 2007-07-21 drh: ** erases all locks at once and returns us immediately to locking level 0. dbda8d6ce9 2007-07-21 drh: ** It is not possible to lower the locking level one step at a time. You dbda8d6ce9 2007-07-21 drh: ** must go straight to locking level 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2Lock( OsFile *id, int locktype ){ dbda8d6ce9 2007-07-21 drh: APIRET rc = SQLITE_OK; /* Return code from subroutines */ dbda8d6ce9 2007-07-21 drh: APIRET res = NO_ERROR; /* Result of an OS/2 lock call */ dbda8d6ce9 2007-07-21 drh: int newLocktype; /* Set id->locktype to this value before exiting */ dbda8d6ce9 2007-07-21 drh: int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ dbda8d6ce9 2007-07-21 drh: FILELOCK LockArea, dbda8d6ce9 2007-07-21 drh: UnlockArea; dbda8d6ce9 2007-07-21 drh: os2File *pFile = (os2File*)id; dbda8d6ce9 2007-07-21 drh: memset(&LockArea, 0, sizeof(LockArea)); dbda8d6ce9 2007-07-21 drh: memset(&UnlockArea, 0, sizeof(UnlockArea)); dbda8d6ce9 2007-07-21 drh: assert( pFile!=0 ); dbda8d6ce9 2007-07-21 drh: OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there is already a lock of this type or more restrictive on the dbda8d6ce9 2007-07-21 drh: ** OsFile, do nothing. Don't use the end_lock: exit path, as dbda8d6ce9 2007-07-21 drh: ** sqlite3OsEnterMutex() hasn't been called yet. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>=locktype ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the locking sequence is correct dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( locktype!=PENDING_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or dbda8d6ce9 2007-07-21 drh: ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of dbda8d6ce9 2007-07-21 drh: ** the PENDING_LOCK byte is temporary. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: newLocktype = pFile->locktype; dbda8d6ce9 2007-07-21 drh: if( pFile->locktype==NO_LOCK dbda8d6ce9 2007-07-21 drh: || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int cnt = 3; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = PENDING_BYTE; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 1L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( cnt-->0 && (res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L) )!=NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: /* Try 3 times to get the pending lock. The pending lock might be dbda8d6ce9 2007-07-21 drh: ** held by another reader process who will release it momentarily. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: OSTRACE2( "could not get a PENDING lock. cnt=%d\n", cnt ); dbda8d6ce9 2007-07-21 drh: DosSleep(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: gotPendingLock = res; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire a shared lock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK && res ){ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype==NO_LOCK ); dbda8d6ce9 2007-07-21 drh: res = getReadLock(pFile); dbda8d6ce9 2007-07-21 drh: if( res == NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: newLocktype = SHARED_LOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire a RESERVED lock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==RESERVED_LOCK && res ){ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = RESERVED_BYTE; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 1L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: if( res == NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: newLocktype = RESERVED_LOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire a PENDING lock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==EXCLUSIVE_LOCK && res ){ dbda8d6ce9 2007-07-21 drh: newLocktype = PENDING_LOCK; dbda8d6ce9 2007-07-21 drh: gotPendingLock = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire an EXCLUSIVE lock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==EXCLUSIVE_LOCK && res ){ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype>=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: res = unlockReadLock(pFile); dbda8d6ce9 2007-07-21 drh: OSTRACE2( "unreadlock = %d\n", res ); dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = SHARED_FIRST; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = SHARED_SIZE; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: if( res == NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: newLocktype = EXCLUSIVE_LOCK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: OSTRACE2( "error-code = %d\n", res ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we are holding a PENDING lock that ought to be released, then dbda8d6ce9 2007-07-21 drh: ** release it now. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( gotPendingLock && locktype==SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = PENDING_BYTE; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 1L; dbda8d6ce9 2007-07-21 drh: DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update the state of the lock has held in the file descriptor then dbda8d6ce9 2007-07-21 drh: ** return the appropriate result code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( res == NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h, dbda8d6ce9 2007-07-21 drh: locktype, newLocktype ); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pFile->locktype = newLocktype; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine checks if there is a RESERVED lock held on the specified dbda8d6ce9 2007-07-21 drh: ** file by this or any other process. If such a lock is held, return dbda8d6ce9 2007-07-21 drh: ** non-zero, otherwise zero. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2CheckReservedLock( OsFile *id ){ dbda8d6ce9 2007-07-21 drh: APIRET rc = NO_ERROR; dbda8d6ce9 2007-07-21 drh: os2File *pFile = (os2File*)id; dbda8d6ce9 2007-07-21 drh: assert( pFile!=0 ); dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>=RESERVED_LOCK ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, rc ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: FILELOCK LockArea, dbda8d6ce9 2007-07-21 drh: UnlockArea; dbda8d6ce9 2007-07-21 drh: memset(&LockArea, 0, sizeof(LockArea)); dbda8d6ce9 2007-07-21 drh: memset(&UnlockArea, 0, sizeof(UnlockArea)); dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = RESERVED_BYTE; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 1L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: if( rc == NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = RESERVED_BYTE; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 1L; dbda8d6ce9 2007-07-21 drh: rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, rc ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Lower the locking level on file descriptor id to locktype. locktype dbda8d6ce9 2007-07-21 drh: ** must be either NO_LOCK or SHARED_LOCK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the locking level of the file descriptor is already at or below dbda8d6ce9 2007-07-21 drh: ** the requested locking level, this routine is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is not possible for this routine to fail if the second argument dbda8d6ce9 2007-07-21 drh: ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine dbda8d6ce9 2007-07-21 drh: ** might return SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int os2Unlock( OsFile *id, int locktype ){ dbda8d6ce9 2007-07-21 drh: int type; dbda8d6ce9 2007-07-21 drh: APIRET rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: os2File *pFile = (os2File*)id; dbda8d6ce9 2007-07-21 drh: FILELOCK LockArea, dbda8d6ce9 2007-07-21 drh: UnlockArea; dbda8d6ce9 2007-07-21 drh: memset(&LockArea, 0, sizeof(LockArea)); dbda8d6ce9 2007-07-21 drh: memset(&UnlockArea, 0, sizeof(UnlockArea)); dbda8d6ce9 2007-07-21 drh: assert( pFile!=0 ); dbda8d6ce9 2007-07-21 drh: assert( locktype<=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ); dbda8d6ce9 2007-07-21 drh: type = pFile->locktype; dbda8d6ce9 2007-07-21 drh: if( type>=EXCLUSIVE_LOCK ){ dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = SHARED_FIRST; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = SHARED_SIZE; dbda8d6ce9 2007-07-21 drh: DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: /* This should never happen. We should always be able to dbda8d6ce9 2007-07-21 drh: ** reacquire the read lock */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( type>=RESERVED_LOCK ){ dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = RESERVED_BYTE; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 1L; dbda8d6ce9 2007-07-21 drh: DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( locktype==NO_LOCK && type>=SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: unlockReadLock(pFile); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( type>=PENDING_LOCK ){ dbda8d6ce9 2007-07-21 drh: LockArea.lOffset = 0L; dbda8d6ce9 2007-07-21 drh: LockArea.lRange = 0L; dbda8d6ce9 2007-07-21 drh: UnlockArea.lOffset = PENDING_BYTE; dbda8d6ce9 2007-07-21 drh: UnlockArea.lRange = 1L; dbda8d6ce9 2007-07-21 drh: DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Turn a relative pathname into a full pathname. Return a pointer dbda8d6ce9 2007-07-21 drh: ** to the full pathname stored in space obtained from sqliteMalloc(). dbda8d6ce9 2007-07-21 drh: ** The calling function is responsible for freeing this space once it dbda8d6ce9 2007-07-21 drh: ** is no longer needed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char *sqlite3Os2FullPathname( const char *zRelative ){ dbda8d6ce9 2007-07-21 drh: char *zFull = 0; dbda8d6ce9 2007-07-21 drh: if( strchr(zRelative, ':') ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString( &zFull, zRelative, (char*)0 ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: ULONG ulDriveNum = 0; dbda8d6ce9 2007-07-21 drh: ULONG ulDriveMap = 0; dbda8d6ce9 2007-07-21 drh: ULONG cbzBufLen = SQLITE_TEMPNAME_SIZE; dbda8d6ce9 2007-07-21 drh: char zDrive[2]; dbda8d6ce9 2007-07-21 drh: char *zBuff; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zBuff = sqliteMalloc( cbzBufLen ); dbda8d6ce9 2007-07-21 drh: if( zBuff != 0 ){ dbda8d6ce9 2007-07-21 drh: DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); dbda8d6ce9 2007-07-21 drh: if( DosQueryCurrentDir( ulDriveNum, (PBYTE)zBuff, &cbzBufLen ) == NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: sprintf( zDrive, "%c", (char)('A' + ulDriveNum - 1) ); dbda8d6ce9 2007-07-21 drh: sqlite3SetString( &zFull, zDrive, ":\\", zBuff, dbda8d6ce9 2007-07-21 drh: "\\", zRelative, (char*)0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqliteFree( zBuff ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zFull; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The fullSync option is meaningless on os2, or correct me if I'm wrong. This is a no-op. dbda8d6ce9 2007-07-21 drh: ** From os_unix.c: Change the value of the fullsync flag in the given file descriptor. dbda8d6ce9 2007-07-21 drh: ** From os_unix.c: ((unixFile*)id)->fullSync = v; dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void os2SetFullSync( OsFile *id, int v ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the underlying file handle for an OsFile dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int os2FileHandle( OsFile *id ){ dbda8d6ce9 2007-07-21 drh: return (int)((os2File*)id)->h; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return an integer that indices the type of lock currently held dbda8d6ce9 2007-07-21 drh: ** by this handle. (Used for testing and analysis only.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int os2LockState( OsFile *id ){ dbda8d6ce9 2007-07-21 drh: return ((os2File*)id)->locktype; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the sector size in bytes of the underlying block device for dbda8d6ce9 2007-07-21 drh: ** the specified file. This is almost always 512 bytes, but may be dbda8d6ce9 2007-07-21 drh: ** larger for some devices. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite code assumes this function cannot fail. It also assumes that dbda8d6ce9 2007-07-21 drh: ** if two files are created in the same file-system directory (i.e. dbda8d6ce9 2007-07-21 drh: ** a database and it's journal file) that the sector size will be the dbda8d6ce9 2007-07-21 drh: ** same for both. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int os2SectorSize(OsFile *id){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DEFAULT_SECTOR_SIZE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This vector defines all the methods that can operate on an OsFile dbda8d6ce9 2007-07-21 drh: ** for os2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const IoMethod sqlite3Os2IoMethod = { dbda8d6ce9 2007-07-21 drh: os2Close, dbda8d6ce9 2007-07-21 drh: os2OpenDirectory, dbda8d6ce9 2007-07-21 drh: os2Read, dbda8d6ce9 2007-07-21 drh: os2Write, dbda8d6ce9 2007-07-21 drh: os2Seek, dbda8d6ce9 2007-07-21 drh: os2Truncate, dbda8d6ce9 2007-07-21 drh: os2Sync, dbda8d6ce9 2007-07-21 drh: os2SetFullSync, dbda8d6ce9 2007-07-21 drh: os2FileHandle, dbda8d6ce9 2007-07-21 drh: os2FileSize, dbda8d6ce9 2007-07-21 drh: os2Lock, dbda8d6ce9 2007-07-21 drh: os2Unlock, dbda8d6ce9 2007-07-21 drh: os2LockState, dbda8d6ce9 2007-07-21 drh: os2CheckReservedLock, dbda8d6ce9 2007-07-21 drh: os2SectorSize, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate memory for an OsFile. Initialize the new OsFile dbda8d6ce9 2007-07-21 drh: ** to the value given in pInit and return a pointer to the new dbda8d6ce9 2007-07-21 drh: ** OsFile. If we run out of memory, close the file and return NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int allocateOs2File( os2File *pInit, OsFile **pld ){ dbda8d6ce9 2007-07-21 drh: os2File *pNew; dbda8d6ce9 2007-07-21 drh: pNew = sqliteMalloc( sizeof(*pNew) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: DosClose( pInit->h ); dbda8d6ce9 2007-07-21 drh: *pld = 0; dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *pNew = *pInit; dbda8d6ce9 2007-07-21 drh: pNew->pMethod = &sqlite3Os2IoMethod; dbda8d6ce9 2007-07-21 drh: pNew->locktype = NO_LOCK; dbda8d6ce9 2007-07-21 drh: *pld = (OsFile*)pNew; dbda8d6ce9 2007-07-21 drh: OpenCounter(+1); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_DISKIO */ dbda8d6ce9 2007-07-21 drh: /*************************************************************************** dbda8d6ce9 2007-07-21 drh: ** Everything above deals with file I/O. Everything that follows deals dbda8d6ce9 2007-07-21 drh: ** with other miscellanous aspects of the operating system interface dbda8d6ce9 2007-07-21 drh: ****************************************************************************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_LOAD_EXTENSION dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Interfaces for opening a shared library, finding entry points dbda8d6ce9 2007-07-21 drh: ** within the shared library, and closing the shared library. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3Os2Dlopen(const char *zFilename){ dbda8d6ce9 2007-07-21 drh: UCHAR loadErr[256]; dbda8d6ce9 2007-07-21 drh: HMODULE hmod; dbda8d6ce9 2007-07-21 drh: APIRET rc; dbda8d6ce9 2007-07-21 drh: rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilename, &hmod); dbda8d6ce9 2007-07-21 drh: if (rc != NO_ERROR) return 0; dbda8d6ce9 2007-07-21 drh: return (void*)hmod; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3Os2Dlsym(void *pHandle, const char *zSymbol){ dbda8d6ce9 2007-07-21 drh: PFN pfn; dbda8d6ce9 2007-07-21 drh: APIRET rc; dbda8d6ce9 2007-07-21 drh: rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn); dbda8d6ce9 2007-07-21 drh: if (rc != NO_ERROR) { dbda8d6ce9 2007-07-21 drh: /* if the symbol itself was not found, search again for the same dbda8d6ce9 2007-07-21 drh: * symbol with an extra underscore, that might be needed depending dbda8d6ce9 2007-07-21 drh: * on the calling convention */ dbda8d6ce9 2007-07-21 drh: char _zSymbol[256] = "_"; dbda8d6ce9 2007-07-21 drh: strncat(_zSymbol, zSymbol, 255); dbda8d6ce9 2007-07-21 drh: rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if (rc != NO_ERROR) return 0; dbda8d6ce9 2007-07-21 drh: return (void *)pfn; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2Dlclose(void *pHandle){ dbda8d6ce9 2007-07-21 drh: return DosFreeModule((HMODULE)pHandle); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_LOAD_EXTENSION */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Get information to seed the random number generator. The seed dbda8d6ce9 2007-07-21 drh: ** is written into the buffer zBuf[256]. The calling function must dbda8d6ce9 2007-07-21 drh: ** supply a sufficiently large buffer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2RandomSeed( char *zBuf ){ dbda8d6ce9 2007-07-21 drh: /* We have to initialize zBuf to prevent valgrind from reporting dbda8d6ce9 2007-07-21 drh: ** errors. The reports issued by valgrind are incorrect - we would dbda8d6ce9 2007-07-21 drh: ** prefer that the randomness be increased by making use of the dbda8d6ce9 2007-07-21 drh: ** uninitialized space in zBuf - but valgrind errors tend to worry dbda8d6ce9 2007-07-21 drh: ** some users. Rather than argue, it seems easier just to initialize dbda8d6ce9 2007-07-21 drh: ** the whole array and silence valgrind, even if that means less randomness dbda8d6ce9 2007-07-21 drh: ** in the random seed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When testing, initializing zBuf[] to zero is all we do. That means dbda8d6ce9 2007-07-21 drh: ** that we always use the same random number sequence. This makes the dbda8d6ce9 2007-07-21 drh: ** tests repeatable. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: memset( zBuf, 0, 256 ); dbda8d6ce9 2007-07-21 drh: DosGetDateTime( (PDATETIME)zBuf ); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Sleep for a little while. Return the amount of time slept. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2Sleep( int ms ){ dbda8d6ce9 2007-07-21 drh: DosSleep( ms ); dbda8d6ce9 2007-07-21 drh: return ms; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Static variables used for thread synchronization dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int inMutex = 0; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OS2_THREADS dbda8d6ce9 2007-07-21 drh: static ULONG mutexOwner; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following pair of routines implement mutual exclusion for dbda8d6ce9 2007-07-21 drh: ** multi-threaded processes. Only a single thread is allowed to dbda8d6ce9 2007-07-21 drh: ** executed code that is surrounded by EnterMutex() and LeaveMutex(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite uses only a single Mutex. There is not much critical dbda8d6ce9 2007-07-21 drh: ** code and what little there is executes quickly and without blocking. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Os2EnterMutex(){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OS2_THREADS dbda8d6ce9 2007-07-21 drh: PTIB ptib; dbda8d6ce9 2007-07-21 drh: DosEnterCritSec(); dbda8d6ce9 2007-07-21 drh: DosGetInfoBlocks( &ptib, NULL ); dbda8d6ce9 2007-07-21 drh: mutexOwner = ptib->tib_ptib2->tib2_ultid; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: assert( !inMutex ); dbda8d6ce9 2007-07-21 drh: inMutex = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Os2LeaveMutex(){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OS2_THREADS dbda8d6ce9 2007-07-21 drh: PTIB ptib; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: assert( inMutex ); dbda8d6ce9 2007-07-21 drh: inMutex = 0; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OS2_THREADS dbda8d6ce9 2007-07-21 drh: DosGetInfoBlocks( &ptib, NULL ); dbda8d6ce9 2007-07-21 drh: assert( mutexOwner == ptib->tib_ptib2->tib2_ultid ); dbda8d6ce9 2007-07-21 drh: DosExitCritSec(); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the mutex is currently held. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the thisThreadOnly parameter is true, return true if and only if the dbda8d6ce9 2007-07-21 drh: ** calling thread holds the mutex. If the parameter is false, return dbda8d6ce9 2007-07-21 drh: ** true if any thread holds the mutex. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2InMutex( int thisThreadOnly ){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OS2_THREADS dbda8d6ce9 2007-07-21 drh: PTIB ptib; dbda8d6ce9 2007-07-21 drh: DosGetInfoBlocks( &ptib, NULL ); dbda8d6ce9 2007-07-21 drh: return inMutex>0 && (thisThreadOnly==0 || mutexOwner==ptib->tib_ptib2->tib2_ultid); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: return inMutex>0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following variable, if set to a non-zero value, becomes the result dbda8d6ce9 2007-07-21 drh: ** returned from sqlite3OsCurrentTime(). This is used for testing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_current_time = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the current time (in Universal Coordinated Time). Write the dbda8d6ce9 2007-07-21 drh: ** current time and date as a Julian Day number into *prNow and dbda8d6ce9 2007-07-21 drh: ** return 0. Return 1 if the time and date cannot be found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Os2CurrentTime( double *prNow ){ dbda8d6ce9 2007-07-21 drh: double now; dbda8d6ce9 2007-07-21 drh: USHORT second, minute, hour, dbda8d6ce9 2007-07-21 drh: day, month, year; dbda8d6ce9 2007-07-21 drh: DATETIME dt; dbda8d6ce9 2007-07-21 drh: DosGetDateTime( &dt ); dbda8d6ce9 2007-07-21 drh: second = (USHORT)dt.seconds; dbda8d6ce9 2007-07-21 drh: minute = (USHORT)dt.minutes + dt.timezone; dbda8d6ce9 2007-07-21 drh: hour = (USHORT)dt.hours; dbda8d6ce9 2007-07-21 drh: day = (USHORT)dt.day; dbda8d6ce9 2007-07-21 drh: month = (USHORT)dt.month; dbda8d6ce9 2007-07-21 drh: year = (USHORT)dt.year; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html dbda8d6ce9 2007-07-21 drh: http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ dbda8d6ce9 2007-07-21 drh: /* Calculate the Julian days */ dbda8d6ce9 2007-07-21 drh: now = day - 32076 + dbda8d6ce9 2007-07-21 drh: 1461*(year + 4800 + (month - 14)/12)/4 + dbda8d6ce9 2007-07-21 drh: 367*(month - 2 - (month - 14)/12*12)/12 - dbda8d6ce9 2007-07-21 drh: 3*((year + 4900 + (month - 14)/12)/100)/4; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add the fractional hours, mins and seconds */ dbda8d6ce9 2007-07-21 drh: now += (hour + 12.0)/24.0; dbda8d6ce9 2007-07-21 drh: now += minute/1440.0; dbda8d6ce9 2007-07-21 drh: now += second/86400.0; dbda8d6ce9 2007-07-21 drh: *prNow = now; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: if( sqlite3_current_time ){ dbda8d6ce9 2007-07-21 drh: *prNow = sqlite3_current_time/86400.0 + 2440587.5; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Remember the number of thread-specific-data blocks allocated. dbda8d6ce9 2007-07-21 drh: ** Use this to verify that we are not leaking thread-specific-data. dbda8d6ce9 2007-07-21 drh: ** Ticket #1601 dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_tsd_count = 0; dbda8d6ce9 2007-07-21 drh: # define TSD_COUNTER_INCR InterlockedIncrement( &sqlite3_tsd_count ) dbda8d6ce9 2007-07-21 drh: # define TSD_COUNTER_DECR InterlockedDecrement( &sqlite3_tsd_count ) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define TSD_COUNTER_INCR /* no-op */ dbda8d6ce9 2007-07-21 drh: # define TSD_COUNTER_DECR /* no-op */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If called with allocateFlag>1, then return a pointer to thread dbda8d6ce9 2007-07-21 drh: ** specific data for the current thread. Allocate and zero the dbda8d6ce9 2007-07-21 drh: ** thread-specific data if it does not already exist necessary. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If called with allocateFlag==0, then check the current thread dbda8d6ce9 2007-07-21 drh: ** specific data. Return it if it exists. If it does not exist, dbda8d6ce9 2007-07-21 drh: ** then return NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If called with allocateFlag<0, check to see if the thread specific dbda8d6ce9 2007-07-21 drh: ** data is allocated and is all zero. If it is then deallocate it. dbda8d6ce9 2007-07-21 drh: ** Return a pointer to the thread specific data or NULL if it is dbda8d6ce9 2007-07-21 drh: ** unallocated or gets deallocated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE ThreadData *sqlite3Os2ThreadSpecificData( int allocateFlag ){ dbda8d6ce9 2007-07-21 drh: static ThreadData **s_ppTsd = NULL; dbda8d6ce9 2007-07-21 drh: static const ThreadData zeroData = {0, 0, 0}; dbda8d6ce9 2007-07-21 drh: ThreadData *pTsd; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !s_ppTsd ){ dbda8d6ce9 2007-07-21 drh: sqlite3OsEnterMutex(); dbda8d6ce9 2007-07-21 drh: if( !s_ppTsd ){ dbda8d6ce9 2007-07-21 drh: PULONG pul; dbda8d6ce9 2007-07-21 drh: APIRET rc = DosAllocThreadLocalMemory(1, &pul); dbda8d6ce9 2007-07-21 drh: if( rc != NO_ERROR ){ dbda8d6ce9 2007-07-21 drh: sqlite3OsLeaveMutex(); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: s_ppTsd = (ThreadData **)pul; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3OsLeaveMutex(); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTsd = *s_ppTsd; dbda8d6ce9 2007-07-21 drh: if( allocateFlag>0 ){ dbda8d6ce9 2007-07-21 drh: if( !pTsd ){ dbda8d6ce9 2007-07-21 drh: pTsd = sqlite3OsMalloc( sizeof(zeroData) ); dbda8d6ce9 2007-07-21 drh: if( pTsd ){ dbda8d6ce9 2007-07-21 drh: *pTsd = zeroData; dbda8d6ce9 2007-07-21 drh: *s_ppTsd = pTsd; dbda8d6ce9 2007-07-21 drh: TSD_COUNTER_INCR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pTsd!=0 && allocateFlag<0 dbda8d6ce9 2007-07-21 drh: && memcmp( pTsd, &zeroData, sizeof(ThreadData) )==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3OsFree(pTsd); dbda8d6ce9 2007-07-21 drh: *s_ppTsd = NULL; dbda8d6ce9 2007-07-21 drh: TSD_COUNTER_DECR; dbda8d6ce9 2007-07-21 drh: pTsd = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pTsd; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* OS_OS2 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of os_os2.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file os_unix.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 May 22 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains code that is specific to Unix systems. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if OS_UNIX /* This file is used on unix only */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* #define SQLITE_ENABLE_LOCKING_STYLE 0 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** These #defines should enable >2GB file support on Posix if the dbda8d6ce9 2007-07-21 drh: ** underlying operating system supports it. If the OS lacks dbda8d6ce9 2007-07-21 drh: ** large file support, these should be no-ops. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch dbda8d6ce9 2007-07-21 drh: ** on the compiler command line. This is necessary if you are compiling dbda8d6ce9 2007-07-21 drh: ** on a recent machine (ex: RedHat 7.2) but you want your code to work dbda8d6ce9 2007-07-21 drh: ** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 dbda8d6ce9 2007-07-21 drh: ** without this option, LFS is enable. But LFS does not exist in the kernel dbda8d6ce9 2007-07-21 drh: ** in RedHat 6.0, so the code won't work. Hence, for maximum binary dbda8d6ce9 2007-07-21 drh: ** portability you should omit LFS. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DISABLE_LFS dbda8d6ce9 2007-07-21 drh: # define _LARGE_FILE 1 dbda8d6ce9 2007-07-21 drh: # ifndef _FILE_OFFSET_BITS dbda8d6ce9 2007-07-21 drh: # define _FILE_OFFSET_BITS 64 dbda8d6ce9 2007-07-21 drh: # endif dbda8d6ce9 2007-07-21 drh: # define _LARGEFILE_SOURCE 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** standard include files. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #include <sys/types.h> dbda8d6ce9 2007-07-21 drh: #include <sys/stat.h> dbda8d6ce9 2007-07-21 drh: #include <fcntl.h> dbda8d6ce9 2007-07-21 drh: #include <unistd.h> dbda8d6ce9 2007-07-21 drh: #include <sys/time.h> dbda8d6ce9 2007-07-21 drh: #include <errno.h> dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_LOCKING_STYLE dbda8d6ce9 2007-07-21 drh: #include <sys/ioctl.h> dbda8d6ce9 2007-07-21 drh: #include <sys/param.h> dbda8d6ce9 2007-07-21 drh: #include <sys/mount.h> dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ENABLE_LOCKING_STYLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If we are to be thread-safe, include the pthreads header and define dbda8d6ce9 2007-07-21 drh: ** the SQLITE_UNIX_THREADS macro. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE dbda8d6ce9 2007-07-21 drh: # define SQLITE_UNIX_THREADS 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Default permissions when creating a new file dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DEFAULT_FILE_PERMISSIONS dbda8d6ce9 2007-07-21 drh: # define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Maximum supported path-length. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define MAX_PATHNAME 512 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The unixFile structure is subclass of sqlite3_file specific for the unix dbda8d6ce9 2007-07-21 drh: ** protability layer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct unixFile unixFile; dbda8d6ce9 2007-07-21 drh: struct unixFile { c287665ba8 2007-09-14 drh: sqlite3_io_methods const *pMethod; /* Always the first entry */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: /* In test mode, increase the size of this structure a bit so that c287665ba8 2007-09-14 drh: ** it is larger than the struct CrashFile defined in test6.c. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: char aPadding[32]; c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: struct openCnt *pOpen; /* Info about all open fd's on this inode */ dbda8d6ce9 2007-07-21 drh: struct lockInfo *pLock; /* Info about locks on this inode */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_LOCKING_STYLE dbda8d6ce9 2007-07-21 drh: void *lockingContext; /* Locking style specific state */ dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ENABLE_LOCKING_STYLE */ dbda8d6ce9 2007-07-21 drh: int h; /* The file descriptor */ dbda8d6ce9 2007-07-21 drh: unsigned char locktype; /* The type of lock held on this fd */ dbda8d6ce9 2007-07-21 drh: int dirfd; /* File descriptor for the directory */ c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE c287665ba8 2007-09-14 drh: pthread_t tid; /* The thread that "owns" this unixFile */ c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Include code that is common to all os_*.c files dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /************** Include os_common.h in the middle of os_unix.c ***************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file os_common.h ***************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 May 22 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains macros and a little bit of code that is common to dbda8d6ce9 2007-07-21 drh: ** all of the platform-specific files (os_*.c) and is #included into those dbda8d6ce9 2007-07-21 drh: ** files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file should be #included by the os_*.c files only. It is not a dbda8d6ce9 2007-07-21 drh: ** general purpose header file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** At least two bugs have slipped in because we changed the MEMORY_DEBUG dbda8d6ce9 2007-07-21 drh: ** macro to SQLITE_DEBUG and some older makefiles have not yet made the dbda8d6ce9 2007-07-21 drh: ** switch. The following code should catch this problem at compile-time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef MEMORY_DEBUG dbda8d6ce9 2007-07-21 drh: # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * When testing, this global variable stores the location of the dbda8d6ce9 2007-07-21 drh: * pending-byte in the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API unsigned int sqlite3_pending_byte = 0x40000000; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_os_trace = 0; dbda8d6ce9 2007-07-21 drh: #define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X) dbda8d6ce9 2007-07-21 drh: #define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y) dbda8d6ce9 2007-07-21 drh: #define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z) dbda8d6ce9 2007-07-21 drh: #define OSTRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A) dbda8d6ce9 2007-07-21 drh: #define OSTRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B) dbda8d6ce9 2007-07-21 drh: #define OSTRACE6(X,Y,Z,A,B,C) \ dbda8d6ce9 2007-07-21 drh: if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C) dbda8d6ce9 2007-07-21 drh: #define OSTRACE7(X,Y,Z,A,B,C,D) \ dbda8d6ce9 2007-07-21 drh: if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define OSTRACE1(X) dbda8d6ce9 2007-07-21 drh: #define OSTRACE2(X,Y) dbda8d6ce9 2007-07-21 drh: #define OSTRACE3(X,Y,Z) dbda8d6ce9 2007-07-21 drh: #define OSTRACE4(X,Y,Z,A) dbda8d6ce9 2007-07-21 drh: #define OSTRACE5(X,Y,Z,A,B) dbda8d6ce9 2007-07-21 drh: #define OSTRACE6(X,Y,Z,A,B,C) dbda8d6ce9 2007-07-21 drh: #define OSTRACE7(X,Y,Z,A,B,C,D) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Macros for performance tracing. Normally turned off. Only works dbda8d6ce9 2007-07-21 drh: ** on i486 hardware. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_PERFORMANCE_TRACE dbda8d6ce9 2007-07-21 drh: __inline__ unsigned long long int hwtime(void){ dbda8d6ce9 2007-07-21 drh: unsigned long long int x; dbda8d6ce9 2007-07-21 drh: __asm__("rdtsc\n\t" dbda8d6ce9 2007-07-21 drh: "mov %%edx, %%ecx\n\t" dbda8d6ce9 2007-07-21 drh: :"=A" (x)); dbda8d6ce9 2007-07-21 drh: return x; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static unsigned long long int g_start; dbda8d6ce9 2007-07-21 drh: static unsigned int elapse; dbda8d6ce9 2007-07-21 drh: #define TIMER_START g_start=hwtime() dbda8d6ce9 2007-07-21 drh: #define TIMER_END elapse=hwtime()-g_start dbda8d6ce9 2007-07-21 drh: #define TIMER_ELAPSED elapse dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define TIMER_START dbda8d6ce9 2007-07-21 drh: #define TIMER_END dbda8d6ce9 2007-07-21 drh: #define TIMER_ELAPSED 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If we compile with the SQLITE_TEST macro set, then the following block dbda8d6ce9 2007-07-21 drh: ** of code will give us the ability to simulate a disk I/O error. This dbda8d6ce9 2007-07-21 drh: ** is used for testing the I/O recovery logic. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_hit = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_pending = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_persist = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_diskfull_pending = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_diskfull = 0; dbda8d6ce9 2007-07-21 drh: #define SimulateIOError(CODE) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_io_error_pending || sqlite3_io_error_hit ) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_io_error_pending-- == 1 \ dbda8d6ce9 2007-07-21 drh: || (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \ dbda8d6ce9 2007-07-21 drh: { local_ioerr(); CODE; } dbda8d6ce9 2007-07-21 drh: static void local_ioerr(){ dbda8d6ce9 2007-07-21 drh: IOTRACE(("IOERR\n")); dbda8d6ce9 2007-07-21 drh: sqlite3_io_error_hit = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #define SimulateDiskfullError(CODE) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_diskfull_pending ){ \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_diskfull_pending == 1 ){ \ dbda8d6ce9 2007-07-21 drh: local_ioerr(); \ dbda8d6ce9 2007-07-21 drh: sqlite3_diskfull = 1; \ dbda8d6ce9 2007-07-21 drh: sqlite3_io_error_hit = 1; \ dbda8d6ce9 2007-07-21 drh: CODE; \ dbda8d6ce9 2007-07-21 drh: }else{ \ dbda8d6ce9 2007-07-21 drh: sqlite3_diskfull_pending--; \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define SimulateIOError(A) dbda8d6ce9 2007-07-21 drh: #define SimulateDiskfullError(A) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** When testing, keep a count of the number of open files. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_open_file_count = 0; dbda8d6ce9 2007-07-21 drh: #define OpenCounter(X) sqlite3_open_file_count+=(X) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define OpenCounter(X) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of os_common.h *******************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in os_unix.c ********************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Define various macros that are missing from some systems. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef O_LARGEFILE dbda8d6ce9 2007-07-21 drh: # define O_LARGEFILE 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DISABLE_LFS dbda8d6ce9 2007-07-21 drh: # undef O_LARGEFILE dbda8d6ce9 2007-07-21 drh: # define O_LARGEFILE 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef O_NOFOLLOW dbda8d6ce9 2007-07-21 drh: # define O_NOFOLLOW 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef O_BINARY dbda8d6ce9 2007-07-21 drh: # define O_BINARY 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The DJGPP compiler environment looks mostly like Unix, but it dbda8d6ce9 2007-07-21 drh: ** lacks the fcntl() system call. So redefine fcntl() to be something dbda8d6ce9 2007-07-21 drh: ** that always succeeds. This means that locking does not occur under dbda8d6ce9 2007-07-21 drh: ** DJGPP. But it's DOS - what did you expect? dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef __DJGPP__ dbda8d6ce9 2007-07-21 drh: # define fcntl(A,B,C) 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The threadid macro resolves to the thread-id or to 0. Used for dbda8d6ce9 2007-07-21 drh: ** testing and debugging only. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE dbda8d6ce9 2007-07-21 drh: #define threadid pthread_self() dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define threadid 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Set or check the unixFile.tid field. This field is set when an unixFile c287665ba8 2007-09-14 drh: ** is first opened. All subsequent uses of the unixFile verify that the c287665ba8 2007-09-14 drh: ** same thread is operating on the unixFile. Some operating systems do dbda8d6ce9 2007-07-21 drh: ** not allow locks to be overridden by other threads and that restriction dbda8d6ce9 2007-07-21 drh: ** means that sqlite3* database handles cannot be moved from one thread dbda8d6ce9 2007-07-21 drh: ** to another. This logic makes sure a user does not try to do that dbda8d6ce9 2007-07-21 drh: ** by mistake. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Version 3.3.1 (2006-01-15): unixFile can be moved from one thread to dbda8d6ce9 2007-07-21 drh: ** another as long as we are running on a system that supports threads dbda8d6ce9 2007-07-21 drh: ** overriding each others locks (which now the most common behavior) c287665ba8 2007-09-14 drh: ** or if no locks are held. But the unixFile.pLock field needs to be dbda8d6ce9 2007-07-21 drh: ** recomputed because its key includes the thread-id. See the dbda8d6ce9 2007-07-21 drh: ** transferOwnership() function below for additional information dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE dbda8d6ce9 2007-07-21 drh: # define SET_THREADID(X) (X)->tid = pthread_self() dbda8d6ce9 2007-07-21 drh: # define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \ dbda8d6ce9 2007-07-21 drh: !pthread_equal((X)->tid, pthread_self())) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define SET_THREADID(X) dbda8d6ce9 2007-07-21 drh: # define CHECK_THREADID(X) 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Here is the dirt on POSIX advisory locks: ANSI STD 1003.1 (1996) dbda8d6ce9 2007-07-21 drh: ** section 6.5.2.2 lines 483 through 490 specify that when a process dbda8d6ce9 2007-07-21 drh: ** sets or clears a lock, that operation overrides any prior locks set dbda8d6ce9 2007-07-21 drh: ** by the same process. It does not explicitly say so, but this implies dbda8d6ce9 2007-07-21 drh: ** that it overrides locks set by the same process using a different dbda8d6ce9 2007-07-21 drh: ** file descriptor. Consider this test case: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644); dbda8d6ce9 2007-07-21 drh: ** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Suppose ./file1 and ./file2 are really the same file (because dbda8d6ce9 2007-07-21 drh: ** one is a hard or symbolic link to the other) then if you set dbda8d6ce9 2007-07-21 drh: ** an exclusive lock on fd1, then try to get an exclusive lock dbda8d6ce9 2007-07-21 drh: ** on fd2, it works. I would have expected the second lock to dbda8d6ce9 2007-07-21 drh: ** fail since there was already a lock on the file due to fd1. dbda8d6ce9 2007-07-21 drh: ** But not so. Since both locks came from the same process, the dbda8d6ce9 2007-07-21 drh: ** second overrides the first, even though they were on different dbda8d6ce9 2007-07-21 drh: ** file descriptors opened on different file names. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Bummer. If you ask me, this is broken. Badly broken. It means dbda8d6ce9 2007-07-21 drh: ** that we cannot use POSIX locks to synchronize file access among dbda8d6ce9 2007-07-21 drh: ** competing threads of the same process. POSIX locks will work fine dbda8d6ce9 2007-07-21 drh: ** to synchronize access for threads in separate processes, but not dbda8d6ce9 2007-07-21 drh: ** threads within the same process. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To work around the problem, SQLite has to manage file locks internally dbda8d6ce9 2007-07-21 drh: ** on its own. Whenever a new database is opened, we have to find the dbda8d6ce9 2007-07-21 drh: ** specific inode of the database file (the inode is determined by the dbda8d6ce9 2007-07-21 drh: ** st_dev and st_ino fields of the stat structure that fstat() fills in) dbda8d6ce9 2007-07-21 drh: ** and check for locks already existing on that inode. When locks are dbda8d6ce9 2007-07-21 drh: ** created or removed, we have to look at our own internal record of the dbda8d6ce9 2007-07-21 drh: ** locks to see if another thread has previously set a lock on that same dbda8d6ce9 2007-07-21 drh: ** inode. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** The sqlite3_file structure for POSIX is no longer just an integer file dbda8d6ce9 2007-07-21 drh: ** descriptor. It is now a structure that holds the integer file dbda8d6ce9 2007-07-21 drh: ** descriptor and a pointer to a structure that describes the internal dbda8d6ce9 2007-07-21 drh: ** locks on the corresponding inode. There is one locking structure c287665ba8 2007-09-14 drh: ** per inode, so if the same inode is opened twice, both unixFile structures dbda8d6ce9 2007-07-21 drh: ** point to the same locking structure. The locking structure keeps dbda8d6ce9 2007-07-21 drh: ** a reference count (so we will know when to delete it) and a "cnt" dbda8d6ce9 2007-07-21 drh: ** field that tells us its internal lock status. cnt==0 means the dbda8d6ce9 2007-07-21 drh: ** file is unlocked. cnt==-1 means the file has an exclusive lock. dbda8d6ce9 2007-07-21 drh: ** cnt>0 means there are cnt shared locks on the file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Any attempt to lock or unlock a file first checks the locking dbda8d6ce9 2007-07-21 drh: ** structure. The fcntl() system call is only invoked to set a dbda8d6ce9 2007-07-21 drh: ** POSIX lock if the internal lock structure transitions between dbda8d6ce9 2007-07-21 drh: ** a locked and an unlocked state. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2004-Jan-11: dbda8d6ce9 2007-07-21 drh: ** More recent discoveries about POSIX advisory locks. (The more dbda8d6ce9 2007-07-21 drh: ** I discover, the more I realize the a POSIX advisory locks are dbda8d6ce9 2007-07-21 drh: ** an abomination.) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If you close a file descriptor that points to a file that has locks, dbda8d6ce9 2007-07-21 drh: ** all locks on that file that are owned by the current process are c287665ba8 2007-09-14 drh: ** released. To work around this problem, each unixFile structure contains dbda8d6ce9 2007-07-21 drh: ** a pointer to an openCnt structure. There is one openCnt structure c287665ba8 2007-09-14 drh: ** per open inode, which means that multiple unixFile can point to a single c287665ba8 2007-09-14 drh: ** openCnt. When an attempt is made to close an unixFile, if there are c287665ba8 2007-09-14 drh: ** other unixFile open on the same inode that are holding locks, the call dbda8d6ce9 2007-07-21 drh: ** to close() the file descriptor is deferred until all of the locks clear. dbda8d6ce9 2007-07-21 drh: ** The openCnt structure keeps a list of file descriptors that need to dbda8d6ce9 2007-07-21 drh: ** be closed and that list is walked (and cleared) when the last lock dbda8d6ce9 2007-07-21 drh: ** clears. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** First, under Linux threads, because each thread has a separate dbda8d6ce9 2007-07-21 drh: ** process ID, lock operations in one thread do not override locks dbda8d6ce9 2007-07-21 drh: ** to the same file in other threads. Linux threads behave like dbda8d6ce9 2007-07-21 drh: ** separate processes in this respect. But, if you close a file dbda8d6ce9 2007-07-21 drh: ** descriptor in linux threads, all locks are cleared, even locks dbda8d6ce9 2007-07-21 drh: ** on other threads and even though the other threads have different dbda8d6ce9 2007-07-21 drh: ** process IDs. Linux threads is inconsistent in this respect. dbda8d6ce9 2007-07-21 drh: ** (I'm beginning to think that linux threads is an abomination too.) dbda8d6ce9 2007-07-21 drh: ** The consequence of this all is that the hash table for the lockInfo dbda8d6ce9 2007-07-21 drh: ** structure has to include the process id as part of its key because dbda8d6ce9 2007-07-21 drh: ** locks in different threads are treated as distinct. But the dbda8d6ce9 2007-07-21 drh: ** openCnt structure should not include the process id in its dbda8d6ce9 2007-07-21 drh: ** key because close() clears lock on all threads, not just the current dbda8d6ce9 2007-07-21 drh: ** thread. Were it not for this goofiness in linux threads, we could dbda8d6ce9 2007-07-21 drh: ** combine the lockInfo and openCnt structures into a single structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2004-Jun-28: dbda8d6ce9 2007-07-21 drh: ** On some versions of linux, threads can override each others locks. dbda8d6ce9 2007-07-21 drh: ** On others not. Sometimes you can change the behavior on the same dbda8d6ce9 2007-07-21 drh: ** system by setting the LD_ASSUME_KERNEL environment variable. The dbda8d6ce9 2007-07-21 drh: ** POSIX standard is silent as to which behavior is correct, as far dbda8d6ce9 2007-07-21 drh: ** as I can tell, so other versions of unix might show the same dbda8d6ce9 2007-07-21 drh: ** inconsistency. There is no little doubt in my mind that posix dbda8d6ce9 2007-07-21 drh: ** advisory locks and linux threads are profoundly broken. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To work around the inconsistencies, we have to test at runtime dbda8d6ce9 2007-07-21 drh: ** whether or not threads can override each others locks. This test dbda8d6ce9 2007-07-21 drh: ** is run once, the first time any lock is attempted. A static dbda8d6ce9 2007-07-21 drh: ** variable is set to record the results of this test for future dbda8d6ce9 2007-07-21 drh: ** use. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure serves as the key used dbda8d6ce9 2007-07-21 drh: ** to locate a particular lockInfo structure given its inode. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If threads cannot override each others locks, then we set the dbda8d6ce9 2007-07-21 drh: ** lockKey.tid field to the thread ID. If threads can override dbda8d6ce9 2007-07-21 drh: ** each others locks then tid is always set to zero. tid is omitted dbda8d6ce9 2007-07-21 drh: ** if we compile without threading support. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct lockKey { dbda8d6ce9 2007-07-21 drh: dev_t dev; /* Device number */ dbda8d6ce9 2007-07-21 drh: ino_t ino; /* Inode number */ c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE dbda8d6ce9 2007-07-21 drh: pthread_t tid; /* Thread ID or zero if threads can override each other */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure is allocated for each open dbda8d6ce9 2007-07-21 drh: ** inode on each thread with a different process ID. (Threads have dbda8d6ce9 2007-07-21 drh: ** different process IDs on linux, but not on most other unixes.) dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** A single inode can have multiple file descriptors, so each unixFile dbda8d6ce9 2007-07-21 drh: ** structure contains a pointer to an instance of this object and this c287665ba8 2007-09-14 drh: ** object keeps a count of the number of unixFile pointing to it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct lockInfo { dbda8d6ce9 2007-07-21 drh: struct lockKey key; /* The lookup key */ dbda8d6ce9 2007-07-21 drh: int cnt; /* Number of SHARED locks held */ dbda8d6ce9 2007-07-21 drh: int locktype; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ dbda8d6ce9 2007-07-21 drh: int nRef; /* Number of pointers to this structure */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure serves as the key used dbda8d6ce9 2007-07-21 drh: ** to locate a particular openCnt structure given its inode. This dbda8d6ce9 2007-07-21 drh: ** is the same as the lockKey except that the thread ID is omitted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct openKey { dbda8d6ce9 2007-07-21 drh: dev_t dev; /* Device number */ dbda8d6ce9 2007-07-21 drh: ino_t ino; /* Inode number */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure is allocated for each open dbda8d6ce9 2007-07-21 drh: ** inode. This structure keeps track of the number of locks on that dbda8d6ce9 2007-07-21 drh: ** inode. If a close is attempted against an inode that is holding dbda8d6ce9 2007-07-21 drh: ** locks, the close is deferred until all locks clear by adding the dbda8d6ce9 2007-07-21 drh: ** file descriptor to be closed to the pending list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct openCnt { dbda8d6ce9 2007-07-21 drh: struct openKey key; /* The lookup key */ dbda8d6ce9 2007-07-21 drh: int nRef; /* Number of pointers to this structure */ dbda8d6ce9 2007-07-21 drh: int nLock; /* Number of outstanding locks */ dbda8d6ce9 2007-07-21 drh: int nPending; /* Number of pending close() operations */ dbda8d6ce9 2007-07-21 drh: int *aPending; /* Malloced space holding fd's awaiting a close() */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** These hash tables map inodes and file descriptors (really, lockKey and dbda8d6ce9 2007-07-21 drh: ** openKey structures) into lockInfo and openCnt structures. Access to dbda8d6ce9 2007-07-21 drh: ** these hash tables must be protected by a mutex. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0}; c287665ba8 2007-09-14 drh: static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0}; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_LOCKING_STYLE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The locking styles are associated with the different file locking dbda8d6ce9 2007-07-21 drh: ** capabilities supported by different file systems. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** POSIX locking style fully supports shared and exclusive byte-range locks dbda8d6ce9 2007-07-21 drh: ** ADP locking only supports exclusive byte-range locks dbda8d6ce9 2007-07-21 drh: ** FLOCK only supports a single file-global exclusive lock dbda8d6ce9 2007-07-21 drh: ** DOTLOCK isn't a true locking style, it refers to the use of a special dbda8d6ce9 2007-07-21 drh: ** file named the same as the database file with a '.lock' extension, this dbda8d6ce9 2007-07-21 drh: ** can be used on file systems that do not offer any reliable file locking dbda8d6ce9 2007-07-21 drh: ** NO locking means that no locking will be attempted, this is only used for dbda8d6ce9 2007-07-21 drh: ** read-only file systems currently dbda8d6ce9 2007-07-21 drh: ** UNSUPPORTED means that no locking will be attempted, this is only used for dbda8d6ce9 2007-07-21 drh: ** file systems that are known to be unsupported dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef enum { c287665ba8 2007-09-14 drh: posixLockingStyle = 0, /* standard posix-advisory locks */ c287665ba8 2007-09-14 drh: afpLockingStyle, /* use afp locks */ c287665ba8 2007-09-14 drh: flockLockingStyle, /* use flock() */ c287665ba8 2007-09-14 drh: dotlockLockingStyle, /* use <file>.lock files */ c287665ba8 2007-09-14 drh: noLockingStyle, /* useful for read-only file system */ c287665ba8 2007-09-14 drh: unsupportedLockingStyle /* indicates unsupported file system */ dbda8d6ce9 2007-07-21 drh: } sqlite3LockingStyle; dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ENABLE_LOCKING_STYLE */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Helper functions to obtain and relinquish the global mutex. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void enterMutex(){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: static void leaveMutex(){ c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This variable records whether or not threads can override each others dbda8d6ce9 2007-07-21 drh: ** locks. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 0: No. Threads cannot override each others locks. dbda8d6ce9 2007-07-21 drh: ** 1: Yes. Threads can override each others locks. dbda8d6ce9 2007-07-21 drh: ** -1: We don't know yet. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On some systems, we know at compile-time if threads can override each dbda8d6ce9 2007-07-21 drh: ** others locks. On those systems, the SQLITE_THREAD_OVERRIDE_LOCK macro dbda8d6ce9 2007-07-21 drh: ** will be set appropriately. On other systems, we have to check at dbda8d6ce9 2007-07-21 drh: ** runtime. On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is dbda8d6ce9 2007-07-21 drh: ** undefined. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This variable normally has file scope only. But during testing, we make dbda8d6ce9 2007-07-21 drh: ** it a global so that the test code can change its value in order to verify dbda8d6ce9 2007-07-21 drh: ** that the right stuff happens in either case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_THREAD_OVERRIDE_LOCK dbda8d6ce9 2007-07-21 drh: # define SQLITE_THREAD_OVERRIDE_LOCK -1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: static int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This structure holds information passed into individual test dbda8d6ce9 2007-07-21 drh: ** threads by the testThreadLockingBehavior() routine. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct threadTestData { dbda8d6ce9 2007-07-21 drh: int fd; /* File to be locked */ dbda8d6ce9 2007-07-21 drh: struct flock lock; /* The locking operation */ dbda8d6ce9 2007-07-21 drh: int result; /* Result of the locking operation */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_LOCK_TRACE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print out information about all locking operations. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is used for troubleshooting locks on multithreaded dbda8d6ce9 2007-07-21 drh: ** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE dbda8d6ce9 2007-07-21 drh: ** command-line option on the compiler. This code is normally dbda8d6ce9 2007-07-21 drh: ** turned off. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int lockTrace(int fd, int op, struct flock *p){ dbda8d6ce9 2007-07-21 drh: char *zOpName, *zType; dbda8d6ce9 2007-07-21 drh: int s; dbda8d6ce9 2007-07-21 drh: int savedErrno; dbda8d6ce9 2007-07-21 drh: if( op==F_GETLK ){ dbda8d6ce9 2007-07-21 drh: zOpName = "GETLK"; dbda8d6ce9 2007-07-21 drh: }else if( op==F_SETLK ){ dbda8d6ce9 2007-07-21 drh: zOpName = "SETLK"; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: s = fcntl(fd, op, p); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); dbda8d6ce9 2007-07-21 drh: return s; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->l_type==F_RDLCK ){ dbda8d6ce9 2007-07-21 drh: zType = "RDLCK"; dbda8d6ce9 2007-07-21 drh: }else if( p->l_type==F_WRLCK ){ dbda8d6ce9 2007-07-21 drh: zType = "WRLCK"; dbda8d6ce9 2007-07-21 drh: }else if( p->l_type==F_UNLCK ){ dbda8d6ce9 2007-07-21 drh: zType = "UNLCK"; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( 0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( p->l_whence==SEEK_SET ); dbda8d6ce9 2007-07-21 drh: s = fcntl(fd, op, p); dbda8d6ce9 2007-07-21 drh: savedErrno = errno; dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", dbda8d6ce9 2007-07-21 drh: threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, dbda8d6ce9 2007-07-21 drh: (int)p->l_pid, s); dbda8d6ce9 2007-07-21 drh: if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ dbda8d6ce9 2007-07-21 drh: struct flock l2; dbda8d6ce9 2007-07-21 drh: l2 = *p; dbda8d6ce9 2007-07-21 drh: fcntl(fd, F_GETLK, &l2); dbda8d6ce9 2007-07-21 drh: if( l2.l_type==F_RDLCK ){ dbda8d6ce9 2007-07-21 drh: zType = "RDLCK"; dbda8d6ce9 2007-07-21 drh: }else if( l2.l_type==F_WRLCK ){ dbda8d6ce9 2007-07-21 drh: zType = "WRLCK"; dbda8d6ce9 2007-07-21 drh: }else if( l2.l_type==F_UNLCK ){ dbda8d6ce9 2007-07-21 drh: zType = "UNLCK"; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( 0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n", dbda8d6ce9 2007-07-21 drh: zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: errno = savedErrno; dbda8d6ce9 2007-07-21 drh: return s; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #define fcntl lockTrace dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_LOCK_TRACE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The testThreadLockingBehavior() routine launches two separate dbda8d6ce9 2007-07-21 drh: ** threads on this routine. This routine attempts to lock a file dbda8d6ce9 2007-07-21 drh: ** descriptor then returns. The success or failure of that attempt dbda8d6ce9 2007-07-21 drh: ** allows the testThreadLockingBehavior() procedure to determine dbda8d6ce9 2007-07-21 drh: ** whether or not threads can override each others locks. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void *threadLockingTest(void *pArg){ dbda8d6ce9 2007-07-21 drh: struct threadTestData *pData = (struct threadTestData*)pArg; dbda8d6ce9 2007-07-21 drh: pData->result = fcntl(pData->fd, F_SETLK, &pData->lock); dbda8d6ce9 2007-07-21 drh: return pArg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This procedure attempts to determine whether or not threads dbda8d6ce9 2007-07-21 drh: ** can override each others locks then sets the dbda8d6ce9 2007-07-21 drh: ** threadsOverrideEachOthersLocks variable appropriately. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void testThreadLockingBehavior(int fd_orig){ dbda8d6ce9 2007-07-21 drh: int fd; dbda8d6ce9 2007-07-21 drh: struct threadTestData d[2]; dbda8d6ce9 2007-07-21 drh: pthread_t t[2]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: fd = dup(fd_orig); dbda8d6ce9 2007-07-21 drh: if( fd<0 ) return; dbda8d6ce9 2007-07-21 drh: memset(d, 0, sizeof(d)); dbda8d6ce9 2007-07-21 drh: d[0].fd = fd; dbda8d6ce9 2007-07-21 drh: d[0].lock.l_type = F_RDLCK; dbda8d6ce9 2007-07-21 drh: d[0].lock.l_len = 1; dbda8d6ce9 2007-07-21 drh: d[0].lock.l_start = 0; dbda8d6ce9 2007-07-21 drh: d[0].lock.l_whence = SEEK_SET; dbda8d6ce9 2007-07-21 drh: d[1] = d[0]; dbda8d6ce9 2007-07-21 drh: d[1].lock.l_type = F_WRLCK; dbda8d6ce9 2007-07-21 drh: pthread_create(&t[0], 0, threadLockingTest, &d[0]); dbda8d6ce9 2007-07-21 drh: pthread_create(&t[1], 0, threadLockingTest, &d[1]); dbda8d6ce9 2007-07-21 drh: pthread_join(t[0], 0); dbda8d6ce9 2007-07-21 drh: pthread_join(t[1], 0); dbda8d6ce9 2007-07-21 drh: close(fd); dbda8d6ce9 2007-07-21 drh: threadsOverrideEachOthersLocks = d[0].result==0 && d[1].result==0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: #endif /* SQLITE_THREADSAFE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release a lockInfo structure previously allocated by findLockInfo(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void releaseLockInfo(struct lockInfo *pLock){ dbda8d6ce9 2007-07-21 drh: if (pLock == NULL) dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: pLock->nRef--; dbda8d6ce9 2007-07-21 drh: if( pLock->nRef==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); c287665ba8 2007-09-14 drh: sqlite3_free(pLock); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release a openCnt structure previously allocated by findLockInfo(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void releaseOpenCnt(struct openCnt *pOpen){ dbda8d6ce9 2007-07-21 drh: if (pOpen == NULL) dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: pOpen->nRef--; dbda8d6ce9 2007-07-21 drh: if( pOpen->nRef==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); dbda8d6ce9 2007-07-21 drh: free(pOpen->aPending); c287665ba8 2007-09-14 drh: sqlite3_free(pOpen); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_LOCKING_STYLE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Tests a byte-range locking query to see if byte range locks are dbda8d6ce9 2007-07-21 drh: ** supported, if not we fall back to dotlockLockingStyle. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static sqlite3LockingStyle sqlite3TestLockingStyle( c287665ba8 2007-09-14 drh: const char *filePath, c287665ba8 2007-09-14 drh: int fd c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: /* test byte-range lock using fcntl */ dbda8d6ce9 2007-07-21 drh: struct flock lockInfo; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: lockInfo.l_len = 1; dbda8d6ce9 2007-07-21 drh: lockInfo.l_start = 0; dbda8d6ce9 2007-07-21 drh: lockInfo.l_whence = SEEK_SET; dbda8d6ce9 2007-07-21 drh: lockInfo.l_type = F_RDLCK; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( fcntl(fd, F_GETLK, &lockInfo)!=-1 ) { dbda8d6ce9 2007-07-21 drh: return posixLockingStyle; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* testing for flock can give false positives. So if if the above test dbda8d6ce9 2007-07-21 drh: ** fails, then we fall back to using dot-lock style locking. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: return dotlockLockingStyle; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Examines the f_fstypename entry in the statfs structure as returned by dbda8d6ce9 2007-07-21 drh: ** stat() for the file system hosting the database file, assigns the dbda8d6ce9 2007-07-21 drh: ** appropriate locking style based on it's value. These values and dbda8d6ce9 2007-07-21 drh: ** assignments are based on Darwin/OSX behavior and have not been tested on dbda8d6ce9 2007-07-21 drh: ** other systems. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static sqlite3LockingStyle sqlite3DetectLockingStyle( c287665ba8 2007-09-14 drh: const char *filePath, c287665ba8 2007-09-14 drh: int fd c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_FIXED_LOCKING_STYLE dbda8d6ce9 2007-07-21 drh: return (sqlite3LockingStyle)SQLITE_FIXED_LOCKING_STYLE; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: struct statfs fsInfo; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if (statfs(filePath, &fsInfo) == -1) dbda8d6ce9 2007-07-21 drh: return sqlite3TestLockingStyle(filePath, fd); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if (fsInfo.f_flags & MNT_RDONLY) dbda8d6ce9 2007-07-21 drh: return noLockingStyle; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( (!strcmp(fsInfo.f_fstypename, "hfs")) || dbda8d6ce9 2007-07-21 drh: (!strcmp(fsInfo.f_fstypename, "ufs")) ) c287665ba8 2007-09-14 drh: return posixLockingStyle; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if(!strcmp(fsInfo.f_fstypename, "afpfs")) dbda8d6ce9 2007-07-21 drh: return afpLockingStyle; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if(!strcmp(fsInfo.f_fstypename, "nfs")) dbda8d6ce9 2007-07-21 drh: return sqlite3TestLockingStyle(filePath, fd); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if(!strcmp(fsInfo.f_fstypename, "smbfs")) dbda8d6ce9 2007-07-21 drh: return flockLockingStyle; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if(!strcmp(fsInfo.f_fstypename, "msdos")) dbda8d6ce9 2007-07-21 drh: return dotlockLockingStyle; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if(!strcmp(fsInfo.f_fstypename, "webdav")) dbda8d6ce9 2007-07-21 drh: return unsupportedLockingStyle; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return sqlite3TestLockingStyle(filePath, fd); dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_FIXED_LOCKING_STYLE */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ENABLE_LOCKING_STYLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given a file descriptor, locate lockInfo and openCnt structures that dbda8d6ce9 2007-07-21 drh: ** describes that file descriptor. Create new ones if necessary. The dbda8d6ce9 2007-07-21 drh: ** return values might be uninitialized if an error occurs. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the number of errors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int findLockInfo( dbda8d6ce9 2007-07-21 drh: int fd, /* The file descriptor used in the key */ dbda8d6ce9 2007-07-21 drh: struct lockInfo **ppLock, /* Return the lockInfo structure here */ dbda8d6ce9 2007-07-21 drh: struct openCnt **ppOpen /* Return the openCnt structure here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: struct lockKey key1; dbda8d6ce9 2007-07-21 drh: struct openKey key2; dbda8d6ce9 2007-07-21 drh: struct stat statbuf; dbda8d6ce9 2007-07-21 drh: struct lockInfo *pLock; dbda8d6ce9 2007-07-21 drh: struct openCnt *pOpen; dbda8d6ce9 2007-07-21 drh: rc = fstat(fd, &statbuf); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ) return 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memset(&key1, 0, sizeof(key1)); dbda8d6ce9 2007-07-21 drh: key1.dev = statbuf.st_dev; dbda8d6ce9 2007-07-21 drh: key1.ino = statbuf.st_ino; c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE dbda8d6ce9 2007-07-21 drh: if( threadsOverrideEachOthersLocks<0 ){ dbda8d6ce9 2007-07-21 drh: testThreadLockingBehavior(fd); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: key1.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self(); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: memset(&key2, 0, sizeof(key2)); dbda8d6ce9 2007-07-21 drh: key2.dev = statbuf.st_dev; dbda8d6ce9 2007-07-21 drh: key2.ino = statbuf.st_ino; dbda8d6ce9 2007-07-21 drh: pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1)); dbda8d6ce9 2007-07-21 drh: if( pLock==0 ){ dbda8d6ce9 2007-07-21 drh: struct lockInfo *pOld; c287665ba8 2007-09-14 drh: pLock = sqlite3_malloc( sizeof(*pLock) ); dbda8d6ce9 2007-07-21 drh: if( pLock==0 ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto exit_findlockinfo; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pLock->key = key1; dbda8d6ce9 2007-07-21 drh: pLock->nRef = 1; dbda8d6ce9 2007-07-21 drh: pLock->cnt = 0; dbda8d6ce9 2007-07-21 drh: pLock->locktype = 0; dbda8d6ce9 2007-07-21 drh: pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); dbda8d6ce9 2007-07-21 drh: if( pOld!=0 ){ dbda8d6ce9 2007-07-21 drh: assert( pOld==pLock ); c287665ba8 2007-09-14 drh: sqlite3_free(pLock); dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto exit_findlockinfo; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pLock->nRef++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *ppLock = pLock; dbda8d6ce9 2007-07-21 drh: if( ppOpen!=0 ){ dbda8d6ce9 2007-07-21 drh: pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2)); dbda8d6ce9 2007-07-21 drh: if( pOpen==0 ){ dbda8d6ce9 2007-07-21 drh: struct openCnt *pOld; c287665ba8 2007-09-14 drh: pOpen = sqlite3_malloc( sizeof(*pOpen) ); dbda8d6ce9 2007-07-21 drh: if( pOpen==0 ){ dbda8d6ce9 2007-07-21 drh: releaseLockInfo(pLock); dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto exit_findlockinfo; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pOpen->key = key2; dbda8d6ce9 2007-07-21 drh: pOpen->nRef = 1; dbda8d6ce9 2007-07-21 drh: pOpen->nLock = 0; dbda8d6ce9 2007-07-21 drh: pOpen->nPending = 0; dbda8d6ce9 2007-07-21 drh: pOpen->aPending = 0; dbda8d6ce9 2007-07-21 drh: pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); dbda8d6ce9 2007-07-21 drh: if( pOld!=0 ){ dbda8d6ce9 2007-07-21 drh: assert( pOld==pOpen ); c287665ba8 2007-09-14 drh: sqlite3_free(pOpen); dbda8d6ce9 2007-07-21 drh: releaseLockInfo(pLock); dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto exit_findlockinfo; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pOpen->nRef++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *ppOpen = pOpen; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: exit_findlockinfo: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Helper function for printing out trace information from debugging dbda8d6ce9 2007-07-21 drh: ** binaries. This returns the string represetation of the supplied dbda8d6ce9 2007-07-21 drh: ** integer lock-type. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const char *locktypeName(int locktype){ dbda8d6ce9 2007-07-21 drh: switch( locktype ){ dbda8d6ce9 2007-07-21 drh: case NO_LOCK: return "NONE"; dbda8d6ce9 2007-07-21 drh: case SHARED_LOCK: return "SHARED"; dbda8d6ce9 2007-07-21 drh: case RESERVED_LOCK: return "RESERVED"; dbda8d6ce9 2007-07-21 drh: case PENDING_LOCK: return "PENDING"; dbda8d6ce9 2007-07-21 drh: case EXCLUSIVE_LOCK: return "EXCLUSIVE"; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return "ERROR"; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If we are currently in a different thread than the thread that the dbda8d6ce9 2007-07-21 drh: ** unixFile argument belongs to, then transfer ownership of the unixFile dbda8d6ce9 2007-07-21 drh: ** over to the current thread. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A unixFile is only owned by a thread on systems where one thread is dbda8d6ce9 2007-07-21 drh: ** unable to override locks created by a different thread. RedHat9 is dbda8d6ce9 2007-07-21 drh: ** an example of such a system. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Ownership transfer is only allowed if the unixFile is currently unlocked. dbda8d6ce9 2007-07-21 drh: ** If the unixFile is locked and an ownership is wrong, then return dbda8d6ce9 2007-07-21 drh: ** SQLITE_MISUSE. SQLITE_OK is returned if everything works. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE dbda8d6ce9 2007-07-21 drh: static int transferOwnership(unixFile *pFile){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: pthread_t hSelf; dbda8d6ce9 2007-07-21 drh: if( threadsOverrideEachOthersLocks ){ dbda8d6ce9 2007-07-21 drh: /* Ownership transfers not needed on this system */ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: hSelf = pthread_self(); dbda8d6ce9 2007-07-21 drh: if( pthread_equal(pFile->tid, hSelf) ){ dbda8d6ce9 2007-07-21 drh: /* We are still in the same thread */ dbda8d6ce9 2007-07-21 drh: OSTRACE1("No-transfer, same thread\n"); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pFile->locktype!=NO_LOCK ){ dbda8d6ce9 2007-07-21 drh: /* We cannot change ownership while we are holding a lock! */ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: OSTRACE4("Transfer ownership of %d from %d to %d\n", dbda8d6ce9 2007-07-21 drh: pFile->h, pFile->tid, hSelf); dbda8d6ce9 2007-07-21 drh: pFile->tid = hSelf; dbda8d6ce9 2007-07-21 drh: if (pFile->pLock != NULL) { dbda8d6ce9 2007-07-21 drh: releaseLockInfo(pFile->pLock); dbda8d6ce9 2007-07-21 drh: rc = findLockInfo(pFile->h, &pFile->pLock, 0); dbda8d6ce9 2007-07-21 drh: OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h, dbda8d6ce9 2007-07-21 drh: locktypeName(pFile->locktype), dbda8d6ce9 2007-07-21 drh: locktypeName(pFile->pLock->locktype), pFile->pLock->cnt); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: /* On single-threaded builds, ownership transfer is a no-op */ dbda8d6ce9 2007-07-21 drh: # define transferOwnership(X) SQLITE_OK dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Seek to the offset passed as the second argument, then read cnt c287665ba8 2007-09-14 drh: ** bytes into pBuf. Return the number of bytes actually read. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ dbda8d6ce9 2007-07-21 drh: int got; dbda8d6ce9 2007-07-21 drh: i64 newOffset; dbda8d6ce9 2007-07-21 drh: TIMER_START; dbda8d6ce9 2007-07-21 drh: #if defined(USE_PREAD) c287665ba8 2007-09-14 drh: got = pread(id->h, pBuf, cnt, offset); dbda8d6ce9 2007-07-21 drh: SimulateIOError( got = -1 ); dbda8d6ce9 2007-07-21 drh: #elif defined(USE_PREAD64) c287665ba8 2007-09-14 drh: got = pread64(id->h, pBuf, cnt, offset); dbda8d6ce9 2007-07-21 drh: SimulateIOError( got = -1 ); dbda8d6ce9 2007-07-21 drh: #else c287665ba8 2007-09-14 drh: newOffset = lseek(id->h, offset, SEEK_SET); dbda8d6ce9 2007-07-21 drh: SimulateIOError( newOffset-- ); c287665ba8 2007-09-14 drh: if( newOffset!=offset ){ dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: got = read(id->h, pBuf, cnt); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: TIMER_END; c287665ba8 2007-09-14 drh: OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED); dbda8d6ce9 2007-07-21 drh: return got; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read data from a file into a buffer. Return SQLITE_OK if all dbda8d6ce9 2007-07-21 drh: ** bytes were read successfully and SQLITE_IOERR if anything goes dbda8d6ce9 2007-07-21 drh: ** wrong. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixRead( c287665ba8 2007-09-14 drh: sqlite3_file *id, c287665ba8 2007-09-14 drh: void *pBuf, c287665ba8 2007-09-14 drh: int amt, c287665ba8 2007-09-14 drh: sqlite3_int64 offset c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: int got; dbda8d6ce9 2007-07-21 drh: assert( id ); c287665ba8 2007-09-14 drh: got = seekAndRead((unixFile*)id, offset, pBuf, amt); dbda8d6ce9 2007-07-21 drh: if( got==amt ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: }else if( got<0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_READ; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: memset(&((char*)pBuf)[got], 0, amt-got); dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_SHORT_READ; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Seek to the offset in id->offset then read cnt bytes into pBuf. dbda8d6ce9 2007-07-21 drh: ** Return the number of bytes actually read. Update the offset. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ dbda8d6ce9 2007-07-21 drh: int got; dbda8d6ce9 2007-07-21 drh: i64 newOffset; dbda8d6ce9 2007-07-21 drh: TIMER_START; dbda8d6ce9 2007-07-21 drh: #if defined(USE_PREAD) c287665ba8 2007-09-14 drh: got = pwrite(id->h, pBuf, cnt, offset); dbda8d6ce9 2007-07-21 drh: #elif defined(USE_PREAD64) c287665ba8 2007-09-14 drh: got = pwrite64(id->h, pBuf, cnt, offset); c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: newOffset = lseek(id->h, offset, SEEK_SET); c287665ba8 2007-09-14 drh: if( newOffset!=offset ){ dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: got = write(id->h, pBuf, cnt); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: TIMER_END; c287665ba8 2007-09-14 drh: OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED); dbda8d6ce9 2007-07-21 drh: return got; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write data from a buffer into a file. Return SQLITE_OK on success dbda8d6ce9 2007-07-21 drh: ** or some other error code on failure. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixWrite( c287665ba8 2007-09-14 drh: sqlite3_file *id, c287665ba8 2007-09-14 drh: const void *pBuf, c287665ba8 2007-09-14 drh: int amt, c287665ba8 2007-09-14 drh: sqlite3_int64 offset c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: int wrote = 0; dbda8d6ce9 2007-07-21 drh: assert( id ); dbda8d6ce9 2007-07-21 drh: assert( amt>0 ); c287665ba8 2007-09-14 drh: while( amt>0 && (wrote = seekAndWrite((unixFile*)id, offset, pBuf, amt))>0 ){ dbda8d6ce9 2007-07-21 drh: amt -= wrote; c287665ba8 2007-09-14 drh: offset += wrote; dbda8d6ce9 2007-07-21 drh: pBuf = &((char*)pBuf)[wrote]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SimulateIOError(( wrote=(-1), amt=1 )); dbda8d6ce9 2007-07-21 drh: SimulateDiskfullError(( wrote=0, amt=1 )); dbda8d6ce9 2007-07-21 drh: if( amt>0 ){ dbda8d6ce9 2007-07-21 drh: if( wrote<0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_WRITE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return SQLITE_FULL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Count the number of fullsyncs and normal syncs. This is used to test dbda8d6ce9 2007-07-21 drh: ** that syncs and fullsyncs are occuring at the right times. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_sync_count = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_fullsync_count = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined. dbda8d6ce9 2007-07-21 drh: ** Otherwise use fsync() in its place. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef HAVE_FDATASYNC dbda8d6ce9 2007-07-21 drh: # define fdatasync fsync dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not dbda8d6ce9 2007-07-21 drh: ** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently dbda8d6ce9 2007-07-21 drh: ** only available on Mac OS X. But that could change. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef F_FULLFSYNC dbda8d6ce9 2007-07-21 drh: # define HAVE_FULLFSYNC 1 dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define HAVE_FULLFSYNC 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The fsync() system call does not work as advertised on many dbda8d6ce9 2007-07-21 drh: ** unix systems. The following procedure is an attempt to make dbda8d6ce9 2007-07-21 drh: ** it work better. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful dbda8d6ce9 2007-07-21 drh: ** for testing when we want to run through the test suite quickly. dbda8d6ce9 2007-07-21 drh: ** You are strongly advised *not* to deploy with SQLITE_NO_SYNC dbda8d6ce9 2007-07-21 drh: ** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash dbda8d6ce9 2007-07-21 drh: ** or power failure will likely corrupt the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int full_fsync(int fd, int fullSync, int dataOnly){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Record the number of times that we do a normal fsync() and dbda8d6ce9 2007-07-21 drh: ** FULLSYNC. This is used during testing to verify that this procedure dbda8d6ce9 2007-07-21 drh: ** gets called with the correct arguments. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: if( fullSync ) sqlite3_fullsync_count++; dbda8d6ce9 2007-07-21 drh: sqlite3_sync_count++; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a dbda8d6ce9 2007-07-21 drh: ** no-op dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_NO_SYNC dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if HAVE_FULLFSYNC dbda8d6ce9 2007-07-21 drh: if( fullSync ){ dbda8d6ce9 2007-07-21 drh: rc = fcntl(fd, F_FULLFSYNC, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* If the FULLFSYNC failed, fall back to attempting an fsync(). dbda8d6ce9 2007-07-21 drh: * It shouldn't be possible for fullfsync to fail on the local dbda8d6ce9 2007-07-21 drh: * file system (on OSX), so failure indicates that FULLFSYNC dbda8d6ce9 2007-07-21 drh: * isn't supported for this file system. So, attempt an fsync dbda8d6ce9 2007-07-21 drh: * and (for now) ignore the overhead of a superfluous fcntl call. dbda8d6ce9 2007-07-21 drh: * It'd be better to detect fullfsync support once and avoid dbda8d6ce9 2007-07-21 drh: * the fcntl call every time sync is called. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc ) rc = fsync(fd); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: if( dataOnly ){ dbda8d6ce9 2007-07-21 drh: rc = fdatasync(fd); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = fsync(fd); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* HAVE_FULLFSYNC */ dbda8d6ce9 2007-07-21 drh: #endif /* defined(SQLITE_NO_SYNC) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make sure all writes to a particular file are committed to disk. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If dataOnly==0 then both the file itself and its metadata (file dbda8d6ce9 2007-07-21 drh: ** size, access time, etc) are synced. If dataOnly!=0 then only the dbda8d6ce9 2007-07-21 drh: ** file data is synced. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Under Unix, also make sure that the directory entry for the file dbda8d6ce9 2007-07-21 drh: ** has been created by fsync-ing the directory that contains the file. dbda8d6ce9 2007-07-21 drh: ** If we do not do this and we encounter a power failure, the directory dbda8d6ce9 2007-07-21 drh: ** entry for the journal might not exist after we reboot. The next dbda8d6ce9 2007-07-21 drh: ** SQLite to access the file will not know that the journal exists (because dbda8d6ce9 2007-07-21 drh: ** the directory entry for the journal was never created) and the transaction dbda8d6ce9 2007-07-21 drh: ** will not roll back - possibly leading to database corruption. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixSync(sqlite3_file *id, int flags){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: unixFile *pFile = (unixFile*)id; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: int isDataOnly = (flags&SQLITE_SYNC_DATAONLY); c287665ba8 2007-09-14 drh: int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ c287665ba8 2007-09-14 drh: assert((flags&0x0F)==SQLITE_SYNC_NORMAL c287665ba8 2007-09-14 drh: || (flags&0x0F)==SQLITE_SYNC_FULL c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: assert( pFile ); dbda8d6ce9 2007-07-21 drh: OSTRACE2("SYNC %-3d\n", pFile->h); c287665ba8 2007-09-14 drh: rc = full_fsync(pFile->h, isFullsync, isDataOnly); dbda8d6ce9 2007-07-21 drh: SimulateIOError( rc=1 ); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_FSYNC; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pFile->dirfd>=0 ){ dbda8d6ce9 2007-07-21 drh: OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd, c287665ba8 2007-09-14 drh: HAVE_FULLFSYNC, isFullsync); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_DISABLE_DIRSYNC dbda8d6ce9 2007-07-21 drh: /* The directory sync is only attempted if full_fsync is dbda8d6ce9 2007-07-21 drh: ** turned off or unavailable. If a full_fsync occurred above, dbda8d6ce9 2007-07-21 drh: ** then the directory sync is superfluous. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** We have received multiple reports of fsync() returning dbda8d6ce9 2007-07-21 drh: ** errors when applied to directories on certain file systems. dbda8d6ce9 2007-07-21 drh: ** A failed directory sync is not a big deal. So it seems dbda8d6ce9 2007-07-21 drh: ** better to ignore the error. Ticket #1657 dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* return SQLITE_IOERR; */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: close(pFile->dirfd); /* Only need to sync once, so close the directory */ dbda8d6ce9 2007-07-21 drh: pFile->dirfd = -1; /* when we are done. */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Truncate an open file to a specified size dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixTruncate(sqlite3_file *id, i64 nByte){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( id ); dbda8d6ce9 2007-07-21 drh: rc = ftruncate(((unixFile*)id)->h, (off_t)nByte); dbda8d6ce9 2007-07-21 drh: SimulateIOError( rc=1 ); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_TRUNCATE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Determine the current size of a file in bytes dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixFileSize(sqlite3_file *id, i64 *pSize){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: struct stat buf; dbda8d6ce9 2007-07-21 drh: assert( id ); dbda8d6ce9 2007-07-21 drh: rc = fstat(((unixFile*)id)->h, &buf); dbda8d6ce9 2007-07-21 drh: SimulateIOError( rc=1 ); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_FSTAT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pSize = buf.st_size; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine checks if there is a RESERVED lock held on the specified dbda8d6ce9 2007-07-21 drh: ** file by this or any other process. If such a lock is held, return dbda8d6ce9 2007-07-21 drh: ** non-zero. If the file is unlocked or holds only SHARED locks, then dbda8d6ce9 2007-07-21 drh: ** return zero. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixCheckReservedLock(sqlite3_file *id){ dbda8d6ce9 2007-07-21 drh: int r = 0; dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pFile ); c287665ba8 2007-09-14 drh: enterMutex(); /* Because pFile->pLock is shared across threads */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check if a thread in this process holds such a lock */ dbda8d6ce9 2007-07-21 drh: if( pFile->pLock->locktype>SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: r = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Otherwise see if some other process holds it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !r ){ dbda8d6ce9 2007-07-21 drh: struct flock lock; dbda8d6ce9 2007-07-21 drh: lock.l_whence = SEEK_SET; dbda8d6ce9 2007-07-21 drh: lock.l_start = RESERVED_BYTE; dbda8d6ce9 2007-07-21 drh: lock.l_len = 1; dbda8d6ce9 2007-07-21 drh: lock.l_type = F_WRLCK; dbda8d6ce9 2007-07-21 drh: fcntl(pFile->h, F_GETLK, &lock); dbda8d6ce9 2007-07-21 drh: if( lock.l_type!=F_UNLCK ){ dbda8d6ce9 2007-07-21 drh: r = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Lock the file with the lock specified by parameter locktype - one dbda8d6ce9 2007-07-21 drh: ** of the following: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) SHARED_LOCK dbda8d6ce9 2007-07-21 drh: ** (2) RESERVED_LOCK dbda8d6ce9 2007-07-21 drh: ** (3) PENDING_LOCK dbda8d6ce9 2007-07-21 drh: ** (4) EXCLUSIVE_LOCK dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Sometimes when requesting one lock state, additional lock states dbda8d6ce9 2007-07-21 drh: ** are inserted in between. The locking might fail on one of the later dbda8d6ce9 2007-07-21 drh: ** transitions leaving the lock state different from what it started but dbda8d6ce9 2007-07-21 drh: ** still short of its goal. The following chart shows the allowed dbda8d6ce9 2007-07-21 drh: ** transitions and the inserted intermediate states: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** UNLOCKED -> SHARED dbda8d6ce9 2007-07-21 drh: ** SHARED -> RESERVED dbda8d6ce9 2007-07-21 drh: ** SHARED -> (PENDING) -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** RESERVED -> (PENDING) -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** PENDING -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine will only increase a lock. Use the sqlite3OsUnlock() dbda8d6ce9 2007-07-21 drh: ** routine to lower a locking level. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixLock(sqlite3_file *id, int locktype){ dbda8d6ce9 2007-07-21 drh: /* The following describes the implementation of the various locks and dbda8d6ce9 2007-07-21 drh: ** lock transitions in terms of the POSIX advisory shared and exclusive dbda8d6ce9 2007-07-21 drh: ** lock primitives (called read-locks and write-locks below, to avoid dbda8d6ce9 2007-07-21 drh: ** confusion with SQLite lock names). The algorithms are complicated dbda8d6ce9 2007-07-21 drh: ** slightly in order to be compatible with windows systems simultaneously dbda8d6ce9 2007-07-21 drh: ** accessing the same database file, in case that is ever required. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved dbda8d6ce9 2007-07-21 drh: ** byte', each single bytes at well known offsets, and the 'shared byte dbda8d6ce9 2007-07-21 drh: ** range', a range of 510 bytes at a well known offset. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To obtain a SHARED lock, a read-lock is obtained on the 'pending dbda8d6ce9 2007-07-21 drh: ** byte'. If this is successful, a random byte from the 'shared byte dbda8d6ce9 2007-07-21 drh: ** range' is read-locked and the lock on the 'pending byte' released. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A process may only obtain a RESERVED lock after it has a SHARED lock. dbda8d6ce9 2007-07-21 drh: ** A RESERVED lock is implemented by grabbing a write-lock on the dbda8d6ce9 2007-07-21 drh: ** 'reserved byte'. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A process may only obtain a PENDING lock after it has obtained a dbda8d6ce9 2007-07-21 drh: ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock dbda8d6ce9 2007-07-21 drh: ** on the 'pending byte'. This ensures that no new SHARED locks can be dbda8d6ce9 2007-07-21 drh: ** obtained, but existing SHARED locks are allowed to persist. A process dbda8d6ce9 2007-07-21 drh: ** does not have to obtain a RESERVED lock on the way to a PENDING lock. dbda8d6ce9 2007-07-21 drh: ** This property is used by the algorithm for rolling back a journal file dbda8d6ce9 2007-07-21 drh: ** after a crash. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is dbda8d6ce9 2007-07-21 drh: ** implemented by obtaining a write-lock on the entire 'shared byte dbda8d6ce9 2007-07-21 drh: ** range'. Since all other locks require a read-lock on one of the bytes dbda8d6ce9 2007-07-21 drh: ** within this range, this ensures that no other locks are held on the dbda8d6ce9 2007-07-21 drh: ** database. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The reason a single byte cannot be used instead of the 'shared byte dbda8d6ce9 2007-07-21 drh: ** range' is that some versions of windows do not support read-locks. By dbda8d6ce9 2007-07-21 drh: ** locking a random byte from a range, concurrent SHARED locks may exist dbda8d6ce9 2007-07-21 drh: ** even if the locking primitive used is always a write-lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: struct lockInfo *pLock = pFile->pLock; dbda8d6ce9 2007-07-21 drh: struct flock lock; dbda8d6ce9 2007-07-21 drh: int s; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pFile ); dbda8d6ce9 2007-07-21 drh: OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h, dbda8d6ce9 2007-07-21 drh: locktypeName(locktype), locktypeName(pFile->locktype), dbda8d6ce9 2007-07-21 drh: locktypeName(pLock->locktype), pLock->cnt , getpid()); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there is already a lock of this type or more restrictive on the c287665ba8 2007-09-14 drh: ** unixFile, do nothing. Don't use the end_lock: exit path, as c287665ba8 2007-09-14 drh: ** enterMutex() hasn't been called yet. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>=locktype ){ dbda8d6ce9 2007-07-21 drh: OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h, dbda8d6ce9 2007-07-21 drh: locktypeName(locktype)); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the locking sequence is correct dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( locktype!=PENDING_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This mutex is needed because pFile->pLock is shared across threads dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: enterMutex(); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the current thread owns the pFile. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = transferOwnership(pFile); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pLock = pFile->pLock; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* If some thread using this PID has a lock via a different unixFile* dbda8d6ce9 2007-07-21 drh: ** handle that precludes the requested lock, return BUSY. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (pFile->locktype!=pLock->locktype && dbda8d6ce9 2007-07-21 drh: (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK)) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: goto end_lock; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a SHARED lock is requested, and some thread using this PID already dbda8d6ce9 2007-07-21 drh: ** has a SHARED or RESERVED lock, then increment reference counts and dbda8d6ce9 2007-07-21 drh: ** return SQLITE_OK. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK && dbda8d6ce9 2007-07-21 drh: (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){ dbda8d6ce9 2007-07-21 drh: assert( locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype==0 ); dbda8d6ce9 2007-07-21 drh: assert( pLock->cnt>0 ); dbda8d6ce9 2007-07-21 drh: pFile->locktype = SHARED_LOCK; dbda8d6ce9 2007-07-21 drh: pLock->cnt++; dbda8d6ce9 2007-07-21 drh: pFile->pOpen->nLock++; dbda8d6ce9 2007-07-21 drh: goto end_lock; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: lock.l_len = 1L; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: lock.l_whence = SEEK_SET; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A PENDING lock is needed before acquiring a SHARED lock and before dbda8d6ce9 2007-07-21 drh: ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will dbda8d6ce9 2007-07-21 drh: ** be released. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK dbda8d6ce9 2007-07-21 drh: || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK); dbda8d6ce9 2007-07-21 drh: lock.l_start = PENDING_BYTE; dbda8d6ce9 2007-07-21 drh: s = fcntl(pFile->h, F_SETLK, &lock); dbda8d6ce9 2007-07-21 drh: if( s==(-1) ){ dbda8d6ce9 2007-07-21 drh: rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: goto end_lock; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If control gets to this point, then actually go ahead and make dbda8d6ce9 2007-07-21 drh: ** operating system calls for the specified lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: assert( pLock->cnt==0 ); dbda8d6ce9 2007-07-21 drh: assert( pLock->locktype==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Now get the read-lock */ dbda8d6ce9 2007-07-21 drh: lock.l_start = SHARED_FIRST; dbda8d6ce9 2007-07-21 drh: lock.l_len = SHARED_SIZE; dbda8d6ce9 2007-07-21 drh: s = fcntl(pFile->h, F_SETLK, &lock); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Drop the temporary PENDING lock */ dbda8d6ce9 2007-07-21 drh: lock.l_start = PENDING_BYTE; dbda8d6ce9 2007-07-21 drh: lock.l_len = 1L; dbda8d6ce9 2007-07-21 drh: lock.l_type = F_UNLCK; dbda8d6ce9 2007-07-21 drh: if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ dbda8d6ce9 2007-07-21 drh: goto end_lock; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( s==(-1) ){ dbda8d6ce9 2007-07-21 drh: rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pFile->locktype = SHARED_LOCK; dbda8d6ce9 2007-07-21 drh: pFile->pOpen->nLock++; dbda8d6ce9 2007-07-21 drh: pLock->cnt = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){ dbda8d6ce9 2007-07-21 drh: /* We are trying for an exclusive lock but another thread in this dbda8d6ce9 2007-07-21 drh: ** same process is still holding a shared lock. */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The request was for a RESERVED or EXCLUSIVE lock. It is dbda8d6ce9 2007-07-21 drh: ** assumed that there is a SHARED or greater lock on the file dbda8d6ce9 2007-07-21 drh: ** already. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( 0!=pFile->locktype ); dbda8d6ce9 2007-07-21 drh: lock.l_type = F_WRLCK; dbda8d6ce9 2007-07-21 drh: switch( locktype ){ dbda8d6ce9 2007-07-21 drh: case RESERVED_LOCK: dbda8d6ce9 2007-07-21 drh: lock.l_start = RESERVED_BYTE; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case EXCLUSIVE_LOCK: dbda8d6ce9 2007-07-21 drh: lock.l_start = SHARED_FIRST; dbda8d6ce9 2007-07-21 drh: lock.l_len = SHARED_SIZE; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: default: dbda8d6ce9 2007-07-21 drh: assert(0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: s = fcntl(pFile->h, F_SETLK, &lock); dbda8d6ce9 2007-07-21 drh: if( s==(-1) ){ dbda8d6ce9 2007-07-21 drh: rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: pLock->locktype = locktype; dbda8d6ce9 2007-07-21 drh: }else if( locktype==EXCLUSIVE_LOCK ){ dbda8d6ce9 2007-07-21 drh: pFile->locktype = PENDING_LOCK; dbda8d6ce9 2007-07-21 drh: pLock->locktype = PENDING_LOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: end_lock: c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), dbda8d6ce9 2007-07-21 drh: rc==SQLITE_OK ? "ok" : "failed"); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Lower the locking level on file descriptor pFile to locktype. locktype dbda8d6ce9 2007-07-21 drh: ** must be either NO_LOCK or SHARED_LOCK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the locking level of the file descriptor is already at or below dbda8d6ce9 2007-07-21 drh: ** the requested locking level, this routine is a no-op. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixUnlock(sqlite3_file *id, int locktype){ dbda8d6ce9 2007-07-21 drh: struct lockInfo *pLock; dbda8d6ce9 2007-07-21 drh: struct flock lock; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pFile ); dbda8d6ce9 2007-07-21 drh: OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype, dbda8d6ce9 2007-07-21 drh: pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid()); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( locktype<=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: if( pFile->locktype<=locktype ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( CHECK_THREADID(pFile) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: enterMutex(); dbda8d6ce9 2007-07-21 drh: pLock = pFile->pLock; dbda8d6ce9 2007-07-21 drh: assert( pLock->cnt!=0 ); dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: assert( pLock->locktype==pFile->locktype ); dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: lock.l_type = F_RDLCK; dbda8d6ce9 2007-07-21 drh: lock.l_whence = SEEK_SET; dbda8d6ce9 2007-07-21 drh: lock.l_start = SHARED_FIRST; dbda8d6ce9 2007-07-21 drh: lock.l_len = SHARED_SIZE; dbda8d6ce9 2007-07-21 drh: if( fcntl(pFile->h, F_SETLK, &lock)==(-1) ){ dbda8d6ce9 2007-07-21 drh: /* This should never happen */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_RDLOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: lock.l_type = F_UNLCK; dbda8d6ce9 2007-07-21 drh: lock.l_whence = SEEK_SET; dbda8d6ce9 2007-07-21 drh: lock.l_start = PENDING_BYTE; dbda8d6ce9 2007-07-21 drh: lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); dbda8d6ce9 2007-07-21 drh: if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){ dbda8d6ce9 2007-07-21 drh: pLock->locktype = SHARED_LOCK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( locktype==NO_LOCK ){ dbda8d6ce9 2007-07-21 drh: struct openCnt *pOpen; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Decrement the shared lock counter. Release the lock using an dbda8d6ce9 2007-07-21 drh: ** OS call only when all threads in this same process have released dbda8d6ce9 2007-07-21 drh: ** the lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pLock->cnt--; dbda8d6ce9 2007-07-21 drh: if( pLock->cnt==0 ){ dbda8d6ce9 2007-07-21 drh: lock.l_type = F_UNLCK; dbda8d6ce9 2007-07-21 drh: lock.l_whence = SEEK_SET; dbda8d6ce9 2007-07-21 drh: lock.l_start = lock.l_len = 0L; dbda8d6ce9 2007-07-21 drh: if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){ dbda8d6ce9 2007-07-21 drh: pLock->locktype = NO_LOCK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Decrement the count of locks against this same file. When the dbda8d6ce9 2007-07-21 drh: ** count reaches zero, close any other file descriptors whose close dbda8d6ce9 2007-07-21 drh: ** was deferred because of outstanding locks. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pOpen = pFile->pOpen; dbda8d6ce9 2007-07-21 drh: pOpen->nLock--; dbda8d6ce9 2007-07-21 drh: assert( pOpen->nLock>=0 ); dbda8d6ce9 2007-07-21 drh: if( pOpen->nLock==0 && pOpen->nPending>0 ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pOpen->nPending; i++){ dbda8d6ce9 2007-07-21 drh: close(pOpen->aPending[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: free(pOpen->aPending); dbda8d6ce9 2007-07-21 drh: pOpen->nPending = 0; dbda8d6ce9 2007-07-21 drh: pOpen->aPending = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close a file. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixClose(sqlite3_file *id){ c287665ba8 2007-09-14 drh: unixFile *pFile = (unixFile *)id; c287665ba8 2007-09-14 drh: if( !pFile ) return SQLITE_OK; c287665ba8 2007-09-14 drh: unixUnlock(id, NO_LOCK); c287665ba8 2007-09-14 drh: if( pFile->dirfd>=0 ) close(pFile->dirfd); c287665ba8 2007-09-14 drh: pFile->dirfd = -1; c287665ba8 2007-09-14 drh: enterMutex(); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( pFile->pOpen->nLock ){ dbda8d6ce9 2007-07-21 drh: /* If there are outstanding locks, do not actually close the file just dbda8d6ce9 2007-07-21 drh: ** yet because that would clear those locks. Instead, add the file dbda8d6ce9 2007-07-21 drh: ** descriptor to pOpen->aPending. It will be automatically closed when dbda8d6ce9 2007-07-21 drh: ** the last lock is cleared. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int *aNew; c287665ba8 2007-09-14 drh: struct openCnt *pOpen = pFile->pOpen; dbda8d6ce9 2007-07-21 drh: aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) ); dbda8d6ce9 2007-07-21 drh: if( aNew==0 ){ dbda8d6ce9 2007-07-21 drh: /* If a malloc fails, just leak the file descriptor */ dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pOpen->aPending = aNew; c287665ba8 2007-09-14 drh: pOpen->aPending[pOpen->nPending] = pFile->h; dbda8d6ce9 2007-07-21 drh: pOpen->nPending++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* There are no outstanding locks so we can close the file immediately */ c287665ba8 2007-09-14 drh: close(pFile->h); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: releaseLockInfo(pFile->pLock); c287665ba8 2007-09-14 drh: releaseOpenCnt(pFile->pOpen); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: leaveMutex(); c287665ba8 2007-09-14 drh: OSTRACE2("CLOSE %-3d\n", pFile->h); dbda8d6ce9 2007-07-21 drh: OpenCounter(-1); c287665ba8 2007-09-14 drh: memset(pFile, 0, sizeof(unixFile)); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_LOCKING_STYLE dbda8d6ce9 2007-07-21 drh: #pragma mark AFP Support dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The afpLockingContext structure contains all afp lock specific state dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct afpLockingContext afpLockingContext; dbda8d6ce9 2007-07-21 drh: struct afpLockingContext { dbda8d6ce9 2007-07-21 drh: unsigned long long sharedLockByte; dbda8d6ce9 2007-07-21 drh: char *filePath; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: struct ByteRangeLockPB2 dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: unsigned long long offset; /* offset to first byte to lock */ dbda8d6ce9 2007-07-21 drh: unsigned long long length; /* nbr of bytes to lock */ dbda8d6ce9 2007-07-21 drh: unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */ dbda8d6ce9 2007-07-21 drh: unsigned char unLockFlag; /* 1 = unlock, 0 = lock */ dbda8d6ce9 2007-07-21 drh: unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */ dbda8d6ce9 2007-07-21 drh: int fd; /* file desc to assoc this lock with */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: #define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2) c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return 0 on success, 1 on failure. To match the behavior of the c287665ba8 2007-09-14 drh: ** normal posix file locking (used in unixLock for example), we should c287665ba8 2007-09-14 drh: ** provide 'richer' return codes - specifically to differentiate between c287665ba8 2007-09-14 drh: ** 'file busy' and 'file system error' results. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int _AFPFSSetLock( c287665ba8 2007-09-14 drh: const char *path, c287665ba8 2007-09-14 drh: int fd, c287665ba8 2007-09-14 drh: unsigned long long offset, c287665ba8 2007-09-14 drh: unsigned long long length, c287665ba8 2007-09-14 drh: int setLockFlag c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: struct ByteRangeLockPB2 pb; dbda8d6ce9 2007-07-21 drh: int err; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pb.unLockFlag = setLockFlag ? 0 : 1; dbda8d6ce9 2007-07-21 drh: pb.startEndFlag = 0; dbda8d6ce9 2007-07-21 drh: pb.offset = offset; dbda8d6ce9 2007-07-21 drh: pb.length = length; dbda8d6ce9 2007-07-21 drh: pb.fd = fd; dbda8d6ce9 2007-07-21 drh: OSTRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n", dbda8d6ce9 2007-07-21 drh: (setLockFlag?"ON":"OFF"), fd, offset, length); dbda8d6ce9 2007-07-21 drh: err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0); dbda8d6ce9 2007-07-21 drh: if ( err==-1 ) { dbda8d6ce9 2007-07-21 drh: OSTRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, errno, dbda8d6ce9 2007-07-21 drh: strerror(errno)); dbda8d6ce9 2007-07-21 drh: return 1; /* error */ dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine checks if there is a RESERVED lock held on the specified dbda8d6ce9 2007-07-21 drh: ** file by this or any other process. If such a lock is held, return dbda8d6ce9 2007-07-21 drh: ** non-zero. If the file is unlocked or holds only SHARED locks, then dbda8d6ce9 2007-07-21 drh: ** return zero. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int afpUnixCheckReservedLock(sqlite3_file *id){ dbda8d6ce9 2007-07-21 drh: int r = 0; dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pFile ); dbda8d6ce9 2007-07-21 drh: afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check if a thread in this process holds such a lock */ dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: r = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Otherwise see if some other process holds it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if ( !r ) { dbda8d6ce9 2007-07-21 drh: /* lock the byte */ dbda8d6ce9 2007-07-21 drh: int failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1); dbda8d6ce9 2007-07-21 drh: if (failed) { dbda8d6ce9 2007-07-21 drh: /* if we failed to get the lock then someone else must have it */ dbda8d6ce9 2007-07-21 drh: r = 1; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: /* if we succeeded in taking the reserved lock, unlock it to restore dbda8d6ce9 2007-07-21 drh: ** the original state */ dbda8d6ce9 2007-07-21 drh: _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* AFP-style locking following the behavior of unixLock, see the unixLock dbda8d6ce9 2007-07-21 drh: ** function comments for details of lock management. */ c287665ba8 2007-09-14 drh: static int afpUnixLock(sqlite3_file *id, int locktype) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; dbda8d6ce9 2007-07-21 drh: int gotPendingLock = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pFile ); dbda8d6ce9 2007-07-21 drh: OSTRACE5("LOCK %d %s was %s pid=%d\n", pFile->h, dbda8d6ce9 2007-07-21 drh: locktypeName(locktype), locktypeName(pFile->locktype), getpid()); dbda8d6ce9 2007-07-21 drh: /* If there is already a lock of this type or more restrictive on the c287665ba8 2007-09-14 drh: ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as c287665ba8 2007-09-14 drh: ** enterMutex() hasn't been called yet. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>=locktype ){ dbda8d6ce9 2007-07-21 drh: OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h, dbda8d6ce9 2007-07-21 drh: locktypeName(locktype)); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the locking sequence is correct dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( locktype!=PENDING_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This mutex is needed because pFile->pLock is shared across threads dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: enterMutex(); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the current thread owns the pFile. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = transferOwnership(pFile); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A PENDING lock is needed before acquiring a SHARED lock and before dbda8d6ce9 2007-07-21 drh: ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will dbda8d6ce9 2007-07-21 drh: ** be released. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK dbda8d6ce9 2007-07-21 drh: || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int failed = _AFPFSSetLock(context->filePath, pFile->h, dbda8d6ce9 2007-07-21 drh: PENDING_BYTE, 1, 1); dbda8d6ce9 2007-07-21 drh: if (failed) { dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: goto afp_end_lock; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If control gets to this point, then actually go ahead and make dbda8d6ce9 2007-07-21 drh: ** operating system calls for the specified lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: int lk, failed; dbda8d6ce9 2007-07-21 drh: int tries = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Now get the read-lock */ dbda8d6ce9 2007-07-21 drh: /* note that the quality of the randomness doesn't matter that much */ dbda8d6ce9 2007-07-21 drh: lk = random(); dbda8d6ce9 2007-07-21 drh: context->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); dbda8d6ce9 2007-07-21 drh: failed = _AFPFSSetLock(context->filePath, pFile->h, dbda8d6ce9 2007-07-21 drh: SHARED_FIRST+context->sharedLockByte, 1, 1); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Drop the temporary PENDING lock */ dbda8d6ce9 2007-07-21 drh: if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)) { dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ dbda8d6ce9 2007-07-21 drh: goto afp_end_lock; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( failed ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: pFile->locktype = SHARED_LOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The request was for a RESERVED or EXCLUSIVE lock. It is dbda8d6ce9 2007-07-21 drh: ** assumed that there is a SHARED or greater lock on the file dbda8d6ce9 2007-07-21 drh: ** already. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int failed = 0; dbda8d6ce9 2007-07-21 drh: assert( 0!=pFile->locktype ); dbda8d6ce9 2007-07-21 drh: if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) { dbda8d6ce9 2007-07-21 drh: /* Acquire a RESERVED lock */ dbda8d6ce9 2007-07-21 drh: failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if (!failed && locktype == EXCLUSIVE_LOCK) { dbda8d6ce9 2007-07-21 drh: /* Acquire an EXCLUSIVE lock */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Remove the shared lock before trying the range. we'll need to dbda8d6ce9 2007-07-21 drh: ** reestablish the shared lock if we can't get the afpUnixUnlock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if (!_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST + dbda8d6ce9 2007-07-21 drh: context->sharedLockByte, 1, 0)) { dbda8d6ce9 2007-07-21 drh: /* now attemmpt to get the exclusive lock range */ dbda8d6ce9 2007-07-21 drh: failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST, dbda8d6ce9 2007-07-21 drh: SHARED_SIZE, 1); dbda8d6ce9 2007-07-21 drh: if (failed && _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST + dbda8d6ce9 2007-07-21 drh: context->sharedLockByte, 1, 1)) { dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_RDLOCK; /* this should never happen */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: /* */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; /* this should never happen */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( failed && rc == SQLITE_OK){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: }else if( locktype==EXCLUSIVE_LOCK ){ dbda8d6ce9 2007-07-21 drh: pFile->locktype = PENDING_LOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: afp_end_lock: c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), dbda8d6ce9 2007-07-21 drh: rc==SQLITE_OK ? "ok" : "failed"); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Lower the locking level on file descriptor pFile to locktype. locktype dbda8d6ce9 2007-07-21 drh: ** must be either NO_LOCK or SHARED_LOCK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the locking level of the file descriptor is already at or below dbda8d6ce9 2007-07-21 drh: ** the requested locking level, this routine is a no-op. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int afpUnixUnlock(sqlite3_file *id, int locktype) { dbda8d6ce9 2007-07-21 drh: struct flock lock; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pFile ); dbda8d6ce9 2007-07-21 drh: OSTRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype, dbda8d6ce9 2007-07-21 drh: pFile->locktype, getpid()); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( locktype<=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: if( pFile->locktype<=locktype ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( CHECK_THREADID(pFile) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: enterMutex(); dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: int failed = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* unlock the exclusive range - then re-establish the shared lock */ dbda8d6ce9 2007-07-21 drh: if (pFile->locktype==EXCLUSIVE_LOCK) { dbda8d6ce9 2007-07-21 drh: failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST, dbda8d6ce9 2007-07-21 drh: SHARED_SIZE, 0); dbda8d6ce9 2007-07-21 drh: if (!failed) { dbda8d6ce9 2007-07-21 drh: /* successfully removed the exclusive lock */ dbda8d6ce9 2007-07-21 drh: if (_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST+ dbda8d6ce9 2007-07-21 drh: context->sharedLockByte, 1, 1)) { dbda8d6ce9 2007-07-21 drh: /* failed to re-establish our shared lock */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_RDLOCK; /* This should never happen */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: /* This should never happen - failed to unlock the exclusive range */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if (rc == SQLITE_OK && pFile->locktype>=PENDING_LOCK) { dbda8d6ce9 2007-07-21 drh: if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)){ dbda8d6ce9 2007-07-21 drh: /* failed to release the pending lock */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if (rc == SQLITE_OK && pFile->locktype>=RESERVED_LOCK) { dbda8d6ce9 2007-07-21 drh: if (_AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0)) { dbda8d6ce9 2007-07-21 drh: /* failed to release the reserved lock */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( locktype==NO_LOCK ){ dbda8d6ce9 2007-07-21 drh: int failed = _AFPFSSetLock(context->filePath, pFile->h, dbda8d6ce9 2007-07-21 drh: SHARED_FIRST + context->sharedLockByte, 1, 0); dbda8d6ce9 2007-07-21 drh: if (failed) { dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if (rc == SQLITE_OK) dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close a file & cleanup AFP specific locking context dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int afpUnixClose(sqlite3_file *id) { c287665ba8 2007-09-14 drh: unixFile *pFile = (unixFile*)pId; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( !pFile ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: afpUnixUnlock(*pId, NO_LOCK); dbda8d6ce9 2007-07-21 drh: /* free the AFP locking structure */ c287665ba8 2007-09-14 drh: if (pFile->lockingContext != NULL) { c287665ba8 2007-09-14 drh: if (((afpLockingContext *)pFile->lockingContext)->filePath != NULL) c287665ba8 2007-09-14 drh: sqlite3_free(((afpLockingContext*)pFile->lockingContext)->filePath); c287665ba8 2007-09-14 drh: sqlite3_free(pFile->lockingContext); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( pFile->dirfd>=0 ) close(pFile->dirfd); c287665ba8 2007-09-14 drh: pFile->dirfd = -1; c287665ba8 2007-09-14 drh: close(pFile->h); c287665ba8 2007-09-14 drh: OSTRACE2("CLOSE %-3d\n", pFile->h); c287665ba8 2007-09-14 drh: OpenCounter(-1); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #pragma mark flock() style locking dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The flockLockingContext is not used dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef void flockLockingContext; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: static int flockUnixCheckReservedLock(sqlite3_file *id) { dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if (pFile->locktype == RESERVED_LOCK) { dbda8d6ce9 2007-07-21 drh: return 1; /* already have a reserved lock */ dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: /* attempt to get the lock */ dbda8d6ce9 2007-07-21 drh: int rc = flock(pFile->h, LOCK_EX | LOCK_NB); dbda8d6ce9 2007-07-21 drh: if (!rc) { dbda8d6ce9 2007-07-21 drh: /* got the lock, unlock it */ dbda8d6ce9 2007-07-21 drh: flock(pFile->h, LOCK_UN); dbda8d6ce9 2007-07-21 drh: return 0; /* no one has it reserved */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; /* someone else might have it reserved */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: static int flockUnixLock(sqlite3_file *id, int locktype) { dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* if we already have a lock, it is exclusive. dbda8d6ce9 2007-07-21 drh: ** Just adjust level and punt on outta here. */ dbda8d6ce9 2007-07-21 drh: if (pFile->locktype > NO_LOCK) { dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* grab an exclusive lock */ dbda8d6ce9 2007-07-21 drh: int rc = flock(pFile->h, LOCK_EX | LOCK_NB); dbda8d6ce9 2007-07-21 drh: if (rc) { dbda8d6ce9 2007-07-21 drh: /* didn't get, must be busy */ dbda8d6ce9 2007-07-21 drh: return SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: /* got it, set the type and return ok */ dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: static int flockUnixUnlock(sqlite3_file *id, int locktype) { dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( locktype<=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* no-op if possible */ dbda8d6ce9 2007-07-21 drh: if( pFile->locktype==locktype ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* shared can just be set because we always have an exclusive */ dbda8d6ce9 2007-07-21 drh: if (locktype==SHARED_LOCK) { dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* no, really, unlock. */ dbda8d6ce9 2007-07-21 drh: int rc = flock(pFile->h, LOCK_UN); dbda8d6ce9 2007-07-21 drh: if (rc) dbda8d6ce9 2007-07-21 drh: return SQLITE_IOERR_UNLOCK; dbda8d6ce9 2007-07-21 drh: else { dbda8d6ce9 2007-07-21 drh: pFile->locktype = NO_LOCK; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close a file. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int flockUnixClose(sqlite3_file *pId) { c287665ba8 2007-09-14 drh: unixFile *pFile = (unixFile*)*pId; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( !pFile ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: flockUnixUnlock(*pId, NO_LOCK); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( pFile->dirfd>=0 ) close(pFile->dirfd); c287665ba8 2007-09-14 drh: pFile->dirfd = -1; c287665ba8 2007-09-14 drh: enterMutex(); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: close(pFile->h); c287665ba8 2007-09-14 drh: leaveMutex(); c287665ba8 2007-09-14 drh: OSTRACE2("CLOSE %-3d\n", pFile->h); c287665ba8 2007-09-14 drh: OpenCounter(-1); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #pragma mark Old-School .lock file based locking dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The dotlockLockingContext structure contains all dotlock (.lock) lock dbda8d6ce9 2007-07-21 drh: ** specific state dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct dotlockLockingContext dotlockLockingContext; dbda8d6ce9 2007-07-21 drh: struct dotlockLockingContext { dbda8d6ce9 2007-07-21 drh: char *lockPath; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: static int dotlockUnixCheckReservedLock(sqlite3_file *id) { dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dotlockLockingContext *context = dbda8d6ce9 2007-07-21 drh: (dotlockLockingContext *) pFile->lockingContext; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if (pFile->locktype == RESERVED_LOCK) { dbda8d6ce9 2007-07-21 drh: return 1; /* already have a reserved lock */ dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: struct stat statBuf; dbda8d6ce9 2007-07-21 drh: if (lstat(context->lockPath,&statBuf) == 0) dbda8d6ce9 2007-07-21 drh: /* file exists, someone else has the lock */ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: else dbda8d6ce9 2007-07-21 drh: /* file does not exist, we could have it if we want it */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: static int dotlockUnixLock(sqlite3_file *id, int locktype) { dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dotlockLockingContext *context = dbda8d6ce9 2007-07-21 drh: (dotlockLockingContext *) pFile->lockingContext; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* if we already have a lock, it is exclusive. dbda8d6ce9 2007-07-21 drh: ** Just adjust level and punt on outta here. */ dbda8d6ce9 2007-07-21 drh: if (pFile->locktype > NO_LOCK) { dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Always update the timestamp on the old file */ dbda8d6ce9 2007-07-21 drh: utimes(context->lockPath,NULL); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* check to see if lock file already exists */ dbda8d6ce9 2007-07-21 drh: struct stat statBuf; dbda8d6ce9 2007-07-21 drh: if (lstat(context->lockPath,&statBuf) == 0){ dbda8d6ce9 2007-07-21 drh: return SQLITE_BUSY; /* it does, busy */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* grab an exclusive lock */ dbda8d6ce9 2007-07-21 drh: int fd = open(context->lockPath,O_RDONLY|O_CREAT|O_EXCL,0600); dbda8d6ce9 2007-07-21 drh: if (fd < 0) { dbda8d6ce9 2007-07-21 drh: /* failed to open/create the file, someone else may have stolen the lock */ dbda8d6ce9 2007-07-21 drh: return SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: close(fd); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* got it, set the type and return ok */ dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: static int dotlockUnixUnlock(sqlite3_file *id, int locktype) { dbda8d6ce9 2007-07-21 drh: unixFile *pFile = (unixFile*)id; dbda8d6ce9 2007-07-21 drh: dotlockLockingContext *context = dbda8d6ce9 2007-07-21 drh: (dotlockLockingContext *) pFile->lockingContext; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( locktype<=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* no-op if possible */ dbda8d6ce9 2007-07-21 drh: if( pFile->locktype==locktype ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* shared can just be set because we always have an exclusive */ dbda8d6ce9 2007-07-21 drh: if (locktype==SHARED_LOCK) { dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* no, really, unlock. */ dbda8d6ce9 2007-07-21 drh: unlink(context->lockPath); dbda8d6ce9 2007-07-21 drh: pFile->locktype = NO_LOCK; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close a file. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int dotlockUnixClose(sqlite3_file *id) { c287665ba8 2007-09-14 drh: unixFile *pFile = (unixFile*)id; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( !pFile ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dotlockUnixUnlock(*pId, NO_LOCK); dbda8d6ce9 2007-07-21 drh: /* free the dotlock locking structure */ c287665ba8 2007-09-14 drh: if (pFile->lockingContext != NULL) { c287665ba8 2007-09-14 drh: if (((dotlockLockingContext *)pFile->lockingContext)->lockPath != NULL) c287665ba8 2007-09-14 drh: sqlite3_free( ( (dotlockLockingContext *) c287665ba8 2007-09-14 drh: pFile->lockingContext)->lockPath); c287665ba8 2007-09-14 drh: sqlite3_free(pFile->lockingContext); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( pFile->dirfd>=0 ) close(pFile->dirfd); c287665ba8 2007-09-14 drh: pFile->dirfd = -1; c287665ba8 2007-09-14 drh: enterMutex(); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: close(pFile->h); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: leaveMutex(); c287665ba8 2007-09-14 drh: OSTRACE2("CLOSE %-3d\n", pFile->h); c287665ba8 2007-09-14 drh: OpenCounter(-1); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #pragma mark No locking dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The nolockLockingContext is void dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef void nolockLockingContext; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: static int nolockUnixCheckReservedLock(sqlite3_file *id) { c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: static int nolockUnixLock(sqlite3_file *id, int locktype) { c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: static int nolockUnixUnlock(sqlite3_file *id, int locktype) { dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close a file. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int nolockUnixClose(sqlite3_file *id) { c287665ba8 2007-09-14 drh: unixFile *pFile = (unixFile*)id; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( !pFile ) return SQLITE_OK; c287665ba8 2007-09-14 drh: if( pFile->dirfd>=0 ) close(pFile->dirfd); c287665ba8 2007-09-14 drh: pFile->dirfd = -1; c287665ba8 2007-09-14 drh: enterMutex(); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: close(pFile->h); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: leaveMutex(); c287665ba8 2007-09-14 drh: OSTRACE2("CLOSE %-3d\n", pFile->h); c287665ba8 2007-09-14 drh: OpenCounter(-1); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ENABLE_LOCKING_STYLE */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Information and control of an open file handle. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixFileControl(sqlite3_file *id, int op, void *pArg){ c287665ba8 2007-09-14 drh: switch( op ){ c287665ba8 2007-09-14 drh: case SQLITE_FCNTL_LOCKSTATE: { c287665ba8 2007-09-14 drh: *(int*)pArg = ((unixFile*)id)->locktype; c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the sector size in bytes of the underlying block device for dbda8d6ce9 2007-07-21 drh: ** the specified file. This is almost always 512 bytes, but may be dbda8d6ce9 2007-07-21 drh: ** larger for some devices. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite code assumes this function cannot fail. It also assumes that dbda8d6ce9 2007-07-21 drh: ** if two files are created in the same file-system directory (i.e. dbda8d6ce9 2007-07-21 drh: ** a database and it's journal file) that the sector size will be the dbda8d6ce9 2007-07-21 drh: ** same for both. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixSectorSize(sqlite3_file *id){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DEFAULT_SECTOR_SIZE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Return the device characteristics for the file. This is always 0. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixDeviceCharacteristics(sqlite3_file *id){ c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This vector defines all the methods that can operate on an sqlite3_file dbda8d6ce9 2007-07-21 drh: ** for unix. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static const sqlite3_io_methods sqlite3UnixIoMethod = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: unixClose, dbda8d6ce9 2007-07-21 drh: unixRead, dbda8d6ce9 2007-07-21 drh: unixWrite, dbda8d6ce9 2007-07-21 drh: unixTruncate, dbda8d6ce9 2007-07-21 drh: unixSync, dbda8d6ce9 2007-07-21 drh: unixFileSize, dbda8d6ce9 2007-07-21 drh: unixLock, dbda8d6ce9 2007-07-21 drh: unixUnlock, dbda8d6ce9 2007-07-21 drh: unixCheckReservedLock, c287665ba8 2007-09-14 drh: unixFileControl, dbda8d6ce9 2007-07-21 drh: unixSectorSize, c287665ba8 2007-09-14 drh: unixDeviceCharacteristics dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_LOCKING_STYLE dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** This vector defines all the methods that can operate on an sqlite3_file c287665ba8 2007-09-14 drh: ** for unix with AFP style file locking. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static const sqlite3_io_methods sqlite3AFPLockingUnixIoMethod = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: unixClose, c287665ba8 2007-09-14 drh: unixRead, c287665ba8 2007-09-14 drh: unixWrite, c287665ba8 2007-09-14 drh: unixTruncate, c287665ba8 2007-09-14 drh: unixSync, c287665ba8 2007-09-14 drh: unixFileSize, c287665ba8 2007-09-14 drh: afpUnixLock, c287665ba8 2007-09-14 drh: afpUnixUnlock, c287665ba8 2007-09-14 drh: afpUnixCheckReservedLock, c287665ba8 2007-09-14 drh: unixFileControl, c287665ba8 2007-09-14 drh: unixSectorSize, c287665ba8 2007-09-14 drh: unixDeviceCharacteristics c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This vector defines all the methods that can operate on an sqlite3_file c287665ba8 2007-09-14 drh: ** for unix with flock() style file locking. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static const sqlite3_io_methods sqlite3FlockLockingUnixIoMethod = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: flockUnixClose, c287665ba8 2007-09-14 drh: unixRead, c287665ba8 2007-09-14 drh: unixWrite, c287665ba8 2007-09-14 drh: unixTruncate, c287665ba8 2007-09-14 drh: unixSync, c287665ba8 2007-09-14 drh: unixFileSize, c287665ba8 2007-09-14 drh: flockUnixLock, c287665ba8 2007-09-14 drh: flockUnixUnlock, c287665ba8 2007-09-14 drh: flockUnixCheckReservedLock, c287665ba8 2007-09-14 drh: unixFileControl, c287665ba8 2007-09-14 drh: unixSectorSize, c287665ba8 2007-09-14 drh: unixDeviceCharacteristics c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This vector defines all the methods that can operate on an sqlite3_file c287665ba8 2007-09-14 drh: ** for unix with dotlock style file locking. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static const sqlite3_io_methods sqlite3DotlockLockingUnixIoMethod = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: dotlockUnixClose, c287665ba8 2007-09-14 drh: unixRead, c287665ba8 2007-09-14 drh: unixWrite, c287665ba8 2007-09-14 drh: unixTruncate, c287665ba8 2007-09-14 drh: unixSync, c287665ba8 2007-09-14 drh: unixFileSize, c287665ba8 2007-09-14 drh: dotlockUnixLock, c287665ba8 2007-09-14 drh: dotlockUnixUnlock, c287665ba8 2007-09-14 drh: dotlockUnixCheckReservedLock, c287665ba8 2007-09-14 drh: unixFileControl, c287665ba8 2007-09-14 drh: unixSectorSize, c287665ba8 2007-09-14 drh: unixDeviceCharacteristics c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This vector defines all the methods that can operate on an sqlite3_file c287665ba8 2007-09-14 drh: ** for unix with dotlock style file locking. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static const sqlite3_io_methods sqlite3NolockLockingUnixIoMethod = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: nolockUnixClose, dbda8d6ce9 2007-07-21 drh: unixRead, dbda8d6ce9 2007-07-21 drh: unixWrite, dbda8d6ce9 2007-07-21 drh: unixTruncate, dbda8d6ce9 2007-07-21 drh: unixSync, dbda8d6ce9 2007-07-21 drh: unixFileSize, dbda8d6ce9 2007-07-21 drh: nolockUnixLock, dbda8d6ce9 2007-07-21 drh: nolockUnixUnlock, dbda8d6ce9 2007-07-21 drh: nolockUnixCheckReservedLock, c287665ba8 2007-09-14 drh: unixFileControl, dbda8d6ce9 2007-07-21 drh: unixSectorSize, c287665ba8 2007-09-14 drh: unixDeviceCharacteristics dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ENABLE_LOCKING_STYLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate memory for a new unixFile and initialize that unixFile. dbda8d6ce9 2007-07-21 drh: ** Write a pointer to the new unixFile into *pId. dbda8d6ce9 2007-07-21 drh: ** If we run out of memory, close the file and return an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_LOCKING_STYLE dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** When locking extensions are enabled, the filepath and locking style c287665ba8 2007-09-14 drh: ** are needed to determine the unixFile pMethod to use for locking operations. c287665ba8 2007-09-14 drh: ** The locking-style specific lockingContext data structure is created c287665ba8 2007-09-14 drh: ** and assigned here also. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int fillInUnixFile( dbda8d6ce9 2007-07-21 drh: int h, /* Open file descriptor of file being opened */ c287665ba8 2007-09-14 drh: int dirfd, /* Directory file descriptor */ c287665ba8 2007-09-14 drh: sqlite3_file *pId, /* Write completed initialization here */ c287665ba8 2007-09-14 drh: const char *zFilename, /* Name of the file being opened */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3LockingStyle lockingStyle; c287665ba8 2007-09-14 drh: unixFile *pNew = (unixFile *)pId; c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: memset(pNew, 0, sizeof(unixFile)); dbda8d6ce9 2007-07-21 drh: lockingStyle = sqlite3DetectLockingStyle(zFilename, h); dbda8d6ce9 2007-07-21 drh: if ( lockingStyle == posixLockingStyle ) { c287665ba8 2007-09-14 drh: enterMutex(); c287665ba8 2007-09-14 drh: rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen); c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: close(h); dbda8d6ce9 2007-07-21 drh: unlink(zFilename); dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: /* pLock and pOpen are only used for posix advisory locking */ c287665ba8 2007-09-14 drh: pNew->pLock = NULL; c287665ba8 2007-09-14 drh: pNew->pOpen = NULL; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pNew->dirfd = -1; c287665ba8 2007-09-14 drh: pNew->h = h; c287665ba8 2007-09-14 drh: SET_THREADID(pNew); c287665ba8 2007-09-14 drh: pNew = sqlite3_malloc( sizeof(unixFile) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: close(h); c287665ba8 2007-09-14 drh: enterMutex(); c287665ba8 2007-09-14 drh: releaseLockInfo(pNew->pLock); c287665ba8 2007-09-14 drh: releaseOpenCnt(pNew->pOpen); c287665ba8 2007-09-14 drh: leaveMutex(); c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: }else{ dbda8d6ce9 2007-07-21 drh: switch(lockingStyle) { dbda8d6ce9 2007-07-21 drh: case afpLockingStyle: { dbda8d6ce9 2007-07-21 drh: /* afp locking uses the file path so it needs to be included in dbda8d6ce9 2007-07-21 drh: ** the afpLockingContext */ dbda8d6ce9 2007-07-21 drh: int nFilename; dbda8d6ce9 2007-07-21 drh: pNew->pMethod = &sqlite3AFPLockingUnixIoMethod; dbda8d6ce9 2007-07-21 drh: pNew->lockingContext = c287665ba8 2007-09-14 drh: sqlite3_malloc(sizeof(afpLockingContext)); dbda8d6ce9 2007-07-21 drh: nFilename = strlen(zFilename)+1; dbda8d6ce9 2007-07-21 drh: ((afpLockingContext *)pNew->lockingContext)->filePath = c287665ba8 2007-09-14 drh: sqlite3_malloc(nFilename); dbda8d6ce9 2007-07-21 drh: memcpy(((afpLockingContext *)pNew->lockingContext)->filePath, dbda8d6ce9 2007-07-21 drh: zFilename, nFilename); dbda8d6ce9 2007-07-21 drh: srandomdev(); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case flockLockingStyle: dbda8d6ce9 2007-07-21 drh: /* flock locking doesn't need additional lockingContext information */ dbda8d6ce9 2007-07-21 drh: pNew->pMethod = &sqlite3FlockLockingUnixIoMethod; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case dotlockLockingStyle: { dbda8d6ce9 2007-07-21 drh: /* dotlock locking uses the file path so it needs to be included in dbda8d6ce9 2007-07-21 drh: ** the dotlockLockingContext */ dbda8d6ce9 2007-07-21 drh: int nFilename; dbda8d6ce9 2007-07-21 drh: pNew->pMethod = &sqlite3DotlockLockingUnixIoMethod; c287665ba8 2007-09-14 drh: pNew->lockingContext = sqlite3_malloc( dbda8d6ce9 2007-07-21 drh: sizeof(dotlockLockingContext)); dbda8d6ce9 2007-07-21 drh: nFilename = strlen(zFilename) + 6; dbda8d6ce9 2007-07-21 drh: ((dotlockLockingContext *)pNew->lockingContext)->lockPath = c287665ba8 2007-09-14 drh: sqlite3_malloc( nFilename ); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(nFilename, dbda8d6ce9 2007-07-21 drh: ((dotlockLockingContext *)pNew->lockingContext)->lockPath, dbda8d6ce9 2007-07-21 drh: "%s.lock", zFilename); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case posixLockingStyle: dbda8d6ce9 2007-07-21 drh: /* posix locking doesn't need additional lockingContext information */ dbda8d6ce9 2007-07-21 drh: pNew->pMethod = &sqlite3UnixIoMethod; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case noLockingStyle: dbda8d6ce9 2007-07-21 drh: case unsupportedLockingStyle: dbda8d6ce9 2007-07-21 drh: default: dbda8d6ce9 2007-07-21 drh: pNew->pMethod = &sqlite3NolockLockingUnixIoMethod; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: OpenCounter(+1); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else /* SQLITE_ENABLE_LOCKING_STYLE */ c287665ba8 2007-09-14 drh: static int fillInUnixFile( dbda8d6ce9 2007-07-21 drh: int h, /* Open file descriptor on file being opened */ c287665ba8 2007-09-14 drh: int dirfd, c287665ba8 2007-09-14 drh: sqlite3_file *pId, /* Write to the unixFile structure here */ c287665ba8 2007-09-14 drh: const char *zFilename /* Name of the file being opened */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: unixFile *pNew = (unixFile *)pId; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef FD_CLOEXEC dbda8d6ce9 2007-07-21 drh: fcntl(h, F_SETFD, fcntl(h, F_GETFD, 0) | FD_CLOEXEC); dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: enterMutex(); c287665ba8 2007-09-14 drh: rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen); c287665ba8 2007-09-14 drh: leaveMutex(); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: close(h); dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: OSTRACE3("OPEN %-3d %s\n", h, zFilename); c287665ba8 2007-09-14 drh: pNew->dirfd = -1; c287665ba8 2007-09-14 drh: pNew->h = h; c287665ba8 2007-09-14 drh: pNew->dirfd = dirfd; c287665ba8 2007-09-14 drh: SET_THREADID(pNew); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pNew->pMethod = &sqlite3UnixIoMethod; c287665ba8 2007-09-14 drh: OpenCounter(+1); c287665ba8 2007-09-14 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ENABLE_LOCKING_STYLE */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Open a file descriptor to the directory containing file zFilename. c287665ba8 2007-09-14 drh: ** If successful, *pFd is set to the opened file descriptor and c287665ba8 2007-09-14 drh: ** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM c287665ba8 2007-09-14 drh: ** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined c287665ba8 2007-09-14 drh: ** value. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If SQLITE_OK is returned, the caller is responsible for closing c287665ba8 2007-09-14 drh: ** the file descriptor *pFd using close(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int openDirectory(const char *zFilename, int *pFd){ c287665ba8 2007-09-14 drh: int ii; c287665ba8 2007-09-14 drh: int fd; c287665ba8 2007-09-14 drh: char zDirname[MAX_PATHNAME+1]; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); c287665ba8 2007-09-14 drh: for(ii=strlen(zDirname); ii>=0 && zDirname[ii]!='/'; ii--); c287665ba8 2007-09-14 drh: if( ii>0 ){ c287665ba8 2007-09-14 drh: zDirname[ii] = '\0'; c287665ba8 2007-09-14 drh: fd = open(zDirname, O_RDONLY|O_BINARY, 0); c287665ba8 2007-09-14 drh: if( fd>0 ){ c287665ba8 2007-09-14 drh: #ifdef FD_CLOEXEC c287665ba8 2007-09-14 drh: fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: *pFd = fd; c287665ba8 2007-09-14 drh: return (fd>0?SQLITE_OK:SQLITE_CANTOPEN); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Open the file zPath. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Previously, the SQLite OS layer used three functions in place of this c287665ba8 2007-09-14 drh: ** one: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** sqlite3OsOpenReadWrite(); c287665ba8 2007-09-14 drh: ** sqlite3OsOpenReadOnly(); c287665ba8 2007-09-14 drh: ** sqlite3OsOpenExclusive(); c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** These calls correspond to the following combinations of flags: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** ReadWrite() -> (READWRITE | CREATE) c287665ba8 2007-09-14 drh: ** ReadOnly() -> (READONLY) c287665ba8 2007-09-14 drh: ** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE) c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The old OpenExclusive() accepted a boolean argument - "delFlag". If c287665ba8 2007-09-14 drh: ** true, the file was configured to be automatically deleted when the c287665ba8 2007-09-14 drh: ** file handle closed. To achieve the same effect using this new c287665ba8 2007-09-14 drh: ** interface, add the DELETEONCLOSE flag to those specified above for c287665ba8 2007-09-14 drh: ** OpenExclusive(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixOpen( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, c287665ba8 2007-09-14 drh: const char *zPath, c287665ba8 2007-09-14 drh: sqlite3_file *pFile, c287665ba8 2007-09-14 drh: int flags, c287665ba8 2007-09-14 drh: int *pOutFlags c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int fd = 0; /* File descriptor returned by open() */ c287665ba8 2007-09-14 drh: int dirfd = -1; /* Directory file descriptor */ c287665ba8 2007-09-14 drh: int oflags = 0; /* Flags to pass to open() */ c287665ba8 2007-09-14 drh: int eType = flags&0xFFFFFF00; /* Type of file to open */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); c287665ba8 2007-09-14 drh: int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); c287665ba8 2007-09-14 drh: int isCreate = (flags & SQLITE_OPEN_CREATE); c287665ba8 2007-09-14 drh: int isReadonly = (flags & SQLITE_OPEN_READONLY); c287665ba8 2007-09-14 drh: int isReadWrite = (flags & SQLITE_OPEN_READWRITE); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* If creating a master or main-file journal, this function will open c287665ba8 2007-09-14 drh: ** a file-descriptor on the directory too. The first time unixSync() c287665ba8 2007-09-14 drh: ** is called the directory file descriptor will be fsync()ed and close()d. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: int isOpenDirectory = (isCreate && c287665ba8 2007-09-14 drh: (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL) c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Check the following statements are true: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (a) Exactly one of the READWRITE and READONLY flags must be set, and c287665ba8 2007-09-14 drh: ** (b) if CREATE is set, then READWRITE must also be set, and c287665ba8 2007-09-14 drh: ** (c) if EXCLUSIVE is set, then CREATE must also be set. c287665ba8 2007-09-14 drh: ** (d) if DELETEONCLOSE is set, then CREATE must also be set. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); c287665ba8 2007-09-14 drh: assert(isCreate==0 || isReadWrite); c287665ba8 2007-09-14 drh: assert(isExclusive==0 || isCreate); c287665ba8 2007-09-14 drh: assert(isDelete==0 || isCreate); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* The main DB, main journal, and master journal are never automatically c287665ba8 2007-09-14 drh: ** deleted c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert( eType!=SQLITE_OPEN_MAIN_DB || !isDelete ); c287665ba8 2007-09-14 drh: assert( eType!=SQLITE_OPEN_MAIN_JOURNAL || !isDelete ); c287665ba8 2007-09-14 drh: assert( eType!=SQLITE_OPEN_MASTER_JOURNAL || !isDelete ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Assert that the upper layer has set one of the "file-type" flags. */ c287665ba8 2007-09-14 drh: assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB c287665ba8 2007-09-14 drh: || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL c287665ba8 2007-09-14 drh: || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL c287665ba8 2007-09-14 drh: || eType==SQLITE_OPEN_TRANSIENT_DB c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( isReadonly ) oflags |= O_RDONLY; c287665ba8 2007-09-14 drh: if( isReadWrite ) oflags |= O_RDWR; c287665ba8 2007-09-14 drh: if( isCreate ) oflags |= O_CREAT; c287665ba8 2007-09-14 drh: if( isExclusive ) oflags |= (O_EXCL|O_NOFOLLOW); c287665ba8 2007-09-14 drh: oflags |= (O_LARGEFILE|O_BINARY); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: memset(pFile, 0, sizeof(unixFile)); c287665ba8 2007-09-14 drh: fd = open(zPath, oflags, isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS); c287665ba8 2007-09-14 drh: if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){ c287665ba8 2007-09-14 drh: /* Failed to open the file for read/write access. Try read-only. */ c287665ba8 2007-09-14 drh: flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); c287665ba8 2007-09-14 drh: flags |= SQLITE_OPEN_READONLY; c287665ba8 2007-09-14 drh: return unixOpen(pVfs, zPath, pFile, flags, pOutFlags); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( fd<0 ){ c287665ba8 2007-09-14 drh: return SQLITE_CANTOPEN; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( isDelete ){ c287665ba8 2007-09-14 drh: unlink(zPath); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pOutFlags ){ c287665ba8 2007-09-14 drh: *pOutFlags = flags; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert(fd!=0); c287665ba8 2007-09-14 drh: if( isOpenDirectory ){ c287665ba8 2007-09-14 drh: int rc = openDirectory(zPath, &dirfd); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: close(fd); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return fillInUnixFile(fd, dirfd, pFile, zPath); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Delete the file at zPath. If the dirSync argument is true, fsync() c287665ba8 2007-09-14 drh: ** the directory after deleting the file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: SimulateIOError(return SQLITE_IOERR_DELETE); c287665ba8 2007-09-14 drh: unlink(zPath); c287665ba8 2007-09-14 drh: if( dirSync ){ c287665ba8 2007-09-14 drh: int fd; c287665ba8 2007-09-14 drh: rc = openDirectory(zPath, &fd); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: if( fsync(fd) ){ c287665ba8 2007-09-14 drh: rc = SQLITE_IOERR_DIR_FSYNC; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: close(fd); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Test the existance of or access permissions of file zPath. The c287665ba8 2007-09-14 drh: ** test performed depends on the value of flags: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLITE_ACCESS_EXISTS: Return 1 if the file exists c287665ba8 2007-09-14 drh: ** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable. c287665ba8 2007-09-14 drh: ** SQLITE_ACCESS_READONLY: Return 1 if the file is readable. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Otherwise return 0. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){ c287665ba8 2007-09-14 drh: int amode; c287665ba8 2007-09-14 drh: switch( flags ){ c287665ba8 2007-09-14 drh: case SQLITE_ACCESS_EXISTS: c287665ba8 2007-09-14 drh: amode = F_OK; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: case SQLITE_ACCESS_READWRITE: c287665ba8 2007-09-14 drh: amode = W_OK|R_OK; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: case SQLITE_ACCESS_READ: c287665ba8 2007-09-14 drh: amode = R_OK; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: default: c287665ba8 2007-09-14 drh: assert(!"Invalid flags argument"); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return (access(zPath, amode)==0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Create a temporary file name in zBuf. zBuf must be allocated c287665ba8 2007-09-14 drh: ** by the calling process and must be big enough to hold at least c287665ba8 2007-09-14 drh: ** pVfs->mxPathname bytes. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixGetTempName(sqlite3_vfs *pVfs, char *zBuf){ c287665ba8 2007-09-14 drh: static const char *azDirs[] = { c287665ba8 2007-09-14 drh: 0, c287665ba8 2007-09-14 drh: "/var/tmp", c287665ba8 2007-09-14 drh: "/usr/tmp", c287665ba8 2007-09-14 drh: "/tmp", c287665ba8 2007-09-14 drh: ".", c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: static const unsigned char zChars[] = c287665ba8 2007-09-14 drh: "abcdefghijklmnopqrstuvwxyz" c287665ba8 2007-09-14 drh: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" c287665ba8 2007-09-14 drh: "0123456789"; c287665ba8 2007-09-14 drh: int i, j; c287665ba8 2007-09-14 drh: struct stat buf; c287665ba8 2007-09-14 drh: const char *zDir = "."; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* It's odd to simulate an io-error here, but really this is just c287665ba8 2007-09-14 drh: ** using the io-error infrastructure to test that SQLite handles this c287665ba8 2007-09-14 drh: ** function failing. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SimulateIOError( return SQLITE_ERROR ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: azDirs[0] = sqlite3_temp_directory; c287665ba8 2007-09-14 drh: for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ c287665ba8 2007-09-14 drh: if( azDirs[i]==0 ) continue; c287665ba8 2007-09-14 drh: if( stat(azDirs[i], &buf) ) continue; c287665ba8 2007-09-14 drh: if( !S_ISDIR(buf.st_mode) ) continue; c287665ba8 2007-09-14 drh: if( access(azDirs[i], 07) ) continue; c287665ba8 2007-09-14 drh: zDir = azDirs[i]; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: do{ c287665ba8 2007-09-14 drh: assert( pVfs->mxPathname==MAX_PATHNAME ); c287665ba8 2007-09-14 drh: sqlite3_snprintf(MAX_PATHNAME-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir); c287665ba8 2007-09-14 drh: j = strlen(zBuf); c287665ba8 2007-09-14 drh: sqlite3Randomness(15, &zBuf[j]); c287665ba8 2007-09-14 drh: for(i=0; i<15; i++, j++){ c287665ba8 2007-09-14 drh: zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: zBuf[j] = 0; c287665ba8 2007-09-14 drh: }while( access(zBuf,0)==0 ); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Turn a relative pathname into a full pathname. The relative path c287665ba8 2007-09-14 drh: ** is stored as a nul-terminated string in the buffer pointed to by c287665ba8 2007-09-14 drh: ** zPath. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes c287665ba8 2007-09-14 drh: ** (in this case, MAX_PATHNAME bytes). The full-path is written to c287665ba8 2007-09-14 drh: ** this buffer before returning. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixFullPathname(sqlite3_vfs *pVfs, const char *zPath, char *zOut){ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* It's odd to simulate an io-error here, but really this is just c287665ba8 2007-09-14 drh: ** using the io-error infrastructure to test that SQLite handles this c287665ba8 2007-09-14 drh: ** function failing. This function could fail if, for example, the c287665ba8 2007-09-14 drh: ** current working directly has been unlinked. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SimulateIOError( return SQLITE_ERROR ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( pVfs->mxPathname==MAX_PATHNAME ); c287665ba8 2007-09-14 drh: zOut[MAX_PATHNAME-1] = '\0'; c287665ba8 2007-09-14 drh: if( zPath[0]=='/' ){ c287665ba8 2007-09-14 drh: sqlite3_snprintf(MAX_PATHNAME, zOut, "%s", zPath); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: int nCwd; c287665ba8 2007-09-14 drh: if( getcwd(zOut, MAX_PATHNAME-1)==0 ){ c287665ba8 2007-09-14 drh: return SQLITE_CANTOPEN; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: nCwd = strlen(zOut); c287665ba8 2007-09-14 drh: sqlite3_snprintf(MAX_PATHNAME-nCwd, &zOut[nCwd], "/%s", zPath); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #if 0 c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Remove "/./" path elements and convert "/A/./" path elements c287665ba8 2007-09-14 drh: ** to just "/". c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( zFull ){ c287665ba8 2007-09-14 drh: int i, j; c287665ba8 2007-09-14 drh: for(i=j=0; zFull[i]; i++){ c287665ba8 2007-09-14 drh: if( zFull[i]=='/' ){ c287665ba8 2007-09-14 drh: if( zFull[i+1]=='/' ) continue; c287665ba8 2007-09-14 drh: if( zFull[i+1]=='.' && zFull[i+2]=='/' ){ c287665ba8 2007-09-14 drh: i += 1; c287665ba8 2007-09-14 drh: continue; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( zFull[i+1]=='.' && zFull[i+2]=='.' && zFull[i+3]=='/' ){ c287665ba8 2007-09-14 drh: while( j>0 && zFull[j-1]!='/' ){ j--; } c287665ba8 2007-09-14 drh: i += 3; c287665ba8 2007-09-14 drh: continue; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: zFull[j++] = zFull[i]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: zFull[j] = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_LOAD_EXTENSION dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Interfaces for opening a shared library, finding entry points dbda8d6ce9 2007-07-21 drh: ** within the shared library, and closing the shared library. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #include <dlfcn.h> c287665ba8 2007-09-14 drh: static void *unixDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ dbda8d6ce9 2007-07-21 drh: return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** SQLite calls this function immediately after a call to unixDlSym() or c287665ba8 2007-09-14 drh: ** unixDlOpen() fails (returns a null pointer). If a more detailed error c287665ba8 2007-09-14 drh: ** message is available, it is written to zBufOut. If no error message c287665ba8 2007-09-14 drh: ** is available, zBufOut is left unmodified and SQLite uses a default c287665ba8 2007-09-14 drh: ** error message. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void unixDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ c287665ba8 2007-09-14 drh: char *zErr; c287665ba8 2007-09-14 drh: enterMutex(); c287665ba8 2007-09-14 drh: zErr = dlerror(); c287665ba8 2007-09-14 drh: if( zErr ){ c287665ba8 2007-09-14 drh: sqlite3_snprintf(nBuf, zBufOut, "%s", zErr); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: leaveMutex(); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: static void *unixDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ dbda8d6ce9 2007-07-21 drh: return dlsym(pHandle, zSymbol); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: static void unixDlClose(sqlite3_vfs *pVfs, void *pHandle){ c287665ba8 2007-09-14 drh: dlclose(pHandle); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ c287665ba8 2007-09-14 drh: #define unixDlOpen 0 c287665ba8 2007-09-14 drh: #define unixDlError 0 c287665ba8 2007-09-14 drh: #define unixDlSym 0 c287665ba8 2007-09-14 drh: #define unixDlClose 0 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Write nBuf bytes of random data to the supplied buffer zBuf. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert(nBuf>=(sizeof(time_t)+sizeof(int))); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* We have to initialize zBuf to prevent valgrind from reporting dbda8d6ce9 2007-07-21 drh: ** errors. The reports issued by valgrind are incorrect - we would dbda8d6ce9 2007-07-21 drh: ** prefer that the randomness be increased by making use of the dbda8d6ce9 2007-07-21 drh: ** uninitialized space in zBuf - but valgrind errors tend to worry dbda8d6ce9 2007-07-21 drh: ** some users. Rather than argue, it seems easier just to initialize dbda8d6ce9 2007-07-21 drh: ** the whole array and silence valgrind, even if that means less randomness dbda8d6ce9 2007-07-21 drh: ** in the random seed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When testing, initializing zBuf[] to zero is all we do. That means dbda8d6ce9 2007-07-21 drh: ** that we always use the same random number sequence. This makes the dbda8d6ce9 2007-07-21 drh: ** tests repeatable. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: memset(zBuf, 0, nBuf); dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_TEST) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int pid, fd; dbda8d6ce9 2007-07-21 drh: fd = open("/dev/urandom", O_RDONLY); dbda8d6ce9 2007-07-21 drh: if( fd<0 ){ dbda8d6ce9 2007-07-21 drh: time_t t; dbda8d6ce9 2007-07-21 drh: time(&t); dbda8d6ce9 2007-07-21 drh: memcpy(zBuf, &t, sizeof(t)); dbda8d6ce9 2007-07-21 drh: pid = getpid(); c287665ba8 2007-09-14 drh: memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: read(fd, zBuf, nBuf); dbda8d6ce9 2007-07-21 drh: close(fd); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Sleep for a little while. Return the amount of time slept. c287665ba8 2007-09-14 drh: ** The argument is the number of microseconds we want to sleep. c287665ba8 2007-09-14 drh: ** The return value is the number of microseconds of sleep actually c287665ba8 2007-09-14 drh: ** requested from the underlying operating system, a number which c287665ba8 2007-09-14 drh: ** might be greater than or equal to the argument, but not less c287665ba8 2007-09-14 drh: ** than the argument. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unixSleep(sqlite3_vfs *pVfs, int microseconds){ dbda8d6ce9 2007-07-21 drh: #if defined(HAVE_USLEEP) && HAVE_USLEEP c287665ba8 2007-09-14 drh: usleep(microseconds); c287665ba8 2007-09-14 drh: return microseconds; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: int seconds = (microseconds+999999)/1000000; c287665ba8 2007-09-14 drh: sleep(seconds); c287665ba8 2007-09-14 drh: return seconds*1000000; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following variable, if set to a non-zero value, becomes the result dbda8d6ce9 2007-07-21 drh: ** returned from sqlite3OsCurrentTime(). This is used for testing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_current_time = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the current time (in Universal Coordinated Time). Write the dbda8d6ce9 2007-07-21 drh: ** current time and date as a Julian Day number into *prNow and dbda8d6ce9 2007-07-21 drh: ** return 0. Return 1 if the time and date cannot be found. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int unixCurrentTime(sqlite3_vfs *pVfs, double *prNow){ dbda8d6ce9 2007-07-21 drh: #ifdef NO_GETTOD dbda8d6ce9 2007-07-21 drh: time_t t; dbda8d6ce9 2007-07-21 drh: time(&t); dbda8d6ce9 2007-07-21 drh: *prNow = t/86400.0 + 2440587.5; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: struct timeval sNow; dbda8d6ce9 2007-07-21 drh: gettimeofday(&sNow, 0); dbda8d6ce9 2007-07-21 drh: *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: if( sqlite3_current_time ){ dbda8d6ce9 2007-07-21 drh: *prNow = sqlite3_current_time/86400.0 + 2440587.5; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return a pointer to the sqlite3DefaultVfs structure. We use c287665ba8 2007-09-14 drh: ** a function rather than give the structure global scope because c287665ba8 2007-09-14 drh: ** some compilers (MSVC) do not allow forward declarations of c287665ba8 2007-09-14 drh: ** initialized structures. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3_vfs *sqlite3OsDefaultVfs(void){ c287665ba8 2007-09-14 drh: static sqlite3_vfs unixVfs = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: sizeof(unixFile), /* szOsFile */ c287665ba8 2007-09-14 drh: MAX_PATHNAME, /* mxPathname */ c287665ba8 2007-09-14 drh: 0, /* pNext */ c287665ba8 2007-09-14 drh: "unix", /* zName */ c287665ba8 2007-09-14 drh: 0, /* pAppData */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: unixOpen, /* xOpen */ c287665ba8 2007-09-14 drh: unixDelete, /* xDelete */ c287665ba8 2007-09-14 drh: unixAccess, /* xAccess */ c287665ba8 2007-09-14 drh: unixGetTempName, /* xGetTempName */ c287665ba8 2007-09-14 drh: unixFullPathname, /* xFullPathname */ c287665ba8 2007-09-14 drh: unixDlOpen, /* xDlOpen */ c287665ba8 2007-09-14 drh: unixDlError, /* xDlError */ c287665ba8 2007-09-14 drh: unixDlSym, /* xDlSym */ c287665ba8 2007-09-14 drh: unixDlClose, /* xDlClose */ c287665ba8 2007-09-14 drh: unixRandomness, /* xRandomness */ c287665ba8 2007-09-14 drh: unixSleep, /* xSleep */ c287665ba8 2007-09-14 drh: unixCurrentTime /* xCurrentTime */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: return &unixVfs; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* OS_UNIX */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of os_unix.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file os_win.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 May 22 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains code that is specific to windows. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if OS_WIN /* This file is used for windows only */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** A Note About Memory Allocation: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This driver uses malloc()/free() directly rather than going through c287665ba8 2007-09-14 drh: ** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers c287665ba8 2007-09-14 drh: ** are designed for use on embedded systems where memory is scarce and c287665ba8 2007-09-14 drh: ** malloc failures happen frequently. Win32 does not typically run on c287665ba8 2007-09-14 drh: ** embedded systems, and when it does the developers normally have bigger c287665ba8 2007-09-14 drh: ** problems to worry about than running out of memory. So there is not c287665ba8 2007-09-14 drh: ** a compelling need to use the wrappers. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** But there is a good reason to not use the wrappers. If we use the c287665ba8 2007-09-14 drh: ** wrappers then we will get simulated malloc() failures within this c287665ba8 2007-09-14 drh: ** driver. And that causes all kinds of problems for our tests. We c287665ba8 2007-09-14 drh: ** could enhance SQLite to deal with simulated malloc failures within c287665ba8 2007-09-14 drh: ** the OS driver, but the code to deal with those failure would not c287665ba8 2007-09-14 drh: ** be exercised on Linux (which does not need to malloc() in the driver) c287665ba8 2007-09-14 drh: ** and so we would have difficulty writing coverage tests for that c287665ba8 2007-09-14 drh: ** code. Better to leave the code out, we think. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The point of this discussion is as follows: When creating a new c287665ba8 2007-09-14 drh: ** OS layer for an embedded system, if you use this file as an example, c287665ba8 2007-09-14 drh: ** avoid the use of malloc()/free(). Those routines work ok on windows c287665ba8 2007-09-14 drh: ** desktops but not so well in embedded systems. c287665ba8 2007-09-14 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #include <winbase.h> dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef __CYGWIN__ dbda8d6ce9 2007-07-21 drh: # include <sys/cygwin.h> dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Macros used to determine whether or not to use threads. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if defined(THREADSAFE) && THREADSAFE dbda8d6ce9 2007-07-21 drh: # define SQLITE_W32_THREADS 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Include code that is common to all os_*.c files dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /************** Include os_common.h in the middle of os_win.c ****************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file os_common.h ***************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 May 22 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ****************************************************************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains macros and a little bit of code that is common to dbda8d6ce9 2007-07-21 drh: ** all of the platform-specific files (os_*.c) and is #included into those dbda8d6ce9 2007-07-21 drh: ** files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file should be #included by the os_*.c files only. It is not a dbda8d6ce9 2007-07-21 drh: ** general purpose header file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** At least two bugs have slipped in because we changed the MEMORY_DEBUG dbda8d6ce9 2007-07-21 drh: ** macro to SQLITE_DEBUG and some older makefiles have not yet made the dbda8d6ce9 2007-07-21 drh: ** switch. The following code should catch this problem at compile-time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef MEMORY_DEBUG dbda8d6ce9 2007-07-21 drh: # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * When testing, this global variable stores the location of the dbda8d6ce9 2007-07-21 drh: * pending-byte in the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API unsigned int sqlite3_pending_byte = 0x40000000; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_os_trace = 0; dbda8d6ce9 2007-07-21 drh: #define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X) dbda8d6ce9 2007-07-21 drh: #define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y) dbda8d6ce9 2007-07-21 drh: #define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z) dbda8d6ce9 2007-07-21 drh: #define OSTRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A) dbda8d6ce9 2007-07-21 drh: #define OSTRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B) dbda8d6ce9 2007-07-21 drh: #define OSTRACE6(X,Y,Z,A,B,C) \ dbda8d6ce9 2007-07-21 drh: if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C) dbda8d6ce9 2007-07-21 drh: #define OSTRACE7(X,Y,Z,A,B,C,D) \ dbda8d6ce9 2007-07-21 drh: if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define OSTRACE1(X) dbda8d6ce9 2007-07-21 drh: #define OSTRACE2(X,Y) dbda8d6ce9 2007-07-21 drh: #define OSTRACE3(X,Y,Z) dbda8d6ce9 2007-07-21 drh: #define OSTRACE4(X,Y,Z,A) dbda8d6ce9 2007-07-21 drh: #define OSTRACE5(X,Y,Z,A,B) dbda8d6ce9 2007-07-21 drh: #define OSTRACE6(X,Y,Z,A,B,C) dbda8d6ce9 2007-07-21 drh: #define OSTRACE7(X,Y,Z,A,B,C,D) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Macros for performance tracing. Normally turned off. Only works dbda8d6ce9 2007-07-21 drh: ** on i486 hardware. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_PERFORMANCE_TRACE dbda8d6ce9 2007-07-21 drh: __inline__ unsigned long long int hwtime(void){ dbda8d6ce9 2007-07-21 drh: unsigned long long int x; dbda8d6ce9 2007-07-21 drh: __asm__("rdtsc\n\t" dbda8d6ce9 2007-07-21 drh: "mov %%edx, %%ecx\n\t" dbda8d6ce9 2007-07-21 drh: :"=A" (x)); dbda8d6ce9 2007-07-21 drh: return x; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static unsigned long long int g_start; dbda8d6ce9 2007-07-21 drh: static unsigned int elapse; dbda8d6ce9 2007-07-21 drh: #define TIMER_START g_start=hwtime() dbda8d6ce9 2007-07-21 drh: #define TIMER_END elapse=hwtime()-g_start dbda8d6ce9 2007-07-21 drh: #define TIMER_ELAPSED elapse dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define TIMER_START dbda8d6ce9 2007-07-21 drh: #define TIMER_END dbda8d6ce9 2007-07-21 drh: #define TIMER_ELAPSED 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If we compile with the SQLITE_TEST macro set, then the following block dbda8d6ce9 2007-07-21 drh: ** of code will give us the ability to simulate a disk I/O error. This dbda8d6ce9 2007-07-21 drh: ** is used for testing the I/O recovery logic. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_hit = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_pending = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_io_error_persist = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_diskfull_pending = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_diskfull = 0; dbda8d6ce9 2007-07-21 drh: #define SimulateIOError(CODE) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_io_error_pending || sqlite3_io_error_hit ) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_io_error_pending-- == 1 \ dbda8d6ce9 2007-07-21 drh: || (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \ dbda8d6ce9 2007-07-21 drh: { local_ioerr(); CODE; } dbda8d6ce9 2007-07-21 drh: static void local_ioerr(){ dbda8d6ce9 2007-07-21 drh: IOTRACE(("IOERR\n")); dbda8d6ce9 2007-07-21 drh: sqlite3_io_error_hit = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #define SimulateDiskfullError(CODE) \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_diskfull_pending ){ \ dbda8d6ce9 2007-07-21 drh: if( sqlite3_diskfull_pending == 1 ){ \ dbda8d6ce9 2007-07-21 drh: local_ioerr(); \ dbda8d6ce9 2007-07-21 drh: sqlite3_diskfull = 1; \ dbda8d6ce9 2007-07-21 drh: sqlite3_io_error_hit = 1; \ dbda8d6ce9 2007-07-21 drh: CODE; \ dbda8d6ce9 2007-07-21 drh: }else{ \ dbda8d6ce9 2007-07-21 drh: sqlite3_diskfull_pending--; \ dbda8d6ce9 2007-07-21 drh: } \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define SimulateIOError(A) dbda8d6ce9 2007-07-21 drh: #define SimulateDiskfullError(A) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** When testing, keep a count of the number of open files. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_open_file_count = 0; dbda8d6ce9 2007-07-21 drh: #define OpenCounter(X) sqlite3_open_file_count+=(X) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define OpenCounter(X) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of os_common.h *******************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in os_win.c *********************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Determine if we are dealing with WindowsCE - which has a much dbda8d6ce9 2007-07-21 drh: ** reduced API. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if defined(_WIN32_WCE) dbda8d6ce9 2007-07-21 drh: # define OS_WINCE 1 dbda8d6ce9 2007-07-21 drh: # define AreFileApisANSI() 1 dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define OS_WINCE 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** WinCE lacks native support for file locking so we have to fake it dbda8d6ce9 2007-07-21 drh: ** with some code of our own. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if OS_WINCE dbda8d6ce9 2007-07-21 drh: typedef struct winceLock { dbda8d6ce9 2007-07-21 drh: int nReaders; /* Number of reader locks obtained */ dbda8d6ce9 2007-07-21 drh: BOOL bPending; /* Indicates a pending lock has been obtained */ dbda8d6ce9 2007-07-21 drh: BOOL bReserved; /* Indicates a reserved lock has been obtained */ dbda8d6ce9 2007-07-21 drh: BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ dbda8d6ce9 2007-07-21 drh: } winceLock; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** The winFile structure is a subclass of sqlite3_file* specific to the win32 dbda8d6ce9 2007-07-21 drh: ** portability layer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct winFile winFile; dbda8d6ce9 2007-07-21 drh: struct winFile { c287665ba8 2007-09-14 drh: const sqlite3_io_methods *pMethod;/* Must be first */ dbda8d6ce9 2007-07-21 drh: HANDLE h; /* Handle for accessing the file */ dbda8d6ce9 2007-07-21 drh: unsigned char locktype; /* Type of lock currently held on this file */ dbda8d6ce9 2007-07-21 drh: short sharedLockByte; /* Randomly chosen byte used as a shared lock */ dbda8d6ce9 2007-07-21 drh: #if OS_WINCE dbda8d6ce9 2007-07-21 drh: WCHAR *zDeleteOnClose; /* Name of file to delete when closing */ dbda8d6ce9 2007-07-21 drh: HANDLE hMutex; /* Mutex used to control access to shared lock */ dbda8d6ce9 2007-07-21 drh: HANDLE hShared; /* Shared memory segment used for locking */ dbda8d6ce9 2007-07-21 drh: winceLock local; /* Locks obtained by this instance of winFile */ dbda8d6ce9 2007-07-21 drh: winceLock *shared; /* Global shared lock memory for the file */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following variable is (normally) set once and never changes dbda8d6ce9 2007-07-21 drh: ** thereafter. It records whether the operating system is Win95 dbda8d6ce9 2007-07-21 drh: ** or WinNT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 0: Operating system unknown. dbda8d6ce9 2007-07-21 drh: ** 1: Operating system is Win95. dbda8d6ce9 2007-07-21 drh: ** 2: Operating system is WinNT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In order to facilitate testing on a WinNT system, the test fixture dbda8d6ce9 2007-07-21 drh: ** can manually set this value to 1 to emulate Win98 behavior. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_os_type = 0; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: static int sqlite3_os_type = 0; c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, dbda8d6ce9 2007-07-21 drh: ** or WinCE. Return false (zero) for Win95, Win98, or WinME. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Here is an interesting observation: Win95, Win98, and WinME lack dbda8d6ce9 2007-07-21 drh: ** the LockFileEx() API. But we can still statically link against that dbda8d6ce9 2007-07-21 drh: ** API as long as we don't call it win running Win95/98/ME. A call to dbda8d6ce9 2007-07-21 drh: ** this routine is used to determine if the host is Win95/98/ME or dbda8d6ce9 2007-07-21 drh: ** WinNT/2K/XP so that we will know whether or not we can safely call dbda8d6ce9 2007-07-21 drh: ** the LockFileEx() API. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if OS_WINCE dbda8d6ce9 2007-07-21 drh: # define isNT() (1) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: static int isNT(void){ dbda8d6ce9 2007-07-21 drh: if( sqlite3_os_type==0 ){ dbda8d6ce9 2007-07-21 drh: OSVERSIONINFO sInfo; dbda8d6ce9 2007-07-21 drh: sInfo.dwOSVersionInfoSize = sizeof(sInfo); dbda8d6ce9 2007-07-21 drh: GetVersionEx(&sInfo); dbda8d6ce9 2007-07-21 drh: sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return sqlite3_os_type==2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* OS_WINCE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert a UTF-8 string to microsoft unicode (UTF-16?). dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Space to hold the returned string is obtained from malloc. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static WCHAR *utf8ToUnicode(const char *zFilename){ dbda8d6ce9 2007-07-21 drh: int nChar; dbda8d6ce9 2007-07-21 drh: WCHAR *zWideFilename; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); c287665ba8 2007-09-14 drh: zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) ); dbda8d6ce9 2007-07-21 drh: if( zWideFilename==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar); dbda8d6ce9 2007-07-21 drh: if( nChar==0 ){ c287665ba8 2007-09-14 drh: free(zWideFilename); dbda8d6ce9 2007-07-21 drh: zWideFilename = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zWideFilename; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert microsoft unicode to UTF-8. Space to hold the returned string is c287665ba8 2007-09-14 drh: ** obtained from malloc(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char *unicodeToUtf8(const WCHAR *zWideFilename){ dbda8d6ce9 2007-07-21 drh: int nByte; dbda8d6ce9 2007-07-21 drh: char *zFilename; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); c287665ba8 2007-09-14 drh: zFilename = malloc( nByte ); dbda8d6ce9 2007-07-21 drh: if( zFilename==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, dbda8d6ce9 2007-07-21 drh: 0, 0); dbda8d6ce9 2007-07-21 drh: if( nByte == 0 ){ c287665ba8 2007-09-14 drh: free(zFilename); dbda8d6ce9 2007-07-21 drh: zFilename = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zFilename; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert an ansi string to microsoft unicode, based on the dbda8d6ce9 2007-07-21 drh: ** current codepage settings for file apis. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Space to hold the returned string is obtained c287665ba8 2007-09-14 drh: ** from malloc. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static WCHAR *mbcsToUnicode(const char *zFilename){ dbda8d6ce9 2007-07-21 drh: int nByte; dbda8d6ce9 2007-07-21 drh: WCHAR *zMbcsFilename; dbda8d6ce9 2007-07-21 drh: int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR); c287665ba8 2007-09-14 drh: zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) ); dbda8d6ce9 2007-07-21 drh: if( zMbcsFilename==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte); dbda8d6ce9 2007-07-21 drh: if( nByte==0 ){ c287665ba8 2007-09-14 drh: free(zMbcsFilename); dbda8d6ce9 2007-07-21 drh: zMbcsFilename = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zMbcsFilename; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert microsoft unicode to multibyte character string, based on the dbda8d6ce9 2007-07-21 drh: ** user's Ansi codepage. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Space to hold the returned string is obtained from c287665ba8 2007-09-14 drh: ** malloc(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char *unicodeToMbcs(const WCHAR *zWideFilename){ dbda8d6ce9 2007-07-21 drh: int nByte; dbda8d6ce9 2007-07-21 drh: char *zFilename; dbda8d6ce9 2007-07-21 drh: int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0); c287665ba8 2007-09-14 drh: zFilename = malloc( nByte ); dbda8d6ce9 2007-07-21 drh: if( zFilename==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte, dbda8d6ce9 2007-07-21 drh: 0, 0); dbda8d6ce9 2007-07-21 drh: if( nByte == 0 ){ c287665ba8 2007-09-14 drh: free(zFilename); dbda8d6ce9 2007-07-21 drh: zFilename = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zFilename; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert multibyte character string to UTF-8. Space to hold the c287665ba8 2007-09-14 drh: ** returned string is obtained from malloc(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char *mbcsToUtf8(const char *zFilename){ dbda8d6ce9 2007-07-21 drh: char *zFilenameUtf8; dbda8d6ce9 2007-07-21 drh: WCHAR *zTmpWide; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zTmpWide = mbcsToUnicode(zFilename); dbda8d6ce9 2007-07-21 drh: if( zTmpWide==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zFilenameUtf8 = unicodeToUtf8(zTmpWide); c287665ba8 2007-09-14 drh: free(zTmpWide); dbda8d6ce9 2007-07-21 drh: return zFilenameUtf8; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert UTF-8 to multibyte character string. Space to hold the c287665ba8 2007-09-14 drh: ** returned string is obtained from malloc(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char *utf8ToMbcs(const char *zFilename){ dbda8d6ce9 2007-07-21 drh: char *zFilenameMbcs; dbda8d6ce9 2007-07-21 drh: WCHAR *zTmpWide; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zTmpWide = utf8ToUnicode(zFilename); dbda8d6ce9 2007-07-21 drh: if( zTmpWide==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zFilenameMbcs = unicodeToMbcs(zTmpWide); c287665ba8 2007-09-14 drh: free(zTmpWide); dbda8d6ce9 2007-07-21 drh: return zFilenameMbcs; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if OS_WINCE dbda8d6ce9 2007-07-21 drh: /************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This section contains code for WinCE only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** WindowsCE does not have a localtime() function. So create a dbda8d6ce9 2007-07-21 drh: ** substitute. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct tm *__cdecl localtime(const time_t *t) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: static struct tm y; dbda8d6ce9 2007-07-21 drh: FILETIME uTm, lTm; dbda8d6ce9 2007-07-21 drh: SYSTEMTIME pTm; dbda8d6ce9 2007-07-21 drh: i64 t64; dbda8d6ce9 2007-07-21 drh: t64 = *t; dbda8d6ce9 2007-07-21 drh: t64 = (t64 + 11644473600)*10000000; dbda8d6ce9 2007-07-21 drh: uTm.dwLowDateTime = t64 & 0xFFFFFFFF; dbda8d6ce9 2007-07-21 drh: uTm.dwHighDateTime= t64 >> 32; dbda8d6ce9 2007-07-21 drh: FileTimeToLocalFileTime(&uTm,&lTm); dbda8d6ce9 2007-07-21 drh: FileTimeToSystemTime(&lTm,&pTm); dbda8d6ce9 2007-07-21 drh: y.tm_year = pTm.wYear - 1900; dbda8d6ce9 2007-07-21 drh: y.tm_mon = pTm.wMonth - 1; dbda8d6ce9 2007-07-21 drh: y.tm_wday = pTm.wDayOfWeek; dbda8d6ce9 2007-07-21 drh: y.tm_mday = pTm.wDay; dbda8d6ce9 2007-07-21 drh: y.tm_hour = pTm.wHour; dbda8d6ce9 2007-07-21 drh: y.tm_min = pTm.wMinute; dbda8d6ce9 2007-07-21 drh: y.tm_sec = pTm.wSecond; dbda8d6ce9 2007-07-21 drh: return &y; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This will never be called, but defined to make the code compile */ dbda8d6ce9 2007-07-21 drh: #define GetTempPathA(a,b) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e) dbda8d6ce9 2007-07-21 drh: #define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e) dbda8d6ce9 2007-07-21 drh: #define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-offsetof(winFile,h)] dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Acquire a lock on the handle h dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void winceMutexAcquire(HANDLE h){ dbda8d6ce9 2007-07-21 drh: DWORD dwErr; dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: dwErr = WaitForSingleObject(h, INFINITE); dbda8d6ce9 2007-07-21 drh: } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release a lock acquired by winceMutexAcquire() dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define winceMutexRelease(h) ReleaseMutex(h) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create the mutex and shared memory used for locking in the file dbda8d6ce9 2007-07-21 drh: ** descriptor pFile dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static BOOL winceCreateLock(const char *zFilename, winFile *pFile){ dbda8d6ce9 2007-07-21 drh: WCHAR *zTok; dbda8d6ce9 2007-07-21 drh: WCHAR *zName = utf8ToUnicode(zFilename); dbda8d6ce9 2007-07-21 drh: BOOL bInit = TRUE; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the local lockdata */ dbda8d6ce9 2007-07-21 drh: ZeroMemory(&pFile->local, sizeof(pFile->local)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Replace the backslashes from the filename and lowercase it dbda8d6ce9 2007-07-21 drh: ** to derive a mutex name. */ dbda8d6ce9 2007-07-21 drh: zTok = CharLowerW(zName); dbda8d6ce9 2007-07-21 drh: for (;*zTok;zTok++){ dbda8d6ce9 2007-07-21 drh: if (*zTok == '\\') *zTok = '_'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create/open the named mutex */ dbda8d6ce9 2007-07-21 drh: pFile->hMutex = CreateMutexW(NULL, FALSE, zName); dbda8d6ce9 2007-07-21 drh: if (!pFile->hMutex){ c287665ba8 2007-09-14 drh: free(zName); dbda8d6ce9 2007-07-21 drh: return FALSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire the mutex before continuing */ dbda8d6ce9 2007-07-21 drh: winceMutexAcquire(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Since the names of named mutexes, semaphores, file mappings etc are dbda8d6ce9 2007-07-21 drh: ** case-sensitive, take advantage of that by uppercasing the mutex name dbda8d6ce9 2007-07-21 drh: ** and using that as the shared filemapping name. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: CharUpperW(zName); dbda8d6ce9 2007-07-21 drh: pFile->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, dbda8d6ce9 2007-07-21 drh: PAGE_READWRITE, 0, sizeof(winceLock), dbda8d6ce9 2007-07-21 drh: zName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set a flag that indicates we're the first to create the memory so it dbda8d6ce9 2007-07-21 drh: ** must be zero-initialized */ dbda8d6ce9 2007-07-21 drh: if (GetLastError() == ERROR_ALREADY_EXISTS){ dbda8d6ce9 2007-07-21 drh: bInit = FALSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: free(zName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we succeeded in making the shared memory handle, map it. */ dbda8d6ce9 2007-07-21 drh: if (pFile->hShared){ dbda8d6ce9 2007-07-21 drh: pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, dbda8d6ce9 2007-07-21 drh: FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); dbda8d6ce9 2007-07-21 drh: /* If mapping failed, close the shared memory handle and erase it */ dbda8d6ce9 2007-07-21 drh: if (!pFile->shared){ dbda8d6ce9 2007-07-21 drh: CloseHandle(pFile->hShared); dbda8d6ce9 2007-07-21 drh: pFile->hShared = NULL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If shared memory could not be created, then close the mutex and fail */ dbda8d6ce9 2007-07-21 drh: if (pFile->hShared == NULL){ dbda8d6ce9 2007-07-21 drh: winceMutexRelease(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: CloseHandle(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: pFile->hMutex = NULL; dbda8d6ce9 2007-07-21 drh: return FALSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the shared memory if we're supposed to */ dbda8d6ce9 2007-07-21 drh: if (bInit) { dbda8d6ce9 2007-07-21 drh: ZeroMemory(pFile->shared, sizeof(winceLock)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: winceMutexRelease(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: return TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Destroy the part of winFile that deals with wince locks dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void winceDestroyLock(winFile *pFile){ dbda8d6ce9 2007-07-21 drh: if (pFile->hMutex){ dbda8d6ce9 2007-07-21 drh: /* Acquire the mutex */ dbda8d6ce9 2007-07-21 drh: winceMutexAcquire(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following blocks should probably assert in debug mode, but they dbda8d6ce9 2007-07-21 drh: are to cleanup in case any locks remained open */ dbda8d6ce9 2007-07-21 drh: if (pFile->local.nReaders){ dbda8d6ce9 2007-07-21 drh: pFile->shared->nReaders --; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if (pFile->local.bReserved){ dbda8d6ce9 2007-07-21 drh: pFile->shared->bReserved = FALSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if (pFile->local.bPending){ dbda8d6ce9 2007-07-21 drh: pFile->shared->bPending = FALSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if (pFile->local.bExclusive){ dbda8d6ce9 2007-07-21 drh: pFile->shared->bExclusive = FALSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* De-reference and close our copy of the shared memory handle */ dbda8d6ce9 2007-07-21 drh: UnmapViewOfFile(pFile->shared); dbda8d6ce9 2007-07-21 drh: CloseHandle(pFile->hShared); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pFile->zDeleteOnClose ){ dbda8d6ce9 2007-07-21 drh: DeleteFileW(pFile->zDeleteOnClose); c287665ba8 2007-09-14 drh: free(pFile->zDeleteOnClose); dbda8d6ce9 2007-07-21 drh: pFile->zDeleteOnClose = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Done with the mutex */ dbda8d6ce9 2007-07-21 drh: winceMutexRelease(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: CloseHandle(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: pFile->hMutex = NULL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An implementation of the LockFile() API of windows for wince dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static BOOL winceLockFile( dbda8d6ce9 2007-07-21 drh: HANDLE *phFile, dbda8d6ce9 2007-07-21 drh: DWORD dwFileOffsetLow, dbda8d6ce9 2007-07-21 drh: DWORD dwFileOffsetHigh, dbda8d6ce9 2007-07-21 drh: DWORD nNumberOfBytesToLockLow, dbda8d6ce9 2007-07-21 drh: DWORD nNumberOfBytesToLockHigh dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: winFile *pFile = HANDLE_TO_WINFILE(phFile); dbda8d6ce9 2007-07-21 drh: BOOL bReturn = FALSE; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if (!pFile->hMutex) return TRUE; dbda8d6ce9 2007-07-21 drh: winceMutexAcquire(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Wanting an exclusive lock? */ dbda8d6ce9 2007-07-21 drh: if (dwFileOffsetLow == SHARED_FIRST dbda8d6ce9 2007-07-21 drh: && nNumberOfBytesToLockLow == SHARED_SIZE){ dbda8d6ce9 2007-07-21 drh: if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){ dbda8d6ce9 2007-07-21 drh: pFile->shared->bExclusive = TRUE; dbda8d6ce9 2007-07-21 drh: pFile->local.bExclusive = TRUE; dbda8d6ce9 2007-07-21 drh: bReturn = TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Want a read-only lock? */ dbda8d6ce9 2007-07-21 drh: else if ((dwFileOffsetLow >= SHARED_FIRST && dbda8d6ce9 2007-07-21 drh: dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) && dbda8d6ce9 2007-07-21 drh: nNumberOfBytesToLockLow == 1){ dbda8d6ce9 2007-07-21 drh: if (pFile->shared->bExclusive == 0){ dbda8d6ce9 2007-07-21 drh: pFile->local.nReaders ++; dbda8d6ce9 2007-07-21 drh: if (pFile->local.nReaders == 1){ dbda8d6ce9 2007-07-21 drh: pFile->shared->nReaders ++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: bReturn = TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Want a pending lock? */ dbda8d6ce9 2007-07-21 drh: else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToLockLow == 1){ dbda8d6ce9 2007-07-21 drh: /* If no pending lock has been acquired, then acquire it */ dbda8d6ce9 2007-07-21 drh: if (pFile->shared->bPending == 0) { dbda8d6ce9 2007-07-21 drh: pFile->shared->bPending = TRUE; dbda8d6ce9 2007-07-21 drh: pFile->local.bPending = TRUE; dbda8d6ce9 2007-07-21 drh: bReturn = TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Want a reserved lock? */ dbda8d6ce9 2007-07-21 drh: else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToLockLow == 1){ dbda8d6ce9 2007-07-21 drh: if (pFile->shared->bReserved == 0) { dbda8d6ce9 2007-07-21 drh: pFile->shared->bReserved = TRUE; dbda8d6ce9 2007-07-21 drh: pFile->local.bReserved = TRUE; dbda8d6ce9 2007-07-21 drh: bReturn = TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: winceMutexRelease(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: return bReturn; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An implementation of the UnlockFile API of windows for wince dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static BOOL winceUnlockFile( dbda8d6ce9 2007-07-21 drh: HANDLE *phFile, dbda8d6ce9 2007-07-21 drh: DWORD dwFileOffsetLow, dbda8d6ce9 2007-07-21 drh: DWORD dwFileOffsetHigh, dbda8d6ce9 2007-07-21 drh: DWORD nNumberOfBytesToUnlockLow, dbda8d6ce9 2007-07-21 drh: DWORD nNumberOfBytesToUnlockHigh dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: winFile *pFile = HANDLE_TO_WINFILE(phFile); dbda8d6ce9 2007-07-21 drh: BOOL bReturn = FALSE; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if (!pFile->hMutex) return TRUE; dbda8d6ce9 2007-07-21 drh: winceMutexAcquire(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Releasing a reader lock or an exclusive lock */ dbda8d6ce9 2007-07-21 drh: if (dwFileOffsetLow >= SHARED_FIRST && dbda8d6ce9 2007-07-21 drh: dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE){ dbda8d6ce9 2007-07-21 drh: /* Did we have an exclusive lock? */ dbda8d6ce9 2007-07-21 drh: if (pFile->local.bExclusive){ dbda8d6ce9 2007-07-21 drh: pFile->local.bExclusive = FALSE; dbda8d6ce9 2007-07-21 drh: pFile->shared->bExclusive = FALSE; dbda8d6ce9 2007-07-21 drh: bReturn = TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Did we just have a reader lock? */ dbda8d6ce9 2007-07-21 drh: else if (pFile->local.nReaders){ dbda8d6ce9 2007-07-21 drh: pFile->local.nReaders --; dbda8d6ce9 2007-07-21 drh: if (pFile->local.nReaders == 0) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: pFile->shared->nReaders --; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: bReturn = TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Releasing a pending lock */ dbda8d6ce9 2007-07-21 drh: else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){ dbda8d6ce9 2007-07-21 drh: if (pFile->local.bPending){ dbda8d6ce9 2007-07-21 drh: pFile->local.bPending = FALSE; dbda8d6ce9 2007-07-21 drh: pFile->shared->bPending = FALSE; dbda8d6ce9 2007-07-21 drh: bReturn = TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Releasing a reserved lock */ dbda8d6ce9 2007-07-21 drh: else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){ dbda8d6ce9 2007-07-21 drh: if (pFile->local.bReserved) { dbda8d6ce9 2007-07-21 drh: pFile->local.bReserved = FALSE; dbda8d6ce9 2007-07-21 drh: pFile->shared->bReserved = FALSE; dbda8d6ce9 2007-07-21 drh: bReturn = TRUE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: winceMutexRelease(pFile->hMutex); dbda8d6ce9 2007-07-21 drh: return bReturn; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An implementation of the LockFileEx() API of windows for wince dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static BOOL winceLockFileEx( dbda8d6ce9 2007-07-21 drh: HANDLE *phFile, dbda8d6ce9 2007-07-21 drh: DWORD dwFlags, dbda8d6ce9 2007-07-21 drh: DWORD dwReserved, dbda8d6ce9 2007-07-21 drh: DWORD nNumberOfBytesToLockLow, dbda8d6ce9 2007-07-21 drh: DWORD nNumberOfBytesToLockHigh, dbda8d6ce9 2007-07-21 drh: LPOVERLAPPED lpOverlapped dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: /* If the caller wants a shared read lock, forward this call dbda8d6ce9 2007-07-21 drh: ** to winceLockFile */ dbda8d6ce9 2007-07-21 drh: if (lpOverlapped->Offset == SHARED_FIRST && dbda8d6ce9 2007-07-21 drh: dwFlags == 1 && dbda8d6ce9 2007-07-21 drh: nNumberOfBytesToLockLow == SHARED_SIZE){ dbda8d6ce9 2007-07-21 drh: return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return FALSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** End of the special code for wince dbda8d6ce9 2007-07-21 drh: *****************************************************************************/ dbda8d6ce9 2007-07-21 drh: #endif /* OS_WINCE */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /***************************************************************************** c287665ba8 2007-09-14 drh: ** The next group of routines implement the I/O methods specified c287665ba8 2007-09-14 drh: ** by the sqlite3_io_methods object. c287665ba8 2007-09-14 drh: ******************************************************************************/ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Close a file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** It is reported that an attempt to close a handle might sometimes c287665ba8 2007-09-14 drh: ** fail. This is a very unreasonable result, but windows is notorious c287665ba8 2007-09-14 drh: ** for being unreasonable so I do not doubt that it might happen. If c287665ba8 2007-09-14 drh: ** the close fails, we pause for 100 milliseconds and try again. As c287665ba8 2007-09-14 drh: ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before c287665ba8 2007-09-14 drh: ** giving up and returning an error. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define MX_CLOSE_ATTEMPT 3 c287665ba8 2007-09-14 drh: static int winClose(sqlite3_file *id){ c287665ba8 2007-09-14 drh: int rc, cnt = 0; c287665ba8 2007-09-14 drh: winFile *pFile = (winFile*)id; c287665ba8 2007-09-14 drh: OSTRACE2("CLOSE %d\n", pFile->h); c287665ba8 2007-09-14 drh: do{ c287665ba8 2007-09-14 drh: rc = CloseHandle(pFile->h); c287665ba8 2007-09-14 drh: }while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) ); dbda8d6ce9 2007-07-21 drh: #if OS_WINCE c287665ba8 2007-09-14 drh: winceDestroyLock(pFile); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: OpenCounter(-1); c287665ba8 2007-09-14 drh: return rc ? SQLITE_OK : SQLITE_IOERR; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Some microsoft compilers lack this definition. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef INVALID_SET_FILE_POINTER c287665ba8 2007-09-14 drh: # define INVALID_SET_FILE_POINTER ((DWORD)-1) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Read data from a file into a buffer. Return SQLITE_OK if all c287665ba8 2007-09-14 drh: ** bytes were read successfully and SQLITE_IOERR if anything goes c287665ba8 2007-09-14 drh: ** wrong. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winRead( c287665ba8 2007-09-14 drh: sqlite3_file *id, /* File to read from */ c287665ba8 2007-09-14 drh: void *pBuf, /* Write content into this buffer */ c287665ba8 2007-09-14 drh: int amt, /* Number of bytes to read */ c287665ba8 2007-09-14 drh: sqlite3_int64 offset /* Begin reading at this offset */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: LONG upperBits = (offset>>32) & 0x7fffffff; c287665ba8 2007-09-14 drh: LONG lowerBits = offset & 0xffffffff; c287665ba8 2007-09-14 drh: DWORD rc; c287665ba8 2007-09-14 drh: DWORD got; c287665ba8 2007-09-14 drh: winFile *pFile = (winFile*)id; c287665ba8 2007-09-14 drh: assert( id!=0 ); c287665ba8 2007-09-14 drh: SimulateIOError(return SQLITE_IOERR_READ); c287665ba8 2007-09-14 drh: OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype); c287665ba8 2007-09-14 drh: rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); c287665ba8 2007-09-14 drh: if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ c287665ba8 2007-09-14 drh: return SQLITE_FULL; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( !ReadFile(pFile->h, pBuf, amt, &got, 0) ){ c287665ba8 2007-09-14 drh: return SQLITE_IOERR_READ; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( got==(DWORD)amt ){ c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: memset(&((char*)pBuf)[got], 0, amt-got); c287665ba8 2007-09-14 drh: return SQLITE_IOERR_SHORT_READ; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Write data from a buffer into a file. Return SQLITE_OK on success c287665ba8 2007-09-14 drh: ** or some other error code on failure. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winWrite( c287665ba8 2007-09-14 drh: sqlite3_file *id, /* File to write into */ c287665ba8 2007-09-14 drh: const void *pBuf, /* The bytes to be written */ c287665ba8 2007-09-14 drh: int amt, /* Number of bytes to write */ c287665ba8 2007-09-14 drh: sqlite3_int64 offset /* Offset into the file to begin writing at */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: LONG upperBits = (offset>>32) & 0x7fffffff; c287665ba8 2007-09-14 drh: LONG lowerBits = offset & 0xffffffff; c287665ba8 2007-09-14 drh: DWORD rc; c287665ba8 2007-09-14 drh: DWORD wrote; c287665ba8 2007-09-14 drh: winFile *pFile = (winFile*)id; c287665ba8 2007-09-14 drh: assert( id!=0 ); c287665ba8 2007-09-14 drh: SimulateIOError(return SQLITE_IOERR_WRITE); c287665ba8 2007-09-14 drh: SimulateDiskfullError(return SQLITE_FULL); c287665ba8 2007-09-14 drh: OSTRACE3("WRITE %d lock=%d\n", pFile->h, pFile->locktype); c287665ba8 2007-09-14 drh: rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); c287665ba8 2007-09-14 drh: if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ c287665ba8 2007-09-14 drh: return SQLITE_FULL; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert( amt>0 ); c287665ba8 2007-09-14 drh: while( c287665ba8 2007-09-14 drh: amt>0 c287665ba8 2007-09-14 drh: && (rc = WriteFile(pFile->h, pBuf, amt, &wrote, 0))!=0 c287665ba8 2007-09-14 drh: && wrote>0 c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: amt -= wrote; c287665ba8 2007-09-14 drh: pBuf = &((char*)pBuf)[wrote]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( !rc || amt>(int)wrote ){ c287665ba8 2007-09-14 drh: return SQLITE_FULL; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Truncate an open file to a specified size c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winTruncate(sqlite3_file *id, i64 nByte){ c287665ba8 2007-09-14 drh: LONG upperBits = (nByte>>32) & 0x7fffffff; c287665ba8 2007-09-14 drh: LONG lowerBits = nByte & 0xffffffff; c287665ba8 2007-09-14 drh: winFile *pFile = (winFile*)id; c287665ba8 2007-09-14 drh: OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte); c287665ba8 2007-09-14 drh: SimulateIOError(return SQLITE_IOERR_TRUNCATE); c287665ba8 2007-09-14 drh: SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); c287665ba8 2007-09-14 drh: SetEndOfFile(pFile->h); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Count the number of fullsyncs and normal syncs. This is used to test c287665ba8 2007-09-14 drh: ** that syncs and fullsyncs are occuring at the right times. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_sync_count = 0; c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_fullsync_count = 0; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Make sure all writes to a particular file are committed to disk. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winSync(sqlite3_file *id, int flags){ c287665ba8 2007-09-14 drh: winFile *pFile = (winFile*)id; c287665ba8 2007-09-14 drh: OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype); c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: if( flags & SQLITE_SYNC_FULL ){ c287665ba8 2007-09-14 drh: sqlite3_fullsync_count++; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_sync_count++; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: if( FlushFileBuffers(pFile->h) ){ c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: return SQLITE_IOERR; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Determine the current size of a file in bytes c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ c287665ba8 2007-09-14 drh: winFile *pFile = (winFile*)id; c287665ba8 2007-09-14 drh: DWORD upperBits, lowerBits; c287665ba8 2007-09-14 drh: SimulateIOError(return SQLITE_IOERR_FSTAT); c287665ba8 2007-09-14 drh: lowerBits = GetFileSize(pFile->h, &upperBits); c287665ba8 2007-09-14 drh: *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef LOCKFILE_FAIL_IMMEDIATELY c287665ba8 2007-09-14 drh: # define LOCKFILE_FAIL_IMMEDIATELY 1 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Acquire a reader lock. c287665ba8 2007-09-14 drh: ** Different API routines are called depending on whether or not this c287665ba8 2007-09-14 drh: ** is Win95 or WinNT. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int getReadLock(winFile *pFile){ c287665ba8 2007-09-14 drh: int res; dbda8d6ce9 2007-07-21 drh: if( isNT() ){ c287665ba8 2007-09-14 drh: OVERLAPPED ovlp; c287665ba8 2007-09-14 drh: ovlp.Offset = SHARED_FIRST; c287665ba8 2007-09-14 drh: ovlp.OffsetHigh = 0; c287665ba8 2007-09-14 drh: ovlp.hEvent = 0; c287665ba8 2007-09-14 drh: res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY, c287665ba8 2007-09-14 drh: 0, SHARED_SIZE, 0, &ovlp); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: int lk; c287665ba8 2007-09-14 drh: sqlite3Randomness(sizeof(lk), &lk); c287665ba8 2007-09-14 drh: pFile->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); c287665ba8 2007-09-14 drh: res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return res; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Undo a readlock c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int unlockReadLock(winFile *pFile){ c287665ba8 2007-09-14 drh: int res; dbda8d6ce9 2007-07-21 drh: if( isNT() ){ dbda8d6ce9 2007-07-21 drh: res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return res; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Lock the file with the lock specified by parameter locktype - one dbda8d6ce9 2007-07-21 drh: ** of the following: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) SHARED_LOCK dbda8d6ce9 2007-07-21 drh: ** (2) RESERVED_LOCK dbda8d6ce9 2007-07-21 drh: ** (3) PENDING_LOCK dbda8d6ce9 2007-07-21 drh: ** (4) EXCLUSIVE_LOCK dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Sometimes when requesting one lock state, additional lock states dbda8d6ce9 2007-07-21 drh: ** are inserted in between. The locking might fail on one of the later dbda8d6ce9 2007-07-21 drh: ** transitions leaving the lock state different from what it started but dbda8d6ce9 2007-07-21 drh: ** still short of its goal. The following chart shows the allowed dbda8d6ce9 2007-07-21 drh: ** transitions and the inserted intermediate states: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** UNLOCKED -> SHARED dbda8d6ce9 2007-07-21 drh: ** SHARED -> RESERVED dbda8d6ce9 2007-07-21 drh: ** SHARED -> (PENDING) -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** RESERVED -> (PENDING) -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** PENDING -> EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine will only increase a lock. The winUnlock() routine dbda8d6ce9 2007-07-21 drh: ** erases all locks at once and returns us immediately to locking level 0. dbda8d6ce9 2007-07-21 drh: ** It is not possible to lower the locking level one step at a time. You dbda8d6ce9 2007-07-21 drh: ** must go straight to locking level 0. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int winLock(sqlite3_file *id, int locktype){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; /* Return code from subroutines */ dbda8d6ce9 2007-07-21 drh: int res = 1; /* Result of a windows lock call */ c287665ba8 2007-09-14 drh: int newLocktype; /* Set pFile->locktype to this value before exiting */ dbda8d6ce9 2007-07-21 drh: int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ dbda8d6ce9 2007-07-21 drh: winFile *pFile = (winFile*)id; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pFile!=0 ); dbda8d6ce9 2007-07-21 drh: OSTRACE5("LOCK %d %d was %d(%d)\n", dbda8d6ce9 2007-07-21 drh: pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there is already a lock of this type or more restrictive on the dbda8d6ce9 2007-07-21 drh: ** OsFile, do nothing. Don't use the end_lock: exit path, as dbda8d6ce9 2007-07-21 drh: ** sqlite3OsEnterMutex() hasn't been called yet. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>=locktype ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the locking sequence is correct dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( locktype!=PENDING_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or dbda8d6ce9 2007-07-21 drh: ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of dbda8d6ce9 2007-07-21 drh: ** the PENDING_LOCK byte is temporary. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: newLocktype = pFile->locktype; dbda8d6ce9 2007-07-21 drh: if( pFile->locktype==NO_LOCK dbda8d6ce9 2007-07-21 drh: || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int cnt = 3; dbda8d6ce9 2007-07-21 drh: while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){ dbda8d6ce9 2007-07-21 drh: /* Try 3 times to get the pending lock. The pending lock might be dbda8d6ce9 2007-07-21 drh: ** held by another reader process who will release it momentarily. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt); dbda8d6ce9 2007-07-21 drh: Sleep(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: gotPendingLock = res; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire a shared lock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK && res ){ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype==NO_LOCK ); dbda8d6ce9 2007-07-21 drh: res = getReadLock(pFile); dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: newLocktype = SHARED_LOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire a RESERVED lock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==RESERVED_LOCK && res ){ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: newLocktype = RESERVED_LOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire a PENDING lock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==EXCLUSIVE_LOCK && res ){ dbda8d6ce9 2007-07-21 drh: newLocktype = PENDING_LOCK; dbda8d6ce9 2007-07-21 drh: gotPendingLock = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Acquire an EXCLUSIVE lock dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( locktype==EXCLUSIVE_LOCK && res ){ dbda8d6ce9 2007-07-21 drh: assert( pFile->locktype>=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: res = unlockReadLock(pFile); dbda8d6ce9 2007-07-21 drh: OSTRACE2("unreadlock = %d\n", res); dbda8d6ce9 2007-07-21 drh: res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: newLocktype = EXCLUSIVE_LOCK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: OSTRACE2("error-code = %d\n", GetLastError()); dbda8d6ce9 2007-07-21 drh: getReadLock(pFile); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we are holding a PENDING lock that ought to be released, then dbda8d6ce9 2007-07-21 drh: ** release it now. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( gotPendingLock && locktype==SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update the state of the lock has held in the file descriptor then dbda8d6ce9 2007-07-21 drh: ** return the appropriate result code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h, dbda8d6ce9 2007-07-21 drh: locktype, newLocktype); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pFile->locktype = newLocktype; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine checks if there is a RESERVED lock held on the specified dbda8d6ce9 2007-07-21 drh: ** file by this or any other process. If such a lock is held, return dbda8d6ce9 2007-07-21 drh: ** non-zero, otherwise zero. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int winCheckReservedLock(sqlite3_file *id){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: winFile *pFile = (winFile*)id; dbda8d6ce9 2007-07-21 drh: assert( pFile!=0 ); dbda8d6ce9 2007-07-21 drh: if( pFile->locktype>=RESERVED_LOCK ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = !rc; dbda8d6ce9 2007-07-21 drh: OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Lower the locking level on file descriptor id to locktype. locktype dbda8d6ce9 2007-07-21 drh: ** must be either NO_LOCK or SHARED_LOCK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the locking level of the file descriptor is already at or below dbda8d6ce9 2007-07-21 drh: ** the requested locking level, this routine is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is not possible for this routine to fail if the second argument dbda8d6ce9 2007-07-21 drh: ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine dbda8d6ce9 2007-07-21 drh: ** might return SQLITE_IOERR; dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int winUnlock(sqlite3_file *id, int locktype){ dbda8d6ce9 2007-07-21 drh: int type; dbda8d6ce9 2007-07-21 drh: winFile *pFile = (winFile*)id; c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: assert( pFile!=0 ); dbda8d6ce9 2007-07-21 drh: assert( locktype<=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype, dbda8d6ce9 2007-07-21 drh: pFile->locktype, pFile->sharedLockByte); dbda8d6ce9 2007-07-21 drh: type = pFile->locktype; dbda8d6ce9 2007-07-21 drh: if( type>=EXCLUSIVE_LOCK ){ dbda8d6ce9 2007-07-21 drh: UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); dbda8d6ce9 2007-07-21 drh: if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ dbda8d6ce9 2007-07-21 drh: /* This should never happen. We should always be able to dbda8d6ce9 2007-07-21 drh: ** reacquire the read lock */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_UNLOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( type>=RESERVED_LOCK ){ dbda8d6ce9 2007-07-21 drh: UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( locktype==NO_LOCK && type>=SHARED_LOCK ){ dbda8d6ce9 2007-07-21 drh: unlockReadLock(pFile); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( type>=PENDING_LOCK ){ dbda8d6ce9 2007-07-21 drh: UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pFile->locktype = locktype; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Control and query of the open file handle. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winFileControl(sqlite3_file *id, int op, void *pArg){ c287665ba8 2007-09-14 drh: switch( op ){ c287665ba8 2007-09-14 drh: case SQLITE_FCNTL_LOCKSTATE: { c287665ba8 2007-09-14 drh: *(int*)pArg = ((winFile*)id)->locktype; c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the sector size in bytes of the underlying block device for dbda8d6ce9 2007-07-21 drh: ** the specified file. This is almost always 512 bytes, but may be dbda8d6ce9 2007-07-21 drh: ** larger for some devices. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLite code assumes this function cannot fail. It also assumes that dbda8d6ce9 2007-07-21 drh: ** if two files are created in the same file-system directory (i.e. dbda8d6ce9 2007-07-21 drh: ** a database and it's journal file) that the sector size will be the dbda8d6ce9 2007-07-21 drh: ** same for both. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int winSectorSize(sqlite3_file *id){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DEFAULT_SECTOR_SIZE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Return a vector of device characteristics. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winDeviceCharacteristics(sqlite3_file *id){ c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This vector defines all the methods that can operate on an c287665ba8 2007-09-14 drh: ** sqlite3_file for win32. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static const sqlite3_io_methods winIoMethod = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: winClose, dbda8d6ce9 2007-07-21 drh: winRead, dbda8d6ce9 2007-07-21 drh: winWrite, dbda8d6ce9 2007-07-21 drh: winTruncate, dbda8d6ce9 2007-07-21 drh: winSync, dbda8d6ce9 2007-07-21 drh: winFileSize, dbda8d6ce9 2007-07-21 drh: winLock, dbda8d6ce9 2007-07-21 drh: winUnlock, dbda8d6ce9 2007-07-21 drh: winCheckReservedLock, c287665ba8 2007-09-14 drh: winFileControl, dbda8d6ce9 2007-07-21 drh: winSectorSize, c287665ba8 2007-09-14 drh: winDeviceCharacteristics c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /*************************************************************************** c287665ba8 2007-09-14 drh: ** Here ends the I/O methods that form the sqlite3_io_methods object. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The next block of code implements the VFS methods. dbda8d6ce9 2007-07-21 drh: ****************************************************************************/ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Convert a UTF-8 filename into whatever form the underlying c287665ba8 2007-09-14 drh: ** operating system wants filenames in. Space to hold the result c287665ba8 2007-09-14 drh: ** is obtained from malloc and must be freed by the calling c287665ba8 2007-09-14 drh: ** function. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void *convertUtf8Filename(const char *zFilename){ c287665ba8 2007-09-14 drh: void *zConverted = 0; c287665ba8 2007-09-14 drh: if( isNT() ){ c287665ba8 2007-09-14 drh: zConverted = utf8ToUnicode(zFilename); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: zConverted = utf8ToMbcs(zFilename); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: /* caller will handle out of memory */ c287665ba8 2007-09-14 drh: return zConverted; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Open a file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winOpen( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, /* Not used */ c287665ba8 2007-09-14 drh: const char *zName, /* Name of the file (UTF-8) */ c287665ba8 2007-09-14 drh: sqlite3_file *id, /* Write the SQLite file handle here */ c287665ba8 2007-09-14 drh: int flags, /* Open mode flags */ c287665ba8 2007-09-14 drh: int *pOutFlags /* Status return flags */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: HANDLE h; c287665ba8 2007-09-14 drh: DWORD dwDesiredAccess; c287665ba8 2007-09-14 drh: DWORD dwShareMode; c287665ba8 2007-09-14 drh: DWORD dwCreationDisposition; c287665ba8 2007-09-14 drh: DWORD dwFlagsAndAttributes = 0; c287665ba8 2007-09-14 drh: winFile *pFile = (winFile*)id; c287665ba8 2007-09-14 drh: void *zConverted = convertUtf8Filename(zName); c287665ba8 2007-09-14 drh: if( zConverted==0 ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( flags & SQLITE_OPEN_READWRITE ){ c287665ba8 2007-09-14 drh: dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: dwDesiredAccess = GENERIC_READ; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( flags & SQLITE_OPEN_CREATE ){ c287665ba8 2007-09-14 drh: dwCreationDisposition = OPEN_ALWAYS; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: dwCreationDisposition = OPEN_EXISTING; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( flags & SQLITE_OPEN_MAIN_DB ){ c287665ba8 2007-09-14 drh: dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: dwShareMode = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( flags & (SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TEMP_JOURNAL c287665ba8 2007-09-14 drh: | SQLITE_OPEN_SUBJOURNAL) ){ c287665ba8 2007-09-14 drh: dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY c287665ba8 2007-09-14 drh: | FILE_ATTRIBUTE_HIDDEN c287665ba8 2007-09-14 drh: | FILE_FLAG_DELETE_ON_CLOSE; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( flags & (SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_TEMP_DB) ){ c287665ba8 2007-09-14 drh: dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( isNT() ){ c287665ba8 2007-09-14 drh: h = CreateFileW((WCHAR*)zConverted, c287665ba8 2007-09-14 drh: dwDesiredAccess, c287665ba8 2007-09-14 drh: dwShareMode, c287665ba8 2007-09-14 drh: NULL, c287665ba8 2007-09-14 drh: dwCreationDisposition, c287665ba8 2007-09-14 drh: dwFlagsAndAttributes, c287665ba8 2007-09-14 drh: NULL c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: #if OS_WINCE c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: h = CreateFileA((char*)zConverted, c287665ba8 2007-09-14 drh: dwDesiredAccess, c287665ba8 2007-09-14 drh: dwShareMode, c287665ba8 2007-09-14 drh: NULL, c287665ba8 2007-09-14 drh: dwCreationDisposition, c287665ba8 2007-09-14 drh: dwFlagsAndAttributes, c287665ba8 2007-09-14 drh: NULL c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( h==INVALID_HANDLE_VALUE ){ c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: if( flags & SQLITE_OPEN_READWRITE ){ c287665ba8 2007-09-14 drh: return winOpen(0, zName, id, c287665ba8 2007-09-14 drh: ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: return SQLITE_CANTOPEN; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pOutFlags ){ c287665ba8 2007-09-14 drh: if( flags & SQLITE_OPEN_READWRITE ){ c287665ba8 2007-09-14 drh: *pOutFlags = SQLITE_OPEN_READWRITE; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: *pOutFlags = SQLITE_OPEN_READONLY; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: memset(pFile, 0, sizeof(*pFile)); c287665ba8 2007-09-14 drh: pFile->pMethod = &winIoMethod; c287665ba8 2007-09-14 drh: pFile->h = h; c287665ba8 2007-09-14 drh: #if OS_WINCE c287665ba8 2007-09-14 drh: if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) == c287665ba8 2007-09-14 drh: (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB) c287665ba8 2007-09-14 drh: && !winceCreateLock(zFilename, &f) c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: CloseHandle(h); c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: return SQLITE_CANTOPEN; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( dwFlagsAndAttributes & FILE_FLAG_DELETEONCLOSE ){ c287665ba8 2007-09-14 drh: pFile->zDeleteOnClose = zConverted; c287665ba8 2007-09-14 drh: }else c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: { c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: OpenCounter(+1); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Delete the named file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Note that windows does not allow a file to be deleted if some other c287665ba8 2007-09-14 drh: ** process has it open. Sometimes a virus scanner or indexing program c287665ba8 2007-09-14 drh: ** will open a journal file shortly after it is created in order to do c287665ba8 2007-09-14 drh: ** whatever it is it does. While this other process is holding the c287665ba8 2007-09-14 drh: ** file open, we will be unable to delete it. To work around this c287665ba8 2007-09-14 drh: ** problem, we delay 100 milliseconds and try to delete again. Up c287665ba8 2007-09-14 drh: ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving c287665ba8 2007-09-14 drh: ** up and returning an error. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define MX_DELETION_ATTEMPTS 3 c287665ba8 2007-09-14 drh: static int winDelete( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, /* Not used on win32 */ c287665ba8 2007-09-14 drh: const char *zFilename, /* Name of file to delete */ c287665ba8 2007-09-14 drh: int syncDir /* Not used on win32 */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int cnt = 0; c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: void *zConverted = convertUtf8Filename(zFilename); c287665ba8 2007-09-14 drh: if( zConverted==0 ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SimulateIOError(return SQLITE_IOERR_DELETE); c287665ba8 2007-09-14 drh: if( isNT() ){ c287665ba8 2007-09-14 drh: do{ c287665ba8 2007-09-14 drh: rc = DeleteFileW(zConverted); c287665ba8 2007-09-14 drh: }while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff c287665ba8 2007-09-14 drh: && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: #if OS_WINCE c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: do{ c287665ba8 2007-09-14 drh: rc = DeleteFileA(zConverted); c287665ba8 2007-09-14 drh: }while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff c287665ba8 2007-09-14 drh: && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: OSTRACE2("DELETE \"%s\"\n", zFilename); c287665ba8 2007-09-14 drh: return rc!=0 ? SQLITE_OK : SQLITE_IOERR; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Check the existance and status of a file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winAccess( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, /* Not used on win32 */ c287665ba8 2007-09-14 drh: const char *zFilename, /* Name of file to check */ c287665ba8 2007-09-14 drh: int flags /* Type of test to make on this file */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: DWORD attr; c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: void *zConverted = convertUtf8Filename(zFilename); c287665ba8 2007-09-14 drh: if( zConverted==0 ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( isNT() ){ c287665ba8 2007-09-14 drh: attr = GetFileAttributesW((WCHAR*)zConverted); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: #if OS_WINCE c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: attr = GetFileAttributesA((char*)zConverted); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: switch( flags ){ c287665ba8 2007-09-14 drh: case SQLITE_ACCESS_READ: c287665ba8 2007-09-14 drh: case SQLITE_ACCESS_EXISTS: c287665ba8 2007-09-14 drh: rc = attr!=0xffffffff; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: case SQLITE_ACCESS_READWRITE: c287665ba8 2007-09-14 drh: rc = (attr & FILE_ATTRIBUTE_READONLY)==0; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: default: c287665ba8 2007-09-14 drh: assert(!"Invalid flags argument"); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Create a temporary file name in zBuf. zBuf must be big enough to c287665ba8 2007-09-14 drh: ** hold at pVfs->mxPathname characters. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winGetTempName(sqlite3_vfs *pVfs, char *zBuf){ c287665ba8 2007-09-14 drh: static char zChars[] = c287665ba8 2007-09-14 drh: "abcdefghijklmnopqrstuvwxyz" c287665ba8 2007-09-14 drh: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" c287665ba8 2007-09-14 drh: "0123456789"; c287665ba8 2007-09-14 drh: int i, j; c287665ba8 2007-09-14 drh: char zTempPath[MAX_PATH+1]; c287665ba8 2007-09-14 drh: if( sqlite3_temp_directory ){ c287665ba8 2007-09-14 drh: sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory); c287665ba8 2007-09-14 drh: }else if( isNT() ){ c287665ba8 2007-09-14 drh: char *zMulti; c287665ba8 2007-09-14 drh: WCHAR zWidePath[MAX_PATH]; c287665ba8 2007-09-14 drh: GetTempPathW(MAX_PATH-30, zWidePath); c287665ba8 2007-09-14 drh: zMulti = unicodeToUtf8(zWidePath); c287665ba8 2007-09-14 drh: if( zMulti ){ c287665ba8 2007-09-14 drh: sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti); c287665ba8 2007-09-14 drh: free(zMulti); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: char *zUtf8; c287665ba8 2007-09-14 drh: char zMbcsPath[MAX_PATH]; c287665ba8 2007-09-14 drh: GetTempPathA(MAX_PATH-30, zMbcsPath); c287665ba8 2007-09-14 drh: zUtf8 = mbcsToUtf8(zMbcsPath); c287665ba8 2007-09-14 drh: if( zUtf8 ){ c287665ba8 2007-09-14 drh: sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8); c287665ba8 2007-09-14 drh: free(zUtf8); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} c287665ba8 2007-09-14 drh: zTempPath[i] = 0; c287665ba8 2007-09-14 drh: sqlite3_snprintf(pVfs->mxPathname-30, zBuf, c287665ba8 2007-09-14 drh: "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); c287665ba8 2007-09-14 drh: j = strlen(zBuf); c287665ba8 2007-09-14 drh: sqlite3Randomness(20, &zBuf[j]); c287665ba8 2007-09-14 drh: for(i=0; i<20; i++, j++){ c287665ba8 2007-09-14 drh: zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: zBuf[j] = 0; c287665ba8 2007-09-14 drh: OSTRACE2("TEMP FILENAME: %s\n", zBuf); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Turn a relative pathname into a full pathname. Write the full c287665ba8 2007-09-14 drh: ** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname c287665ba8 2007-09-14 drh: ** bytes in size. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winFullPathname( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, c287665ba8 2007-09-14 drh: const char *zRelative, c287665ba8 2007-09-14 drh: char *zFull c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #if defined(__CYGWIN__) c287665ba8 2007-09-14 drh: cygwin_conv_to_full_win32_path(zRelative, zFull); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #if OS_WINCE c287665ba8 2007-09-14 drh: /* WinCE has no concept of a relative pathname, or so I am told. */ c287665ba8 2007-09-14 drh: sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #if !OS_WINCE && !defined(__CYGWIN__) c287665ba8 2007-09-14 drh: int nByte; c287665ba8 2007-09-14 drh: void *zConverted; c287665ba8 2007-09-14 drh: char *zOut; c287665ba8 2007-09-14 drh: zConverted = convertUtf8Filename(zRelative); c287665ba8 2007-09-14 drh: if( isNT() ){ c287665ba8 2007-09-14 drh: WCHAR *zTemp; c287665ba8 2007-09-14 drh: nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3; c287665ba8 2007-09-14 drh: zTemp = malloc( nByte*sizeof(zTemp[0]) ); c287665ba8 2007-09-14 drh: if( zTemp==0 ){ c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0); c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: zOut = unicodeToUtf8(zTemp); c287665ba8 2007-09-14 drh: free(zTemp); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: char *zTemp; c287665ba8 2007-09-14 drh: nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3; c287665ba8 2007-09-14 drh: zTemp = malloc( nByte*sizeof(zTemp[0]) ); c287665ba8 2007-09-14 drh: if( zTemp==0 ){ c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: GetFullPathNameA((char*)zConverted, nByte, zTemp, 0); c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: zOut = mbcsToUtf8(zTemp); c287665ba8 2007-09-14 drh: free(zTemp); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( zOut ){ c287665ba8 2007-09-14 drh: sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut); c287665ba8 2007-09-14 drh: free(zOut); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_LOAD_EXTENSION c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Interfaces for opening a shared library, finding entry points c287665ba8 2007-09-14 drh: ** within the shared library, and closing the shared library. c287665ba8 2007-09-14 drh: */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Interfaces for opening a shared library, finding entry points dbda8d6ce9 2007-07-21 drh: ** within the shared library, and closing the shared library. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ dbda8d6ce9 2007-07-21 drh: HANDLE h; dbda8d6ce9 2007-07-21 drh: void *zConverted = convertUtf8Filename(zFilename); dbda8d6ce9 2007-07-21 drh: if( zConverted==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( isNT() ){ dbda8d6ce9 2007-07-21 drh: h = LoadLibraryW((WCHAR*)zConverted); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: #if OS_WINCE dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: h = LoadLibraryA((char*)zConverted); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: free(zConverted); c287665ba8 2007-09-14 drh: return (void*)h; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ c287665ba8 2007-09-14 drh: FormatMessage( c287665ba8 2007-09-14 drh: FORMAT_MESSAGE_FROM_SYSTEM, c287665ba8 2007-09-14 drh: NULL, c287665ba8 2007-09-14 drh: GetLastError(), c287665ba8 2007-09-14 drh: 0, c287665ba8 2007-09-14 drh: zBufOut, c287665ba8 2007-09-14 drh: nBuf-1, c287665ba8 2007-09-14 drh: 0 c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: void *winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ dbda8d6ce9 2007-07-21 drh: #if OS_WINCE dbda8d6ce9 2007-07-21 drh: /* The GetProcAddressA() routine is only available on wince. */ dbda8d6ce9 2007-07-21 drh: return GetProcAddressA((HANDLE)pHandle, zSymbol); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: /* All other windows platforms expect GetProcAddress() to take dbda8d6ce9 2007-07-21 drh: ** an Ansi string regardless of the _UNICODE setting */ dbda8d6ce9 2007-07-21 drh: return GetProcAddress((HANDLE)pHandle, zSymbol); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ c287665ba8 2007-09-14 drh: FreeLibrary((HANDLE)pHandle); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ c287665ba8 2007-09-14 drh: #define winDlOpen 0 c287665ba8 2007-09-14 drh: #define winDlError 0 c287665ba8 2007-09-14 drh: #define winDlSym 0 c287665ba8 2007-09-14 drh: #define winDlClose 0 c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Write up to nBuf bytes of randomness into zBuf. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ c287665ba8 2007-09-14 drh: int n = 0; c287665ba8 2007-09-14 drh: if( sizeof(SYSTEMTIME)<=nBuf-n ){ c287665ba8 2007-09-14 drh: SYSTEMTIME x; c287665ba8 2007-09-14 drh: GetSystemTime(&x); c287665ba8 2007-09-14 drh: memcpy(&zBuf[n], &x, sizeof(x)); c287665ba8 2007-09-14 drh: n += sizeof(x); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( sizeof(DWORD)<=nBuf-n ){ c287665ba8 2007-09-14 drh: DWORD pid = GetCurrentProcessId(); c287665ba8 2007-09-14 drh: memcpy(&zBuf[n], &pid, sizeof(pid)); c287665ba8 2007-09-14 drh: n += sizeof(pid); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( sizeof(DWORD)<=nBuf-n ){ c287665ba8 2007-09-14 drh: DWORD cnt = GetTickCount(); c287665ba8 2007-09-14 drh: memcpy(&zBuf[n], &cnt, sizeof(cnt)); c287665ba8 2007-09-14 drh: n += sizeof(cnt); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( sizeof(LARGE_INTEGER)<=nBuf-n ){ c287665ba8 2007-09-14 drh: LARGE_INTEGER i; c287665ba8 2007-09-14 drh: QueryPerformanceCounter(&i); c287665ba8 2007-09-14 drh: memcpy(&zBuf[n], &i, sizeof(i)); c287665ba8 2007-09-14 drh: n += sizeof(i); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return n; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Sleep for a little while. Return the amount of time slept. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int winSleep(sqlite3_vfs *pVfs, int microsec){ c287665ba8 2007-09-14 drh: Sleep((microsec+999)/1000); c287665ba8 2007-09-14 drh: return ((microsec+999)/1000)*1000; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following variable, if set to a non-zero value, becomes the result dbda8d6ce9 2007-07-21 drh: ** returned from sqlite3OsCurrentTime(). This is used for testing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_current_time = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the current time (in Universal Coordinated Time). Write the dbda8d6ce9 2007-07-21 drh: ** current time and date as a Julian Day number into *prNow and dbda8d6ce9 2007-07-21 drh: ** return 0. Return 1 if the time and date cannot be found. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ dbda8d6ce9 2007-07-21 drh: FILETIME ft; dbda8d6ce9 2007-07-21 drh: /* FILETIME structure is a 64-bit value representing the number of dbda8d6ce9 2007-07-21 drh: 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: double now; dbda8d6ce9 2007-07-21 drh: #if OS_WINCE dbda8d6ce9 2007-07-21 drh: SYSTEMTIME time; dbda8d6ce9 2007-07-21 drh: GetSystemTime(&time); dbda8d6ce9 2007-07-21 drh: SystemTimeToFileTime(&time,&ft); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: GetSystemTimeAsFileTime( &ft ); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: now = ((double)ft.dwHighDateTime) * 4294967296.0; dbda8d6ce9 2007-07-21 drh: *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: if( sqlite3_current_time ){ dbda8d6ce9 2007-07-21 drh: *prNow = sqlite3_current_time/86400.0 + 2440587.5; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return a pointer to the sqlite3DefaultVfs structure. We use c287665ba8 2007-09-14 drh: ** a function rather than give the structure global scope because c287665ba8 2007-09-14 drh: ** some compilers (MSVC) do not allow forward declarations of c287665ba8 2007-09-14 drh: ** initialized structures. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3_vfs *sqlite3OsDefaultVfs(void){ c287665ba8 2007-09-14 drh: static sqlite3_vfs winVfs = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: sizeof(winFile), /* szOsFile */ c287665ba8 2007-09-14 drh: MAX_PATH, /* mxPathname */ c287665ba8 2007-09-14 drh: 0, /* pNext */ c287665ba8 2007-09-14 drh: "win32", /* zName */ c287665ba8 2007-09-14 drh: 0, /* pAppData */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: winOpen, /* xOpen */ c287665ba8 2007-09-14 drh: winDelete, /* xDelete */ c287665ba8 2007-09-14 drh: winAccess, /* xAccess */ c287665ba8 2007-09-14 drh: winGetTempName, /* xGetTempName */ c287665ba8 2007-09-14 drh: winFullPathname, /* xFullPathname */ c287665ba8 2007-09-14 drh: winDlOpen, /* xDlOpen */ c287665ba8 2007-09-14 drh: winDlError, /* xDlError */ c287665ba8 2007-09-14 drh: winDlSym, /* xDlSym */ c287665ba8 2007-09-14 drh: winDlClose, /* xDlClose */ c287665ba8 2007-09-14 drh: winRandomness, /* xRandomness */ c287665ba8 2007-09-14 drh: winSleep, /* xSleep */ c287665ba8 2007-09-14 drh: winCurrentTime /* xCurrentTime */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: return &winVfs; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: #endif /* OS_WIN */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of os_win.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file pager.c *******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This is the implementation of the page cache subsystem or "pager". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pager is used to access a database disk file. It implements dbda8d6ce9 2007-07-21 drh: ** atomic commit and rollback through the use of a journal file that dbda8d6ce9 2007-07-21 drh: ** is separate from the database file. The pager also implements file dbda8d6ce9 2007-07-21 drh: ** locking to prevent two processes from writing the same database dbda8d6ce9 2007-07-21 drh: ** file simultaneously, or one process from reading the database while dbda8d6ce9 2007-07-21 drh: ** another is writing. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: pager.c,v 1.388 2007/09/10 06:12:04 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_DISKIO dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Macros for troubleshooting. Normally turned off dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if 0 dbda8d6ce9 2007-07-21 drh: #define sqlite3DebugPrintf printf dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE1(X) sqlite3DebugPrintf(X) dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE2(X,Y) sqlite3DebugPrintf(X,Y) dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z) dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W) dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE5(X,Y,Z,W,V) sqlite3DebugPrintf(X,Y,Z,W,V) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE1(X) dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE2(X,Y) dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE3(X,Y,Z) dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE4(X,Y,Z,W) dbda8d6ce9 2007-07-21 drh: #define PAGERTRACE5(X,Y,Z,W,V) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following two macros are used within the PAGERTRACEX() macros above dbda8d6ce9 2007-07-21 drh: ** to print out file-descriptors. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PAGERID() takes a pointer to a Pager struct as it's argument. The c287665ba8 2007-09-14 drh: ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file dbda8d6ce9 2007-07-21 drh: ** struct as it's argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define PAGERID(p) ((int)(p->fd)) dbda8d6ce9 2007-07-21 drh: #define FILEHANDLEID(fd) ((int)fd) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The page cache as a whole is always in one of the following dbda8d6ce9 2007-07-21 drh: ** states: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PAGER_UNLOCK The page cache is not currently reading or dbda8d6ce9 2007-07-21 drh: ** writing the database file. There is no dbda8d6ce9 2007-07-21 drh: ** data held in memory. This is the initial dbda8d6ce9 2007-07-21 drh: ** state. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PAGER_SHARED The page cache is reading the database. dbda8d6ce9 2007-07-21 drh: ** Writing is not permitted. There can be dbda8d6ce9 2007-07-21 drh: ** multiple readers accessing the same database dbda8d6ce9 2007-07-21 drh: ** file at the same time. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PAGER_RESERVED This process has reserved the database for writing dbda8d6ce9 2007-07-21 drh: ** but has not yet made any changes. Only one process dbda8d6ce9 2007-07-21 drh: ** at a time can reserve the database. The original dbda8d6ce9 2007-07-21 drh: ** database file has not been modified so other dbda8d6ce9 2007-07-21 drh: ** processes may still be reading the on-disk dbda8d6ce9 2007-07-21 drh: ** database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PAGER_EXCLUSIVE The page cache is writing the database. dbda8d6ce9 2007-07-21 drh: ** Access is exclusive. No other processes or dbda8d6ce9 2007-07-21 drh: ** threads can be reading or writing while one dbda8d6ce9 2007-07-21 drh: ** process is writing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PAGER_SYNCED The pager moves to this state from PAGER_EXCLUSIVE dbda8d6ce9 2007-07-21 drh: ** after all dirty pages have been written to the dbda8d6ce9 2007-07-21 drh: ** database file and the file has been synced to dbda8d6ce9 2007-07-21 drh: ** disk. All that remains to do is to remove or dbda8d6ce9 2007-07-21 drh: ** truncate the journal file and the transaction dbda8d6ce9 2007-07-21 drh: ** will be committed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The page cache comes up in PAGER_UNLOCK. The first time a dbda8d6ce9 2007-07-21 drh: ** sqlite3PagerGet() occurs, the state transitions to PAGER_SHARED. dbda8d6ce9 2007-07-21 drh: ** After all pages have been released using sqlite_page_unref(), dbda8d6ce9 2007-07-21 drh: ** the state transitions back to PAGER_UNLOCK. The first time dbda8d6ce9 2007-07-21 drh: ** that sqlite3PagerWrite() is called, the state transitions to dbda8d6ce9 2007-07-21 drh: ** PAGER_RESERVED. (Note that sqlite3PagerWrite() can only be dbda8d6ce9 2007-07-21 drh: ** called on an outstanding page which means that the pager must dbda8d6ce9 2007-07-21 drh: ** be in PAGER_SHARED before it transitions to PAGER_RESERVED.) dbda8d6ce9 2007-07-21 drh: ** PAGER_RESERVED means that there is an open rollback journal. dbda8d6ce9 2007-07-21 drh: ** The transition to PAGER_EXCLUSIVE occurs before any changes dbda8d6ce9 2007-07-21 drh: ** are made to the database file, though writes to the rollback dbda8d6ce9 2007-07-21 drh: ** journal occurs with just PAGER_RESERVED. After an sqlite3PagerRollback() dbda8d6ce9 2007-07-21 drh: ** or sqlite3PagerCommitPhaseTwo(), the state can go back to PAGER_SHARED, dbda8d6ce9 2007-07-21 drh: ** or it can stay at PAGER_EXCLUSIVE if we are in exclusive access mode. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define PAGER_UNLOCK 0 dbda8d6ce9 2007-07-21 drh: #define PAGER_SHARED 1 /* same as SHARED_LOCK */ dbda8d6ce9 2007-07-21 drh: #define PAGER_RESERVED 2 /* same as RESERVED_LOCK */ dbda8d6ce9 2007-07-21 drh: #define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */ dbda8d6ce9 2007-07-21 drh: #define PAGER_SYNCED 5 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the SQLITE_BUSY_RESERVED_LOCK macro is set to true at compile-time, dbda8d6ce9 2007-07-21 drh: ** then failed attempts to get a reserved lock will invoke the busy callback. dbda8d6ce9 2007-07-21 drh: ** This is off by default. To see why, consider the following scenario: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Suppose thread A already has a shared lock and wants a reserved lock. dbda8d6ce9 2007-07-21 drh: ** Thread B already has a reserved lock and wants an exclusive lock. If dbda8d6ce9 2007-07-21 drh: ** both threads are using their busy callbacks, it might be a long time dbda8d6ce9 2007-07-21 drh: ** be for one of the threads give up and allows the other to proceed. dbda8d6ce9 2007-07-21 drh: ** But if the thread trying to get the reserved lock gives up quickly dbda8d6ce9 2007-07-21 drh: ** (if it never invokes its busy callback) then the contention will be dbda8d6ce9 2007-07-21 drh: ** resolved quickly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_BUSY_RESERVED_LOCK dbda8d6ce9 2007-07-21 drh: # define SQLITE_BUSY_RESERVED_LOCK 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This macro rounds values up so that if the value is an address it dbda8d6ce9 2007-07-21 drh: ** is guaranteed to be an address that is aligned to an 8-byte boundary. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define FORCE_ALIGNMENT(X) (((X)+7)&~7) c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: typedef struct PgHdr PgHdr; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Each pager stores all currently unreferenced pages in a list sorted c287665ba8 2007-09-14 drh: ** in least-recently-used (LRU) order (i.e. the first item on the list has c287665ba8 2007-09-14 drh: ** not been referenced in a long time, the last item has been recently c287665ba8 2007-09-14 drh: ** used). An instance of this structure is included as part of each c287665ba8 2007-09-14 drh: ** pager structure for this purpose (variable Pager.lru). c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Additionally, if memory-management is enabled, all unreferenced pages c287665ba8 2007-09-14 drh: ** are stored in a global LRU list (global variable sqlite3LruPageList). c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** In both cases, the PagerLruList.pFirstSynced variable points to c287665ba8 2007-09-14 drh: ** the first page in the corresponding list that does not require an c287665ba8 2007-09-14 drh: ** fsync() operation before it's memory can be reclaimed. If no such c287665ba8 2007-09-14 drh: ** page exists, PagerLruList.pFirstSynced is set to NULL. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: typedef struct PagerLruList PagerLruList; c287665ba8 2007-09-14 drh: struct PagerLruList { c287665ba8 2007-09-14 drh: PgHdr *pFirst; /* First page in LRU list */ c287665ba8 2007-09-14 drh: PgHdr *pLast; /* Last page in LRU list (the most recently used) */ c287665ba8 2007-09-14 drh: PgHdr *pFirstSynced; /* First page in list with PgHdr.needSync==0 */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The following structure contains the next and previous pointers used c287665ba8 2007-09-14 drh: ** to link a PgHdr structure into a PagerLruList linked list. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: typedef struct PagerLruLink PagerLruLink; c287665ba8 2007-09-14 drh: struct PagerLruLink { c287665ba8 2007-09-14 drh: PgHdr *pNext; c287665ba8 2007-09-14 drh: PgHdr *pPrev; c287665ba8 2007-09-14 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each in-memory image of a page begins with the following header. dbda8d6ce9 2007-07-21 drh: ** This header is only visible to this pager module. The client dbda8d6ce9 2007-07-21 drh: ** code that calls pager sees only the data that follows the header. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Client code should call sqlite3PagerWrite() on a page prior to making dbda8d6ce9 2007-07-21 drh: ** any modifications to that page. The first time sqlite3PagerWrite() dbda8d6ce9 2007-07-21 drh: ** is called, the original page contents are written into the rollback dbda8d6ce9 2007-07-21 drh: ** journal and PgHdr.inJournal and PgHdr.needSync are set. Later, once dbda8d6ce9 2007-07-21 drh: ** the journal page has made it onto the disk surface, PgHdr.needSync dbda8d6ce9 2007-07-21 drh: ** is cleared. The modified page cannot be written back into the original dbda8d6ce9 2007-07-21 drh: ** database file until the journal pages has been synced to disk and the dbda8d6ce9 2007-07-21 drh: ** PgHdr.needSync has been cleared. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The PgHdr.dirty flag is set when sqlite3PagerWrite() is called and dbda8d6ce9 2007-07-21 drh: ** is cleared again when the page content is written back to the original dbda8d6ce9 2007-07-21 drh: ** database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Details of important structure elements: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** needSync dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If this is true, this means that it is not safe to write the page dbda8d6ce9 2007-07-21 drh: ** content to the database because the original content needed dbda8d6ce9 2007-07-21 drh: ** for rollback has not by synced to the main rollback journal. dbda8d6ce9 2007-07-21 drh: ** The original content may have been written to the rollback journal dbda8d6ce9 2007-07-21 drh: ** but it has not yet been synced. So we cannot write to the database dbda8d6ce9 2007-07-21 drh: ** file because power failure might cause the page in the journal file dbda8d6ce9 2007-07-21 drh: ** to never reach the disk. It is as if the write to the journal file dbda8d6ce9 2007-07-21 drh: ** does not occur until the journal file is synced. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This flag is false if the page content exactly matches what dbda8d6ce9 2007-07-21 drh: ** currently exists in the database file. The needSync flag is also dbda8d6ce9 2007-07-21 drh: ** false if the original content has been written to the main rollback dbda8d6ce9 2007-07-21 drh: ** journal and synced. If the page represents a new page that has dbda8d6ce9 2007-07-21 drh: ** been added onto the end of the database during the current dbda8d6ce9 2007-07-21 drh: ** transaction, the needSync flag is true until the original database dbda8d6ce9 2007-07-21 drh: ** size in the journal header has been synced to disk. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** inJournal dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is true if the original page has been written into the main dbda8d6ce9 2007-07-21 drh: ** rollback journal. This is always false for new pages added to dbda8d6ce9 2007-07-21 drh: ** the end of the database file during the current transaction. dbda8d6ce9 2007-07-21 drh: ** And this flag says nothing about whether or not the journal dbda8d6ce9 2007-07-21 drh: ** has been synced to disk. For pages that are in the original dbda8d6ce9 2007-07-21 drh: ** database file, the following expression should always be true: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** inJournal = (pPager->aInJournal[(pgno-1)/8] & (1<<((pgno-1)%8))!=0 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pPager->aInJournal[] array is only valid for the original dbda8d6ce9 2007-07-21 drh: ** pages of the database, not new pages that are added to the end dbda8d6ce9 2007-07-21 drh: ** of the database, so obviously the above expression cannot be dbda8d6ce9 2007-07-21 drh: ** valid for new pages. For new pages inJournal is always 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** dirty dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When true, this means that the content of the page has been dbda8d6ce9 2007-07-21 drh: ** modified and needs to be written back to the database file. dbda8d6ce9 2007-07-21 drh: ** If false, it means that either the content of the page is dbda8d6ce9 2007-07-21 drh: ** unchanged or else the content is unimportant and we do not dbda8d6ce9 2007-07-21 drh: ** care whether or not it is preserved. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** alwaysRollback dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This means that the sqlite3PagerDontRollback() API should be dbda8d6ce9 2007-07-21 drh: ** ignored for this page. The DontRollback() API attempts to say dbda8d6ce9 2007-07-21 drh: ** that the content of the page on disk is unimportant (it is an dbda8d6ce9 2007-07-21 drh: ** unused page on the freelist) so that it is unnecessary to dbda8d6ce9 2007-07-21 drh: ** rollback changes to this page because the content of the page dbda8d6ce9 2007-07-21 drh: ** can change without changing the meaning of the database. This dbda8d6ce9 2007-07-21 drh: ** flag overrides any DontRollback() attempt. This flag is set dbda8d6ce9 2007-07-21 drh: ** when a page that originally contained valid data is added to dbda8d6ce9 2007-07-21 drh: ** the freelist. Later in the same transaction, this page might dbda8d6ce9 2007-07-21 drh: ** be pulled from the freelist and reused for something different dbda8d6ce9 2007-07-21 drh: ** and at that point the DontRollback() API will be called because dbda8d6ce9 2007-07-21 drh: ** pages taken from the freelist do not need to be protected by dbda8d6ce9 2007-07-21 drh: ** the rollback journal. But this flag says that the page was dbda8d6ce9 2007-07-21 drh: ** not originally part of the freelist so that it still needs to dbda8d6ce9 2007-07-21 drh: ** be rolled back in spite of any subsequent DontRollback() calls. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** needRead dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This flag means (when true) that the content of the page has dbda8d6ce9 2007-07-21 drh: ** not yet been loaded from disk. The in-memory content is just dbda8d6ce9 2007-07-21 drh: ** garbage. (Actually, we zero the content, but you should not dbda8d6ce9 2007-07-21 drh: ** make any assumptions about the content nevertheless.) If the dbda8d6ce9 2007-07-21 drh: ** content is needed in the future, it should be read from the dbda8d6ce9 2007-07-21 drh: ** original database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct PgHdr { dbda8d6ce9 2007-07-21 drh: Pager *pPager; /* The pager to which this page belongs */ dbda8d6ce9 2007-07-21 drh: Pgno pgno; /* The page number for this page */ dbda8d6ce9 2007-07-21 drh: PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */ c287665ba8 2007-09-14 drh: PagerLruLink free; /* Next and previous free pages */ dbda8d6ce9 2007-07-21 drh: PgHdr *pNextAll; /* A list of all pages */ dbda8d6ce9 2007-07-21 drh: u8 inJournal; /* TRUE if has been written to journal */ dbda8d6ce9 2007-07-21 drh: u8 dirty; /* TRUE if we need to write back changes */ dbda8d6ce9 2007-07-21 drh: u8 needSync; /* Sync journal before writing this page */ dbda8d6ce9 2007-07-21 drh: u8 alwaysRollback; /* Disable DontRollback() for this page */ dbda8d6ce9 2007-07-21 drh: u8 needRead; /* Read content if PagerWrite() is called */ dbda8d6ce9 2007-07-21 drh: short int nRef; /* Number of users of this page */ dbda8d6ce9 2007-07-21 drh: PgHdr *pDirty, *pPrevDirty; /* Dirty pages */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: PagerLruLink gfree; /* Global list of nRef==0 pages */ c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_CHECK_PAGES dbda8d6ce9 2007-07-21 drh: u32 pageHash; dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: void *pData; /* Page data */ c287665ba8 2007-09-14 drh: /* Pager.nExtra bytes of local data appended to this header */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** For an in-memory only database, some extra information is recorded about dbda8d6ce9 2007-07-21 drh: ** each page so that changes can be rolled back. (Journal files are not dbda8d6ce9 2007-07-21 drh: ** used for in-memory databases.) The following information is added to dbda8d6ce9 2007-07-21 drh: ** the end of every EXTRA block for in-memory databases. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This information could have been added directly to the PgHdr structure. dbda8d6ce9 2007-07-21 drh: ** But then it would take up an extra 8 bytes of storage on every PgHdr dbda8d6ce9 2007-07-21 drh: ** even for disk-based databases. Splitting it out saves 8 bytes. This dbda8d6ce9 2007-07-21 drh: ** is only a savings of 0.8% but those percentages add up. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct PgHistory PgHistory; dbda8d6ce9 2007-07-21 drh: struct PgHistory { dbda8d6ce9 2007-07-21 drh: u8 *pOrig; /* Original page text. Restore to this on a full rollback */ dbda8d6ce9 2007-07-21 drh: u8 *pStmt; /* Text as it was at the beginning of the current statement */ dbda8d6ce9 2007-07-21 drh: PgHdr *pNextStmt, *pPrevStmt; /* List of pages in the statement journal */ dbda8d6ce9 2007-07-21 drh: u8 inStmt; /* TRUE if in the statement subjournal */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A macro used for invoking the codec if there is one dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_HAS_CODEC dbda8d6ce9 2007-07-21 drh: # define CODEC1(P,D,N,X) if( P->xCodec!=0 ){ P->xCodec(P->pCodecArg,D,N,X); } dbda8d6ce9 2007-07-21 drh: # define CODEC2(P,D,N,X) ((char*)(P->xCodec!=0?P->xCodec(P->pCodecArg,D,N,X):D)) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define CODEC1(P,D,N,X) /* NO-OP */ dbda8d6ce9 2007-07-21 drh: # define CODEC2(P,D,N,X) ((char*)D) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert a pointer to a PgHdr into a pointer to its data dbda8d6ce9 2007-07-21 drh: ** and back again. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: #define PGHDR_TO_DATA(P) ((P)->pData) c287665ba8 2007-09-14 drh: #define PGHDR_TO_EXTRA(G,P) ((void*)&((G)[1])) dbda8d6ce9 2007-07-21 drh: #define PGHDR_TO_HIST(P,PGR) \ c287665ba8 2007-09-14 drh: ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->nExtra]) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A open page cache is an instance of the following structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, or dbda8d6ce9 2007-07-21 drh: ** or SQLITE_FULL. Once one of the first three errors occurs, it persists dbda8d6ce9 2007-07-21 drh: ** and is returned as the result of every major pager API call. The dbda8d6ce9 2007-07-21 drh: ** SQLITE_FULL return code is slightly different. It persists only until the dbda8d6ce9 2007-07-21 drh: ** next successful rollback is performed on the pager cache. Also, dbda8d6ce9 2007-07-21 drh: ** SQLITE_FULL does not affect the sqlite3PagerGet() and sqlite3PagerLookup() dbda8d6ce9 2007-07-21 drh: ** APIs, they may still be used successfully. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Pager { c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs; /* OS functions to use for IO */ dbda8d6ce9 2007-07-21 drh: u8 journalOpen; /* True if journal file descriptors is valid */ dbda8d6ce9 2007-07-21 drh: u8 journalStarted; /* True if header of journal is synced */ dbda8d6ce9 2007-07-21 drh: u8 useJournal; /* Use a rollback journal on this file */ dbda8d6ce9 2007-07-21 drh: u8 noReadlock; /* Do not bother to obtain readlocks */ dbda8d6ce9 2007-07-21 drh: u8 stmtOpen; /* True if the statement subjournal is open */ dbda8d6ce9 2007-07-21 drh: u8 stmtInUse; /* True we are in a statement subtransaction */ dbda8d6ce9 2007-07-21 drh: u8 stmtAutoopen; /* Open stmt journal when main journal is opened*/ dbda8d6ce9 2007-07-21 drh: u8 noSync; /* Do not sync the journal if true */ dbda8d6ce9 2007-07-21 drh: u8 fullSync; /* Do extra syncs of the journal for robustness */ c287665ba8 2007-09-14 drh: u8 sync_flags; /* One of SYNC_NORMAL or SYNC_FULL */ dbda8d6ce9 2007-07-21 drh: u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ dbda8d6ce9 2007-07-21 drh: u8 tempFile; /* zFilename is a temporary file */ dbda8d6ce9 2007-07-21 drh: u8 readOnly; /* True for a read-only database */ dbda8d6ce9 2007-07-21 drh: u8 needSync; /* True if an fsync() is needed on the journal */ dbda8d6ce9 2007-07-21 drh: u8 dirtyCache; /* True if cached pages have changed */ dbda8d6ce9 2007-07-21 drh: u8 alwaysRollback; /* Disable DontRollback() for all pages */ dbda8d6ce9 2007-07-21 drh: u8 memDb; /* True to inhibit all file I/O */ dbda8d6ce9 2007-07-21 drh: u8 setMaster; /* True if a m-j name has been written to jrnl */ dbda8d6ce9 2007-07-21 drh: u8 doNotSync; /* Boolean. While true, do not spill the cache */ dbda8d6ce9 2007-07-21 drh: u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */ dbda8d6ce9 2007-07-21 drh: u8 changeCountDone; /* Set after incrementing the change-counter */ c287665ba8 2007-09-14 drh: u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ dbda8d6ce9 2007-07-21 drh: int errCode; /* One of several kinds of errors */ dbda8d6ce9 2007-07-21 drh: int dbSize; /* Number of pages in the file */ dbda8d6ce9 2007-07-21 drh: int origDbSize; /* dbSize before the current change */ dbda8d6ce9 2007-07-21 drh: int stmtSize; /* Size of database (in pages) at stmt_begin() */ dbda8d6ce9 2007-07-21 drh: int nRec; /* Number of pages written to the journal */ dbda8d6ce9 2007-07-21 drh: u32 cksumInit; /* Quasi-random value added to every checksum */ dbda8d6ce9 2007-07-21 drh: int stmtNRec; /* Number of records in stmt subjournal */ dbda8d6ce9 2007-07-21 drh: int nExtra; /* Add this many bytes to each in-memory page */ dbda8d6ce9 2007-07-21 drh: int pageSize; /* Number of bytes in a page */ dbda8d6ce9 2007-07-21 drh: int nPage; /* Total number of in-memory pages */ dbda8d6ce9 2007-07-21 drh: int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ dbda8d6ce9 2007-07-21 drh: int mxPage; /* Maximum number of pages to hold in cache */ dbda8d6ce9 2007-07-21 drh: Pgno mxPgno; /* Maximum allowed size of the database */ dbda8d6ce9 2007-07-21 drh: u8 *aInJournal; /* One bit for each page in the database file */ dbda8d6ce9 2007-07-21 drh: u8 *aInStmt; /* One bit for each page in the database */ dbda8d6ce9 2007-07-21 drh: char *zFilename; /* Name of the database file */ dbda8d6ce9 2007-07-21 drh: char *zJournal; /* Name of the journal file */ dbda8d6ce9 2007-07-21 drh: char *zDirectory; /* Directory hold database and journal files */ c287665ba8 2007-09-14 drh: char *zStmtJrnl; /* Name of the statement journal file */ c287665ba8 2007-09-14 drh: sqlite3_file *fd, *jfd; /* File descriptors for database and journal */ c287665ba8 2007-09-14 drh: sqlite3_file *stfd; /* File descriptor for the statement subjournal*/ dbda8d6ce9 2007-07-21 drh: BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ c287665ba8 2007-09-14 drh: PagerLruList lru; /* LRU list of free pages */ dbda8d6ce9 2007-07-21 drh: PgHdr *pAll; /* List of all pages */ dbda8d6ce9 2007-07-21 drh: PgHdr *pStmt; /* List of pages in the statement subjournal */ dbda8d6ce9 2007-07-21 drh: PgHdr *pDirty; /* List of all dirty pages */ dbda8d6ce9 2007-07-21 drh: i64 journalOff; /* Current byte offset in the journal file */ dbda8d6ce9 2007-07-21 drh: i64 journalHdr; /* Byte offset to previous journal header */ dbda8d6ce9 2007-07-21 drh: i64 stmtHdrOff; /* First journal header written this statement */ dbda8d6ce9 2007-07-21 drh: i64 stmtCksum; /* cksumInit when statement was started */ dbda8d6ce9 2007-07-21 drh: i64 stmtJSize; /* Size of journal at stmt_begin() */ dbda8d6ce9 2007-07-21 drh: int sectorSize; /* Assumed sector size during rollback */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: int nHit, nMiss; /* Cache hits and missing */ dbda8d6ce9 2007-07-21 drh: int nRead, nWrite; /* Database pages read/written */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: void (*xDestructor)(DbPage*,int); /* Call this routine when freeing pages */ dbda8d6ce9 2007-07-21 drh: void (*xReiniter)(DbPage*,int); /* Call this routine when reloading pages */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_HAS_CODEC dbda8d6ce9 2007-07-21 drh: void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ dbda8d6ce9 2007-07-21 drh: void *pCodecArg; /* First argument to xCodec() */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: int nHash; /* Size of the pager hash table */ dbda8d6ce9 2007-07-21 drh: PgHdr **aHash; /* Hash table to map page number to PgHdr */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: Pager *pNext; /* Doubly linked list of pagers on which */ c287665ba8 2007-09-14 drh: Pager *pPrev; /* sqlite3_release_memory() will work */ c287665ba8 2007-09-14 drh: int iInUseMM; /* Non-zero if unavailable to MM */ c287665ba8 2007-09-14 drh: int iInUseDB; /* Non-zero if in sqlite3_release_memory() */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ dbda8d6ce9 2007-07-21 drh: char dbFileVers[16]; /* Changes whenever database file changes */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following global variables hold counters used for dbda8d6ce9 2007-07-21 drh: ** testing purposes only. These variables do not exist in dbda8d6ce9 2007-07-21 drh: ** a non-testing build. These variables are not thread-safe. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_pager_pgfree_count = 0; /* Number of cache pages freed */ dbda8d6ce9 2007-07-21 drh: # define PAGER_INCR(v) v++ dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define PAGER_INCR(v) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The following variable points to the head of a double-linked list c287665ba8 2007-09-14 drh: ** of all pagers that are eligible for page stealing by the c287665ba8 2007-09-14 drh: ** sqlite3_release_memory() interface. Access to this list is c287665ba8 2007-09-14 drh: ** protected by the SQLITE_MUTEX_STATIC_MEM2 mutex. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: static Pager *sqlite3PagerList = 0; c287665ba8 2007-09-14 drh: static PagerLruList sqlite3LruPageList = {0, 0, 0}; c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Journal files begin with the following magic string. The data dbda8d6ce9 2007-07-21 drh: ** was obtained from /dev/random. It is used only as a sanity check. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Since version 2.8.0, the journal format contains additional sanity dbda8d6ce9 2007-07-21 drh: ** checking information. If the power fails while the journal is begin dbda8d6ce9 2007-07-21 drh: ** written, semi-random garbage data might appear in the journal dbda8d6ce9 2007-07-21 drh: ** file after power is restored. If an attempt is then made dbda8d6ce9 2007-07-21 drh: ** to roll the journal back, the database could be corrupted. The additional dbda8d6ce9 2007-07-21 drh: ** sanity checking data is an attempt to discover the garbage in the dbda8d6ce9 2007-07-21 drh: ** journal and ignore it. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sanity checking information for the new journal format consists dbda8d6ce9 2007-07-21 drh: ** of a 32-bit checksum on each page of data. The checksum covers both dbda8d6ce9 2007-07-21 drh: ** the page number and the pPager->pageSize bytes of data for the page. dbda8d6ce9 2007-07-21 drh: ** This cksum is initialized to a 32-bit random value that appears in the dbda8d6ce9 2007-07-21 drh: ** journal file right after the header. The random initializer is important, dbda8d6ce9 2007-07-21 drh: ** because garbage data that appears at the end of a journal is likely dbda8d6ce9 2007-07-21 drh: ** data that was once in other files that have now been deleted. If the dbda8d6ce9 2007-07-21 drh: ** garbage data came from an obsolete journal file, the checksums might dbda8d6ce9 2007-07-21 drh: ** be correct. But by initializing the checksum to random value which dbda8d6ce9 2007-07-21 drh: ** is different for every journal, we minimize that risk. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const unsigned char aJournalMagic[] = { dbda8d6ce9 2007-07-21 drh: 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The size of the header and of each page in the journal is determined dbda8d6ce9 2007-07-21 drh: ** by the following macros. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The journal header size for this pager. In the future, this could be dbda8d6ce9 2007-07-21 drh: ** set to some value read from the disk controller. The important dbda8d6ce9 2007-07-21 drh: ** characteristic is that it is the same size as a disk sector. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The macro MEMDB is true if we are dealing with an in-memory database. dbda8d6ce9 2007-07-21 drh: ** We do this as a macro so that if the SQLITE_OMIT_MEMORYDB macro is set, dbda8d6ce9 2007-07-21 drh: ** the value of MEMDB will be a constant and the compiler will optimize dbda8d6ce9 2007-07-21 drh: ** out code that would never execute. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_MEMORYDB dbda8d6ce9 2007-07-21 drh: # define MEMDB 0 dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define MEMDB pPager->memDb dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is dbda8d6ce9 2007-07-21 drh: ** reserved for working around a windows/posix incompatibility). It is dbda8d6ce9 2007-07-21 drh: ** used in the journal to signify that the remainder of the journal file dbda8d6ce9 2007-07-21 drh: ** is devoted to storing a master journal name - there are no more pages to dbda8d6ce9 2007-07-21 drh: ** roll back. See comments for function writeMasterJournal() for details. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* #define PAGER_MJ_PGNO(x) (PENDING_BYTE/((x)->pageSize)) */ dbda8d6ce9 2007-07-21 drh: #define PAGER_MJ_PGNO(x) ((PENDING_BYTE/((x)->pageSize))+1) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The maximum legal page number is (2^31 - 1). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define PAGER_MAX_PGNO 2147483647 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** The pagerEnter() and pagerLeave() routines acquire and release c287665ba8 2007-09-14 drh: ** a mutex on each pager. The mutex is recursive. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This is a special-purpose mutex. It only provides mutual exclusion c287665ba8 2007-09-14 drh: ** between the Btree and the Memory Management sqlite3_release_memory() c287665ba8 2007-09-14 drh: ** function. It does not prevent, for example, two Btrees from accessing c287665ba8 2007-09-14 drh: ** the same pager at the same time. Other general-purpose mutexes in c287665ba8 2007-09-14 drh: ** the btree layer handle that chore. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: static void pagerEnter(Pager *p){ c287665ba8 2007-09-14 drh: p->iInUseDB++; c287665ba8 2007-09-14 drh: if( p->iInUseMM && p->iInUseDB==1 ){ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex; c287665ba8 2007-09-14 drh: mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); c287665ba8 2007-09-14 drh: p->iInUseDB = 0; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: p->iInUseDB = 1; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert( p->iInUseMM==0 ); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: static void pagerLeave(Pager *p){ c287665ba8 2007-09-14 drh: p->iInUseDB--; c287665ba8 2007-09-14 drh: assert( p->iInUseDB>=0 ); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: # define pagerEnter(X) c287665ba8 2007-09-14 drh: # define pagerLeave(X) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* dbda8d6ce9 2007-07-21 drh: ** Enable reference count tracking (for debugging) here: dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: int pager3_refinfo_enable = 0; dbda8d6ce9 2007-07-21 drh: static void pager_refinfo(PgHdr *p){ dbda8d6ce9 2007-07-21 drh: static int cnt = 0; dbda8d6ce9 2007-07-21 drh: if( !pager3_refinfo_enable ) return; dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf( dbda8d6ce9 2007-07-21 drh: "REFCNT: %4d addr=%p nRef=%-3d total=%d\n", dbda8d6ce9 2007-07-21 drh: p->pgno, PGHDR_TO_DATA(p), p->nRef, p->pPager->nRef dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: cnt++; /* Something to set a breakpoint on */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: # define REFINFO(X) pager_refinfo(X) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define REFINFO(X) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Add page pPg to the end of the linked list managed by structure c287665ba8 2007-09-14 drh: ** pList (pPg becomes the last entry in the list - the most recently c287665ba8 2007-09-14 drh: ** used). Argument pLink should point to either pPg->free or pPg->gfree, c287665ba8 2007-09-14 drh: ** depending on whether pPg is being added to the pager-specific or c287665ba8 2007-09-14 drh: ** global LRU list. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void listAdd(PagerLruList *pList, PagerLruLink *pLink, PgHdr *pPg){ c287665ba8 2007-09-14 drh: pLink->pNext = 0; c287665ba8 2007-09-14 drh: pLink->pPrev = pList->pLast; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: assert(pLink==&pPg->free || pLink==&pPg->gfree); c287665ba8 2007-09-14 drh: assert(pLink==&pPg->gfree || pList!=&sqlite3LruPageList); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( pList->pLast ){ c287665ba8 2007-09-14 drh: int iOff = (char *)pLink - (char *)pPg; c287665ba8 2007-09-14 drh: PagerLruLink *pLastLink = (PagerLruLink *)(&((u8 *)pList->pLast)[iOff]); c287665ba8 2007-09-14 drh: pLastLink->pNext = pPg; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: assert(!pList->pFirst); c287665ba8 2007-09-14 drh: pList->pFirst = pPg; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pList->pLast = pPg; c287665ba8 2007-09-14 drh: if( !pList->pFirstSynced && pPg->needSync==0 ){ c287665ba8 2007-09-14 drh: pList->pFirstSynced = pPg; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Remove pPg from the list managed by the structure pointed to by pList. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Argument pLink should point to either pPg->free or pPg->gfree, depending c287665ba8 2007-09-14 drh: ** on whether pPg is being added to the pager-specific or global LRU list. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void listRemove(PagerLruList *pList, PagerLruLink *pLink, PgHdr *pPg){ c287665ba8 2007-09-14 drh: int iOff = (char *)pLink - (char *)pPg; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: assert(pLink==&pPg->free || pLink==&pPg->gfree); c287665ba8 2007-09-14 drh: assert(pLink==&pPg->gfree || pList!=&sqlite3LruPageList); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( pPg==pList->pFirst ){ c287665ba8 2007-09-14 drh: pList->pFirst = pLink->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pPg==pList->pLast ){ c287665ba8 2007-09-14 drh: pList->pLast = pLink->pPrev; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pLink->pPrev ){ c287665ba8 2007-09-14 drh: PagerLruLink *pPrevLink = (PagerLruLink *)(&((u8 *)pLink->pPrev)[iOff]); c287665ba8 2007-09-14 drh: pPrevLink->pNext = pLink->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pLink->pNext ){ c287665ba8 2007-09-14 drh: PagerLruLink *pNextLink = (PagerLruLink *)(&((u8 *)pLink->pNext)[iOff]); c287665ba8 2007-09-14 drh: pNextLink->pPrev = pLink->pPrev; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pPg==pList->pFirstSynced ){ c287665ba8 2007-09-14 drh: PgHdr *p = pLink->pNext; c287665ba8 2007-09-14 drh: while( p && p->needSync ){ c287665ba8 2007-09-14 drh: PagerLruLink *pL = (PagerLruLink *)(&((u8 *)p)[iOff]); c287665ba8 2007-09-14 drh: p = pL->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pList->pFirstSynced = p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pLink->pNext = pLink->pPrev = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Add page pPg to the list of free pages for the pager. If c287665ba8 2007-09-14 drh: ** memory-management is enabled, also add the page to the global c287665ba8 2007-09-14 drh: ** list of free pages. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void lruListAdd(PgHdr *pPg){ c287665ba8 2007-09-14 drh: listAdd(&pPg->pPager->lru, &pPg->free, pPg); c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: if( !pPg->pPager->memDb ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); c287665ba8 2007-09-14 drh: listAdd(&sqlite3LruPageList, &pPg->gfree, pPg); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Remove page pPg from the list of free pages for the associated pager. c287665ba8 2007-09-14 drh: ** If memory-management is enabled, also remove pPg from the global list c287665ba8 2007-09-14 drh: ** of free pages. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void lruListRemove(PgHdr *pPg){ c287665ba8 2007-09-14 drh: listRemove(&pPg->pPager->lru, &pPg->free, pPg); c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: if( !pPg->pPager->memDb ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); c287665ba8 2007-09-14 drh: listRemove(&sqlite3LruPageList, &pPg->gfree, pPg); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This function is called just after the needSync flag has been cleared c287665ba8 2007-09-14 drh: ** from all pages managed by pPager (usually because the journal file c287665ba8 2007-09-14 drh: ** has just been synced). It updates the pPager->lru.pFirstSynced variable c287665ba8 2007-09-14 drh: ** and, if memory-management is enabled, the sqlite3LruPageList.pFirstSynced c287665ba8 2007-09-14 drh: ** variable also. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void lruListSetFirstSynced(Pager *pPager){ c287665ba8 2007-09-14 drh: pPager->lru.pFirstSynced = pPager->lru.pFirst; c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: if( !pPager->memDb ){ c287665ba8 2007-09-14 drh: PgHdr *p; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); c287665ba8 2007-09-14 drh: for(p=sqlite3LruPageList.pFirst; p && p->needSync; p=p->gfree.pNext); c287665ba8 2007-09-14 drh: assert(p==pPager->lru.pFirstSynced || p==sqlite3LruPageList.pFirstSynced); c287665ba8 2007-09-14 drh: sqlite3LruPageList.pFirstSynced = p; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return true if page *pPg has already been written to the statement dbda8d6ce9 2007-07-21 drh: ** journal (or statement snapshot has been created, if *pPg is part dbda8d6ce9 2007-07-21 drh: ** of an in-memory database). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pageInStatement(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: return PGHDR_TO_HIST(pPg, pPager)->inStmt; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Pgno pgno = pPg->pgno; dbda8d6ce9 2007-07-21 drh: u8 *a = pPager->aInStmt; dbda8d6ce9 2007-07-21 drh: return (a && (int)pgno<=pPager->stmtSize && (a[pgno/8] & (1<<(pgno&7)))); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the size of the pager hash table to N. N must be a power dbda8d6ce9 2007-07-21 drh: ** of two. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void pager_resize_hash_table(Pager *pPager, int N){ dbda8d6ce9 2007-07-21 drh: PgHdr **aHash, *pPg; dbda8d6ce9 2007-07-21 drh: assert( N>0 && (N&(N-1))==0 ); c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: sqlite3MallocBenignFailure((int)pPager->aHash); c287665ba8 2007-09-14 drh: aHash = sqlite3MallocZero( sizeof(aHash[0])*N ); c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( aHash==0 ){ dbda8d6ce9 2007-07-21 drh: /* Failure to rehash is not an error. It is only a performance hit. */ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pPager->aHash); dbda8d6ce9 2007-07-21 drh: pPager->nHash = N; dbda8d6ce9 2007-07-21 drh: pPager->aHash = aHash; dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ dbda8d6ce9 2007-07-21 drh: int h; dbda8d6ce9 2007-07-21 drh: if( pPg->pgno==0 ){ dbda8d6ce9 2007-07-21 drh: assert( pPg->pNextHash==0 && pPg->pPrevHash==0 ); dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: h = pPg->pgno & (N-1); dbda8d6ce9 2007-07-21 drh: pPg->pNextHash = aHash[h]; dbda8d6ce9 2007-07-21 drh: if( aHash[h] ){ dbda8d6ce9 2007-07-21 drh: aHash[h]->pPrevHash = pPg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: aHash[h] = pPg; dbda8d6ce9 2007-07-21 drh: pPg->pPrevHash = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read a 32-bit integer from the given file descriptor. Store the integer dbda8d6ce9 2007-07-21 drh: ** that is read in *pRes. Return SQLITE_OK if everything worked, or an dbda8d6ce9 2007-07-21 drh: ** error code is something goes wrong. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All values are stored on disk as big-endian. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){ dbda8d6ce9 2007-07-21 drh: unsigned char ac[4]; c287665ba8 2007-09-14 drh: int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: *pRes = sqlite3Get4byte(ac); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write a 32-bit integer into a string buffer in big-endian byte order. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define put32bits(A,B) sqlite3Put4byte((u8*)A,B) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK dbda8d6ce9 2007-07-21 drh: ** on success or an error code is something goes wrong. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int write32bits(sqlite3_file *fd, i64 offset, u32 val){ dbda8d6ce9 2007-07-21 drh: char ac[4]; dbda8d6ce9 2007-07-21 drh: put32bits(ac, val); c287665ba8 2007-09-14 drh: return sqlite3OsWrite(fd, ac, 4, offset); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** If file pFd is open, call sqlite3OsUnlock() on it. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int osUnlock(sqlite3_file *pFd, int eLock){ c287665ba8 2007-09-14 drh: if( !pFd->pMethods ){ c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return sqlite3OsUnlock(pFd, eLock); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This function determines whether or not the atomic-write optimization c287665ba8 2007-09-14 drh: ** can be used with this pager. The optimization can be used if: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (a) the value returned by OsDeviceCharacteristics() indicates that c287665ba8 2007-09-14 drh: ** a database page may be written atomically, and c287665ba8 2007-09-14 drh: ** (b) the value returned by OsSectorSize() is less than or equal c287665ba8 2007-09-14 drh: ** to the page size. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If the optimization cannot be used, 0 is returned. If it can be used, c287665ba8 2007-09-14 drh: ** then the value returned is the size of the journal file when it c287665ba8 2007-09-14 drh: ** contains rollback data for exactly one page. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_ATOMIC_WRITE c287665ba8 2007-09-14 drh: static int jrnlBufferSize(Pager *pPager){ c287665ba8 2007-09-14 drh: int dc; /* Device characteristics */ c287665ba8 2007-09-14 drh: int nSector; /* Sector size */ c287665ba8 2007-09-14 drh: int nPage; /* Page size */ c287665ba8 2007-09-14 drh: sqlite3_file *fd = pPager->fd; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( fd->pMethods ){ c287665ba8 2007-09-14 drh: dc = sqlite3OsDeviceCharacteristics(fd); c287665ba8 2007-09-14 drh: nSector = sqlite3OsSectorSize(fd); c287665ba8 2007-09-14 drh: nPage = pPager->pageSize; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); c287665ba8 2007-09-14 drh: assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( !fd->pMethods || (dc&(SQLITE_IOCAP_ATOMIC|(nPage>>8))&&nSector<=nPage) ){ c287665ba8 2007-09-14 drh: return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function should be called when an error occurs within the pager dbda8d6ce9 2007-07-21 drh: ** code. The first argument is a pointer to the pager structure, the dbda8d6ce9 2007-07-21 drh: ** second the error-code about to be returned by a pager API function. dbda8d6ce9 2007-07-21 drh: ** The value returned is a copy of the second argument to this function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT, or SQLITE_FULL dbda8d6ce9 2007-07-21 drh: ** the error becomes persistent. All subsequent API calls on this Pager dbda8d6ce9 2007-07-21 drh: ** will immediately return the same error code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_error(Pager *pPager, int rc){ dbda8d6ce9 2007-07-21 drh: int rc2 = rc & 0xff; c287665ba8 2007-09-14 drh: assert( c287665ba8 2007-09-14 drh: pPager->errCode==SQLITE_FULL || c287665ba8 2007-09-14 drh: pPager->errCode==SQLITE_OK || c287665ba8 2007-09-14 drh: (pPager->errCode & 0xff)==SQLITE_IOERR c287665ba8 2007-09-14 drh: ); dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: rc2==SQLITE_FULL || dbda8d6ce9 2007-07-21 drh: rc2==SQLITE_IOERR || dbda8d6ce9 2007-07-21 drh: rc2==SQLITE_CORRUPT dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: pPager->errCode = rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If SQLITE_CHECK_PAGES is defined then we do some sanity checking dbda8d6ce9 2007-07-21 drh: ** on the cache using a hash function. This is used for testing dbda8d6ce9 2007-07-21 drh: ** and debugging only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_CHECK_PAGES dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a 32-bit hash of the page data for pPage. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static u32 pager_datahash(int nByte, unsigned char *pData){ dbda8d6ce9 2007-07-21 drh: u32 hash = 0; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nByte; i++){ dbda8d6ce9 2007-07-21 drh: hash = (hash*1039) + pData[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return hash; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static u32 pager_pagehash(PgHdr *pPage){ dbda8d6ce9 2007-07-21 drh: return pager_datahash(pPage->pPager->pageSize, dbda8d6ce9 2007-07-21 drh: (unsigned char *)PGHDR_TO_DATA(pPage)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES dbda8d6ce9 2007-07-21 drh: ** is defined, and NDEBUG is not defined, an assert() statement checks dbda8d6ce9 2007-07-21 drh: ** that the page is either dirty or still matches the calculated page-hash. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define CHECK_PAGE(x) checkPage(x) dbda8d6ce9 2007-07-21 drh: static void checkPage(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: assert( !pPg->pageHash || pPager->errCode || MEMDB || pPg->dirty || dbda8d6ce9 2007-07-21 drh: pPg->pageHash==pager_pagehash(pPg) ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define pager_datahash(X,Y) 0 dbda8d6ce9 2007-07-21 drh: #define pager_pagehash(X) 0 dbda8d6ce9 2007-07-21 drh: #define CHECK_PAGE(x) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** When this is called the journal file for pager pPager must be open. dbda8d6ce9 2007-07-21 drh: ** The master journal file name is read from the end of the file and c287665ba8 2007-09-14 drh: ** written into memory supplied by the caller. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** zMaster must point to a buffer of at least nMaster bytes allocated by c287665ba8 2007-09-14 drh: ** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is c287665ba8 2007-09-14 drh: ** enough space to write the master journal name). If the master journal c287665ba8 2007-09-14 drh: ** name in the journal is longer than nMaster bytes (including a c287665ba8 2007-09-14 drh: ** nul-terminator), then this is handled as if no master journal name c287665ba8 2007-09-14 drh: ** were present in the journal. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If no master journal file name is present zMaster[0] is set to 0 and dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK returned. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, int nMaster){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: u32 len; dbda8d6ce9 2007-07-21 drh: i64 szJ; dbda8d6ce9 2007-07-21 drh: u32 cksum; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: unsigned char aMagic[8]; /* A buffer to hold the magic header */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: zMaster[0] = '\0'; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsFileSize(pJrnl, &szJ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK || szJ<16 ) return rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: rc = read32bits(pJrnl, szJ-16, &len); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( len>=nMaster ){ c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = read32bits(pJrnl, szJ-12, &cksum); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: zMaster[len] = '\0'; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* See if the checksum matches the master journal name */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<len; i++){ c287665ba8 2007-09-14 drh: cksum -= zMaster[i]; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( cksum ){ dbda8d6ce9 2007-07-21 drh: /* If the checksum doesn't add up, then one or more of the disk sectors dbda8d6ce9 2007-07-21 drh: ** containing the master journal filename is corrupted. This means dbda8d6ce9 2007-07-21 drh: ** definitely roll back, so just return SQLITE_OK and report a (nul) dbda8d6ce9 2007-07-21 drh: ** master-journal filename. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: zMaster[0] = '\0'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Seek the journal file descriptor to the next sector boundary where a dbda8d6ce9 2007-07-21 drh: ** journal header may be read or written. Pager.journalOff is updated with dbda8d6ce9 2007-07-21 drh: ** the new seek offset. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** i.e for a sector size of 512: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Input Offset Output Offset dbda8d6ce9 2007-07-21 drh: ** --------------------------------------- dbda8d6ce9 2007-07-21 drh: ** 0 0 dbda8d6ce9 2007-07-21 drh: ** 512 512 dbda8d6ce9 2007-07-21 drh: ** 100 512 dbda8d6ce9 2007-07-21 drh: ** 2000 2048 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static void seekJournalHdr(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: i64 offset = 0; dbda8d6ce9 2007-07-21 drh: i64 c = pPager->journalOff; dbda8d6ce9 2007-07-21 drh: if( c ){ dbda8d6ce9 2007-07-21 drh: offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( offset%JOURNAL_HDR_SZ(pPager)==0 ); dbda8d6ce9 2007-07-21 drh: assert( offset>=c ); dbda8d6ce9 2007-07-21 drh: assert( (offset-c)<JOURNAL_HDR_SZ(pPager) ); dbda8d6ce9 2007-07-21 drh: pPager->journalOff = offset; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The journal file must be open when this routine is called. A journal dbda8d6ce9 2007-07-21 drh: ** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the dbda8d6ce9 2007-07-21 drh: ** current location. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The format for the journal header is as follows: dbda8d6ce9 2007-07-21 drh: ** - 8 bytes: Magic identifying journal format. dbda8d6ce9 2007-07-21 drh: ** - 4 bytes: Number of records in journal, or -1 no-sync mode is on. dbda8d6ce9 2007-07-21 drh: ** - 4 bytes: Random number used for page hash. dbda8d6ce9 2007-07-21 drh: ** - 4 bytes: Initial database page count. dbda8d6ce9 2007-07-21 drh: ** - 4 bytes: Sector size used by the process that wrote this journal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Followed by (JOURNAL_HDR_SZ - 24) bytes of unused space. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int writeJournalHdr(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: char zHeader[sizeof(aJournalMagic)+16]; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->stmtHdrOff==0 ){ dbda8d6ce9 2007-07-21 drh: pPager->stmtHdrOff = pPager->journalOff; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: seekJournalHdr(pPager); dbda8d6ce9 2007-07-21 drh: pPager->journalHdr = pPager->journalOff; c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Write the nRec Field - the number of page records that follow this c287665ba8 2007-09-14 drh: ** journal header. Normally, zero is written to this value at this time. c287665ba8 2007-09-14 drh: ** After the records are added to the journal (and the journal synced, c287665ba8 2007-09-14 drh: ** if in full-sync mode), the zero is overwritten with the true number c287665ba8 2007-09-14 drh: ** of records (see syncJournal()). c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When c287665ba8 2007-09-14 drh: ** reading the journal this value tells SQLite to assume that the c287665ba8 2007-09-14 drh: ** rest of the journal file contains valid page records. This assumption c287665ba8 2007-09-14 drh: ** is dangerous, as if a failure occured whilst writing to the journal c287665ba8 2007-09-14 drh: ** file it may contain some garbage data. There are two scenarios c287665ba8 2007-09-14 drh: ** where this risk can be ignored: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** * When the pager is in no-sync mode. Corruption can follow a c287665ba8 2007-09-14 drh: ** power failure in this case anyway. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees c287665ba8 2007-09-14 drh: ** that garbage data is never appended to the journal file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert(pPager->fd->pMethods||pPager->noSync); c287665ba8 2007-09-14 drh: if( (pPager->noSync) c287665ba8 2007-09-14 drh: || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: put32bits(&zHeader[sizeof(aJournalMagic)], 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* The random check-hash initialiser */ dbda8d6ce9 2007-07-21 drh: sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); dbda8d6ce9 2007-07-21 drh: put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); dbda8d6ce9 2007-07-21 drh: /* The initial database size */ dbda8d6ce9 2007-07-21 drh: put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbSize); dbda8d6ce9 2007-07-21 drh: /* The assumed sector size for this process */ dbda8d6ce9 2007-07-21 drh: put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize); dbda8d6ce9 2007-07-21 drh: IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, sizeof(zHeader))) c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader),pPager->journalOff); c287665ba8 2007-09-14 drh: pPager->journalOff += JOURNAL_HDR_SZ(pPager); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The journal header has been written successfully. Seek the journal dbda8d6ce9 2007-07-21 drh: ** file descriptor to the end of the journal header sector. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: IOTRACE(("JTAIL %p %lld\n", pPager, pPager->journalOff-1)) c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->jfd, "\000", 1, pPager->journalOff-1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The journal file must be open when this is called. A journal header file dbda8d6ce9 2007-07-21 drh: ** (JOURNAL_HDR_SZ bytes) is read from the current location in the journal dbda8d6ce9 2007-07-21 drh: ** file. See comments above function writeJournalHdr() for a description of dbda8d6ce9 2007-07-21 drh: ** the journal header format. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the header is read successfully, *nRec is set to the number of dbda8d6ce9 2007-07-21 drh: ** page records following this header and *dbSize is set to the size of the dbda8d6ce9 2007-07-21 drh: ** database before the transaction began, in pages. Also, pPager->cksumInit dbda8d6ce9 2007-07-21 drh: ** is set to the value read from the journal header. SQLITE_OK is returned dbda8d6ce9 2007-07-21 drh: ** in this case. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the journal header file appears to be corrupted, SQLITE_DONE is dbda8d6ce9 2007-07-21 drh: ** returned and *nRec and *dbSize are not set. If JOURNAL_HDR_SZ bytes dbda8d6ce9 2007-07-21 drh: ** cannot be read from the journal file an error code is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int readJournalHdr( dbda8d6ce9 2007-07-21 drh: Pager *pPager, dbda8d6ce9 2007-07-21 drh: i64 journalSize, dbda8d6ce9 2007-07-21 drh: u32 *pNRec, dbda8d6ce9 2007-07-21 drh: u32 *pDbSize dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: unsigned char aMagic[8]; /* A buffer to hold the magic header */ c287665ba8 2007-09-14 drh: i64 jrnlOff; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: seekJournalHdr(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: jrnlOff = pPager->journalOff; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), jrnlOff); c287665ba8 2007-09-14 drh: if( rc ) return rc; c287665ba8 2007-09-14 drh: jrnlOff += sizeof(aMagic); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: rc = read32bits(pPager->jfd, jrnlOff, pNRec); c287665ba8 2007-09-14 drh: if( rc ) return rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = read32bits(pPager->jfd, jrnlOff+4, &pPager->cksumInit); c287665ba8 2007-09-14 drh: if( rc ) return rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = read32bits(pPager->jfd, jrnlOff+8, pDbSize); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update the assumed sector-size to match the value used by dbda8d6ce9 2007-07-21 drh: ** the process that created this journal. If this journal was dbda8d6ce9 2007-07-21 drh: ** created by a process other than this one, then this routine dbda8d6ce9 2007-07-21 drh: ** is being called from within pager_playback(). The local value dbda8d6ce9 2007-07-21 drh: ** of Pager.sectorSize is restored at the end of that routine. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: rc = read32bits(pPager->jfd, jrnlOff+12, (u32 *)&pPager->sectorSize); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPager->journalOff += JOURNAL_HDR_SZ(pPager); c287665ba8 2007-09-14 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write the supplied master journal name into the journal file for pager dbda8d6ce9 2007-07-21 drh: ** pPager at the current location. The master journal name must be the last dbda8d6ce9 2007-07-21 drh: ** thing written to a journal file. If the pager is in full-sync mode, the dbda8d6ce9 2007-07-21 drh: ** journal file descriptor is advanced to the next sector boundary before dbda8d6ce9 2007-07-21 drh: ** anything is written. The format is: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** + 4 bytes: PAGER_MJ_PGNO. dbda8d6ce9 2007-07-21 drh: ** + N bytes: length of master journal name. dbda8d6ce9 2007-07-21 drh: ** + 4 bytes: N dbda8d6ce9 2007-07-21 drh: ** + 4 bytes: Master journal name checksum. dbda8d6ce9 2007-07-21 drh: ** + 8 bytes: aJournalMagic[]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The master journal page checksum is the sum of the bytes in the master dbda8d6ce9 2007-07-21 drh: ** journal name. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If zMaster is a NULL pointer (occurs for a single database transaction), dbda8d6ce9 2007-07-21 drh: ** this call is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int writeMasterJournal(Pager *pPager, const char *zMaster){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: int i; c287665ba8 2007-09-14 drh: i64 jrnlOff; dbda8d6ce9 2007-07-21 drh: u32 cksum = 0; dbda8d6ce9 2007-07-21 drh: char zBuf[sizeof(aJournalMagic)+2*4]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !zMaster || pPager->setMaster) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: pPager->setMaster = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: len = strlen(zMaster); dbda8d6ce9 2007-07-21 drh: for(i=0; i<len; i++){ dbda8d6ce9 2007-07-21 drh: cksum += zMaster[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If in full-sync mode, advance to the next disk sector before writing dbda8d6ce9 2007-07-21 drh: ** the master journal name. This is in case the previous page written to dbda8d6ce9 2007-07-21 drh: ** the journal has already been synced. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPager->fullSync ){ c287665ba8 2007-09-14 drh: seekJournalHdr(pPager); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: jrnlOff = pPager->journalOff; dbda8d6ce9 2007-07-21 drh: pPager->journalOff += (len+20); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: rc = write32bits(pPager->jfd, jrnlOff, PAGER_MJ_PGNO(pPager)); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; c287665ba8 2007-09-14 drh: jrnlOff += 4; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->jfd, zMaster, len, jrnlOff); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; c287665ba8 2007-09-14 drh: jrnlOff += len; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: put32bits(zBuf, len); dbda8d6ce9 2007-07-21 drh: put32bits(&zBuf[4], cksum); dbda8d6ce9 2007-07-21 drh: memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic)); c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic), jrnlOff); dbda8d6ce9 2007-07-21 drh: pPager->needSync = !pPager->noSync; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add or remove a page from the list of all pages that are in the dbda8d6ce9 2007-07-21 drh: ** statement journal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The Pager keeps a separate list of pages that are currently in dbda8d6ce9 2007-07-21 drh: ** the statement journal. This helps the sqlite3PagerStmtCommit() dbda8d6ce9 2007-07-21 drh: ** routine run MUCH faster for the common case where there are many dbda8d6ce9 2007-07-21 drh: ** pages in memory but only a few are in the statement journal. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void page_add_to_stmt_list(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); dbda8d6ce9 2007-07-21 drh: assert( MEMDB ); dbda8d6ce9 2007-07-21 drh: if( !pHist->inStmt ){ dbda8d6ce9 2007-07-21 drh: assert( pHist->pPrevStmt==0 && pHist->pNextStmt==0 ); dbda8d6ce9 2007-07-21 drh: if( pPager->pStmt ){ dbda8d6ce9 2007-07-21 drh: PGHDR_TO_HIST(pPager->pStmt, pPager)->pPrevStmt = pPg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pHist->pNextStmt = pPager->pStmt; dbda8d6ce9 2007-07-21 drh: pPager->pStmt = pPg; dbda8d6ce9 2007-07-21 drh: pHist->inStmt = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find a page in the hash table given its page number. Return dbda8d6ce9 2007-07-21 drh: ** a pointer to the page or NULL if not found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ dbda8d6ce9 2007-07-21 drh: PgHdr *p; dbda8d6ce9 2007-07-21 drh: if( pPager->aHash==0 ) return 0; dbda8d6ce9 2007-07-21 drh: p = pPager->aHash[pgno & (pPager->nHash-1)]; dbda8d6ce9 2007-07-21 drh: while( p && p->pgno!=pgno ){ dbda8d6ce9 2007-07-21 drh: p = p->pNextHash; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Unlock the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void pager_unlock(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: if( !pPager->exclusiveMode ){ dbda8d6ce9 2007-07-21 drh: if( !MEMDB ){ c287665ba8 2007-09-14 drh: osUnlock(pPager->fd, NO_LOCK); dbda8d6ce9 2007-07-21 drh: pPager->dbSize = -1; dbda8d6ce9 2007-07-21 drh: IOTRACE(("UNLOCK %p\n", pPager)) dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_UNLOCK; dbda8d6ce9 2007-07-21 drh: pPager->changeCountDone = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Execute a rollback if a transaction is active and unlock the dbda8d6ce9 2007-07-21 drh: ** database file. This is a no-op if the pager has already entered dbda8d6ce9 2007-07-21 drh: ** the error-state. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void pagerUnlockAndRollback(Pager *p){ dbda8d6ce9 2007-07-21 drh: if( p->errCode ) return; dbda8d6ce9 2007-07-21 drh: assert( p->state>=PAGER_RESERVED || p->journalOpen==0 ); dbda8d6ce9 2007-07-21 drh: if( p->state>=PAGER_RESERVED ){ dbda8d6ce9 2007-07-21 drh: sqlite3PagerRollback(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pager_unlock(p); dbda8d6ce9 2007-07-21 drh: assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) ); dbda8d6ce9 2007-07-21 drh: assert( p->errCode || !p->stmtOpen || p->exclusiveMode ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear the in-memory cache. This routine dbda8d6ce9 2007-07-21 drh: ** sets the state of the pager back to what it was when it was first dbda8d6ce9 2007-07-21 drh: ** opened. Any outstanding pages are invalidated and subsequent attempts dbda8d6ce9 2007-07-21 drh: ** to access those pages will likely result in a coredump. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void pager_reset(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg, *pNext; dbda8d6ce9 2007-07-21 drh: if( pPager->errCode ) return; dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pAll; pPg; pPg=pNext){ dbda8d6ce9 2007-07-21 drh: IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); dbda8d6ce9 2007-07-21 drh: PAGER_INCR(sqlite3_pager_pgfree_count); dbda8d6ce9 2007-07-21 drh: pNext = pPg->pNextAll; c287665ba8 2007-09-14 drh: lruListRemove(pPg); c287665ba8 2007-09-14 drh: sqlite3_free(pPg->pData); c287665ba8 2007-09-14 drh: sqlite3_free(pPg); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert(pPager->lru.pFirst==0); c287665ba8 2007-09-14 drh: assert(pPager->lru.pFirstSynced==0); c287665ba8 2007-09-14 drh: assert(pPager->lru.pLast==0); c287665ba8 2007-09-14 drh: pPager->pStmt = 0; dbda8d6ce9 2007-07-21 drh: pPager->pAll = 0; dbda8d6ce9 2007-07-21 drh: pPager->nHash = 0; c287665ba8 2007-09-14 drh: sqlite3_free(pPager->aHash); dbda8d6ce9 2007-07-21 drh: pPager->nPage = 0; dbda8d6ce9 2007-07-21 drh: pPager->aHash = 0; dbda8d6ce9 2007-07-21 drh: pPager->nRef = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine ends a transaction. A transaction is ended by either dbda8d6ce9 2007-07-21 drh: ** a COMMIT or a ROLLBACK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When this routine is called, the pager has the journal file open and dbda8d6ce9 2007-07-21 drh: ** a RESERVED or EXCLUSIVE lock on the database. This routine will release dbda8d6ce9 2007-07-21 drh: ** the database lock and acquires a SHARED lock in its place if that is dbda8d6ce9 2007-07-21 drh: ** the appropriate thing to do. Release locks usually is appropriate, dbda8d6ce9 2007-07-21 drh: ** unless we are in exclusive access mode or unless this is a dbda8d6ce9 2007-07-21 drh: ** COMMIT AND BEGIN or ROLLBACK AND BEGIN operation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The journal file is either deleted or truncated. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** TODO: Consider keeping the journal file open for temporary databases. dbda8d6ce9 2007-07-21 drh: ** This might give a performance improvement on windows where opening dbda8d6ce9 2007-07-21 drh: ** a file is an expensive operation. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_end_transaction(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int rc2 = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: assert( !MEMDB ); dbda8d6ce9 2007-07-21 drh: if( pPager->state<PAGER_RESERVED ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3PagerStmtCommit(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->stmtOpen && !pPager->exclusiveMode ){ c287665ba8 2007-09-14 drh: sqlite3OsClose(pPager->stfd); dbda8d6ce9 2007-07-21 drh: pPager->stmtOpen = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->journalOpen ){ dbda8d6ce9 2007-07-21 drh: if( pPager->exclusiveMode dbda8d6ce9 2007-07-21 drh: && (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){; dbda8d6ce9 2007-07-21 drh: pPager->journalOff = 0; dbda8d6ce9 2007-07-21 drh: pPager->journalStarted = 0; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: sqlite3OsClose(pPager->jfd); dbda8d6ce9 2007-07-21 drh: pPager->journalOpen = 0; dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free( pPager->aInJournal ); dbda8d6ce9 2007-07-21 drh: pPager->aInJournal = 0; dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ dbda8d6ce9 2007-07-21 drh: pPg->inJournal = 0; dbda8d6ce9 2007-07-21 drh: pPg->dirty = 0; dbda8d6ce9 2007-07-21 drh: pPg->needSync = 0; dbda8d6ce9 2007-07-21 drh: pPg->alwaysRollback = 0; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_CHECK_PAGES dbda8d6ce9 2007-07-21 drh: pPg->pageHash = pager_pagehash(pPg); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->pDirty = 0; dbda8d6ce9 2007-07-21 drh: pPager->dirtyCache = 0; dbda8d6ce9 2007-07-21 drh: pPager->nRec = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pPager->aInJournal==0 ); dbda8d6ce9 2007-07-21 drh: assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pPager->exclusiveMode ){ c287665ba8 2007-09-14 drh: rc2 = osUnlock(pPager->fd, SHARED_LOCK); dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_SHARED; dbda8d6ce9 2007-07-21 drh: }else if( pPager->state==PAGER_SYNCED ){ dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_EXCLUSIVE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->origDbSize = 0; dbda8d6ce9 2007-07-21 drh: pPager->setMaster = 0; dbda8d6ce9 2007-07-21 drh: pPager->needSync = 0; c287665ba8 2007-09-14 drh: lruListSetFirstSynced(pPager); dbda8d6ce9 2007-07-21 drh: pPager->dbSize = -1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return (rc==SQLITE_OK?rc2:rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute and return a checksum for the page of data. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is not a real checksum. It is really just the sum of the dbda8d6ce9 2007-07-21 drh: ** random initial value and the page number. We experimented with dbda8d6ce9 2007-07-21 drh: ** a checksum of the entire data, but that was found to be too slow. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that the page number is stored at the beginning of data and dbda8d6ce9 2007-07-21 drh: ** the checksum is stored at the end. This is important. If journal dbda8d6ce9 2007-07-21 drh: ** corruption occurs due to a power failure, the most likely scenario dbda8d6ce9 2007-07-21 drh: ** is that one end or the other of the record will be changed. It is dbda8d6ce9 2007-07-21 drh: ** much less likely that the two ends of the journal record will be dbda8d6ce9 2007-07-21 drh: ** correct and the middle be corrupt. Thus, this "checksum" scheme, dbda8d6ce9 2007-07-21 drh: ** though fast and simple, catches the mostly likely kind of corruption. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** FIX ME: Consider adding every 200th (or so) byte of the data to the dbda8d6ce9 2007-07-21 drh: ** checksum. That way if a single page spans 3 or more disk sectors and dbda8d6ce9 2007-07-21 drh: ** only the middle sector is corrupt, we will still have a reasonable dbda8d6ce9 2007-07-21 drh: ** chance of failing the checksum and thus detecting the problem. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static u32 pager_cksum(Pager *pPager, const u8 *aData){ dbda8d6ce9 2007-07-21 drh: u32 cksum = pPager->cksumInit; dbda8d6ce9 2007-07-21 drh: int i = pPager->pageSize-200; dbda8d6ce9 2007-07-21 drh: while( i>0 ){ dbda8d6ce9 2007-07-21 drh: cksum += aData[i]; dbda8d6ce9 2007-07-21 drh: i -= 200; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return cksum; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward declaration */ dbda8d6ce9 2007-07-21 drh: static void makeClean(PgHdr*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read a single page from the journal file opened on file descriptor dbda8d6ce9 2007-07-21 drh: ** jfd. Playback this one page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If useCksum==0 it means this journal does not use checksums. Checksums dbda8d6ce9 2007-07-21 drh: ** are not used in statement journals because statement journals do not dbda8d6ce9 2007-07-21 drh: ** need to survive power failures. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int pager_playback_one_page( c287665ba8 2007-09-14 drh: Pager *pPager, c287665ba8 2007-09-14 drh: sqlite3_file *jfd, c287665ba8 2007-09-14 drh: i64 offset, c287665ba8 2007-09-14 drh: int useCksum c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; /* An existing page in the cache */ dbda8d6ce9 2007-07-21 drh: Pgno pgno; /* The page number of a page in journal */ dbda8d6ce9 2007-07-21 drh: u32 cksum; /* Checksum used for sanity checking */ dbda8d6ce9 2007-07-21 drh: u8 *aData = (u8 *)pPager->pTmpSpace; /* Temp storage for a page */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* useCksum should be true for the main journal and false for dbda8d6ce9 2007-07-21 drh: ** statement journals. Verify that this is always the case dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) ); dbda8d6ce9 2007-07-21 drh: assert( aData ); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: rc = read32bits(jfd, offset, &pgno); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: pPager->journalOff += pPager->pageSize + 4; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Sanity checking on the page. This is more important that I originally dbda8d6ce9 2007-07-21 drh: ** thought. If a power failure occurs while the journal is being written, dbda8d6ce9 2007-07-21 drh: ** it could cause invalid data to be written into the journal. We need to dbda8d6ce9 2007-07-21 drh: ** detect this invalid data (with high probability) and ignore it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pgno>(unsigned)pPager->dbSize ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( useCksum ){ c287665ba8 2007-09-14 drh: rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: pPager->journalOff += 4; dbda8d6ce9 2007-07-21 drh: if( pager_cksum(pPager, aData)!=cksum ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPager->state==PAGER_RESERVED || pPager->state>=PAGER_EXCLUSIVE ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the pager is in RESERVED state, then there must be a copy of this dbda8d6ce9 2007-07-21 drh: ** page in the pager cache. In this case just update the pager cache, dbda8d6ce9 2007-07-21 drh: ** not the database file. The page is left marked dirty in this case. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An exception to the above rule: If the database is in no-sync mode dbda8d6ce9 2007-07-21 drh: ** and a page is moved during an incremental vacuum then the page may dbda8d6ce9 2007-07-21 drh: ** not be in the pager cache. Later: if a malloc() or IO error occurs dbda8d6ce9 2007-07-21 drh: ** during a Movepage() call, then the page may not be in the cache dbda8d6ce9 2007-07-21 drh: ** either. So the condition described in the above paragraph is not dbda8d6ce9 2007-07-21 drh: ** assert()able. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If in EXCLUSIVE state, then we update the pager cache if it exists dbda8d6ce9 2007-07-21 drh: ** and the main file. The page is then marked not dirty. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Ticket #1171: The statement journal might contain page content that is dbda8d6ce9 2007-07-21 drh: ** different from the page content at the start of the transaction. dbda8d6ce9 2007-07-21 drh: ** This occurs when a page is changed prior to the start of a statement dbda8d6ce9 2007-07-21 drh: ** then changed again within the statement. When rolling back such a dbda8d6ce9 2007-07-21 drh: ** statement we must not write to the original database unless we know dbda8d6ce9 2007-07-21 drh: ** for certain that original page contents are synced into the main rollback dbda8d6ce9 2007-07-21 drh: ** journal. Otherwise, a power loss might leave modified data in the dbda8d6ce9 2007-07-21 drh: ** database file without an entry in the rollback journal that can dbda8d6ce9 2007-07-21 drh: ** restore the database to its original form. Two conditions must be dbda8d6ce9 2007-07-21 drh: ** met before writing to the database files. (1) the database must be dbda8d6ce9 2007-07-21 drh: ** locked. (2) we know that the original page content is fully synced dbda8d6ce9 2007-07-21 drh: ** in the main journal either because the page is not in cache or else dbda8d6ce9 2007-07-21 drh: ** the page is marked as needSync==0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pPg = pager_lookup(pPager, pgno); dbda8d6ce9 2007-07-21 drh: PAGERTRACE4("PLAYBACK %d page %d hash(%08x)\n", dbda8d6ce9 2007-07-21 drh: PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData)); dbda8d6ce9 2007-07-21 drh: if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ c287665ba8 2007-09-14 drh: i64 offset = (pgno-1)*(i64)pPager->pageSize; c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize, offset); dbda8d6ce9 2007-07-21 drh: if( pPg ){ dbda8d6ce9 2007-07-21 drh: makeClean(pPg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPg ){ dbda8d6ce9 2007-07-21 drh: /* No page should ever be explicitly rolled back that is in use, except dbda8d6ce9 2007-07-21 drh: ** for page 1 which is held in use in order to keep the lock on the dbda8d6ce9 2007-07-21 drh: ** database active. However such a page may be rolled back as a result dbda8d6ce9 2007-07-21 drh: ** of an internal error resulting in an automatic call to dbda8d6ce9 2007-07-21 drh: ** sqlite3PagerRollback(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void *pData; dbda8d6ce9 2007-07-21 drh: /* assert( pPg->nRef==0 || pPg->pgno==1 ); */ dbda8d6ce9 2007-07-21 drh: pData = PGHDR_TO_DATA(pPg); dbda8d6ce9 2007-07-21 drh: memcpy(pData, aData, pPager->pageSize); dbda8d6ce9 2007-07-21 drh: if( pPager->xReiniter ){ dbda8d6ce9 2007-07-21 drh: pPager->xReiniter(pPg, pPager->pageSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_CHECK_PAGES dbda8d6ce9 2007-07-21 drh: pPg->pageHash = pager_pagehash(pPg); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: /* If this was page 1, then restore the value of Pager.dbFileVers. dbda8d6ce9 2007-07-21 drh: ** Do this before any decoding. */ dbda8d6ce9 2007-07-21 drh: if( pgno==1 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Decode the page just read from disk */ dbda8d6ce9 2007-07-21 drh: CODEC1(pPager, pData, pPg->pgno, 3); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Parameter zMaster is the name of a master journal file. A single journal dbda8d6ce9 2007-07-21 drh: ** file that referred to the master journal file has just been rolled back. dbda8d6ce9 2007-07-21 drh: ** This routine checks if it is possible to delete the master journal file, dbda8d6ce9 2007-07-21 drh: ** and does so if it is. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not c287665ba8 2007-09-14 drh: ** available for use within this function. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** dbda8d6ce9 2007-07-21 drh: ** The master journal file contains the names of all child journals. dbda8d6ce9 2007-07-21 drh: ** To tell if a master journal can be deleted, check to each of the dbda8d6ce9 2007-07-21 drh: ** children. If all children are either missing or do not refer to dbda8d6ce9 2007-07-21 drh: ** a different master journal, then this master journal can be deleted. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int pager_delmaster(Pager *pPager, const char *zMaster){ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs = pPager->pVfs; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: int master_open = 0; c287665ba8 2007-09-14 drh: sqlite3_file *pMaster; c287665ba8 2007-09-14 drh: sqlite3_file *pJournal; dbda8d6ce9 2007-07-21 drh: char *zMasterJournal = 0; /* Contents of master journal file */ dbda8d6ce9 2007-07-21 drh: i64 nMasterJournal; /* Size of master journal file */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open the master journal file exclusively in case some other process dbda8d6ce9 2007-07-21 drh: ** is running this routine also. Not that it makes too much difference. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: pMaster = (sqlite3_file *)sqlite3_malloc(pVfs->szOsFile * 2); c287665ba8 2007-09-14 drh: pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile); c287665ba8 2007-09-14 drh: if( !pMaster ){ c287665ba8 2007-09-14 drh: rc = SQLITE_NOMEM; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL); c287665ba8 2007-09-14 drh: rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto delmaster_out; dbda8d6ce9 2007-07-21 drh: master_open = 1; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = sqlite3OsFileSize(pMaster, &nMasterJournal); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto delmaster_out; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( nMasterJournal>0 ){ dbda8d6ce9 2007-07-21 drh: char *zJournal; dbda8d6ce9 2007-07-21 drh: char *zMasterPtr = 0; c287665ba8 2007-09-14 drh: int nMasterPtr = pPager->pVfs->mxPathname+1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Load the entire master journal file into space obtained from c287665ba8 2007-09-14 drh: ** sqlite3_malloc() and pointed to by zMasterJournal. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: zMasterJournal = (char *)sqlite3_malloc(nMasterJournal + nMasterPtr); dbda8d6ce9 2007-07-21 drh: if( !zMasterJournal ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto delmaster_out; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: zMasterPtr = &zMasterJournal[nMasterJournal]; c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(pMaster, zMasterJournal, nMasterJournal, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto delmaster_out; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zJournal = zMasterJournal; dbda8d6ce9 2007-07-21 drh: while( (zJournal-zMasterJournal)<nMasterJournal ){ c287665ba8 2007-09-14 drh: if( sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS) ){ dbda8d6ce9 2007-07-21 drh: /* One of the journals pointed to by the master journal exists. dbda8d6ce9 2007-07-21 drh: ** Open it and check if it points at the master journal. If dbda8d6ce9 2007-07-21 drh: ** so, return without deleting the master journal file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int c; c287665ba8 2007-09-14 drh: int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL); c287665ba8 2007-09-14 drh: rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: goto delmaster_out; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr); c287665ba8 2007-09-14 drh: sqlite3OsClose(pJournal); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto delmaster_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0; dbda8d6ce9 2007-07-21 drh: if( c ){ dbda8d6ce9 2007-07-21 drh: /* We have a match. Do not delete the master journal file. */ dbda8d6ce9 2007-07-21 drh: goto delmaster_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zJournal += (strlen(zJournal)+1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: rc = sqlite3OsDelete(pVfs, zMaster, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: delmaster_out: dbda8d6ce9 2007-07-21 drh: if( zMasterJournal ){ c287665ba8 2007-09-14 drh: sqlite3_free(zMasterJournal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( master_open ){ c287665ba8 2007-09-14 drh: sqlite3OsClose(pMaster); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pMaster); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: static void pager_truncate_cache(Pager *pPager); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Truncate the main file of the given pager to the number of pages dbda8d6ce9 2007-07-21 drh: ** indicated. Also truncate the cached representation of the file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_truncate(Pager *pPager, int nPage){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: if( pPager->state>=PAGER_EXCLUSIVE && pPager->fd->pMethods ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pPager->dbSize = nPage; dbda8d6ce9 2007-07-21 drh: pager_truncate_cache(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the sectorSize for the given pager. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sector size is the larger of the sector size reported dbda8d6ce9 2007-07-21 drh: ** by sqlite3OsSectorSize() and the pageSize. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void setSectorSize(Pager *pPager){ c287665ba8 2007-09-14 drh: assert(pPager->fd->pMethods||pPager->tempFile); c287665ba8 2007-09-14 drh: if( !pPager->tempFile ){ c287665ba8 2007-09-14 drh: /* Sector size doesn't matter for temporary files. Also, the file c287665ba8 2007-09-14 drh: ** may not have been opened yet, in whcih case the OsSectorSize() c287665ba8 2007-09-14 drh: ** call will segfault. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: pPager->sectorSize = sqlite3OsSectorSize(pPager->fd); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->sectorSize<pPager->pageSize ){ dbda8d6ce9 2007-07-21 drh: pPager->sectorSize = pPager->pageSize; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Playback the journal and thus restore the database file to dbda8d6ce9 2007-07-21 drh: ** the state it was in before we started making changes. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The journal file format is as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) 8 byte prefix. A copy of aJournalMagic[]. dbda8d6ce9 2007-07-21 drh: ** (2) 4 byte big-endian integer which is the number of valid page records dbda8d6ce9 2007-07-21 drh: ** in the journal. If this value is 0xffffffff, then compute the dbda8d6ce9 2007-07-21 drh: ** number of page records from the journal size. dbda8d6ce9 2007-07-21 drh: ** (3) 4 byte big-endian integer which is the initial value for the dbda8d6ce9 2007-07-21 drh: ** sanity checksum. dbda8d6ce9 2007-07-21 drh: ** (4) 4 byte integer which is the number of pages to truncate the dbda8d6ce9 2007-07-21 drh: ** database to during a rollback. dbda8d6ce9 2007-07-21 drh: ** (5) 4 byte integer which is the number of bytes in the master journal dbda8d6ce9 2007-07-21 drh: ** name. The value may be zero (indicate that there is no master dbda8d6ce9 2007-07-21 drh: ** journal.) dbda8d6ce9 2007-07-21 drh: ** (6) N bytes of the master journal name. The name will be nul-terminated dbda8d6ce9 2007-07-21 drh: ** and might be shorter than the value read from (5). If the first byte dbda8d6ce9 2007-07-21 drh: ** of the name is \000 then there is no master journal. The master dbda8d6ce9 2007-07-21 drh: ** journal name is stored in UTF-8. dbda8d6ce9 2007-07-21 drh: ** (7) Zero or more pages instances, each as follows: dbda8d6ce9 2007-07-21 drh: ** + 4 byte page number. dbda8d6ce9 2007-07-21 drh: ** + pPager->pageSize bytes of data. dbda8d6ce9 2007-07-21 drh: ** + 4 byte checksum dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When we speak of the journal header, we mean the first 6 items above. dbda8d6ce9 2007-07-21 drh: ** Each entry in the journal is an instance of the 7th item. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Call the value from the second bullet "nRec". nRec is the number of dbda8d6ce9 2007-07-21 drh: ** valid page entries in the journal. In most cases, you can compute the dbda8d6ce9 2007-07-21 drh: ** value of nRec from the size of the journal file. But if a power dbda8d6ce9 2007-07-21 drh: ** failure occurred while the journal was being written, it could be the dbda8d6ce9 2007-07-21 drh: ** case that the size of the journal file had already been increased but dbda8d6ce9 2007-07-21 drh: ** the extra entries had not yet made it safely to disk. In such a case, dbda8d6ce9 2007-07-21 drh: ** the value of nRec computed from the file size would be too large. For dbda8d6ce9 2007-07-21 drh: ** that reason, we always use the nRec value in the header. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the nRec value is 0xffffffff it means that nRec should be computed dbda8d6ce9 2007-07-21 drh: ** from the file size. This value is used when the user selects the dbda8d6ce9 2007-07-21 drh: ** no-sync option for the journal. A power failure could lead to corruption dbda8d6ce9 2007-07-21 drh: ** in this case. But for things like temporary table (which will be dbda8d6ce9 2007-07-21 drh: ** deleted when the power is restored) we don't care. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the file opened as the journal file is not a well-formed dbda8d6ce9 2007-07-21 drh: ** journal file then all pages up to the first corrupted page are rolled dbda8d6ce9 2007-07-21 drh: ** back (or no pages if the journal header is corrupted). The journal file dbda8d6ce9 2007-07-21 drh: ** is then deleted and SQLITE_OK returned, just as if no corruption had dbda8d6ce9 2007-07-21 drh: ** been encountered. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an I/O or malloc() error occurs, the journal-file is not deleted dbda8d6ce9 2007-07-21 drh: ** and an error code is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_playback(Pager *pPager, int isHot){ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs = pPager->pVfs; dbda8d6ce9 2007-07-21 drh: i64 szJ; /* Size of the journal file in bytes */ dbda8d6ce9 2007-07-21 drh: u32 nRec; /* Number of Records in the journal */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: Pgno mxPg = 0; /* Size of the original file in pages */ dbda8d6ce9 2007-07-21 drh: int rc; /* Result code of a subroutine */ dbda8d6ce9 2007-07-21 drh: char *zMaster = 0; /* Name of master journal file if any */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out how many records are in the journal. Abort early if dbda8d6ce9 2007-07-21 drh: ** the journal is empty. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOpen ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsFileSize(pPager->jfd, &szJ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK || szJ==0 ){ dbda8d6ce9 2007-07-21 drh: goto end_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read the master journal name from the journal, if it is present. dbda8d6ce9 2007-07-21 drh: ** If a master journal file name is specified, but the file is not dbda8d6ce9 2007-07-21 drh: ** present on disk, then the journal is not hot and does not need to be dbda8d6ce9 2007-07-21 drh: ** played back. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: zMaster = pPager->pTmpSpace; c287665ba8 2007-09-14 drh: rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); dbda8d6ce9 2007-07-21 drh: assert( rc!=SQLITE_DONE ); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK c287665ba8 2007-09-14 drh: || (zMaster[0] && !sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS)) c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: zMaster = 0; dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_DONE ) rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: goto end_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->journalOff = 0; c287665ba8 2007-09-14 drh: zMaster = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This loop terminates either when the readJournalHdr() call returns dbda8d6ce9 2007-07-21 drh: ** SQLITE_DONE or an IO error occurs. */ dbda8d6ce9 2007-07-21 drh: while( 1 ){ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read the next journal header from the journal file. If there are dbda8d6ce9 2007-07-21 drh: ** not enough bytes left in the journal file for a complete header, or dbda8d6ce9 2007-07-21 drh: ** it is corrupted, then a process must of failed while writing it. dbda8d6ce9 2007-07-21 drh: ** This indicates nothing more needs to be rolled back. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = readJournalHdr(pPager, szJ, &nRec, &mxPg); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_DONE ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto end_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If nRec is 0xffffffff, then this journal was created by a process dbda8d6ce9 2007-07-21 drh: ** working in no-sync mode. This means that the rest of the journal dbda8d6ce9 2007-07-21 drh: ** file consists of pages, there are no more journal headers. Compute dbda8d6ce9 2007-07-21 drh: ** the value of nRec based on this assumption. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( nRec==0xffffffff ){ dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ); dbda8d6ce9 2007-07-21 drh: nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If nRec is 0 and this rollback is of a transaction created by this c287665ba8 2007-09-14 drh: ** process and if this is the final header in the journal, then it means c287665ba8 2007-09-14 drh: ** that this part of the journal was being filled but has not yet been c287665ba8 2007-09-14 drh: ** synced to disk. Compute the number of pages based on the remaining c287665ba8 2007-09-14 drh: ** size of the file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The third term of the test was added to fix ticket #2565. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( nRec==0 && !isHot && c287665ba8 2007-09-14 drh: pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ dbda8d6ce9 2007-07-21 drh: nRec = (szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is the first header read from the journal, truncate the dbda8d6ce9 2007-07-21 drh: ** database file back to it's original size. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ dbda8d6ce9 2007-07-21 drh: rc = pager_truncate(pPager, mxPg); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto end_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Copy original pages out of the journal and back into the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nRec; i++){ c287665ba8 2007-09-14 drh: rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_DONE ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: pPager->journalOff = szJ; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: goto end_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /*NOTREACHED*/ dbda8d6ce9 2007-07-21 drh: assert( 0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: end_playback: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: zMaster = pPager->pTmpSpace; c287665ba8 2007-09-14 drh: rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = pager_end_transaction(pPager); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK && zMaster[0] ){ dbda8d6ce9 2007-07-21 drh: /* If there was a master journal and this routine will return success, dbda8d6ce9 2007-07-21 drh: ** see if it is possible to delete the master journal. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: rc = pager_delmaster(pPager, zMaster); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The Pager.sectorSize variable may have been updated while rolling dbda8d6ce9 2007-07-21 drh: ** back a journal created by a process with a different sector size dbda8d6ce9 2007-07-21 drh: ** value. Reset it to the correct value for this process. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: setSectorSize(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Playback the statement journal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is similar to playing back the transaction journal but with dbda8d6ce9 2007-07-21 drh: ** a few extra twists. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) The number of pages in the database file at the start of dbda8d6ce9 2007-07-21 drh: ** the statement is stored in pPager->stmtSize, not in the dbda8d6ce9 2007-07-21 drh: ** journal file itself. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (2) In addition to playing back the statement journal, also dbda8d6ce9 2007-07-21 drh: ** playback all pages of the transaction journal beginning dbda8d6ce9 2007-07-21 drh: ** at offset pPager->stmtJSize. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_stmt_playback(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: i64 szJ; /* Size of the full journal */ dbda8d6ce9 2007-07-21 drh: i64 hdrOff; dbda8d6ce9 2007-07-21 drh: int nRec; /* Number of Records */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: szJ = pPager->journalOff; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: i64 os_szJ; dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsFileSize(pPager->jfd, &os_szJ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: assert( szJ==os_szJ ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set hdrOff to be the offset just after the end of the last journal dbda8d6ce9 2007-07-21 drh: ** page written before the first journal-header for this statement dbda8d6ce9 2007-07-21 drh: ** transaction was written, or the end of the file if no journal dbda8d6ce9 2007-07-21 drh: ** header was written. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: hdrOff = pPager->stmtHdrOff; dbda8d6ce9 2007-07-21 drh: assert( pPager->fullSync || !hdrOff ); dbda8d6ce9 2007-07-21 drh: if( !hdrOff ){ dbda8d6ce9 2007-07-21 drh: hdrOff = szJ; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Truncate the database back to its original size. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = pager_truncate(pPager, pPager->stmtSize); dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_SHARED ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out how many records are in the statement journal. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPager->stmtInUse && pPager->journalOpen ); dbda8d6ce9 2007-07-21 drh: nRec = pPager->stmtNRec; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Copy original pages out of the statement journal and back into the dbda8d6ce9 2007-07-21 drh: ** database file. Note that the statement journal omits checksums from dbda8d6ce9 2007-07-21 drh: ** each record since power-failure recovery is not important to statement dbda8d6ce9 2007-07-21 drh: ** journals. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: for(i=0; i<nRec; i++){ c287665ba8 2007-09-14 drh: i64 offset = i*(4+pPager->pageSize); c287665ba8 2007-09-14 drh: rc = pager_playback_one_page(pPager, pPager->stfd, offset, 0); dbda8d6ce9 2007-07-21 drh: assert( rc!=SQLITE_DONE ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_stmt_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Now roll some pages back from the transaction journal. Pager.stmtJSize dbda8d6ce9 2007-07-21 drh: ** was the size of the journal file when this statement was started, so dbda8d6ce9 2007-07-21 drh: ** everything after that needs to be rolled back, either into the dbda8d6ce9 2007-07-21 drh: ** database, the memory cache, or both. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If it is not zero, then Pager.stmtHdrOff is the offset to the start dbda8d6ce9 2007-07-21 drh: ** of the first journal header written during this statement transaction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pPager->journalOff = pPager->stmtJSize; dbda8d6ce9 2007-07-21 drh: pPager->cksumInit = pPager->stmtCksum; dbda8d6ce9 2007-07-21 drh: while( pPager->journalOff < hdrOff ){ c287665ba8 2007-09-14 drh: rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); dbda8d6ce9 2007-07-21 drh: assert( rc!=SQLITE_DONE ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_stmt_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( pPager->journalOff < szJ ){ dbda8d6ce9 2007-07-21 drh: u32 nJRec; /* Number of Journal Records */ dbda8d6ce9 2007-07-21 drh: u32 dummy; dbda8d6ce9 2007-07-21 drh: rc = readJournalHdr(pPager, szJ, &nJRec, &dummy); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: assert( rc!=SQLITE_DONE ); dbda8d6ce9 2007-07-21 drh: goto end_stmt_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nJRec==0 ){ dbda8d6ce9 2007-07-21 drh: nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=nJRec-1; i>=0 && pPager->journalOff < szJ; i--){ c287665ba8 2007-09-14 drh: rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); dbda8d6ce9 2007-07-21 drh: assert( rc!=SQLITE_DONE ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_stmt_playback; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPager->journalOff = szJ; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: end_stmt_playback: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK) { dbda8d6ce9 2007-07-21 drh: pPager->journalOff = szJ; dbda8d6ce9 2007-07-21 drh: /* pager_reload_cache(pPager); */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the maximum number of in-memory pages that are allowed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ dbda8d6ce9 2007-07-21 drh: if( mxPage>10 ){ dbda8d6ce9 2007-07-21 drh: pPager->mxPage = mxPage; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pPager->mxPage = 10; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Adjust the robustness of the database to damage due to OS crashes dbda8d6ce9 2007-07-21 drh: ** or power failures by changing the number of syncs()s when writing dbda8d6ce9 2007-07-21 drh: ** the rollback journal. There are three levels: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** OFF sqlite3OsSync() is never called. This is the default dbda8d6ce9 2007-07-21 drh: ** for temporary and transient files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** NORMAL The journal is synced once before writes begin on the dbda8d6ce9 2007-07-21 drh: ** database. This is normally adequate protection, but dbda8d6ce9 2007-07-21 drh: ** it is theoretically possible, though very unlikely, dbda8d6ce9 2007-07-21 drh: ** that an inopertune power failure could leave the journal dbda8d6ce9 2007-07-21 drh: ** in a state which would cause damage to the database dbda8d6ce9 2007-07-21 drh: ** when it is rolled back. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** FULL The journal is synced twice before writes begin on the dbda8d6ce9 2007-07-21 drh: ** database (with some additional information - the nRec field dbda8d6ce9 2007-07-21 drh: ** of the journal header - being written in between the two dbda8d6ce9 2007-07-21 drh: ** syncs). If we assume that writing a dbda8d6ce9 2007-07-21 drh: ** single disk sector is atomic, then this mode provides dbda8d6ce9 2007-07-21 drh: ** assurance that the journal will not be corrupted to the dbda8d6ce9 2007-07-21 drh: ** point of causing damage to the database during rollback. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Numeric values associated with these states are OFF==1, NORMAL=2, dbda8d6ce9 2007-07-21 drh: ** and FULL=3. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int full_fsync){ dbda8d6ce9 2007-07-21 drh: pPager->noSync = level==1 || pPager->tempFile; dbda8d6ce9 2007-07-21 drh: pPager->fullSync = level==3 && !pPager->tempFile; c287665ba8 2007-09-14 drh: pPager->sync_flags = (full_fsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL); dbda8d6ce9 2007-07-21 drh: if( pPager->noSync ) pPager->needSync = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following global variable is incremented whenever the library dbda8d6ce9 2007-07-21 drh: ** attempts to open a temporary file. This information is used for dbda8d6ce9 2007-07-21 drh: ** testing and analysis only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_opentemp_count = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Open a temporary file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Write the file descriptor into *fd. Return SQLITE_OK on success or some c287665ba8 2007-09-14 drh: ** other error code if we fail. The OS will automatically delete the temporary c287665ba8 2007-09-14 drh: ** file when it is closed. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int sqlite3PagerOpentemp( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, /* The virtual file system layer */ c287665ba8 2007-09-14 drh: sqlite3_file *pFile, /* Write the file descriptor here */ c287665ba8 2007-09-14 drh: char *zFilename, /* Name of the file. Might be NULL */ c287665ba8 2007-09-14 drh: int vfsFlags /* Flags passed through to the VFS */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: assert( zFilename!=0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: sqlite3_opentemp_count++; /* Used for testing and analysis only */ dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: vfsFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE; c287665ba8 2007-09-14 drh: rc = sqlite3OsOpen(pVfs, zFilename, pFile, vfsFlags, 0); c287665ba8 2007-09-14 drh: assert( rc!=SQLITE_OK || pFile->pMethods ); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new page cache and put a pointer to the page cache in *ppPager. dbda8d6ce9 2007-07-21 drh: ** The file to be cached need not exist. The file is not locked until dbda8d6ce9 2007-07-21 drh: ** the first call to sqlite3PagerGet() and is only held open until the dbda8d6ce9 2007-07-21 drh: ** last page is released using sqlite3PagerUnref(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If zFilename is NULL then a randomly-named temporary file is created dbda8d6ce9 2007-07-21 drh: ** and used as the file to be cached. The file will be deleted dbda8d6ce9 2007-07-21 drh: ** automatically when it is closed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If zFilename is ":memory:" then all information is held in cache. dbda8d6ce9 2007-07-21 drh: ** It is never written to disk. This can be used to implement an dbda8d6ce9 2007-07-21 drh: ** in-memory database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerOpen( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, /* The virtual file system to use */ dbda8d6ce9 2007-07-21 drh: Pager **ppPager, /* Return the Pager structure here */ dbda8d6ce9 2007-07-21 drh: const char *zFilename, /* Name of the database file to open */ dbda8d6ce9 2007-07-21 drh: int nExtra, /* Extra bytes append to each in-memory page */ c287665ba8 2007-09-14 drh: int flags, /* flags controlling this file */ c287665ba8 2007-09-14 drh: int vfsFlags /* flags passed through to sqlite3_vfs.xOpen() */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: u8 *pPtr; c287665ba8 2007-09-14 drh: Pager *pPager = 0; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int tempFile = 0; dbda8d6ce9 2007-07-21 drh: int memDb = 0; dbda8d6ce9 2007-07-21 drh: int readOnly = 0; dbda8d6ce9 2007-07-21 drh: int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; dbda8d6ce9 2007-07-21 drh: int noReadlock = (flags & PAGER_NO_READLOCK)!=0; c287665ba8 2007-09-14 drh: int journalFileSize = sqlite3JournalSize(pVfs); c287665ba8 2007-09-14 drh: int nDefaultPage = SQLITE_DEFAULT_PAGE_SIZE; c287665ba8 2007-09-14 drh: char *zPathname; c287665ba8 2007-09-14 drh: int nPathname; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* The default return is a NULL pointer */ dbda8d6ce9 2007-07-21 drh: *ppPager = 0; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* Compute the full pathname */ c287665ba8 2007-09-14 drh: zPathname = sqlite3_malloc(pVfs->mxPathname+1); c287665ba8 2007-09-14 drh: if( zPathname==0 ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( zFilename && zFilename[0] ){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_MEMORYDB dbda8d6ce9 2007-07-21 drh: if( strcmp(zFilename,":memory:")==0 ){ dbda8d6ce9 2007-07-21 drh: memDb = 1; c287665ba8 2007-09-14 drh: zPathname[0] = 0; dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: rc = sqlite3OsFullPathname(pVfs, zFilename, zPathname); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: rc = sqlite3OsGetTempName(pVfs, zPathname); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3_free(zPathname); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: nPathname = strlen(zPathname); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Allocate memory for the pager structure */ c287665ba8 2007-09-14 drh: pPager = sqlite3MallocZero( c287665ba8 2007-09-14 drh: sizeof(*pPager) + /* Pager structure */ c287665ba8 2007-09-14 drh: journalFileSize + /* The journal file structure */ c287665ba8 2007-09-14 drh: pVfs->szOsFile * 2 + /* The db and stmt journal files */ c287665ba8 2007-09-14 drh: 4*nPathname + 40 /* zFilename, zDirectory, zJournal, zStmtJrnl */ c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: if( !pPager ){ c287665ba8 2007-09-14 drh: sqlite3_free(zPathname); c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pPtr = (u8 *)&pPager[1]; c287665ba8 2007-09-14 drh: pPager->vfsFlags = vfsFlags; c287665ba8 2007-09-14 drh: pPager->fd = (sqlite3_file*)&pPtr[pVfs->szOsFile*0]; c287665ba8 2007-09-14 drh: pPager->stfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*1]; c287665ba8 2007-09-14 drh: pPager->jfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*2]; c287665ba8 2007-09-14 drh: pPager->zFilename = (char*)&pPtr[pVfs->szOsFile*2+journalFileSize]; c287665ba8 2007-09-14 drh: pPager->zDirectory = &pPager->zFilename[nPathname+1]; c287665ba8 2007-09-14 drh: pPager->zJournal = &pPager->zDirectory[nPathname+1]; c287665ba8 2007-09-14 drh: pPager->zStmtJrnl = &pPager->zJournal[nPathname+10]; c287665ba8 2007-09-14 drh: pPager->pVfs = pVfs; c287665ba8 2007-09-14 drh: memcpy(pPager->zFilename, zPathname, nPathname+1); c287665ba8 2007-09-14 drh: sqlite3_free(zPathname); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Open the pager file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( zFilename && zFilename[0] && !memDb ){ c287665ba8 2007-09-14 drh: if( nPathname>(pVfs->mxPathname - sizeof("-journal")) ){ c287665ba8 2007-09-14 drh: rc = SQLITE_CANTOPEN; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: int fout = 0; c287665ba8 2007-09-14 drh: rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, c287665ba8 2007-09-14 drh: pPager->vfsFlags, &fout); c287665ba8 2007-09-14 drh: readOnly = (fout&SQLITE_OPEN_READONLY); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* If the file was successfully opened for read/write access, c287665ba8 2007-09-14 drh: ** choose a default page size in case we have to create the c287665ba8 2007-09-14 drh: ** database file. The default page size is the maximum of: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** + SQLITE_DEFAULT_PAGE_SIZE, c287665ba8 2007-09-14 drh: ** + The value returned by sqlite3OsSectorSize() c287665ba8 2007-09-14 drh: ** + The largest page size that can be written atomically. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK && !readOnly ){ c287665ba8 2007-09-14 drh: int iSectorSize = sqlite3OsSectorSize(pPager->fd); c287665ba8 2007-09-14 drh: if( nDefaultPage<iSectorSize ){ c287665ba8 2007-09-14 drh: nDefaultPage = iSectorSize; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_ATOMIC_WRITE c287665ba8 2007-09-14 drh: { c287665ba8 2007-09-14 drh: int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); c287665ba8 2007-09-14 drh: int ii; c287665ba8 2007-09-14 drh: assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); c287665ba8 2007-09-14 drh: assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); c287665ba8 2007-09-14 drh: assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); c287665ba8 2007-09-14 drh: for(ii=nDefaultPage; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ c287665ba8 2007-09-14 drh: if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ) nDefaultPage = ii; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: if( nDefaultPage>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ c287665ba8 2007-09-14 drh: nDefaultPage = SQLITE_MAX_DEFAULT_PAGE_SIZE; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: }else if( !memDb ){ c287665ba8 2007-09-14 drh: /* If a temporary file is requested, it is not opened immediately. c287665ba8 2007-09-14 drh: ** In this case we accept the default page size and delay actually c287665ba8 2007-09-14 drh: ** opening the file until the first call to OsWrite(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: tempFile = 1; c287665ba8 2007-09-14 drh: pPager->state = PAGER_EXCLUSIVE; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( pPager && rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: pPager->pTmpSpace = (char *)sqlite3_malloc(nDefaultPage); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* If an error occured in either of the blocks above. c287665ba8 2007-09-14 drh: ** Free the Pager structure and close the file. c287665ba8 2007-09-14 drh: ** Since the pager is not allocated there is no need to set dbda8d6ce9 2007-07-21 drh: ** any Pager.errMask variables. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: if( !pPager || !pPager->pTmpSpace ){ c287665ba8 2007-09-14 drh: sqlite3OsClose(pPager->fd); c287665ba8 2007-09-14 drh: sqlite3_free(pPager); dbda8d6ce9 2007-07-21 drh: return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: PAGERTRACE3("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename); c287665ba8 2007-09-14 drh: IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Fill in Pager.zDirectory[] */ c287665ba8 2007-09-14 drh: memcpy(pPager->zDirectory, pPager->zFilename, nPathname+1); c287665ba8 2007-09-14 drh: for(i=strlen(pPager->zDirectory); i>0 && pPager->zDirectory[i-1]!='/'; i--){} dbda8d6ce9 2007-07-21 drh: if( i>0 ) pPager->zDirectory[i-1] = 0; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Fill in Pager.zJournal[] and Pager.zStmtJrnl[] */ c287665ba8 2007-09-14 drh: memcpy(pPager->zJournal, pPager->zFilename, nPathname); c287665ba8 2007-09-14 drh: memcpy(&pPager->zJournal[nPathname], "-journal", 9); c287665ba8 2007-09-14 drh: memcpy(pPager->zStmtJrnl, pPager->zFilename, nPathname); c287665ba8 2007-09-14 drh: memcpy(&pPager->zStmtJrnl[nPathname], "-stmtjrnl", 10); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* pPager->journalOpen = 0; */ dbda8d6ce9 2007-07-21 drh: pPager->useJournal = useJournal && !memDb; dbda8d6ce9 2007-07-21 drh: pPager->noReadlock = noReadlock && readOnly; dbda8d6ce9 2007-07-21 drh: /* pPager->stmtOpen = 0; */ dbda8d6ce9 2007-07-21 drh: /* pPager->stmtInUse = 0; */ dbda8d6ce9 2007-07-21 drh: /* pPager->nRef = 0; */ dbda8d6ce9 2007-07-21 drh: pPager->dbSize = memDb-1; c287665ba8 2007-09-14 drh: pPager->pageSize = nDefaultPage; dbda8d6ce9 2007-07-21 drh: /* pPager->stmtSize = 0; */ dbda8d6ce9 2007-07-21 drh: /* pPager->stmtJSize = 0; */ dbda8d6ce9 2007-07-21 drh: /* pPager->nPage = 0; */ dbda8d6ce9 2007-07-21 drh: pPager->mxPage = 100; dbda8d6ce9 2007-07-21 drh: pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; dbda8d6ce9 2007-07-21 drh: /* pPager->state = PAGER_UNLOCK; */ c287665ba8 2007-09-14 drh: assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) ); dbda8d6ce9 2007-07-21 drh: /* pPager->errMask = 0; */ dbda8d6ce9 2007-07-21 drh: pPager->tempFile = tempFile; dbda8d6ce9 2007-07-21 drh: assert( tempFile==PAGER_LOCKINGMODE_NORMAL dbda8d6ce9 2007-07-21 drh: || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE ); dbda8d6ce9 2007-07-21 drh: assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 ); dbda8d6ce9 2007-07-21 drh: pPager->exclusiveMode = tempFile; dbda8d6ce9 2007-07-21 drh: pPager->memDb = memDb; dbda8d6ce9 2007-07-21 drh: pPager->readOnly = readOnly; dbda8d6ce9 2007-07-21 drh: /* pPager->needSync = 0; */ dbda8d6ce9 2007-07-21 drh: pPager->noSync = pPager->tempFile || !useJournal; dbda8d6ce9 2007-07-21 drh: pPager->fullSync = (pPager->noSync?0:1); c287665ba8 2007-09-14 drh: pPager->sync_flags = SQLITE_SYNC_NORMAL; dbda8d6ce9 2007-07-21 drh: /* pPager->pFirst = 0; */ dbda8d6ce9 2007-07-21 drh: /* pPager->pFirstSynced = 0; */ dbda8d6ce9 2007-07-21 drh: /* pPager->pLast = 0; */ dbda8d6ce9 2007-07-21 drh: pPager->nExtra = FORCE_ALIGNMENT(nExtra); c287665ba8 2007-09-14 drh: assert(pPager->fd->pMethods||memDb||tempFile); dbda8d6ce9 2007-07-21 drh: if( !memDb ){ dbda8d6ce9 2007-07-21 drh: setSectorSize(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* pPager->pBusyHandler = 0; */ dbda8d6ce9 2007-07-21 drh: /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ dbda8d6ce9 2007-07-21 drh: *ppPager = pPager; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: pPager->iInUseMM = 0; c287665ba8 2007-09-14 drh: pPager->iInUseDB = 0; c287665ba8 2007-09-14 drh: if( !memDb ){ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: pPager->pNext = sqlite3PagerList; c287665ba8 2007-09-14 drh: if( sqlite3PagerList ){ c287665ba8 2007-09-14 drh: assert( sqlite3PagerList->pPrev==0 ); c287665ba8 2007-09-14 drh: sqlite3PagerList->pPrev = pPager; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pPager->pPrev = 0; c287665ba8 2007-09-14 drh: sqlite3PagerList = pPager; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the busy handler function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager *pPager, BusyHandler *pBusyHandler){ dbda8d6ce9 2007-07-21 drh: pPager->pBusyHandler = pBusyHandler; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the destructor for this pager. If not NULL, the destructor is called dbda8d6ce9 2007-07-21 drh: ** when the reference count on each page reaches zero. The destructor can dbda8d6ce9 2007-07-21 drh: ** be used to clean up information in the extra segment appended to each page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The destructor is not called as a result sqlite3PagerClose(). dbda8d6ce9 2007-07-21 drh: ** Destructors are only called by sqlite3PagerUnref(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetDestructor(Pager *pPager, void (*xDesc)(DbPage*,int)){ dbda8d6ce9 2007-07-21 drh: pPager->xDestructor = xDesc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the reinitializer for this pager. If not NULL, the reinitializer dbda8d6ce9 2007-07-21 drh: ** is called when the content of a page in cache is restored to its original dbda8d6ce9 2007-07-21 drh: ** value as a result of a rollback. The callback gives higher-level code dbda8d6ce9 2007-07-21 drh: ** an opportunity to restore the EXTRA section to agree with the restored dbda8d6ce9 2007-07-21 drh: ** page data. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*,int)){ dbda8d6ce9 2007-07-21 drh: pPager->xReiniter = xReinit; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Set the page size to *pPageSize. If the suggest new page size is c287665ba8 2007-09-14 drh: ** inappropriate, then an alternative page size is set to that c287665ba8 2007-09-14 drh: ** value before returning. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: u16 pageSize = *pPageSize; c287665ba8 2007-09-14 drh: assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); c287665ba8 2007-09-14 drh: if( pageSize && pageSize!=pPager->pageSize c287665ba8 2007-09-14 drh: && !pPager->memDb && pPager->nRef==0 c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: char *pNew = (char *)sqlite3_malloc(pageSize); c287665ba8 2007-09-14 drh: if( !pNew ){ c287665ba8 2007-09-14 drh: rc = SQLITE_NOMEM; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pagerEnter(pPager); c287665ba8 2007-09-14 drh: pager_reset(pPager); c287665ba8 2007-09-14 drh: pPager->pageSize = pageSize; c287665ba8 2007-09-14 drh: setSectorSize(pPager); c287665ba8 2007-09-14 drh: sqlite3_free(pPager->pTmpSpace); c287665ba8 2007-09-14 drh: pPager->pTmpSpace = pNew; c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: *pPageSize = pPager->pageSize; c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to set the maximum database page count if mxPage is positive. dbda8d6ce9 2007-07-21 drh: ** Make no changes if mxPage is zero or negative. And never reduce the dbda8d6ce9 2007-07-21 drh: ** maximum page count below the current size of the database. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Regardless of mxPage, return the current maximum page count. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){ dbda8d6ce9 2007-07-21 drh: if( mxPage>0 ){ dbda8d6ce9 2007-07-21 drh: pPager->mxPgno = mxPage; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3PagerPagecount(pPager); dbda8d6ce9 2007-07-21 drh: return pPager->mxPgno; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following set of routines are used to disable the simulated dbda8d6ce9 2007-07-21 drh: ** I/O error mechanism. These routines are used to avoid simulated dbda8d6ce9 2007-07-21 drh: ** errors in places where we do not care about errors. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops dbda8d6ce9 2007-07-21 drh: ** and generate no code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API extern int sqlite3_io_error_pending; c287665ba8 2007-09-14 drh: SQLITE_API extern int sqlite3_io_error_hit; dbda8d6ce9 2007-07-21 drh: static int saved_cnt; dbda8d6ce9 2007-07-21 drh: void disable_simulated_io_errors(void){ dbda8d6ce9 2007-07-21 drh: saved_cnt = sqlite3_io_error_pending; dbda8d6ce9 2007-07-21 drh: sqlite3_io_error_pending = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: void enable_simulated_io_errors(void){ dbda8d6ce9 2007-07-21 drh: sqlite3_io_error_pending = saved_cnt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define disable_simulated_io_errors() dbda8d6ce9 2007-07-21 drh: # define enable_simulated_io_errors() dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read the first N bytes from the beginning of the file into memory dbda8d6ce9 2007-07-21 drh: ** that pDest points to. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** No error checking is done. The rational for this is that this function dbda8d6ce9 2007-07-21 drh: ** may be called even if the file does not exist or contain a header. In dbda8d6ce9 2007-07-21 drh: ** these cases sqlite3OsRead() will return an error, to which the correct dbda8d6ce9 2007-07-21 drh: ** response is to zero the memory at pDest and continue. A real IO error dbda8d6ce9 2007-07-21 drh: ** will presumably recur and be picked up later (Todo: Think about this). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: memset(pDest, 0, N); c287665ba8 2007-09-14 drh: assert(MEMDB||pPager->fd->pMethods||pPager->tempFile); c287665ba8 2007-09-14 drh: if( pPager->fd->pMethods ){ dbda8d6ce9 2007-07-21 drh: IOTRACE(("DBHDR %p 0 %d\n", pPager, N)) c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(pPager->fd, pDest, N, 0); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_IOERR_SHORT_READ ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the total number of pages in the disk file associated with dbda8d6ce9 2007-07-21 drh: ** pPager. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the PENDING_BYTE lies on the page directly after the end of the dbda8d6ce9 2007-07-21 drh: ** file, then consider this page part of the file too. For example, if dbda8d6ce9 2007-07-21 drh: ** PENDING_BYTE is byte 4096 (the first byte of page 5) and the size of the dbda8d6ce9 2007-07-21 drh: ** file is 4096 bytes, 5 is returned instead of 4. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerPagecount(Pager *pPager){ c287665ba8 2007-09-14 drh: i64 n = 0; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( pPager!=0 ); dbda8d6ce9 2007-07-21 drh: if( pPager->errCode ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->dbSize>=0 ){ dbda8d6ce9 2007-07-21 drh: n = pPager->dbSize; dbda8d6ce9 2007-07-21 drh: } else { c287665ba8 2007-09-14 drh: assert(pPager->fd->pMethods||pPager->tempFile); c287665ba8 2007-09-14 drh: if( (pPager->fd->pMethods) c287665ba8 2007-09-14 drh: && (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pager_error(pPager, rc); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( n>0 && n<pPager->pageSize ){ dbda8d6ce9 2007-07-21 drh: n = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: n /= pPager->pageSize; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->state!=PAGER_UNLOCK ){ dbda8d6ce9 2007-07-21 drh: pPager->dbSize = n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( n==(PENDING_BYTE/pPager->pageSize) ){ dbda8d6ce9 2007-07-21 drh: n++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( n>pPager->mxPgno ){ dbda8d6ce9 2007-07-21 drh: pPager->mxPgno = n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_MEMORYDB dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear a PgHistory block dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void clearHistory(PgHistory *pHist){ c287665ba8 2007-09-14 drh: sqlite3_free(pHist->pOrig); c287665ba8 2007-09-14 drh: sqlite3_free(pHist->pStmt); dbda8d6ce9 2007-07-21 drh: pHist->pOrig = 0; dbda8d6ce9 2007-07-21 drh: pHist->pStmt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define clearHistory(x) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Forward declaration dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int syncJournal(Pager*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Unlink pPg from it's hash chain. Also set the page number to 0 to indicate dbda8d6ce9 2007-07-21 drh: ** that the page is not part of any hash chain. This is required because the dbda8d6ce9 2007-07-21 drh: ** sqlite3PagerMovepage() routine can leave a page in the dbda8d6ce9 2007-07-21 drh: ** pNextFree/pPrevFree list that is not a part of any hash-chain. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void unlinkHashChain(Pager *pPager, PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: if( pPg->pgno==0 ){ dbda8d6ce9 2007-07-21 drh: assert( pPg->pNextHash==0 && pPg->pPrevHash==0 ); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPg->pNextHash ){ dbda8d6ce9 2007-07-21 drh: pPg->pNextHash->pPrevHash = pPg->pPrevHash; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPg->pPrevHash ){ dbda8d6ce9 2007-07-21 drh: assert( pPager->aHash[pPg->pgno & (pPager->nHash-1)]!=pPg ); dbda8d6ce9 2007-07-21 drh: pPg->pPrevHash->pNextHash = pPg->pNextHash; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int h = pPg->pgno & (pPager->nHash-1); dbda8d6ce9 2007-07-21 drh: pPager->aHash[h] = pPg->pNextHash; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: clearHistory(PGHDR_TO_HIST(pPg, pPager)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPg->pgno = 0; dbda8d6ce9 2007-07-21 drh: pPg->pNextHash = pPg->pPrevHash = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Unlink a page from the free list (the list of all pages where nRef==0) dbda8d6ce9 2007-07-21 drh: ** and from its hash collision chain. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void unlinkPage(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* Unlink from free page list */ c287665ba8 2007-09-14 drh: lruListRemove(pPg); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Unlink from the pgno hash table */ dbda8d6ce9 2007-07-21 drh: unlinkHashChain(pPager, pPg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is used to truncate the cache when a database dbda8d6ce9 2007-07-21 drh: ** is truncated. Drop from the cache all pages whose pgno is dbda8d6ce9 2007-07-21 drh: ** larger than pPager->dbSize and is unreferenced. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Referenced pages larger than pPager->dbSize are zeroed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Actually, at the point this routine is called, it would be dbda8d6ce9 2007-07-21 drh: ** an error to have a referenced page. But rather than delete dbda8d6ce9 2007-07-21 drh: ** that page and guarantee a subsequent segfault, it seems better dbda8d6ce9 2007-07-21 drh: ** to zero it and hope that we error out sanely. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void pager_truncate_cache(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: PgHdr **ppPg; dbda8d6ce9 2007-07-21 drh: int dbSize = pPager->dbSize; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: ppPg = &pPager->pAll; dbda8d6ce9 2007-07-21 drh: while( (pPg = *ppPg)!=0 ){ dbda8d6ce9 2007-07-21 drh: if( pPg->pgno<=dbSize ){ dbda8d6ce9 2007-07-21 drh: ppPg = &pPg->pNextAll; dbda8d6ce9 2007-07-21 drh: }else if( pPg->nRef>0 ){ dbda8d6ce9 2007-07-21 drh: memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); dbda8d6ce9 2007-07-21 drh: ppPg = &pPg->pNextAll; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *ppPg = pPg->pNextAll; dbda8d6ce9 2007-07-21 drh: IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); dbda8d6ce9 2007-07-21 drh: PAGER_INCR(sqlite3_pager_pgfree_count); dbda8d6ce9 2007-07-21 drh: unlinkPage(pPg); dbda8d6ce9 2007-07-21 drh: makeClean(pPg); c287665ba8 2007-09-14 drh: sqlite3_free(pPg->pData); c287665ba8 2007-09-14 drh: sqlite3_free(pPg); dbda8d6ce9 2007-07-21 drh: pPager->nPage--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Try to obtain a lock on a file. Invoke the busy callback if the lock dbda8d6ce9 2007-07-21 drh: ** is currently not available. Repeat until the busy callback returns dbda8d6ce9 2007-07-21 drh: ** false or until the lock succeeds. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK on success and an error code if we cannot obtain dbda8d6ce9 2007-07-21 drh: ** the lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_wait_on_lock(Pager *pPager, int locktype){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The OS lock values must be the same as the Pager lock values */ dbda8d6ce9 2007-07-21 drh: assert( PAGER_SHARED==SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( PAGER_RESERVED==RESERVED_LOCK ); dbda8d6ce9 2007-07-21 drh: assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the file is currently unlocked then the size must be unknown */ dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 || MEMDB ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->state>=locktype ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsLock(pPager->fd, locktype); dbda8d6ce9 2007-07-21 drh: }while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) ); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pPager->state = locktype; dbda8d6ce9 2007-07-21 drh: IOTRACE(("LOCK %p %d\n", pPager, locktype)) dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Truncate the file to the number of pages specified. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_SHARED || MEMDB ); dbda8d6ce9 2007-07-21 drh: sqlite3PagerPagecount(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->errCode ){ dbda8d6ce9 2007-07-21 drh: rc = pPager->errCode; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nPage>=(unsigned)pPager->dbSize ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: pPager->dbSize = nPage; dbda8d6ce9 2007-07-21 drh: pager_truncate_cache(pPager); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: rc = syncJournal(pPager); c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Get an exclusive lock on the database before truncating. */ c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = pager_truncate(pPager, nPage); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Shutdown the page cache. Free all memory and close all files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If a transaction was in progress when this routine is called, that dbda8d6ce9 2007-07-21 drh: ** transaction is rolled back. All outstanding pages are invalidated dbda8d6ce9 2007-07-21 drh: ** and their memory is freed. Any attempt to use a page associated dbda8d6ce9 2007-07-21 drh: ** with this page cache after this function returns will likely dbda8d6ce9 2007-07-21 drh: ** result in a coredump. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function always succeeds. If a transaction is active an attempt dbda8d6ce9 2007-07-21 drh: ** is made to roll it back. If an error occurs during the rollback dbda8d6ce9 2007-07-21 drh: ** a hot journal may be left in the filesystem but no error is returned dbda8d6ce9 2007-07-21 drh: ** to the caller. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT c287665ba8 2007-09-14 drh: if( !MEMDB ){ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: if( pPager->pPrev ){ c287665ba8 2007-09-14 drh: pPager->pPrev->pNext = pPager->pNext; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: sqlite3PagerList = pPager->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pPager->pNext ){ c287665ba8 2007-09-14 drh: pPager->pNext->pPrev = pPager->pPrev; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: disable_simulated_io_errors(); dbda8d6ce9 2007-07-21 drh: pPager->errCode = 0; dbda8d6ce9 2007-07-21 drh: pPager->exclusiveMode = 0; dbda8d6ce9 2007-07-21 drh: pager_reset(pPager); dbda8d6ce9 2007-07-21 drh: pagerUnlockAndRollback(pPager); dbda8d6ce9 2007-07-21 drh: enable_simulated_io_errors(); dbda8d6ce9 2007-07-21 drh: PAGERTRACE2("CLOSE %d\n", PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: IOTRACE(("CLOSE %p\n", pPager)) dbda8d6ce9 2007-07-21 drh: assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) ); dbda8d6ce9 2007-07-21 drh: if( pPager->journalOpen ){ c287665ba8 2007-09-14 drh: sqlite3OsClose(pPager->jfd); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pPager->aInJournal); dbda8d6ce9 2007-07-21 drh: if( pPager->stmtOpen ){ c287665ba8 2007-09-14 drh: sqlite3OsClose(pPager->stfd); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3OsClose(pPager->fd); dbda8d6ce9 2007-07-21 drh: /* Temp files are automatically deleted by the OS dbda8d6ce9 2007-07-21 drh: ** if( pPager->tempFile ){ dbda8d6ce9 2007-07-21 drh: ** sqlite3OsDelete(pPager->zFilename); dbda8d6ce9 2007-07-21 drh: ** } dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3_free(pPager->aHash); c287665ba8 2007-09-14 drh: sqlite3_free(pPager->pTmpSpace); c287665ba8 2007-09-14 drh: sqlite3_free(pPager); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(NDEBUG) || defined(SQLITE_TEST) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the page number for the given page data. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage *p){ dbda8d6ce9 2007-07-21 drh: return p->pgno; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The page_ref() function increments the reference count for a page. dbda8d6ce9 2007-07-21 drh: ** If the page is currently on the freelist (the reference count is zero) then dbda8d6ce9 2007-07-21 drh: ** remove it from the freelist. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For non-test systems, page_ref() is a macro that calls _page_ref() dbda8d6ce9 2007-07-21 drh: ** online of the reference count is zero. For test systems, page_ref() dbda8d6ce9 2007-07-21 drh: ** is a real function so that we can set breakpoints and trace it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void _page_ref(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: if( pPg->nRef==0 ){ dbda8d6ce9 2007-07-21 drh: /* The page is currently on the freelist. Remove it. */ c287665ba8 2007-09-14 drh: lruListRemove(pPg); dbda8d6ce9 2007-07-21 drh: pPg->pPager->nRef++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPg->nRef++; dbda8d6ce9 2007-07-21 drh: REFINFO(pPg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: static void page_ref(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: if( pPg->nRef==0 ){ dbda8d6ce9 2007-07-21 drh: _page_ref(pPg); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pPg->nRef++; dbda8d6ce9 2007-07-21 drh: REFINFO(pPg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define page_ref(P) ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Increment the reference count for a page. The input pointer is dbda8d6ce9 2007-07-21 drh: ** a reference to the page data. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerRef(DbPage *pPg){ c287665ba8 2007-09-14 drh: pagerEnter(pPg->pPager); dbda8d6ce9 2007-07-21 drh: page_ref(pPg); c287665ba8 2007-09-14 drh: pagerLeave(pPg->pPager); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Sync the journal. In other words, make sure all the pages that have dbda8d6ce9 2007-07-21 drh: ** been written to the journal have actually reached the surface of the dbda8d6ce9 2007-07-21 drh: ** disk. It is not safe to modify the original database file until after dbda8d6ce9 2007-07-21 drh: ** the journal has been synced. If the original database is modified before dbda8d6ce9 2007-07-21 drh: ** the journal is synced and a power failure occurs, the unsynced journal dbda8d6ce9 2007-07-21 drh: ** data would be lost and we would be unable to completely rollback the dbda8d6ce9 2007-07-21 drh: ** database changes. Database corruption would occur. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine also updates the nRec field in the header of the journal. dbda8d6ce9 2007-07-21 drh: ** (See comments on the pager_playback() routine for additional information.) dbda8d6ce9 2007-07-21 drh: ** If the sync mode is FULL, two syncs will occur. First the whole journal dbda8d6ce9 2007-07-21 drh: ** is synced, then the nRec field is updated, then a second sync occurs. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For temporary databases, we do not care if we are able to rollback c287665ba8 2007-09-14 drh: ** after a power failure, so no sync occurs. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If the IOCAP_SEQUENTIAL flag is set for the persistent media on which c287665ba8 2007-09-14 drh: ** the database is stored, then OsSync() is never called on the journal c287665ba8 2007-09-14 drh: ** file. In this case all that is required is to update the nRec field in c287665ba8 2007-09-14 drh: ** the journal header. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine clears the needSync field of every page current held in dbda8d6ce9 2007-07-21 drh: ** memory. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int syncJournal(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* Sync the journal before modifying the main database dbda8d6ce9 2007-07-21 drh: ** (assuming there is a journal and it needs to be synced.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPager->needSync ){ dbda8d6ce9 2007-07-21 drh: if( !pPager->tempFile ){ c287665ba8 2007-09-14 drh: int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOpen ); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* assert( !pPager->noSync ); // noSync might be set if synchronous dbda8d6ce9 2007-07-21 drh: ** was turned off after the transaction was started. Ticket #615 */ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: /* Make sure the pPager->nRec counter we are keeping agrees dbda8d6ce9 2007-07-21 drh: ** with the nRec computed from the size of the journal file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: i64 jSz; dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsFileSize(pPager->jfd, &jSz); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ) return rc; dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOff==jSz ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ dbda8d6ce9 2007-07-21 drh: /* Write the nRec value into the journal file header. If in dbda8d6ce9 2007-07-21 drh: ** full-synchronous mode, sync the journal first. This ensures that dbda8d6ce9 2007-07-21 drh: ** all data has really hit the disk before nRec is updated to mark dbda8d6ce9 2007-07-21 drh: ** it as a candidate for rollback. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This is not required if the persistent media supports the c287665ba8 2007-09-14 drh: ** SAFE_APPEND property. Because in this case it is not possible c287665ba8 2007-09-14 drh: ** for garbage data to be appended to the file, the nRec field c287665ba8 2007-09-14 drh: ** is populated with 0xFFFFFFFF when the journal header is written c287665ba8 2007-09-14 drh: ** and never needs to be updated. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: i64 jrnlOff; c287665ba8 2007-09-14 drh: if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ dbda8d6ce9 2007-07-21 drh: PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: IOTRACE(("JSYNC %p\n", pPager)) c287665ba8 2007-09-14 drh: rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ) return rc; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: jrnlOff = pPager->journalHdr + sizeof(aJournalMagic); c287665ba8 2007-09-14 drh: IOTRACE(("JHDR %p %lld %d\n", pPager, jrnlOff, 4)); c287665ba8 2007-09-14 drh: rc = write32bits(pPager->jfd, jrnlOff, pPager->nRec); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ c287665ba8 2007-09-14 drh: PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager)); c287665ba8 2007-09-14 drh: IOTRACE(("JSYNC %p\n", pPager)) c287665ba8 2007-09-14 drh: rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags| c287665ba8 2007-09-14 drh: (pPager->sync_flags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0) c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: if( rc!=0 ) return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: pPager->journalStarted = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->needSync = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Erase the needSync flag from every page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ dbda8d6ce9 2007-07-21 drh: pPg->needSync = 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: lruListSetFirstSynced(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* If the Pager.needSync flag is clear then the PgHdr.needSync dbda8d6ce9 2007-07-21 drh: ** flag must also be clear for all pages. Verify that this dbda8d6ce9 2007-07-21 drh: ** invariant is true. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: else{ dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ dbda8d6ce9 2007-07-21 drh: assert( pPg->needSync==0 ); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert( pPager->lru.pFirstSynced==pPager->lru.pFirst ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Merge two lists of pages connected by pDirty and in pgno order. dbda8d6ce9 2007-07-21 drh: ** Do not both fixing the pPrevDirty pointers. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB){ dbda8d6ce9 2007-07-21 drh: PgHdr result, *pTail; dbda8d6ce9 2007-07-21 drh: pTail = &result; dbda8d6ce9 2007-07-21 drh: while( pA && pB ){ dbda8d6ce9 2007-07-21 drh: if( pA->pgno<pB->pgno ){ dbda8d6ce9 2007-07-21 drh: pTail->pDirty = pA; dbda8d6ce9 2007-07-21 drh: pTail = pA; dbda8d6ce9 2007-07-21 drh: pA = pA->pDirty; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTail->pDirty = pB; dbda8d6ce9 2007-07-21 drh: pTail = pB; dbda8d6ce9 2007-07-21 drh: pB = pB->pDirty; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pA ){ dbda8d6ce9 2007-07-21 drh: pTail->pDirty = pA; dbda8d6ce9 2007-07-21 drh: }else if( pB ){ dbda8d6ce9 2007-07-21 drh: pTail->pDirty = pB; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTail->pDirty = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return result.pDirty; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Sort the list of pages in accending order by pgno. Pages are dbda8d6ce9 2007-07-21 drh: ** connected by pDirty pointers. The pPrevDirty pointers are dbda8d6ce9 2007-07-21 drh: ** corrupted by this sort. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define N_SORT_BUCKET_ALLOC 25 dbda8d6ce9 2007-07-21 drh: #define N_SORT_BUCKET 25 dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: int sqlite3_pager_n_sort_bucket = 0; dbda8d6ce9 2007-07-21 drh: #undef N_SORT_BUCKET dbda8d6ce9 2007-07-21 drh: #define N_SORT_BUCKET \ dbda8d6ce9 2007-07-21 drh: (sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: static PgHdr *sort_pagelist(PgHdr *pIn){ dbda8d6ce9 2007-07-21 drh: PgHdr *a[N_SORT_BUCKET_ALLOC], *p; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: memset(a, 0, sizeof(a)); dbda8d6ce9 2007-07-21 drh: while( pIn ){ dbda8d6ce9 2007-07-21 drh: p = pIn; dbda8d6ce9 2007-07-21 drh: pIn = p->pDirty; dbda8d6ce9 2007-07-21 drh: p->pDirty = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<N_SORT_BUCKET-1; i++){ dbda8d6ce9 2007-07-21 drh: if( a[i]==0 ){ dbda8d6ce9 2007-07-21 drh: a[i] = p; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: p = merge_pagelist(a[i], p); dbda8d6ce9 2007-07-21 drh: a[i] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i==N_SORT_BUCKET-1 ){ dbda8d6ce9 2007-07-21 drh: /* Coverage: To get here, there need to be 2^(N_SORT_BUCKET) dbda8d6ce9 2007-07-21 drh: ** elements in the input list. This is possible, but impractical. dbda8d6ce9 2007-07-21 drh: ** Testing this line is the point of global variable dbda8d6ce9 2007-07-21 drh: ** sqlite3_pager_n_sort_bucket. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: a[i] = merge_pagelist(a[i], p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p = a[0]; dbda8d6ce9 2007-07-21 drh: for(i=1; i<N_SORT_BUCKET; i++){ dbda8d6ce9 2007-07-21 drh: p = merge_pagelist(p, a[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given a list of pages (connected by the PgHdr.pDirty pointer) write dbda8d6ce9 2007-07-21 drh: ** every one of those pages out to the database file and mark them all dbda8d6ce9 2007-07-21 drh: ** as clean. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_write_pagelist(PgHdr *pList){ dbda8d6ce9 2007-07-21 drh: Pager *pPager; c287665ba8 2007-09-14 drh: PgHdr *p; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: pPager = pList->pPager; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* At this point there may be either a RESERVED or EXCLUSIVE lock on the dbda8d6ce9 2007-07-21 drh: ** database file. If there is already an EXCLUSIVE lock, the following dbda8d6ce9 2007-07-21 drh: ** calls to sqlite3OsLock() are no-ops. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Moving the lock from RESERVED to EXCLUSIVE actually involves going dbda8d6ce9 2007-07-21 drh: ** through an intermediate state PENDING. A PENDING lock prevents new dbda8d6ce9 2007-07-21 drh: ** readers from attaching to the database but is unsufficient for us to dbda8d6ce9 2007-07-21 drh: ** write. The idea of a PENDING lock is to prevent new readers from dbda8d6ce9 2007-07-21 drh: ** coming in while we wait for existing readers to clear. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** While the pager is in the RESERVED state, the original database file dbda8d6ce9 2007-07-21 drh: ** is unchanged and we can rollback without having to playback the dbda8d6ce9 2007-07-21 drh: ** journal into the original database file. Once we transition to dbda8d6ce9 2007-07-21 drh: ** EXCLUSIVE, it means the database file has been changed and any rollback dbda8d6ce9 2007-07-21 drh: ** will require a journal playback. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pList = sort_pagelist(pList); c287665ba8 2007-09-14 drh: for(p=pList; p; p=p->pDirty){ c287665ba8 2007-09-14 drh: assert( p->dirty ); c287665ba8 2007-09-14 drh: p->dirty = 0; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: while( pList ){ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* If the file has not yet been opened, open it now. */ c287665ba8 2007-09-14 drh: if( !pPager->fd->pMethods ){ c287665ba8 2007-09-14 drh: assert(pPager->tempFile); c287665ba8 2007-09-14 drh: rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->fd, pPager->zFilename, c287665ba8 2007-09-14 drh: pPager->vfsFlags); c287665ba8 2007-09-14 drh: if( rc ) return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* If there are dirty pages in the page cache with page numbers greater dbda8d6ce9 2007-07-21 drh: ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to dbda8d6ce9 2007-07-21 drh: ** make the file smaller (presumably by auto-vacuum code). Do not write dbda8d6ce9 2007-07-21 drh: ** any such pages to the file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pList->pgno<=pPager->dbSize ){ c287665ba8 2007-09-14 drh: i64 offset = (pList->pgno-1)*(i64)pPager->pageSize; dbda8d6ce9 2007-07-21 drh: char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); dbda8d6ce9 2007-07-21 drh: PAGERTRACE4("STORE %d page %d hash(%08x)\n", dbda8d6ce9 2007-07-21 drh: PAGERID(pPager), pList->pgno, pager_pagehash(pList)); dbda8d6ce9 2007-07-21 drh: IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno)); c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); dbda8d6ce9 2007-07-21 drh: PAGER_INCR(sqlite3_pager_writedb_count); dbda8d6ce9 2007-07-21 drh: PAGER_INCR(pPager->nWrite); dbda8d6ce9 2007-07-21 drh: if( pList->pgno==1 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: else{ dbda8d6ce9 2007-07-21 drh: PAGERTRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_CHECK_PAGES dbda8d6ce9 2007-07-21 drh: pList->pageHash = pager_pagehash(pList); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: pList = pList->pDirty; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Collect every dirty page into a dirty list and dbda8d6ce9 2007-07-21 drh: ** return a pointer to the head of that list. All pages are dbda8d6ce9 2007-07-21 drh: ** collected even if they are still in use. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static PgHdr *pager_get_all_dirty_pages(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: return pPager->pDirty; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if there is a hot journal on the given pager. dbda8d6ce9 2007-07-21 drh: ** A hot journal is one that needs to be played back. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the current size of the database file is 0 but a journal file dbda8d6ce9 2007-07-21 drh: ** exists, that is probably an old journal left over from a prior dbda8d6ce9 2007-07-21 drh: ** database with the same name. Just delete the journal. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int hasHotJournal(Pager *pPager){ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs = pPager->pVfs; dbda8d6ce9 2007-07-21 drh: if( !pPager->useJournal ) return 0; c287665ba8 2007-09-14 drh: if( !sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3OsCheckReservedLock(pPager->fd) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3PagerPagecount(pPager)==0 ){ c287665ba8 2007-09-14 drh: sqlite3OsDelete(pVfs, pPager->zJournal, 0); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Try to find a page in the cache that can be recycled. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It dbda8d6ce9 2007-07-21 drh: ** does not set the pPager->errCode variable. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int pager_recycle(Pager *pPager, PgHdr **ppPg){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: *ppPg = 0; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* It is illegal to call this function unless the pager object c287665ba8 2007-09-14 drh: ** pointed to by pPager has at least one free page (page with nRef==0). c287665ba8 2007-09-14 drh: */ dbda8d6ce9 2007-07-21 drh: assert(!MEMDB); c287665ba8 2007-09-14 drh: assert(pPager->lru.pFirst); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Find a page to recycle. Try to locate a page that does not dbda8d6ce9 2007-07-21 drh: ** require us to do an fsync() on the journal. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: pPg = pPager->lru.pFirstSynced; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we could not find a page that does not require an fsync() dbda8d6ce9 2007-07-21 drh: ** on the journal file then fsync the journal file. This is a dbda8d6ce9 2007-07-21 drh: ** very slow operation, so we work hard to avoid it. But sometimes dbda8d6ce9 2007-07-21 drh: ** it can't be helped. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: if( pPg==0 && pPager->lru.pFirst){ c287665ba8 2007-09-14 drh: int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); dbda8d6ce9 2007-07-21 drh: int rc = syncJournal(pPager); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ dbda8d6ce9 2007-07-21 drh: /* If in full-sync mode, write a new journal header into the dbda8d6ce9 2007-07-21 drh: ** journal file. This is done to avoid ever modifying a journal dbda8d6ce9 2007-07-21 drh: ** header that is involved in the rollback of pages that have dbda8d6ce9 2007-07-21 drh: ** already been written to the database (in case the header is dbda8d6ce9 2007-07-21 drh: ** trashed when the nRec field is updated). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pPager->nRec = 0; dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOff > 0 ); dbda8d6ce9 2007-07-21 drh: assert( pPager->doNotSync==0 ); dbda8d6ce9 2007-07-21 drh: rc = writeJournalHdr(pPager); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pPg = pPager->lru.pFirst; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPg->nRef==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Write the page to the database file if it is dirty. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPg->dirty ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( pPg->needSync==0 ); dbda8d6ce9 2007-07-21 drh: makeClean(pPg); dbda8d6ce9 2007-07-21 drh: pPg->dirty = 1; dbda8d6ce9 2007-07-21 drh: pPg->pDirty = 0; dbda8d6ce9 2007-07-21 drh: rc = pager_write_pagelist( pPg ); c287665ba8 2007-09-14 drh: pPg->dirty = 0; dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPg->dirty==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the page we are recycling is marked as alwaysRollback, then dbda8d6ce9 2007-07-21 drh: ** set the global alwaysRollback flag, thus disabling the dbda8d6ce9 2007-07-21 drh: ** sqlite3PagerDontRollback() optimization for the rest of this transaction. dbda8d6ce9 2007-07-21 drh: ** It is necessary to do this because the page marked alwaysRollback dbda8d6ce9 2007-07-21 drh: ** might be reloaded at a later time but at that point we won't remember dbda8d6ce9 2007-07-21 drh: ** that is was marked alwaysRollback. This means that all pages must dbda8d6ce9 2007-07-21 drh: ** be marked as alwaysRollback from here on out. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPg->alwaysRollback ){ dbda8d6ce9 2007-07-21 drh: IOTRACE(("ALWAYS_ROLLBACK %p\n", pPager)) dbda8d6ce9 2007-07-21 drh: pPager->alwaysRollback = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Unlink the old page from the free list and the hash table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: unlinkPage(pPg); dbda8d6ce9 2007-07-21 drh: assert( pPg->pgno==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: *ppPg = pPg; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is called to free superfluous dynamically allocated memory dbda8d6ce9 2007-07-21 drh: ** held by the pager system. Memory in use by any SQLite pager allocated c287665ba8 2007-09-14 drh: ** by the current thread may be sqlite3_free()ed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** nReq is the number of bytes of memory required. Once this much has c287665ba8 2007-09-14 drh: ** been released, the function returns. The return value is the total number dbda8d6ce9 2007-07-21 drh: ** of bytes of memory released. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerReleaseMemory(int nReq){ c287665ba8 2007-09-14 drh: int nReleased = 0; /* Bytes of memory released so far */ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex; /* The MEM2 mutex */ c287665ba8 2007-09-14 drh: Pager *pPager; /* For looping over pagers */ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Acquire the memory-management mutex c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Signal all database connections that memory management wants c287665ba8 2007-09-14 drh: ** to have access to the pagers. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){ c287665ba8 2007-09-14 drh: pPager->iInUseMM = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: while( rc==SQLITE_OK && (nReq<0 || nReleased<nReq) ){ c287665ba8 2007-09-14 drh: PgHdr *pPg; c287665ba8 2007-09-14 drh: PgHdr *pRecycled; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Try to find a page to recycle that does not require a sync(). If c287665ba8 2007-09-14 drh: ** this is not possible, find one that does require a sync(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); c287665ba8 2007-09-14 drh: pPg = sqlite3LruPageList.pFirstSynced; c287665ba8 2007-09-14 drh: while( pPg && (pPg->needSync || pPg->pPager->iInUseDB) ){ c287665ba8 2007-09-14 drh: pPg = pPg->gfree.pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( !pPg ){ c287665ba8 2007-09-14 drh: pPg = sqlite3LruPageList.pFirst; c287665ba8 2007-09-14 drh: while( pPg && pPg->pPager->iInUseDB ){ c287665ba8 2007-09-14 drh: pPg = pPg->gfree.pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* If pPg==0, then the block above has failed to find a page to c287665ba8 2007-09-14 drh: ** recycle. In this case return early - no further memory will c287665ba8 2007-09-14 drh: ** be released. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( !pPg ) break; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pPager = pPg->pPager; c287665ba8 2007-09-14 drh: assert(!pPg->needSync || pPg==pPager->lru.pFirst); c287665ba8 2007-09-14 drh: assert(pPg->needSync || pPg==pPager->lru.pFirstSynced); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = pager_recycle(pPager, &pRecycled); c287665ba8 2007-09-14 drh: assert(pRecycled==pPg || rc!=SQLITE_OK); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: /* We've found a page to free. At this point the page has been c287665ba8 2007-09-14 drh: ** removed from the page hash-table, free-list and synced-list c287665ba8 2007-09-14 drh: ** (pFirstSynced). It is still in the all pages (pAll) list. c287665ba8 2007-09-14 drh: ** Remove it from this list before freeing. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Todo: Check the Pager.pStmt list to make sure this is Ok. It c287665ba8 2007-09-14 drh: ** probably is though. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: PgHdr *pTmp; c287665ba8 2007-09-14 drh: assert( pPg ); c287665ba8 2007-09-14 drh: if( pPg==pPager->pAll ){ c287665ba8 2007-09-14 drh: pPager->pAll = pPg->pNextAll; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: for( pTmp=pPager->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){} c287665ba8 2007-09-14 drh: pTmp->pNextAll = pPg->pNextAll; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: nReleased += ( c287665ba8 2007-09-14 drh: sizeof(*pPg) + pPager->pageSize c287665ba8 2007-09-14 drh: + sizeof(u32) + pPager->nExtra c287665ba8 2007-09-14 drh: + MEMDB*sizeof(PgHistory) c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: IOTRACE(("PGFREE %p %d *\n", pPager, pPg->pgno)); c287665ba8 2007-09-14 drh: PAGER_INCR(sqlite3_pager_pgfree_count); c287665ba8 2007-09-14 drh: sqlite3_free(pPg->pData); c287665ba8 2007-09-14 drh: sqlite3_free(pPg); c287665ba8 2007-09-14 drh: pPager->nPage--; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: /* An error occured whilst writing to the database file or c287665ba8 2007-09-14 drh: ** journal in pager_recycle(). The error is not returned to the c287665ba8 2007-09-14 drh: ** caller of this function. Instead, set the Pager.errCode variable. c287665ba8 2007-09-14 drh: ** The error will be returned to the user (or users, in the case c287665ba8 2007-09-14 drh: ** of a shared pager cache) of the pager for which the error occured. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert( c287665ba8 2007-09-14 drh: (rc&0xff)==SQLITE_IOERR || c287665ba8 2007-09-14 drh: rc==SQLITE_FULL || c287665ba8 2007-09-14 drh: rc==SQLITE_BUSY c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: assert( pPager->state>=PAGER_RESERVED ); c287665ba8 2007-09-14 drh: pager_error(pPager, rc); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Clear the memory management flags and release the mutex c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){ c287665ba8 2007-09-14 drh: pPager->iInUseMM = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Return the number of bytes released c287665ba8 2007-09-14 drh: */ dbda8d6ce9 2007-07-21 drh: return nReleased; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read the content of page pPg out of the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: i64 offset; dbda8d6ce9 2007-07-21 drh: assert( MEMDB==0 ); c287665ba8 2007-09-14 drh: assert(pPager->fd->pMethods||pPager->tempFile); c287665ba8 2007-09-14 drh: if( !pPager->fd->pMethods ){ c287665ba8 2007-09-14 drh: return SQLITE_IOERR_SHORT_READ; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: offset = (pgno-1)*(i64)pPager->pageSize; c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize, offset); dbda8d6ce9 2007-07-21 drh: PAGER_INCR(sqlite3_pager_readdb_count); dbda8d6ce9 2007-07-21 drh: PAGER_INCR(pPager->nRead); dbda8d6ce9 2007-07-21 drh: IOTRACE(("PGIN %p %d\n", pPager, pgno)); dbda8d6ce9 2007-07-21 drh: if( pgno==1 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&pPager->dbFileVers, &((u8*)PGHDR_TO_DATA(pPg))[24], dbda8d6ce9 2007-07-21 drh: sizeof(pPager->dbFileVers)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); dbda8d6ce9 2007-07-21 drh: PAGERTRACE4("FETCH %d page %d hash(%08x)\n", dbda8d6ce9 2007-07-21 drh: PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is called to obtain the shared lock required before dbda8d6ce9 2007-07-21 drh: ** data may be read from the pager cache. If the shared lock has already dbda8d6ce9 2007-07-21 drh: ** been obtained, this function is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Immediately after obtaining the shared lock (if required), this function dbda8d6ce9 2007-07-21 drh: ** checks for a hot-journal file. If one is found, an emergency rollback dbda8d6ce9 2007-07-21 drh: ** is performed immediately. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pagerSharedLock(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->state==PAGER_UNLOCK ){ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs = pPager->pVfs; dbda8d6ce9 2007-07-21 drh: if( !MEMDB ){ dbda8d6ce9 2007-07-21 drh: assert( pPager->nRef==0 ); dbda8d6ce9 2007-07-21 drh: if( !pPager->noReadlock ){ dbda8d6ce9 2007-07-21 drh: rc = pager_wait_on_lock(pPager, SHARED_LOCK); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return pager_error(pPager, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a journal file exists, and there is no RESERVED lock on the dbda8d6ce9 2007-07-21 drh: ** database file, then it either needs to be played back or deleted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( hasHotJournal(pPager) ){ dbda8d6ce9 2007-07-21 drh: /* Get an EXCLUSIVE lock on the database file. At this point it is dbda8d6ce9 2007-07-21 drh: ** important that a RESERVED lock is not obtained on the way to the dbda8d6ce9 2007-07-21 drh: ** EXCLUSIVE lock. If it were, another process might open the dbda8d6ce9 2007-07-21 drh: ** database file, detect the RESERVED lock, and conclude that the dbda8d6ce9 2007-07-21 drh: ** database is safe to read while this process is still rolling it dbda8d6ce9 2007-07-21 drh: ** back. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Because the intermediate RESERVED lock is not requested, the dbda8d6ce9 2007-07-21 drh: ** second process will get to this point in the code and fail to dbda8d6ce9 2007-07-21 drh: ** obtain it's own EXCLUSIVE lock on the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pager_unlock(pPager); dbda8d6ce9 2007-07-21 drh: return pager_error(pPager, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_EXCLUSIVE; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open the journal for reading only. Return SQLITE_BUSY if dbda8d6ce9 2007-07-21 drh: ** we are unable to open the journal file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The journal file does not need to be locked itself. The dbda8d6ce9 2007-07-21 drh: ** journal file is never open unless the main database file holds dbda8d6ce9 2007-07-21 drh: ** a write lock, so there is never any chance of two or more dbda8d6ce9 2007-07-21 drh: ** processes opening the journal at the same time. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Open the journal for read/write access. This is because in c287665ba8 2007-09-14 drh: ** exclusive-access mode the file descriptor will be kept open and dbda8d6ce9 2007-07-21 drh: ** possibly used for a transaction later on. On some systems, the dbda8d6ce9 2007-07-21 drh: ** OsTruncate() call used in exclusive-access mode also requires dbda8d6ce9 2007-07-21 drh: ** a read/write file handle. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; c287665ba8 2007-09-14 drh: if( sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){ c287665ba8 2007-09-14 drh: int fout = 0; c287665ba8 2007-09-14 drh: int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL; dbda8d6ce9 2007-07-21 drh: assert( !pPager->tempFile ); c287665ba8 2007-09-14 drh: rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, &fout); c287665ba8 2007-09-14 drh: assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); c287665ba8 2007-09-14 drh: if( fout&SQLITE_OPEN_READONLY ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; c287665ba8 2007-09-14 drh: sqlite3OsClose(pPager->jfd); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pager_unlock(pPager); c287665ba8 2007-09-14 drh: return (rc==SQLITE_NOMEM?rc:SQLITE_BUSY); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->journalOpen = 1; dbda8d6ce9 2007-07-21 drh: pPager->journalStarted = 0; dbda8d6ce9 2007-07-21 drh: pPager->journalOff = 0; dbda8d6ce9 2007-07-21 drh: pPager->setMaster = 0; dbda8d6ce9 2007-07-21 drh: pPager->journalHdr = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Playback and delete the journal. Drop the database write dbda8d6ce9 2007-07-21 drh: ** lock and reacquire the read lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = pager_playback(pPager, 1); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return pager_error(pPager, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert(pPager->state==PAGER_SHARED || dbda8d6ce9 2007-07-21 drh: (pPager->exclusiveMode && pPager->state>PAGER_SHARED) dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->pAll ){ dbda8d6ce9 2007-07-21 drh: /* The shared-lock has just been acquired on the database file dbda8d6ce9 2007-07-21 drh: ** and there are already pages in the cache (from a previous dbda8d6ce9 2007-07-21 drh: ** read or write transaction). Check to see if the database dbda8d6ce9 2007-07-21 drh: ** has been modified. If the database has changed, flush the dbda8d6ce9 2007-07-21 drh: ** cache. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Database changes is detected by looking at 15 bytes beginning dbda8d6ce9 2007-07-21 drh: ** at offset 24 into the file. The first 4 of these 16 bytes are dbda8d6ce9 2007-07-21 drh: ** a 32-bit counter that is incremented with each change. The dbda8d6ce9 2007-07-21 drh: ** other bytes change randomly with each file change when dbda8d6ce9 2007-07-21 drh: ** a codec is in use. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There is a vanishingly small chance that a change will not be dbda8d6ce9 2007-07-21 drh: ** detected. The chance of an undetected change is so small that dbda8d6ce9 2007-07-21 drh: ** it can be neglected. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: char dbFileVers[sizeof(pPager->dbFileVers)]; dbda8d6ce9 2007-07-21 drh: sqlite3PagerPagecount(pPager); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->errCode ){ dbda8d6ce9 2007-07-21 drh: return pPager->errCode; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->dbSize>0 ){ dbda8d6ce9 2007-07-21 drh: IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: memset(dbFileVers, 0, sizeof(dbFileVers)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ dbda8d6ce9 2007-07-21 drh: pager_reset(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPager->exclusiveMode || pPager->state<=PAGER_SHARED ); dbda8d6ce9 2007-07-21 drh: if( pPager->state==PAGER_UNLOCK ){ dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_SHARED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate a PgHdr object. Either create a new one or reuse dbda8d6ce9 2007-07-21 drh: ** an existing one that is not otherwise in use. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A new PgHdr structure is created if any of the following are dbda8d6ce9 2007-07-21 drh: ** true: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) We have not exceeded our maximum allocated cache size dbda8d6ce9 2007-07-21 drh: ** as set by the "PRAGMA cache_size" command. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (2) There are no unused PgHdr objects available at this time. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (3) This is an in-memory database. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (4) There are no PgHdr objects that do not require a journal dbda8d6ce9 2007-07-21 drh: ** file sync and a sync of the journal file is currently dbda8d6ce9 2007-07-21 drh: ** prohibited. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Otherwise, reuse an existing PgHdr. In other words, reuse an dbda8d6ce9 2007-07-21 drh: ** existing PgHdr if all of the following are true: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) We have reached or exceeded the maximum cache size dbda8d6ce9 2007-07-21 drh: ** allowed by "PRAGMA cache_size". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (2) There is a PgHdr available with PgHdr->nRef==0 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (3) We are not in an in-memory database dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (4) Either there is an available PgHdr that does not need dbda8d6ce9 2007-07-21 drh: ** to be synced to disk or else disk syncing is currently dbda8d6ce9 2007-07-21 drh: ** allowed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; c287665ba8 2007-09-14 drh: void *pData; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create a new PgHdr if any of the four conditions defined c287665ba8 2007-09-14 drh: ** above are met: */ dbda8d6ce9 2007-07-21 drh: if( pPager->nPage<pPager->mxPage c287665ba8 2007-09-14 drh: || pPager->lru.pFirst==0 dbda8d6ce9 2007-07-21 drh: || MEMDB c287665ba8 2007-09-14 drh: || (pPager->lru.pFirstSynced==0 && pPager->doNotSync) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( pPager->nPage>=pPager->nHash ){ dbda8d6ce9 2007-07-21 drh: pager_resize_hash_table(pPager, dbda8d6ce9 2007-07-21 drh: pPager->nHash<256 ? 256 : pPager->nHash*2); dbda8d6ce9 2007-07-21 drh: if( pPager->nHash==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto pager_allocate_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: pPg = sqlite3_malloc( sizeof(*pPg) + sizeof(u32) + pPager->nExtra dbda8d6ce9 2007-07-21 drh: + MEMDB*sizeof(PgHistory) ); c287665ba8 2007-09-14 drh: if( pPg ){ c287665ba8 2007-09-14 drh: pData = sqlite3_malloc( pPager->pageSize ); c287665ba8 2007-09-14 drh: if( pData==0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(pPg); c287665ba8 2007-09-14 drh: pPg = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( pPg==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto pager_allocate_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memset(pPg, 0, sizeof(*pPg)); dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory)); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pPg->pData = pData; dbda8d6ce9 2007-07-21 drh: pPg->pPager = pPager; dbda8d6ce9 2007-07-21 drh: pPg->pNextAll = pPager->pAll; dbda8d6ce9 2007-07-21 drh: pPager->pAll = pPg; dbda8d6ce9 2007-07-21 drh: pPager->nPage++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Recycle an existing page with a zero ref-count. */ c287665ba8 2007-09-14 drh: rc = pager_recycle(pPager, &pPg); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_BUSY ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_IOERR_BLOCKED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto pager_allocate_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=SHARED_LOCK ); dbda8d6ce9 2007-07-21 drh: assert(pPg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *ppPg = pPg; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pager_allocate_out: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make sure we have the content for a page. If the page was dbda8d6ce9 2007-07-21 drh: ** previously acquired with noContent==1, then the content was dbda8d6ce9 2007-07-21 drh: ** just initialized to zeros instead of being read from disk. dbda8d6ce9 2007-07-21 drh: ** But now we need the real data off of disk. So make sure we dbda8d6ce9 2007-07-21 drh: ** have it. Read it in if we do not have it already. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_get_content(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: if( pPg->needRead ){ dbda8d6ce9 2007-07-21 drh: int rc = readDbPage(pPg->pPager, pPg, pPg->pgno); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pPg->needRead = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Acquire a page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A read lock on the disk file is obtained when the first page is acquired. dbda8d6ce9 2007-07-21 drh: ** This read lock is dropped when the last page is released. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine works for any page number greater than 0. If the database dbda8d6ce9 2007-07-21 drh: ** file is smaller than the requested page, then no actual disk dbda8d6ce9 2007-07-21 drh: ** read occurs and the memory image of the page is initialized to dbda8d6ce9 2007-07-21 drh: ** all zeros. The extra data appended to a page is always initialized dbda8d6ce9 2007-07-21 drh: ** to zeros the first time a page is loaded into memory. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The acquisition might fail for several reasons. In all cases, dbda8d6ce9 2007-07-21 drh: ** an appropriate error code is returned and *ppPage is set to NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also sqlite3PagerLookup(). Both this routine and Lookup() attempt dbda8d6ce9 2007-07-21 drh: ** to find a page in the in-memory cache first. If the page is not already dbda8d6ce9 2007-07-21 drh: ** in memory, this routine goes to disk to read it in whereas Lookup() dbda8d6ce9 2007-07-21 drh: ** just returns 0. This routine acquires a read-lock the first time it dbda8d6ce9 2007-07-21 drh: ** has to go to disk, and could also playback an old journal if necessary. dbda8d6ce9 2007-07-21 drh: ** Since Lookup() never goes to disk, it never has to deal with locks dbda8d6ce9 2007-07-21 drh: ** or journal files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If noContent is false, the page contents are actually read from disk. dbda8d6ce9 2007-07-21 drh: ** If noContent is true, it means that we do not care about the contents dbda8d6ce9 2007-07-21 drh: ** of the page at this time, so do not do a disk read. Just fill in the dbda8d6ce9 2007-07-21 drh: ** page content with zeros. But mark the fact that we have not read the dbda8d6ce9 2007-07-21 drh: ** content by setting the PgHdr.needRead flag. Later on, if dbda8d6ce9 2007-07-21 drh: ** sqlite3PagerWrite() is called on this page or if this routine is dbda8d6ce9 2007-07-21 drh: ** called again with noContent==0, that means that the content is needed dbda8d6ce9 2007-07-21 drh: ** and the disk read should occur at that point. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int pagerAcquire( dbda8d6ce9 2007-07-21 drh: Pager *pPager, /* The pager open on the database file */ dbda8d6ce9 2007-07-21 drh: Pgno pgno, /* Page number to fetch */ dbda8d6ce9 2007-07-21 drh: DbPage **ppPage, /* Write a pointer to the page here */ dbda8d6ce9 2007-07-21 drh: int noContent /* Do not bother reading content from disk if true */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPager->state==PAGER_UNLOCK || pPager->nRef>0 || pgno==1 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page dbda8d6ce9 2007-07-21 drh: ** number greater than this, or zero, is requested. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pgno>PAGER_MAX_PGNO || pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure we have not hit any critical errors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPager!=0 ); dbda8d6ce9 2007-07-21 drh: *ppPage = 0; dbda8d6ce9 2007-07-21 drh: if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ dbda8d6ce9 2007-07-21 drh: return pPager->errCode; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is the first page accessed, then get a SHARED lock dbda8d6ce9 2007-07-21 drh: ** on the database file. pagerSharedLock() is a no-op if dbda8d6ce9 2007-07-21 drh: ** a database lock is already held. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = pagerSharedLock(pPager); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPager->state!=PAGER_UNLOCK ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPg = pager_lookup(pPager, pgno); dbda8d6ce9 2007-07-21 drh: if( pPg==0 ){ dbda8d6ce9 2007-07-21 drh: /* The requested page is not in the page cache. */ dbda8d6ce9 2007-07-21 drh: int nMax; dbda8d6ce9 2007-07-21 drh: int h; dbda8d6ce9 2007-07-21 drh: PAGER_INCR(pPager->nMiss); dbda8d6ce9 2007-07-21 drh: rc = pagerAllocatePage(pPager, &pPg); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPg->pgno = pgno; dbda8d6ce9 2007-07-21 drh: assert( !MEMDB || pgno>pPager->stmtSize ); dbda8d6ce9 2007-07-21 drh: if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ c287665ba8 2007-09-14 drh: #if 0 dbda8d6ce9 2007-07-21 drh: sqlite3CheckMemory(pPager->aInJournal, pgno/8); c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOpen ); dbda8d6ce9 2007-07-21 drh: pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; dbda8d6ce9 2007-07-21 drh: pPg->needSync = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pPg->inJournal = 0; dbda8d6ce9 2007-07-21 drh: pPg->needSync = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: makeClean(pPg); dbda8d6ce9 2007-07-21 drh: pPg->nRef = 1; dbda8d6ce9 2007-07-21 drh: REFINFO(pPg); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPager->nRef++; dbda8d6ce9 2007-07-21 drh: if( pPager->nExtra>0 ){ dbda8d6ce9 2007-07-21 drh: memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nMax = sqlite3PagerPagecount(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->errCode ){ dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPg); dbda8d6ce9 2007-07-21 drh: rc = pPager->errCode; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Populate the page with data, either by reading from the database dbda8d6ce9 2007-07-21 drh: ** file, or by setting the entire page to zero. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( nMax<(int)pgno || MEMDB || (noContent && !pPager->alwaysRollback) ){ dbda8d6ce9 2007-07-21 drh: if( pgno>pPager->mxPgno ){ dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPg); dbda8d6ce9 2007-07-21 drh: return SQLITE_FULL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); dbda8d6ce9 2007-07-21 drh: pPg->needRead = noContent && !pPager->alwaysRollback; dbda8d6ce9 2007-07-21 drh: IOTRACE(("ZERO %p %d\n", pPager, pgno)); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = readDbPage(pPager, pPg, pgno); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ dbda8d6ce9 2007-07-21 drh: pPg->pgno = 0; dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPg); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPg->needRead = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Link the page into the page hash table */ dbda8d6ce9 2007-07-21 drh: h = pgno & (pPager->nHash-1); dbda8d6ce9 2007-07-21 drh: assert( pgno!=0 ); dbda8d6ce9 2007-07-21 drh: pPg->pNextHash = pPager->aHash[h]; dbda8d6ce9 2007-07-21 drh: pPager->aHash[h] = pPg; dbda8d6ce9 2007-07-21 drh: if( pPg->pNextHash ){ dbda8d6ce9 2007-07-21 drh: assert( pPg->pNextHash->pPrevHash==0 ); dbda8d6ce9 2007-07-21 drh: pPg->pNextHash->pPrevHash = pPg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_CHECK_PAGES dbda8d6ce9 2007-07-21 drh: pPg->pageHash = pager_pagehash(pPg); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The requested page is in the page cache. */ dbda8d6ce9 2007-07-21 drh: assert(pPager->nRef>0 || pgno==1); dbda8d6ce9 2007-07-21 drh: PAGER_INCR(pPager->nHit); dbda8d6ce9 2007-07-21 drh: if( !noContent ){ dbda8d6ce9 2007-07-21 drh: rc = pager_get_content(pPg); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: page_ref(pPg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *ppPage = pPg; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3PagerAcquire( c287665ba8 2007-09-14 drh: Pager *pPager, /* The pager open on the database file */ c287665ba8 2007-09-14 drh: Pgno pgno, /* Page number to fetch */ c287665ba8 2007-09-14 drh: DbPage **ppPage, /* Write a pointer to the page here */ c287665ba8 2007-09-14 drh: int noContent /* Do not bother reading content from disk if true */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: pagerEnter(pPager); c287665ba8 2007-09-14 drh: rc = pagerAcquire(pPager, pgno, ppPage, noContent); c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Acquire a page if it is already in the in-memory cache. Do dbda8d6ce9 2007-07-21 drh: ** not read the page from disk. Return a pointer to the page, dbda8d6ce9 2007-07-21 drh: ** or 0 if the page is not in cache. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also sqlite3PagerGet(). The difference between this routine dbda8d6ce9 2007-07-21 drh: ** and sqlite3PagerGet() is that _get() will go to the disk and read dbda8d6ce9 2007-07-21 drh: ** in the page if the page is not already in cache. This routine dbda8d6ce9 2007-07-21 drh: ** returns NULL if the page is not in cache or if a disk I/O error dbda8d6ce9 2007-07-21 drh: ** has ever happened. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ c287665ba8 2007-09-14 drh: PgHdr *pPg = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPager!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pgno!=0 ); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->state==PAGER_UNLOCK ){ dbda8d6ce9 2007-07-21 drh: assert( !pPager->pAll || pPager->exclusiveMode ); c287665ba8 2007-09-14 drh: }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ c287665ba8 2007-09-14 drh: /* Do nothing */ c287665ba8 2007-09-14 drh: }else if( (pPg = pager_lookup(pPager, pgno))!=0 ){ c287665ba8 2007-09-14 drh: page_ref(pPg); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return pPg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release a page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the number of references to the page drop to zero, then the dbda8d6ce9 2007-07-21 drh: ** page is added to the LRU list. When all references to all pages dbda8d6ce9 2007-07-21 drh: ** are released, a rollback occurs and the lock on the database is dbda8d6ce9 2007-07-21 drh: ** removed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerUnref(DbPage *pPg){ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Decrement the reference count for this page dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPg->nRef>0 ); c287665ba8 2007-09-14 drh: pagerEnter(pPg->pPager); dbda8d6ce9 2007-07-21 drh: pPg->nRef--; dbda8d6ce9 2007-07-21 drh: REFINFO(pPg); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: CHECK_PAGE(pPg); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* When the number of references to a page reach 0, call the dbda8d6ce9 2007-07-21 drh: ** destructor and add the page to the freelist. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPg->nRef==0 ){ c287665ba8 2007-09-14 drh: Pager *pPager = pPg->pPager; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: lruListAdd(pPg); dbda8d6ce9 2007-07-21 drh: if( pPager->xDestructor ){ dbda8d6ce9 2007-07-21 drh: pPager->xDestructor(pPg, pPager->pageSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* When all pages reach the freelist, drop the read lock from dbda8d6ce9 2007-07-21 drh: ** the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pPager->nRef--; dbda8d6ce9 2007-07-21 drh: assert( pPager->nRef>=0 ); dbda8d6ce9 2007-07-21 drh: if( pPager->nRef==0 && (!pPager->exclusiveMode || pPager->journalOff>0) ){ dbda8d6ce9 2007-07-21 drh: pagerUnlockAndRollback(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPg->pPager); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a journal file for pPager. There should already be a RESERVED dbda8d6ce9 2007-07-21 drh: ** or EXCLUSIVE lock on the database file when this routine is called. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK if everything. Return an error code and release the dbda8d6ce9 2007-07-21 drh: ** write lock if anything goes wrong. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_open_journal(Pager *pPager){ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs = pPager->pVfs; c287665ba8 2007-09-14 drh: int flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( !MEMDB ); dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_RESERVED ); dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOpen==0 ); dbda8d6ce9 2007-07-21 drh: assert( pPager->useJournal ); dbda8d6ce9 2007-07-21 drh: assert( pPager->aInJournal==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3PagerPagecount(pPager); c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 ); c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->aInJournal==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto failed_to_open_journal; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( pPager->tempFile ){ c287665ba8 2007-09-14 drh: flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: flags |= (SQLITE_OPEN_MAIN_JOURNAL); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_ATOMIC_WRITE c287665ba8 2007-09-14 drh: rc = sqlite3JournalOpen( c287665ba8 2007-09-14 drh: pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager) c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); dbda8d6ce9 2007-07-21 drh: pPager->journalOff = 0; dbda8d6ce9 2007-07-21 drh: pPager->setMaster = 0; dbda8d6ce9 2007-07-21 drh: pPager->journalHdr = 0; dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_NOMEM ){ c287665ba8 2007-09-14 drh: sqlite3OsDelete(pVfs, pPager->zJournal, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto failed_to_open_journal; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->journalOpen = 1; dbda8d6ce9 2007-07-21 drh: pPager->journalStarted = 0; dbda8d6ce9 2007-07-21 drh: pPager->needSync = 0; dbda8d6ce9 2007-07-21 drh: pPager->alwaysRollback = 0; dbda8d6ce9 2007-07-21 drh: pPager->nRec = 0; dbda8d6ce9 2007-07-21 drh: if( pPager->errCode ){ dbda8d6ce9 2007-07-21 drh: rc = pPager->errCode; dbda8d6ce9 2007-07-21 drh: goto failed_to_open_journal; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->origDbSize = pPager->dbSize; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = writeJournalHdr(pPager); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->stmtAutoopen && rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerStmtBegin(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ dbda8d6ce9 2007-07-21 drh: rc = pager_end_transaction(pPager); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_FULL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: failed_to_open_journal: c287665ba8 2007-09-14 drh: sqlite3_free(pPager->aInJournal); dbda8d6ce9 2007-07-21 drh: pPager->aInJournal = 0; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Acquire a write-lock on the database. The lock is removed when dbda8d6ce9 2007-07-21 drh: ** the any of the following happen: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * sqlite3PagerCommitPhaseTwo() is called. dbda8d6ce9 2007-07-21 drh: ** * sqlite3PagerRollback() is called. dbda8d6ce9 2007-07-21 drh: ** * sqlite3PagerClose() is called. dbda8d6ce9 2007-07-21 drh: ** * sqlite3PagerUnref() is called to on every outstanding page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first parameter to this routine is a pointer to any open page of the dbda8d6ce9 2007-07-21 drh: ** database file. Nothing changes about the page - it is used merely to dbda8d6ce9 2007-07-21 drh: ** acquire a pointer to the Pager structure and as proof that there is dbda8d6ce9 2007-07-21 drh: ** already a read-lock on the database. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The second parameter indicates how much space in bytes to reserve for a dbda8d6ce9 2007-07-21 drh: ** master journal file-name at the start of the journal when it is created. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A journal file is opened if this is not a temporary file. For temporary dbda8d6ce9 2007-07-21 drh: ** files, the opening of the journal file is deferred until there is an dbda8d6ce9 2007-07-21 drh: ** actual need to write to the journal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the database is already reserved for writing, this routine is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If exFlag is true, go ahead and get an EXCLUSIVE lock on the file dbda8d6ce9 2007-07-21 drh: ** immediately instead of waiting until we try to flush the cache. The dbda8d6ce9 2007-07-21 drh: ** exFlag is ignored if a transaction is already active. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerBegin(DbPage *pPg, int exFlag){ dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: assert( pPg->nRef>0 ); dbda8d6ce9 2007-07-21 drh: assert( pPager->state!=PAGER_UNLOCK ); dbda8d6ce9 2007-07-21 drh: if( pPager->state==PAGER_SHARED ){ dbda8d6ce9 2007-07-21 drh: assert( pPager->aInJournal==0 ); dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_EXCLUSIVE; dbda8d6ce9 2007-07-21 drh: pPager->origDbSize = pPager->dbSize; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_RESERVED; dbda8d6ce9 2007-07-21 drh: if( exFlag ){ dbda8d6ce9 2007-07-21 drh: rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->dirtyCache = 0; dbda8d6ce9 2007-07-21 drh: PAGERTRACE2("TRANSACTION %d\n", PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: if( pPager->useJournal && !pPager->tempFile ){ dbda8d6ce9 2007-07-21 drh: rc = pager_open_journal(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pPager->journalOpen && pPager->journalOff==0 ){ dbda8d6ce9 2007-07-21 drh: /* This happens when the pager was in exclusive-access mode last dbda8d6ce9 2007-07-21 drh: ** time a (read or write) transaction was successfully concluded dbda8d6ce9 2007-07-21 drh: ** by this connection. Instead of deleting the journal file it was dbda8d6ce9 2007-07-21 drh: ** kept open and truncated to 0 bytes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPager->nRec==0 ); dbda8d6ce9 2007-07-21 drh: assert( pPager->origDbSize==0 ); dbda8d6ce9 2007-07-21 drh: assert( pPager->aInJournal==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3PagerPagecount(pPager); c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 ); c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( !pPager->aInJournal ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pPager->origDbSize = pPager->dbSize; dbda8d6ce9 2007-07-21 drh: rc = writeJournalHdr(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK ); c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make a page dirty. Set its dirty flag and add it to the dirty dbda8d6ce9 2007-07-21 drh: ** page list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void makeDirty(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: if( pPg->dirty==0 ){ dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: pPg->dirty = 1; dbda8d6ce9 2007-07-21 drh: pPg->pDirty = pPager->pDirty; dbda8d6ce9 2007-07-21 drh: if( pPager->pDirty ){ dbda8d6ce9 2007-07-21 drh: pPager->pDirty->pPrevDirty = pPg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPg->pPrevDirty = 0; dbda8d6ce9 2007-07-21 drh: pPager->pDirty = pPg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make a page clean. Clear its dirty bit and remove it from the dbda8d6ce9 2007-07-21 drh: ** dirty page list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void makeClean(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: if( pPg->dirty ){ dbda8d6ce9 2007-07-21 drh: pPg->dirty = 0; dbda8d6ce9 2007-07-21 drh: if( pPg->pDirty ){ c287665ba8 2007-09-14 drh: assert( pPg->pDirty->pPrevDirty==pPg ); dbda8d6ce9 2007-07-21 drh: pPg->pDirty->pPrevDirty = pPg->pPrevDirty; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPg->pPrevDirty ){ c287665ba8 2007-09-14 drh: assert( pPg->pPrevDirty->pDirty==pPg ); dbda8d6ce9 2007-07-21 drh: pPg->pPrevDirty->pDirty = pPg->pDirty; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: assert( pPg->pPager->pDirty==pPg ); dbda8d6ce9 2007-07-21 drh: pPg->pPager->pDirty = pPg->pDirty; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Mark a data page as writeable. The page is written into the journal dbda8d6ce9 2007-07-21 drh: ** if it is not there already. This routine must be called before making dbda8d6ce9 2007-07-21 drh: ** changes to a page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first time this routine is called, the pager creates a new dbda8d6ce9 2007-07-21 drh: ** journal and acquires a RESERVED lock on the database. If the RESERVED dbda8d6ce9 2007-07-21 drh: ** lock could not be acquired, this routine returns SQLITE_BUSY. The dbda8d6ce9 2007-07-21 drh: ** calling routine must check for that return value and be careful not to dbda8d6ce9 2007-07-21 drh: ** change any page data until this routine returns SQLITE_OK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the journal file could not be written because the disk is full, dbda8d6ce9 2007-07-21 drh: ** then this routine returns SQLITE_FULL and does an immediate rollback. dbda8d6ce9 2007-07-21 drh: ** All subsequent write attempts also return SQLITE_FULL until there dbda8d6ce9 2007-07-21 drh: ** is a call to sqlite3PagerCommit() or sqlite3PagerRollback() to dbda8d6ce9 2007-07-21 drh: ** reset. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int pager_write(PgHdr *pPg){ dbda8d6ce9 2007-07-21 drh: void *pData = PGHDR_TO_DATA(pPg); dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check for errors dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPager->errCode ){ dbda8d6ce9 2007-07-21 drh: return pPager->errCode; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->readOnly ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_PERM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( !pPager->setMaster ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: CHECK_PAGE(pPg); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this page was previously acquired with noContent==1, that means dbda8d6ce9 2007-07-21 drh: ** we didn't really read in the content of the page. This can happen dbda8d6ce9 2007-07-21 drh: ** (for example) when the page is being moved to the freelist. But dbda8d6ce9 2007-07-21 drh: ** now we are (perhaps) moving the page off of the freelist for dbda8d6ce9 2007-07-21 drh: ** reuse and we need to know its original content so that content dbda8d6ce9 2007-07-21 drh: ** can be stored in the rollback journal. So do the read at this dbda8d6ce9 2007-07-21 drh: ** time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = pager_get_content(pPg); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Mark the page as dirty. If the page has already been written dbda8d6ce9 2007-07-21 drh: ** to the journal then we can return right away. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: makeDirty(pPg); dbda8d6ce9 2007-07-21 drh: if( pPg->inJournal && (pageInStatement(pPg) || pPager->stmtInUse==0) ){ dbda8d6ce9 2007-07-21 drh: pPager->dirtyCache = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we get this far, it means that the page needs to be dbda8d6ce9 2007-07-21 drh: ** written to the transaction journal or the ckeckpoint journal dbda8d6ce9 2007-07-21 drh: ** or both. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** First check to see that the transaction journal exists and dbda8d6ce9 2007-07-21 drh: ** create it if it does not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPager->state!=PAGER_UNLOCK ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerBegin(pPg, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_RESERVED ); dbda8d6ce9 2007-07-21 drh: if( !pPager->journalOpen && pPager->useJournal ){ dbda8d6ce9 2007-07-21 drh: rc = pager_open_journal(pPager); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOpen || !pPager->useJournal ); dbda8d6ce9 2007-07-21 drh: pPager->dirtyCache = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The transaction journal now exists and we have a RESERVED or an dbda8d6ce9 2007-07-21 drh: ** EXCLUSIVE lock on the main database file. Write the current page to dbda8d6ce9 2007-07-21 drh: ** the transaction journal if it is not there already. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){ dbda8d6ce9 2007-07-21 drh: if( (int)pPg->pgno <= pPager->origDbSize ){ dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); dbda8d6ce9 2007-07-21 drh: PAGERTRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); dbda8d6ce9 2007-07-21 drh: assert( pHist->pOrig==0 ); c287665ba8 2007-09-14 drh: pHist->pOrig = sqlite3_malloc( pPager->pageSize ); dbda8d6ce9 2007-07-21 drh: if( pHist->pOrig ){ dbda8d6ce9 2007-07-21 drh: memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: u32 cksum; c287665ba8 2007-09-14 drh: char *pData2; c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* We should never write to the journal file the page that dbda8d6ce9 2007-07-21 drh: ** contains the database locks. The following assert verifies dbda8d6ce9 2007-07-21 drh: ** that we do not. */ dbda8d6ce9 2007-07-21 drh: assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); dbda8d6ce9 2007-07-21 drh: pData2 = CODEC2(pPager, pData, pPg->pgno, 7); dbda8d6ce9 2007-07-21 drh: cksum = pager_cksum(pPager, (u8*)pData2); c287665ba8 2007-09-14 drh: rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, c287665ba8 2007-09-14 drh: pPager->journalOff + 4); c287665ba8 2007-09-14 drh: pPager->journalOff += pPager->pageSize+4; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = write32bits(pPager->jfd, pPager->journalOff, cksum); c287665ba8 2007-09-14 drh: pPager->journalOff += 4; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, c287665ba8 2007-09-14 drh: pPager->journalOff, pPager->pageSize)); c287665ba8 2007-09-14 drh: PAGER_INCR(sqlite3_pager_writej_count); dbda8d6ce9 2007-07-21 drh: PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n", dbda8d6ce9 2007-07-21 drh: PAGERID(pPager), pPg->pgno, pPg->needSync, pager_pagehash(pPg)); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* An error has occured writing to the journal file. The dbda8d6ce9 2007-07-21 drh: ** transaction will be rolled back by the layer above. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPager->nRec++; dbda8d6ce9 2007-07-21 drh: assert( pPager->aInJournal!=0 ); dbda8d6ce9 2007-07-21 drh: pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); dbda8d6ce9 2007-07-21 drh: pPg->needSync = !pPager->noSync; dbda8d6ce9 2007-07-21 drh: if( pPager->stmtInUse ){ dbda8d6ce9 2007-07-21 drh: pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pPg->needSync = !pPager->journalStarted && !pPager->noSync; dbda8d6ce9 2007-07-21 drh: PAGERTRACE4("APPEND %d page %d needSync=%d\n", dbda8d6ce9 2007-07-21 drh: PAGERID(pPager), pPg->pgno, pPg->needSync); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPg->needSync ){ dbda8d6ce9 2007-07-21 drh: pPager->needSync = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPg->inJournal = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the statement journal is open and the page is not in it, dbda8d6ce9 2007-07-21 drh: ** then write the current page to the statement journal. Note that dbda8d6ce9 2007-07-21 drh: ** the statement journal format differs from the standard journal format dbda8d6ce9 2007-07-21 drh: ** in that it omits the checksums and the header. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPager->stmtInUse dbda8d6ce9 2007-07-21 drh: && !pageInStatement(pPg) dbda8d6ce9 2007-07-21 drh: && (int)pPg->pgno<=pPager->stmtSize dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize ); dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); dbda8d6ce9 2007-07-21 drh: assert( pHist->pStmt==0 ); c287665ba8 2007-09-14 drh: pHist->pStmt = sqlite3_malloc( pPager->pageSize ); dbda8d6ce9 2007-07-21 drh: if( pHist->pStmt ){ dbda8d6ce9 2007-07-21 drh: memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); dbda8d6ce9 2007-07-21 drh: page_add_to_stmt_list(pPg); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: i64 offset = pPager->stmtNRec*(4+pPager->pageSize); c287665ba8 2007-09-14 drh: char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7); c287665ba8 2007-09-14 drh: rc = write32bits(pPager->stfd, offset, pPg->pgno); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->stmtNRec++; dbda8d6ce9 2007-07-21 drh: assert( pPager->aInStmt!=0 ); dbda8d6ce9 2007-07-21 drh: pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update the database size and return. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_SHARED ); dbda8d6ce9 2007-07-21 drh: if( pPager->dbSize<(int)pPg->pgno ){ dbda8d6ce9 2007-07-21 drh: pPager->dbSize = pPg->pgno; dbda8d6ce9 2007-07-21 drh: if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){ dbda8d6ce9 2007-07-21 drh: pPager->dbSize++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is used to mark a data-page as writable. It uses dbda8d6ce9 2007-07-21 drh: ** pager_write() to open a journal file (if it is not already open) dbda8d6ce9 2007-07-21 drh: ** and write the page *pData to the journal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The difference between this function and pager_write() is that this dbda8d6ce9 2007-07-21 drh: ** function also deals with the special case where 2 or more pages dbda8d6ce9 2007-07-21 drh: ** fit on a single disk sector. In this case all co-resident pages dbda8d6ce9 2007-07-21 drh: ** must have been written to the journal file before returning. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: PgHdr *pPg = pDbPage; dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( !MEMDB && nPagePerSector>1 ){ dbda8d6ce9 2007-07-21 drh: Pgno nPageCount; /* Total number of pages in database file */ dbda8d6ce9 2007-07-21 drh: Pgno pg1; /* First page of the sector pPg is located on. */ dbda8d6ce9 2007-07-21 drh: int nPage; /* Number of pages starting at pg1 to journal */ dbda8d6ce9 2007-07-21 drh: int ii; c287665ba8 2007-09-14 drh: int needSync = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the doNotSync flag to 1. This is because we cannot allow a journal dbda8d6ce9 2007-07-21 drh: ** header to be written between the pages journaled by this function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPager->doNotSync==0 ); dbda8d6ce9 2007-07-21 drh: pPager->doNotSync = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This trick assumes that both the page-size and sector-size are dbda8d6ce9 2007-07-21 drh: ** an integer power of 2. It sets variable pg1 to the identifier dbda8d6ce9 2007-07-21 drh: ** of the first page of the sector pPg is located on. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nPageCount = sqlite3PagerPagecount(pPager); dbda8d6ce9 2007-07-21 drh: if( pPg->pgno>nPageCount ){ dbda8d6ce9 2007-07-21 drh: nPage = (pPg->pgno - pg1)+1; dbda8d6ce9 2007-07-21 drh: }else if( (pg1+nPagePerSector-1)>nPageCount ){ dbda8d6ce9 2007-07-21 drh: nPage = nPageCount+1-pg1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nPage = nPagePerSector; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert(nPage>0); dbda8d6ce9 2007-07-21 drh: assert(pg1<=pPg->pgno); dbda8d6ce9 2007-07-21 drh: assert((pg1+nPage)>pPg->pgno); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){ dbda8d6ce9 2007-07-21 drh: Pgno pg = pg1+ii; c287665ba8 2007-09-14 drh: PgHdr *pPage; dbda8d6ce9 2007-07-21 drh: if( !pPager->aInJournal || pg==pPg->pgno || dbda8d6ce9 2007-07-21 drh: pg>pPager->origDbSize || !(pPager->aInJournal[pg/8]&(1<<(pg&7))) dbda8d6ce9 2007-07-21 drh: ) { dbda8d6ce9 2007-07-21 drh: if( pg!=PAGER_MJ_PGNO(pPager) ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pPager, pg, &pPage); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = pager_write(pPage); c287665ba8 2007-09-14 drh: if( pPage->needSync ){ c287665ba8 2007-09-14 drh: needSync = 1; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: }else if( (pPage = pager_lookup(pPager, pg)) ){ c287665ba8 2007-09-14 drh: if( pPage->needSync ){ c287665ba8 2007-09-14 drh: needSync = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* If the PgHdr.needSync flag is set for any of the nPage pages c287665ba8 2007-09-14 drh: ** starting at pg1, then it needs to be set for all of them. Because c287665ba8 2007-09-14 drh: ** writing to any of these nPage pages may damage the others, the c287665ba8 2007-09-14 drh: ** journal file must contain sync()ed copies of all of them c287665ba8 2007-09-14 drh: ** before any of them can be written out to the database file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( needSync ){ c287665ba8 2007-09-14 drh: for(ii=0; ii<nPage && needSync; ii++){ c287665ba8 2007-09-14 drh: PgHdr *pPage = pager_lookup(pPager, pg1+ii); c287665ba8 2007-09-14 drh: if( pPage ) pPage->needSync = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert(pPager->needSync); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPager->doNotSync==1 ); dbda8d6ce9 2007-07-21 drh: pPager->doNotSync = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = pager_write(pDbPage); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the page given in the argument was previously passed dbda8d6ce9 2007-07-21 drh: ** to sqlite3PagerWrite(). In other words, return TRUE if it is ok dbda8d6ce9 2007-07-21 drh: ** to change the content of the page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){ dbda8d6ce9 2007-07-21 drh: return pPg->dirty; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VACUUM dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Replace the content of a single page with the information in the third dbda8d6ce9 2007-07-21 drh: ** argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void *pData){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pPager, pgno, &pPg); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPg); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: memcpy(sqlite3PagerGetData(pPg), pData, pPager->pageSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPg); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A call to this routine tells the pager that it is not necessary to dbda8d6ce9 2007-07-21 drh: ** write the information on page pPg back to the disk, even though dbda8d6ce9 2007-07-21 drh: ** that page might be marked as dirty. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The overlying software layer calls this routine when all of the data dbda8d6ce9 2007-07-21 drh: ** on the given page is unused. The pager marks the page as clean so dbda8d6ce9 2007-07-21 drh: ** that it does not get written to disk. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Tests show that this optimization, together with the dbda8d6ce9 2007-07-21 drh: ** sqlite3PagerDontRollback() below, more than double the speed dbda8d6ce9 2007-07-21 drh: ** of large INSERT operations and quadruple the speed of large DELETEs. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When this routine is called, set the alwaysRollback flag to true. dbda8d6ce9 2007-07-21 drh: ** Subsequent calls to sqlite3PagerDontRollback() for the same page dbda8d6ce9 2007-07-21 drh: ** will thereafter be ignored. This is necessary to avoid a problem dbda8d6ce9 2007-07-21 drh: ** where a page with data is added to the freelist during one part of dbda8d6ce9 2007-07-21 drh: ** a transaction then removed from the freelist during a later part dbda8d6ce9 2007-07-21 drh: ** of the same transaction and reused for some other purpose. When it dbda8d6ce9 2007-07-21 drh: ** is first added to the freelist, this routine is called. When reused, dbda8d6ce9 2007-07-21 drh: ** the sqlite3PagerDontRollback() routine is called. But because the dbda8d6ce9 2007-07-21 drh: ** page contains critical data, we still need to be sure it gets dbda8d6ce9 2007-07-21 drh: ** rolled back in spite of the sqlite3PagerDontRollback() call. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage *pDbPage){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg = pDbPage; dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( MEMDB ) return; c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: pPg->alwaysRollback = 1; dbda8d6ce9 2007-07-21 drh: if( pPg->dirty && !pPager->stmtInUse ){ dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_SHARED ); dbda8d6ce9 2007-07-21 drh: if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){ dbda8d6ce9 2007-07-21 drh: /* If this pages is the last page in the file and the file has grown dbda8d6ce9 2007-07-21 drh: ** during the current transaction, then do NOT mark the page as clean. dbda8d6ce9 2007-07-21 drh: ** When the database file grows, we must make sure that the last page dbda8d6ce9 2007-07-21 drh: ** gets written at least once so that the disk file will be the correct dbda8d6ce9 2007-07-21 drh: ** size. If you do not write this page and the size of the file dbda8d6ce9 2007-07-21 drh: ** on the disk ends up being too small, that can lead to database dbda8d6ce9 2007-07-21 drh: ** corruption during the next transaction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: PAGERTRACE3("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno)) dbda8d6ce9 2007-07-21 drh: makeClean(pPg); dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_CHECK_PAGES dbda8d6ce9 2007-07-21 drh: pPg->pageHash = pager_pagehash(pPg); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A call to this routine tells the pager that if a rollback occurs, dbda8d6ce9 2007-07-21 drh: ** it is not necessary to restore the data on the given page. This dbda8d6ce9 2007-07-21 drh: ** means that the pager does not have to record the given page in the dbda8d6ce9 2007-07-21 drh: ** rollback journal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If we have not yet actually read the content of this page (if dbda8d6ce9 2007-07-21 drh: ** the PgHdr.needRead flag is set) then this routine acts as a promise dbda8d6ce9 2007-07-21 drh: ** that we will never need to read the page content in the future. dbda8d6ce9 2007-07-21 drh: ** so the needRead flag can be cleared at this point. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerDontRollback(DbPage *pPg){ dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_RESERVED ); dbda8d6ce9 2007-07-21 drh: if( pPager->journalOpen==0 ) return; dbda8d6ce9 2007-07-21 drh: if( pPg->alwaysRollback || pPager->alwaysRollback || MEMDB ) return; dbda8d6ce9 2007-07-21 drh: if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){ dbda8d6ce9 2007-07-21 drh: assert( pPager->aInJournal!=0 ); dbda8d6ce9 2007-07-21 drh: pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); dbda8d6ce9 2007-07-21 drh: pPg->inJournal = 1; dbda8d6ce9 2007-07-21 drh: pPg->needRead = 0; dbda8d6ce9 2007-07-21 drh: if( pPager->stmtInUse ){ dbda8d6ce9 2007-07-21 drh: pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno)) dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->stmtInUse dbda8d6ce9 2007-07-21 drh: && !pageInStatement(pPg) dbda8d6ce9 2007-07-21 drh: && (int)pPg->pgno<=pPager->stmtSize dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize ); dbda8d6ce9 2007-07-21 drh: assert( pPager->aInStmt!=0 ); dbda8d6ce9 2007-07-21 drh: pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called to increment the database file change-counter, dbda8d6ce9 2007-07-21 drh: ** stored at byte 24 of the pager file. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int pager_incr_changecounter(Pager *pPager, int isDirect){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPgHdr; dbda8d6ce9 2007-07-21 drh: u32 change_counter; c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pPager->changeCountDone ){ dbda8d6ce9 2007-07-21 drh: /* Open page 1 of the file for writing. */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pPager, 1, &pPgHdr); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( !isDirect ){ c287665ba8 2007-09-14 drh: rc = sqlite3PagerWrite(pPgHdr); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ) return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Increment the value just read and write it back to byte 24. */ d8590e093f 2007-07-24 drh: change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers); dbda8d6ce9 2007-07-21 drh: change_counter++; dbda8d6ce9 2007-07-21 drh: put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( isDirect && pPager->fd->pMethods ){ c287665ba8 2007-09-14 drh: const void *zBuf = PGHDR_TO_DATA(pPgHdr); c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* Release the page reference. */ dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPgHdr); dbda8d6ce9 2007-07-21 drh: pPager->changeCountDone = 1; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Sync the database file for the pager pPager. zMaster points to the name dbda8d6ce9 2007-07-21 drh: ** of a master journal file that should be written into the individual dbda8d6ce9 2007-07-21 drh: ** journal file. zMaster may be NULL, which is interpreted as no master dbda8d6ce9 2007-07-21 drh: ** journal (a single database transaction). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine ensures that the journal is synced, all dirty pages written dbda8d6ce9 2007-07-21 drh: ** to the database file and the database file synced. The only thing that dbda8d6ce9 2007-07-21 drh: ** remains to commit the transaction is to delete the journal file (or dbda8d6ce9 2007-07-21 drh: ** master journal file if specified). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that if zMaster==NULL, this does not overwrite a previous value dbda8d6ce9 2007-07-21 drh: ** passed to an sqlite3PagerCommitPhaseOne() call. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If parameter nTrunc is non-zero, then the pager file is truncated to dbda8d6ce9 2007-07-21 drh: ** nTrunc pages (this is used by auto-vacuum databases). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n", dbda8d6ce9 2007-07-21 drh: pPager->zFilename, zMaster, nTrunc); c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is an in-memory db, or no pages have been written to, or this dbda8d6ce9 2007-07-21 drh: ** function has already been called, it is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_ATOMIC_WRITE c287665ba8 2007-09-14 drh: /* The atomic-write optimization can be used if all of the c287665ba8 2007-09-14 drh: ** following are true: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** + The file-system supports the atomic-write property for c287665ba8 2007-09-14 drh: ** blocks of size page-size, and c287665ba8 2007-09-14 drh: ** + This commit is not part of a multi-file transaction, and c287665ba8 2007-09-14 drh: ** + Exactly one page has been modified and store in the journal file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If the optimization can be used, then the journal file will never c287665ba8 2007-09-14 drh: ** be created for this transaction. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: int useAtomicWrite = ( c287665ba8 2007-09-14 drh: !zMaster && c287665ba8 2007-09-14 drh: pPager->journalOff==jrnlBufferSize(pPager) && c287665ba8 2007-09-14 drh: nTrunc==0 && c287665ba8 2007-09-14 drh: (0==pPager->pDirty || 0==pPager->pDirty->pDirty) c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: if( useAtomicWrite ){ c287665ba8 2007-09-14 drh: /* Update the nRec field in the journal file. */ c287665ba8 2007-09-14 drh: int offset = pPager->journalHdr + sizeof(aJournalMagic); c287665ba8 2007-09-14 drh: assert(pPager->nRec==1); c287665ba8 2007-09-14 drh: rc = write32bits(pPager->jfd, offset, pPager->nRec); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Update the db file change counter. The following call will modify c287665ba8 2007-09-14 drh: ** the in-memory representation of page 1 to include the updated c287665ba8 2007-09-14 drh: ** change counter and then write page 1 directly to the database c287665ba8 2007-09-14 drh: ** file. Because of the atomic-write property of the host file-system, c287665ba8 2007-09-14 drh: ** this is safe. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: rc = pager_incr_changecounter(pPager, 1); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: rc = sqlite3JournalCreate(pPager->jfd); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ) goto sync_exit; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( !useAtomicWrite ) c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a master journal file name has already been written to the dbda8d6ce9 2007-07-21 drh: ** journal file, then no sync is required. This happens when it is dbda8d6ce9 2007-07-21 drh: ** written, then the process fails to upgrade from a RESERVED to an dbda8d6ce9 2007-07-21 drh: ** EXCLUSIVE lock. The next time the process tries to commit the dbda8d6ce9 2007-07-21 drh: ** transaction the m-j name will have already been written. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !pPager->setMaster ){ c287665ba8 2007-09-14 drh: assert( pPager->journalOpen ); c287665ba8 2007-09-14 drh: rc = pager_incr_changecounter(pPager, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto sync_exit; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( nTrunc!=0 ){ dbda8d6ce9 2007-07-21 drh: /* If this transaction has made the database smaller, then all pages dbda8d6ce9 2007-07-21 drh: ** being discarded by the truncation must be written to the journal dbda8d6ce9 2007-07-21 drh: ** file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: Pgno i; dbda8d6ce9 2007-07-21 drh: int iSkip = PAGER_MJ_PGNO(pPager); dbda8d6ce9 2007-07-21 drh: for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){ dbda8d6ce9 2007-07-21 drh: if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pPager, i, &pPg); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto sync_exit; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPg); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPg); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto sync_exit; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: rc = writeMasterJournal(pPager, zMaster); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto sync_exit; dbda8d6ce9 2007-07-21 drh: rc = syncJournal(pPager); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ) goto sync_exit; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( nTrunc!=0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerTruncate(pPager, nTrunc); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto sync_exit; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Write all dirty pages to the database file */ dbda8d6ce9 2007-07-21 drh: pPg = pager_get_all_dirty_pages(pPager); dbda8d6ce9 2007-07-21 drh: rc = pager_write_pagelist(pPg); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: while( pPg && !pPg->dirty ){ pPg = pPg->pDirty; } c287665ba8 2007-09-14 drh: pPager->pDirty = pPg; c287665ba8 2007-09-14 drh: goto sync_exit; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: pPager->pDirty = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Sync the database file. */ dbda8d6ce9 2007-07-21 drh: if( !pPager->noSync ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsSync(pPager->fd, pPager->sync_flags); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: IOTRACE(("DBSYNC %p\n", pPager)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_SYNCED; dbda8d6ce9 2007-07-21 drh: }else if( MEMDB && nTrunc!=0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerTruncate(pPager, nTrunc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sync_exit: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_IOERR_BLOCKED ){ dbda8d6ce9 2007-07-21 drh: /* pager_incr_changecounter() may attempt to obtain an exclusive dbda8d6ce9 2007-07-21 drh: * lock to spill the cache and return IOERR_BLOCKED. But since dbda8d6ce9 2007-07-21 drh: * there is no chance the cache is inconsistent, it's dbda8d6ce9 2007-07-21 drh: * better to return SQLITE_BUSY. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Commit all changes to the database and release the write lock. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the commit fails for any reason, a rollback attempt is made dbda8d6ce9 2007-07-21 drh: ** and an error code is returned. If the commit worked, SQLITE_OK dbda8d6ce9 2007-07-21 drh: ** is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->errCode ){ dbda8d6ce9 2007-07-21 drh: return pPager->errCode; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->state<PAGER_RESERVED ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: PAGERTRACE2("COMMIT %d\n", PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: pPg = pager_get_all_dirty_pages(pPager); dbda8d6ce9 2007-07-21 drh: while( pPg ){ dbda8d6ce9 2007-07-21 drh: PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); dbda8d6ce9 2007-07-21 drh: clearHistory(pHist); dbda8d6ce9 2007-07-21 drh: pPg->dirty = 0; dbda8d6ce9 2007-07-21 drh: pPg->inJournal = 0; dbda8d6ce9 2007-07-21 drh: pHist->inStmt = 0; dbda8d6ce9 2007-07-21 drh: pPg->needSync = 0; dbda8d6ce9 2007-07-21 drh: pHist->pPrevStmt = pHist->pNextStmt = 0; dbda8d6ce9 2007-07-21 drh: pPg = pPg->pDirty; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->pDirty = 0; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ dbda8d6ce9 2007-07-21 drh: PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); dbda8d6ce9 2007-07-21 drh: assert( !pPg->alwaysRollback ); dbda8d6ce9 2007-07-21 drh: assert( !pHist->pOrig ); dbda8d6ce9 2007-07-21 drh: assert( !pHist->pStmt ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: pPager->pStmt = 0; dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_SHARED; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOpen || !pPager->dirtyCache ); dbda8d6ce9 2007-07-21 drh: assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache ); dbda8d6ce9 2007-07-21 drh: rc = pager_end_transaction(pPager); c287665ba8 2007-09-14 drh: rc = pager_error(pPager, rc); c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Rollback all changes. The database falls back to PAGER_SHARED mode. dbda8d6ce9 2007-07-21 drh: ** All in-memory cache pages revert to their original data contents. dbda8d6ce9 2007-07-21 drh: ** The journal is deleted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine cannot fail unless some other process is not following dbda8d6ce9 2007-07-21 drh: ** the correct locking protocol or unless some other dbda8d6ce9 2007-07-21 drh: ** process is writing trash into the journal file (SQLITE_CORRUPT) or dbda8d6ce9 2007-07-21 drh: ** unless a prior malloc() failed (SQLITE_NOMEM). Appropriate error dbda8d6ce9 2007-07-21 drh: ** codes are returned for all these occasions. Otherwise, dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: PgHdr *p; dbda8d6ce9 2007-07-21 drh: for(p=pPager->pAll; p; p=p->pNextAll){ dbda8d6ce9 2007-07-21 drh: PgHistory *pHist; dbda8d6ce9 2007-07-21 drh: assert( !p->alwaysRollback ); dbda8d6ce9 2007-07-21 drh: if( !p->dirty ){ dbda8d6ce9 2007-07-21 drh: assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig ); dbda8d6ce9 2007-07-21 drh: assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt ); dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pHist = PGHDR_TO_HIST(p, pPager); dbda8d6ce9 2007-07-21 drh: if( pHist->pOrig ){ dbda8d6ce9 2007-07-21 drh: memcpy(PGHDR_TO_DATA(p), pHist->pOrig, pPager->pageSize); dbda8d6ce9 2007-07-21 drh: PAGERTRACE3("ROLLBACK-PAGE %d of %d\n", p->pgno, PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: PAGERTRACE3("PAGE %d is clean on %d\n", p->pgno, PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: clearHistory(pHist); dbda8d6ce9 2007-07-21 drh: p->dirty = 0; dbda8d6ce9 2007-07-21 drh: p->inJournal = 0; dbda8d6ce9 2007-07-21 drh: pHist->inStmt = 0; dbda8d6ce9 2007-07-21 drh: pHist->pPrevStmt = pHist->pNextStmt = 0; dbda8d6ce9 2007-07-21 drh: if( pPager->xReiniter ){ dbda8d6ce9 2007-07-21 drh: pPager->xReiniter(p, pPager->pageSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->pDirty = 0; dbda8d6ce9 2007-07-21 drh: pPager->pStmt = 0; dbda8d6ce9 2007-07-21 drh: pPager->dbSize = pPager->origDbSize; dbda8d6ce9 2007-07-21 drh: pager_truncate_cache(pPager); dbda8d6ce9 2007-07-21 drh: pPager->stmtInUse = 0; dbda8d6ce9 2007-07-21 drh: pPager->state = PAGER_SHARED; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( !pPager->dirtyCache || !pPager->journalOpen ){ dbda8d6ce9 2007-07-21 drh: rc = pager_end_transaction(pPager); c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ dbda8d6ce9 2007-07-21 drh: if( pPager->state>=PAGER_EXCLUSIVE ){ dbda8d6ce9 2007-07-21 drh: pager_playback(pPager, 0); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return pPager->errCode; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->state==PAGER_RESERVED ){ dbda8d6ce9 2007-07-21 drh: int rc2; dbda8d6ce9 2007-07-21 drh: rc = pager_playback(pPager, 0); dbda8d6ce9 2007-07-21 drh: rc2 = pager_end_transaction(pPager); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = rc2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = pager_playback(pPager, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* pager_reset(pPager); */ dbda8d6ce9 2007-07-21 drh: pPager->dbSize = -1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If an error occurs during a ROLLBACK, we can no longer trust the pager dbda8d6ce9 2007-07-21 drh: ** cache. So call pager_error() on the way out to make any error dbda8d6ce9 2007-07-21 drh: ** persistent. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: rc = pager_error(pPager, rc); c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the database file is opened read-only. Return FALSE dbda8d6ce9 2007-07-21 drh: ** if the database is (in theory) writable. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerIsreadonly(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: return pPager->readOnly; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of references to the pager. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: return pPager->nRef; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is used for testing and analysis only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: static int a[11]; dbda8d6ce9 2007-07-21 drh: a[0] = pPager->nRef; dbda8d6ce9 2007-07-21 drh: a[1] = pPager->nPage; dbda8d6ce9 2007-07-21 drh: a[2] = pPager->mxPage; dbda8d6ce9 2007-07-21 drh: a[3] = pPager->dbSize; dbda8d6ce9 2007-07-21 drh: a[4] = pPager->state; dbda8d6ce9 2007-07-21 drh: a[5] = pPager->errCode; dbda8d6ce9 2007-07-21 drh: a[6] = pPager->nHit; dbda8d6ce9 2007-07-21 drh: a[7] = pPager->nMiss; dbda8d6ce9 2007-07-21 drh: a[8] = 0; /* Used to be pPager->nOvfl */ dbda8d6ce9 2007-07-21 drh: a[9] = pPager->nRead; dbda8d6ce9 2007-07-21 drh: a[10] = pPager->nWrite; dbda8d6ce9 2007-07-21 drh: return a; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the statement rollback point. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine should be called with the transaction journal already dbda8d6ce9 2007-07-21 drh: ** open. A new statement journal is created that can be used to rollback dbda8d6ce9 2007-07-21 drh: ** changes of a single SQL command within a larger transaction. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int pagerStmtBegin(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( !pPager->stmtInUse ); dbda8d6ce9 2007-07-21 drh: assert( pPager->state>=PAGER_SHARED ); dbda8d6ce9 2007-07-21 drh: assert( pPager->dbSize>=0 ); dbda8d6ce9 2007-07-21 drh: PAGERTRACE2("STMT-BEGIN %d\n", PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: pPager->stmtInUse = 1; dbda8d6ce9 2007-07-21 drh: pPager->stmtSize = pPager->dbSize; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pPager->journalOpen ){ dbda8d6ce9 2007-07-21 drh: pPager->stmtAutoopen = 1; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pPager->journalOpen ); c287665ba8 2007-09-14 drh: pagerLeave(pPager); c287665ba8 2007-09-14 drh: pPager->aInStmt = sqlite3MallocZero( pPager->dbSize/8 + 1 ); c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->aInStmt==0 ){ dbda8d6ce9 2007-07-21 drh: /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize); dbda8d6ce9 2007-07-21 drh: if( rc ) goto stmt_begin_failed; dbda8d6ce9 2007-07-21 drh: assert( pPager->stmtJSize == pPager->journalOff ); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: pPager->stmtJSize = pPager->journalOff; dbda8d6ce9 2007-07-21 drh: pPager->stmtSize = pPager->dbSize; dbda8d6ce9 2007-07-21 drh: pPager->stmtHdrOff = 0; dbda8d6ce9 2007-07-21 drh: pPager->stmtCksum = pPager->cksumInit; dbda8d6ce9 2007-07-21 drh: if( !pPager->stmtOpen ){ c287665ba8 2007-09-14 drh: rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->stfd, pPager->zStmtJrnl, c287665ba8 2007-09-14 drh: SQLITE_OPEN_SUBJOURNAL); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: goto stmt_begin_failed; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: pPager->stmtOpen = 1; dbda8d6ce9 2007-07-21 drh: pPager->stmtNRec = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->stmtInUse = 1; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: stmt_begin_failed: dbda8d6ce9 2007-07-21 drh: if( pPager->aInStmt ){ c287665ba8 2007-09-14 drh: sqlite3_free(pPager->aInStmt); dbda8d6ce9 2007-07-21 drh: pPager->aInStmt = 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3PagerStmtBegin(Pager *pPager){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: pagerEnter(pPager); c287665ba8 2007-09-14 drh: rc = pagerStmtBegin(pPager); c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Commit a statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerStmtCommit(Pager *pPager){ c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->stmtInUse ){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg, *pNext; dbda8d6ce9 2007-07-21 drh: PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: if( !MEMDB ){ dbda8d6ce9 2007-07-21 drh: /* sqlite3OsTruncate(pPager->stfd, 0); */ c287665ba8 2007-09-14 drh: sqlite3_free( pPager->aInStmt ); dbda8d6ce9 2007-07-21 drh: pPager->aInStmt = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pStmt; pPg; pPg=pNext){ dbda8d6ce9 2007-07-21 drh: PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); dbda8d6ce9 2007-07-21 drh: pNext = pHist->pNextStmt; dbda8d6ce9 2007-07-21 drh: assert( pHist->inStmt ); dbda8d6ce9 2007-07-21 drh: pHist->inStmt = 0; dbda8d6ce9 2007-07-21 drh: pHist->pPrevStmt = pHist->pNextStmt = 0; c287665ba8 2007-09-14 drh: sqlite3_free(pHist->pStmt); dbda8d6ce9 2007-07-21 drh: pHist->pStmt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->stmtNRec = 0; dbda8d6ce9 2007-07-21 drh: pPager->stmtInUse = 0; dbda8d6ce9 2007-07-21 drh: pPager->pStmt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->stmtAutoopen = 0; c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Rollback a statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerStmtRollback(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: if( pPager->stmtInUse ){ dbda8d6ce9 2007-07-21 drh: PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager)); dbda8d6ce9 2007-07-21 drh: if( MEMDB ){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: PgHistory *pHist; dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pStmt; pPg; pPg=pHist->pNextStmt){ dbda8d6ce9 2007-07-21 drh: pHist = PGHDR_TO_HIST(pPg, pPager); dbda8d6ce9 2007-07-21 drh: if( pHist->pStmt ){ dbda8d6ce9 2007-07-21 drh: memcpy(PGHDR_TO_DATA(pPg), pHist->pStmt, pPager->pageSize); c287665ba8 2007-09-14 drh: sqlite3_free(pHist->pStmt); dbda8d6ce9 2007-07-21 drh: pHist->pStmt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->dbSize = pPager->stmtSize; dbda8d6ce9 2007-07-21 drh: pager_truncate_cache(pPager); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = pager_stmt_playback(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3PagerStmtCommit(pPager); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager->stmtAutoopen = 0; c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the full pathname of the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: return pPager->zFilename; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return the VFS structure for the pager. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){ c287665ba8 2007-09-14 drh: return pPager->pVfs; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return the file handle for the database file associated c287665ba8 2007-09-14 drh: ** with the pager. This might return NULL if the file has c287665ba8 2007-09-14 drh: ** not yet been opened. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){ c287665ba8 2007-09-14 drh: return pPager->fd; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the directory of the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3PagerDirname(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: return pPager->zDirectory; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the full pathname of the journal file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: return pPager->zJournal; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return true if fsync() calls are disabled for this pager. Return FALSE dbda8d6ce9 2007-07-21 drh: ** if fsync()s are executed normally. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: return pPager->noSync; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_HAS_CODEC dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the codec for this pager dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerSetCodec( dbda8d6ce9 2007-07-21 drh: Pager *pPager, dbda8d6ce9 2007-07-21 drh: void *(*xCodec)(void*,void*,Pgno,int), dbda8d6ce9 2007-07-21 drh: void *pCodecArg dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: pPager->xCodec = xCodec; dbda8d6ce9 2007-07-21 drh: pPager->pCodecArg = pCodecArg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move the page pPg to location pgno in the file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There must be no references to the page previously located at dbda8d6ce9 2007-07-21 drh: ** pgno (which we call pPgOld) though that page is allowed to be dbda8d6ce9 2007-07-21 drh: ** in cache. If the page previous located at pgno is not already dbda8d6ce9 2007-07-21 drh: ** in the rollback journal, it is not put there by by this routine. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** References to the page pPg remain valid. Updating any dbda8d6ce9 2007-07-21 drh: ** meta-data associated with pPg (i.e. data stored in the nExtra bytes dbda8d6ce9 2007-07-21 drh: ** allocated along with the page) is the responsibility of the caller. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A transaction must be active when this routine is called. It used to be dbda8d6ce9 2007-07-21 drh: ** required that a statement transaction was not active, but this restriction dbda8d6ce9 2007-07-21 drh: ** has been removed (CREATE INDEX needs to move a page when a statement dbda8d6ce9 2007-07-21 drh: ** transaction is active). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPgOld; /* The page being overwritten. */ dbda8d6ce9 2007-07-21 drh: int h; dbda8d6ce9 2007-07-21 drh: Pgno needSyncPgno = 0; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pagerEnter(pPager); dbda8d6ce9 2007-07-21 drh: assert( pPg->nRef>0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: PAGERTRACE5("MOVE %d page %d (needSync=%d) moves to %d\n", dbda8d6ce9 2007-07-21 drh: PAGERID(pPager), pPg->pgno, pPg->needSync, pgno); dbda8d6ce9 2007-07-21 drh: IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pager_get_content(pPg); dbda8d6ce9 2007-07-21 drh: if( pPg->needSync ){ dbda8d6ce9 2007-07-21 drh: needSyncPgno = pPg->pgno; dbda8d6ce9 2007-07-21 drh: assert( pPg->inJournal || (int)pgno>pPager->origDbSize ); dbda8d6ce9 2007-07-21 drh: assert( pPg->dirty ); dbda8d6ce9 2007-07-21 drh: assert( pPager->needSync ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Unlink pPg from it's hash-chain */ dbda8d6ce9 2007-07-21 drh: unlinkHashChain(pPager, pPg); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the cache contains a page with page-number pgno, remove it dbda8d6ce9 2007-07-21 drh: ** from it's hash chain. Also, if the PgHdr.needSync was set for dbda8d6ce9 2007-07-21 drh: ** page pgno before the 'move' operation, it needs to be retained dbda8d6ce9 2007-07-21 drh: ** for the page moved there. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pPg->needSync = 0; dbda8d6ce9 2007-07-21 drh: pPgOld = pager_lookup(pPager, pgno); dbda8d6ce9 2007-07-21 drh: if( pPgOld ){ dbda8d6ce9 2007-07-21 drh: assert( pPgOld->nRef==0 ); dbda8d6ce9 2007-07-21 drh: unlinkHashChain(pPager, pPgOld); dbda8d6ce9 2007-07-21 drh: makeClean(pPgOld); dbda8d6ce9 2007-07-21 drh: pPg->needSync = pPgOld->needSync; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pPg->needSync = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ dbda8d6ce9 2007-07-21 drh: pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pPg->inJournal = 0; dbda8d6ce9 2007-07-21 drh: assert( pPg->needSync==0 || (int)pgno>pPager->origDbSize ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Change the page number for pPg and insert it into the new hash-chain. */ dbda8d6ce9 2007-07-21 drh: assert( pgno!=0 ); dbda8d6ce9 2007-07-21 drh: pPg->pgno = pgno; dbda8d6ce9 2007-07-21 drh: h = pgno & (pPager->nHash-1); dbda8d6ce9 2007-07-21 drh: if( pPager->aHash[h] ){ dbda8d6ce9 2007-07-21 drh: assert( pPager->aHash[h]->pPrevHash==0 ); dbda8d6ce9 2007-07-21 drh: pPager->aHash[h]->pPrevHash = pPg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPg->pNextHash = pPager->aHash[h]; dbda8d6ce9 2007-07-21 drh: pPager->aHash[h] = pPg; dbda8d6ce9 2007-07-21 drh: pPg->pPrevHash = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: makeDirty(pPg); dbda8d6ce9 2007-07-21 drh: pPager->dirtyCache = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( needSyncPgno ){ dbda8d6ce9 2007-07-21 drh: /* If needSyncPgno is non-zero, then the journal file needs to be dbda8d6ce9 2007-07-21 drh: ** sync()ed before any data is written to database file page needSyncPgno. dbda8d6ce9 2007-07-21 drh: ** Currently, no such page exists in the page-cache and the dbda8d6ce9 2007-07-21 drh: ** Pager.aInJournal bit has been set. This needs to be remedied by loading dbda8d6ce9 2007-07-21 drh: ** the page into the pager-cache and setting the PgHdr.needSync flag. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3PagerGet() call may cause the journal to sync. So make dbda8d6ce9 2007-07-21 drh: ** sure the Pager.needSync flag is set too. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: PgHdr *pPgHdr; dbda8d6ce9 2007-07-21 drh: assert( pPager->needSync ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: pPager->needSync = 1; dbda8d6ce9 2007-07-21 drh: pPgHdr->needSync = 1; dbda8d6ce9 2007-07-21 drh: pPgHdr->inJournal = 1; dbda8d6ce9 2007-07-21 drh: makeDirty(pPgHdr); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPgHdr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pagerLeave(pPager); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a pointer to the data for the specified page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){ dbda8d6ce9 2007-07-21 drh: return PGHDR_TO_DATA(pPg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a pointer to the Pager.nExtra bytes of "extra" space dbda8d6ce9 2007-07-21 drh: ** allocated along with the specified page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){ dbda8d6ce9 2007-07-21 drh: Pager *pPager = pPg->pPager; dbda8d6ce9 2007-07-21 drh: return (pPager?PGHDR_TO_EXTRA(pPg, pPager):0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Get/set the locking-mode for this pager. Parameter eMode must be one dbda8d6ce9 2007-07-21 drh: ** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or dbda8d6ce9 2007-07-21 drh: ** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then dbda8d6ce9 2007-07-21 drh: ** the locking-mode is set to the value specified. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The returned value is either PAGER_LOCKINGMODE_NORMAL or dbda8d6ce9 2007-07-21 drh: ** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated) dbda8d6ce9 2007-07-21 drh: ** locking-mode. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){ dbda8d6ce9 2007-07-21 drh: assert( eMode==PAGER_LOCKINGMODE_QUERY dbda8d6ce9 2007-07-21 drh: || eMode==PAGER_LOCKINGMODE_NORMAL dbda8d6ce9 2007-07-21 drh: || eMode==PAGER_LOCKINGMODE_EXCLUSIVE ); dbda8d6ce9 2007-07-21 drh: assert( PAGER_LOCKINGMODE_QUERY<0 ); dbda8d6ce9 2007-07-21 drh: assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 ); dbda8d6ce9 2007-07-21 drh: if( eMode>=0 && !pPager->tempFile ){ dbda8d6ce9 2007-07-21 drh: pPager->exclusiveMode = eMode; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return (int)pPager->exclusiveMode; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print a listing of all referenced pages and their ref count. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PagerRefdump(Pager *pPager){ dbda8d6ce9 2007-07-21 drh: PgHdr *pPg; dbda8d6ce9 2007-07-21 drh: for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ dbda8d6ce9 2007-07-21 drh: if( pPg->nRef<=0 ) continue; dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("PAGE %3d addr=%p nRef=%d\n", dbda8d6ce9 2007-07-21 drh: pPg->pgno, PGHDR_TO_DATA(pPg), pPg->nRef); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_DISKIO */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of pager.c ***********************************************/ c287665ba8 2007-09-14 drh: /************** Begin file btmutex.c *****************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 27 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: btmutex.c,v 1.7 2007/08/30 01:19:59 drh Exp $ c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This file contains code used to implement mutexes on Btree objects. c287665ba8 2007-09-14 drh: ** This code really belongs in btree.c. But btree.c is getting too c287665ba8 2007-09-14 drh: ** big and we want to break it down some. This packaged seemed like c287665ba8 2007-09-14 drh: ** a good breakout. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: /************** Include btreeInt.h in the middle of btmutex.c ****************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file btreeInt.h ****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 April 6 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** $Id: btreeInt.h,v 1.13 2007/08/30 01:19:59 drh Exp $ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file implements a external (disk-based) database using BTrees. dbda8d6ce9 2007-07-21 drh: ** For a detailed discussion of BTrees, refer to dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: dbda8d6ce9 2007-07-21 drh: ** "Sorting And Searching", pages 473-480. Addison-Wesley dbda8d6ce9 2007-07-21 drh: ** Publishing Company, Reading, Massachusetts. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The basic idea is that each page of the file contains N database dbda8d6ce9 2007-07-21 drh: ** entries and N+1 pointers to subpages. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ---------------------------------------------------------------- dbda8d6ce9 2007-07-21 drh: ** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) | dbda8d6ce9 2007-07-21 drh: ** ---------------------------------------------------------------- dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All of the keys on the page that Ptr(0) points to have values less dbda8d6ce9 2007-07-21 drh: ** than Key(0). All of the keys on page Ptr(1) and its subpages have dbda8d6ce9 2007-07-21 drh: ** values greater than Key(0) and less than Key(1). All of the keys dbda8d6ce9 2007-07-21 drh: ** on Ptr(N) and its subpages have values greater than Key(N-1). And dbda8d6ce9 2007-07-21 drh: ** so forth. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Finding a particular key requires reading O(log(M)) pages from the dbda8d6ce9 2007-07-21 drh: ** disk where M is the number of entries in the tree. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In this implementation, a single file can hold one or more separate dbda8d6ce9 2007-07-21 drh: ** BTrees. Each BTree is identified by the index of its root page. The dbda8d6ce9 2007-07-21 drh: ** key and data for any entry are combined to form the "payload". A dbda8d6ce9 2007-07-21 drh: ** fixed amount of payload can be carried directly on the database dbda8d6ce9 2007-07-21 drh: ** page. If the payload is larger than the preset amount then surplus dbda8d6ce9 2007-07-21 drh: ** bytes are stored on overflow pages. The payload for an entry dbda8d6ce9 2007-07-21 drh: ** and the preceding pointer are combined to form a "Cell". Each dbda8d6ce9 2007-07-21 drh: ** page has a small header which contains the Ptr(N) pointer and other dbda8d6ce9 2007-07-21 drh: ** information such as the size of key and data. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** FORMAT DETAILS dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The file is divided into pages. The first page is called page 1, dbda8d6ce9 2007-07-21 drh: ** the second is page 2, and so forth. A page number of zero indicates dbda8d6ce9 2007-07-21 drh: ** "no such page". The page size can be anything between 512 and 65536. dbda8d6ce9 2007-07-21 drh: ** Each page can be either a btree page, a freelist page or an overflow dbda8d6ce9 2007-07-21 drh: ** page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first page is always a btree page. The first 100 bytes of the first dbda8d6ce9 2007-07-21 drh: ** page contain a special header (the "file header") that describes the file. dbda8d6ce9 2007-07-21 drh: ** The format of the file header is as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** OFFSET SIZE DESCRIPTION dbda8d6ce9 2007-07-21 drh: ** 0 16 Header string: "SQLite format 3\000" dbda8d6ce9 2007-07-21 drh: ** 16 2 Page size in bytes. dbda8d6ce9 2007-07-21 drh: ** 18 1 File format write version dbda8d6ce9 2007-07-21 drh: ** 19 1 File format read version dbda8d6ce9 2007-07-21 drh: ** 20 1 Bytes of unused space at the end of each page dbda8d6ce9 2007-07-21 drh: ** 21 1 Max embedded payload fraction dbda8d6ce9 2007-07-21 drh: ** 22 1 Min embedded payload fraction dbda8d6ce9 2007-07-21 drh: ** 23 1 Min leaf payload fraction dbda8d6ce9 2007-07-21 drh: ** 24 4 File change counter dbda8d6ce9 2007-07-21 drh: ** 28 4 Reserved for future use dbda8d6ce9 2007-07-21 drh: ** 32 4 First freelist page dbda8d6ce9 2007-07-21 drh: ** 36 4 Number of freelist pages in the file dbda8d6ce9 2007-07-21 drh: ** 40 60 15 4-byte meta values passed to higher layers dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All of the integer values are big-endian (most significant byte first). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The file change counter is incremented when the database is changed dbda8d6ce9 2007-07-21 drh: ** This counter allows other processes to know when the file has changed dbda8d6ce9 2007-07-21 drh: ** and thus when they need to flush their cache. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The max embedded payload fraction is the amount of the total usable dbda8d6ce9 2007-07-21 drh: ** space in a page that can be consumed by a single cell for standard dbda8d6ce9 2007-07-21 drh: ** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default dbda8d6ce9 2007-07-21 drh: ** is to limit the maximum cell size so that at least 4 cells will fit dbda8d6ce9 2007-07-21 drh: ** on one page. Thus the default max embedded payload fraction is 64. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the payload for a cell is larger than the max payload, then extra dbda8d6ce9 2007-07-21 drh: ** payload is spilled to overflow pages. Once an overflow page is allocated, dbda8d6ce9 2007-07-21 drh: ** as many bytes as possible are moved into the overflow pages without letting dbda8d6ce9 2007-07-21 drh: ** the cell size drop below the min embedded payload fraction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The min leaf payload fraction is like the min embedded payload fraction dbda8d6ce9 2007-07-21 drh: ** except that it applies to leaf nodes in a LEAFDATA tree. The maximum dbda8d6ce9 2007-07-21 drh: ** payload fraction for a LEAFDATA tree is always 100% (or 255) and it dbda8d6ce9 2007-07-21 drh: ** not specified in the header. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each btree pages is divided into three sections: The header, the dbda8d6ce9 2007-07-21 drh: ** cell pointer array, and the cell content area. Page 1 also has a 100-byte dbda8d6ce9 2007-07-21 drh: ** file header that occurs before the page header. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** |----------------| dbda8d6ce9 2007-07-21 drh: ** | file header | 100 bytes. Page 1 only. dbda8d6ce9 2007-07-21 drh: ** |----------------| dbda8d6ce9 2007-07-21 drh: ** | page header | 8 bytes for leaves. 12 bytes for interior nodes dbda8d6ce9 2007-07-21 drh: ** |----------------| dbda8d6ce9 2007-07-21 drh: ** | cell pointer | | 2 bytes per cell. Sorted order. dbda8d6ce9 2007-07-21 drh: ** | array | | Grows downward dbda8d6ce9 2007-07-21 drh: ** | | v dbda8d6ce9 2007-07-21 drh: ** |----------------| dbda8d6ce9 2007-07-21 drh: ** | unallocated | dbda8d6ce9 2007-07-21 drh: ** | space | dbda8d6ce9 2007-07-21 drh: ** |----------------| ^ Grows upwards dbda8d6ce9 2007-07-21 drh: ** | cell content | | Arbitrary order interspersed with freeblocks. dbda8d6ce9 2007-07-21 drh: ** | area | | and free space fragments. dbda8d6ce9 2007-07-21 drh: ** |----------------| dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The page headers looks like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** OFFSET SIZE DESCRIPTION dbda8d6ce9 2007-07-21 drh: ** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf dbda8d6ce9 2007-07-21 drh: ** 1 2 byte offset to the first freeblock dbda8d6ce9 2007-07-21 drh: ** 3 2 number of cells on this page dbda8d6ce9 2007-07-21 drh: ** 5 2 first byte of the cell content area dbda8d6ce9 2007-07-21 drh: ** 7 1 number of fragmented free bytes dbda8d6ce9 2007-07-21 drh: ** 8 4 Right child (the Ptr(N) value). Omitted on leaves. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The flags define the format of this btree page. The leaf flag means that dbda8d6ce9 2007-07-21 drh: ** this page has no children. The zerodata flag means that this page carries dbda8d6ce9 2007-07-21 drh: ** only keys and no data. The intkey flag means that the key is a integer dbda8d6ce9 2007-07-21 drh: ** which is stored in the key size entry of the cell header rather than in dbda8d6ce9 2007-07-21 drh: ** the payload area. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The cell pointer array begins on the first byte after the page header. dbda8d6ce9 2007-07-21 drh: ** The cell pointer array contains zero or more 2-byte numbers which are dbda8d6ce9 2007-07-21 drh: ** offsets from the beginning of the page to the cell content in the cell dbda8d6ce9 2007-07-21 drh: ** content area. The cell pointers occur in sorted order. The system strives dbda8d6ce9 2007-07-21 drh: ** to keep free space after the last cell pointer so that new cells can dbda8d6ce9 2007-07-21 drh: ** be easily added without having to defragment the page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Cell content is stored at the very end of the page and grows toward the dbda8d6ce9 2007-07-21 drh: ** beginning of the page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Unused space within the cell content area is collected into a linked list of dbda8d6ce9 2007-07-21 drh: ** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset dbda8d6ce9 2007-07-21 drh: ** to the first freeblock is given in the header. Freeblocks occur in dbda8d6ce9 2007-07-21 drh: ** increasing order. Because a freeblock must be at least 4 bytes in size, dbda8d6ce9 2007-07-21 drh: ** any group of 3 or fewer unused bytes in the cell content area cannot dbda8d6ce9 2007-07-21 drh: ** exist on the freeblock chain. A group of 3 or fewer free bytes is called dbda8d6ce9 2007-07-21 drh: ** a fragment. The total number of bytes in all fragments is recorded. dbda8d6ce9 2007-07-21 drh: ** in the page header at offset 7. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SIZE DESCRIPTION dbda8d6ce9 2007-07-21 drh: ** 2 Byte offset of the next freeblock dbda8d6ce9 2007-07-21 drh: ** 2 Bytes in this freeblock dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Cells are of variable length. Cells are stored in the cell content area at dbda8d6ce9 2007-07-21 drh: ** the end of the page. Pointers to the cells are in the cell pointer array dbda8d6ce9 2007-07-21 drh: ** that immediately follows the page header. Cells is not necessarily dbda8d6ce9 2007-07-21 drh: ** contiguous or in order, but cell pointers are contiguous and in order. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Cell content makes use of variable length integers. A variable dbda8d6ce9 2007-07-21 drh: ** length integer is 1 to 9 bytes where the lower 7 bits of each dbda8d6ce9 2007-07-21 drh: ** byte are used. The integer consists of all bytes that have bit 8 set and dbda8d6ce9 2007-07-21 drh: ** the first byte with bit 8 clear. The most significant byte of the integer dbda8d6ce9 2007-07-21 drh: ** appears first. A variable-length integer may not be more than 9 bytes long. dbda8d6ce9 2007-07-21 drh: ** As a special case, all 8 bytes of the 9th byte are used as data. This dbda8d6ce9 2007-07-21 drh: ** allows a 64-bit integer to be encoded in 9 bytes. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 0x00 becomes 0x00000000 dbda8d6ce9 2007-07-21 drh: ** 0x7f becomes 0x0000007f dbda8d6ce9 2007-07-21 drh: ** 0x81 0x00 becomes 0x00000080 dbda8d6ce9 2007-07-21 drh: ** 0x82 0x00 becomes 0x00000100 dbda8d6ce9 2007-07-21 drh: ** 0x80 0x7f becomes 0x0000007f dbda8d6ce9 2007-07-21 drh: ** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678 dbda8d6ce9 2007-07-21 drh: ** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Variable length integers are used for rowids and to hold the number of dbda8d6ce9 2007-07-21 drh: ** bytes of key and data in a btree cell. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The content of a cell looks like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SIZE DESCRIPTION dbda8d6ce9 2007-07-21 drh: ** 4 Page number of the left child. Omitted if leaf flag is set. dbda8d6ce9 2007-07-21 drh: ** var Number of bytes of data. Omitted if the zerodata flag is set. dbda8d6ce9 2007-07-21 drh: ** var Number of bytes of key. Or the key itself if intkey flag is set. dbda8d6ce9 2007-07-21 drh: ** * Payload dbda8d6ce9 2007-07-21 drh: ** 4 First page of the overflow chain. Omitted if no overflow dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Overflow pages form a linked list. Each page except the last is completely dbda8d6ce9 2007-07-21 drh: ** filled with data (pagesize - 4 bytes). The last page can have as little dbda8d6ce9 2007-07-21 drh: ** as 1 byte of data. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SIZE DESCRIPTION dbda8d6ce9 2007-07-21 drh: ** 4 Page number of next overflow page dbda8d6ce9 2007-07-21 drh: ** * Data dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Freelist pages come in two subtypes: trunk pages and leaf pages. The dbda8d6ce9 2007-07-21 drh: ** file header points to the first in a linked list of trunk page. Each trunk dbda8d6ce9 2007-07-21 drh: ** page points to multiple leaf pages. The content of a leaf page is dbda8d6ce9 2007-07-21 drh: ** unspecified. A trunk page looks like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SIZE DESCRIPTION dbda8d6ce9 2007-07-21 drh: ** 4 Page number of next trunk page dbda8d6ce9 2007-07-21 drh: ** 4 Number of leaf pointers on this page dbda8d6ce9 2007-07-21 drh: ** * zero or more pages numbers of leaves dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Round up a number to the next larger multiple of 8. This is used dbda8d6ce9 2007-07-21 drh: ** to force 8-byte alignment on 64-bit architectures. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define ROUND8(x) ((x+7)&~7) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following value is the maximum cell size assuming a maximum page dbda8d6ce9 2007-07-21 drh: ** size give above. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define MX_CELL_SIZE(pBt) (pBt->pageSize-8) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The maximum number of cells on a single page of the database. This dbda8d6ce9 2007-07-21 drh: ** assumes a minimum cell size of 3 bytes. Such small cells will be dbda8d6ce9 2007-07-21 drh: ** exceedingly rare, but they are possible. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define MX_CELL(pBt) ((pBt->pageSize-8)/3) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward declarations */ dbda8d6ce9 2007-07-21 drh: typedef struct MemPage MemPage; dbda8d6ce9 2007-07-21 drh: typedef struct BtLock BtLock; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is a magic string that appears at the beginning of every dbda8d6ce9 2007-07-21 drh: ** SQLite database in order to identify the file as a real database. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** You can change this value at compile-time by specifying a dbda8d6ce9 2007-07-21 drh: ** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The dbda8d6ce9 2007-07-21 drh: ** header must be exactly 16 bytes including the zero-terminator so dbda8d6ce9 2007-07-21 drh: ** the string itself should be 15 characters long. If you change dbda8d6ce9 2007-07-21 drh: ** the header, then your custom library will not be able to read dbda8d6ce9 2007-07-21 drh: ** databases generated by the standard tools and the standard tools dbda8d6ce9 2007-07-21 drh: ** will not be able to read databases created by your custom library. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_FILE_HEADER /* 123456789 123456 */ dbda8d6ce9 2007-07-21 drh: # define SQLITE_FILE_HEADER "SQLite format 3" dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Page type flags. An ORed combination of these flags appear as the c287665ba8 2007-09-14 drh: ** first byte of on-disk image of every BTree page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define PTF_INTKEY 0x01 dbda8d6ce9 2007-07-21 drh: #define PTF_ZERODATA 0x02 dbda8d6ce9 2007-07-21 drh: #define PTF_LEAFDATA 0x04 dbda8d6ce9 2007-07-21 drh: #define PTF_LEAF 0x08 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** As each page of the file is loaded into memory, an instance of the following dbda8d6ce9 2007-07-21 drh: ** structure is appended and initialized to zero. This structure stores dbda8d6ce9 2007-07-21 drh: ** information about the page that is decoded from the raw file page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pParent field points back to the parent page. This allows us to dbda8d6ce9 2007-07-21 drh: ** walk up the BTree from any leaf to the root. Care must be taken to dbda8d6ce9 2007-07-21 drh: ** unref() the parent page pointer when this page is no longer referenced. dbda8d6ce9 2007-07-21 drh: ** The pageDestructor() routine handles that chore. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Access to all fields of this structure is controlled by the mutex c287665ba8 2007-09-14 drh: ** stored in MemPage.pBt->mutex. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct MemPage { dbda8d6ce9 2007-07-21 drh: u8 isInit; /* True if previously initialized. MUST BE FIRST! */ dbda8d6ce9 2007-07-21 drh: u8 idxShift; /* True if Cell indices have changed */ dbda8d6ce9 2007-07-21 drh: u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ dbda8d6ce9 2007-07-21 drh: u8 intKey; /* True if intkey flag is set */ dbda8d6ce9 2007-07-21 drh: u8 leaf; /* True if leaf flag is set */ dbda8d6ce9 2007-07-21 drh: u8 zeroData; /* True if table stores keys only */ dbda8d6ce9 2007-07-21 drh: u8 leafData; /* True if tables stores data on leaves only */ dbda8d6ce9 2007-07-21 drh: u8 hasData; /* True if this page stores data */ dbda8d6ce9 2007-07-21 drh: u8 hdrOffset; /* 100 for page 1. 0 otherwise */ dbda8d6ce9 2007-07-21 drh: u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ c287665ba8 2007-09-14 drh: u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ c287665ba8 2007-09-14 drh: u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ dbda8d6ce9 2007-07-21 drh: u16 cellOffset; /* Index in aData of first cell pointer */ dbda8d6ce9 2007-07-21 drh: u16 idxParent; /* Index in parent of this node */ dbda8d6ce9 2007-07-21 drh: u16 nFree; /* Number of free bytes on the page */ dbda8d6ce9 2007-07-21 drh: u16 nCell; /* Number of cells on this page, local and ovfl */ dbda8d6ce9 2007-07-21 drh: struct _OvflCell { /* Cells that will not fit on aData[] */ dbda8d6ce9 2007-07-21 drh: u8 *pCell; /* Pointers to the body of the overflow cell */ dbda8d6ce9 2007-07-21 drh: u16 idx; /* Insert this cell before idx-th non-overflow cell */ dbda8d6ce9 2007-07-21 drh: } aOvfl[5]; c287665ba8 2007-09-14 drh: BtShared *pBt; /* Pointer to BtShared that this page is part of */ c287665ba8 2007-09-14 drh: u8 *aData; /* Pointer to disk image of the page data */ dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; /* Pager page handle */ dbda8d6ce9 2007-07-21 drh: Pgno pgno; /* Page number for this page */ dbda8d6ce9 2007-07-21 drh: MemPage *pParent; /* The parent of this page. NULL for root */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The in-memory image of a disk page has the auxiliary information appended dbda8d6ce9 2007-07-21 drh: ** to the end. EXTRA_SIZE is the number of bytes of space needed to hold dbda8d6ce9 2007-07-21 drh: ** that extra information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define EXTRA_SIZE sizeof(MemPage) dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* A Btree handle c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** A database connection contains a pointer to an instance of c287665ba8 2007-09-14 drh: ** this object for every database file that it has open. This structure c287665ba8 2007-09-14 drh: ** is opaque to the database connection. The database connection cannot c287665ba8 2007-09-14 drh: ** see the internals of this structure and only deals with pointers to c287665ba8 2007-09-14 drh: ** this structure. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** For some database files, the same underlying database cache might be c287665ba8 2007-09-14 drh: ** shared between multiple connections. In that case, each contection c287665ba8 2007-09-14 drh: ** has it own pointer to this object. But each instance of this object c287665ba8 2007-09-14 drh: ** points to the same BtShared object. The database cache and the c287665ba8 2007-09-14 drh: ** schema associated with the database file are all contained within c287665ba8 2007-09-14 drh: ** the BtShared object. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** All fields in this structure are accessed under sqlite3.mutex. c287665ba8 2007-09-14 drh: ** The pBt pointer itself may not be changed while there exists cursors c287665ba8 2007-09-14 drh: ** in the referenced BtShared that point back to this Btree since those c287665ba8 2007-09-14 drh: ** cursors have to do go through this Btree to find their BtShared and c287665ba8 2007-09-14 drh: ** they often do so without holding sqlite3.mutex. c287665ba8 2007-09-14 drh: */ dbda8d6ce9 2007-07-21 drh: struct Btree { c287665ba8 2007-09-14 drh: sqlite3 *pSqlite; /* The database connection holding this btree */ c287665ba8 2007-09-14 drh: BtShared *pBt; /* Sharable content of this btree */ c287665ba8 2007-09-14 drh: u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ c287665ba8 2007-09-14 drh: u8 sharable; /* True if we can share pBt with other pSqlite */ c287665ba8 2007-09-14 drh: u8 locked; /* True if pSqlite currently has pBt locked */ c287665ba8 2007-09-14 drh: int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ c287665ba8 2007-09-14 drh: Btree *pNext; /* List of other sharable Btrees from the same pSqlite */ c287665ba8 2007-09-14 drh: Btree *pPrev; /* Back pointer of the same list */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Btree.inTrans may take one of the following values. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the shared-data extension is enabled, there may be multiple users dbda8d6ce9 2007-07-21 drh: ** of the Btree structure. At most one of these may open a write transaction, c287665ba8 2007-09-14 drh: ** but any number may have active read transactions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define TRANS_NONE 0 dbda8d6ce9 2007-07-21 drh: #define TRANS_READ 1 dbda8d6ce9 2007-07-21 drh: #define TRANS_WRITE 2 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** An instance of this object represents a single database file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** A single database file can be in use as the same time by two c287665ba8 2007-09-14 drh: ** or more database connections. When two or more connections are c287665ba8 2007-09-14 drh: ** sharing the same database file, each connection has it own c287665ba8 2007-09-14 drh: ** private Btree object for the file and each of those Btrees points c287665ba8 2007-09-14 drh: ** to this one BtShared object. BtShared.nRef is the number of c287665ba8 2007-09-14 drh: ** connections currently sharing this database file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Fields in this structure are accessed under the BtShared.mutex c287665ba8 2007-09-14 drh: ** mutex, except for nRef and pNext which are accessed under the c287665ba8 2007-09-14 drh: ** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field c287665ba8 2007-09-14 drh: ** may not be modified once it is initially set as long as nRef>0. c287665ba8 2007-09-14 drh: ** The pSchema field may be set once under BtShared.mutex and c287665ba8 2007-09-14 drh: ** thereafter is unchanged as long as nRef>0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct BtShared { dbda8d6ce9 2007-07-21 drh: Pager *pPager; /* The page cache */ dbda8d6ce9 2007-07-21 drh: BtCursor *pCursor; /* A list of all open cursors */ dbda8d6ce9 2007-07-21 drh: MemPage *pPage1; /* First page of the database */ dbda8d6ce9 2007-07-21 drh: u8 inStmt; /* True if we are in a statement subtransaction */ dbda8d6ce9 2007-07-21 drh: u8 readOnly; /* True if the underlying file is readonly */ dbda8d6ce9 2007-07-21 drh: u8 maxEmbedFrac; /* Maximum payload as % of total page size */ dbda8d6ce9 2007-07-21 drh: u8 minEmbedFrac; /* Minimum payload as % of total page size */ dbda8d6ce9 2007-07-21 drh: u8 minLeafFrac; /* Minimum leaf payload as % of total page size */ dbda8d6ce9 2007-07-21 drh: u8 pageSizeFixed; /* True if the page size can no longer be changed */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: u8 autoVacuum; /* True if auto-vacuum is enabled */ dbda8d6ce9 2007-07-21 drh: u8 incrVacuum; /* True if incr-vacuum is enabled */ dbda8d6ce9 2007-07-21 drh: Pgno nTrunc; /* Non-zero if the db will be truncated (incr vacuum) */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: u16 pageSize; /* Total number of bytes on a page */ dbda8d6ce9 2007-07-21 drh: u16 usableSize; /* Number of usable bytes on each page */ dbda8d6ce9 2007-07-21 drh: int maxLocal; /* Maximum local payload in non-LEAFDATA tables */ dbda8d6ce9 2007-07-21 drh: int minLocal; /* Minimum local payload in non-LEAFDATA tables */ dbda8d6ce9 2007-07-21 drh: int maxLeaf; /* Maximum local payload in a LEAFDATA table */ dbda8d6ce9 2007-07-21 drh: int minLeaf; /* Minimum local payload in a LEAFDATA table */ dbda8d6ce9 2007-07-21 drh: BusyHandler *pBusyHandler; /* Callback for when there is lock contention */ dbda8d6ce9 2007-07-21 drh: u8 inTransaction; /* Transaction state */ dbda8d6ce9 2007-07-21 drh: int nTransaction; /* Number of open transactions (read + write) */ dbda8d6ce9 2007-07-21 drh: void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ dbda8d6ce9 2007-07-21 drh: void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */ c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_SHARED_CACHE c287665ba8 2007-09-14 drh: int nRef; /* Number of references to this structure */ c287665ba8 2007-09-14 drh: BtShared *pNext; /* Next on a list of sharable BtShared structs */ c287665ba8 2007-09-14 drh: BtLock *pLock; /* List of locks held on this shared-btree struct */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure is used to hold information dbda8d6ce9 2007-07-21 drh: ** about a cell. The parseCellPtr() function fills in this structure dbda8d6ce9 2007-07-21 drh: ** based on information extract from the raw disk page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct CellInfo CellInfo; dbda8d6ce9 2007-07-21 drh: struct CellInfo { dbda8d6ce9 2007-07-21 drh: u8 *pCell; /* Pointer to the start of cell content */ dbda8d6ce9 2007-07-21 drh: i64 nKey; /* The key for INTKEY tables, or number of bytes in key */ dbda8d6ce9 2007-07-21 drh: u32 nData; /* Number of bytes of data */ dbda8d6ce9 2007-07-21 drh: u32 nPayload; /* Total amount of payload */ dbda8d6ce9 2007-07-21 drh: u16 nHeader; /* Size of the cell content header in bytes */ dbda8d6ce9 2007-07-21 drh: u16 nLocal; /* Amount of payload held locally */ dbda8d6ce9 2007-07-21 drh: u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */ dbda8d6ce9 2007-07-21 drh: u16 nSize; /* Size of the cell content on the main b-tree page */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** A cursor is a pointer to a particular entry within a particular c287665ba8 2007-09-14 drh: ** b-tree within a database file. c287665ba8 2007-09-14 drh: ** dbda8d6ce9 2007-07-21 drh: ** The entry is identified by its MemPage and the index in dbda8d6ce9 2007-07-21 drh: ** MemPage.aCell[] of the entry. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** When a single database file can shared by two more database connections, c287665ba8 2007-09-14 drh: ** but cursors cannot be shared. Each cursor is associated with a c287665ba8 2007-09-14 drh: ** particular database connection identified BtCursor.pBtree.pSqlite. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Fields in this structure are accessed under the BtShared.mutex c287665ba8 2007-09-14 drh: ** found at self->pBt->mutex. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct BtCursor { dbda8d6ce9 2007-07-21 drh: Btree *pBtree; /* The Btree to which this cursor belongs */ c287665ba8 2007-09-14 drh: BtShared *pBt; /* The BtShared this cursor points to */ dbda8d6ce9 2007-07-21 drh: BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ dbda8d6ce9 2007-07-21 drh: int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */ dbda8d6ce9 2007-07-21 drh: void *pArg; /* First arg to xCompare() */ dbda8d6ce9 2007-07-21 drh: Pgno pgnoRoot; /* The root page of this tree */ dbda8d6ce9 2007-07-21 drh: MemPage *pPage; /* Page that contains the entry */ dbda8d6ce9 2007-07-21 drh: int idx; /* Index of the entry in pPage->aCell[] */ dbda8d6ce9 2007-07-21 drh: CellInfo info; /* A parse of the cell we are pointing at */ dbda8d6ce9 2007-07-21 drh: u8 wrFlag; /* True if writable */ dbda8d6ce9 2007-07-21 drh: u8 eState; /* One of the CURSOR_XXX constants (see below) */ dbda8d6ce9 2007-07-21 drh: void *pKey; /* Saved key that was cursor's last known position */ dbda8d6ce9 2007-07-21 drh: i64 nKey; /* Size of pKey, or last integer key */ dbda8d6ce9 2007-07-21 drh: int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */ dbda8d6ce9 2007-07-21 drh: Pgno *aOverflow; /* Cache of overflow page locations */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Potential values for BtCursor.eState. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CURSOR_VALID: dbda8d6ce9 2007-07-21 drh: ** Cursor points to a valid entry. getPayload() etc. may be called. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CURSOR_INVALID: dbda8d6ce9 2007-07-21 drh: ** Cursor does not point to a valid entry. This can happen (for example) dbda8d6ce9 2007-07-21 drh: ** because the table is empty or because BtreeCursorFirst() has not been dbda8d6ce9 2007-07-21 drh: ** called. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CURSOR_REQUIRESEEK: dbda8d6ce9 2007-07-21 drh: ** The table that this cursor was opened on still exists, but has been dbda8d6ce9 2007-07-21 drh: ** modified since the cursor was last used. The cursor position is saved dbda8d6ce9 2007-07-21 drh: ** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in dbda8d6ce9 2007-07-21 drh: ** this state, restoreOrClearCursorPosition() can be called to attempt to dbda8d6ce9 2007-07-21 drh: ** seek the cursor to the saved position. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** CURSOR_FAULT: c287665ba8 2007-09-14 drh: ** A unrecoverable error (an I/O error or a malloc failure) has occurred c287665ba8 2007-09-14 drh: ** on a different connection that shares the BtShared cache with this c287665ba8 2007-09-14 drh: ** cursor. The error has left the cache in an inconsistent state. c287665ba8 2007-09-14 drh: ** Do nothing else with this cursor. Any attempt to use the cursor c287665ba8 2007-09-14 drh: ** should return the error code stored in BtCursor.skip dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define CURSOR_INVALID 0 dbda8d6ce9 2007-07-21 drh: #define CURSOR_VALID 1 dbda8d6ce9 2007-07-21 drh: #define CURSOR_REQUIRESEEK 2 c287665ba8 2007-09-14 drh: #define CURSOR_FAULT 3 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The TRACE macro will print high-level status information about the dbda8d6ce9 2007-07-21 drh: ** btree operation when the global variable sqlite3_btree_trace is dbda8d6ce9 2007-07-21 drh: ** enabled. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if SQLITE_TEST dbda8d6ce9 2007-07-21 drh: # define TRACE(X) if( sqlite3_btree_trace ){ printf X; fflush(stdout); } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define TRACE(X) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Routines to read and write variable-length integers. These used to dbda8d6ce9 2007-07-21 drh: ** be defined locally, but now we use the varint routines in the util.c dbda8d6ce9 2007-07-21 drh: ** file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define getVarint sqlite3GetVarint dbda8d6ce9 2007-07-21 drh: #define getVarint32(A,B) ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B)) dbda8d6ce9 2007-07-21 drh: #define putVarint sqlite3PutVarint dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The database page the PENDING_BYTE occupies. This page is never used. dbda8d6ce9 2007-07-21 drh: ** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They dbda8d6ce9 2007-07-21 drh: ** should possibly be consolidated (presumably in pager.h). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If disk I/O is omitted (meaning that the database is stored purely dbda8d6ce9 2007-07-21 drh: ** in memory) then there is no pending byte. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_DISKIO dbda8d6ce9 2007-07-21 drh: # define PENDING_BYTE_PAGE(pBt) 0x7fffffff dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A linked list of the following structures is stored at BtShared.pLock. dbda8d6ce9 2007-07-21 drh: ** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor dbda8d6ce9 2007-07-21 drh: ** is opened on the table with root page BtShared.iTable. Locks are removed dbda8d6ce9 2007-07-21 drh: ** from this list when a transaction is committed or rolled back, or when dbda8d6ce9 2007-07-21 drh: ** a btree handle is closed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct BtLock { dbda8d6ce9 2007-07-21 drh: Btree *pBtree; /* Btree handle holding this lock */ dbda8d6ce9 2007-07-21 drh: Pgno iTable; /* Root page of table */ dbda8d6ce9 2007-07-21 drh: u8 eLock; /* READ_LOCK or WRITE_LOCK */ dbda8d6ce9 2007-07-21 drh: BtLock *pNext; /* Next in BtShared.pLock list */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Candidate values for BtLock.eLock */ dbda8d6ce9 2007-07-21 drh: #define READ_LOCK 1 dbda8d6ce9 2007-07-21 drh: #define WRITE_LOCK 2 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** These macros define the location of the pointer-map entry for a dbda8d6ce9 2007-07-21 drh: ** database page. The first argument to each is the number of usable dbda8d6ce9 2007-07-21 drh: ** bytes on each page of the database (often 1024). The second is the dbda8d6ce9 2007-07-21 drh: ** page number to look up in the pointer map. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_PAGENO returns the database page number of the pointer-map dbda8d6ce9 2007-07-21 drh: ** page that stores the required pointer. PTRMAP_PTROFFSET returns dbda8d6ce9 2007-07-21 drh: ** the offset of the requested map entry. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page, dbda8d6ce9 2007-07-21 drh: ** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be dbda8d6ce9 2007-07-21 drh: ** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements dbda8d6ce9 2007-07-21 drh: ** this test. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno) dbda8d6ce9 2007-07-21 drh: #define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1)) dbda8d6ce9 2007-07-21 drh: #define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The pointer map is a lookup table that identifies the parent page for dbda8d6ce9 2007-07-21 drh: ** each child page in the database file. The parent page is the page that dbda8d6ce9 2007-07-21 drh: ** contains a pointer to the child. Every page in the database contains dbda8d6ce9 2007-07-21 drh: ** 0 or 1 parent pages. (In this context 'database page' refers dbda8d6ce9 2007-07-21 drh: ** to any page that is not part of the pointer map itself.) Each pointer map dbda8d6ce9 2007-07-21 drh: ** entry consists of a single byte 'type' and a 4 byte parent page number. dbda8d6ce9 2007-07-21 drh: ** The PTRMAP_XXX identifiers below are the valid types. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The purpose of the pointer map is to facility moving pages from one dbda8d6ce9 2007-07-21 drh: ** position in the file to another as part of autovacuum. When a page dbda8d6ce9 2007-07-21 drh: ** is moved, the pointer in its parent must be updated to point to the dbda8d6ce9 2007-07-21 drh: ** new location. The pointer map is used to locate the parent page quickly. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not dbda8d6ce9 2007-07-21 drh: ** used in this case. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number dbda8d6ce9 2007-07-21 drh: ** is not used in this case. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_OVERFLOW1: The database page is the first page in a list of dbda8d6ce9 2007-07-21 drh: ** overflow pages. The page number identifies the page that dbda8d6ce9 2007-07-21 drh: ** contains the cell with a pointer to this overflow page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of dbda8d6ce9 2007-07-21 drh: ** overflow pages. The page-number identifies the previous dbda8d6ce9 2007-07-21 drh: ** page in the overflow page list. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_BTREE: The database page is a non-root btree page. The page number dbda8d6ce9 2007-07-21 drh: ** identifies the parent page in the btree. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define PTRMAP_ROOTPAGE 1 dbda8d6ce9 2007-07-21 drh: #define PTRMAP_FREEPAGE 2 dbda8d6ce9 2007-07-21 drh: #define PTRMAP_OVERFLOW1 3 dbda8d6ce9 2007-07-21 drh: #define PTRMAP_OVERFLOW2 4 dbda8d6ce9 2007-07-21 drh: #define PTRMAP_BTREE 5 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A bunch of assert() statements to check the transaction state variables dbda8d6ce9 2007-07-21 drh: ** of handle p (type Btree*) are internally consistent. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define btreeIntegrity(p) \ dbda8d6ce9 2007-07-21 drh: assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \ dbda8d6ce9 2007-07-21 drh: assert( p->pBt->inTransaction>=p->inTrans ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The ISAUTOVACUUM macro is used within balance_nonroot() to determine dbda8d6ce9 2007-07-21 drh: ** if the database supports auto-vacuum or not. Because it is used dbda8d6ce9 2007-07-21 drh: ** within an expression that is an argument to another macro dbda8d6ce9 2007-07-21 drh: ** (sqliteMallocRaw), it is not possible to use conditional compilation. dbda8d6ce9 2007-07-21 drh: ** So, this macro is defined instead. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: #define ISAUTOVACUUM (pBt->autoVacuum) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define ISAUTOVACUUM 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This structure is passed around through all the sanity checking routines dbda8d6ce9 2007-07-21 drh: ** in order to keep track of some global state information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct IntegrityCk IntegrityCk; dbda8d6ce9 2007-07-21 drh: struct IntegrityCk { dbda8d6ce9 2007-07-21 drh: BtShared *pBt; /* The tree being checked out */ dbda8d6ce9 2007-07-21 drh: Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ dbda8d6ce9 2007-07-21 drh: int nPage; /* Number of pages in the database */ dbda8d6ce9 2007-07-21 drh: int *anRef; /* Number of times each page is referenced */ dbda8d6ce9 2007-07-21 drh: int mxErr; /* Stop accumulating errors when this reaches zero */ dbda8d6ce9 2007-07-21 drh: char *zErrMsg; /* An error message. NULL if no errors seen. */ dbda8d6ce9 2007-07-21 drh: int nErr; /* Number of messages written to zErrMsg so far */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read or write a two- and four-byte big-endian integer values. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define get2byte(x) ((x)[0]<<8 | (x)[1]) dbda8d6ce9 2007-07-21 drh: #define put2byte(p,v) ((p)[0] = (v)>>8, (p)[1] = (v)) dbda8d6ce9 2007-07-21 drh: #define get4byte sqlite3Get4byte dbda8d6ce9 2007-07-21 drh: #define put4byte sqlite3Put4byte dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Internal routines that should be accessed by the btree layer only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeParseCell(MemPage*, int, CellInfo*); c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell); c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeReleaseTempCursor(BtCursor *pCur); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeIsRootPage(MemPage *pPage); dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeMoveToParent(BtCursor *pCur); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of btreeInt.h ********************************************/ c287665ba8 2007-09-14 drh: /************** Continuing where we left off in btmutex.c ********************/ c287665ba8 2007-09-14 drh: #if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE) c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Enter a mutex on the given BTree object. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If the object is not sharable, then no mutex is ever required c287665ba8 2007-09-14 drh: ** and this routine is a no-op. The underlying mutex is non-recursive. c287665ba8 2007-09-14 drh: ** But we keep a reference count in Btree.wantToLock so the behavior c287665ba8 2007-09-14 drh: ** of this interface is recursive. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** To avoid deadlocks, multiple Btrees are locked in the same order c287665ba8 2007-09-14 drh: ** by all database connections. The p->pNext is a list of other c287665ba8 2007-09-14 drh: ** Btrees belonging to the same database connection as the p Btree c287665ba8 2007-09-14 drh: ** which need to be locked after p. If we cannot get a lock on c287665ba8 2007-09-14 drh: ** p, then first unlock all of the others on p->pNext, then wait c287665ba8 2007-09-14 drh: ** for the lock to become available on p, then relock all of the c287665ba8 2007-09-14 drh: ** subsequent Btrees that desire a lock. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){ c287665ba8 2007-09-14 drh: Btree *pLater; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Some basic sanity checking on the Btree. The list of Btrees c287665ba8 2007-09-14 drh: ** connected by pNext and pPrev should be in sorted order by c287665ba8 2007-09-14 drh: ** Btree.pBt value. All elements of the list should belong to c287665ba8 2007-09-14 drh: ** the same connection. Only shared Btrees are on the list. */ c287665ba8 2007-09-14 drh: assert( p->pNext==0 || p->pNext->pBt>p->pBt ); c287665ba8 2007-09-14 drh: assert( p->pPrev==0 || p->pPrev->pBt<p->pBt ); c287665ba8 2007-09-14 drh: assert( p->pNext==0 || p->pNext->pSqlite==p->pSqlite ); c287665ba8 2007-09-14 drh: assert( p->pPrev==0 || p->pPrev->pSqlite==p->pSqlite ); c287665ba8 2007-09-14 drh: assert( p->sharable || (p->pNext==0 && p->pPrev==0) ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Check for locking consistency */ c287665ba8 2007-09-14 drh: assert( !p->locked || p->wantToLock>0 ); c287665ba8 2007-09-14 drh: assert( p->sharable || p->wantToLock==0 ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* We should already hold a lock on the database connection */ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( !p->sharable ) return; c287665ba8 2007-09-14 drh: p->wantToLock++; c287665ba8 2007-09-14 drh: if( p->locked ) return; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* In most cases, we should be able to acquire the lock we c287665ba8 2007-09-14 drh: ** want without having to go throught the ascending lock c287665ba8 2007-09-14 drh: ** procedure that follows. Just be sure not to block. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ c287665ba8 2007-09-14 drh: p->locked = 1; c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* To avoid deadlock, first release all locks with a larger c287665ba8 2007-09-14 drh: ** BtShared address. Then acquire our lock. Then reacquire c287665ba8 2007-09-14 drh: ** the other BtShared locks that we used to hold in ascending c287665ba8 2007-09-14 drh: ** order. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: for(pLater=p->pNext; pLater; pLater=pLater->pNext){ c287665ba8 2007-09-14 drh: assert( pLater->sharable ); c287665ba8 2007-09-14 drh: assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt ); c287665ba8 2007-09-14 drh: assert( !pLater->locked || pLater->wantToLock>0 ); c287665ba8 2007-09-14 drh: if( pLater->locked ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(pLater->pBt->mutex); c287665ba8 2007-09-14 drh: pLater->locked = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->pBt->mutex); c287665ba8 2007-09-14 drh: p->locked = 1; c287665ba8 2007-09-14 drh: for(pLater=p->pNext; pLater; pLater=pLater->pNext){ c287665ba8 2007-09-14 drh: if( pLater->wantToLock ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(pLater->pBt->mutex); c287665ba8 2007-09-14 drh: pLater->locked = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Exit the recursive mutex on a Btree. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeLeave(Btree *p){ c287665ba8 2007-09-14 drh: if( p->sharable ){ c287665ba8 2007-09-14 drh: assert( p->wantToLock>0 ); c287665ba8 2007-09-14 drh: p->wantToLock--; c287665ba8 2007-09-14 drh: if( p->wantToLock==0 ){ c287665ba8 2007-09-14 drh: assert( p->locked ); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->pBt->mutex); c287665ba8 2007-09-14 drh: p->locked = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef NDEBUG c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return true if the BtShared mutex is held on the btree. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine makes no determination one why or another if the c287665ba8 2007-09-14 drh: ** database connection mutex is held. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine is used only from within assert() statements. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){ c287665ba8 2007-09-14 drh: return (p->sharable==0 || c287665ba8 2007-09-14 drh: (p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex))); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_INCRBLOB c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Enter and leave a mutex on a Btree given a cursor owned by that c287665ba8 2007-09-14 drh: ** Btree. These entry points are used by incremental I/O and can be c287665ba8 2007-09-14 drh: ** omitted if that module is not used. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){ c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(pCur->pBtree); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pCur->pBtree); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif /* SQLITE_OMIT_INCRBLOB */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Enter the mutex on every Btree associated with a database c287665ba8 2007-09-14 drh: ** connection. This is needed (for example) prior to parsing c287665ba8 2007-09-14 drh: ** a statement since we will be comparing table and column names c287665ba8 2007-09-14 drh: ** against all schemas and we do not want those schemas being c287665ba8 2007-09-14 drh: ** reset out from under us. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** There is a corresponding leave-all procedures. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Enter the mutexes in accending order by BtShared pointer address c287665ba8 2007-09-14 drh: ** to avoid the possibility of deadlock when two threads with c287665ba8 2007-09-14 drh: ** two or more btrees in common both try to lock all their btrees c287665ba8 2007-09-14 drh: ** at the same instant. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: Btree *p, *pLater; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); c287665ba8 2007-09-14 drh: for(i=0; i<db->nDb; i++){ c287665ba8 2007-09-14 drh: p = db->aDb[i].pBt; c287665ba8 2007-09-14 drh: if( p && p->sharable ){ c287665ba8 2007-09-14 drh: p->wantToLock++; c287665ba8 2007-09-14 drh: if( !p->locked ){ c287665ba8 2007-09-14 drh: assert( p->wantToLock==1 ); c287665ba8 2007-09-14 drh: while( p->pPrev ) p = p->pPrev; c287665ba8 2007-09-14 drh: while( p->locked && p->pNext ) p = p->pNext; c287665ba8 2007-09-14 drh: for(pLater = p->pNext; pLater; pLater=pLater->pNext){ c287665ba8 2007-09-14 drh: if( pLater->locked ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(pLater->pBt->mutex); c287665ba8 2007-09-14 drh: pLater->locked = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: while( p ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->pBt->mutex); c287665ba8 2007-09-14 drh: p->locked++; c287665ba8 2007-09-14 drh: p = p->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: Btree *p; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); c287665ba8 2007-09-14 drh: for(i=0; i<db->nDb; i++){ c287665ba8 2007-09-14 drh: p = db->aDb[i].pBt; c287665ba8 2007-09-14 drh: if( p && p->sharable ){ c287665ba8 2007-09-14 drh: assert( p->wantToLock>0 ); c287665ba8 2007-09-14 drh: p->wantToLock--; c287665ba8 2007-09-14 drh: if( p->wantToLock==0 ){ c287665ba8 2007-09-14 drh: assert( p->locked ); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->pBt->mutex); c287665ba8 2007-09-14 drh: p->locked = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef NDEBUG c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return true if the current thread holds the database connection c287665ba8 2007-09-14 drh: ** mutex and all required BtShared mutexes. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine is used inside assert() statements only. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: if( !sqlite3_mutex_held(db->mutex) ){ c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: for(i=0; i<db->nDb; i++){ c287665ba8 2007-09-14 drh: Btree *p; c287665ba8 2007-09-14 drh: p = db->aDb[i].pBt; c287665ba8 2007-09-14 drh: if( p && p->sharable && c287665ba8 2007-09-14 drh: (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){ c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif /* NDEBUG */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Potentially dd a new Btree pointer to a BtreeMutexArray. c287665ba8 2007-09-14 drh: ** Really only add the Btree if it can possibly be shared with c287665ba8 2007-09-14 drh: ** another database connection. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The Btrees are kept in sorted order by pBtree->pBt. That c287665ba8 2007-09-14 drh: ** way when we go to enter all the mutexes, we can enter them c287665ba8 2007-09-14 drh: ** in order without every having to backup and retry and without c287665ba8 2007-09-14 drh: ** worrying about deadlock. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The number of shared btrees will always be small (usually 0 or 1) c287665ba8 2007-09-14 drh: ** so an insertion sort is an adequate algorithm here. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){ c287665ba8 2007-09-14 drh: int i, j; c287665ba8 2007-09-14 drh: BtShared *pBt; c287665ba8 2007-09-14 drh: if( pBtree==0 || pBtree->sharable==0 ) return; c287665ba8 2007-09-14 drh: #ifndef NDEBUG c287665ba8 2007-09-14 drh: { c287665ba8 2007-09-14 drh: for(i=0; i<pArray->nMutex; i++){ c287665ba8 2007-09-14 drh: assert( pArray->aBtree[i]!=pBtree ); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: assert( pArray->nMutex>=0 ); c287665ba8 2007-09-14 drh: assert( pArray->nMutex<sizeof(pArray->aBtree)/sizeof(pArray->aBtree[0])-1 ); c287665ba8 2007-09-14 drh: pBt = pBtree->pBt; c287665ba8 2007-09-14 drh: for(i=0; i<pArray->nMutex; i++){ c287665ba8 2007-09-14 drh: assert( pArray->aBtree[i]!=pBtree ); c287665ba8 2007-09-14 drh: if( pArray->aBtree[i]->pBt>pBt ){ c287665ba8 2007-09-14 drh: for(j=pArray->nMutex; j>i; j--){ c287665ba8 2007-09-14 drh: pArray->aBtree[j] = pArray->aBtree[j-1]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pArray->aBtree[i] = pBtree; c287665ba8 2007-09-14 drh: pArray->nMutex++; c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pArray->aBtree[pArray->nMutex++] = pBtree; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Enter the mutex of every btree in the array. This routine is c287665ba8 2007-09-14 drh: ** called at the beginning of sqlite3VdbeExec(). The mutexes are c287665ba8 2007-09-14 drh: ** exited at the end of the same function. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: for(i=0; i<pArray->nMutex; i++){ c287665ba8 2007-09-14 drh: Btree *p = pArray->aBtree[i]; c287665ba8 2007-09-14 drh: /* Some basic sanity checking */ c287665ba8 2007-09-14 drh: assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt ); c287665ba8 2007-09-14 drh: assert( !p->locked || p->wantToLock>0 ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* We should already hold a lock on the database connection */ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: p->wantToLock++; c287665ba8 2007-09-14 drh: if( !p->locked && p->sharable ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->pBt->mutex); c287665ba8 2007-09-14 drh: p->locked = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Leave the mutex of every btree in the group. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: for(i=0; i<pArray->nMutex; i++){ c287665ba8 2007-09-14 drh: Btree *p = pArray->aBtree[i]; c287665ba8 2007-09-14 drh: /* Some basic sanity checking */ c287665ba8 2007-09-14 drh: assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt ); c287665ba8 2007-09-14 drh: assert( p->locked || !p->sharable ); c287665ba8 2007-09-14 drh: assert( p->wantToLock>0 ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* We should already hold a lock on the database connection */ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: p->wantToLock--; c287665ba8 2007-09-14 drh: if( p->wantToLock==0 && p->locked ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->pBt->mutex); c287665ba8 2007-09-14 drh: p->locked = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #endif /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of btmutex.c *********************************************/ c287665ba8 2007-09-14 drh: /************** Begin file btree.c *******************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2004 April 6 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** $Id: btree.c,v 1.426 2007/09/12 17:01:45 danielk1977 Exp $ c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This file implements a external (disk-based) database using BTrees. c287665ba8 2007-09-14 drh: ** See the header comment on "btreeInt.h" for additional information. c287665ba8 2007-09-14 drh: ** Including a description of file format and an overview of operation. c287665ba8 2007-09-14 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The header string that appears at the beginning of every dbda8d6ce9 2007-07-21 drh: ** SQLite database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const char zMagicHeader[] = SQLITE_FILE_HEADER; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set this global variable to 1 to enable tracing using the TRACE dbda8d6ce9 2007-07-21 drh: ** macro. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if SQLITE_TEST dbda8d6ce9 2007-07-21 drh: int sqlite3_btree_trace=0; /* True to enable tracing */ dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_SHARED_CACHE c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** A flag to indicate whether or not shared cache is enabled. Also, c287665ba8 2007-09-14 drh: ** a list of BtShared objects that are eligible for participation c287665ba8 2007-09-14 drh: ** in shared cache. The variables have file scope during normal builds, c287665ba8 2007-09-14 drh: ** but the test harness needs to access these variables so we make them c287665ba8 2007-09-14 drh: ** global for test builds. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_PRIVATE BtShared *sqlite3SharedCacheList = 0; c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3SharedCacheEnabled = 0; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: static BtShared *sqlite3SharedCacheList = 0; c287665ba8 2007-09-14 drh: static int sqlite3SharedCacheEnabled = 0; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: #endif /* SQLITE_OMIT_SHARED_CACHE */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_SHARED_CACHE c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Enable or disable the shared pager and schema features. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine has no effect on existing database connections. c287665ba8 2007-09-14 drh: ** The shared cache setting effects only future calls to c287665ba8 2007-09-14 drh: ** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_enable_shared_cache(int enable){ c287665ba8 2007-09-14 drh: sqlite3SharedCacheEnabled = enable; c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Forward declaration dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int checkReadLocks(Btree*,Pgno,BtCursor*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The functions queryTableLock(), lockTable() and unlockAllTables() dbda8d6ce9 2007-07-21 drh: ** manipulate entries in the BtShared.pLock linked list used to store dbda8d6ce9 2007-07-21 drh: ** shared-cache table level locks. If the library is compiled with the dbda8d6ce9 2007-07-21 drh: ** shared-cache feature disabled, then there is only ever one user dbda8d6ce9 2007-07-21 drh: ** of each BtShared structure and so this locking is not necessary. dbda8d6ce9 2007-07-21 drh: ** So define the lock related functions as no-ops. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define queryTableLock(a,b,c) SQLITE_OK dbda8d6ce9 2007-07-21 drh: #define lockTable(a,b,c) SQLITE_OK dbda8d6ce9 2007-07-21 drh: #define unlockAllTables(a) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Query to see if btree handle p may obtain a lock of type eLock dbda8d6ce9 2007-07-21 drh: ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK if the lock may be obtained (by calling lockTable()), or dbda8d6ce9 2007-07-21 drh: ** SQLITE_LOCKED if not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: BtLock *pIter; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(p) ); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* This is a no-op if the shared-cache is not enabled */ c287665ba8 2007-09-14 drh: if( !p->sharable ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This (along with lockTable()) is where the ReadUncommitted flag is dbda8d6ce9 2007-07-21 drh: ** dealt with. If the caller is querying for a read-lock and the flag is dbda8d6ce9 2007-07-21 drh: ** set, it is unconditionally granted - even if there are write-locks dbda8d6ce9 2007-07-21 drh: ** on the table. If a write-lock is requested, the ReadUncommitted flag dbda8d6ce9 2007-07-21 drh: ** is not considered. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In function lockTable(), if a read-lock is demanded and the dbda8d6ce9 2007-07-21 drh: ** ReadUncommitted flag is set, no entry is added to the locks list dbda8d6ce9 2007-07-21 drh: ** (BtShared.pLock). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To summarize: If the ReadUncommitted flag is set, then read cursors do dbda8d6ce9 2007-07-21 drh: ** not create or respect table locks. The locking procedure for a dbda8d6ce9 2007-07-21 drh: ** write-cursor does not change. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: !p->pSqlite || dbda8d6ce9 2007-07-21 drh: 0==(p->pSqlite->flags&SQLITE_ReadUncommitted) || dbda8d6ce9 2007-07-21 drh: eLock==WRITE_LOCK || dbda8d6ce9 2007-07-21 drh: iTab==MASTER_ROOT dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ dbda8d6ce9 2007-07-21 drh: if( pIter->pBtree!=p && pIter->iTable==iTab && dbda8d6ce9 2007-07-21 drh: (pIter->eLock!=eLock || eLock!=READ_LOCK) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_LOCKED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: #endif /* !SQLITE_OMIT_SHARED_CACHE */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a lock on the table with root-page iTable to the shared-btree used dbda8d6ce9 2007-07-21 drh: ** by Btree handle p. Parameter eLock must be either READ_LOCK or dbda8d6ce9 2007-07-21 drh: ** WRITE_LOCK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK is returned if the lock is added successfully. SQLITE_BUSY and dbda8d6ce9 2007-07-21 drh: ** SQLITE_NOMEM may also be returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int lockTable(Btree *p, Pgno iTable, u8 eLock){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: BtLock *pLock = 0; dbda8d6ce9 2007-07-21 drh: BtLock *pIter; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(p) ); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* This is a no-op if the shared-cache is not enabled */ c287665ba8 2007-09-14 drh: if( !p->sharable ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( SQLITE_OK==queryTableLock(p, iTable, eLock) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the read-uncommitted flag is set and a read-lock is requested, dbda8d6ce9 2007-07-21 drh: ** return early without adding an entry to the BtShared.pLock list. See dbda8d6ce9 2007-07-21 drh: ** comment in function queryTableLock() for more info on handling dbda8d6ce9 2007-07-21 drh: ** the ReadUncommitted flag. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: (p->pSqlite) && dbda8d6ce9 2007-07-21 drh: (p->pSqlite->flags&SQLITE_ReadUncommitted) && dbda8d6ce9 2007-07-21 drh: (eLock==READ_LOCK) && dbda8d6ce9 2007-07-21 drh: iTable!=MASTER_ROOT dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* First search the list for an existing lock on this table. */ dbda8d6ce9 2007-07-21 drh: for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ dbda8d6ce9 2007-07-21 drh: if( pIter->iTable==iTable && pIter->pBtree==p ){ dbda8d6ce9 2007-07-21 drh: pLock = pIter; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the above search did not find a BtLock struct associating Btree p dbda8d6ce9 2007-07-21 drh: ** with table iTable, allocate one and link it into the list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !pLock ){ c287665ba8 2007-09-14 drh: pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock)); dbda8d6ce9 2007-07-21 drh: if( !pLock ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pLock->iTable = iTable; dbda8d6ce9 2007-07-21 drh: pLock->pBtree = p; dbda8d6ce9 2007-07-21 drh: pLock->pNext = pBt->pLock; dbda8d6ce9 2007-07-21 drh: pBt->pLock = pLock; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the BtLock.eLock variable to the maximum of the current lock dbda8d6ce9 2007-07-21 drh: ** and the requested lock. This means if a write-lock was already held dbda8d6ce9 2007-07-21 drh: ** and a read-lock requested, we don't incorrectly downgrade the lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( WRITE_LOCK>READ_LOCK ); dbda8d6ce9 2007-07-21 drh: if( eLock>pLock->eLock ){ dbda8d6ce9 2007-07-21 drh: pLock->eLock = eLock; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: #endif /* !SQLITE_OMIT_SHARED_CACHE */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release all the table locks (locks obtained via calls to the lockTable() dbda8d6ce9 2007-07-21 drh: ** procedure) held by Btree handle p. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void unlockAllTables(Btree *p){ dbda8d6ce9 2007-07-21 drh: BtLock **ppIter = &p->pBt->pLock; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(p) ); c287665ba8 2007-09-14 drh: assert( p->sharable || 0==*ppIter ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( *ppIter ){ dbda8d6ce9 2007-07-21 drh: BtLock *pLock = *ppIter; dbda8d6ce9 2007-07-21 drh: if( pLock->pBtree==p ){ dbda8d6ce9 2007-07-21 drh: *ppIter = pLock->pNext; c287665ba8 2007-09-14 drh: sqlite3_free(pLock); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: ppIter = &pLock->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_SHARED_CACHE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: static void releasePage(MemPage *pPage); /* Forward reference */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Verify that the cursor holds a mutex on the BtShared c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef NDEBUG c287665ba8 2007-09-14 drh: static int cursorHoldsMutex(BtCursor *p){ c287665ba8 2007-09-14 drh: return sqlite3_mutex_held(p->pBt->mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invalidate the overflow page-list cache for cursor pCur, if any. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void invalidateOverflowCache(BtCursor *pCur){ c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: sqlite3_free(pCur->aOverflow); dbda8d6ce9 2007-07-21 drh: pCur->aOverflow = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invalidate the overflow page-list cache for all cursors opened dbda8d6ce9 2007-07-21 drh: ** on the shared btree structure pBt. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void invalidateAllOverflowCache(BtShared *pBt){ dbda8d6ce9 2007-07-21 drh: BtCursor *p; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: for(p=pBt->pCursor; p; p=p->pNext){ dbda8d6ce9 2007-07-21 drh: invalidateOverflowCache(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define invalidateOverflowCache(x) dbda8d6ce9 2007-07-21 drh: #define invalidateAllOverflowCache(x) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Save the current cursor position in the variables BtCursor.nKey dbda8d6ce9 2007-07-21 drh: ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int saveCursorPosition(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( CURSOR_VALID==pCur->eState ); dbda8d6ce9 2007-07-21 drh: assert( 0==pCur->pKey ); c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is an intKey table, then the above call to BtreeKeySize() dbda8d6ce9 2007-07-21 drh: ** stores the integer key in pCur->nKey. In this case this value is dbda8d6ce9 2007-07-21 drh: ** all that is required. Otherwise, if pCur is not open on an intKey dbda8d6ce9 2007-07-21 drh: ** table, then malloc space for and store the pCur->nKey bytes of key dbda8d6ce9 2007-07-21 drh: ** data. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && 0==pCur->pPage->intKey){ c287665ba8 2007-09-14 drh: void *pKey = sqlite3_malloc(pCur->nKey); dbda8d6ce9 2007-07-21 drh: if( pKey ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pCur->pKey = pKey; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: sqlite3_free(pKey); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( !pCur->pPage->intKey || !pCur->pKey ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pCur->pPage); dbda8d6ce9 2007-07-21 drh: pCur->pPage = 0; dbda8d6ce9 2007-07-21 drh: pCur->eState = CURSOR_REQUIRESEEK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: invalidateOverflowCache(pCur); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Save the positions of all cursors except pExcept open on the table dbda8d6ce9 2007-07-21 drh: ** with root-page iRoot. Usually, this is called just before cursor dbda8d6ce9 2007-07-21 drh: ** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ dbda8d6ce9 2007-07-21 drh: BtCursor *p; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); c287665ba8 2007-09-14 drh: assert( pExcept==0 || pExcept->pBt==pBt ); dbda8d6ce9 2007-07-21 drh: for(p=pBt->pCursor; p; p=p->pNext){ dbda8d6ce9 2007-07-21 drh: if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) && dbda8d6ce9 2007-07-21 drh: p->eState==CURSOR_VALID ){ dbda8d6ce9 2007-07-21 drh: int rc = saveCursorPosition(p); dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=rc ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear the current cursor position. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void clearCursorPosition(BtCursor *pCur){ c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: sqlite3_free(pCur->pKey); dbda8d6ce9 2007-07-21 drh: pCur->pKey = 0; dbda8d6ce9 2007-07-21 drh: pCur->eState = CURSOR_INVALID; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Restore the cursor to the position it was in (or as close to as possible) dbda8d6ce9 2007-07-21 drh: ** when saveCursorPosition() was called. Note that this call deletes the dbda8d6ce9 2007-07-21 drh: ** saved position info stored by saveCursorPosition(), so there can be dbda8d6ce9 2007-07-21 drh: ** at most one effective restoreOrClearCursorPosition() call after each dbda8d6ce9 2007-07-21 drh: ** saveCursorPosition(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the second argument argument - doSeek - is false, then instead of dbda8d6ce9 2007-07-21 drh: ** returning the cursor to it's saved position, any saved position is deleted dbda8d6ce9 2007-07-21 drh: ** and the cursor state set to CURSOR_INVALID. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: assert( pCur->eState>=CURSOR_REQUIRESEEK ); c287665ba8 2007-09-14 drh: if( pCur->eState==CURSOR_FAULT ){ c287665ba8 2007-09-14 drh: return pCur->skip; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: if( pCur->isIncrblobHandle ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ABORT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: pCur->eState = CURSOR_INVALID; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3_free(pCur->pKey); dbda8d6ce9 2007-07-21 drh: pCur->pKey = 0; dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define restoreOrClearCursorPosition(p) \ c287665ba8 2007-09-14 drh: (p->eState>=CURSOR_REQUIRESEEK ? \ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeRestoreOrClearCursorPosition(p) : \ dbda8d6ce9 2007-07-21 drh: SQLITE_OK) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given a page number of a regular database page, return the page dbda8d6ce9 2007-07-21 drh: ** number for the pointer-map page that contains the entry for the dbda8d6ce9 2007-07-21 drh: ** input page number. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ c287665ba8 2007-09-14 drh: int nPagesPerMapPage, iPtrMap, ret; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); c287665ba8 2007-09-14 drh: nPagesPerMapPage = (pBt->usableSize/5)+1; c287665ba8 2007-09-14 drh: iPtrMap = (pgno-2)/nPagesPerMapPage; c287665ba8 2007-09-14 drh: ret = (iPtrMap*nPagesPerMapPage) + 2; dbda8d6ce9 2007-07-21 drh: if( ret==PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: ret++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return ret; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write an entry into the pointer map. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine updates the pointer map entry for page number 'key' dbda8d6ce9 2007-07-21 drh: ** so that it maps to type 'eType' and parent page number 'pgno'. dbda8d6ce9 2007-07-21 drh: ** An error code is returned if something goes wrong, otherwise SQLITE_OK. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){ dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; /* The pointer map page */ dbda8d6ce9 2007-07-21 drh: u8 *pPtrmap; /* The pointer map data */ dbda8d6ce9 2007-07-21 drh: Pgno iPtrmap; /* The pointer map page number */ dbda8d6ce9 2007-07-21 drh: int offset; /* Offset in pointer map page */ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: /* The master-journal page number must never be used as a pointer map page */ dbda8d6ce9 2007-07-21 drh: assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pBt->autoVacuum ); dbda8d6ce9 2007-07-21 drh: if( key==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iPtrmap = PTRMAP_PAGENO(pBt, key); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: offset = PTRMAP_PTROFFSET(pBt, key); dbda8d6ce9 2007-07-21 drh: pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ dbda8d6ce9 2007-07-21 drh: TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent)); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pPtrmap[offset] = eType; dbda8d6ce9 2007-07-21 drh: put4byte(&pPtrmap[offset+1], parent); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pDbPage); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read an entry from the pointer map. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine retrieves the pointer map entry for page 'key', writing dbda8d6ce9 2007-07-21 drh: ** the type and parent page number to *pEType and *pPgno respectively. dbda8d6ce9 2007-07-21 drh: ** An error code is returned if something goes wrong, otherwise SQLITE_OK. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; /* The pointer map page */ dbda8d6ce9 2007-07-21 drh: int iPtrmap; /* Pointer map page index */ dbda8d6ce9 2007-07-21 drh: u8 *pPtrmap; /* Pointer map page data */ dbda8d6ce9 2007-07-21 drh: int offset; /* Offset of entry in pointer map */ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: iPtrmap = PTRMAP_PAGENO(pBt, key); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: offset = PTRMAP_PTROFFSET(pBt, key); dbda8d6ce9 2007-07-21 drh: assert( pEType!=0 ); dbda8d6ce9 2007-07-21 drh: *pEType = pPtrmap[offset]; dbda8d6ce9 2007-07-21 drh: if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pDbPage); dbda8d6ce9 2007-07-21 drh: if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_AUTOVACUUM */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given a btree page and a cell index (0 means the first cell on dbda8d6ce9 2007-07-21 drh: ** the page, 1 means the second cell, and so forth) return a pointer dbda8d6ce9 2007-07-21 drh: ** to the cell content. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine works only for pages that do not contain overflow cells. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define findCell(pPage, iCell) \ dbda8d6ce9 2007-07-21 drh: ((pPage)->aData + get2byte(&(pPage)->aData[(pPage)->cellOffset+2*(iCell)])) c287665ba8 2007-09-14 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell){ dbda8d6ce9 2007-07-21 drh: assert( iCell>=0 ); dbda8d6ce9 2007-07-21 drh: assert( iCell<get2byte(&pPage->aData[pPage->hdrOffset+3]) ); dbda8d6ce9 2007-07-21 drh: return findCell(pPage, iCell); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This a more complex version of sqlite3BtreeFindCell() that works for dbda8d6ce9 2007-07-21 drh: ** pages that do contain overflow cells. See insert dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static u8 *findOverflowCell(MemPage *pPage, int iCell){ dbda8d6ce9 2007-07-21 drh: int i; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: for(i=pPage->nOverflow-1; i>=0; i--){ dbda8d6ce9 2007-07-21 drh: int k; dbda8d6ce9 2007-07-21 drh: struct _OvflCell *pOvfl; dbda8d6ce9 2007-07-21 drh: pOvfl = &pPage->aOvfl[i]; dbda8d6ce9 2007-07-21 drh: k = pOvfl->idx; dbda8d6ce9 2007-07-21 drh: if( k<=iCell ){ dbda8d6ce9 2007-07-21 drh: if( k==iCell ){ dbda8d6ce9 2007-07-21 drh: return pOvfl->pCell; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iCell--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return findCell(pPage, iCell); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Parse a cell content block and fill in the CellInfo structure. There dbda8d6ce9 2007-07-21 drh: ** are two versions of this function. sqlite3BtreeParseCell() takes a dbda8d6ce9 2007-07-21 drh: ** cell index as the second argument and sqlite3BtreeParseCellPtr() dbda8d6ce9 2007-07-21 drh: ** takes a pointer to the body of the cell as its second argument. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Within this file, the parseCell() macro can be called instead of dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeParseCellPtr(). Using some compilers, this will be faster. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeParseCellPtr( dbda8d6ce9 2007-07-21 drh: MemPage *pPage, /* Page containing the cell */ dbda8d6ce9 2007-07-21 drh: u8 *pCell, /* Pointer to the cell text. */ dbda8d6ce9 2007-07-21 drh: CellInfo *pInfo /* Fill in this structure */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int n; /* Number bytes in cell content header */ dbda8d6ce9 2007-07-21 drh: u32 nPayload; /* Number of bytes of cell payload */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pInfo->pCell = pCell; dbda8d6ce9 2007-07-21 drh: assert( pPage->leaf==0 || pPage->leaf==1 ); dbda8d6ce9 2007-07-21 drh: n = pPage->childPtrSize; dbda8d6ce9 2007-07-21 drh: assert( n==4-4*pPage->leaf ); dbda8d6ce9 2007-07-21 drh: if( pPage->hasData ){ dbda8d6ce9 2007-07-21 drh: n += getVarint32(&pCell[n], &nPayload); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nPayload = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pInfo->nData = nPayload; dbda8d6ce9 2007-07-21 drh: if( pPage->intKey ){ dbda8d6ce9 2007-07-21 drh: n += getVarint(&pCell[n], (u64 *)&pInfo->nKey); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: u32 x; dbda8d6ce9 2007-07-21 drh: n += getVarint32(&pCell[n], &x); dbda8d6ce9 2007-07-21 drh: pInfo->nKey = x; dbda8d6ce9 2007-07-21 drh: nPayload += x; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pInfo->nPayload = nPayload; dbda8d6ce9 2007-07-21 drh: pInfo->nHeader = n; dbda8d6ce9 2007-07-21 drh: if( nPayload<=pPage->maxLocal ){ dbda8d6ce9 2007-07-21 drh: /* This is the (easy) common case where the entire payload fits dbda8d6ce9 2007-07-21 drh: ** on the local page. No overflow is required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int nSize; /* Total size of cell content in bytes */ dbda8d6ce9 2007-07-21 drh: pInfo->nLocal = nPayload; dbda8d6ce9 2007-07-21 drh: pInfo->iOverflow = 0; dbda8d6ce9 2007-07-21 drh: nSize = nPayload + n; dbda8d6ce9 2007-07-21 drh: if( nSize<4 ){ dbda8d6ce9 2007-07-21 drh: nSize = 4; /* Minimum cell size is 4 */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pInfo->nSize = nSize; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* If the payload will not fit completely on the local page, we have dbda8d6ce9 2007-07-21 drh: ** to decide how much to store locally and how much to spill onto dbda8d6ce9 2007-07-21 drh: ** overflow pages. The strategy is to minimize the amount of unused dbda8d6ce9 2007-07-21 drh: ** space on overflow pages while keeping the amount of local storage dbda8d6ce9 2007-07-21 drh: ** in between minLocal and maxLocal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Warning: changing the way overflow payload is distributed in any dbda8d6ce9 2007-07-21 drh: ** way will result in an incompatible file format. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int minLocal; /* Minimum amount of payload held locally */ dbda8d6ce9 2007-07-21 drh: int maxLocal; /* Maximum amount of payload held locally */ dbda8d6ce9 2007-07-21 drh: int surplus; /* Overflow payload available for local storage */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: minLocal = pPage->minLocal; dbda8d6ce9 2007-07-21 drh: maxLocal = pPage->maxLocal; dbda8d6ce9 2007-07-21 drh: surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4); dbda8d6ce9 2007-07-21 drh: if( surplus <= maxLocal ){ dbda8d6ce9 2007-07-21 drh: pInfo->nLocal = surplus; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pInfo->nLocal = minLocal; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pInfo->iOverflow = pInfo->nLocal + n; dbda8d6ce9 2007-07-21 drh: pInfo->nSize = pInfo->iOverflow + 4; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #define parseCell(pPage, iCell, pInfo) \ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr((pPage), findCell((pPage), (iCell)), (pInfo)) dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeParseCell( dbda8d6ce9 2007-07-21 drh: MemPage *pPage, /* Page containing the cell */ dbda8d6ce9 2007-07-21 drh: int iCell, /* The cell index. First cell is 0 */ dbda8d6ce9 2007-07-21 drh: CellInfo *pInfo /* Fill in this structure */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: parseCell(pPage, iCell, pInfo); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the total number of bytes that a Cell needs in the cell dbda8d6ce9 2007-07-21 drh: ** data area of the btree-page. The return number includes the cell dbda8d6ce9 2007-07-21 drh: ** data header and the local payload, but not any overflow page or dbda8d6ce9 2007-07-21 drh: ** the space used by the cell pointer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: static int cellSize(MemPage *pPage, int iCell){ dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCell(pPage, iCell, &info); dbda8d6ce9 2007-07-21 drh: return info.nSize; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: static int cellSizePtr(MemPage *pPage, u8 *pCell){ dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pPage, pCell, &info); dbda8d6ce9 2007-07-21 drh: return info.nSize; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the cell pCell, part of page pPage contains a pointer dbda8d6ce9 2007-07-21 drh: ** to an overflow page, insert an entry into the pointer-map dbda8d6ce9 2007-07-21 drh: ** for the overflow page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){ dbda8d6ce9 2007-07-21 drh: if( pCell ){ dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pPage, pCell, &info); dbda8d6ce9 2007-07-21 drh: assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); dbda8d6ce9 2007-07-21 drh: if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ dbda8d6ce9 2007-07-21 drh: Pgno ovfl = get4byte(&pCell[info.iOverflow]); dbda8d6ce9 2007-07-21 drh: return ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the cell with index iCell on page pPage contains a pointer dbda8d6ce9 2007-07-21 drh: ** to an overflow page, insert an entry into the pointer-map dbda8d6ce9 2007-07-21 drh: ** for the overflow page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int ptrmapPutOvfl(MemPage *pPage, int iCell){ dbda8d6ce9 2007-07-21 drh: u8 *pCell; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: pCell = findOverflowCell(pPage, iCell); dbda8d6ce9 2007-07-21 drh: return ptrmapPutOvflPtr(pPage, pCell); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Defragment the page given. All Cells are moved to the dbda8d6ce9 2007-07-21 drh: ** end of the page and all free space is collected into one dbda8d6ce9 2007-07-21 drh: ** big FreeBlk that occurs in between the header and cell dbda8d6ce9 2007-07-21 drh: ** pointer array and the cell content area. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int defragmentPage(MemPage *pPage){ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: int pc; /* Address of a i-th cell */ dbda8d6ce9 2007-07-21 drh: int addr; /* Offset of first byte after cell pointer array */ dbda8d6ce9 2007-07-21 drh: int hdr; /* Offset to the page header */ dbda8d6ce9 2007-07-21 drh: int size; /* Size of a cell */ dbda8d6ce9 2007-07-21 drh: int usableSize; /* Number of usable bytes on a page */ dbda8d6ce9 2007-07-21 drh: int cellOffset; /* Offset to the cell pointer array */ dbda8d6ce9 2007-07-21 drh: int brk; /* Offset to the cell content area */ dbda8d6ce9 2007-07-21 drh: int nCell; /* Number of cells on the page */ dbda8d6ce9 2007-07-21 drh: unsigned char *data; /* The page data */ dbda8d6ce9 2007-07-21 drh: unsigned char *temp; /* Temp area for cell content */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( sqlite3PagerIswriteable(pPage->pDbPage) ); dbda8d6ce9 2007-07-21 drh: assert( pPage->pBt!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); dbda8d6ce9 2007-07-21 drh: assert( pPage->nOverflow==0 ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); c287665ba8 2007-09-14 drh: temp = sqlite3_malloc( pPage->pBt->pageSize ); dbda8d6ce9 2007-07-21 drh: if( temp==0 ) return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: data = pPage->aData; dbda8d6ce9 2007-07-21 drh: hdr = pPage->hdrOffset; dbda8d6ce9 2007-07-21 drh: cellOffset = pPage->cellOffset; dbda8d6ce9 2007-07-21 drh: nCell = pPage->nCell; dbda8d6ce9 2007-07-21 drh: assert( nCell==get2byte(&data[hdr+3]) ); dbda8d6ce9 2007-07-21 drh: usableSize = pPage->pBt->usableSize; dbda8d6ce9 2007-07-21 drh: brk = get2byte(&data[hdr+5]); dbda8d6ce9 2007-07-21 drh: memcpy(&temp[brk], &data[brk], usableSize - brk); dbda8d6ce9 2007-07-21 drh: brk = usableSize; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCell; i++){ dbda8d6ce9 2007-07-21 drh: u8 *pAddr; /* The i-th cell pointer */ dbda8d6ce9 2007-07-21 drh: pAddr = &data[cellOffset + i*2]; dbda8d6ce9 2007-07-21 drh: pc = get2byte(pAddr); dbda8d6ce9 2007-07-21 drh: assert( pc<pPage->pBt->usableSize ); dbda8d6ce9 2007-07-21 drh: size = cellSizePtr(pPage, &temp[pc]); dbda8d6ce9 2007-07-21 drh: brk -= size; dbda8d6ce9 2007-07-21 drh: memcpy(&data[brk], &temp[pc], size); dbda8d6ce9 2007-07-21 drh: put2byte(pAddr, brk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( brk>=cellOffset+2*nCell ); dbda8d6ce9 2007-07-21 drh: put2byte(&data[hdr+5], brk); dbda8d6ce9 2007-07-21 drh: data[hdr+1] = 0; dbda8d6ce9 2007-07-21 drh: data[hdr+2] = 0; dbda8d6ce9 2007-07-21 drh: data[hdr+7] = 0; dbda8d6ce9 2007-07-21 drh: addr = cellOffset+2*nCell; dbda8d6ce9 2007-07-21 drh: memset(&data[addr], 0, brk-addr); c287665ba8 2007-09-14 drh: sqlite3_free(temp); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate nByte bytes of space on a page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the index into pPage->aData[] of the first byte of dbda8d6ce9 2007-07-21 drh: ** the new allocation. Or return 0 if there is not enough free dbda8d6ce9 2007-07-21 drh: ** space on the page to satisfy the allocation request. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the page contains nBytes of free space but does not contain dbda8d6ce9 2007-07-21 drh: ** nBytes of contiguous free space, then this routine automatically dbda8d6ce9 2007-07-21 drh: ** calls defragementPage() to consolidate all free space before dbda8d6ce9 2007-07-21 drh: ** allocating the new chunk. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int allocateSpace(MemPage *pPage, int nByte){ dbda8d6ce9 2007-07-21 drh: int addr, pc, hdr; dbda8d6ce9 2007-07-21 drh: int size; dbda8d6ce9 2007-07-21 drh: int nFrag; dbda8d6ce9 2007-07-21 drh: int top; dbda8d6ce9 2007-07-21 drh: int nCell; dbda8d6ce9 2007-07-21 drh: int cellOffset; dbda8d6ce9 2007-07-21 drh: unsigned char *data; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: data = pPage->aData; dbda8d6ce9 2007-07-21 drh: assert( sqlite3PagerIswriteable(pPage->pDbPage) ); dbda8d6ce9 2007-07-21 drh: assert( pPage->pBt ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( nByte<4 ) nByte = 4; dbda8d6ce9 2007-07-21 drh: if( pPage->nFree<nByte || pPage->nOverflow>0 ) return 0; dbda8d6ce9 2007-07-21 drh: pPage->nFree -= nByte; dbda8d6ce9 2007-07-21 drh: hdr = pPage->hdrOffset; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nFrag = data[hdr+7]; dbda8d6ce9 2007-07-21 drh: if( nFrag<60 ){ dbda8d6ce9 2007-07-21 drh: /* Search the freelist looking for a slot big enough to satisfy the dbda8d6ce9 2007-07-21 drh: ** space request. */ dbda8d6ce9 2007-07-21 drh: addr = hdr+1; dbda8d6ce9 2007-07-21 drh: while( (pc = get2byte(&data[addr]))>0 ){ dbda8d6ce9 2007-07-21 drh: size = get2byte(&data[pc+2]); dbda8d6ce9 2007-07-21 drh: if( size>=nByte ){ dbda8d6ce9 2007-07-21 drh: if( size<nByte+4 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&data[addr], &data[pc], 2); dbda8d6ce9 2007-07-21 drh: data[hdr+7] = nFrag + size - nByte; dbda8d6ce9 2007-07-21 drh: return pc; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: put2byte(&data[pc+2], size-nByte); dbda8d6ce9 2007-07-21 drh: return pc + size - nByte; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: addr = pc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate memory from the gap in between the cell pointer array dbda8d6ce9 2007-07-21 drh: ** and the cell content area. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: top = get2byte(&data[hdr+5]); dbda8d6ce9 2007-07-21 drh: nCell = get2byte(&data[hdr+3]); dbda8d6ce9 2007-07-21 drh: cellOffset = pPage->cellOffset; dbda8d6ce9 2007-07-21 drh: if( nFrag>=60 || cellOffset + 2*nCell > top - nByte ){ dbda8d6ce9 2007-07-21 drh: if( defragmentPage(pPage) ) return 0; dbda8d6ce9 2007-07-21 drh: top = get2byte(&data[hdr+5]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: top -= nByte; dbda8d6ce9 2007-07-21 drh: assert( cellOffset + 2*nCell <= top ); dbda8d6ce9 2007-07-21 drh: put2byte(&data[hdr+5], top); dbda8d6ce9 2007-07-21 drh: return top; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a section of the pPage->aData to the freelist. dbda8d6ce9 2007-07-21 drh: ** The first byte of the new free block is pPage->aDisk[start] dbda8d6ce9 2007-07-21 drh: ** and the size of the block is "size" bytes. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Most of the effort here is involved in coalesing adjacent dbda8d6ce9 2007-07-21 drh: ** free blocks into a single big free block. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void freeSpace(MemPage *pPage, int start, int size){ dbda8d6ce9 2007-07-21 drh: int addr, pbegin, hdr; dbda8d6ce9 2007-07-21 drh: unsigned char *data = pPage->aData; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPage->pBt!=0 ); dbda8d6ce9 2007-07-21 drh: assert( sqlite3PagerIswriteable(pPage->pDbPage) ); dbda8d6ce9 2007-07-21 drh: assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) ); dbda8d6ce9 2007-07-21 drh: assert( (start + size)<=pPage->pBt->usableSize ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( size<4 ) size = 4; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SECURE_DELETE dbda8d6ce9 2007-07-21 drh: /* Overwrite deleted information with zeros when the SECURE_DELETE dbda8d6ce9 2007-07-21 drh: ** option is enabled at compile-time */ dbda8d6ce9 2007-07-21 drh: memset(&data[start], 0, size); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add the space back into the linked list of freeblocks */ dbda8d6ce9 2007-07-21 drh: hdr = pPage->hdrOffset; dbda8d6ce9 2007-07-21 drh: addr = hdr + 1; dbda8d6ce9 2007-07-21 drh: while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){ dbda8d6ce9 2007-07-21 drh: assert( pbegin<=pPage->pBt->usableSize-4 ); dbda8d6ce9 2007-07-21 drh: assert( pbegin>addr ); dbda8d6ce9 2007-07-21 drh: addr = pbegin; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pbegin<=pPage->pBt->usableSize-4 ); dbda8d6ce9 2007-07-21 drh: assert( pbegin>addr || pbegin==0 ); dbda8d6ce9 2007-07-21 drh: put2byte(&data[addr], start); dbda8d6ce9 2007-07-21 drh: put2byte(&data[start], pbegin); dbda8d6ce9 2007-07-21 drh: put2byte(&data[start+2], size); dbda8d6ce9 2007-07-21 drh: pPage->nFree += size; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Coalesce adjacent free blocks */ dbda8d6ce9 2007-07-21 drh: addr = pPage->hdrOffset + 1; dbda8d6ce9 2007-07-21 drh: while( (pbegin = get2byte(&data[addr]))>0 ){ dbda8d6ce9 2007-07-21 drh: int pnext, psize; dbda8d6ce9 2007-07-21 drh: assert( pbegin>addr ); dbda8d6ce9 2007-07-21 drh: assert( pbegin<=pPage->pBt->usableSize-4 ); dbda8d6ce9 2007-07-21 drh: pnext = get2byte(&data[pbegin]); dbda8d6ce9 2007-07-21 drh: psize = get2byte(&data[pbegin+2]); dbda8d6ce9 2007-07-21 drh: if( pbegin + psize + 3 >= pnext && pnext>0 ){ dbda8d6ce9 2007-07-21 drh: int frag = pnext - (pbegin+psize); dbda8d6ce9 2007-07-21 drh: assert( frag<=data[pPage->hdrOffset+7] ); dbda8d6ce9 2007-07-21 drh: data[pPage->hdrOffset+7] -= frag; dbda8d6ce9 2007-07-21 drh: put2byte(&data[pbegin], get2byte(&data[pnext])); dbda8d6ce9 2007-07-21 drh: put2byte(&data[pbegin+2], pnext+get2byte(&data[pnext+2])-pbegin); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: addr = pbegin; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the cell content area begins with a freeblock, remove it. */ dbda8d6ce9 2007-07-21 drh: if( data[hdr+1]==data[hdr+5] && data[hdr+2]==data[hdr+6] ){ dbda8d6ce9 2007-07-21 drh: int top; dbda8d6ce9 2007-07-21 drh: pbegin = get2byte(&data[hdr+1]); dbda8d6ce9 2007-07-21 drh: memcpy(&data[hdr+1], &data[pbegin], 2); dbda8d6ce9 2007-07-21 drh: top = get2byte(&data[hdr+5]); dbda8d6ce9 2007-07-21 drh: put2byte(&data[hdr+5], top + get2byte(&data[pbegin+2])); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Decode the flags byte (the first byte of the header) for a page dbda8d6ce9 2007-07-21 drh: ** and initialize fields of the MemPage structure accordingly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void decodeFlags(MemPage *pPage, int flagByte){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt; /* A copy of pPage->pBt */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0; dbda8d6ce9 2007-07-21 drh: pPage->zeroData = (flagByte & PTF_ZERODATA)!=0; dbda8d6ce9 2007-07-21 drh: pPage->leaf = (flagByte & PTF_LEAF)!=0; dbda8d6ce9 2007-07-21 drh: pPage->childPtrSize = 4*(pPage->leaf==0); dbda8d6ce9 2007-07-21 drh: pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: if( flagByte & PTF_LEAFDATA ){ dbda8d6ce9 2007-07-21 drh: pPage->leafData = 1; dbda8d6ce9 2007-07-21 drh: pPage->maxLocal = pBt->maxLeaf; dbda8d6ce9 2007-07-21 drh: pPage->minLocal = pBt->minLeaf; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pPage->leafData = 0; dbda8d6ce9 2007-07-21 drh: pPage->maxLocal = pBt->maxLocal; dbda8d6ce9 2007-07-21 drh: pPage->minLocal = pBt->minLocal; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Initialize the auxiliary information for a disk block. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pParent parameter must be a pointer to the MemPage which dbda8d6ce9 2007-07-21 drh: ** is the parent of the page being initialized. The root of a dbda8d6ce9 2007-07-21 drh: ** BTree has no parent and so for that page, pParent==NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK on success. If we see that the page does dbda8d6ce9 2007-07-21 drh: ** not contain a well-formed database page, then return dbda8d6ce9 2007-07-21 drh: ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not dbda8d6ce9 2007-07-21 drh: ** guarantee that the page is well-formed. It only shows that dbda8d6ce9 2007-07-21 drh: ** we failed to detect any corruption. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeInitPage( dbda8d6ce9 2007-07-21 drh: MemPage *pPage, /* The page to be initialized */ dbda8d6ce9 2007-07-21 drh: MemPage *pParent /* The parent. Might be NULL */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int pc; /* Address of a freeblock within pPage->aData[] */ dbda8d6ce9 2007-07-21 drh: int hdr; /* Offset to beginning of page header */ dbda8d6ce9 2007-07-21 drh: u8 *data; /* Equal to pPage->aData */ dbda8d6ce9 2007-07-21 drh: BtShared *pBt; /* The main btree structure */ dbda8d6ce9 2007-07-21 drh: int usableSize; /* Amount of usable space on each page */ dbda8d6ce9 2007-07-21 drh: int cellOffset; /* Offset from start of page to first cell pointer */ dbda8d6ce9 2007-07-21 drh: int nFree; /* Number of unused bytes on the page */ dbda8d6ce9 2007-07-21 drh: int top; /* First byte of the cell content area */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: assert( pBt!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pParent==0 || pParent->pBt==pBt ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); c287665ba8 2007-09-14 drh: assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); c287665ba8 2007-09-14 drh: assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); dbda8d6ce9 2007-07-21 drh: if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){ dbda8d6ce9 2007-07-21 drh: /* The parent page should never change unless the file is corrupt */ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPage->isInit ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( pPage->pParent==0 && pParent!=0 ){ dbda8d6ce9 2007-07-21 drh: pPage->pParent = pParent; dbda8d6ce9 2007-07-21 drh: sqlite3PagerRef(pParent->pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: hdr = pPage->hdrOffset; dbda8d6ce9 2007-07-21 drh: data = pPage->aData; dbda8d6ce9 2007-07-21 drh: decodeFlags(pPage, data[hdr]); dbda8d6ce9 2007-07-21 drh: pPage->nOverflow = 0; dbda8d6ce9 2007-07-21 drh: pPage->idxShift = 0; dbda8d6ce9 2007-07-21 drh: usableSize = pBt->usableSize; dbda8d6ce9 2007-07-21 drh: pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf; dbda8d6ce9 2007-07-21 drh: top = get2byte(&data[hdr+5]); dbda8d6ce9 2007-07-21 drh: pPage->nCell = get2byte(&data[hdr+3]); dbda8d6ce9 2007-07-21 drh: if( pPage->nCell>MX_CELL(pBt) ){ dbda8d6ce9 2007-07-21 drh: /* To many cells for a single page. The page must be corrupt */ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){ dbda8d6ce9 2007-07-21 drh: /* All pages must have at least one cell, except for root pages */ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Compute the total free space on the page */ dbda8d6ce9 2007-07-21 drh: pc = get2byte(&data[hdr+1]); dbda8d6ce9 2007-07-21 drh: nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell); dbda8d6ce9 2007-07-21 drh: while( pc>0 ){ dbda8d6ce9 2007-07-21 drh: int next, size; dbda8d6ce9 2007-07-21 drh: if( pc>usableSize-4 ){ dbda8d6ce9 2007-07-21 drh: /* Free block is off the page */ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: next = get2byte(&data[pc]); dbda8d6ce9 2007-07-21 drh: size = get2byte(&data[pc+2]); dbda8d6ce9 2007-07-21 drh: if( next>0 && next<=pc+size+3 ){ dbda8d6ce9 2007-07-21 drh: /* Free blocks must be in accending order */ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nFree += size; dbda8d6ce9 2007-07-21 drh: pc = next; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPage->nFree = nFree; dbda8d6ce9 2007-07-21 drh: if( nFree>=usableSize ){ dbda8d6ce9 2007-07-21 drh: /* Free space cannot exceed total page size */ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPage->isInit = 1; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set up a raw page so that it looks like a database page holding dbda8d6ce9 2007-07-21 drh: ** no entries. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void zeroPage(MemPage *pPage, int flags){ dbda8d6ce9 2007-07-21 drh: unsigned char *data = pPage->aData; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: int hdr = pPage->hdrOffset; dbda8d6ce9 2007-07-21 drh: int first; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno ); c287665ba8 2007-09-14 drh: assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); c287665ba8 2007-09-14 drh: assert( sqlite3PagerGetData(pPage->pDbPage) == data ); dbda8d6ce9 2007-07-21 drh: assert( sqlite3PagerIswriteable(pPage->pDbPage) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: memset(&data[hdr], 0, pBt->usableSize - hdr); dbda8d6ce9 2007-07-21 drh: data[hdr] = flags; dbda8d6ce9 2007-07-21 drh: first = hdr + 8 + 4*((flags&PTF_LEAF)==0); dbda8d6ce9 2007-07-21 drh: memset(&data[hdr+1], 0, 4); dbda8d6ce9 2007-07-21 drh: data[hdr+7] = 0; dbda8d6ce9 2007-07-21 drh: put2byte(&data[hdr+5], pBt->usableSize); dbda8d6ce9 2007-07-21 drh: pPage->nFree = pBt->usableSize - first; dbda8d6ce9 2007-07-21 drh: decodeFlags(pPage, flags); dbda8d6ce9 2007-07-21 drh: pPage->hdrOffset = hdr; dbda8d6ce9 2007-07-21 drh: pPage->cellOffset = first; dbda8d6ce9 2007-07-21 drh: pPage->nOverflow = 0; dbda8d6ce9 2007-07-21 drh: pPage->idxShift = 0; dbda8d6ce9 2007-07-21 drh: pPage->nCell = 0; dbda8d6ce9 2007-07-21 drh: pPage->isInit = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Get a page from the pager. Initialize the MemPage.pBt and dbda8d6ce9 2007-07-21 drh: ** MemPage.aData elements if needed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the noContent flag is set, it means that we do not care about dbda8d6ce9 2007-07-21 drh: ** the content of the page at this time. So do not go to the disk dbda8d6ce9 2007-07-21 drh: ** to fetch the content. Just fill in the content with zeros for now. dbda8d6ce9 2007-07-21 drh: ** If in the future we call sqlite3PagerWrite() on this page, that dbda8d6ce9 2007-07-21 drh: ** means we have started to be concerned about content and the disk dbda8d6ce9 2007-07-21 drh: ** read should occur at that point. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeGetPage( dbda8d6ce9 2007-07-21 drh: BtShared *pBt, /* The btree */ dbda8d6ce9 2007-07-21 drh: Pgno pgno, /* Number of the page to fetch */ dbda8d6ce9 2007-07-21 drh: MemPage **ppPage, /* Return the page in this parameter */ dbda8d6ce9 2007-07-21 drh: int noContent /* Do not load page content if true */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage); dbda8d6ce9 2007-07-21 drh: pPage->aData = sqlite3PagerGetData(pDbPage); dbda8d6ce9 2007-07-21 drh: pPage->pDbPage = pDbPage; dbda8d6ce9 2007-07-21 drh: pPage->pBt = pBt; dbda8d6ce9 2007-07-21 drh: pPage->pgno = pgno; dbda8d6ce9 2007-07-21 drh: pPage->hdrOffset = pPage->pgno==1 ? 100 : 0; dbda8d6ce9 2007-07-21 drh: *ppPage = pPage; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Get a page from the pager and initialize it. This routine dbda8d6ce9 2007-07-21 drh: ** is just a convenience wrapper around separate calls to dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeGetPage() and sqlite3BtreeInitPage(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getAndInitPage( dbda8d6ce9 2007-07-21 drh: BtShared *pBt, /* The database file */ dbda8d6ce9 2007-07-21 drh: Pgno pgno, /* Number of the page to get */ dbda8d6ce9 2007-07-21 drh: MemPage **ppPage, /* Write the page pointer here */ dbda8d6ce9 2007-07-21 drh: MemPage *pParent /* Parent of the page */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pgno==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeInitPage(*ppPage, pParent); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release a MemPage. This should be called once for each prior dbda8d6ce9 2007-07-21 drh: ** call to sqlite3BtreeGetPage. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void releasePage(MemPage *pPage){ dbda8d6ce9 2007-07-21 drh: if( pPage ){ dbda8d6ce9 2007-07-21 drh: assert( pPage->aData ); dbda8d6ce9 2007-07-21 drh: assert( pPage->pBt ); c287665ba8 2007-09-14 drh: assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); c287665ba8 2007-09-14 drh: assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called when the reference count for a page dbda8d6ce9 2007-07-21 drh: ** reaches zero. We need to unref the pParent pointer when that dbda8d6ce9 2007-07-21 drh: ** happens. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void pageDestructor(DbPage *pData, int pageSize){ dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: assert( (pageSize & 7)==0 ); dbda8d6ce9 2007-07-21 drh: pPage = (MemPage *)sqlite3PagerGetExtra(pData); c287665ba8 2007-09-14 drh: assert( pPage->isInit==0 || sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pPage->pParent ){ dbda8d6ce9 2007-07-21 drh: MemPage *pParent = pPage->pParent; c287665ba8 2007-09-14 drh: assert( pParent->pBt==pPage->pBt ); dbda8d6ce9 2007-07-21 drh: pPage->pParent = 0; dbda8d6ce9 2007-07-21 drh: releasePage(pParent); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPage->isInit = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** During a rollback, when the pager reloads information into the cache dbda8d6ce9 2007-07-21 drh: ** so that the cache is restored to its original state at the start of dbda8d6ce9 2007-07-21 drh: ** the transaction, for each page restored this routine is called. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine needs to reset the extra data section at the end of the dbda8d6ce9 2007-07-21 drh: ** page to agree with the restored data. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void pageReinit(DbPage *pData, int pageSize){ dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: assert( (pageSize & 7)==0 ); dbda8d6ce9 2007-07-21 drh: pPage = (MemPage *)sqlite3PagerGetExtra(pData); dbda8d6ce9 2007-07-21 drh: if( pPage->isInit ){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: pPage->isInit = 0; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeInitPage(pPage, pPage->pParent); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Open a database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** zFilename is the name of the database file. If zFilename is NULL dbda8d6ce9 2007-07-21 drh: ** a new database with a random name is created. This randomly named dbda8d6ce9 2007-07-21 drh: ** database file will be deleted when sqlite3BtreeClose() is called. c287665ba8 2007-09-14 drh: ** If zFilename is ":memory:" then an in-memory database is created c287665ba8 2007-09-14 drh: ** that is automatically destroyed when it is closed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeOpen( dbda8d6ce9 2007-07-21 drh: const char *zFilename, /* Name of the file containing the BTree database */ dbda8d6ce9 2007-07-21 drh: sqlite3 *pSqlite, /* Associated database handle */ dbda8d6ce9 2007-07-21 drh: Btree **ppBtree, /* Pointer to new Btree object written here */ c287665ba8 2007-09-14 drh: int flags, /* Options */ c287665ba8 2007-09-14 drh: int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs; /* The VFS to use for this btree */ c287665ba8 2007-09-14 drh: BtShared *pBt = 0; /* Shared part of btree structure */ dbda8d6ce9 2007-07-21 drh: Btree *p; /* Handle to return */ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int nReserve; dbda8d6ce9 2007-07-21 drh: unsigned char zDbHeader[100]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the variable isMemdb to true for an in-memory database, or dbda8d6ce9 2007-07-21 drh: ** false for a file-based database. This symbol is only required if dbda8d6ce9 2007-07-21 drh: ** either of the shared-data or autovacuum features are compiled dbda8d6ce9 2007-07-21 drh: ** into the library. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM) dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_MEMORYDB dbda8d6ce9 2007-07-21 drh: const int isMemdb = 0; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: const int isMemdb = zFilename && !strcmp(zFilename, ":memory:"); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( pSqlite!=0 ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pSqlite->mutex) ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pVfs = pSqlite->pVfs; c287665ba8 2007-09-14 drh: p = sqlite3MallocZero(sizeof(Btree)); dbda8d6ce9 2007-07-21 drh: if( !p ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->inTrans = TRANS_NONE; dbda8d6ce9 2007-07-21 drh: p->pSqlite = pSqlite; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** If this Btree is a candidate for shared cache, try to find an c287665ba8 2007-09-14 drh: ** existing BtShared object that we can share with c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( (flags & BTREE_PRIVATE)==0 c287665ba8 2007-09-14 drh: && isMemdb==0 c287665ba8 2007-09-14 drh: && (pSqlite->flags & SQLITE_Vtab)==0 c287665ba8 2007-09-14 drh: && zFilename && zFilename[0] c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: if( sqlite3SharedCacheEnabled ){ c287665ba8 2007-09-14 drh: char *zFullPathname = (char *)sqlite3_malloc(pVfs->mxPathname); c287665ba8 2007-09-14 drh: sqlite3_mutex *mutexShared; c287665ba8 2007-09-14 drh: p->sharable = 1; c287665ba8 2007-09-14 drh: if( pSqlite ){ c287665ba8 2007-09-14 drh: pSqlite->flags |= SQLITE_SharedCache; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( !zFullPathname ){ c287665ba8 2007-09-14 drh: sqlite3_free(p); c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3OsFullPathname(pVfs, zFilename, zFullPathname); c287665ba8 2007-09-14 drh: mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutexShared); c287665ba8 2007-09-14 drh: for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){ c287665ba8 2007-09-14 drh: assert( pBt->nRef>0 ); c287665ba8 2007-09-14 drh: if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) c287665ba8 2007-09-14 drh: && sqlite3PagerVfs(pBt->pPager)==pVfs ){ c287665ba8 2007-09-14 drh: p->pBt = pBt; c287665ba8 2007-09-14 drh: pBt->nRef++; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutexShared); c287665ba8 2007-09-14 drh: sqlite3_free(zFullPathname); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: else{ c287665ba8 2007-09-14 drh: /* In debug mode, we mark all persistent databases as sharable c287665ba8 2007-09-14 drh: ** even when they are not. This exercises the locking code and c287665ba8 2007-09-14 drh: ** gives more opportunity for asserts(sqlite3_mutex_held()) c287665ba8 2007-09-14 drh: ** statements to find locking problems. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: p->sharable = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: if( pBt==0 ){ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The following asserts make sure that structures used by the btree are c287665ba8 2007-09-14 drh: ** the right size. This is to guard against size changes that result c287665ba8 2007-09-14 drh: ** when compiling on a different architecture. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert( sizeof(i64)==8 || sizeof(i64)==4 ); c287665ba8 2007-09-14 drh: assert( sizeof(u64)==8 || sizeof(u64)==4 ); c287665ba8 2007-09-14 drh: assert( sizeof(u32)==4 ); c287665ba8 2007-09-14 drh: assert( sizeof(u16)==2 ); c287665ba8 2007-09-14 drh: assert( sizeof(Pgno)==4 ); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pBt = sqlite3MallocZero( sizeof(*pBt) ); c287665ba8 2007-09-14 drh: if( pBt==0 ){ c287665ba8 2007-09-14 drh: rc = SQLITE_NOMEM; c287665ba8 2007-09-14 drh: goto btree_open_out; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, c287665ba8 2007-09-14 drh: EXTRA_SIZE, flags, vfsFlags); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: goto btree_open_out; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p->pBt = pBt; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3PagerSetDestructor(pBt->pPager, pageDestructor); c287665ba8 2007-09-14 drh: sqlite3PagerSetReiniter(pBt->pPager, pageReinit); c287665ba8 2007-09-14 drh: pBt->pCursor = 0; c287665ba8 2007-09-14 drh: pBt->pPage1 = 0; c287665ba8 2007-09-14 drh: pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager); c287665ba8 2007-09-14 drh: pBt->pageSize = get2byte(&zDbHeader[16]); c287665ba8 2007-09-14 drh: if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE c287665ba8 2007-09-14 drh: || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ c287665ba8 2007-09-14 drh: pBt->pageSize = 0; c287665ba8 2007-09-14 drh: sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); c287665ba8 2007-09-14 drh: pBt->maxEmbedFrac = 64; /* 25% */ c287665ba8 2007-09-14 drh: pBt->minEmbedFrac = 32; /* 12.5% */ c287665ba8 2007-09-14 drh: pBt->minLeafFrac = 32; /* 12.5% */ c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_AUTOVACUUM c287665ba8 2007-09-14 drh: /* If the magic name ":memory:" will create an in-memory database, then c287665ba8 2007-09-14 drh: ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if c287665ba8 2007-09-14 drh: ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if c287665ba8 2007-09-14 drh: ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a c287665ba8 2007-09-14 drh: ** regular file-name. In this case the auto-vacuum applies as per normal. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( zFilename && !isMemdb ){ c287665ba8 2007-09-14 drh: pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0); c287665ba8 2007-09-14 drh: pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: nReserve = 0; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: nReserve = zDbHeader[20]; c287665ba8 2007-09-14 drh: pBt->maxEmbedFrac = zDbHeader[21]; c287665ba8 2007-09-14 drh: pBt->minEmbedFrac = zDbHeader[22]; c287665ba8 2007-09-14 drh: pBt->minLeafFrac = zDbHeader[23]; c287665ba8 2007-09-14 drh: pBt->pageSizeFixed = 1; c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_AUTOVACUUM c287665ba8 2007-09-14 drh: pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0); c287665ba8 2007-09-14 drh: pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0); c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pBt->usableSize = pBt->pageSize - nReserve; c287665ba8 2007-09-14 drh: assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ c287665ba8 2007-09-14 drh: sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) c287665ba8 2007-09-14 drh: /* Add the new BtShared object to the linked list sharable BtShareds. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( p->sharable ){ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutexShared; c287665ba8 2007-09-14 drh: pBt->nRef = 1; c287665ba8 2007-09-14 drh: mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: if( SQLITE_THREADSAFE ){ c287665ba8 2007-09-14 drh: pBt->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); c287665ba8 2007-09-14 drh: if( pBt->mutex==0 ){ c287665ba8 2007-09-14 drh: rc = SQLITE_NOMEM; c287665ba8 2007-09-14 drh: pSqlite->mallocFailed = 0; c287665ba8 2007-09-14 drh: goto btree_open_out; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutexShared); c287665ba8 2007-09-14 drh: pBt->pNext = sqlite3SharedCacheList; c287665ba8 2007-09-14 drh: sqlite3SharedCacheList = pBt; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutexShared); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) c287665ba8 2007-09-14 drh: /* If the new Btree uses a sharable pBtShared, then link the new c287665ba8 2007-09-14 drh: ** Btree into the list of all sharable Btrees for the same connection. c287665ba8 2007-09-14 drh: ** The list is kept in ascending order by pBt address. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( p->sharable ){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: Btree *pSib; c287665ba8 2007-09-14 drh: for(i=0; i<pSqlite->nDb; i++){ c287665ba8 2007-09-14 drh: if( (pSib = pSqlite->aDb[i].pBt)!=0 && pSib->sharable ){ c287665ba8 2007-09-14 drh: while( pSib->pPrev ){ pSib = pSib->pPrev; } c287665ba8 2007-09-14 drh: if( p->pBt<pSib->pBt ){ c287665ba8 2007-09-14 drh: p->pNext = pSib; c287665ba8 2007-09-14 drh: p->pPrev = 0; c287665ba8 2007-09-14 drh: pSib->pPrev = p; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: while( pSib->pNext && pSib->pNext->pBt<p->pBt ){ c287665ba8 2007-09-14 drh: pSib = pSib->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p->pNext = pSib->pNext; c287665ba8 2007-09-14 drh: p->pPrev = pSib; c287665ba8 2007-09-14 drh: if( p->pNext ){ c287665ba8 2007-09-14 drh: p->pNext->pPrev = p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pSib->pNext = p; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: *ppBtree = p; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: btree_open_out: dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( pBt && pBt->pPager ){ dbda8d6ce9 2007-07-21 drh: sqlite3PagerClose(pBt->pPager); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pBt); c287665ba8 2007-09-14 drh: sqlite3_free(p); dbda8d6ce9 2007-07-21 drh: *ppBtree = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Decrement the BtShared.nRef counter. When it reaches zero, c287665ba8 2007-09-14 drh: ** remove the BtShared structure from the sharing list. Return c287665ba8 2007-09-14 drh: ** true if the BtShared.nRef counter reaches zero and return c287665ba8 2007-09-14 drh: ** false if it is still positive. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int removeFromSharingList(BtShared *pBt){ c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_SHARED_CACHE c287665ba8 2007-09-14 drh: sqlite3_mutex *pMaster; c287665ba8 2007-09-14 drh: BtShared *pList; c287665ba8 2007-09-14 drh: int removed = 0; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_notheld(pBt->mutex) ); c287665ba8 2007-09-14 drh: pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(pMaster); c287665ba8 2007-09-14 drh: pBt->nRef--; c287665ba8 2007-09-14 drh: if( pBt->nRef<=0 ){ c287665ba8 2007-09-14 drh: if( sqlite3SharedCacheList==pBt ){ c287665ba8 2007-09-14 drh: sqlite3SharedCacheList = pBt->pNext; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pList = sqlite3SharedCacheList; c287665ba8 2007-09-14 drh: while( pList && pList->pNext!=pBt ){ c287665ba8 2007-09-14 drh: pList=pList->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pList ){ c287665ba8 2007-09-14 drh: pList->pNext = pBt->pNext; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( SQLITE_THREADSAFE ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_free(pBt->mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: removed = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(pMaster); c287665ba8 2007-09-14 drh: return removed; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: return 1; c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close an open database and invalidate all cursors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: BtCursor *pCur; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Close all cursors opened via this handle. */ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: pCur = pBt->pCursor; dbda8d6ce9 2007-07-21 drh: while( pCur ){ dbda8d6ce9 2007-07-21 drh: BtCursor *pTmp = pCur; dbda8d6ce9 2007-07-21 drh: pCur = pCur->pNext; dbda8d6ce9 2007-07-21 drh: if( pTmp->pBtree==p ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCloseCursor(pTmp); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Rollback any active transaction and free the handle structure. dbda8d6ce9 2007-07-21 drh: ** The call to sqlite3BtreeRollback() drops any table-locks held by dbda8d6ce9 2007-07-21 drh: ** this handle. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeRollback(p); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* If there are still other outstanding references to the shared-btree dbda8d6ce9 2007-07-21 drh: ** structure, return now. The remainder of this procedure cleans dbda8d6ce9 2007-07-21 drh: ** up the shared-btree. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: assert( p->wantToLock==0 && p->locked==0 ); c287665ba8 2007-09-14 drh: if( !p->sharable || removeFromSharingList(pBt) ){ c287665ba8 2007-09-14 drh: /* The pBt is no longer on the sharing list, so we can access c287665ba8 2007-09-14 drh: ** it without having to hold the mutex. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Clean out and delete the BtShared object. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert( !pBt->pCursor ); c287665ba8 2007-09-14 drh: sqlite3PagerClose(pBt->pPager); c287665ba8 2007-09-14 drh: if( pBt->xFreeSchema && pBt->pSchema ){ c287665ba8 2007-09-14 drh: pBt->xFreeSchema(pBt->pSchema); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pBt->pSchema); c287665ba8 2007-09-14 drh: sqlite3_free(pBt); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_SHARED_CACHE c287665ba8 2007-09-14 drh: assert( p->wantToLock==0 ); c287665ba8 2007-09-14 drh: assert( p->locked==0 ); c287665ba8 2007-09-14 drh: if( p->pPrev ) p->pPrev->pNext = p->pNext; c287665ba8 2007-09-14 drh: if( p->pNext ) p->pNext->pPrev = p->pPrev; c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3_free(p); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the busy handler callback function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: pBt->pBusyHandler = pHandler; dbda8d6ce9 2007-07-21 drh: sqlite3PagerSetBusyhandler(pBt->pPager, pHandler); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the limit on the number of pages allowed in the cache. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The maximum number of cache pages is set to the absolute dbda8d6ce9 2007-07-21 drh: ** value of mxPage. If mxPage is negative, the pager will dbda8d6ce9 2007-07-21 drh: ** operate asynchronously - it will not stop to do fsync()s dbda8d6ce9 2007-07-21 drh: ** to insure data is written to the disk surface before dbda8d6ce9 2007-07-21 drh: ** continuing. Transactions still work if synchronous is off, dbda8d6ce9 2007-07-21 drh: ** and the database cannot be corrupted if this program dbda8d6ce9 2007-07-21 drh: ** crashes. But if the operating system crashes or there is dbda8d6ce9 2007-07-21 drh: ** an abrupt power failure when synchronous is off, the database dbda8d6ce9 2007-07-21 drh: ** could be left in an inconsistent and unrecoverable state. dbda8d6ce9 2007-07-21 drh: ** Synchronous is on by default so database corruption is not dbda8d6ce9 2007-07-21 drh: ** normally a worry. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: sqlite3PagerSetCachesize(pBt->pPager, mxPage); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the way data is synced to disk in order to increase or decrease dbda8d6ce9 2007-07-21 drh: ** how well the database resists damage due to OS crashes and power dbda8d6ce9 2007-07-21 drh: ** failures. Level 1 is the same as asynchronous (no syncs() occur and dbda8d6ce9 2007-07-21 drh: ** there is a high probability of damage) Level 2 is the default. There dbda8d6ce9 2007-07-21 drh: ** is a very low but non-zero probability of damage. Level 3 reduces the dbda8d6ce9 2007-07-21 drh: ** probability of damage to near zero but with a write performance reduction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the given btree is set to safety level 1. In other dbda8d6ce9 2007-07-21 drh: ** words, return TRUE if no sync() occurs on the disk files. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: assert( pBt && pBt->pPager ); c287665ba8 2007-09-14 drh: rc = sqlite3PagerNosync(pBt->pPager); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the default pages size and the number of reserved bytes per page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The page size must be a power of 2 between 512 and 65536. If the page dbda8d6ce9 2007-07-21 drh: ** size supplied does not meet this constraint then the page size is not dbda8d6ce9 2007-07-21 drh: ** changed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Page sizes are constrained to be a power of two so that the region dbda8d6ce9 2007-07-21 drh: ** of the database file used for locking (beginning at PENDING_BYTE, dbda8d6ce9 2007-07-21 drh: ** the first byte past the 1GB boundary, 0x40000000) needs to occur dbda8d6ce9 2007-07-21 drh: ** at the beginning of a page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If parameter nReserve is less than zero, then the number of reserved dbda8d6ce9 2007-07-21 drh: ** bytes per page is left unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: if( pBt->pageSizeFixed ){ c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return SQLITE_READONLY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nReserve<0 ){ dbda8d6ce9 2007-07-21 drh: nReserve = pBt->pageSize - pBt->usableSize; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && dbda8d6ce9 2007-07-21 drh: ((pageSize-1)&pageSize)==0 ){ dbda8d6ce9 2007-07-21 drh: assert( (pageSize & 7)==0 ); dbda8d6ce9 2007-07-21 drh: assert( !pBt->pPage1 && !pBt->pCursor ); c287665ba8 2007-09-14 drh: pBt->pageSize = pageSize; c287665ba8 2007-09-14 drh: rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pBt->usableSize = pBt->pageSize - nReserve; c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the currently defined page size dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){ dbda8d6ce9 2007-07-21 drh: return p->pBt->pageSize; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree *p){ c287665ba8 2007-09-14 drh: int n; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); c287665ba8 2007-09-14 drh: n = p->pBt->pageSize - p->pBt->usableSize; c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the maximum page count for a database if mxPage is positive. dbda8d6ce9 2007-07-21 drh: ** No changes are made if mxPage is 0 or negative. dbda8d6ce9 2007-07-21 drh: ** Regardless of the value of mxPage, return the maximum page count. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ c287665ba8 2007-09-14 drh: int n; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); c287665ba8 2007-09-14 drh: n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' dbda8d6ce9 2007-07-21 drh: ** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it dbda8d6ce9 2007-07-21 drh: ** is disabled. The default value for the auto-vacuum property is dbda8d6ce9 2007-07-21 drh: ** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: return SQLITE_READONLY; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int av = (autoVacuum?1:0); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: if( pBt->pageSizeFixed && av!=pBt->autoVacuum ){ c287665ba8 2007-09-14 drh: rc = SQLITE_READONLY; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pBt->autoVacuum = av; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the value of the 'auto-vacuum' property. If auto-vacuum is dbda8d6ce9 2007-07-21 drh: ** enabled 1 is returned. Otherwise 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: return BTREE_AUTOVACUUM_NONE; dbda8d6ce9 2007-07-21 drh: #else c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); c287665ba8 2007-09-14 drh: rc = ( dbda8d6ce9 2007-07-21 drh: (!p->pBt->autoVacuum)?BTREE_AUTOVACUUM_NONE: dbda8d6ce9 2007-07-21 drh: (!p->pBt->incrVacuum)?BTREE_AUTOVACUUM_FULL: dbda8d6ce9 2007-07-21 drh: BTREE_AUTOVACUUM_INCR dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Get a reference to pPage1 of the database file. This will dbda8d6ce9 2007-07-21 drh: ** also acquire a readlock on that file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK is returned on success. If the file is not a dbda8d6ce9 2007-07-21 drh: ** well-formed database file, then SQLITE_CORRUPT is returned. dbda8d6ce9 2007-07-21 drh: ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM dbda8d6ce9 2007-07-21 drh: ** is returned if we run out of memory. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int lockBtree(BtShared *pBt){ dbda8d6ce9 2007-07-21 drh: int rc, pageSize; dbda8d6ce9 2007-07-21 drh: MemPage *pPage1; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pBt->pPage1 ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, 1, &pPage1, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do some checking to help insure the file we opened really is dbda8d6ce9 2007-07-21 drh: ** a valid database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOTADB; dbda8d6ce9 2007-07-21 drh: if( sqlite3PagerPagecount(pBt->pPager)>0 ){ dbda8d6ce9 2007-07-21 drh: u8 *page1 = pPage1->aData; dbda8d6ce9 2007-07-21 drh: if( memcmp(page1, zMagicHeader, 16)!=0 ){ dbda8d6ce9 2007-07-21 drh: goto page1_init_failed; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( page1[18]>1 ){ dbda8d6ce9 2007-07-21 drh: pBt->readOnly = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( page1[19]>1 ){ dbda8d6ce9 2007-07-21 drh: goto page1_init_failed; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pageSize = get2byte(&page1[16]); c287665ba8 2007-09-14 drh: if( ((pageSize-1)&pageSize)!=0 || pageSize<512 || c287665ba8 2007-09-14 drh: (SQLITE_MAX_PAGE_SIZE<32768 && pageSize>SQLITE_MAX_PAGE_SIZE) c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: goto page1_init_failed; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( (pageSize & 7)==0 ); dbda8d6ce9 2007-07-21 drh: pBt->pageSize = pageSize; dbda8d6ce9 2007-07-21 drh: pBt->usableSize = pageSize - page1[20]; dbda8d6ce9 2007-07-21 drh: if( pBt->usableSize<500 ){ dbda8d6ce9 2007-07-21 drh: goto page1_init_failed; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pBt->maxEmbedFrac = page1[21]; dbda8d6ce9 2007-07-21 drh: pBt->minEmbedFrac = page1[22]; dbda8d6ce9 2007-07-21 drh: pBt->minLeafFrac = page1[23]; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: pBt->autoVacuum = (get4byte(&page1[36 + 4*4])?1:0); dbda8d6ce9 2007-07-21 drh: pBt->incrVacuum = (get4byte(&page1[36 + 7*4])?1:0); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* maxLocal is the maximum amount of payload to store locally for dbda8d6ce9 2007-07-21 drh: ** a cell. Make sure it is small enough so that at least minFanout dbda8d6ce9 2007-07-21 drh: ** cells can will fit on one page. We assume a 10-byte page header. dbda8d6ce9 2007-07-21 drh: ** Besides the payload, the cell must store: dbda8d6ce9 2007-07-21 drh: ** 2-byte pointer to the cell dbda8d6ce9 2007-07-21 drh: ** 4-byte child pointer dbda8d6ce9 2007-07-21 drh: ** 9-byte nKey value dbda8d6ce9 2007-07-21 drh: ** 4-byte nData value dbda8d6ce9 2007-07-21 drh: ** 4-byte overflow page pointer dbda8d6ce9 2007-07-21 drh: ** So a cell consists of a 2-byte poiner, a header which is as much as dbda8d6ce9 2007-07-21 drh: ** 17 bytes long, 0 to N bytes of payload, and an optional 4 byte overflow dbda8d6ce9 2007-07-21 drh: ** page pointer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pBt->maxLocal = (pBt->usableSize-12)*pBt->maxEmbedFrac/255 - 23; dbda8d6ce9 2007-07-21 drh: pBt->minLocal = (pBt->usableSize-12)*pBt->minEmbedFrac/255 - 23; dbda8d6ce9 2007-07-21 drh: pBt->maxLeaf = pBt->usableSize - 35; dbda8d6ce9 2007-07-21 drh: pBt->minLeaf = (pBt->usableSize-12)*pBt->minLeafFrac/255 - 23; dbda8d6ce9 2007-07-21 drh: if( pBt->minLocal>pBt->maxLocal || pBt->maxLocal<0 ){ dbda8d6ce9 2007-07-21 drh: goto page1_init_failed; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) ); dbda8d6ce9 2007-07-21 drh: pBt->pPage1 = pPage1; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: page1_init_failed: dbda8d6ce9 2007-07-21 drh: releasePage(pPage1); dbda8d6ce9 2007-07-21 drh: pBt->pPage1 = 0; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine works like lockBtree() except that it also invokes the dbda8d6ce9 2007-07-21 drh: ** busy callback if there is lock contention. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int lockBtreeWithRetry(Btree *pRef){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(pRef) ); dbda8d6ce9 2007-07-21 drh: if( pRef->inTrans==TRANS_NONE ){ dbda8d6ce9 2007-07-21 drh: u8 inTransaction = pRef->pBt->inTransaction; dbda8d6ce9 2007-07-21 drh: btreeIntegrity(pRef); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeBeginTrans(pRef, 0); dbda8d6ce9 2007-07-21 drh: pRef->pBt->inTransaction = inTransaction; dbda8d6ce9 2007-07-21 drh: pRef->inTrans = TRANS_NONE; dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pRef->pBt->nTransaction--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: btreeIntegrity(pRef); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If there are no outstanding cursors and we are not in the middle dbda8d6ce9 2007-07-21 drh: ** of a transaction but there is a read lock on the database, then dbda8d6ce9 2007-07-21 drh: ** this routine unrefs the first page of the database file which dbda8d6ce9 2007-07-21 drh: ** has the effect of releasing the read lock. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If there are any outstanding cursors, this routine is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If there is a transaction in progress, this routine is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void unlockBtreeIfUnused(BtShared *pBt){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3PagerRefcount(pBt->pPager)>=1 ){ dbda8d6ce9 2007-07-21 drh: if( pBt->pPage1->aData==0 ){ dbda8d6ce9 2007-07-21 drh: MemPage *pPage = pBt->pPage1; c287665ba8 2007-09-14 drh: pPage->aData = sqlite3PagerGetData(pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: pPage->pBt = pBt; dbda8d6ce9 2007-07-21 drh: pPage->pgno = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releasePage(pBt->pPage1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pBt->pPage1 = 0; dbda8d6ce9 2007-07-21 drh: pBt->inStmt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new database by initializing the first page of the dbda8d6ce9 2007-07-21 drh: ** file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int newDatabase(BtShared *pBt){ dbda8d6ce9 2007-07-21 drh: MemPage *pP1; dbda8d6ce9 2007-07-21 drh: unsigned char *data; dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( sqlite3PagerPagecount(pBt->pPager)>0 ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: pP1 = pBt->pPage1; dbda8d6ce9 2007-07-21 drh: assert( pP1!=0 ); dbda8d6ce9 2007-07-21 drh: data = pP1->aData; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pP1->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: memcpy(data, zMagicHeader, sizeof(zMagicHeader)); dbda8d6ce9 2007-07-21 drh: assert( sizeof(zMagicHeader)==16 ); dbda8d6ce9 2007-07-21 drh: put2byte(&data[16], pBt->pageSize); dbda8d6ce9 2007-07-21 drh: data[18] = 1; dbda8d6ce9 2007-07-21 drh: data[19] = 1; dbda8d6ce9 2007-07-21 drh: data[20] = pBt->pageSize - pBt->usableSize; dbda8d6ce9 2007-07-21 drh: data[21] = pBt->maxEmbedFrac; dbda8d6ce9 2007-07-21 drh: data[22] = pBt->minEmbedFrac; dbda8d6ce9 2007-07-21 drh: data[23] = pBt->minLeafFrac; dbda8d6ce9 2007-07-21 drh: memset(&data[24], 0, 100-24); dbda8d6ce9 2007-07-21 drh: zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA ); dbda8d6ce9 2007-07-21 drh: pBt->pageSizeFixed = 1; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 ); dbda8d6ce9 2007-07-21 drh: assert( pBt->incrVacuum==1 || pBt->incrVacuum==0 ); dbda8d6ce9 2007-07-21 drh: put4byte(&data[36 + 4*4], pBt->autoVacuum); dbda8d6ce9 2007-07-21 drh: put4byte(&data[36 + 7*4], pBt->incrVacuum); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to start a new transaction. A write-transaction dbda8d6ce9 2007-07-21 drh: ** is started if the second argument is nonzero, otherwise a read- dbda8d6ce9 2007-07-21 drh: ** transaction. If the second argument is 2 or more and exclusive dbda8d6ce9 2007-07-21 drh: ** transaction is started, meaning that no other process is allowed dbda8d6ce9 2007-07-21 drh: ** to access the database. A preexisting transaction may not be dbda8d6ce9 2007-07-21 drh: ** upgraded to exclusive by calling this routine a second time - the dbda8d6ce9 2007-07-21 drh: ** exclusivity flag only works for a new transaction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A write-transaction must be started before attempting any dbda8d6ce9 2007-07-21 drh: ** changes to the database. None of the following routines dbda8d6ce9 2007-07-21 drh: ** will work unless a transaction is started first: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeCreateTable() dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeCreateIndex() dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeClearTable() dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeDropTable() dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeInsert() dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeDelete() dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeUpdateMeta() dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an initial attempt to acquire the lock fails because of lock contention dbda8d6ce9 2007-07-21 drh: ** and the database was previously unlocked, then invoke the busy handler dbda8d6ce9 2007-07-21 drh: ** if there is one. But if there was previously a read-lock, do not dbda8d6ce9 2007-07-21 drh: ** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is dbda8d6ce9 2007-07-21 drh: ** returned when there is already a read-lock in order to avoid a deadlock. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Suppose there are two processes A and B. A has a read lock and B has dbda8d6ce9 2007-07-21 drh: ** a reserved lock. B tries to promote to exclusive but is blocked because dbda8d6ce9 2007-07-21 drh: ** of A's read lock. A tries to promote to reserved but is blocked by B. dbda8d6ce9 2007-07-21 drh: ** One or the other of the two processes must give way or there can be dbda8d6ce9 2007-07-21 drh: ** no progress. By returning SQLITE_BUSY and not invoking the busy callback dbda8d6ce9 2007-07-21 drh: ** when A already has a read lock, we encourage A to give up and let B dbda8d6ce9 2007-07-21 drh: ** proceed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: btreeIntegrity(p); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the btree is already in a write-transaction, or it dbda8d6ce9 2007-07-21 drh: ** is already in a read-transaction and a read-transaction dbda8d6ce9 2007-07-21 drh: ** is requested, this is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ c287665ba8 2007-09-14 drh: goto trans_begun; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Write transactions are not possible on a read-only database */ dbda8d6ce9 2007-07-21 drh: if( pBt->readOnly && wrflag ){ c287665ba8 2007-09-14 drh: rc = SQLITE_READONLY; c287665ba8 2007-09-14 drh: goto trans_begun; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If another database handle has already opened a write transaction dbda8d6ce9 2007-07-21 drh: ** on this shared-btree structure and a second write transaction is dbda8d6ce9 2007-07-21 drh: ** requested, return SQLITE_BUSY. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pBt->inTransaction==TRANS_WRITE && wrflag ){ c287665ba8 2007-09-14 drh: rc = SQLITE_BUSY; c287665ba8 2007-09-14 drh: goto trans_begun; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: if( pBt->pPage1==0 ){ dbda8d6ce9 2007-07-21 drh: rc = lockBtree(pBt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && wrflag ){ dbda8d6ce9 2007-07-21 drh: if( pBt->readOnly ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_READONLY; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerBegin(pBt->pPage1->pDbPage, wrflag>1); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = newDatabase(pBt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( wrflag ) pBt->inStmt = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: unlockBtreeIfUnused(pBt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && dbda8d6ce9 2007-07-21 drh: sqlite3InvokeBusyHandler(pBt->pBusyHandler) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( p->inTrans==TRANS_NONE ){ dbda8d6ce9 2007-07-21 drh: pBt->nTransaction++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); dbda8d6ce9 2007-07-21 drh: if( p->inTrans>pBt->inTransaction ){ dbda8d6ce9 2007-07-21 drh: pBt->inTransaction = p->inTrans; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: trans_begun: dbda8d6ce9 2007-07-21 drh: btreeIntegrity(p); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the pointer-map entries for all children of page pPage. Also, if dbda8d6ce9 2007-07-21 drh: ** pPage contains cells that point to overflow pages, set the pointer dbda8d6ce9 2007-07-21 drh: ** map entries for the overflow pages as well. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int setChildPtrmaps(MemPage *pPage){ dbda8d6ce9 2007-07-21 drh: int i; /* Counter variable */ dbda8d6ce9 2007-07-21 drh: int nCell; /* Number of cells in page pPage */ dbda8d6ce9 2007-07-21 drh: int rc; /* Return code */ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: int isInitOrig = pPage->isInit; dbda8d6ce9 2007-07-21 drh: Pgno pgno = pPage->pgno; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeInitPage(pPage, pPage->pParent); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto set_child_ptrmaps_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nCell = pPage->nCell; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCell; i++){ dbda8d6ce9 2007-07-21 drh: u8 *pCell = findCell(pPage, i); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = ptrmapPutOvflPtr(pPage, pCell); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto set_child_ptrmaps_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: Pgno childPgno = get4byte(pCell); dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto set_child_ptrmaps_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: Pgno childPgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: set_child_ptrmaps_out: dbda8d6ce9 2007-07-21 drh: pPage->isInit = isInitOrig; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Somewhere on pPage, which is guarenteed to be a btree page, not an overflow dbda8d6ce9 2007-07-21 drh: ** page, is a pointer to page iFrom. Modify this pointer so that it points to dbda8d6ce9 2007-07-21 drh: ** iTo. Parameter eType describes the type of pointer to be modified, as dbda8d6ce9 2007-07-21 drh: ** follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child dbda8d6ce9 2007-07-21 drh: ** page of pPage. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow dbda8d6ce9 2007-07-21 drh: ** page pointed to by one of the cells on pPage. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PTRMAP_OVERFLOW2: pPage is an overflow-page. The pointer points at the next dbda8d6ce9 2007-07-21 drh: ** overflow page in the list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( eType==PTRMAP_OVERFLOW2 ){ dbda8d6ce9 2007-07-21 drh: /* The pointer is always the first 4 bytes of the page in this case. */ dbda8d6ce9 2007-07-21 drh: if( get4byte(pPage->aData)!=iFrom ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: put4byte(pPage->aData, iTo); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int isInitOrig = pPage->isInit; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nCell; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3BtreeInitPage(pPage, 0); dbda8d6ce9 2007-07-21 drh: nCell = pPage->nCell; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCell; i++){ dbda8d6ce9 2007-07-21 drh: u8 *pCell = findCell(pPage, i); dbda8d6ce9 2007-07-21 drh: if( eType==PTRMAP_OVERFLOW1 ){ dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pPage, pCell, &info); dbda8d6ce9 2007-07-21 drh: if( info.iOverflow ){ dbda8d6ce9 2007-07-21 drh: if( iFrom==get4byte(&pCell[info.iOverflow]) ){ dbda8d6ce9 2007-07-21 drh: put4byte(&pCell[info.iOverflow], iTo); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( get4byte(pCell)==iFrom ){ dbda8d6ce9 2007-07-21 drh: put4byte(pCell, iTo); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( i==nCell ){ dbda8d6ce9 2007-07-21 drh: if( eType!=PTRMAP_BTREE || dbda8d6ce9 2007-07-21 drh: get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPage->isInit = isInitOrig; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move the open database page pDbPage to location iFreePage in the dbda8d6ce9 2007-07-21 drh: ** database. The pDbPage reference remains valid. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int relocatePage( dbda8d6ce9 2007-07-21 drh: BtShared *pBt, /* Btree */ dbda8d6ce9 2007-07-21 drh: MemPage *pDbPage, /* Open page to move */ dbda8d6ce9 2007-07-21 drh: u8 eType, /* Pointer map 'type' entry for pDbPage */ dbda8d6ce9 2007-07-21 drh: Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */ dbda8d6ce9 2007-07-21 drh: Pgno iFreePage /* The location to move pDbPage to */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: MemPage *pPtrPage; /* The page that contains a pointer to pDbPage */ dbda8d6ce9 2007-07-21 drh: Pgno iDbPage = pDbPage->pgno; dbda8d6ce9 2007-07-21 drh: Pager *pPager = pBt->pPager; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || dbda8d6ce9 2007-07-21 drh: eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); c287665ba8 2007-09-14 drh: assert( pDbPage->pBt==pBt ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Move page iDbPage from it's current location to page number iFreePage */ dbda8d6ce9 2007-07-21 drh: TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", dbda8d6ce9 2007-07-21 drh: iDbPage, iFreePage, iPtrPage, eType)); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pDbPage->pgno = iFreePage; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If pDbPage was a btree-page, then it may have child pages and/or cells dbda8d6ce9 2007-07-21 drh: ** that point to overflow pages. The pointer map entries for all these dbda8d6ce9 2007-07-21 drh: ** pages need to be changed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If pDbPage is an overflow page, then the first 4 bytes may store a dbda8d6ce9 2007-07-21 drh: ** pointer to a subsequent overflow page. If this is the case, then dbda8d6ce9 2007-07-21 drh: ** the pointer map needs to be updated for the subsequent overflow page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ){ dbda8d6ce9 2007-07-21 drh: rc = setChildPtrmaps(pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Pgno nextOvfl = get4byte(pDbPage->aData); dbda8d6ce9 2007-07-21 drh: if( nextOvfl!=0 ){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, nextOvfl, PTRMAP_OVERFLOW2, iFreePage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Fix the database pointer on page iPtrPage that pointed at iDbPage so dbda8d6ce9 2007-07-21 drh: ** that it points at iFreePage. Also fix the pointer map entry for dbda8d6ce9 2007-07-21 drh: ** iPtrPage. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( eType!=PTRMAP_ROOTPAGE ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, iPtrPage, &pPtrPage, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPtrPage->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pPtrPage); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType); dbda8d6ce9 2007-07-21 drh: releasePage(pPtrPage); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, iFreePage, eType, iPtrPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward declaration required by incrVacuumStep(). */ dbda8d6ce9 2007-07-21 drh: static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Perform a single step of an incremental-vacuum. If successful, dbda8d6ce9 2007-07-21 drh: ** return SQLITE_OK. If there is no work to do (and therefore no dbda8d6ce9 2007-07-21 drh: ** point in calling this function again), return SQLITE_DONE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** More specificly, this function attempts to re-organize the dbda8d6ce9 2007-07-21 drh: ** database so that the last page of the file currently in use dbda8d6ce9 2007-07-21 drh: ** is no longer in use. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the nFin parameter is non-zero, the implementation assumes dbda8d6ce9 2007-07-21 drh: ** that the caller will keep calling incrVacuumStep() until dbda8d6ce9 2007-07-21 drh: ** it returns SQLITE_DONE or an error, and that nFin is the dbda8d6ce9 2007-07-21 drh: ** number of pages the database file will contain after this dbda8d6ce9 2007-07-21 drh: ** process is complete. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int incrVacuumStep(BtShared *pBt, Pgno nFin){ dbda8d6ce9 2007-07-21 drh: Pgno iLastPg; /* Last page in the database */ dbda8d6ce9 2007-07-21 drh: Pgno nFreeList; /* Number of pages still on the free-list */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: iLastPg = pBt->nTrunc; dbda8d6ce9 2007-07-21 drh: if( iLastPg==0 ){ dbda8d6ce9 2007-07-21 drh: iLastPg = sqlite3PagerPagecount(pBt->pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: u8 eType; dbda8d6ce9 2007-07-21 drh: Pgno iPtrPage; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nFreeList = get4byte(&pBt->pPage1->aData[36]); dbda8d6ce9 2007-07-21 drh: if( nFreeList==0 || nFin==iLastPg ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = ptrmapGet(pBt, iLastPg, &eType, &iPtrPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( eType==PTRMAP_ROOTPAGE ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( eType==PTRMAP_FREEPAGE ){ dbda8d6ce9 2007-07-21 drh: if( nFin==0 ){ dbda8d6ce9 2007-07-21 drh: /* Remove the page from the files free-list. This is not required dbda8d6ce9 2007-07-21 drh: ** if nFin is non-zero. In that case, the free-list will be dbda8d6ce9 2007-07-21 drh: ** truncated to zero after this function returns, so it doesn't dbda8d6ce9 2007-07-21 drh: ** matter if it still contains some garbage entries. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: Pgno iFreePg; dbda8d6ce9 2007-07-21 drh: MemPage *pFreePg; dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( iFreePg==iLastPg ); dbda8d6ce9 2007-07-21 drh: releasePage(pFreePg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: Pgno iFreePg; /* Index of free page to move pLastPg to */ dbda8d6ce9 2007-07-21 drh: MemPage *pLastPg; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, iLastPg, &pLastPg, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If nFin is zero, this loop runs exactly once and page pLastPg dbda8d6ce9 2007-07-21 drh: ** is swapped with the first free page pulled off the free list. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** On the other hand, if nFin is greater than zero, then keep dbda8d6ce9 2007-07-21 drh: ** looping until a free-page located within the first nFin pages dbda8d6ce9 2007-07-21 drh: ** of the file is found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: MemPage *pFreePg; dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pLastPg); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releasePage(pFreePg); dbda8d6ce9 2007-07-21 drh: }while( nFin!=0 && iFreePg>nFin ); dbda8d6ce9 2007-07-21 drh: assert( iFreePg<iLastPg ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pLastPg->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg); dbda8d6ce9 2007-07-21 drh: releasePage(pLastPg); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pBt->nTrunc = iLastPg - 1; dbda8d6ce9 2007-07-21 drh: while( pBt->nTrunc==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, pBt->nTrunc) ){ dbda8d6ce9 2007-07-21 drh: pBt->nTrunc--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A write-transaction must be opened before calling this function. dbda8d6ce9 2007-07-21 drh: ** It performs a single unit of work towards an incremental vacuum. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the incremental vacuum is finished after this function has run, dbda8d6ce9 2007-07-21 drh: ** SQLITE_DONE is returned. If it is not finished, but no error occured, dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK is returned. Otherwise an SQLite error code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); dbda8d6ce9 2007-07-21 drh: if( !pBt->autoVacuum ){ c287665ba8 2007-09-14 drh: rc = SQLITE_DONE; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: invalidateAllOverflowCache(pBt); c287665ba8 2007-09-14 drh: rc = incrVacuumStep(pBt, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called prior to sqlite3PagerCommit when a transaction dbda8d6ce9 2007-07-21 drh: ** is commited for an auto-vacuum database. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages dbda8d6ce9 2007-07-21 drh: ** the database file should be truncated to during the commit process. dbda8d6ce9 2007-07-21 drh: ** i.e. the database has been reorganized so that only the first *pnTrunc dbda8d6ce9 2007-07-21 drh: ** pages are in use. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: Pager *pPager = pBt->pPager; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: int nRef = sqlite3PagerRefcount(pPager); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: invalidateAllOverflowCache(pBt); dbda8d6ce9 2007-07-21 drh: assert(pBt->autoVacuum); dbda8d6ce9 2007-07-21 drh: if( !pBt->incrVacuum ){ dbda8d6ce9 2007-07-21 drh: Pgno nFin = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pBt->nTrunc==0 ){ dbda8d6ce9 2007-07-21 drh: Pgno nFree; dbda8d6ce9 2007-07-21 drh: Pgno nPtrmap; dbda8d6ce9 2007-07-21 drh: const int pgsz = pBt->pageSize; dbda8d6ce9 2007-07-21 drh: Pgno nOrig = sqlite3PagerPagecount(pBt->pPager); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( PTRMAP_ISPAGE(pBt, nOrig) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nOrig==PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: nOrig--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nFree = get4byte(&pBt->pPage1->aData[36]); dbda8d6ce9 2007-07-21 drh: nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+pgsz/5)/(pgsz/5); dbda8d6ce9 2007-07-21 drh: nFin = nOrig - nFree - nPtrmap; dbda8d6ce9 2007-07-21 drh: if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<=PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: nFin--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: nFin--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = incrVacuumStep(pBt, nFin); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_DONE ){ dbda8d6ce9 2007-07-21 drh: assert(nFin==0 || pBt->nTrunc==0 || nFin<=pBt->nTrunc); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( pBt->nTrunc ){ d8590e093f 2007-07-24 drh: rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); dbda8d6ce9 2007-07-21 drh: put4byte(&pBt->pPage1->aData[32], 0); dbda8d6ce9 2007-07-21 drh: put4byte(&pBt->pPage1->aData[36], 0); dbda8d6ce9 2007-07-21 drh: pBt->nTrunc = nFin; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3PagerRollback(pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: *pnTrunc = pBt->nTrunc; dbda8d6ce9 2007-07-21 drh: pBt->nTrunc = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( nRef==sqlite3PagerRefcount(pPager) ); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine does the first phase of a two-phase commit. This routine dbda8d6ce9 2007-07-21 drh: ** causes a rollback journal to be created (if it does not already exist) dbda8d6ce9 2007-07-21 drh: ** and populated with enough information so that if a power loss occurs dbda8d6ce9 2007-07-21 drh: ** the database can be restored to its original state by playing back dbda8d6ce9 2007-07-21 drh: ** the journal. Then the contents of the journal are flushed out to dbda8d6ce9 2007-07-21 drh: ** the disk. After the journal is safely on oxide, the changes to the dbda8d6ce9 2007-07-21 drh: ** database are written into the database file and flushed to oxide. dbda8d6ce9 2007-07-21 drh: ** At the end of this call, the rollback journal still exists on the dbda8d6ce9 2007-07-21 drh: ** disk and we are still holding all locks, so the transaction has not dbda8d6ce9 2007-07-21 drh: ** committed. See sqlite3BtreeCommit() for the second phase of the dbda8d6ce9 2007-07-21 drh: ** commit process. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This call is a no-op if no write-transaction is currently active on pBt. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Otherwise, sync the database file for the btree pBt. zMaster points to dbda8d6ce9 2007-07-21 drh: ** the name of a master journal file that should be written into the dbda8d6ce9 2007-07-21 drh: ** individual journal file, or is NULL, indicating no master journal file dbda8d6ce9 2007-07-21 drh: ** (single database transaction). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When this is called, the master journal should already have been dbda8d6ce9 2007-07-21 drh: ** created, populated with this journal pointer and synced to disk. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Once this is routine has returned, the only thing required to commit dbda8d6ce9 2007-07-21 drh: ** the write-transaction for this database file is to delete the journal. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( p->inTrans==TRANS_WRITE ){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: Pgno nTrunc = 0; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: rc = autoVacuumCommit(pBt, &nTrunc); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, nTrunc); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Commit the transaction currently in progress. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine implements the second phase of a 2-phase commit. The dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeSync() routine does the first phase and should be invoked dbda8d6ce9 2007-07-21 drh: ** prior to calling this routine. The sqlite3BtreeSync() routine did dbda8d6ce9 2007-07-21 drh: ** all the work of writing information out to disk and flushing the dbda8d6ce9 2007-07-21 drh: ** contents so that they are written onto the disk platter. All this dbda8d6ce9 2007-07-21 drh: ** routine has to do is delete or truncate the rollback journal dbda8d6ce9 2007-07-21 drh: ** (which causes the transaction to commit) and drop locks. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This will release the write lock on the database file. If there dbda8d6ce9 2007-07-21 drh: ** are no active cursors, it also releases the read lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: btreeIntegrity(p); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the handle has a write-transaction open, commit the shared-btrees dbda8d6ce9 2007-07-21 drh: ** transaction and set the shared state to TRANS_READ. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->inTrans==TRANS_WRITE ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( pBt->inTransaction==TRANS_WRITE ); dbda8d6ce9 2007-07-21 drh: assert( pBt->nTransaction>0 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pBt->inTransaction = TRANS_READ; dbda8d6ce9 2007-07-21 drh: pBt->inStmt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: unlockAllTables(p); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the handle has any kind of transaction open, decrement the transaction dbda8d6ce9 2007-07-21 drh: ** count of the shared btree. If the transaction count reaches 0, set dbda8d6ce9 2007-07-21 drh: ** the shared state to TRANS_NONE. The unlockBtreeIfUnused() call below dbda8d6ce9 2007-07-21 drh: ** will unlock the pager. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->inTrans!=TRANS_NONE ){ dbda8d6ce9 2007-07-21 drh: pBt->nTransaction--; dbda8d6ce9 2007-07-21 drh: if( 0==pBt->nTransaction ){ dbda8d6ce9 2007-07-21 drh: pBt->inTransaction = TRANS_NONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the handles current transaction state to TRANS_NONE and unlock dbda8d6ce9 2007-07-21 drh: ** the pager if this call closed the only read or write transaction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: p->inTrans = TRANS_NONE; dbda8d6ce9 2007-07-21 drh: unlockBtreeIfUnused(pBt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: btreeIntegrity(p); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Do both phases of a commit. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCommitPhaseOne(p, 0); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCommitPhaseTwo(p); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of write-cursors open on this handle. This is for use dbda8d6ce9 2007-07-21 drh: ** in assert() expressions, so it is only compiled if NDEBUG is not dbda8d6ce9 2007-07-21 drh: ** defined. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** For the purposes of this routine, a write-cursor is any cursor that c287665ba8 2007-09-14 drh: ** is capable of writing to the databse. That means the cursor was c287665ba8 2007-09-14 drh: ** originally opened for writing and the cursor has not be disabled c287665ba8 2007-09-14 drh: ** by having its state changed to CURSOR_FAULT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int countWriteCursors(BtShared *pBt){ dbda8d6ce9 2007-07-21 drh: BtCursor *pCur; dbda8d6ce9 2007-07-21 drh: int r = 0; dbda8d6ce9 2007-07-21 drh: for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ c287665ba8 2007-09-14 drh: if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine sets the state to CURSOR_FAULT and the error c287665ba8 2007-09-14 drh: ** code to errCode for every cursor on BtShared that pBtree c287665ba8 2007-09-14 drh: ** references. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Every cursor is tripped, including cursors that belong c287665ba8 2007-09-14 drh: ** to other database connections that happen to be sharing c287665ba8 2007-09-14 drh: ** the cache with pBtree. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine gets called when a rollback occurs. c287665ba8 2007-09-14 drh: ** All cursors using the same cache must be tripped c287665ba8 2007-09-14 drh: ** to prevent them from trying to use the btree after c287665ba8 2007-09-14 drh: ** the rollback. The rollback may have deleted tables c287665ba8 2007-09-14 drh: ** or moved root pages, so it is not sufficient to c287665ba8 2007-09-14 drh: ** save the state of the cursor. The cursor must be c287665ba8 2007-09-14 drh: ** invalidated. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ c287665ba8 2007-09-14 drh: BtCursor *p; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(pBtree); c287665ba8 2007-09-14 drh: for(p=pBtree->pBt->pCursor; p; p=p->pNext){ c287665ba8 2007-09-14 drh: clearCursorPosition(p); c287665ba8 2007-09-14 drh: p->eState = CURSOR_FAULT; c287665ba8 2007-09-14 drh: p->skip = errCode; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pBtree); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Rollback the transaction in progress. All cursors will be dbda8d6ce9 2007-07-21 drh: ** invalided by this operation. Any attempt to use a cursor dbda8d6ce9 2007-07-21 drh: ** that was open at the beginning of this operation will result dbda8d6ce9 2007-07-21 drh: ** in an error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This will release the write lock on the database file. If there dbda8d6ce9 2007-07-21 drh: ** are no active cursors, it also releases the read lock. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: MemPage *pPage1; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: rc = saveAllCursors(pBt, 0, 0); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: /* This is a horrible situation. An IO or malloc() error occured whilst dbda8d6ce9 2007-07-21 drh: ** trying to save cursor positions. If this is an automatic rollback (as dbda8d6ce9 2007-07-21 drh: ** the result of a constraint, malloc() failure or IO error) then dbda8d6ce9 2007-07-21 drh: ** the cache may be internally inconsistent (not contain valid trees) so dbda8d6ce9 2007-07-21 drh: ** we cannot simply return the error to the caller. Instead, abort dbda8d6ce9 2007-07-21 drh: ** all queries that may be using any of the cursors that failed to save. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: sqlite3BtreeTripAllCursors(p, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: btreeIntegrity(p); dbda8d6ce9 2007-07-21 drh: unlockAllTables(p); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( p->inTrans==TRANS_WRITE ){ dbda8d6ce9 2007-07-21 drh: int rc2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: pBt->nTrunc = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( TRANS_WRITE==pBt->inTransaction ); dbda8d6ce9 2007-07-21 drh: rc2 = sqlite3PagerRollback(pBt->pPager); dbda8d6ce9 2007-07-21 drh: if( rc2!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = rc2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The rollback may have destroyed the pPage1->aData value. So dbda8d6ce9 2007-07-21 drh: ** call sqlite3BtreeGetPage() on page 1 again to make dbda8d6ce9 2007-07-21 drh: ** sure pPage1->aData is set correctly. */ dbda8d6ce9 2007-07-21 drh: if( sqlite3BtreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pPage1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( countWriteCursors(pBt)==0 ); dbda8d6ce9 2007-07-21 drh: pBt->inTransaction = TRANS_READ; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( p->inTrans!=TRANS_NONE ){ dbda8d6ce9 2007-07-21 drh: assert( pBt->nTransaction>0 ); dbda8d6ce9 2007-07-21 drh: pBt->nTransaction--; dbda8d6ce9 2007-07-21 drh: if( 0==pBt->nTransaction ){ dbda8d6ce9 2007-07-21 drh: pBt->inTransaction = TRANS_NONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: p->inTrans = TRANS_NONE; dbda8d6ce9 2007-07-21 drh: pBt->inStmt = 0; dbda8d6ce9 2007-07-21 drh: unlockBtreeIfUnused(pBt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: btreeIntegrity(p); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Start a statement subtransaction. The subtransaction can dbda8d6ce9 2007-07-21 drh: ** can be rolled back independently of the main transaction. dbda8d6ce9 2007-07-21 drh: ** You must start a transaction before starting a subtransaction. dbda8d6ce9 2007-07-21 drh: ** The subtransaction is ended automatically if the main transaction dbda8d6ce9 2007-07-21 drh: ** commits or rolls back. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Only one subtransaction may be active at a time. It is an error to try dbda8d6ce9 2007-07-21 drh: ** to start a new subtransaction if another subtransaction is already active. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Statement subtransactions are used around individual SQL statements dbda8d6ce9 2007-07-21 drh: ** that are contained within a BEGIN...COMMIT block. If a constraint dbda8d6ce9 2007-07-21 drh: ** error occurs within the statement, the effect of that one statement dbda8d6ce9 2007-07-21 drh: ** can be rolled back without having to rollback the entire transaction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){ c287665ba8 2007-09-14 drh: rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: assert( pBt->inTransaction==TRANS_WRITE ); c287665ba8 2007-09-14 drh: rc = pBt->readOnly ? SQLITE_OK : sqlite3PagerStmtBegin(pBt->pPager); c287665ba8 2007-09-14 drh: pBt->inStmt = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Commit the statment subtransaction currently in progress. If no dbda8d6ce9 2007-07-21 drh: ** subtransaction is active, this is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeCommitStmt(Btree *p){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: if( pBt->inStmt && !pBt->readOnly ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerStmtCommit(pBt->pPager); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pBt->inStmt = 0; c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Rollback the active statement subtransaction. If no subtransaction dbda8d6ce9 2007-07-21 drh: ** is active this routine is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All cursors will be invalidated by this operation. Any attempt dbda8d6ce9 2007-07-21 drh: ** to use a cursor that was open at the beginning of this operation dbda8d6ce9 2007-07-21 drh: ** will result in an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeRollbackStmt(Btree *p){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: sqlite3MallocDisallow(); dbda8d6ce9 2007-07-21 drh: if( pBt->inStmt && !pBt->readOnly ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerStmtRollback(pBt->pPager); dbda8d6ce9 2007-07-21 drh: assert( countWriteCursors(pBt)==0 ); dbda8d6ce9 2007-07-21 drh: pBt->inStmt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3MallocAllow(); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Default key comparison function to be used if no comparison function dbda8d6ce9 2007-07-21 drh: ** is specified on the sqlite3BtreeCursor() call. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int dfltCompare( dbda8d6ce9 2007-07-21 drh: void *NotUsed, /* User data is not used */ dbda8d6ce9 2007-07-21 drh: int n1, const void *p1, /* First key to compare */ dbda8d6ce9 2007-07-21 drh: int n2, const void *p2 /* Second key to compare */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int c; dbda8d6ce9 2007-07-21 drh: c = memcmp(p1, p2, n1<n2 ? n1 : n2); dbda8d6ce9 2007-07-21 drh: if( c==0 ){ dbda8d6ce9 2007-07-21 drh: c = n1 - n2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return c; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new cursor for the BTree whose root is on the page dbda8d6ce9 2007-07-21 drh: ** iTable. The act of acquiring a cursor gets a read lock on dbda8d6ce9 2007-07-21 drh: ** the database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If wrFlag==0, then the cursor can only be used for reading. dbda8d6ce9 2007-07-21 drh: ** If wrFlag==1, then the cursor can be used for reading or for dbda8d6ce9 2007-07-21 drh: ** writing if other conditions for writing are also met. These dbda8d6ce9 2007-07-21 drh: ** are the conditions that must be met in order for writing to dbda8d6ce9 2007-07-21 drh: ** be allowed: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1: The cursor must have been opened with wrFlag==1 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2: Other database connections that share the same pager cache dbda8d6ce9 2007-07-21 drh: ** but which are not in the READ_UNCOMMITTED state may not have dbda8d6ce9 2007-07-21 drh: ** cursors open with wrFlag==0 on the same table. Otherwise dbda8d6ce9 2007-07-21 drh: ** the changes made by this write cursor would be visible to dbda8d6ce9 2007-07-21 drh: ** the read cursors in the other database connection. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 3: The database must be writable (not on read-only media) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 4: There must be an active transaction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** No checking is done to make sure that page iTable really is the dbda8d6ce9 2007-07-21 drh: ** root page of a b-tree. If it is not, then the cursor acquired dbda8d6ce9 2007-07-21 drh: ** will not work correctly. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The comparison function must be logically the same for every cursor dbda8d6ce9 2007-07-21 drh: ** on a particular table. Changing the comparison function will result dbda8d6ce9 2007-07-21 drh: ** in incorrect operations. If the comparison function is NULL, a dbda8d6ce9 2007-07-21 drh: ** default comparison function is used. The comparison function is dbda8d6ce9 2007-07-21 drh: ** always ignored for INTKEY tables. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int btreeCursor( dbda8d6ce9 2007-07-21 drh: Btree *p, /* The btree */ dbda8d6ce9 2007-07-21 drh: int iTable, /* Root page of table to open */ dbda8d6ce9 2007-07-21 drh: int wrFlag, /* 1 to write. 0 read-only */ dbda8d6ce9 2007-07-21 drh: int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */ dbda8d6ce9 2007-07-21 drh: void *pArg, /* First arg to xCompare() */ dbda8d6ce9 2007-07-21 drh: BtCursor **ppCur /* Write new cursor here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: BtCursor *pCur; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(p) ); dbda8d6ce9 2007-07-21 drh: *ppCur = 0; dbda8d6ce9 2007-07-21 drh: if( wrFlag ){ dbda8d6ce9 2007-07-21 drh: if( pBt->readOnly ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_READONLY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( checkReadLocks(p, iTable, 0) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_LOCKED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pBt->pPage1==0 ){ dbda8d6ce9 2007-07-21 drh: rc = lockBtreeWithRetry(p); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pBt->readOnly && wrFlag ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_READONLY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pCur = sqlite3MallocZero( sizeof(*pCur) ); dbda8d6ce9 2007-07-21 drh: if( pCur==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto create_cursor_exception; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->pgnoRoot = (Pgno)iTable; dbda8d6ce9 2007-07-21 drh: if( iTable==1 && sqlite3PagerPagecount(pBt->pPager)==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_EMPTY; dbda8d6ce9 2007-07-21 drh: goto create_cursor_exception; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->pPage, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto create_cursor_exception; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Now that no other errors can occur, finish filling in the BtCursor dbda8d6ce9 2007-07-21 drh: ** variables, link the cursor into the BtShared list and set *ppCur (the dbda8d6ce9 2007-07-21 drh: ** output argument to this function). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pCur->xCompare = xCmp ? xCmp : dfltCompare; dbda8d6ce9 2007-07-21 drh: pCur->pArg = pArg; dbda8d6ce9 2007-07-21 drh: pCur->pBtree = p; c287665ba8 2007-09-14 drh: pCur->pBt = pBt; dbda8d6ce9 2007-07-21 drh: pCur->wrFlag = wrFlag; dbda8d6ce9 2007-07-21 drh: pCur->pNext = pBt->pCursor; dbda8d6ce9 2007-07-21 drh: if( pCur->pNext ){ dbda8d6ce9 2007-07-21 drh: pCur->pNext->pPrev = pCur; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pBt->pCursor = pCur; dbda8d6ce9 2007-07-21 drh: pCur->eState = CURSOR_INVALID; dbda8d6ce9 2007-07-21 drh: *ppCur = pCur; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: create_cursor_exception: dbda8d6ce9 2007-07-21 drh: if( pCur ){ dbda8d6ce9 2007-07-21 drh: releasePage(pCur->pPage); c287665ba8 2007-09-14 drh: sqlite3_free(pCur); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: unlockBtreeIfUnused(pBt); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCursor( c287665ba8 2007-09-14 drh: Btree *p, /* The btree */ c287665ba8 2007-09-14 drh: int iTable, /* Root page of table to open */ c287665ba8 2007-09-14 drh: int wrFlag, /* 1 to write. 0 read-only */ c287665ba8 2007-09-14 drh: int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */ c287665ba8 2007-09-14 drh: void *pArg, /* First arg to xCompare() */ c287665ba8 2007-09-14 drh: BtCursor **ppCur /* Write new cursor here */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); c287665ba8 2007-09-14 drh: rc = btreeCursor(p, iTable, wrFlag, xCmp, pArg, ppCur); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close a cursor. The read lock on the database file is released dbda8d6ce9 2007-07-21 drh: ** when the last cursor is closed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ c287665ba8 2007-09-14 drh: BtShared *pBt = pCur->pBt; c287665ba8 2007-09-14 drh: Btree *pBtree = pCur->pBtree; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(pBtree); dbda8d6ce9 2007-07-21 drh: clearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: if( pCur->pPrev ){ dbda8d6ce9 2007-07-21 drh: pCur->pPrev->pNext = pCur->pNext; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pBt->pCursor = pCur->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCur->pNext ){ dbda8d6ce9 2007-07-21 drh: pCur->pNext->pPrev = pCur->pPrev; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releasePage(pCur->pPage); dbda8d6ce9 2007-07-21 drh: unlockBtreeIfUnused(pBt); dbda8d6ce9 2007-07-21 drh: invalidateOverflowCache(pCur); c287665ba8 2007-09-14 drh: sqlite3_free(pCur); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pBtree); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make a temporary cursor by filling in the fields of pTempCur. dbda8d6ce9 2007-07-21 drh: ** The temporary cursor is not on the cursor list for the Btree. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){ c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: memcpy(pTempCur, pCur, sizeof(*pCur)); dbda8d6ce9 2007-07-21 drh: pTempCur->pNext = 0; dbda8d6ce9 2007-07-21 drh: pTempCur->pPrev = 0; dbda8d6ce9 2007-07-21 drh: if( pTempCur->pPage ){ dbda8d6ce9 2007-07-21 drh: sqlite3PagerRef(pTempCur->pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete a temporary cursor such as was made by the CreateTemporaryCursor() dbda8d6ce9 2007-07-21 drh: ** function above. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: if( pCur->pPage ){ dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pCur->pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make sure the BtCursor* given in the argument has a valid dbda8d6ce9 2007-07-21 drh: ** BtCursor.info structure. If it is not already valid, call dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeParseCell() to fill it in. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** BtCursor.info is a cache of the information in the current cell. dbda8d6ce9 2007-07-21 drh: ** Using this cache reduces the number of calls to sqlite3BtreeParseCell(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2007-06-25: There is a bug in some versions of MSVC that cause the dbda8d6ce9 2007-07-21 drh: ** compiler to crash when getCellInfo() is implemented as a macro. dbda8d6ce9 2007-07-21 drh: ** But there is a measureable speed advantage to using the macro on gcc dbda8d6ce9 2007-07-21 drh: ** (when less compiler optimizations like -Os or -O0 are used and the dbda8d6ce9 2007-07-21 drh: ** compiler is not doing agressive inlining.) So we use a real function dbda8d6ce9 2007-07-21 drh: ** for MSVC and a macro for everything else. Ticket #2457. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: static void assertCellInfo(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: memset(&info, 0, sizeof(info)); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &info); dbda8d6ce9 2007-07-21 drh: assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define assertCellInfo(x) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef _MSC_VER dbda8d6ce9 2007-07-21 drh: /* Use a real function in MSVC to work around bugs in that compiler. */ dbda8d6ce9 2007-07-21 drh: static void getCellInfo(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: if( pCur->info.nSize==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assertCellInfo(pCur); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else /* if not _MSC_VER */ dbda8d6ce9 2007-07-21 drh: /* Use a macro in all other compilers so that the function is inlined */ dbda8d6ce9 2007-07-21 drh: #define getCellInfo(pCur) \ dbda8d6ce9 2007-07-21 drh: if( pCur->info.nSize==0 ){ \ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); \ dbda8d6ce9 2007-07-21 drh: }else{ \ dbda8d6ce9 2007-07-21 drh: assertCellInfo(pCur); \ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* _MSC_VER */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set *pSize to the size of the buffer needed to hold the value of dbda8d6ce9 2007-07-21 drh: ** the key for the current entry. If the cursor is not pointing dbda8d6ce9 2007-07-21 drh: ** to a valid entry, *pSize is set to 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For a table with the INTKEY flag set, this routine returns the key dbda8d6ce9 2007-07-21 drh: ** itself, not the number of bytes in the key. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: rc = restoreOrClearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); dbda8d6ce9 2007-07-21 drh: if( pCur->eState==CURSOR_INVALID ){ dbda8d6ce9 2007-07-21 drh: *pSize = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: getCellInfo(pCur); dbda8d6ce9 2007-07-21 drh: *pSize = pCur->info.nKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set *pSize to the number of bytes of data in the entry the dbda8d6ce9 2007-07-21 drh: ** cursor currently points to. Always return SQLITE_OK. dbda8d6ce9 2007-07-21 drh: ** Failure is not possible. If the cursor is not currently dbda8d6ce9 2007-07-21 drh: ** pointing to an entry (which can happen, for example, if dbda8d6ce9 2007-07-21 drh: ** the database is empty) then *pSize is set to 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: rc = restoreOrClearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); dbda8d6ce9 2007-07-21 drh: if( pCur->eState==CURSOR_INVALID ){ dbda8d6ce9 2007-07-21 drh: /* Not pointing at a valid entry - set *pSize to 0. */ dbda8d6ce9 2007-07-21 drh: *pSize = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: getCellInfo(pCur); dbda8d6ce9 2007-07-21 drh: *pSize = pCur->info.nData; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given the page number of an overflow page in the database (parameter dbda8d6ce9 2007-07-21 drh: ** ovfl), this function finds the page number of the next page in the dbda8d6ce9 2007-07-21 drh: ** linked list of overflow pages. If possible, it uses the auto-vacuum dbda8d6ce9 2007-07-21 drh: ** pointer-map data instead of reading the content of page ovfl to do so. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an error occurs an SQLite error code is returned. Otherwise: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Unless pPgnoNext is NULL, the page number of the next overflow dbda8d6ce9 2007-07-21 drh: ** page in the linked list is written to *pPgnoNext. If page ovfl dbda8d6ce9 2007-07-21 drh: ** is the last page in it's linked list, *pPgnoNext is set to zero. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If ppPage is not NULL, *ppPage is set to the MemPage* handle dbda8d6ce9 2007-07-21 drh: ** for page ovfl. The underlying pager page may have been requested dbda8d6ce9 2007-07-21 drh: ** with the noContent flag set, so the page data accessable via dbda8d6ce9 2007-07-21 drh: ** this handle may not be trusted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getOverflowPage( dbda8d6ce9 2007-07-21 drh: BtShared *pBt, dbda8d6ce9 2007-07-21 drh: Pgno ovfl, /* Overflow page */ dbda8d6ce9 2007-07-21 drh: MemPage **ppPage, /* OUT: MemPage handle */ dbda8d6ce9 2007-07-21 drh: Pgno *pPgnoNext /* OUT: Next overflow page number */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Pgno next = 0; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: /* One of these must not be NULL. Otherwise, why call this function? */ dbda8d6ce9 2007-07-21 drh: assert(ppPage || pPgnoNext); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If pPgnoNext is NULL, then this function is being called to obtain dbda8d6ce9 2007-07-21 drh: ** a MemPage* reference only. No page-data is required in this case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !pPgnoNext ){ dbda8d6ce9 2007-07-21 drh: return sqlite3BtreeGetPage(pBt, ovfl, ppPage, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* Try to find the next page in the overflow list using the dbda8d6ce9 2007-07-21 drh: ** autovacuum pointer-map pages. Guess that the next page in dbda8d6ce9 2007-07-21 drh: ** the overflow list is page number (ovfl+1). If that guess turns dbda8d6ce9 2007-07-21 drh: ** out to be wrong, fall back to loading the data of page dbda8d6ce9 2007-07-21 drh: ** number ovfl to determine the next page number. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: Pgno pgno; dbda8d6ce9 2007-07-21 drh: Pgno iGuess = ovfl+1; dbda8d6ce9 2007-07-21 drh: u8 eType; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( PTRMAP_ISPAGE(pBt, iGuess) || iGuess==PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: iGuess++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( iGuess<=sqlite3PagerPagecount(pBt->pPager) ){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapGet(pBt, iGuess, &eType, &pgno); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){ dbda8d6ce9 2007-07-21 drh: next = iGuess; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( next==0 || ppPage ){ dbda8d6ce9 2007-07-21 drh: MemPage *pPage = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, ovfl, &pPage, next!=0); dbda8d6ce9 2007-07-21 drh: assert(rc==SQLITE_OK || pPage==0); dbda8d6ce9 2007-07-21 drh: if( next==0 && rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: next = get4byte(pPage->aData); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( ppPage ){ dbda8d6ce9 2007-07-21 drh: *ppPage = pPage; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pPgnoNext = next; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Copy data from a buffer to a page, or from a page to a buffer. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pPayload is a pointer to data stored on database page pDbPage. dbda8d6ce9 2007-07-21 drh: ** If argument eOp is false, then nByte bytes of data are copied dbda8d6ce9 2007-07-21 drh: ** from pPayload to the buffer pointed at by pBuf. If eOp is true, dbda8d6ce9 2007-07-21 drh: ** then sqlite3PagerWrite() is called on pDbPage and nByte bytes dbda8d6ce9 2007-07-21 drh: ** of data are copied from the buffer pBuf to pPayload. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK is returned on success, otherwise an error code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int copyPayload( dbda8d6ce9 2007-07-21 drh: void *pPayload, /* Pointer to page data */ dbda8d6ce9 2007-07-21 drh: void *pBuf, /* Pointer to buffer */ dbda8d6ce9 2007-07-21 drh: int nByte, /* Number of bytes to copy */ dbda8d6ce9 2007-07-21 drh: int eOp, /* 0 -> copy from page, 1 -> copy to page */ dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage /* Page containing pPayload */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( eOp ){ dbda8d6ce9 2007-07-21 drh: /* Copy data from buffer to page (a write operation) */ dbda8d6ce9 2007-07-21 drh: int rc = sqlite3PagerWrite(pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(pPayload, pBuf, nByte); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Copy data from page to buffer (a read operation) */ dbda8d6ce9 2007-07-21 drh: memcpy(pBuf, pPayload, nByte); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is used to read or overwrite payload information dbda8d6ce9 2007-07-21 drh: ** for the entry that the pCur cursor is pointing to. If the eOp dbda8d6ce9 2007-07-21 drh: ** parameter is 0, this is a read operation (data copied into dbda8d6ce9 2007-07-21 drh: ** buffer pBuf). If it is non-zero, a write (data copied from dbda8d6ce9 2007-07-21 drh: ** buffer pBuf). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A total of "amt" bytes are read or written beginning at "offset". dbda8d6ce9 2007-07-21 drh: ** Data is read to or from the buffer pBuf. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine does not make a distinction between key and data. dbda8d6ce9 2007-07-21 drh: ** It just reads or writes bytes from the payload area. Data might dbda8d6ce9 2007-07-21 drh: ** appear on the main page or be scattered out on multiple overflow dbda8d6ce9 2007-07-21 drh: ** pages. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the BtCursor.isIncrblobHandle flag is set, and the current dbda8d6ce9 2007-07-21 drh: ** cursor entry uses one or more overflow pages, this function dbda8d6ce9 2007-07-21 drh: ** allocates space for and lazily popluates the overflow page-list dbda8d6ce9 2007-07-21 drh: ** cache array (BtCursor.aOverflow). Subsequent calls use this dbda8d6ce9 2007-07-21 drh: ** cache to make seeking to the supplied offset more efficient. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Once an overflow page-list cache has been allocated, it may be dbda8d6ce9 2007-07-21 drh: ** invalidated if some other cursor writes to the same table, or if dbda8d6ce9 2007-07-21 drh: ** the cursor is moved to a different row. Additionally, in auto-vacuum dbda8d6ce9 2007-07-21 drh: ** mode, the following events may invalidate an overflow page-list cache. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * An incremental vacuum, dbda8d6ce9 2007-07-21 drh: ** * A commit in auto_vacuum="full" mode, dbda8d6ce9 2007-07-21 drh: ** * Creating a table (may require moving an overflow page). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int accessPayload( dbda8d6ce9 2007-07-21 drh: BtCursor *pCur, /* Cursor pointing to entry to read from */ dbda8d6ce9 2007-07-21 drh: int offset, /* Begin reading this far into payload */ dbda8d6ce9 2007-07-21 drh: int amt, /* Read this many bytes */ dbda8d6ce9 2007-07-21 drh: unsigned char *pBuf, /* Write the bytes into this buffer */ dbda8d6ce9 2007-07-21 drh: int skipKey, /* offset begins at data if this is true */ dbda8d6ce9 2007-07-21 drh: int eOp /* zero to read. non-zero to write. */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: unsigned char *aPayload; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: u32 nKey; dbda8d6ce9 2007-07-21 drh: int iIdx = 0; c287665ba8 2007-09-14 drh: MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */ c287665ba8 2007-09-14 drh: BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPage ); dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID ); dbda8d6ce9 2007-07-21 drh: assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); dbda8d6ce9 2007-07-21 drh: assert( offset>=0 ); c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: getCellInfo(pCur); dbda8d6ce9 2007-07-21 drh: aPayload = pCur->info.pCell + pCur->info.nHeader; dbda8d6ce9 2007-07-21 drh: nKey = (pPage->intKey ? 0 : pCur->info.nKey); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( skipKey ){ dbda8d6ce9 2007-07-21 drh: offset += nKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( offset+amt > nKey+pCur->info.nData ){ dbda8d6ce9 2007-07-21 drh: /* Trying to read or write past the end of the data is an error */ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check if data must be read/written to/from the btree page itself. */ dbda8d6ce9 2007-07-21 drh: if( offset<pCur->info.nLocal ){ dbda8d6ce9 2007-07-21 drh: int a = amt; dbda8d6ce9 2007-07-21 drh: if( a+offset>pCur->info.nLocal ){ dbda8d6ce9 2007-07-21 drh: a = pCur->info.nLocal - offset; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: offset = 0; dbda8d6ce9 2007-07-21 drh: pBuf += a; dbda8d6ce9 2007-07-21 drh: amt -= a; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: offset -= pCur->info.nLocal; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && amt>0 ){ dbda8d6ce9 2007-07-21 drh: const int ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */ dbda8d6ce9 2007-07-21 drh: Pgno nextPage; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nextPage = get4byte(&aPayload[pCur->info.nLocal]); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[] dbda8d6ce9 2007-07-21 drh: ** has not been allocated, allocate it now. The array is sized at dbda8d6ce9 2007-07-21 drh: ** one entry for each overflow page in the overflow chain. The dbda8d6ce9 2007-07-21 drh: ** page number of the first overflow page is stored in aOverflow[0], dbda8d6ce9 2007-07-21 drh: ** etc. A value of 0 in the aOverflow[] array means "not yet known" dbda8d6ce9 2007-07-21 drh: ** (the cache is lazily populated). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pCur->isIncrblobHandle && !pCur->aOverflow ){ dbda8d6ce9 2007-07-21 drh: int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; c287665ba8 2007-09-14 drh: pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); dbda8d6ce9 2007-07-21 drh: if( nOvfl && !pCur->aOverflow ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the overflow page-list cache has been allocated and the dbda8d6ce9 2007-07-21 drh: ** entry for the first required overflow page is valid, skip dbda8d6ce9 2007-07-21 drh: ** directly to it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){ dbda8d6ce9 2007-07-21 drh: iIdx = (offset/ovflSize); dbda8d6ce9 2007-07-21 drh: nextPage = pCur->aOverflow[iIdx]; dbda8d6ce9 2007-07-21 drh: offset = (offset%ovflSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: /* If required, populate the overflow page-list cache. */ dbda8d6ce9 2007-07-21 drh: if( pCur->aOverflow ){ dbda8d6ce9 2007-07-21 drh: assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage); dbda8d6ce9 2007-07-21 drh: pCur->aOverflow[iIdx] = nextPage; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( offset>=ovflSize ){ dbda8d6ce9 2007-07-21 drh: /* The only reason to read this page is to obtain the page dbda8d6ce9 2007-07-21 drh: ** number for the next page in the overflow chain. The page c287665ba8 2007-09-14 drh: ** data is not required. So first try to lookup the overflow c287665ba8 2007-09-14 drh: ** page-list cache, if any, then fall back to the getOverflowPage() dbda8d6ce9 2007-07-21 drh: ** function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){ dbda8d6ce9 2007-07-21 drh: nextPage = pCur->aOverflow[iIdx+1]; dbda8d6ce9 2007-07-21 drh: } else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: rc = getOverflowPage(pBt, nextPage, 0, &nextPage); dbda8d6ce9 2007-07-21 drh: offset -= ovflSize; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Need to read this page properly. It contains some of the dbda8d6ce9 2007-07-21 drh: ** range of data that is being read (eOp==0) or written (eOp!=0). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; dbda8d6ce9 2007-07-21 drh: int a = amt; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: aPayload = sqlite3PagerGetData(pDbPage); dbda8d6ce9 2007-07-21 drh: nextPage = get4byte(aPayload); dbda8d6ce9 2007-07-21 drh: if( a + offset > ovflSize ){ dbda8d6ce9 2007-07-21 drh: a = ovflSize - offset; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pDbPage); dbda8d6ce9 2007-07-21 drh: offset = 0; dbda8d6ce9 2007-07-21 drh: amt -= a; dbda8d6ce9 2007-07-21 drh: pBuf += a; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && amt>0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read part of the key associated with cursor pCur. Exactly dbda8d6ce9 2007-07-21 drh: ** "amt" bytes will be transfered into pBuf[]. The transfer dbda8d6ce9 2007-07-21 drh: ** begins at "offset". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK on success or an error code if anything goes dbda8d6ce9 2007-07-21 drh: ** wrong. An error is returned if "offset+amt" is larger than dbda8d6ce9 2007-07-21 drh: ** the available payload. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: rc = restoreOrClearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID ); dbda8d6ce9 2007-07-21 drh: assert( pCur->pPage!=0 ); dbda8d6ce9 2007-07-21 drh: if( pCur->pPage->intKey ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pCur->pPage->intKey==0 ); dbda8d6ce9 2007-07-21 drh: assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); dbda8d6ce9 2007-07-21 drh: rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read part of the data associated with cursor pCur. Exactly dbda8d6ce9 2007-07-21 drh: ** "amt" bytes will be transfered into pBuf[]. The transfer dbda8d6ce9 2007-07-21 drh: ** begins at "offset". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK on success or an error code if anything goes dbda8d6ce9 2007-07-21 drh: ** wrong. An error is returned if "offset+amt" is larger than dbda8d6ce9 2007-07-21 drh: ** the available payload. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: rc = restoreOrClearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID ); dbda8d6ce9 2007-07-21 drh: assert( pCur->pPage!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); dbda8d6ce9 2007-07-21 drh: rc = accessPayload(pCur, offset, amt, pBuf, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a pointer to payload information from the entry that the dbda8d6ce9 2007-07-21 drh: ** pCur cursor is pointing to. The pointer is to the beginning of dbda8d6ce9 2007-07-21 drh: ** the key if skipKey==0 and it points to the beginning of data if dbda8d6ce9 2007-07-21 drh: ** skipKey==1. The number of bytes of available key/data is written dbda8d6ce9 2007-07-21 drh: ** into *pAmt. If *pAmt==0, then the value returned will not be dbda8d6ce9 2007-07-21 drh: ** a valid pointer. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is an optimization. It is common for the entire key dbda8d6ce9 2007-07-21 drh: ** and data to fit on the local page and for there to be no overflow dbda8d6ce9 2007-07-21 drh: ** pages. When that is so, this routine can be used to access the dbda8d6ce9 2007-07-21 drh: ** key and data without making a copy. If the key and/or data spills dbda8d6ce9 2007-07-21 drh: ** onto overflow pages, then accessPayload() must be used to reassembly dbda8d6ce9 2007-07-21 drh: ** the key/data and copy it into a preallocated buffer. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pointer returned by this routine looks directly into the cached dbda8d6ce9 2007-07-21 drh: ** page of the database. The data might change or move the next time dbda8d6ce9 2007-07-21 drh: ** any btree routine is called. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const unsigned char *fetchPayload( dbda8d6ce9 2007-07-21 drh: BtCursor *pCur, /* Cursor pointing to entry to read from */ dbda8d6ce9 2007-07-21 drh: int *pAmt, /* Write the number of available bytes here */ dbda8d6ce9 2007-07-21 drh: int skipKey /* read beginning at data if this is true */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: unsigned char *aPayload; dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: u32 nKey; dbda8d6ce9 2007-07-21 drh: int nLocal; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pCur!=0 && pCur->pPage!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID ); c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); dbda8d6ce9 2007-07-21 drh: getCellInfo(pCur); dbda8d6ce9 2007-07-21 drh: aPayload = pCur->info.pCell; dbda8d6ce9 2007-07-21 drh: aPayload += pCur->info.nHeader; dbda8d6ce9 2007-07-21 drh: if( pPage->intKey ){ dbda8d6ce9 2007-07-21 drh: nKey = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nKey = pCur->info.nKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( skipKey ){ dbda8d6ce9 2007-07-21 drh: aPayload += nKey; dbda8d6ce9 2007-07-21 drh: nLocal = pCur->info.nLocal - nKey; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nLocal = pCur->info.nLocal; dbda8d6ce9 2007-07-21 drh: if( nLocal>nKey ){ dbda8d6ce9 2007-07-21 drh: nLocal = nKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pAmt = nLocal; dbda8d6ce9 2007-07-21 drh: return aPayload; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** For the entry that cursor pCur is point to, return as dbda8d6ce9 2007-07-21 drh: ** many bytes of the key or data as are available on the local dbda8d6ce9 2007-07-21 drh: ** b-tree page. Write the number of available bytes into *pAmt. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pointer returned is ephemeral. The key/data may move c287665ba8 2007-09-14 drh: ** or be destroyed on the next call to any Btree routine, c287665ba8 2007-09-14 drh: ** including calls from other threads against the same cache. c287665ba8 2007-09-14 drh: ** Hence, a mutex on the BtShared should be held prior to calling c287665ba8 2007-09-14 drh: ** this routine. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines is used to get quick access to key and data dbda8d6ce9 2007-07-21 drh: ** in the common case where no overflow pages are used. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){ c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: if( pCur->eState==CURSOR_VALID ){ dbda8d6ce9 2007-07-21 drh: return (const void*)fetchPayload(pCur, pAmt, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){ c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: if( pCur->eState==CURSOR_VALID ){ dbda8d6ce9 2007-07-21 drh: return (const void*)fetchPayload(pCur, pAmt, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move the cursor down to a new child page. The newPgno argument is the dbda8d6ce9 2007-07-21 drh: ** page number of the child page to move to. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int moveToChild(BtCursor *pCur, u32 newPgno){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: MemPage *pNewPage; dbda8d6ce9 2007-07-21 drh: MemPage *pOldPage; c287665ba8 2007-09-14 drh: BtShared *pBt = pCur->pBt; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID ); dbda8d6ce9 2007-07-21 drh: rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: pNewPage->idxParent = pCur->idx; dbda8d6ce9 2007-07-21 drh: pOldPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: pOldPage->idxShift = 0; dbda8d6ce9 2007-07-21 drh: releasePage(pOldPage); dbda8d6ce9 2007-07-21 drh: pCur->pPage = pNewPage; dbda8d6ce9 2007-07-21 drh: pCur->idx = 0; dbda8d6ce9 2007-07-21 drh: pCur->info.nSize = 0; dbda8d6ce9 2007-07-21 drh: if( pNewPage->nCell<1 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return true if the page is the virtual root of its table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The virtual root page is the root page for most tables. But dbda8d6ce9 2007-07-21 drh: ** for the table rooted on page 1, sometime the real root page dbda8d6ce9 2007-07-21 drh: ** is empty except for the right-pointer. In such cases the dbda8d6ce9 2007-07-21 drh: ** virtual root page is the page that the right-pointer of page dbda8d6ce9 2007-07-21 drh: ** 1 is pointing to. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeIsRootPage(MemPage *pPage){ c287665ba8 2007-09-14 drh: MemPage *pParent; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); c287665ba8 2007-09-14 drh: pParent = pPage->pParent; dbda8d6ce9 2007-07-21 drh: if( pParent==0 ) return 1; dbda8d6ce9 2007-07-21 drh: if( pParent->pgno>1 ) return 0; dbda8d6ce9 2007-07-21 drh: if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move the cursor up to the parent page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pCur->idx is set to the cell index that contains the pointer dbda8d6ce9 2007-07-21 drh: ** to the page we are coming from. If we are coming from the dbda8d6ce9 2007-07-21 drh: ** right-most child page then pCur->idx is set to one more than dbda8d6ce9 2007-07-21 drh: ** the largest cell index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeMoveToParent(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: MemPage *pParent; dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: int idxParent; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID ); dbda8d6ce9 2007-07-21 drh: pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: assert( pPage!=0 ); dbda8d6ce9 2007-07-21 drh: assert( !sqlite3BtreeIsRootPage(pPage) ); dbda8d6ce9 2007-07-21 drh: pParent = pPage->pParent; dbda8d6ce9 2007-07-21 drh: assert( pParent!=0 ); dbda8d6ce9 2007-07-21 drh: idxParent = pPage->idxParent; dbda8d6ce9 2007-07-21 drh: sqlite3PagerRef(pParent->pDbPage); dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: pCur->pPage = pParent; dbda8d6ce9 2007-07-21 drh: pCur->info.nSize = 0; dbda8d6ce9 2007-07-21 drh: assert( pParent->idxShift==0 ); dbda8d6ce9 2007-07-21 drh: pCur->idx = idxParent; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move the cursor to the root page dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int moveToRoot(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: MemPage *pRoot; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: Btree *p = pCur->pBtree; c287665ba8 2007-09-14 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); c287665ba8 2007-09-14 drh: assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); c287665ba8 2007-09-14 drh: assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); c287665ba8 2007-09-14 drh: if( pCur->eState>=CURSOR_REQUIRESEEK ){ c287665ba8 2007-09-14 drh: if( pCur->eState==CURSOR_FAULT ){ c287665ba8 2007-09-14 drh: return pCur->skip; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: clearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pRoot = pCur->pPage; dbda8d6ce9 2007-07-21 drh: if( pRoot && pRoot->pgno==pCur->pgnoRoot ){ dbda8d6ce9 2007-07-21 drh: assert( pRoot->isInit ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0)) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: pCur->eState = CURSOR_INVALID; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releasePage(pCur->pPage); dbda8d6ce9 2007-07-21 drh: pCur->pPage = pRoot; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->idx = 0; dbda8d6ce9 2007-07-21 drh: pCur->info.nSize = 0; dbda8d6ce9 2007-07-21 drh: if( pRoot->nCell==0 && !pRoot->leaf ){ dbda8d6ce9 2007-07-21 drh: Pgno subpage; dbda8d6ce9 2007-07-21 drh: assert( pRoot->pgno==1 ); dbda8d6ce9 2007-07-21 drh: subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); dbda8d6ce9 2007-07-21 drh: assert( subpage>0 ); dbda8d6ce9 2007-07-21 drh: pCur->eState = CURSOR_VALID; dbda8d6ce9 2007-07-21 drh: rc = moveToChild(pCur, subpage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->eState = ((pCur->pPage->nCell>0)?CURSOR_VALID:CURSOR_INVALID); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move the cursor down to the left-most leaf entry beneath the dbda8d6ce9 2007-07-21 drh: ** entry to which it is currently pointing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The left-most leaf is the one with the smallest key - the first dbda8d6ce9 2007-07-21 drh: ** in ascending order. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int moveToLeftmost(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: Pgno pgno; c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID ); c287665ba8 2007-09-14 drh: while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ dbda8d6ce9 2007-07-21 drh: assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); dbda8d6ce9 2007-07-21 drh: pgno = get4byte(findCell(pPage, pCur->idx)); dbda8d6ce9 2007-07-21 drh: rc = moveToChild(pCur, pgno); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move the cursor down to the right-most leaf entry beneath the dbda8d6ce9 2007-07-21 drh: ** page to which it is currently pointing. Notice the difference dbda8d6ce9 2007-07-21 drh: ** between moveToLeftmost() and moveToRightmost(). moveToLeftmost() dbda8d6ce9 2007-07-21 drh: ** finds the left-most entry beneath the *entry* whereas moveToRightmost() dbda8d6ce9 2007-07-21 drh: ** finds the right-most entry beneath the *page*. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The right-most entry is the one with the largest key - the last dbda8d6ce9 2007-07-21 drh: ** key in ascending order. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int moveToRightmost(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: Pgno pgno; c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: assert( pCur->eState==CURSOR_VALID ); c287665ba8 2007-09-14 drh: while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ dbda8d6ce9 2007-07-21 drh: pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); dbda8d6ce9 2007-07-21 drh: pCur->idx = pPage->nCell; dbda8d6ce9 2007-07-21 drh: rc = moveToChild(pCur, pgno); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: pCur->idx = pPage->nCell - 1; c287665ba8 2007-09-14 drh: pCur->info.nSize = 0; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Move the cursor to the first entry in the table. Return SQLITE_OK dbda8d6ce9 2007-07-21 drh: ** on success. Set *pRes to 0 if the cursor actually points to something dbda8d6ce9 2007-07-21 drh: ** or set *pRes to 1 if the table is empty. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); dbda8d6ce9 2007-07-21 drh: rc = moveToRoot(pCur); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: if( pCur->eState==CURSOR_INVALID ){ c287665ba8 2007-09-14 drh: assert( pCur->pPage->nCell==0 ); c287665ba8 2007-09-14 drh: *pRes = 1; c287665ba8 2007-09-14 drh: rc = SQLITE_OK; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: assert( pCur->pPage->nCell>0 ); c287665ba8 2007-09-14 drh: *pRes = 0; c287665ba8 2007-09-14 drh: rc = moveToLeftmost(pCur); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Move the cursor to the last entry in the table. Return SQLITE_OK dbda8d6ce9 2007-07-21 drh: ** on success. Set *pRes to 0 if the cursor actually points to something dbda8d6ce9 2007-07-21 drh: ** or set *pRes to 1 if the table is empty. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); dbda8d6ce9 2007-07-21 drh: rc = moveToRoot(pCur); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: if( CURSOR_INVALID==pCur->eState ){ c287665ba8 2007-09-14 drh: assert( pCur->pPage->nCell==0 ); c287665ba8 2007-09-14 drh: *pRes = 1; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: assert( pCur->eState==CURSOR_VALID ); c287665ba8 2007-09-14 drh: *pRes = 0; c287665ba8 2007-09-14 drh: rc = moveToRightmost(pCur); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Move the cursor so that it points to an entry near pKey/nKey. dbda8d6ce9 2007-07-21 drh: ** Return a success code. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For INTKEY tables, only the nKey parameter is used. pKey is dbda8d6ce9 2007-07-21 drh: ** ignored. For other tables, nKey is the number of bytes of data dbda8d6ce9 2007-07-21 drh: ** in pKey. The comparison function specified when the cursor was dbda8d6ce9 2007-07-21 drh: ** created is used to compare keys. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an exact match is not found, then the cursor is always dbda8d6ce9 2007-07-21 drh: ** left pointing at a leaf page which would hold the entry if it dbda8d6ce9 2007-07-21 drh: ** were present. The cursor might point to an entry that comes dbda8d6ce9 2007-07-21 drh: ** before or after the key. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The result of comparing the key with the entry to which the dbda8d6ce9 2007-07-21 drh: ** cursor is written to *pRes if pRes!=NULL. The meaning of dbda8d6ce9 2007-07-21 drh: ** this value is as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** *pRes<0 The cursor is left pointing at an entry that dbda8d6ce9 2007-07-21 drh: ** is smaller than pKey or if the table is empty dbda8d6ce9 2007-07-21 drh: ** and the cursor is therefore left point to nothing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** *pRes==0 The cursor is left pointing at an entry that dbda8d6ce9 2007-07-21 drh: ** exactly matches pKey. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** *pRes>0 The cursor is left pointing at an entry that dbda8d6ce9 2007-07-21 drh: ** is larger than pKey. c287665ba8 2007-09-14 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeMoveto( dbda8d6ce9 2007-07-21 drh: BtCursor *pCur, /* The cursor to be moved */ dbda8d6ce9 2007-07-21 drh: const void *pKey, /* The key content for indices. Not used by tables */ dbda8d6ce9 2007-07-21 drh: i64 nKey, /* Size of pKey. Or the key for tables */ dbda8d6ce9 2007-07-21 drh: int biasRight, /* If true, bias the search to the high end */ dbda8d6ce9 2007-07-21 drh: int *pRes /* Search result flag */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); dbda8d6ce9 2007-07-21 drh: rc = moveToRoot(pCur); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: assert( pCur->pPage ); dbda8d6ce9 2007-07-21 drh: assert( pCur->pPage->isInit ); dbda8d6ce9 2007-07-21 drh: if( pCur->eState==CURSOR_INVALID ){ dbda8d6ce9 2007-07-21 drh: *pRes = -1; dbda8d6ce9 2007-07-21 drh: assert( pCur->pPage->nCell==0 ); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(;;){ dbda8d6ce9 2007-07-21 drh: int lwr, upr; dbda8d6ce9 2007-07-21 drh: Pgno chldPg; dbda8d6ce9 2007-07-21 drh: MemPage *pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: int c = -1; /* pRes return if table is empty must be -1 */ dbda8d6ce9 2007-07-21 drh: lwr = 0; dbda8d6ce9 2007-07-21 drh: upr = pPage->nCell-1; dbda8d6ce9 2007-07-21 drh: if( !pPage->intKey && pKey==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( biasRight ){ dbda8d6ce9 2007-07-21 drh: pCur->idx = upr; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pCur->idx = (upr+lwr)/2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( lwr<=upr ) for(;;){ dbda8d6ce9 2007-07-21 drh: void *pCellKey; dbda8d6ce9 2007-07-21 drh: i64 nCellKey; dbda8d6ce9 2007-07-21 drh: pCur->info.nSize = 0; dbda8d6ce9 2007-07-21 drh: if( pPage->intKey ){ dbda8d6ce9 2007-07-21 drh: u8 *pCell; dbda8d6ce9 2007-07-21 drh: pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize; dbda8d6ce9 2007-07-21 drh: if( pPage->hasData ){ dbda8d6ce9 2007-07-21 drh: u32 dummy; dbda8d6ce9 2007-07-21 drh: pCell += getVarint32(pCell, &dummy); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: getVarint(pCell, (u64 *)&nCellKey); dbda8d6ce9 2007-07-21 drh: if( nCellKey<nKey ){ dbda8d6ce9 2007-07-21 drh: c = -1; dbda8d6ce9 2007-07-21 drh: }else if( nCellKey>nKey ){ dbda8d6ce9 2007-07-21 drh: c = +1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: c = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int available; dbda8d6ce9 2007-07-21 drh: pCellKey = (void *)fetchPayload(pCur, &available, 0); dbda8d6ce9 2007-07-21 drh: nCellKey = pCur->info.nKey; dbda8d6ce9 2007-07-21 drh: if( available>=nCellKey ){ dbda8d6ce9 2007-07-21 drh: c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: pCellKey = sqlite3_malloc( nCellKey ); dbda8d6ce9 2007-07-21 drh: if( pCellKey==0 ) return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey); dbda8d6ce9 2007-07-21 drh: c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey); c287665ba8 2007-09-14 drh: sqlite3_free(pCellKey); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( c==0 ){ dbda8d6ce9 2007-07-21 drh: if( pPage->leafData && !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: lwr = pCur->idx; dbda8d6ce9 2007-07-21 drh: upr = lwr - 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( pRes ) *pRes = 0; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( c<0 ){ dbda8d6ce9 2007-07-21 drh: lwr = pCur->idx+1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: upr = pCur->idx-1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( lwr>upr ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->idx = (lwr+upr)/2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( lwr==upr+1 ); dbda8d6ce9 2007-07-21 drh: assert( pPage->isInit ); dbda8d6ce9 2007-07-21 drh: if( pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: chldPg = 0; dbda8d6ce9 2007-07-21 drh: }else if( lwr>=pPage->nCell ){ dbda8d6ce9 2007-07-21 drh: chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: chldPg = get4byte(findCell(pPage, lwr)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( chldPg==0 ){ dbda8d6ce9 2007-07-21 drh: assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); dbda8d6ce9 2007-07-21 drh: if( pRes ) *pRes = c; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->idx = lwr; dbda8d6ce9 2007-07-21 drh: pCur->info.nSize = 0; dbda8d6ce9 2007-07-21 drh: rc = moveToChild(pCur, chldPg); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* NOT REACHED */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the cursor is not pointing at an entry of the table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** TRUE will be returned after a call to sqlite3BtreeNext() moves dbda8d6ce9 2007-07-21 drh: ** past the last entry in the table or sqlite3BtreePrev() moves past dbda8d6ce9 2007-07-21 drh: ** the first entry. TRUE is also returned if the table is empty. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries dbda8d6ce9 2007-07-21 drh: ** have been deleted? This API will need to change to return an error code dbda8d6ce9 2007-07-21 drh: ** as well as the boolean result value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: return (CURSOR_VALID!=pCur->eState); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Return the database connection handle for a cursor. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3 *sqlite3BtreeCursorDb(const BtCursor *pCur){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: return pCur->pBtree->pSqlite; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* dbda8d6ce9 2007-07-21 drh: ** Advance the cursor to the next entry in the database. If dbda8d6ce9 2007-07-21 drh: ** successful then set *pRes=0. If the cursor dbda8d6ce9 2007-07-21 drh: ** was already pointing to the last entry in the database before dbda8d6ce9 2007-07-21 drh: ** this routine was called, then set *pRes=1. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int btreeNext(BtCursor *pCur, int *pRes){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: rc = restoreOrClearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pRes!=0 ); dbda8d6ce9 2007-07-21 drh: pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: if( CURSOR_INVALID==pCur->eState ){ dbda8d6ce9 2007-07-21 drh: *pRes = 1; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCur->skip>0 ){ dbda8d6ce9 2007-07-21 drh: pCur->skip = 0; dbda8d6ce9 2007-07-21 drh: *pRes = 0; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->skip = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPage->isInit ); dbda8d6ce9 2007-07-21 drh: assert( pCur->idx<pPage->nCell ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pCur->idx++; dbda8d6ce9 2007-07-21 drh: pCur->info.nSize = 0; dbda8d6ce9 2007-07-21 drh: if( pCur->idx>=pPage->nCell ){ dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: rc = moveToLeftmost(pCur); dbda8d6ce9 2007-07-21 drh: *pRes = 0; dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: if( sqlite3BtreeIsRootPage(pPage) ){ dbda8d6ce9 2007-07-21 drh: *pRes = 1; dbda8d6ce9 2007-07-21 drh: pCur->eState = CURSOR_INVALID; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3BtreeMoveToParent(pCur); dbda8d6ce9 2007-07-21 drh: pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: }while( pCur->idx>=pPage->nCell ); dbda8d6ce9 2007-07-21 drh: *pRes = 0; dbda8d6ce9 2007-07-21 drh: if( pPage->leafData ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeNext(pCur, pRes); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pRes = 0; dbda8d6ce9 2007-07-21 drh: if( pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = moveToLeftmost(pCur); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: rc = btreeNext(pCur, pRes); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Step the cursor to the back to the previous entry in the database. If dbda8d6ce9 2007-07-21 drh: ** successful then set *pRes=0. If the cursor dbda8d6ce9 2007-07-21 drh: ** was already pointing to the first entry in the database before dbda8d6ce9 2007-07-21 drh: ** this routine was called, then set *pRes=1. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int btreePrevious(BtCursor *pCur, int *pRes){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Pgno pgno; dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: rc = restoreOrClearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( CURSOR_INVALID==pCur->eState ){ dbda8d6ce9 2007-07-21 drh: *pRes = 1; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCur->skip<0 ){ dbda8d6ce9 2007-07-21 drh: pCur->skip = 0; dbda8d6ce9 2007-07-21 drh: *pRes = 0; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->skip = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: assert( pPage->isInit ); dbda8d6ce9 2007-07-21 drh: assert( pCur->idx>=0 ); dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: pgno = get4byte( findCell(pPage, pCur->idx) ); dbda8d6ce9 2007-07-21 drh: rc = moveToChild(pCur, pgno); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: rc = moveToRightmost(pCur); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: while( pCur->idx==0 ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3BtreeIsRootPage(pPage) ){ dbda8d6ce9 2007-07-21 drh: pCur->eState = CURSOR_INVALID; dbda8d6ce9 2007-07-21 drh: *pRes = 1; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3BtreeMoveToParent(pCur); dbda8d6ce9 2007-07-21 drh: pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->idx--; dbda8d6ce9 2007-07-21 drh: pCur->info.nSize = 0; dbda8d6ce9 2007-07-21 drh: if( pPage->leafData && !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreePrevious(pCur, pRes); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pRes = 0; c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: rc = btreePrevious(pCur, pRes); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate a new page from the database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The new page is marked as dirty. (In other words, sqlite3PagerWrite() dbda8d6ce9 2007-07-21 drh: ** has already been called on the new page.) The new page has also dbda8d6ce9 2007-07-21 drh: ** been referenced and the calling routine is responsible for calling dbda8d6ce9 2007-07-21 drh: ** sqlite3PagerUnref() on the new page when it is done. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK is returned on success. Any other return value indicates dbda8d6ce9 2007-07-21 drh: ** an error. *ppPage and *pPgno are undefined in the event of an error. dbda8d6ce9 2007-07-21 drh: ** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the "nearby" parameter is not 0, then a (feeble) effort is made to dbda8d6ce9 2007-07-21 drh: ** locate a page close to the page number "nearby". This can be used in an dbda8d6ce9 2007-07-21 drh: ** attempt to keep related pages close to each other in the database file, dbda8d6ce9 2007-07-21 drh: ** which in turn can make database access faster. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the "exact" parameter is not 0, and the page-number nearby exists dbda8d6ce9 2007-07-21 drh: ** anywhere on the free-list, then it is guarenteed to be returned. This dbda8d6ce9 2007-07-21 drh: ** is only used by auto-vacuum databases when allocating a new table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int allocateBtreePage( dbda8d6ce9 2007-07-21 drh: BtShared *pBt, dbda8d6ce9 2007-07-21 drh: MemPage **ppPage, dbda8d6ce9 2007-07-21 drh: Pgno *pPgno, dbda8d6ce9 2007-07-21 drh: Pgno nearby, dbda8d6ce9 2007-07-21 drh: u8 exact dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: MemPage *pPage1; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: int n; /* Number of pages on the freelist */ dbda8d6ce9 2007-07-21 drh: int k; /* Number of leaves on the trunk of the freelist */ dbda8d6ce9 2007-07-21 drh: MemPage *pTrunk = 0; dbda8d6ce9 2007-07-21 drh: MemPage *pPrevTrunk = 0; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: pPage1 = pBt->pPage1; dbda8d6ce9 2007-07-21 drh: n = get4byte(&pPage1->aData[36]); dbda8d6ce9 2007-07-21 drh: if( n>0 ){ dbda8d6ce9 2007-07-21 drh: /* There are pages on the freelist. Reuse one of those pages. */ dbda8d6ce9 2007-07-21 drh: Pgno iTrunk; dbda8d6ce9 2007-07-21 drh: u8 searchList = 0; /* If the free-list must be searched for 'nearby' */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the 'exact' parameter was true and a query of the pointer-map dbda8d6ce9 2007-07-21 drh: ** shows that the page 'nearby' is somewhere on the free-list, then dbda8d6ce9 2007-07-21 drh: ** the entire-list will be searched for that page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( exact && nearby<=sqlite3PagerPagecount(pBt->pPager) ){ dbda8d6ce9 2007-07-21 drh: u8 eType; dbda8d6ce9 2007-07-21 drh: assert( nearby>0 ); dbda8d6ce9 2007-07-21 drh: assert( pBt->autoVacuum ); dbda8d6ce9 2007-07-21 drh: rc = ptrmapGet(pBt, nearby, &eType, 0); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: if( eType==PTRMAP_FREEPAGE ){ dbda8d6ce9 2007-07-21 drh: searchList = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pPgno = nearby; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Decrement the free-list count by 1. Set iTrunk to the index of the dbda8d6ce9 2007-07-21 drh: ** first free-list trunk page. iPrevTrunk is initially 1. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPage1->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: put4byte(&pPage1->aData[36], n-1); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The code within this loop is run only once if the 'searchList' variable dbda8d6ce9 2007-07-21 drh: ** is not true. Otherwise, it runs once for each trunk-page on the dbda8d6ce9 2007-07-21 drh: ** free-list until the page 'nearby' is located. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: pPrevTrunk = pTrunk; dbda8d6ce9 2007-07-21 drh: if( pPrevTrunk ){ dbda8d6ce9 2007-07-21 drh: iTrunk = get4byte(&pPrevTrunk->aData[0]); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: iTrunk = get4byte(&pPage1->aData[32]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, iTrunk, &pTrunk, 0); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: pTrunk = 0; dbda8d6ce9 2007-07-21 drh: goto end_allocate_page; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: k = get4byte(&pTrunk->aData[4]); dbda8d6ce9 2007-07-21 drh: if( k==0 && !searchList ){ dbda8d6ce9 2007-07-21 drh: /* The trunk has no leaves and the list is not being searched. dbda8d6ce9 2007-07-21 drh: ** So extract the trunk page itself and use it as the newly dbda8d6ce9 2007-07-21 drh: ** allocated page */ dbda8d6ce9 2007-07-21 drh: assert( pPrevTrunk==0 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pTrunk->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto end_allocate_page; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pPgno = iTrunk; dbda8d6ce9 2007-07-21 drh: memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); dbda8d6ce9 2007-07-21 drh: *ppPage = pTrunk; dbda8d6ce9 2007-07-21 drh: pTrunk = 0; dbda8d6ce9 2007-07-21 drh: TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); dbda8d6ce9 2007-07-21 drh: }else if( k>pBt->usableSize/4 - 8 ){ dbda8d6ce9 2007-07-21 drh: /* Value of k is out of range. Database corruption */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: goto end_allocate_page; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: }else if( searchList && nearby==iTrunk ){ dbda8d6ce9 2007-07-21 drh: /* The list is being searched and this trunk page is the page dbda8d6ce9 2007-07-21 drh: ** to allocate, regardless of whether it has leaves. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( *pPgno==iTrunk ); dbda8d6ce9 2007-07-21 drh: *ppPage = pTrunk; dbda8d6ce9 2007-07-21 drh: searchList = 0; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pTrunk->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto end_allocate_page; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( k==0 ){ dbda8d6ce9 2007-07-21 drh: if( !pPrevTrunk ){ dbda8d6ce9 2007-07-21 drh: memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: memcpy(&pPrevTrunk->aData[0], &pTrunk->aData[0], 4); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The trunk page is required by the caller but it contains dbda8d6ce9 2007-07-21 drh: ** pointers to free-list leaves. The first leaf becomes a trunk dbda8d6ce9 2007-07-21 drh: ** page in this case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: MemPage *pNewTrunk; dbda8d6ce9 2007-07-21 drh: Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto end_allocate_page; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pNewTrunk->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pNewTrunk); dbda8d6ce9 2007-07-21 drh: goto end_allocate_page; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4); dbda8d6ce9 2007-07-21 drh: put4byte(&pNewTrunk->aData[4], k-1); dbda8d6ce9 2007-07-21 drh: memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4); dbda8d6ce9 2007-07-21 drh: releasePage(pNewTrunk); dbda8d6ce9 2007-07-21 drh: if( !pPrevTrunk ){ dbda8d6ce9 2007-07-21 drh: put4byte(&pPage1->aData[32], iNewTrunk); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPrevTrunk->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto end_allocate_page; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: put4byte(&pPrevTrunk->aData[0], iNewTrunk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTrunk = 0; dbda8d6ce9 2007-07-21 drh: TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Extract a leaf from the trunk */ dbda8d6ce9 2007-07-21 drh: int closest; dbda8d6ce9 2007-07-21 drh: Pgno iPage; dbda8d6ce9 2007-07-21 drh: unsigned char *aData = pTrunk->aData; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pTrunk->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto end_allocate_page; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nearby>0 ){ dbda8d6ce9 2007-07-21 drh: int i, dist; dbda8d6ce9 2007-07-21 drh: closest = 0; dbda8d6ce9 2007-07-21 drh: dist = get4byte(&aData[8]) - nearby; dbda8d6ce9 2007-07-21 drh: if( dist<0 ) dist = -dist; dbda8d6ce9 2007-07-21 drh: for(i=1; i<k; i++){ dbda8d6ce9 2007-07-21 drh: int d2 = get4byte(&aData[8+i*4]) - nearby; dbda8d6ce9 2007-07-21 drh: if( d2<0 ) d2 = -d2; dbda8d6ce9 2007-07-21 drh: if( d2<dist ){ dbda8d6ce9 2007-07-21 drh: closest = i; dbda8d6ce9 2007-07-21 drh: dist = d2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: closest = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: iPage = get4byte(&aData[8+closest*4]); dbda8d6ce9 2007-07-21 drh: if( !searchList || iPage==nearby ){ dbda8d6ce9 2007-07-21 drh: *pPgno = iPage; dbda8d6ce9 2007-07-21 drh: if( *pPgno>sqlite3PagerPagecount(pBt->pPager) ){ dbda8d6ce9 2007-07-21 drh: /* Free page off the end of the file */ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" dbda8d6ce9 2007-07-21 drh: ": %d more free pages\n", dbda8d6ce9 2007-07-21 drh: *pPgno, closest+1, k, pTrunk->pgno, n-1)); dbda8d6ce9 2007-07-21 drh: if( closest<k-1 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&aData[8+closest*4], &aData[4+k*4], 4); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: put4byte(&aData[4], k-1); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 1); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3PagerDontRollback((*ppPage)->pDbPage); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite((*ppPage)->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(*ppPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: searchList = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releasePage(pPrevTrunk); dbda8d6ce9 2007-07-21 drh: pPrevTrunk = 0; dbda8d6ce9 2007-07-21 drh: }while( searchList ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* There are no pages on the freelist, so create a new page at the dbda8d6ce9 2007-07-21 drh: ** end of the file */ dbda8d6ce9 2007-07-21 drh: *pPgno = sqlite3PagerPagecount(pBt->pPager) + 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->nTrunc ){ dbda8d6ce9 2007-07-21 drh: /* An incr-vacuum has already run within this transaction. So the dbda8d6ce9 2007-07-21 drh: ** page to allocate is not from the physical end of the file, but dbda8d6ce9 2007-07-21 drh: ** at pBt->nTrunc. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: *pPgno = pBt->nTrunc+1; dbda8d6ce9 2007-07-21 drh: if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: (*pPgno)++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){ dbda8d6ce9 2007-07-21 drh: /* If *pPgno refers to a pointer-map page, allocate two new pages dbda8d6ce9 2007-07-21 drh: ** at the end of the file instead of one. The first allocated page dbda8d6ce9 2007-07-21 drh: ** becomes a new pointer-map page, the second is used by the caller. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno)); dbda8d6ce9 2007-07-21 drh: assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); dbda8d6ce9 2007-07-21 drh: (*pPgno)++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pBt->nTrunc ){ dbda8d6ce9 2007-07-21 drh: pBt->nTrunc = *pPgno; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 0); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite((*ppPage)->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(*ppPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: end_allocate_page: dbda8d6ce9 2007-07-21 drh: releasePage(pTrunk); dbda8d6ce9 2007-07-21 drh: releasePage(pPrevTrunk); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a page of the database file to the freelist. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** sqlite3PagerUnref() is NOT called for pPage. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int freePage(MemPage *pPage){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: MemPage *pPage1 = pBt->pPage1; dbda8d6ce9 2007-07-21 drh: int rc, n, k; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Prepare the page for freeing */ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: assert( pPage->pgno>1 ); dbda8d6ce9 2007-07-21 drh: pPage->isInit = 0; dbda8d6ce9 2007-07-21 drh: releasePage(pPage->pParent); dbda8d6ce9 2007-07-21 drh: pPage->pParent = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Increment the free page count on pPage1 */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPage1->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: n = get4byte(&pPage1->aData[36]); dbda8d6ce9 2007-07-21 drh: put4byte(&pPage1->aData[36], n+1); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SECURE_DELETE dbda8d6ce9 2007-07-21 drh: /* If the SQLITE_SECURE_DELETE compile-time option is enabled, then dbda8d6ce9 2007-07-21 drh: ** always fully overwrite deleted information with zeros. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: memset(pPage->aData, 0, pPage->pBt->pageSize); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* If the database supports auto-vacuum, write an entry in the pointer-map dbda8d6ce9 2007-07-21 drh: ** to indicate that the page is free. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, pPage->pgno, PTRMAP_FREEPAGE, 0); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( n==0 ){ dbda8d6ce9 2007-07-21 drh: /* This is the first free page */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: memset(pPage->aData, 0, 8); dbda8d6ce9 2007-07-21 drh: put4byte(&pPage1->aData[32], pPage->pgno); dbda8d6ce9 2007-07-21 drh: TRACE(("FREE-PAGE: %d first\n", pPage->pgno)); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Other free pages already exist. Retrive the first trunk page dbda8d6ce9 2007-07-21 drh: ** of the freelist and find out how many leaves it has. */ dbda8d6ce9 2007-07-21 drh: MemPage *pTrunk; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk, 0); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: k = get4byte(&pTrunk->aData[4]); dbda8d6ce9 2007-07-21 drh: if( k>=pBt->usableSize/4 - 8 ){ dbda8d6ce9 2007-07-21 drh: /* The trunk is full. Turn the page being freed into a new dbda8d6ce9 2007-07-21 drh: ** trunk page with no leaves. */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pPage->pDbPage); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: put4byte(pPage->aData, pTrunk->pgno); c287665ba8 2007-09-14 drh: put4byte(&pPage->aData[4], 0); c287665ba8 2007-09-14 drh: put4byte(&pPage1->aData[32], pPage->pgno); c287665ba8 2007-09-14 drh: TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", c287665ba8 2007-09-14 drh: pPage->pgno, pTrunk->pgno)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: }else if( k<0 ){ c287665ba8 2007-09-14 drh: rc = SQLITE_CORRUPT; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Add the newly freed page as a leaf on the current trunk */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pTrunk->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: put4byte(&pTrunk->aData[4], k+1); dbda8d6ce9 2007-07-21 drh: put4byte(&pTrunk->aData[8+k*4], pPage->pgno); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_SECURE_DELETE dbda8d6ce9 2007-07-21 drh: sqlite3PagerDontWrite(pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releasePage(pTrunk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Free any overflow pages associated with the given Cell. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int clearCell(MemPage *pPage, unsigned char *pCell){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: Pgno ovflPgno; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: int nOvfl; dbda8d6ce9 2007-07-21 drh: int ovflPageSize; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pPage, pCell, &info); dbda8d6ce9 2007-07-21 drh: if( info.iOverflow==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; /* No overflow pages. Return without doing anything */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: ovflPgno = get4byte(&pCell[info.iOverflow]); dbda8d6ce9 2007-07-21 drh: ovflPageSize = pBt->usableSize - 4; dbda8d6ce9 2007-07-21 drh: nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize; dbda8d6ce9 2007-07-21 drh: assert( ovflPgno==0 || nOvfl>0 ); dbda8d6ce9 2007-07-21 drh: while( nOvfl-- ){ dbda8d6ce9 2007-07-21 drh: MemPage *pOvfl; dbda8d6ce9 2007-07-21 drh: if( ovflPgno==0 || ovflPgno>sqlite3PagerPagecount(pBt->pPager) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = getOverflowPage(pBt, ovflPgno, &pOvfl, (nOvfl==0)?0:&ovflPgno); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: rc = freePage(pOvfl); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pOvfl->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create the byte sequence used to represent a cell on page pPage dbda8d6ce9 2007-07-21 drh: ** and write that byte sequence into pCell[]. Overflow pages are dbda8d6ce9 2007-07-21 drh: ** allocated and filled in as necessary. The calling procedure dbda8d6ce9 2007-07-21 drh: ** is responsible for making sure sufficient space has been allocated dbda8d6ce9 2007-07-21 drh: ** for pCell[]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that pCell does not necessary need to point to the pPage->aData dbda8d6ce9 2007-07-21 drh: ** area. pCell might point to some temporary storage. The cell will dbda8d6ce9 2007-07-21 drh: ** be constructed in this temporary area then copied into pPage->aData dbda8d6ce9 2007-07-21 drh: ** later. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int fillInCell( dbda8d6ce9 2007-07-21 drh: MemPage *pPage, /* The page that contains the cell */ dbda8d6ce9 2007-07-21 drh: unsigned char *pCell, /* Complete text of the cell */ dbda8d6ce9 2007-07-21 drh: const void *pKey, i64 nKey, /* The key */ dbda8d6ce9 2007-07-21 drh: const void *pData,int nData, /* The data */ dbda8d6ce9 2007-07-21 drh: int nZero, /* Extra zero bytes to append to pData */ dbda8d6ce9 2007-07-21 drh: int *pnSize /* Write cell size here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int nPayload; dbda8d6ce9 2007-07-21 drh: const u8 *pSrc; dbda8d6ce9 2007-07-21 drh: int nSrc, n, rc; dbda8d6ce9 2007-07-21 drh: int spaceLeft; dbda8d6ce9 2007-07-21 drh: MemPage *pOvfl = 0; dbda8d6ce9 2007-07-21 drh: MemPage *pToRelease = 0; dbda8d6ce9 2007-07-21 drh: unsigned char *pPrior; dbda8d6ce9 2007-07-21 drh: unsigned char *pPayload; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: Pgno pgnoOvfl = 0; dbda8d6ce9 2007-07-21 drh: int nHeader; dbda8d6ce9 2007-07-21 drh: CellInfo info; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Fill in the header. */ dbda8d6ce9 2007-07-21 drh: nHeader = 0; dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: nHeader += 4; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPage->hasData ){ dbda8d6ce9 2007-07-21 drh: nHeader += putVarint(&pCell[nHeader], nData+nZero); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nData = nZero = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pPage, pCell, &info); dbda8d6ce9 2007-07-21 drh: assert( info.nHeader==nHeader ); dbda8d6ce9 2007-07-21 drh: assert( info.nKey==nKey ); dbda8d6ce9 2007-07-21 drh: assert( info.nData==nData+nZero ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Fill in the payload */ dbda8d6ce9 2007-07-21 drh: nPayload = nData + nZero; dbda8d6ce9 2007-07-21 drh: if( pPage->intKey ){ dbda8d6ce9 2007-07-21 drh: pSrc = pData; dbda8d6ce9 2007-07-21 drh: nSrc = nData; dbda8d6ce9 2007-07-21 drh: nData = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nPayload += nKey; dbda8d6ce9 2007-07-21 drh: pSrc = pKey; dbda8d6ce9 2007-07-21 drh: nSrc = nKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pnSize = info.nSize; dbda8d6ce9 2007-07-21 drh: spaceLeft = info.nLocal; dbda8d6ce9 2007-07-21 drh: pPayload = &pCell[nHeader]; dbda8d6ce9 2007-07-21 drh: pPrior = &pCell[info.iOverflow]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( nPayload>0 ){ dbda8d6ce9 2007-07-21 drh: if( spaceLeft==0 ){ dbda8d6ce9 2007-07-21 drh: int isExact = 0; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */ dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: pgnoOvfl++; dbda8d6ce9 2007-07-21 drh: } while( dbda8d6ce9 2007-07-21 drh: PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt) dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( pgnoOvfl>1 ){ dbda8d6ce9 2007-07-21 drh: /* isExact = 1; */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl, isExact); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* If the database supports auto-vacuum, and the second or subsequent dbda8d6ce9 2007-07-21 drh: ** overflow page is being allocated, add an entry to the pointer-map dbda8d6ce9 2007-07-21 drh: ** for that page now. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If this is the first overflow page, then write a partial entry dbda8d6ce9 2007-07-21 drh: ** to the pointer-map. If we write nothing to this pointer-map slot, dbda8d6ce9 2007-07-21 drh: ** then the optimistic overflow chain processing in clearCell() dbda8d6ce9 2007-07-21 drh: ** may misinterpret the uninitialised values and delete the dbda8d6ce9 2007-07-21 drh: ** wrong pages from the database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum && rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: u8 eType = (pgnoPtrmap?PTRMAP_OVERFLOW2:PTRMAP_OVERFLOW1); dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: releasePage(pOvfl); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: releasePage(pToRelease); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: put4byte(pPrior, pgnoOvfl); dbda8d6ce9 2007-07-21 drh: releasePage(pToRelease); dbda8d6ce9 2007-07-21 drh: pToRelease = pOvfl; dbda8d6ce9 2007-07-21 drh: pPrior = pOvfl->aData; dbda8d6ce9 2007-07-21 drh: put4byte(pPrior, 0); dbda8d6ce9 2007-07-21 drh: pPayload = &pOvfl->aData[4]; dbda8d6ce9 2007-07-21 drh: spaceLeft = pBt->usableSize - 4; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: n = nPayload; dbda8d6ce9 2007-07-21 drh: if( n>spaceLeft ) n = spaceLeft; dbda8d6ce9 2007-07-21 drh: if( nSrc>0 ){ dbda8d6ce9 2007-07-21 drh: if( n>nSrc ) n = nSrc; dbda8d6ce9 2007-07-21 drh: assert( pSrc ); dbda8d6ce9 2007-07-21 drh: memcpy(pPayload, pSrc, n); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: memset(pPayload, 0, n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nPayload -= n; dbda8d6ce9 2007-07-21 drh: pPayload += n; dbda8d6ce9 2007-07-21 drh: pSrc += n; dbda8d6ce9 2007-07-21 drh: nSrc -= n; dbda8d6ce9 2007-07-21 drh: spaceLeft -= n; dbda8d6ce9 2007-07-21 drh: if( nSrc==0 ){ dbda8d6ce9 2007-07-21 drh: nSrc = nData; dbda8d6ce9 2007-07-21 drh: pSrc = pData; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releasePage(pToRelease); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the MemPage.pParent pointer on the page whose number is dbda8d6ce9 2007-07-21 drh: ** given in the second argument so that MemPage.pParent holds the dbda8d6ce9 2007-07-21 drh: ** pointer in the third argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){ dbda8d6ce9 2007-07-21 drh: MemPage *pThis; dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: assert( pNewParent!=0 ); dbda8d6ce9 2007-07-21 drh: if( pgno==0 ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: assert( pBt->pPager!=0 ); dbda8d6ce9 2007-07-21 drh: pDbPage = sqlite3PagerLookup(pBt->pPager, pgno); dbda8d6ce9 2007-07-21 drh: if( pDbPage ){ dbda8d6ce9 2007-07-21 drh: pThis = (MemPage *)sqlite3PagerGetExtra(pDbPage); dbda8d6ce9 2007-07-21 drh: if( pThis->isInit ){ c287665ba8 2007-09-14 drh: assert( pThis->aData==sqlite3PagerGetData(pDbPage) ); dbda8d6ce9 2007-07-21 drh: if( pThis->pParent!=pNewParent ){ dbda8d6ce9 2007-07-21 drh: if( pThis->pParent ) sqlite3PagerUnref(pThis->pParent->pDbPage); dbda8d6ce9 2007-07-21 drh: pThis->pParent = pNewParent; dbda8d6ce9 2007-07-21 drh: sqlite3PagerRef(pNewParent->pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pThis->idxParent = idx; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: return ptrmapPut(pBt, pgno, PTRMAP_BTREE, pNewParent->pgno); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the pParent pointer of all children of pPage to point back dbda8d6ce9 2007-07-21 drh: ** to pPage. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In other words, for every child of pPage, invoke reparentPage() dbda8d6ce9 2007-07-21 drh: ** to make sure that each child knows that pPage is its parent. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine gets called after you memcpy() one page into dbda8d6ce9 2007-07-21 drh: ** another. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int reparentChildPages(MemPage *pPage){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pPage->leaf ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<pPage->nCell; i++){ dbda8d6ce9 2007-07-21 drh: u8 *pCell = findCell(pPage, i); dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: rc = reparentPage(pBt, get4byte(pCell), pPage, i); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: rc = reparentPage(pBt, get4byte(&pPage->aData[pPage->hdrOffset+8]), dbda8d6ce9 2007-07-21 drh: pPage, i); dbda8d6ce9 2007-07-21 drh: pPage->idxShift = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Remove the i-th cell from pPage. This routine effects pPage only. dbda8d6ce9 2007-07-21 drh: ** The cell content is not freed or deallocated. It is assumed that dbda8d6ce9 2007-07-21 drh: ** the cell content has been copied someplace else. This routine just dbda8d6ce9 2007-07-21 drh: ** removes the reference to the cell from pPage. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** "sz" must be the number of bytes in the cell. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void dropCell(MemPage *pPage, int idx, int sz){ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: int pc; /* Offset to cell content of cell being deleted */ dbda8d6ce9 2007-07-21 drh: u8 *data; /* pPage->aData */ dbda8d6ce9 2007-07-21 drh: u8 *ptr; /* Used to move bytes around within data[] */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( idx>=0 && idx<pPage->nCell ); dbda8d6ce9 2007-07-21 drh: assert( sz==cellSize(pPage, idx) ); dbda8d6ce9 2007-07-21 drh: assert( sqlite3PagerIswriteable(pPage->pDbPage) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: data = pPage->aData; dbda8d6ce9 2007-07-21 drh: ptr = &data[pPage->cellOffset + 2*idx]; dbda8d6ce9 2007-07-21 drh: pc = get2byte(ptr); dbda8d6ce9 2007-07-21 drh: assert( pc>10 && pc+sz<=pPage->pBt->usableSize ); dbda8d6ce9 2007-07-21 drh: freeSpace(pPage, pc, sz); dbda8d6ce9 2007-07-21 drh: for(i=idx+1; i<pPage->nCell; i++, ptr+=2){ dbda8d6ce9 2007-07-21 drh: ptr[0] = ptr[2]; dbda8d6ce9 2007-07-21 drh: ptr[1] = ptr[3]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPage->nCell--; dbda8d6ce9 2007-07-21 drh: put2byte(&data[pPage->hdrOffset+3], pPage->nCell); dbda8d6ce9 2007-07-21 drh: pPage->nFree += 2; dbda8d6ce9 2007-07-21 drh: pPage->idxShift = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Insert a new cell on pPage at cell index "i". pCell points to the dbda8d6ce9 2007-07-21 drh: ** content of the cell. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the cell content will fit on the page, then put it there. If it dbda8d6ce9 2007-07-21 drh: ** will not fit, then make a copy of the cell content into pTemp if dbda8d6ce9 2007-07-21 drh: ** pTemp is not null. Regardless of pTemp, allocate a new entry dbda8d6ce9 2007-07-21 drh: ** in pPage->aOvfl[] and make it point to the cell content (either dbda8d6ce9 2007-07-21 drh: ** in pTemp or the original pCell) and also record its index. dbda8d6ce9 2007-07-21 drh: ** Allocating a new entry in pPage->aCell[] implies that dbda8d6ce9 2007-07-21 drh: ** pPage->nOverflow is incremented. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If nSkip is non-zero, then do not copy the first nSkip bytes of the dbda8d6ce9 2007-07-21 drh: ** cell. The caller will overwrite them after this function returns. If dbda8d6ce9 2007-07-21 drh: ** nSkip is non-zero, then pCell may not point to an invalid memory location dbda8d6ce9 2007-07-21 drh: ** (but pCell+nSkip is always valid). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int insertCell( dbda8d6ce9 2007-07-21 drh: MemPage *pPage, /* Page into which we are copying */ dbda8d6ce9 2007-07-21 drh: int i, /* New cell becomes the i-th cell of the page */ dbda8d6ce9 2007-07-21 drh: u8 *pCell, /* Content of the new cell */ dbda8d6ce9 2007-07-21 drh: int sz, /* Bytes of content in pCell */ dbda8d6ce9 2007-07-21 drh: u8 *pTemp, /* Temp storage space for pCell, if needed */ dbda8d6ce9 2007-07-21 drh: u8 nSkip /* Do not write the first nSkip bytes of the cell */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int idx; /* Where to write new cell content in data[] */ dbda8d6ce9 2007-07-21 drh: int j; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: int top; /* First byte of content for any cell in data[] */ dbda8d6ce9 2007-07-21 drh: int end; /* First byte past the last cell pointer in data[] */ dbda8d6ce9 2007-07-21 drh: int ins; /* Index in data[] where new cell pointer is inserted */ dbda8d6ce9 2007-07-21 drh: int hdr; /* Offset into data[] of the page header */ dbda8d6ce9 2007-07-21 drh: int cellOffset; /* Address of first cell pointer in data[] */ dbda8d6ce9 2007-07-21 drh: u8 *data; /* The content of the whole page */ dbda8d6ce9 2007-07-21 drh: u8 *ptr; /* Used for moving information around in data[] */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); dbda8d6ce9 2007-07-21 drh: assert( sz==cellSizePtr(pPage, pCell) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pPage->nOverflow || sz+2>pPage->nFree ){ dbda8d6ce9 2007-07-21 drh: if( pTemp ){ dbda8d6ce9 2007-07-21 drh: memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip); dbda8d6ce9 2007-07-21 drh: pCell = pTemp; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: j = pPage->nOverflow++; dbda8d6ce9 2007-07-21 drh: assert( j<sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0]) ); dbda8d6ce9 2007-07-21 drh: pPage->aOvfl[j].pCell = pCell; dbda8d6ce9 2007-07-21 drh: pPage->aOvfl[j].idx = i; dbda8d6ce9 2007-07-21 drh: pPage->nFree = 0; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: int rc = sqlite3PagerWrite(pPage->pDbPage); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: assert( sqlite3PagerIswriteable(pPage->pDbPage) ); dbda8d6ce9 2007-07-21 drh: data = pPage->aData; dbda8d6ce9 2007-07-21 drh: hdr = pPage->hdrOffset; dbda8d6ce9 2007-07-21 drh: top = get2byte(&data[hdr+5]); dbda8d6ce9 2007-07-21 drh: cellOffset = pPage->cellOffset; dbda8d6ce9 2007-07-21 drh: end = cellOffset + 2*pPage->nCell + 2; dbda8d6ce9 2007-07-21 drh: ins = cellOffset + 2*i; dbda8d6ce9 2007-07-21 drh: if( end > top - sz ){ c287665ba8 2007-09-14 drh: rc = defragmentPage(pPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: top = get2byte(&data[hdr+5]); dbda8d6ce9 2007-07-21 drh: assert( end + sz <= top ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: idx = allocateSpace(pPage, sz); dbda8d6ce9 2007-07-21 drh: assert( idx>0 ); dbda8d6ce9 2007-07-21 drh: assert( end <= get2byte(&data[hdr+5]) ); dbda8d6ce9 2007-07-21 drh: pPage->nCell++; dbda8d6ce9 2007-07-21 drh: pPage->nFree -= 2; dbda8d6ce9 2007-07-21 drh: memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip); dbda8d6ce9 2007-07-21 drh: for(j=end-2, ptr=&data[j]; j>ins; j-=2, ptr-=2){ dbda8d6ce9 2007-07-21 drh: ptr[0] = ptr[-2]; dbda8d6ce9 2007-07-21 drh: ptr[1] = ptr[-1]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: put2byte(&data[ins], idx); dbda8d6ce9 2007-07-21 drh: put2byte(&data[hdr+3], pPage->nCell); dbda8d6ce9 2007-07-21 drh: pPage->idxShift = 1; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pPage->pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: /* The cell may contain a pointer to an overflow page. If so, write dbda8d6ce9 2007-07-21 drh: ** the entry for the overflow page into the pointer map. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pPage, pCell, &info); dbda8d6ce9 2007-07-21 drh: assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); dbda8d6ce9 2007-07-21 drh: if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ dbda8d6ce9 2007-07-21 drh: Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]); c287665ba8 2007-09-14 drh: rc = ptrmapPut(pPage->pBt, pgnoOvfl, PTRMAP_OVERFLOW1, pPage->pgno); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a list of cells to a page. The page should be initially empty. dbda8d6ce9 2007-07-21 drh: ** The cells are guaranteed to fit on the page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void assemblePage( dbda8d6ce9 2007-07-21 drh: MemPage *pPage, /* The page to be assemblied */ dbda8d6ce9 2007-07-21 drh: int nCell, /* The number of cells to add to this page */ dbda8d6ce9 2007-07-21 drh: u8 **apCell, /* Pointers to cell bodies */ dbda8d6ce9 2007-07-21 drh: int *aSize /* Sizes of the cells */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: int totalSize; /* Total size of all cells */ dbda8d6ce9 2007-07-21 drh: int hdr; /* Index of page header */ dbda8d6ce9 2007-07-21 drh: int cellptr; /* Address of next cell pointer */ dbda8d6ce9 2007-07-21 drh: int cellbody; /* Address of next cell body */ dbda8d6ce9 2007-07-21 drh: u8 *data; /* Data for the page */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPage->nOverflow==0 ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: totalSize = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCell; i++){ dbda8d6ce9 2007-07-21 drh: totalSize += aSize[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( totalSize+2*nCell<=pPage->nFree ); dbda8d6ce9 2007-07-21 drh: assert( pPage->nCell==0 ); dbda8d6ce9 2007-07-21 drh: cellptr = pPage->cellOffset; dbda8d6ce9 2007-07-21 drh: data = pPage->aData; dbda8d6ce9 2007-07-21 drh: hdr = pPage->hdrOffset; dbda8d6ce9 2007-07-21 drh: put2byte(&data[hdr+3], nCell); dbda8d6ce9 2007-07-21 drh: if( nCell ){ dbda8d6ce9 2007-07-21 drh: cellbody = allocateSpace(pPage, totalSize); dbda8d6ce9 2007-07-21 drh: assert( cellbody>0 ); dbda8d6ce9 2007-07-21 drh: assert( pPage->nFree >= 2*nCell ); dbda8d6ce9 2007-07-21 drh: pPage->nFree -= 2*nCell; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCell; i++){ dbda8d6ce9 2007-07-21 drh: put2byte(&data[cellptr], cellbody); dbda8d6ce9 2007-07-21 drh: memcpy(&data[cellbody], apCell[i], aSize[i]); dbda8d6ce9 2007-07-21 drh: cellptr += 2; dbda8d6ce9 2007-07-21 drh: cellbody += aSize[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( cellbody==pPage->pBt->usableSize ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPage->nCell = nCell; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following parameters determine how many adjacent pages get involved dbda8d6ce9 2007-07-21 drh: ** in a balancing operation. NN is the number of neighbors on either side dbda8d6ce9 2007-07-21 drh: ** of the page that participate in the balancing operation. NB is the dbda8d6ce9 2007-07-21 drh: ** total number of pages that participate, including the target page and dbda8d6ce9 2007-07-21 drh: ** NN neighbors on either side. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The minimum value of NN is 1 (of course). Increasing NN above 1 dbda8d6ce9 2007-07-21 drh: ** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance dbda8d6ce9 2007-07-21 drh: ** in exchange for a larger degradation in INSERT and UPDATE performance. dbda8d6ce9 2007-07-21 drh: ** The value of NN appears to give the best results overall. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define NN 1 /* Number of neighbors on either side of pPage */ dbda8d6ce9 2007-07-21 drh: #define NB (NN*2+1) /* Total pages involved in the balance */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward reference */ dbda8d6ce9 2007-07-21 drh: static int balance(MemPage*, int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_QUICKBALANCE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This version of balance() handles the common special case where dbda8d6ce9 2007-07-21 drh: ** a new entry is being inserted on the extreme right-end of the dbda8d6ce9 2007-07-21 drh: ** tree, in other words, when the new entry will become the largest dbda8d6ce9 2007-07-21 drh: ** entry in the tree. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Instead of trying balance the 3 right-most leaf pages, just add dbda8d6ce9 2007-07-21 drh: ** a new page to the right-hand side and put the one new entry in dbda8d6ce9 2007-07-21 drh: ** that page. This leaves the right side of the tree somewhat dbda8d6ce9 2007-07-21 drh: ** unbalanced. But odds are that we will be inserting new entries dbda8d6ce9 2007-07-21 drh: ** at the end soon afterwards so the nearly empty page will quickly dbda8d6ce9 2007-07-21 drh: ** fill up. On average. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pPage is the leaf page which is the right-most page in the tree. dbda8d6ce9 2007-07-21 drh: ** pParent is its parent. pPage must have a single overflow entry dbda8d6ce9 2007-07-21 drh: ** which is also the right-most entry on the page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int balance_quick(MemPage *pPage, MemPage *pParent){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: MemPage *pNew; dbda8d6ce9 2007-07-21 drh: Pgno pgnoNew; dbda8d6ce9 2007-07-21 drh: u8 *pCell; dbda8d6ce9 2007-07-21 drh: int szCell; dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: int parentIdx = pParent->nCell; /* pParent new divider cell index */ dbda8d6ce9 2007-07-21 drh: int parentSize; /* Size of new divider cell */ dbda8d6ce9 2007-07-21 drh: u8 parentCell[64]; /* Space for the new divider cell */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate a new page. Insert the overflow cell from pPage dbda8d6ce9 2007-07-21 drh: ** into it. Then remove the overflow cell from pPage. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCell = pPage->aOvfl[0].pCell; dbda8d6ce9 2007-07-21 drh: szCell = cellSizePtr(pPage, pCell); dbda8d6ce9 2007-07-21 drh: zeroPage(pNew, pPage->aData[0]); dbda8d6ce9 2007-07-21 drh: assemblePage(pNew, 1, &pCell, &szCell); dbda8d6ce9 2007-07-21 drh: pPage->nOverflow = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the parent of the newly allocated page to pParent. */ dbda8d6ce9 2007-07-21 drh: pNew->pParent = pParent; dbda8d6ce9 2007-07-21 drh: sqlite3PagerRef(pParent->pDbPage); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* pPage is currently the right-child of pParent. Change this dbda8d6ce9 2007-07-21 drh: ** so that the right-child is the new page allocated above and dbda8d6ce9 2007-07-21 drh: ** pPage is the next-to-right child. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPage->nCell>0 ); dbda8d6ce9 2007-07-21 drh: pCell = findCell(pPage, pPage->nCell-1); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pPage, pCell, &info); dbda8d6ce9 2007-07-21 drh: rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( parentSize<64 ); dbda8d6ce9 2007-07-21 drh: rc = insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: put4byte(findOverflowCell(pParent,parentIdx), pPage->pgno); dbda8d6ce9 2007-07-21 drh: put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* If this is an auto-vacuum database, update the pointer map dbda8d6ce9 2007-07-21 drh: ** with entries for the new page, and any pointer from the dbda8d6ce9 2007-07-21 drh: ** cell on the page to an overflow page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPutOvfl(pNew, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pNew); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Release the reference to the new page and balance the parent page, dbda8d6ce9 2007-07-21 drh: ** in case the divider cell inserted caused it to become overfull. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: releasePage(pNew); dbda8d6ce9 2007-07-21 drh: return balance(pParent, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_QUICKBALANCE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine redistributes Cells on pPage and up to NN*2 siblings dbda8d6ce9 2007-07-21 drh: ** of pPage so that all pages have about the same amount of free space. dbda8d6ce9 2007-07-21 drh: ** Usually NN siblings on either side of pPage is used in the balancing, dbda8d6ce9 2007-07-21 drh: ** though more siblings might come from one side if pPage is the first dbda8d6ce9 2007-07-21 drh: ** or last child of its parent. If pPage has fewer than 2*NN siblings dbda8d6ce9 2007-07-21 drh: ** (something which can only happen if pPage is the root page or a dbda8d6ce9 2007-07-21 drh: ** child of root) then all available siblings participate in the balancing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The number of siblings of pPage might be increased or decreased by one or dbda8d6ce9 2007-07-21 drh: ** two in an effort to keep pages nearly full but not over full. The root page dbda8d6ce9 2007-07-21 drh: ** is special and is allowed to be nearly empty. If pPage is dbda8d6ce9 2007-07-21 drh: ** the root page, then the depth of the tree might be increased dbda8d6ce9 2007-07-21 drh: ** or decreased by one, as necessary, to keep the root page from being dbda8d6ce9 2007-07-21 drh: ** overfull or completely empty. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that when this routine is called, some of the Cells on pPage dbda8d6ce9 2007-07-21 drh: ** might not actually be stored in pPage->aData[]. This can happen dbda8d6ce9 2007-07-21 drh: ** if the page is overfull. Part of the job of this routine is to dbda8d6ce9 2007-07-21 drh: ** make sure all Cells for pPage once again fit in pPage->aData[]. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the course of balancing the siblings of pPage, the parent of pPage dbda8d6ce9 2007-07-21 drh: ** might become overfull or underfull. If that happens, then this routine dbda8d6ce9 2007-07-21 drh: ** is called recursively on the parent. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If this routine fails for any reason, it might leave the database dbda8d6ce9 2007-07-21 drh: ** in a corrupted state. So if this routine fails, the database should dbda8d6ce9 2007-07-21 drh: ** be rolled back. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int balance_nonroot(MemPage *pPage){ dbda8d6ce9 2007-07-21 drh: MemPage *pParent; /* The parent of pPage */ dbda8d6ce9 2007-07-21 drh: BtShared *pBt; /* The whole database */ dbda8d6ce9 2007-07-21 drh: int nCell = 0; /* Number of cells in apCell[] */ dbda8d6ce9 2007-07-21 drh: int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ dbda8d6ce9 2007-07-21 drh: int nOld; /* Number of pages in apOld[] */ dbda8d6ce9 2007-07-21 drh: int nNew; /* Number of pages in apNew[] */ dbda8d6ce9 2007-07-21 drh: int nDiv; /* Number of cells in apDiv[] */ dbda8d6ce9 2007-07-21 drh: int i, j, k; /* Loop counters */ dbda8d6ce9 2007-07-21 drh: int idx; /* Index of pPage in pParent->aCell[] */ dbda8d6ce9 2007-07-21 drh: int nxDiv; /* Next divider slot in pParent->aCell[] */ dbda8d6ce9 2007-07-21 drh: int rc; /* The return code */ dbda8d6ce9 2007-07-21 drh: int leafCorrection; /* 4 if pPage is a leaf. 0 if not */ dbda8d6ce9 2007-07-21 drh: int leafData; /* True if pPage is a leaf of a LEAFDATA tree */ dbda8d6ce9 2007-07-21 drh: int usableSpace; /* Bytes in pPage beyond the header */ dbda8d6ce9 2007-07-21 drh: int pageFlags; /* Value of pPage->aData[0] */ dbda8d6ce9 2007-07-21 drh: int subtotal; /* Subtotal of bytes in cells on one page */ dbda8d6ce9 2007-07-21 drh: int iSpace = 0; /* First unused byte of aSpace[] */ dbda8d6ce9 2007-07-21 drh: MemPage *apOld[NB]; /* pPage and up to two siblings */ dbda8d6ce9 2007-07-21 drh: Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */ dbda8d6ce9 2007-07-21 drh: MemPage *apCopy[NB]; /* Private copies of apOld[] pages */ dbda8d6ce9 2007-07-21 drh: MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ dbda8d6ce9 2007-07-21 drh: Pgno pgnoNew[NB+2]; /* Page numbers for each page in apNew[] */ dbda8d6ce9 2007-07-21 drh: u8 *apDiv[NB]; /* Divider cells in pParent */ dbda8d6ce9 2007-07-21 drh: int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */ dbda8d6ce9 2007-07-21 drh: int szNew[NB+2]; /* Combined size of cells place on i-th page */ dbda8d6ce9 2007-07-21 drh: u8 **apCell = 0; /* All cells begin balanced */ dbda8d6ce9 2007-07-21 drh: int *szCell; /* Local size of all cells in apCell[] */ dbda8d6ce9 2007-07-21 drh: u8 *aCopy[NB]; /* Space for holding data of apCopy[] */ dbda8d6ce9 2007-07-21 drh: u8 *aSpace; /* Space to hold copies of dividers cells */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: u8 *aFrom = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the parent page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPage->isInit ); c287665ba8 2007-09-14 drh: assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 ); dbda8d6ce9 2007-07-21 drh: pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: pParent = pPage->pParent; dbda8d6ce9 2007-07-21 drh: assert( pParent ); dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=(rc = sqlite3PagerWrite(pParent->pDbPage)) ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_QUICKBALANCE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A special case: If a new entry has just been inserted into a dbda8d6ce9 2007-07-21 drh: ** table (that is, a btree with integer keys and all data at the leaves) dbda8d6ce9 2007-07-21 drh: ** and the new entry is the right-most entry in the tree (it has the dbda8d6ce9 2007-07-21 drh: ** largest key) then use the special balance_quick() routine for dbda8d6ce9 2007-07-21 drh: ** balancing. balance_quick() is much faster and results in a tighter dbda8d6ce9 2007-07-21 drh: ** packing of data in the common case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pPage->leaf && dbda8d6ce9 2007-07-21 drh: pPage->intKey && dbda8d6ce9 2007-07-21 drh: pPage->leafData && dbda8d6ce9 2007-07-21 drh: pPage->nOverflow==1 && dbda8d6ce9 2007-07-21 drh: pPage->aOvfl[0].idx==pPage->nCell && dbda8d6ce9 2007-07-21 drh: pPage->pParent->pgno!=1 && dbda8d6ce9 2007-07-21 drh: get4byte(&pParent->aData[pParent->hdrOffset+8])==pPage->pgno dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** TODO: Check the siblings to the left of pPage. It may be that dbda8d6ce9 2007-07-21 drh: ** they are not full and no new page is required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: return balance_quick(pPage, pParent); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( SQLITE_OK!=(rc = sqlite3PagerWrite(pPage->pDbPage)) ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the cell in the parent page whose left child points back dbda8d6ce9 2007-07-21 drh: ** to pPage. The "idx" variable is the index of that cell. If pPage dbda8d6ce9 2007-07-21 drh: ** is the rightmost child of pParent then set idx to pParent->nCell dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pParent->idxShift ){ dbda8d6ce9 2007-07-21 drh: Pgno pgno; dbda8d6ce9 2007-07-21 drh: pgno = pPage->pgno; dbda8d6ce9 2007-07-21 drh: assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); dbda8d6ce9 2007-07-21 drh: for(idx=0; idx<pParent->nCell; idx++){ dbda8d6ce9 2007-07-21 drh: if( get4byte(findCell(pParent, idx))==pgno ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( idx<pParent->nCell dbda8d6ce9 2007-07-21 drh: || get4byte(&pParent->aData[pParent->hdrOffset+8])==pgno ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: idx = pPage->idxParent; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Initialize variables so that it will be safe to jump dbda8d6ce9 2007-07-21 drh: ** directly to balance_cleanup at any moment. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nOld = nNew = 0; dbda8d6ce9 2007-07-21 drh: sqlite3PagerRef(pParent->pDbPage); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find sibling pages to pPage and the cells in pParent that divide dbda8d6ce9 2007-07-21 drh: ** the siblings. An attempt is made to find NN siblings on either dbda8d6ce9 2007-07-21 drh: ** side of pPage. More siblings are taken from one side, however, if dbda8d6ce9 2007-07-21 drh: ** pPage there are fewer than NN siblings on the other side. If pParent dbda8d6ce9 2007-07-21 drh: ** has NB or fewer children then all children of pParent are taken. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nxDiv = idx - NN; dbda8d6ce9 2007-07-21 drh: if( nxDiv + NB > pParent->nCell ){ dbda8d6ce9 2007-07-21 drh: nxDiv = pParent->nCell - NB + 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nxDiv<0 ){ dbda8d6ce9 2007-07-21 drh: nxDiv = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nDiv = 0; dbda8d6ce9 2007-07-21 drh: for(i=0, k=nxDiv; i<NB; i++, k++){ dbda8d6ce9 2007-07-21 drh: if( k<pParent->nCell ){ dbda8d6ce9 2007-07-21 drh: apDiv[i] = findCell(pParent, k); dbda8d6ce9 2007-07-21 drh: nDiv++; dbda8d6ce9 2007-07-21 drh: assert( !pParent->leaf ); dbda8d6ce9 2007-07-21 drh: pgnoOld[i] = get4byte(apDiv[i]); dbda8d6ce9 2007-07-21 drh: }else if( k==pParent->nCell ){ dbda8d6ce9 2007-07-21 drh: pgnoOld[i] = get4byte(&pParent->aData[pParent->hdrOffset+8]); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = getAndInitPage(pBt, pgnoOld[i], &apOld[i], pParent); dbda8d6ce9 2007-07-21 drh: if( rc ) goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: apOld[i]->idxParent = k; dbda8d6ce9 2007-07-21 drh: apCopy[i] = 0; dbda8d6ce9 2007-07-21 drh: assert( i==nOld ); dbda8d6ce9 2007-07-21 drh: nOld++; dbda8d6ce9 2007-07-21 drh: nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make nMaxCells a multiple of 2 in order to preserve 8-byte dbda8d6ce9 2007-07-21 drh: ** alignment */ dbda8d6ce9 2007-07-21 drh: nMaxCells = (nMaxCells + 1)&~1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate space for memory structures dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: apCell = sqlite3_malloc( dbda8d6ce9 2007-07-21 drh: nMaxCells*sizeof(u8*) /* apCell */ dbda8d6ce9 2007-07-21 drh: + nMaxCells*sizeof(int) /* szCell */ dbda8d6ce9 2007-07-21 drh: + ROUND8(sizeof(MemPage))*NB /* aCopy */ dbda8d6ce9 2007-07-21 drh: + pBt->pageSize*(5+NB) /* aSpace */ dbda8d6ce9 2007-07-21 drh: + (ISAUTOVACUUM ? nMaxCells : 0) /* aFrom */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( apCell==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: szCell = (int*)&apCell[nMaxCells]; dbda8d6ce9 2007-07-21 drh: aCopy[0] = (u8*)&szCell[nMaxCells]; dbda8d6ce9 2007-07-21 drh: assert( ((aCopy[0] - (u8*)apCell) & 7)==0 ); /* 8-byte alignment required */ dbda8d6ce9 2007-07-21 drh: for(i=1; i<NB; i++){ dbda8d6ce9 2007-07-21 drh: aCopy[i] = &aCopy[i-1][pBt->pageSize+ROUND8(sizeof(MemPage))]; dbda8d6ce9 2007-07-21 drh: assert( ((aCopy[i] - (u8*)apCell) & 7)==0 ); /* 8-byte alignment required */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: aSpace = &aCopy[NB-1][pBt->pageSize+ROUND8(sizeof(MemPage))]; dbda8d6ce9 2007-07-21 drh: assert( ((aSpace - (u8*)apCell) & 7)==0 ); /* 8-byte alignment required */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: aFrom = &aSpace[5*pBt->pageSize]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make copies of the content of pPage and its siblings into aOld[]. dbda8d6ce9 2007-07-21 drh: ** The rest of this function will use data from the copies rather dbda8d6ce9 2007-07-21 drh: ** that the original pages since the original pages will be in the dbda8d6ce9 2007-07-21 drh: ** process of being overwritten. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nOld; i++){ c287665ba8 2007-09-14 drh: MemPage *p = apCopy[i] = (MemPage*)aCopy[i]; c287665ba8 2007-09-14 drh: memcpy(p, apOld[i], sizeof(MemPage)); c287665ba8 2007-09-14 drh: p->aData = (void*)&p[1]; c287665ba8 2007-09-14 drh: memcpy(p->aData, apOld[i]->aData, pBt->pageSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Load pointers to all cells on sibling pages and the divider cells dbda8d6ce9 2007-07-21 drh: ** into the local apCell[] array. Make copies of the divider cells dbda8d6ce9 2007-07-21 drh: ** into space obtained form aSpace[] and remove the the divider Cells dbda8d6ce9 2007-07-21 drh: ** from pParent. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the siblings are on leaf pages, then the child pointers of the dbda8d6ce9 2007-07-21 drh: ** divider cells are stripped from the cells before they are copied dbda8d6ce9 2007-07-21 drh: ** into aSpace[]. In this way, all cells in apCell[] are without dbda8d6ce9 2007-07-21 drh: ** child pointers. If siblings are not leaves, then all cell in dbda8d6ce9 2007-07-21 drh: ** apCell[] include child pointers. Either way, all cells in apCell[] dbda8d6ce9 2007-07-21 drh: ** are alike. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** leafCorrection: 4 if pPage is a leaf. 0 if pPage is not a leaf. dbda8d6ce9 2007-07-21 drh: ** leafData: 1 if pPage holds key+data and pParent holds only keys. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nCell = 0; dbda8d6ce9 2007-07-21 drh: leafCorrection = pPage->leaf*4; dbda8d6ce9 2007-07-21 drh: leafData = pPage->leafData && pPage->leaf; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nOld; i++){ dbda8d6ce9 2007-07-21 drh: MemPage *pOld = apCopy[i]; dbda8d6ce9 2007-07-21 drh: int limit = pOld->nCell+pOld->nOverflow; dbda8d6ce9 2007-07-21 drh: for(j=0; j<limit; j++){ dbda8d6ce9 2007-07-21 drh: assert( nCell<nMaxCells ); dbda8d6ce9 2007-07-21 drh: apCell[nCell] = findOverflowCell(pOld, j); dbda8d6ce9 2007-07-21 drh: szCell[nCell] = cellSizePtr(pOld, apCell[nCell]); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: int a; dbda8d6ce9 2007-07-21 drh: aFrom[nCell] = i; dbda8d6ce9 2007-07-21 drh: for(a=0; a<pOld->nOverflow; a++){ dbda8d6ce9 2007-07-21 drh: if( pOld->aOvfl[a].pCell==apCell[nCell] ){ dbda8d6ce9 2007-07-21 drh: aFrom[nCell] = 0xFF; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: nCell++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<nOld-1 ){ dbda8d6ce9 2007-07-21 drh: int sz = cellSizePtr(pParent, apDiv[i]); dbda8d6ce9 2007-07-21 drh: if( leafData ){ dbda8d6ce9 2007-07-21 drh: /* With the LEAFDATA flag, pParent cells hold only INTKEYs that dbda8d6ce9 2007-07-21 drh: ** are duplicates of keys on the child pages. We need to remove dbda8d6ce9 2007-07-21 drh: ** the divider cells from pParent, but the dividers cells are not dbda8d6ce9 2007-07-21 drh: ** added to apCell[] because they are duplicates of child cells. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dropCell(pParent, nxDiv, sz); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: u8 *pTemp; dbda8d6ce9 2007-07-21 drh: assert( nCell<nMaxCells ); dbda8d6ce9 2007-07-21 drh: szCell[nCell] = sz; dbda8d6ce9 2007-07-21 drh: pTemp = &aSpace[iSpace]; dbda8d6ce9 2007-07-21 drh: iSpace += sz; dbda8d6ce9 2007-07-21 drh: assert( iSpace<=pBt->pageSize*5 ); dbda8d6ce9 2007-07-21 drh: memcpy(pTemp, apDiv[i], sz); dbda8d6ce9 2007-07-21 drh: apCell[nCell] = pTemp+leafCorrection; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: aFrom[nCell] = 0xFF; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dropCell(pParent, nxDiv, sz); dbda8d6ce9 2007-07-21 drh: szCell[nCell] -= leafCorrection; dbda8d6ce9 2007-07-21 drh: assert( get4byte(pTemp)==pgnoOld[i] ); dbda8d6ce9 2007-07-21 drh: if( !pOld->leaf ){ dbda8d6ce9 2007-07-21 drh: assert( leafCorrection==0 ); dbda8d6ce9 2007-07-21 drh: /* The right pointer of the child page pOld becomes the left dbda8d6ce9 2007-07-21 drh: ** pointer of the divider cell */ dbda8d6ce9 2007-07-21 drh: memcpy(apCell[nCell], &pOld->aData[pOld->hdrOffset+8], 4); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( leafCorrection==4 ); dbda8d6ce9 2007-07-21 drh: if( szCell[nCell]<4 ){ dbda8d6ce9 2007-07-21 drh: /* Do not allow any cells smaller than 4 bytes. */ dbda8d6ce9 2007-07-21 drh: szCell[nCell] = 4; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nCell++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Figure out the number of pages needed to hold all nCell cells. dbda8d6ce9 2007-07-21 drh: ** Store this number in "k". Also compute szNew[] which is the total dbda8d6ce9 2007-07-21 drh: ** size of all cells on the i-th page and cntNew[] which is the index dbda8d6ce9 2007-07-21 drh: ** in apCell[] of the cell that divides page i from page i+1. dbda8d6ce9 2007-07-21 drh: ** cntNew[k] should equal nCell. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Values computed by this block: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** k: The total number of sibling pages dbda8d6ce9 2007-07-21 drh: ** szNew[i]: Spaced used on the i-th sibling page. dbda8d6ce9 2007-07-21 drh: ** cntNew[i]: Index in apCell[] and szCell[] for the first cell to dbda8d6ce9 2007-07-21 drh: ** the right of the i-th sibling page. dbda8d6ce9 2007-07-21 drh: ** usableSpace: Number of bytes of space available on each sibling. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: usableSpace = pBt->usableSize - 12 + leafCorrection; dbda8d6ce9 2007-07-21 drh: for(subtotal=k=i=0; i<nCell; i++){ dbda8d6ce9 2007-07-21 drh: assert( i<nMaxCells ); dbda8d6ce9 2007-07-21 drh: subtotal += szCell[i] + 2; dbda8d6ce9 2007-07-21 drh: if( subtotal > usableSpace ){ dbda8d6ce9 2007-07-21 drh: szNew[k] = subtotal - szCell[i]; dbda8d6ce9 2007-07-21 drh: cntNew[k] = i; dbda8d6ce9 2007-07-21 drh: if( leafData ){ i--; } dbda8d6ce9 2007-07-21 drh: subtotal = 0; dbda8d6ce9 2007-07-21 drh: k++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: szNew[k] = subtotal; dbda8d6ce9 2007-07-21 drh: cntNew[k] = nCell; dbda8d6ce9 2007-07-21 drh: k++; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The packing computed by the previous block is biased toward the siblings dbda8d6ce9 2007-07-21 drh: ** on the left side. The left siblings are always nearly full, while the dbda8d6ce9 2007-07-21 drh: ** right-most sibling might be nearly empty. This block of code attempts dbda8d6ce9 2007-07-21 drh: ** to adjust the packing of siblings to get a better balance. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This adjustment is more than an optimization. The packing above might dbda8d6ce9 2007-07-21 drh: ** be so out of balance as to be illegal. For example, the right-most dbda8d6ce9 2007-07-21 drh: ** sibling might be completely empty. This adjustment is not optional. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=k-1; i>0; i--){ dbda8d6ce9 2007-07-21 drh: int szRight = szNew[i]; /* Size of sibling on the right */ dbda8d6ce9 2007-07-21 drh: int szLeft = szNew[i-1]; /* Size of sibling on the left */ dbda8d6ce9 2007-07-21 drh: int r; /* Index of right-most cell in left sibling */ dbda8d6ce9 2007-07-21 drh: int d; /* Index of first cell to the left of right sibling */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: r = cntNew[i-1] - 1; dbda8d6ce9 2007-07-21 drh: d = r + 1 - leafData; dbda8d6ce9 2007-07-21 drh: assert( d<nMaxCells ); dbda8d6ce9 2007-07-21 drh: assert( r<nMaxCells ); dbda8d6ce9 2007-07-21 drh: while( szRight==0 || szRight+szCell[d]+2<=szLeft-(szCell[r]+2) ){ dbda8d6ce9 2007-07-21 drh: szRight += szCell[d] + 2; dbda8d6ce9 2007-07-21 drh: szLeft -= szCell[r] + 2; dbda8d6ce9 2007-07-21 drh: cntNew[i-1]--; dbda8d6ce9 2007-07-21 drh: r = cntNew[i-1] - 1; dbda8d6ce9 2007-07-21 drh: d = r + 1 - leafData; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: szNew[i] = szRight; dbda8d6ce9 2007-07-21 drh: szNew[i-1] = szLeft; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Either we found one or more cells (cntnew[0])>0) or we are the dbda8d6ce9 2007-07-21 drh: ** a virtual root page. A virtual root page is when the real root dbda8d6ce9 2007-07-21 drh: ** page is page 1 and we are the only child of that page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate k new pages. Reuse old pages where possible. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pPage->pgno>1 ); dbda8d6ce9 2007-07-21 drh: pageFlags = pPage->aData[0]; dbda8d6ce9 2007-07-21 drh: for(i=0; i<k; i++){ dbda8d6ce9 2007-07-21 drh: MemPage *pNew; dbda8d6ce9 2007-07-21 drh: if( i<nOld ){ dbda8d6ce9 2007-07-21 drh: pNew = apNew[i] = apOld[i]; dbda8d6ce9 2007-07-21 drh: pgnoNew[i] = pgnoOld[i]; dbda8d6ce9 2007-07-21 drh: apOld[i] = 0; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pNew->pDbPage); dbda8d6ce9 2007-07-21 drh: nNew++; dbda8d6ce9 2007-07-21 drh: if( rc ) goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( i>0 ); dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0); dbda8d6ce9 2007-07-21 drh: if( rc ) goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: apNew[i] = pNew; dbda8d6ce9 2007-07-21 drh: nNew++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zeroPage(pNew, pageFlags); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Free any old pages that were not reused as new pages. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: while( i<nOld ){ dbda8d6ce9 2007-07-21 drh: rc = freePage(apOld[i]); dbda8d6ce9 2007-07-21 drh: if( rc ) goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: releasePage(apOld[i]); dbda8d6ce9 2007-07-21 drh: apOld[i] = 0; dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Put the new pages in accending order. This helps to dbda8d6ce9 2007-07-21 drh: ** keep entries in the disk file in order so that a scan dbda8d6ce9 2007-07-21 drh: ** of the table is a linear scan through the file. That dbda8d6ce9 2007-07-21 drh: ** in turn helps the operating system to deliver pages dbda8d6ce9 2007-07-21 drh: ** from the disk more rapidly. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An O(n^2) insertion sort algorithm is used, but since dbda8d6ce9 2007-07-21 drh: ** n is never more than NB (a small constant), that should dbda8d6ce9 2007-07-21 drh: ** not be a problem. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When NB==3, this one optimization makes the database dbda8d6ce9 2007-07-21 drh: ** about 25% faster for large insertions and deletions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<k-1; i++){ dbda8d6ce9 2007-07-21 drh: int minV = pgnoNew[i]; dbda8d6ce9 2007-07-21 drh: int minI = i; dbda8d6ce9 2007-07-21 drh: for(j=i+1; j<k; j++){ dbda8d6ce9 2007-07-21 drh: if( pgnoNew[j]<(unsigned)minV ){ dbda8d6ce9 2007-07-21 drh: minI = j; dbda8d6ce9 2007-07-21 drh: minV = pgnoNew[j]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( minI>i ){ dbda8d6ce9 2007-07-21 drh: int t; dbda8d6ce9 2007-07-21 drh: MemPage *pT; dbda8d6ce9 2007-07-21 drh: t = pgnoNew[i]; dbda8d6ce9 2007-07-21 drh: pT = apNew[i]; dbda8d6ce9 2007-07-21 drh: pgnoNew[i] = pgnoNew[minI]; dbda8d6ce9 2007-07-21 drh: apNew[i] = apNew[minI]; dbda8d6ce9 2007-07-21 drh: pgnoNew[minI] = t; dbda8d6ce9 2007-07-21 drh: apNew[minI] = pT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: TRACE(("BALANCE: old: %d %d %d new: %d(%d) %d(%d) %d(%d) %d(%d) %d(%d)\n", dbda8d6ce9 2007-07-21 drh: pgnoOld[0], dbda8d6ce9 2007-07-21 drh: nOld>=2 ? pgnoOld[1] : 0, dbda8d6ce9 2007-07-21 drh: nOld>=3 ? pgnoOld[2] : 0, dbda8d6ce9 2007-07-21 drh: pgnoNew[0], szNew[0], dbda8d6ce9 2007-07-21 drh: nNew>=2 ? pgnoNew[1] : 0, nNew>=2 ? szNew[1] : 0, dbda8d6ce9 2007-07-21 drh: nNew>=3 ? pgnoNew[2] : 0, nNew>=3 ? szNew[2] : 0, dbda8d6ce9 2007-07-21 drh: nNew>=4 ? pgnoNew[3] : 0, nNew>=4 ? szNew[3] : 0, dbda8d6ce9 2007-07-21 drh: nNew>=5 ? pgnoNew[4] : 0, nNew>=5 ? szNew[4] : 0)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Evenly distribute the data in apCell[] across the new pages. dbda8d6ce9 2007-07-21 drh: ** Insert divider cells into pParent as necessary. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: j = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nNew; i++){ dbda8d6ce9 2007-07-21 drh: /* Assemble the new sibling page. */ dbda8d6ce9 2007-07-21 drh: MemPage *pNew = apNew[i]; dbda8d6ce9 2007-07-21 drh: assert( j<nMaxCells ); dbda8d6ce9 2007-07-21 drh: assert( pNew->pgno==pgnoNew[i] ); dbda8d6ce9 2007-07-21 drh: assemblePage(pNew, cntNew[i]-j, &apCell[j], &szCell[j]); dbda8d6ce9 2007-07-21 drh: assert( pNew->nCell>0 || (nNew==1 && cntNew[0]==0) ); dbda8d6ce9 2007-07-21 drh: assert( pNew->nOverflow==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* If this is an auto-vacuum database, update the pointer map entries dbda8d6ce9 2007-07-21 drh: ** that point to the siblings that were rearranged. These can be: left dbda8d6ce9 2007-07-21 drh: ** children of cells, the right-child of the page, or overflow pages dbda8d6ce9 2007-07-21 drh: ** pointed to by cells. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: for(k=j; k<cntNew[i]; k++){ dbda8d6ce9 2007-07-21 drh: assert( k<nMaxCells ); dbda8d6ce9 2007-07-21 drh: if( aFrom[k]==0xFF || apCopy[aFrom[k]]->pgno!=pNew->pgno ){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPutOvfl(pNew, k-j); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: j = cntNew[i]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the sibling page assembled above was not the right-most sibling, dbda8d6ce9 2007-07-21 drh: ** insert a divider cell into the parent page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( i<nNew-1 && j<nCell ){ dbda8d6ce9 2007-07-21 drh: u8 *pCell; dbda8d6ce9 2007-07-21 drh: u8 *pTemp; dbda8d6ce9 2007-07-21 drh: int sz; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( j<nMaxCells ); dbda8d6ce9 2007-07-21 drh: pCell = apCell[j]; dbda8d6ce9 2007-07-21 drh: sz = szCell[j] + leafCorrection; dbda8d6ce9 2007-07-21 drh: if( !pNew->leaf ){ dbda8d6ce9 2007-07-21 drh: memcpy(&pNew->aData[8], pCell, 4); dbda8d6ce9 2007-07-21 drh: pTemp = 0; dbda8d6ce9 2007-07-21 drh: }else if( leafData ){ c287665ba8 2007-09-14 drh: /* If the tree is a leaf-data tree, and the siblings are leaves, dbda8d6ce9 2007-07-21 drh: ** then there is no divider cell in apCell[]. Instead, the divider dbda8d6ce9 2007-07-21 drh: ** cell consists of the integer key for the right-most cell of dbda8d6ce9 2007-07-21 drh: ** the sibling-page assembled above only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: j--; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pNew, apCell[j], &info); dbda8d6ce9 2007-07-21 drh: pCell = &aSpace[iSpace]; dbda8d6ce9 2007-07-21 drh: fillInCell(pParent, pCell, 0, info.nKey, 0, 0, 0, &sz); dbda8d6ce9 2007-07-21 drh: iSpace += sz; dbda8d6ce9 2007-07-21 drh: assert( iSpace<=pBt->pageSize*5 ); dbda8d6ce9 2007-07-21 drh: pTemp = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pCell -= 4; dbda8d6ce9 2007-07-21 drh: pTemp = &aSpace[iSpace]; dbda8d6ce9 2007-07-21 drh: iSpace += sz; dbda8d6ce9 2007-07-21 drh: assert( iSpace<=pBt->pageSize*5 ); dbda8d6ce9 2007-07-21 drh: /* Obscure case for non-leaf-data trees: If the cell at pCell was dbda8d6ce9 2007-07-21 drh: ** previously stored on a leaf node, and it's reported size was 4 dbda8d6ce9 2007-07-21 drh: ** bytes, then it may actually be smaller than this dbda8d6ce9 2007-07-21 drh: ** (see sqlite3BtreeParseCellPtr(), 4 bytes is the minimum size of dbda8d6ce9 2007-07-21 drh: ** any cell). But it's important to pass the correct size to dbda8d6ce9 2007-07-21 drh: ** insertCell(), so reparse the cell now. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that this can never happen in an SQLite data file, as all dbda8d6ce9 2007-07-21 drh: ** cells are at least 4 bytes. It only happens in b-trees used dbda8d6ce9 2007-07-21 drh: ** to evaluate "IN (SELECT ...)" and similar clauses. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( szCell[j]==4 ){ dbda8d6ce9 2007-07-21 drh: assert(leafCorrection==4); dbda8d6ce9 2007-07-21 drh: sz = cellSizePtr(pParent, pCell); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = insertCell(pParent, nxDiv, pCell, sz, pTemp, 4); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: put4byte(findOverflowCell(pParent,nxDiv), pNew->pgno); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* If this is an auto-vacuum database, and not a leaf-data tree, dbda8d6ce9 2007-07-21 drh: ** then update the pointer map with an entry for the overflow page dbda8d6ce9 2007-07-21 drh: ** that the cell just inserted points to (if any). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum && !leafData ){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPutOvfl(pParent, nxDiv); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: j++; dbda8d6ce9 2007-07-21 drh: nxDiv++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( j==nCell ); dbda8d6ce9 2007-07-21 drh: assert( nOld>0 ); dbda8d6ce9 2007-07-21 drh: assert( nNew>0 ); dbda8d6ce9 2007-07-21 drh: if( (pageFlags & PTF_LEAF)==0 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&apNew[nNew-1]->aData[8], &apCopy[nOld-1]->aData[8], 4); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nxDiv==pParent->nCell+pParent->nOverflow ){ dbda8d6ce9 2007-07-21 drh: /* Right-most sibling is the right-most child of pParent */ dbda8d6ce9 2007-07-21 drh: put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew[nNew-1]); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Right-most sibling is the left child of the first entry in pParent dbda8d6ce9 2007-07-21 drh: ** past the right-most divider entry */ dbda8d6ce9 2007-07-21 drh: put4byte(findOverflowCell(pParent, nxDiv), pgnoNew[nNew-1]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Reparent children of all cells. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nNew; i++){ dbda8d6ce9 2007-07-21 drh: rc = reparentChildPages(apNew[i]); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = reparentChildPages(pParent); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto balance_cleanup; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Balance the parent page. Note that the current page (pPage) might dbda8d6ce9 2007-07-21 drh: ** have been added to the freelist so it might no longer be initialized. dbda8d6ce9 2007-07-21 drh: ** But the parent page will always be initialized. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pParent->isInit ); dbda8d6ce9 2007-07-21 drh: rc = balance(pParent, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Cleanup before returning. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: balance_cleanup: c287665ba8 2007-09-14 drh: sqlite3_free(apCell); dbda8d6ce9 2007-07-21 drh: for(i=0; i<nOld; i++){ dbda8d6ce9 2007-07-21 drh: releasePage(apOld[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<nNew; i++){ dbda8d6ce9 2007-07-21 drh: releasePage(apNew[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releasePage(pParent); dbda8d6ce9 2007-07-21 drh: TRACE(("BALANCE: finished with %d: old=%d new=%d cells=%d\n", dbda8d6ce9 2007-07-21 drh: pPage->pgno, nOld, nNew, nCell)); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called for the root page of a btree when the root dbda8d6ce9 2007-07-21 drh: ** page contains no cells. This is an opportunity to make the tree dbda8d6ce9 2007-07-21 drh: ** shallower by one level. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int balance_shallower(MemPage *pPage){ dbda8d6ce9 2007-07-21 drh: MemPage *pChild; /* The only child page of pPage */ dbda8d6ce9 2007-07-21 drh: Pgno pgnoChild; /* Page number for pChild */ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; /* Return code from subprocedures */ dbda8d6ce9 2007-07-21 drh: BtShared *pBt; /* The main BTree structure */ dbda8d6ce9 2007-07-21 drh: int mxCellPerPage; /* Maximum number of cells per page */ dbda8d6ce9 2007-07-21 drh: u8 **apCell; /* All cells from pages being balanced */ dbda8d6ce9 2007-07-21 drh: int *szCell; /* Local size of all cells */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPage->pParent==0 ); dbda8d6ce9 2007-07-21 drh: assert( pPage->nCell==0 ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: pBt = pPage->pBt; dbda8d6ce9 2007-07-21 drh: mxCellPerPage = MX_CELL(pBt); c287665ba8 2007-09-14 drh: apCell = sqlite3_malloc( mxCellPerPage*(sizeof(u8*)+sizeof(int)) ); dbda8d6ce9 2007-07-21 drh: if( apCell==0 ) return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: szCell = (int*)&apCell[mxCellPerPage]; dbda8d6ce9 2007-07-21 drh: if( pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: /* The table is completely empty */ dbda8d6ce9 2007-07-21 drh: TRACE(("BALANCE: empty table %d\n", pPage->pgno)); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The root page is empty but has one child. Transfer the dbda8d6ce9 2007-07-21 drh: ** information from that one child into the root page if it dbda8d6ce9 2007-07-21 drh: ** will fit. This reduces the depth of the tree by one. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the root page is page 1, it has less space available than dbda8d6ce9 2007-07-21 drh: ** its child (due to the 100 byte header that occurs at the beginning dbda8d6ce9 2007-07-21 drh: ** of the database fle), so it might not be able to hold all of the dbda8d6ce9 2007-07-21 drh: ** information currently contained in the child. If this is the dbda8d6ce9 2007-07-21 drh: ** case, then do not do the transfer. Leave page 1 empty except dbda8d6ce9 2007-07-21 drh: ** for the right-pointer to the child page. The child page becomes dbda8d6ce9 2007-07-21 drh: ** the virtual root of the tree. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]); dbda8d6ce9 2007-07-21 drh: assert( pgnoChild>0 ); dbda8d6ce9 2007-07-21 drh: assert( pgnoChild<=sqlite3PagerPagecount(pPage->pBt->pPager) ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pPage->pBt, pgnoChild, &pChild, 0); dbda8d6ce9 2007-07-21 drh: if( rc ) goto end_shallow_balance; dbda8d6ce9 2007-07-21 drh: if( pPage->pgno==1 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeInitPage(pChild, pPage); dbda8d6ce9 2007-07-21 drh: if( rc ) goto end_shallow_balance; dbda8d6ce9 2007-07-21 drh: assert( pChild->nOverflow==0 ); dbda8d6ce9 2007-07-21 drh: if( pChild->nFree>=100 ){ dbda8d6ce9 2007-07-21 drh: /* The child information will fit on the root page, so do the dbda8d6ce9 2007-07-21 drh: ** copy */ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: zeroPage(pPage, pChild->aData[0]); dbda8d6ce9 2007-07-21 drh: for(i=0; i<pChild->nCell; i++){ dbda8d6ce9 2007-07-21 drh: apCell[i] = findCell(pChild,i); dbda8d6ce9 2007-07-21 drh: szCell[i] = cellSizePtr(pChild, apCell[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assemblePage(pPage, pChild->nCell, apCell, szCell); dbda8d6ce9 2007-07-21 drh: /* Copy the right-pointer of the child to the parent. */ dbda8d6ce9 2007-07-21 drh: put4byte(&pPage->aData[pPage->hdrOffset+8], dbda8d6ce9 2007-07-21 drh: get4byte(&pChild->aData[pChild->hdrOffset+8])); dbda8d6ce9 2007-07-21 drh: freePage(pChild); dbda8d6ce9 2007-07-21 drh: TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno)); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The child has more information that will fit on the root. dbda8d6ce9 2007-07-21 drh: ** The tree is already balanced. Do nothing. */ dbda8d6ce9 2007-07-21 drh: TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize); dbda8d6ce9 2007-07-21 drh: pPage->isInit = 0; dbda8d6ce9 2007-07-21 drh: pPage->pParent = 0; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeInitPage(pPage, 0); dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_OK ); dbda8d6ce9 2007-07-21 drh: freePage(pChild); dbda8d6ce9 2007-07-21 drh: TRACE(("BALANCE: transfer child %d into root %d\n", dbda8d6ce9 2007-07-21 drh: pChild->pgno, pPage->pgno)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = reparentChildPages(pPage); dbda8d6ce9 2007-07-21 drh: assert( pPage->nOverflow==0 ); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pPage->nCell; i++){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPutOvfl(pPage, i); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto end_shallow_balance; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: releasePage(pChild); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: end_shallow_balance: c287665ba8 2007-09-14 drh: sqlite3_free(apCell); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The root page is overfull dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When this happens, Create a new child page and copy the dbda8d6ce9 2007-07-21 drh: ** contents of the root into the child. Then make the root dbda8d6ce9 2007-07-21 drh: ** page an empty page with rightChild pointing to the new dbda8d6ce9 2007-07-21 drh: ** child. Finally, call balance_internal() on the new child dbda8d6ce9 2007-07-21 drh: ** to cause it to split. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int balance_deeper(MemPage *pPage){ dbda8d6ce9 2007-07-21 drh: int rc; /* Return value from subprocedures */ dbda8d6ce9 2007-07-21 drh: MemPage *pChild; /* Pointer to a new child page */ dbda8d6ce9 2007-07-21 drh: Pgno pgnoChild; /* Page number of the new child page */ dbda8d6ce9 2007-07-21 drh: BtShared *pBt; /* The BTree */ dbda8d6ce9 2007-07-21 drh: int usableSize; /* Total usable size of a page */ dbda8d6ce9 2007-07-21 drh: u8 *data; /* Content of the parent page */ dbda8d6ce9 2007-07-21 drh: u8 *cdata; /* Content of the child page */ dbda8d6ce9 2007-07-21 drh: int hdr; /* Offset to page header in parent */ dbda8d6ce9 2007-07-21 drh: int brk; /* Offset to content of first cell in parent */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pPage->pParent==0 ); dbda8d6ce9 2007-07-21 drh: assert( pPage->nOverflow>0 ); dbda8d6ce9 2007-07-21 drh: pBt = pPage->pBt; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pChild, &pgnoChild, pPage->pgno, 0); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: assert( sqlite3PagerIswriteable(pChild->pDbPage) ); dbda8d6ce9 2007-07-21 drh: usableSize = pBt->usableSize; dbda8d6ce9 2007-07-21 drh: data = pPage->aData; dbda8d6ce9 2007-07-21 drh: hdr = pPage->hdrOffset; dbda8d6ce9 2007-07-21 drh: brk = get2byte(&data[hdr+5]); dbda8d6ce9 2007-07-21 drh: cdata = pChild->aData; dbda8d6ce9 2007-07-21 drh: memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr); dbda8d6ce9 2007-07-21 drh: memcpy(&cdata[brk], &data[brk], usableSize-brk); dbda8d6ce9 2007-07-21 drh: assert( pChild->isInit==0 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeInitPage(pChild, pPage); dbda8d6ce9 2007-07-21 drh: if( rc ) goto balancedeeper_out; dbda8d6ce9 2007-07-21 drh: memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0])); dbda8d6ce9 2007-07-21 drh: pChild->nOverflow = pPage->nOverflow; dbda8d6ce9 2007-07-21 drh: if( pChild->nOverflow ){ dbda8d6ce9 2007-07-21 drh: pChild->nFree = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pChild->nCell==pPage->nCell ); dbda8d6ce9 2007-07-21 drh: zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF); dbda8d6ce9 2007-07-21 drh: put4byte(&pPage->aData[pPage->hdrOffset+8], pgnoChild); dbda8d6ce9 2007-07-21 drh: TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno)); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, pChild->pgno, PTRMAP_BTREE, pPage->pgno); dbda8d6ce9 2007-07-21 drh: if( rc ) goto balancedeeper_out; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pChild->nCell; i++){ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPutOvfl(pChild, i); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: rc = balance_nonroot(pChild); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: balancedeeper_out: dbda8d6ce9 2007-07-21 drh: releasePage(pChild); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Decide if the page pPage needs to be balanced. If balancing is dbda8d6ce9 2007-07-21 drh: ** required, call the appropriate balancing routine. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int balance(MemPage *pPage, int insert){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pPage->pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pPage->pParent==0 ){ c287665ba8 2007-09-14 drh: rc = sqlite3PagerWrite(pPage->pDbPage); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK && pPage->nOverflow>0 ){ dbda8d6ce9 2007-07-21 drh: rc = balance_deeper(pPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && pPage->nCell==0 ){ dbda8d6ce9 2007-07-21 drh: rc = balance_shallower(pPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( pPage->nOverflow>0 || dbda8d6ce9 2007-07-21 drh: (!insert && pPage->nFree>pPage->pBt->usableSize*2/3) ){ dbda8d6ce9 2007-07-21 drh: rc = balance_nonroot(pPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine checks all cursors that point to table pgnoRoot. dbda8d6ce9 2007-07-21 drh: ** If any of those cursors were opened with wrFlag==0 in a different dbda8d6ce9 2007-07-21 drh: ** database connection (a database connection that shares the pager dbda8d6ce9 2007-07-21 drh: ** cache with the current connection) and that other connection dbda8d6ce9 2007-07-21 drh: ** is not in the ReadUncommmitted state, then this routine returns dbda8d6ce9 2007-07-21 drh: ** SQLITE_LOCKED. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In addition to checking for read-locks (where a read-lock dbda8d6ce9 2007-07-21 drh: ** means a cursor opened with wrFlag==0) this routine also moves dbda8d6ce9 2007-07-21 drh: ** all write cursors so that they are pointing to the dbda8d6ce9 2007-07-21 drh: ** first Cell on the root page. This is necessary because an insert dbda8d6ce9 2007-07-21 drh: ** or delete might change the number of cells on a page or delete dbda8d6ce9 2007-07-21 drh: ** a page entirely and we do not want to leave any cursors dbda8d6ce9 2007-07-21 drh: ** pointing to non-existant pages or cells. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int checkReadLocks(Btree *pBtree, Pgno pgnoRoot, BtCursor *pExclude){ dbda8d6ce9 2007-07-21 drh: BtCursor *p; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = pBtree->pBt; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pBtree->pSqlite; c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(pBtree) ); dbda8d6ce9 2007-07-21 drh: for(p=pBt->pCursor; p; p=p->pNext){ dbda8d6ce9 2007-07-21 drh: if( p==pExclude ) continue; dbda8d6ce9 2007-07-21 drh: if( p->eState!=CURSOR_VALID ) continue; dbda8d6ce9 2007-07-21 drh: if( p->pgnoRoot!=pgnoRoot ) continue; dbda8d6ce9 2007-07-21 drh: if( p->wrFlag==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *dbOther = p->pBtree->pSqlite; dbda8d6ce9 2007-07-21 drh: if( dbOther==0 || dbda8d6ce9 2007-07-21 drh: (dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_LOCKED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( p->pPage->pgno!=p->pgnoRoot ){ dbda8d6ce9 2007-07-21 drh: moveToRoot(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Insert a new record into the BTree. The key is given by (pKey,nKey) dbda8d6ce9 2007-07-21 drh: ** and the data is given by (pData,nData). The cursor is used only to dbda8d6ce9 2007-07-21 drh: ** define what table the record should be inserted into. The cursor dbda8d6ce9 2007-07-21 drh: ** is left pointing at a random location. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For an INTKEY table, only the nKey value of the key is used. pKey is dbda8d6ce9 2007-07-21 drh: ** ignored. For a ZERODATA table, the pData and nData are both ignored. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeInsert( dbda8d6ce9 2007-07-21 drh: BtCursor *pCur, /* Insert data into the table of this cursor */ dbda8d6ce9 2007-07-21 drh: const void *pKey, i64 nKey, /* The key of the new record */ dbda8d6ce9 2007-07-21 drh: const void *pData, int nData, /* The data of the new record */ dbda8d6ce9 2007-07-21 drh: int nZero, /* Number of extra 0 bytes to append to data */ dbda8d6ce9 2007-07-21 drh: int appendBias /* True if this is likely an append */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: int loc; dbda8d6ce9 2007-07-21 drh: int szNew; dbda8d6ce9 2007-07-21 drh: MemPage *pPage; c287665ba8 2007-09-14 drh: Btree *p = pCur->pBtree; c287665ba8 2007-09-14 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: unsigned char *oldCell; dbda8d6ce9 2007-07-21 drh: unsigned char *newCell = 0; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: if( pBt->inTransaction!=TRANS_WRITE ){ dbda8d6ce9 2007-07-21 drh: /* Must start a transaction before doing an insert */ c287665ba8 2007-09-14 drh: rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( !pBt->readOnly ); dbda8d6ce9 2007-07-21 drh: if( !pCur->wrFlag ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_PERM; /* Cursor not open for writing */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_LOCKED; /* The table pCur points to has a read lock */ c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( pCur->eState==CURSOR_FAULT ){ c287665ba8 2007-09-14 drh: return pCur->skip; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Save the positions of any other cursors open on this table */ dbda8d6ce9 2007-07-21 drh: clearCursorPosition(pCur); dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || dbda8d6ce9 2007-07-21 drh: SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, appendBias, &loc)) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: assert( pPage->intKey || nKey>=0 ); dbda8d6ce9 2007-07-21 drh: assert( pPage->leaf || !pPage->leafData ); dbda8d6ce9 2007-07-21 drh: TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", dbda8d6ce9 2007-07-21 drh: pCur->pgnoRoot, nKey, nData, pPage->pgno, dbda8d6ce9 2007-07-21 drh: loc==0 ? "overwrite" : "new entry")); dbda8d6ce9 2007-07-21 drh: assert( pPage->isInit ); c287665ba8 2007-09-14 drh: newCell = sqlite3_malloc( MX_CELL_SIZE(pBt) ); dbda8d6ce9 2007-07-21 drh: if( newCell==0 ) return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); dbda8d6ce9 2007-07-21 drh: if( rc ) goto end_insert; dbda8d6ce9 2007-07-21 drh: assert( szNew==cellSizePtr(pPage, newCell) ); dbda8d6ce9 2007-07-21 drh: assert( szNew<=MX_CELL_SIZE(pBt) ); dbda8d6ce9 2007-07-21 drh: if( loc==0 && CURSOR_VALID==pCur->eState ){ dbda8d6ce9 2007-07-21 drh: int szOld; dbda8d6ce9 2007-07-21 drh: assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); c287665ba8 2007-09-14 drh: rc = sqlite3PagerWrite(pPage->pDbPage); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: goto end_insert; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: oldCell = findCell(pPage, pCur->idx); dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: memcpy(newCell, oldCell, 4); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: szOld = cellSizePtr(pPage, oldCell); dbda8d6ce9 2007-07-21 drh: rc = clearCell(pPage, oldCell); dbda8d6ce9 2007-07-21 drh: if( rc ) goto end_insert; dbda8d6ce9 2007-07-21 drh: dropCell(pPage, pCur->idx, szOld); dbda8d6ce9 2007-07-21 drh: }else if( loc<0 && pPage->nCell>0 ){ dbda8d6ce9 2007-07-21 drh: assert( pPage->leaf ); dbda8d6ce9 2007-07-21 drh: pCur->idx++; dbda8d6ce9 2007-07-21 drh: pCur->info.nSize = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pPage->leaf ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = insertCell(pPage, pCur->idx, newCell, szNew, 0, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_insert; dbda8d6ce9 2007-07-21 drh: rc = balance(pPage, 1); dbda8d6ce9 2007-07-21 drh: /* sqlite3BtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */ dbda8d6ce9 2007-07-21 drh: /* fflush(stdout); */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: moveToRoot(pCur); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: end_insert: c287665ba8 2007-09-14 drh: sqlite3_free(newCell); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete the entry that the cursor is pointing to. The cursor dbda8d6ce9 2007-07-21 drh: ** is left pointing at a random location. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: MemPage *pPage = pCur->pPage; dbda8d6ce9 2007-07-21 drh: unsigned char *pCell; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Pgno pgnoChild = 0; c287665ba8 2007-09-14 drh: Btree *p = pCur->pBtree; c287665ba8 2007-09-14 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); dbda8d6ce9 2007-07-21 drh: assert( pPage->isInit ); dbda8d6ce9 2007-07-21 drh: if( pBt->inTransaction!=TRANS_WRITE ){ dbda8d6ce9 2007-07-21 drh: /* Must start a transaction before doing a delete */ c287665ba8 2007-09-14 drh: rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( !pBt->readOnly ); c287665ba8 2007-09-14 drh: if( pCur->eState==CURSOR_FAULT ){ c287665ba8 2007-09-14 drh: return pCur->skip; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( pCur->idx >= pPage->nCell ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; /* The cursor is not pointing to anything */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pCur->wrFlag ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_PERM; /* Did not open this cursor for writing */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_LOCKED; /* The table pCur points to has a read lock */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Restore the current cursor position (a no-op if the cursor is not in dbda8d6ce9 2007-07-21 drh: ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors dbda8d6ce9 2007-07-21 drh: ** open on the same table. Then call sqlite3PagerWrite() on the page dbda8d6ce9 2007-07-21 drh: ** that the entry will be deleted from. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: (rc = restoreOrClearCursorPosition(pCur))!=0 || dbda8d6ce9 2007-07-21 drh: (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 || dbda8d6ce9 2007-07-21 drh: (rc = sqlite3PagerWrite(pPage->pDbPage))!=0 dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Locate the cell within it's page and leave pCell pointing to the dbda8d6ce9 2007-07-21 drh: ** data. The clearCell() call frees any overflow pages associated with the dbda8d6ce9 2007-07-21 drh: ** cell. The cell itself is still intact. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pCell = findCell(pPage, pCur->idx); dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: pgnoChild = get4byte(pCell); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = clearCell(pPage, pCell); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The entry we are about to delete is not a leaf so if we do not dbda8d6ce9 2007-07-21 drh: ** do something we will leave a hole on an internal page. dbda8d6ce9 2007-07-21 drh: ** We have to fill the hole by moving in a cell from a leaf. The dbda8d6ce9 2007-07-21 drh: ** next Cell after the one to be deleted is guaranteed to exist and dbda8d6ce9 2007-07-21 drh: ** to be a leaf so we can use it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: BtCursor leafCur; dbda8d6ce9 2007-07-21 drh: unsigned char *pNext; dbda8d6ce9 2007-07-21 drh: int szNext; /* The compiler warning is wrong: szNext is always dbda8d6ce9 2007-07-21 drh: ** initialized before use. Adding an extra initialization dbda8d6ce9 2007-07-21 drh: ** to silence the compiler slows down the code. */ dbda8d6ce9 2007-07-21 drh: int notUsed; dbda8d6ce9 2007-07-21 drh: unsigned char *tempCell = 0; dbda8d6ce9 2007-07-21 drh: assert( !pPage->leafData ); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeGetTempCursor(pCur, &leafCur); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeNext(&leafCur, ¬Used); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(leafCur.pPage->pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", dbda8d6ce9 2007-07-21 drh: pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); dbda8d6ce9 2007-07-21 drh: dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); dbda8d6ce9 2007-07-21 drh: pNext = findCell(leafCur.pPage, leafCur.idx); dbda8d6ce9 2007-07-21 drh: szNext = cellSizePtr(leafCur.pPage, pNext); dbda8d6ce9 2007-07-21 drh: assert( MX_CELL_SIZE(pBt)>=szNext+4 ); c287665ba8 2007-09-14 drh: tempCell = sqlite3_malloc( MX_CELL_SIZE(pBt) ); dbda8d6ce9 2007-07-21 drh: if( tempCell==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild); dbda8d6ce9 2007-07-21 drh: rc = balance(pPage, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: dropCell(leafCur.pPage, leafCur.idx, szNext); dbda8d6ce9 2007-07-21 drh: rc = balance(leafCur.pPage, 0); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(tempCell); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeReleaseTempCursor(&leafCur); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: TRACE(("DELETE: table=%d delete from leaf %d\n", dbda8d6ce9 2007-07-21 drh: pCur->pgnoRoot, pPage->pgno)); dbda8d6ce9 2007-07-21 drh: dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); dbda8d6ce9 2007-07-21 drh: rc = balance(pPage, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: moveToRoot(pCur); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new BTree table. Write into *piTable the page dbda8d6ce9 2007-07-21 drh: ** number for the root page of the new table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The type of type is determined by the flags parameter. Only the dbda8d6ce9 2007-07-21 drh: ** following values of flags are currently in use. Other values for dbda8d6ce9 2007-07-21 drh: ** flags might not work: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys dbda8d6ce9 2007-07-21 drh: ** BTREE_ZERODATA Used for SQL indices dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int btreeCreateTable(Btree *p, int *piTable, int flags){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: MemPage *pRoot; dbda8d6ce9 2007-07-21 drh: Pgno pgnoRoot; dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(p) ); dbda8d6ce9 2007-07-21 drh: if( pBt->inTransaction!=TRANS_WRITE ){ dbda8d6ce9 2007-07-21 drh: /* Must start a transaction first */ c287665ba8 2007-09-14 drh: rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( !pBt->readOnly ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: Pgno pgnoMove; /* Move a page here to make room for the root-page */ dbda8d6ce9 2007-07-21 drh: MemPage *pPageMove; /* The page to move to. */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Creating a new table may probably require moving an existing database dbda8d6ce9 2007-07-21 drh: ** to make room for the new tables root page. In case this page turns dbda8d6ce9 2007-07-21 drh: ** out to be an overflow page, delete all overflow page-map caches dbda8d6ce9 2007-07-21 drh: ** held by open cursors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: invalidateAllOverflowCache(pBt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read the value of meta[3] from the database to determine where the dbda8d6ce9 2007-07-21 drh: ** root page of the new table should go. meta[3] is the largest root-page dbda8d6ce9 2007-07-21 drh: ** created so far, so the new root-page is (meta[3]+1). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: pgnoRoot++; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The new root-page may not be allocated on a pointer-map page, or the dbda8d6ce9 2007-07-21 drh: ** PENDING_BYTE page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) || dbda8d6ce9 2007-07-21 drh: pgnoRoot==PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: pgnoRoot++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pgnoRoot>=3 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate a page. The page that currently resides at pgnoRoot will dbda8d6ce9 2007-07-21 drh: ** be moved to the allocated page (unless the allocated page happens dbda8d6ce9 2007-07-21 drh: ** to reside at pgnoRoot). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pgnoMove!=pgnoRoot ){ dbda8d6ce9 2007-07-21 drh: /* pgnoRoot is the page that will be used for the root-page of dbda8d6ce9 2007-07-21 drh: ** the new table (assuming an error did not occur). But we were dbda8d6ce9 2007-07-21 drh: ** allocated pgnoMove. If required (i.e. if it was not allocated dbda8d6ce9 2007-07-21 drh: ** by extending the file), the current page at position pgnoMove dbda8d6ce9 2007-07-21 drh: ** is already journaled. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: u8 eType; dbda8d6ce9 2007-07-21 drh: Pgno iPtrPage; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: releasePage(pPageMove); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Move the page currently at pgnoRoot to pgnoMove. */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK || eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ dbda8d6ce9 2007-07-21 drh: releasePage(pRoot); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( eType!=PTRMAP_ROOTPAGE ); dbda8d6ce9 2007-07-21 drh: assert( eType!=PTRMAP_FREEPAGE ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pRoot->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pRoot); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove); dbda8d6ce9 2007-07-21 drh: releasePage(pRoot); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Obtain the page at pgnoRoot */ dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pRoot->pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pRoot); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pRoot = pPageMove; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update the pointer-map and meta-data with the new root-page number. */ dbda8d6ce9 2007-07-21 drh: rc = ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: releasePage(pRoot); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: releasePage(pRoot); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); dbda8d6ce9 2007-07-21 drh: zeroPage(pRoot, flags | PTF_LEAF); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pRoot->pDbPage); dbda8d6ce9 2007-07-21 drh: *piTable = (int)pgnoRoot; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); c287665ba8 2007-09-14 drh: rc = btreeCreateTable(p, piTable, flags); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Erase the given database page and all its children. Return dbda8d6ce9 2007-07-21 drh: ** the page to the freelist. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int clearDatabasePage( dbda8d6ce9 2007-07-21 drh: BtShared *pBt, /* The BTree that contains the table */ dbda8d6ce9 2007-07-21 drh: Pgno pgno, /* Page number to clear */ dbda8d6ce9 2007-07-21 drh: MemPage *pParent, /* Parent page. NULL for the root */ dbda8d6ce9 2007-07-21 drh: int freePageFlag /* Deallocate page if true */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: MemPage *pPage = 0; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: unsigned char *pCell; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pBt->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pgno>sqlite3PagerPagecount(pBt->pPager) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = getAndInitPage(pBt, pgno, &pPage, pParent); dbda8d6ce9 2007-07-21 drh: if( rc ) goto cleardatabasepage_out; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pPage->nCell; i++){ dbda8d6ce9 2007-07-21 drh: pCell = findCell(pPage, i); dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1); dbda8d6ce9 2007-07-21 drh: if( rc ) goto cleardatabasepage_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = clearCell(pPage, pCell); dbda8d6ce9 2007-07-21 drh: if( rc ) goto cleardatabasepage_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage->pParent, 1); dbda8d6ce9 2007-07-21 drh: if( rc ) goto cleardatabasepage_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( freePageFlag ){ dbda8d6ce9 2007-07-21 drh: rc = freePage(pPage); dbda8d6ce9 2007-07-21 drh: }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ dbda8d6ce9 2007-07-21 drh: zeroPage(pPage, pPage->aData[0] | PTF_LEAF); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: cleardatabasepage_out: dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete all information from a single table in the database. iTable is dbda8d6ce9 2007-07-21 drh: ** the page number of the root of the table. After this routine returns, dbda8d6ce9 2007-07-21 drh: ** the root page is empty, but still exists. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine will fail with SQLITE_LOCKED if there are any open dbda8d6ce9 2007-07-21 drh: ** read cursors on the table. Open write cursors are moved to the dbda8d6ce9 2007-07-21 drh: ** root of the table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: if( p->inTrans!=TRANS_WRITE ){ c287665ba8 2007-09-14 drh: rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; c287665ba8 2007-09-14 drh: }else if( (rc = checkReadLocks(p, iTable, 0))!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: /* nothing to do */ c287665ba8 2007-09-14 drh: }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){ c287665ba8 2007-09-14 drh: /* nothing to do */ c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Erase all information in a table and add the root of the table to dbda8d6ce9 2007-07-21 drh: ** the freelist. Except, the root of the principle table (the one on dbda8d6ce9 2007-07-21 drh: ** page 1) is never added to the freelist. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine will fail with SQLITE_LOCKED if there are any open dbda8d6ce9 2007-07-21 drh: ** cursors on the table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If AUTOVACUUM is enabled and the page at iTable is not the last dbda8d6ce9 2007-07-21 drh: ** root page in the database file, then the last root page dbda8d6ce9 2007-07-21 drh: ** in the database file is moved into the slot formerly occupied by dbda8d6ce9 2007-07-21 drh: ** iTable and that last slot formerly occupied by the last root page dbda8d6ce9 2007-07-21 drh: ** is added to the freelist instead of iTable. In this say, all dbda8d6ce9 2007-07-21 drh: ** root pages are kept at the beginning of the database file, which dbda8d6ce9 2007-07-21 drh: ** is necessary for AUTOVACUUM to work right. *piMoved is set to the dbda8d6ce9 2007-07-21 drh: ** page number that used to be the last root page in the file before dbda8d6ce9 2007-07-21 drh: ** the move. If no page gets moved, *piMoved is set to 0. dbda8d6ce9 2007-07-21 drh: ** The last root page is recorded in meta[3] and the value of dbda8d6ce9 2007-07-21 drh: ** meta[3] is updated by this procedure. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int btreeDropTable(Btree *p, int iTable, int *piMoved){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: MemPage *pPage = 0; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(p) ); dbda8d6ce9 2007-07-21 drh: if( p->inTrans!=TRANS_WRITE ){ dbda8d6ce9 2007-07-21 drh: return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* It is illegal to drop a table if any cursors are open on the dbda8d6ce9 2007-07-21 drh: ** database. This is because in auto-vacuum mode the backend may dbda8d6ce9 2007-07-21 drh: ** need to move another root-page to fill a gap left by the deleted dbda8d6ce9 2007-07-21 drh: ** root page. If an open cursor was using this page a problem would dbda8d6ce9 2007-07-21 drh: ** occur. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pBt->pCursor ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_LOCKED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeClearTable(p, iTable); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: *piMoved = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( iTable>1 ){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: rc = freePage(pPage); dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: Pgno maxRootPgno; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetMeta(p, 4, &maxRootPgno); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( iTable==maxRootPgno ){ dbda8d6ce9 2007-07-21 drh: /* If the table being dropped is the table with the largest root-page dbda8d6ce9 2007-07-21 drh: ** number in the database, put the root page on the free list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = freePage(pPage); dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The table being dropped does not have the largest root-page dbda8d6ce9 2007-07-21 drh: ** number in the database. So move the page that does into the dbda8d6ce9 2007-07-21 drh: ** gap left by the deleted root-page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: MemPage *pMove; dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable); dbda8d6ce9 2007-07-21 drh: releasePage(pMove); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = freePage(pMove); dbda8d6ce9 2007-07-21 drh: releasePage(pMove); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *piMoved = maxRootPgno; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the new 'max-root-page' value in the database header. This dbda8d6ce9 2007-07-21 drh: ** is the old value less one, less one more if that happens to dbda8d6ce9 2007-07-21 drh: ** be a root-page number, less one again if that is the dbda8d6ce9 2007-07-21 drh: ** PENDING_BYTE_PAGE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: maxRootPgno--; dbda8d6ce9 2007-07-21 drh: if( maxRootPgno==PENDING_BYTE_PAGE(pBt) ){ dbda8d6ce9 2007-07-21 drh: maxRootPgno--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( maxRootPgno==PTRMAP_PAGENO(pBt, maxRootPgno) ){ dbda8d6ce9 2007-07-21 drh: maxRootPgno--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = freePage(pPage); dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* If sqlite3BtreeDropTable was called on page 1. */ dbda8d6ce9 2007-07-21 drh: zeroPage(pPage, PTF_INTKEY|PTF_LEAF ); dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); c287665ba8 2007-09-14 drh: rc = btreeDropTable(p, iTable, piMoved); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read the meta-information out of a database file. Meta[0] dbda8d6ce9 2007-07-21 drh: ** is the number of free pages currently in the database. Meta[1] dbda8d6ce9 2007-07-21 drh: ** through meta[15] are available for use by higher layers. Meta[0] dbda8d6ce9 2007-07-21 drh: ** is read-only, the others are read/write. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The schema layer numbers meta values differently. At the schema dbda8d6ce9 2007-07-21 drh: ** layer (and the SetCookie and ReadCookie opcodes) the number of dbda8d6ce9 2007-07-21 drh: ** free pages is not visible. So Cookie[0] is the same as Meta[1]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: unsigned char *pP1; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* Reading a meta-data value requires a read-lock on page 1 (and hence dbda8d6ce9 2007-07-21 drh: ** the sqlite_master table. We grab this lock regardless of whether or dbda8d6ce9 2007-07-21 drh: ** not the SQLITE_ReadUncommitted flag is set (the table rooted at page dbda8d6ce9 2007-07-21 drh: ** 1 is treated as a special case by queryTableLock() and lockTable()). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = queryTableLock(p, 1, READ_LOCK); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( idx>=0 && idx<=15 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pBt->pPager, 1, &pDbPage); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: pP1 = (unsigned char *)sqlite3PagerGetData(pDbPage); dbda8d6ce9 2007-07-21 drh: *pMeta = get4byte(&pP1[36 + idx*4]); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pDbPage); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If autovacuumed is disabled in this build but we are trying to dbda8d6ce9 2007-07-21 drh: ** access an autovacuumed database, then make the database readonly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( idx==4 && *pMeta>0 ) pBt->readOnly = 1; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Grab the read-lock on page 1. */ dbda8d6ce9 2007-07-21 drh: rc = lockTable(p, 1, READ_LOCK); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write meta-information back into the database. Meta[0] is dbda8d6ce9 2007-07-21 drh: ** read-only and may not be written. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: unsigned char *pP1; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( idx>=1 && idx<=15 ); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: if( p->inTrans!=TRANS_WRITE ){ c287665ba8 2007-09-14 drh: rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: assert( pBt->pPage1!=0 ); c287665ba8 2007-09-14 drh: pP1 = pBt->pPage1->aData; c287665ba8 2007-09-14 drh: rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: put4byte(&pP1[36 + idx*4], iMeta); c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_AUTOVACUUM c287665ba8 2007-09-14 drh: if( idx==7 ){ c287665ba8 2007-09-14 drh: assert( pBt->autoVacuum || iMeta==0 ); c287665ba8 2007-09-14 drh: assert( iMeta==0 || iMeta==1 ); c287665ba8 2007-09-14 drh: pBt->incrVacuum = iMeta; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the flag byte at the beginning of the page that the cursor dbda8d6ce9 2007-07-21 drh: ** is currently pointing to. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeFlags(BtCursor *pCur){ dbda8d6ce9 2007-07-21 drh: /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call dbda8d6ce9 2007-07-21 drh: ** restoreOrClearCursorPosition() here. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: MemPage *pPage = pCur->pPage; c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: assert( pPage->pBt==pCur->pBt ); dbda8d6ce9 2007-07-21 drh: return pPage ? pPage->aData[pPage->hdrOffset] : 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the pager associated with a BTree. This routine is used for dbda8d6ce9 2007-07-21 drh: ** testing and debugging only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){ dbda8d6ce9 2007-07-21 drh: return p->pBt->pPager; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INTEGRITY_CHECK dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Append a message to the error message string. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void checkAppendMsg( dbda8d6ce9 2007-07-21 drh: IntegrityCk *pCheck, dbda8d6ce9 2007-07-21 drh: char *zMsg1, dbda8d6ce9 2007-07-21 drh: const char *zFormat, dbda8d6ce9 2007-07-21 drh: ... dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: char *zMsg2; dbda8d6ce9 2007-07-21 drh: if( !pCheck->mxErr ) return; dbda8d6ce9 2007-07-21 drh: pCheck->mxErr--; dbda8d6ce9 2007-07-21 drh: pCheck->nErr++; dbda8d6ce9 2007-07-21 drh: va_start(ap, zFormat); c287665ba8 2007-09-14 drh: zMsg2 = sqlite3VMPrintf(0, zFormat, ap); dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: if( zMsg1==0 ) zMsg1 = ""; dbda8d6ce9 2007-07-21 drh: if( pCheck->zErrMsg ){ dbda8d6ce9 2007-07-21 drh: char *zOld = pCheck->zErrMsg; dbda8d6ce9 2007-07-21 drh: pCheck->zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&pCheck->zErrMsg, zOld, "\n", zMsg1, zMsg2, (char*)0); c287665ba8 2007-09-14 drh: sqlite3_free(zOld); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&pCheck->zErrMsg, zMsg1, zMsg2, (char*)0); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(zMsg2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INTEGRITY_CHECK dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add 1 to the reference count for page iPage. If this is the second dbda8d6ce9 2007-07-21 drh: ** reference to the page, add an error message to pCheck->zErrMsg. dbda8d6ce9 2007-07-21 drh: ** Return 1 if there are 2 ore more references to the page and 0 if dbda8d6ce9 2007-07-21 drh: ** if this is the first reference to the page. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Also check that the page number is in bounds. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int checkRef(IntegrityCk *pCheck, int iPage, char *zContext){ dbda8d6ce9 2007-07-21 drh: if( iPage==0 ) return 1; dbda8d6ce9 2007-07-21 drh: if( iPage>pCheck->nPage || iPage<0 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCheck->anRef[iPage]==1 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return (pCheck->anRef[iPage]++)>1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check that the entry in the pointer-map for page iChild maps to dbda8d6ce9 2007-07-21 drh: ** page iParent, pointer type ptrType. If not, append an error message dbda8d6ce9 2007-07-21 drh: ** to pCheck. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void checkPtrmap( dbda8d6ce9 2007-07-21 drh: IntegrityCk *pCheck, /* Integrity check context */ dbda8d6ce9 2007-07-21 drh: Pgno iChild, /* Child page number */ dbda8d6ce9 2007-07-21 drh: u8 eType, /* Expected pointer map type */ dbda8d6ce9 2007-07-21 drh: Pgno iParent, /* Expected pointer map parent page number */ dbda8d6ce9 2007-07-21 drh: char *zContext /* Context description (used for error msg) */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: u8 ePtrmapType; dbda8d6ce9 2007-07-21 drh: Pgno iPtrmapParent; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, "Failed to read ptrmap key=%d", iChild); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, dbda8d6ce9 2007-07-21 drh: "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", dbda8d6ce9 2007-07-21 drh: iChild, eType, iParent, ePtrmapType, iPtrmapParent); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check the integrity of the freelist or of an overflow page list. dbda8d6ce9 2007-07-21 drh: ** Verify that the number of pages on the list is N. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void checkList( dbda8d6ce9 2007-07-21 drh: IntegrityCk *pCheck, /* Integrity checking context */ dbda8d6ce9 2007-07-21 drh: int isFreeList, /* True for a freelist. False for overflow page list */ dbda8d6ce9 2007-07-21 drh: int iPage, /* Page number for first page in the list */ dbda8d6ce9 2007-07-21 drh: int N, /* Expected number of pages in the list */ dbda8d6ce9 2007-07-21 drh: char *zContext /* Context for error messages */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int expected = N; dbda8d6ce9 2007-07-21 drh: int iFirst = iPage; dbda8d6ce9 2007-07-21 drh: while( N-- > 0 && pCheck->mxErr ){ dbda8d6ce9 2007-07-21 drh: DbPage *pOvflPage; dbda8d6ce9 2007-07-21 drh: unsigned char *pOvflData; dbda8d6ce9 2007-07-21 drh: if( iPage<1 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, dbda8d6ce9 2007-07-21 drh: "%d of %d pages missing from overflow list starting at %d", dbda8d6ce9 2007-07-21 drh: N+1, expected, iFirst); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( checkRef(pCheck, iPage, zContext) ) break; dbda8d6ce9 2007-07-21 drh: if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); dbda8d6ce9 2007-07-21 drh: if( isFreeList ){ dbda8d6ce9 2007-07-21 drh: int n = get4byte(&pOvflData[4]); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pCheck->pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0, zContext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( n>pCheck->pBt->usableSize/4-8 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, dbda8d6ce9 2007-07-21 drh: "freelist leaf count too big on page %d", iPage); dbda8d6ce9 2007-07-21 drh: N--; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(i=0; i<n; i++){ dbda8d6ce9 2007-07-21 drh: Pgno iFreePage = get4byte(&pOvflData[8+i*4]); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pCheck->pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0, zContext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: checkRef(pCheck, iFreePage, zContext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: N -= n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: else{ dbda8d6ce9 2007-07-21 drh: /* If this database supports auto-vacuum and iPage is not the last dbda8d6ce9 2007-07-21 drh: ** page in this overflow list, check that the pointer-map entry for dbda8d6ce9 2007-07-21 drh: ** the following page matches iPage. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pCheck->pBt->autoVacuum && N>0 ){ dbda8d6ce9 2007-07-21 drh: i = get4byte(pOvflData); dbda8d6ce9 2007-07-21 drh: checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage, zContext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: iPage = get4byte(pOvflData); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pOvflPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INTEGRITY_CHECK dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Do various sanity checks on a single page of a tree. Return dbda8d6ce9 2007-07-21 drh: ** the tree depth. Root pages return 0. Parents of root pages dbda8d6ce9 2007-07-21 drh: ** return 1, and so forth. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These checks are done: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1. Make sure that cells and freeblocks do not overlap dbda8d6ce9 2007-07-21 drh: ** but combine to completely cover the page. dbda8d6ce9 2007-07-21 drh: ** NO 2. Make sure cell keys are in order. dbda8d6ce9 2007-07-21 drh: ** NO 3. Make sure no key is less than or equal to zLowerBound. dbda8d6ce9 2007-07-21 drh: ** NO 4. Make sure no key is greater than or equal to zUpperBound. dbda8d6ce9 2007-07-21 drh: ** 5. Check the integrity of overflow pages. dbda8d6ce9 2007-07-21 drh: ** 6. Recursively call checkTreePage on all children. dbda8d6ce9 2007-07-21 drh: ** 7. Verify that the depth of all children is the same. dbda8d6ce9 2007-07-21 drh: ** 8. Make sure this page is at least 33% full or else it is dbda8d6ce9 2007-07-21 drh: ** the root of the tree. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int checkTreePage( dbda8d6ce9 2007-07-21 drh: IntegrityCk *pCheck, /* Context for the sanity check */ dbda8d6ce9 2007-07-21 drh: int iPage, /* Page number of the page to check */ dbda8d6ce9 2007-07-21 drh: MemPage *pParent, /* Parent page */ dbda8d6ce9 2007-07-21 drh: char *zParentContext /* Parent context */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: MemPage *pPage; dbda8d6ce9 2007-07-21 drh: int i, rc, depth, d2, pgno, cnt; dbda8d6ce9 2007-07-21 drh: int hdr, cellStart; dbda8d6ce9 2007-07-21 drh: int nCell; dbda8d6ce9 2007-07-21 drh: u8 *data; dbda8d6ce9 2007-07-21 drh: BtShared *pBt; dbda8d6ce9 2007-07-21 drh: int usableSize; dbda8d6ce9 2007-07-21 drh: char zContext[100]; dbda8d6ce9 2007-07-21 drh: char *hit; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zContext), zContext, "Page %d: ", iPage); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check that the page exists dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pBt = pCheck->pBt; dbda8d6ce9 2007-07-21 drh: usableSize = pBt->usableSize; dbda8d6ce9 2007-07-21 drh: if( iPage==0 ) return 0; dbda8d6ce9 2007-07-21 drh: if( checkRef(pCheck, iPage, zParentContext) ) return 0; dbda8d6ce9 2007-07-21 drh: if( (rc = sqlite3BtreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, dbda8d6ce9 2007-07-21 drh: "unable to get the page. error code=%d", rc); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (rc = sqlite3BtreeInitPage(pPage, pParent))!=0 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, dbda8d6ce9 2007-07-21 drh: "sqlite3BtreeInitPage() returns error code %d", rc); dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check out all the cells. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: depth = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pPage->nCell && pCheck->mxErr; i++){ dbda8d6ce9 2007-07-21 drh: u8 *pCell; dbda8d6ce9 2007-07-21 drh: int sz; dbda8d6ce9 2007-07-21 drh: CellInfo info; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check payload overflow pages dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zContext), zContext, dbda8d6ce9 2007-07-21 drh: "On tree page %d cell %d: ", iPage, i); dbda8d6ce9 2007-07-21 drh: pCell = findCell(pPage,i); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeParseCellPtr(pPage, pCell, &info); dbda8d6ce9 2007-07-21 drh: sz = info.nData; dbda8d6ce9 2007-07-21 drh: if( !pPage->intKey ) sz += info.nKey; dbda8d6ce9 2007-07-21 drh: assert( sz==info.nPayload ); dbda8d6ce9 2007-07-21 drh: if( sz>info.nLocal ){ dbda8d6ce9 2007-07-21 drh: int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4); dbda8d6ce9 2007-07-21 drh: Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage, zContext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: checkList(pCheck, 0, pgnoOvfl, nPage, zContext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check sanity of left child page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: pgno = get4byte(pCell); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: d2 = checkTreePage(pCheck,pgno,pPage,zContext); dbda8d6ce9 2007-07-21 drh: if( i>0 && d2!=depth ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, zContext, "Child page depth differs"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: depth = d2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pPage->leaf ){ dbda8d6ce9 2007-07-21 drh: pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zContext), zContext, dbda8d6ce9 2007-07-21 drh: "On page %d at right child: ", iPage); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum ){ dbda8d6ce9 2007-07-21 drh: checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: checkTreePage(pCheck, pgno, pPage, zContext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check for complete coverage of the page dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: data = pPage->aData; dbda8d6ce9 2007-07-21 drh: hdr = pPage->hdrOffset; c287665ba8 2007-09-14 drh: hit = sqlite3MallocZero( usableSize ); dbda8d6ce9 2007-07-21 drh: if( hit ){ dbda8d6ce9 2007-07-21 drh: memset(hit, 1, get2byte(&data[hdr+5])); dbda8d6ce9 2007-07-21 drh: nCell = get2byte(&data[hdr+3]); dbda8d6ce9 2007-07-21 drh: cellStart = hdr + 12 - 4*pPage->leaf; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCell; i++){ dbda8d6ce9 2007-07-21 drh: int pc = get2byte(&data[cellStart+i*2]); dbda8d6ce9 2007-07-21 drh: int size = cellSizePtr(pPage, &data[pc]); dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: if( (pc+size-1)>=usableSize || pc<0 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, 0, dbda8d6ce9 2007-07-21 drh: "Corruption detected in cell %d on page %d",i,iPage,0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(j=pc+size-1; j>=pc; j--) hit[j]++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(cnt=0, i=get2byte(&data[hdr+1]); i>0 && i<usableSize && cnt<10000; dbda8d6ce9 2007-07-21 drh: cnt++){ dbda8d6ce9 2007-07-21 drh: int size = get2byte(&data[i+2]); dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: if( (i+size-1)>=usableSize || i<0 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, 0, dbda8d6ce9 2007-07-21 drh: "Corruption detected in cell %d on page %d",i,iPage,0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(j=i+size-1; j>=i; j--) hit[j]++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i = get2byte(&data[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=cnt=0; i<usableSize; i++){ dbda8d6ce9 2007-07-21 drh: if( hit[i]==0 ){ dbda8d6ce9 2007-07-21 drh: cnt++; dbda8d6ce9 2007-07-21 drh: }else if( hit[i]>1 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, 0, dbda8d6ce9 2007-07-21 drh: "Multiple uses for byte %d of page %d", i, iPage); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( cnt!=data[hdr+7] ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(pCheck, 0, dbda8d6ce9 2007-07-21 drh: "Fragmented space is %d byte reported as %d on page %d", dbda8d6ce9 2007-07-21 drh: cnt, data[hdr+7], iPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(hit); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: releasePage(pPage); dbda8d6ce9 2007-07-21 drh: return depth+1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INTEGRITY_CHECK dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine does a complete check of the given BTree file. aRoot[] is dbda8d6ce9 2007-07-21 drh: ** an array of pages numbers were each page number is the root page of dbda8d6ce9 2007-07-21 drh: ** a table. nRoot is the number of entries in aRoot. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If everything checks out, this routine returns NULL. If something is dbda8d6ce9 2007-07-21 drh: ** amiss, an error message is written into memory obtained from malloc() dbda8d6ce9 2007-07-21 drh: ** and a pointer to that error message is returned. The calling function dbda8d6ce9 2007-07-21 drh: ** is responsible for freeing the error message when it is done. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( dbda8d6ce9 2007-07-21 drh: Btree *p, /* The btree to be checked */ dbda8d6ce9 2007-07-21 drh: int *aRoot, /* An array of root pages numbers for individual trees */ dbda8d6ce9 2007-07-21 drh: int nRoot, /* Number of entries in aRoot[] */ dbda8d6ce9 2007-07-21 drh: int mxErr, /* Stop reporting errors after this many */ dbda8d6ce9 2007-07-21 drh: int *pnErr /* Write number of errors seen to this variable */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nRef; dbda8d6ce9 2007-07-21 drh: IntegrityCk sCheck; dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: nRef = sqlite3PagerRefcount(pBt->pPager); dbda8d6ce9 2007-07-21 drh: if( lockBtreeWithRetry(p)!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return sqlite3StrDup("Unable to acquire a read lock on the database"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sCheck.pBt = pBt; dbda8d6ce9 2007-07-21 drh: sCheck.pPager = pBt->pPager; dbda8d6ce9 2007-07-21 drh: sCheck.nPage = sqlite3PagerPagecount(sCheck.pPager); dbda8d6ce9 2007-07-21 drh: sCheck.mxErr = mxErr; dbda8d6ce9 2007-07-21 drh: sCheck.nErr = 0; dbda8d6ce9 2007-07-21 drh: *pnErr = 0; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->nTrunc!=0 ){ dbda8d6ce9 2007-07-21 drh: sCheck.nPage = pBt->nTrunc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( sCheck.nPage==0 ){ dbda8d6ce9 2007-07-21 drh: unlockBtreeIfUnused(pBt); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sCheck.anRef = sqlite3_malloc( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) ); dbda8d6ce9 2007-07-21 drh: if( !sCheck.anRef ){ dbda8d6ce9 2007-07-21 drh: unlockBtreeIfUnused(pBt); dbda8d6ce9 2007-07-21 drh: *pnErr = 1; c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return sqlite3MPrintf(p->pSqlite, "Unable to malloc %d bytes", dbda8d6ce9 2007-07-21 drh: (sCheck.nPage+1)*sizeof(sCheck.anRef[0])); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; } dbda8d6ce9 2007-07-21 drh: i = PENDING_BYTE_PAGE(pBt); dbda8d6ce9 2007-07-21 drh: if( i<=sCheck.nPage ){ dbda8d6ce9 2007-07-21 drh: sCheck.anRef[i] = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sCheck.zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check the integrity of the freelist dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), dbda8d6ce9 2007-07-21 drh: get4byte(&pBt->pPage1->aData[36]), "Main freelist: "); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check all the tables. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nRoot && sCheck.mxErr; i++){ dbda8d6ce9 2007-07-21 drh: if( aRoot[i]==0 ) continue; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( pBt->autoVacuum && aRoot[i]>1 ){ dbda8d6ce9 2007-07-21 drh: checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: "); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure every page in the file is referenced dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( sCheck.anRef[i]==0 ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(&sCheck, 0, "Page %d is never used", i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: /* If the database supports auto-vacuum, make sure no tables contain dbda8d6ce9 2007-07-21 drh: ** references to pointer-map pages. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sCheck.anRef[i]==0 && dbda8d6ce9 2007-07-21 drh: (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(&sCheck, 0, "Page %d is never used", i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sCheck.anRef[i]!=0 && dbda8d6ce9 2007-07-21 drh: (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure this analysis did not leave any unref() pages dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: unlockBtreeIfUnused(pBt); dbda8d6ce9 2007-07-21 drh: if( nRef != sqlite3PagerRefcount(pBt->pPager) ){ dbda8d6ce9 2007-07-21 drh: checkAppendMsg(&sCheck, 0, dbda8d6ce9 2007-07-21 drh: "Outstanding page count goes from %d to %d during this analysis", dbda8d6ce9 2007-07-21 drh: nRef, sqlite3PagerRefcount(pBt->pPager) dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Clean up and report errors. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: sqlite3_free(sCheck.anRef); dbda8d6ce9 2007-07-21 drh: *pnErr = sCheck.nErr; dbda8d6ce9 2007-07-21 drh: return sCheck.zErrMsg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the full pathname of the underlying database file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The pager filename is invariant as long as the pager is c287665ba8 2007-09-14 drh: ** open so it is safe to access without the BtShared mutex. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *p){ dbda8d6ce9 2007-07-21 drh: assert( p->pBt->pPager!=0 ); dbda8d6ce9 2007-07-21 drh: return sqlite3PagerFilename(p->pBt->pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the pathname of the directory that contains the database file. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The pager directory name is invariant as long as the pager is c287665ba8 2007-09-14 drh: ** open so it is safe to access without the BtShared mutex. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3BtreeGetDirname(Btree *p){ dbda8d6ce9 2007-07-21 drh: assert( p->pBt->pPager!=0 ); dbda8d6ce9 2007-07-21 drh: return sqlite3PagerDirname(p->pBt->pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the pathname of the journal file for this database. The return dbda8d6ce9 2007-07-21 drh: ** value of this routine is the same regardless of whether the journal file dbda8d6ce9 2007-07-21 drh: ** has been created or not. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The pager journal filename is invariant as long as the pager is c287665ba8 2007-09-14 drh: ** open so it is safe to access without the BtShared mutex. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *p){ dbda8d6ce9 2007-07-21 drh: assert( p->pBt->pPager!=0 ); dbda8d6ce9 2007-07-21 drh: return sqlite3PagerJournalname(p->pBt->pPager); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VACUUM dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Copy the complete content of pBtFrom into pBtTo. A transaction dbda8d6ce9 2007-07-21 drh: ** must be active for both files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The size of file pBtFrom may be reduced by this operation. dbda8d6ce9 2007-07-21 drh: ** If anything goes wrong, the transaction on pBtFrom is rolled back. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int btreeCopyFile(Btree *pTo, Btree *pFrom){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: Pgno i, nPage, nToPage, iSkip; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: BtShared *pBtTo = pTo->pBt; dbda8d6ce9 2007-07-21 drh: BtShared *pBtFrom = pFrom->pBt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pTo->inTrans!=TRANS_WRITE || pFrom->inTrans!=TRANS_WRITE ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pBtTo->pCursor ) return SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: nToPage = sqlite3PagerPagecount(pBtTo->pPager); dbda8d6ce9 2007-07-21 drh: nPage = sqlite3PagerPagecount(pBtFrom->pPager); dbda8d6ce9 2007-07-21 drh: iSkip = PENDING_BYTE_PAGE(pBtTo); dbda8d6ce9 2007-07-21 drh: for(i=1; rc==SQLITE_OK && i<=nPage; i++){ dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; dbda8d6ce9 2007-07-21 drh: if( i==iSkip ) continue; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pBtFrom->pPager, i, &pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ) break; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerOverwrite(pBtTo->pPager, i, sqlite3PagerGetData(pDbPage)); dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the file is shrinking, journal the pages that are being truncated dbda8d6ce9 2007-07-21 drh: ** so that they can be rolled back if the commit fails. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ dbda8d6ce9 2007-07-21 drh: DbPage *pDbPage; dbda8d6ce9 2007-07-21 drh: if( i==iSkip ) continue; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerGet(pBtTo->pPager, i, &pDbPage); dbda8d6ce9 2007-07-21 drh: if( rc ) break; dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerWrite(pDbPage); dbda8d6ce9 2007-07-21 drh: sqlite3PagerDontWrite(pDbPage); dbda8d6ce9 2007-07-21 drh: /* Yeah. It seems wierd to call DontWrite() right after Write(). But dbda8d6ce9 2007-07-21 drh: ** that is because the names of those procedures do not exactly dbda8d6ce9 2007-07-21 drh: ** represent what they do. Write() really means "put this page in the dbda8d6ce9 2007-07-21 drh: ** rollback journal and mark it as dirty so that it will be written dbda8d6ce9 2007-07-21 drh: ** to the database file later." DontWrite() undoes the second part of dbda8d6ce9 2007-07-21 drh: ** that and prevents the page from being written to the database. The dbda8d6ce9 2007-07-21 drh: ** page is still on the rollback journal, though. And that is the whole dbda8d6ce9 2007-07-21 drh: ** point of this loop: to put pages on the rollback journal. */ dbda8d6ce9 2007-07-21 drh: sqlite3PagerUnref(pDbPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !rc && nPage<nToPage ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3PagerTruncate(pBtTo->pPager, nPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeRollback(pTo); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(pTo); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(pFrom); c287665ba8 2007-09-14 drh: rc = btreeCopyFile(pTo, pFrom); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pFrom); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pTo); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VACUUM */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return non-zero if a transaction is active. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree *p){ c287665ba8 2007-09-14 drh: assert( p==0 || sqlite3_mutex_held(p->pSqlite->mutex) ); dbda8d6ce9 2007-07-21 drh: return (p && (p->inTrans==TRANS_WRITE)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return non-zero if a statement transaction is active. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeIsInStmt(Btree *p){ c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(p) ); dbda8d6ce9 2007-07-21 drh: return (p->pBt && p->pBt->inStmt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return non-zero if a read (or write) transaction is active. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree *p){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); dbda8d6ce9 2007-07-21 drh: return (p && (p->inTrans!=TRANS_NONE)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function returns a pointer to a blob of memory associated with dbda8d6ce9 2007-07-21 drh: ** a single shared-btree. The memory is used by client code for it's own dbda8d6ce9 2007-07-21 drh: ** purposes (for example, to store a high-level schema associated with dbda8d6ce9 2007-07-21 drh: ** the shared-btree). The btree layer manages reference counting issues. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first time this is called on a shared-btree, nBytes bytes of memory dbda8d6ce9 2007-07-21 drh: ** are allocated, zeroed, and returned to the caller. For each subsequent dbda8d6ce9 2007-07-21 drh: ** call the nBytes parameter is ignored and a pointer to the same blob dbda8d6ce9 2007-07-21 drh: ** of memory returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Just before the shared-btree is closed, the function passed as the dbda8d6ce9 2007-07-21 drh: ** xFree argument when the memory allocation was made is invoked on the c287665ba8 2007-09-14 drh: ** blob of allocated memory. This function should not call sqlite3_free() dbda8d6ce9 2007-07-21 drh: ** on the memory, the btree layer does that. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ dbda8d6ce9 2007-07-21 drh: BtShared *pBt = p->pBt; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: if( !pBt->pSchema ){ c287665ba8 2007-09-14 drh: pBt->pSchema = sqlite3MallocZero(nBytes); dbda8d6ce9 2007-07-21 drh: pBt->xFreeSchema = xFree; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return pBt->pSchema; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return true if another user of the same shared btree as the argument dbda8d6ce9 2007-07-21 drh: ** handle holds an exclusive lock on the sqlite_master table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->pSqlite->mutex) ); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); c287665ba8 2007-09-14 drh: rc = (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Obtain a lock on the table whose root page is iTab. The dbda8d6ce9 2007-07-21 drh: ** lock is a write lock if isWritelock is true or a read lock dbda8d6ce9 2007-07-21 drh: ** if it is false. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK); c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(p); dbda8d6ce9 2007-07-21 drh: rc = queryTableLock(p, iTab, lockType); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = lockTable(p, iTab, lockType); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Argument pCsr must be a cursor opened for writing on an dbda8d6ce9 2007-07-21 drh: ** INTKEY table currently pointing at a valid table entry. dbda8d6ce9 2007-07-21 drh: ** This function modifies the data stored as part of that entry. dbda8d6ce9 2007-07-21 drh: ** Only the data content may only be modified, it is not possible dbda8d6ce9 2007-07-21 drh: ** to change the length of the data stored. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCsr) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCsr->pBtree->pSqlite->mutex) ); dbda8d6ce9 2007-07-21 drh: assert(pCsr->isIncrblobHandle); c287665ba8 2007-09-14 drh: if( pCsr->eState>=CURSOR_REQUIRESEEK ){ c287665ba8 2007-09-14 drh: if( pCsr->eState==CURSOR_FAULT ){ c287665ba8 2007-09-14 drh: return pCsr->skip; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: return SQLITE_ABORT; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check some preconditions: dbda8d6ce9 2007-07-21 drh: ** (a) the cursor is open for writing, dbda8d6ce9 2007-07-21 drh: ** (b) there is no read-lock on the table being modified and dbda8d6ce9 2007-07-21 drh: ** (c) the cursor points at a valid row of an intKey table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !pCsr->wrFlag ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_READONLY; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert( !pCsr->pBt->readOnly c287665ba8 2007-09-14 drh: && pCsr->pBt->inTransaction==TRANS_WRITE ); dbda8d6ce9 2007-07-21 drh: if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_LOCKED; /* The table pCur points to has a read lock */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCsr->eState==CURSOR_INVALID || !pCsr->pPage->intKey ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return accessPayload(pCsr, offset, amt, (unsigned char *)z, 0, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set a flag on this cursor to cache the locations of pages from the dbda8d6ce9 2007-07-21 drh: ** overflow list for the current row. This is used by cursors opened dbda8d6ce9 2007-07-21 drh: ** for incremental blob IO only. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function sets a flag only. The actual page location cache dbda8d6ce9 2007-07-21 drh: ** (stored in BtCursor.aOverflow[]) is allocated and used by function dbda8d6ce9 2007-07-21 drh: ** accessPayload() (the worker function for sqlite3BtreeData() and dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreePutData()). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){ c287665ba8 2007-09-14 drh: assert( cursorHoldsMutex(pCur) ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); dbda8d6ce9 2007-07-21 drh: assert(!pCur->isIncrblobHandle); dbda8d6ce9 2007-07-21 drh: assert(!pCur->aOverflow); dbda8d6ce9 2007-07-21 drh: pCur->isIncrblobHandle = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of btree.c ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vdbefifo.c ****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2005 June 16 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file implements a FIFO queue of rowids used for processing dbda8d6ce9 2007-07-21 drh: ** UPDATE and DELETE statements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate a new FifoPage and return a pointer to it. Return NULL if dbda8d6ce9 2007-07-21 drh: ** we run out of memory. Leave space on the page for nEntry entries. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static FifoPage *allocateFifoPage(int nEntry){ dbda8d6ce9 2007-07-21 drh: FifoPage *pPage; dbda8d6ce9 2007-07-21 drh: if( nEntry>32767 ){ dbda8d6ce9 2007-07-21 drh: nEntry = 32767; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pPage = sqlite3_malloc( sizeof(FifoPage) + sizeof(i64)*(nEntry-1) ); dbda8d6ce9 2007-07-21 drh: if( pPage ){ dbda8d6ce9 2007-07-21 drh: pPage->nSlot = nEntry; dbda8d6ce9 2007-07-21 drh: pPage->iWrite = 0; dbda8d6ce9 2007-07-21 drh: pPage->iRead = 0; dbda8d6ce9 2007-07-21 drh: pPage->pNext = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pPage; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Initialize a Fifo structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeFifoInit(Fifo *pFifo){ dbda8d6ce9 2007-07-21 drh: memset(pFifo, 0, sizeof(*pFifo)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Push a single 64-bit integer value into the Fifo. Return SQLITE_OK dbda8d6ce9 2007-07-21 drh: ** normally. SQLITE_NOMEM is returned if we are unable to allocate dbda8d6ce9 2007-07-21 drh: ** memory. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeFifoPush(Fifo *pFifo, i64 val){ dbda8d6ce9 2007-07-21 drh: FifoPage *pPage; dbda8d6ce9 2007-07-21 drh: pPage = pFifo->pLast; dbda8d6ce9 2007-07-21 drh: if( pPage==0 ){ dbda8d6ce9 2007-07-21 drh: pPage = pFifo->pLast = pFifo->pFirst = allocateFifoPage(20); dbda8d6ce9 2007-07-21 drh: if( pPage==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pPage->iWrite>=pPage->nSlot ){ dbda8d6ce9 2007-07-21 drh: pPage->pNext = allocateFifoPage(pFifo->nEntry); dbda8d6ce9 2007-07-21 drh: if( pPage->pNext==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPage = pFifo->pLast = pPage->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPage->aSlot[pPage->iWrite++] = val; dbda8d6ce9 2007-07-21 drh: pFifo->nEntry++; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Extract a single 64-bit integer value from the Fifo. The integer dbda8d6ce9 2007-07-21 drh: ** extracted is the one least recently inserted. If the Fifo is empty dbda8d6ce9 2007-07-21 drh: ** return SQLITE_DONE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeFifoPop(Fifo *pFifo, i64 *pVal){ dbda8d6ce9 2007-07-21 drh: FifoPage *pPage; dbda8d6ce9 2007-07-21 drh: if( pFifo->nEntry==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pFifo->nEntry>0 ); dbda8d6ce9 2007-07-21 drh: pPage = pFifo->pFirst; dbda8d6ce9 2007-07-21 drh: assert( pPage!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pPage->iWrite>pPage->iRead ); dbda8d6ce9 2007-07-21 drh: assert( pPage->iWrite<=pPage->nSlot ); dbda8d6ce9 2007-07-21 drh: assert( pPage->iRead<pPage->nSlot ); dbda8d6ce9 2007-07-21 drh: assert( pPage->iRead>=0 ); dbda8d6ce9 2007-07-21 drh: *pVal = pPage->aSlot[pPage->iRead++]; dbda8d6ce9 2007-07-21 drh: pFifo->nEntry--; dbda8d6ce9 2007-07-21 drh: if( pPage->iRead>=pPage->iWrite ){ dbda8d6ce9 2007-07-21 drh: pFifo->pFirst = pPage->pNext; c287665ba8 2007-09-14 drh: sqlite3_free(pPage); dbda8d6ce9 2007-07-21 drh: if( pFifo->nEntry==0 ){ dbda8d6ce9 2007-07-21 drh: assert( pFifo->pLast==pPage ); dbda8d6ce9 2007-07-21 drh: pFifo->pLast = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pFifo->pFirst!=0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pFifo->nEntry>0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete all information from a Fifo object. Free all memory held dbda8d6ce9 2007-07-21 drh: ** by the Fifo. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeFifoClear(Fifo *pFifo){ dbda8d6ce9 2007-07-21 drh: FifoPage *pPage, *pNextPage; dbda8d6ce9 2007-07-21 drh: for(pPage=pFifo->pFirst; pPage; pPage=pNextPage){ dbda8d6ce9 2007-07-21 drh: pNextPage = pPage->pNext; c287665ba8 2007-09-14 drh: sqlite3_free(pPage); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeFifoInit(pFifo); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vdbefifo.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vdbemem.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 May 26 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains code use to manipulate "Mem" structure. A "Mem" dbda8d6ce9 2007-07-21 drh: ** stores a single value in the VDBE. Mem is an opaque structure visible dbda8d6ce9 2007-07-21 drh: ** only within the VDBE. Interface routines refer to a Mem using the dbda8d6ce9 2007-07-21 drh: ** name sqlite_value dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) dbda8d6ce9 2007-07-21 drh: ** P if required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define expandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If pMem is an object with a valid string representation, this routine dbda8d6ce9 2007-07-21 drh: ** ensures the internal encoding for the string representation is dbda8d6ce9 2007-07-21 drh: ** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If pMem is not a string object, or the encoding of the string dbda8d6ce9 2007-07-21 drh: ** representation is already stored using the requested encoding, then this dbda8d6ce9 2007-07-21 drh: ** routine is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK is returned if the conversion is successful (or not required). dbda8d6ce9 2007-07-21 drh: ** SQLITE_NOMEM may be returned if a malloc() fails during conversion dbda8d6ce9 2007-07-21 drh: ** between formats. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned, dbda8d6ce9 2007-07-21 drh: ** then the encoding of the value may not have changed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemTranslate(pMem, desiredEnc); dbda8d6ce9 2007-07-21 drh: assert(rc==SQLITE_OK || rc==SQLITE_NOMEM); dbda8d6ce9 2007-07-21 drh: assert(rc==SQLITE_OK || pMem->enc!=desiredEnc); dbda8d6ce9 2007-07-21 drh: assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make the given Mem object MEM_Dyn. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemDynamicify(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: u8 *z; c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: expandBlob(pMem); dbda8d6ce9 2007-07-21 drh: if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: n = pMem->n; dbda8d6ce9 2007-07-21 drh: assert( pMem->flags & (MEM_Str|MEM_Blob) ); c287665ba8 2007-09-14 drh: z = sqlite3DbMallocRaw(pMem->db, n+2 ); dbda8d6ce9 2007-07-21 drh: if( z==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Dyn|MEM_Term; dbda8d6ce9 2007-07-21 drh: pMem->xDel = 0; dbda8d6ce9 2007-07-21 drh: memcpy(z, pMem->z, n ); dbda8d6ce9 2007-07-21 drh: z[n] = 0; dbda8d6ce9 2007-07-21 drh: z[n+1] = 0; dbda8d6ce9 2007-07-21 drh: pMem->z = (char*)z; dbda8d6ce9 2007-07-21 drh: pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the given Mem* has a zero-filled tail, turn it into an ordinary dbda8d6ce9 2007-07-21 drh: ** blob stored in dynamically allocated space. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: if( pMem->flags & MEM_Zero ){ dbda8d6ce9 2007-07-21 drh: char *pNew; dbda8d6ce9 2007-07-21 drh: int nByte; dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & MEM_Blob)!=0 ); dbda8d6ce9 2007-07-21 drh: nByte = pMem->n + pMem->u.i; dbda8d6ce9 2007-07-21 drh: if( nByte<=0 ) nByte = 1; c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocRaw(pMem->db, nByte); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(pNew, pMem->z, pMem->n); dbda8d6ce9 2007-07-21 drh: memset(&pNew[pMem->n], 0, pMem->u.i); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: pMem->z = pNew; dbda8d6ce9 2007-07-21 drh: pMem->n += pMem->u.i; dbda8d6ce9 2007-07-21 drh: pMem->u.i = 0; dbda8d6ce9 2007-07-21 drh: pMem->flags &= ~(MEM_Zero|MEM_Static|MEM_Ephem|MEM_Short|MEM_Term); dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Dyn; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes dbda8d6ce9 2007-07-21 drh: ** of the Mem.z[] array can be modified. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: u8 *z; c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: expandBlob(pMem); dbda8d6ce9 2007-07-21 drh: if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: assert( pMem->flags & (MEM_Str|MEM_Blob) ); dbda8d6ce9 2007-07-21 drh: if( (n = pMem->n)+2<sizeof(pMem->zShort) ){ dbda8d6ce9 2007-07-21 drh: z = (u8*)pMem->zShort; dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Short|MEM_Term; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: z = sqlite3DbMallocRaw(pMem->db, n+2 ); dbda8d6ce9 2007-07-21 drh: if( z==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Dyn|MEM_Term; dbda8d6ce9 2007-07-21 drh: pMem->xDel = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(z, pMem->z, n ); dbda8d6ce9 2007-07-21 drh: z[n] = 0; dbda8d6ce9 2007-07-21 drh: z[n+1] = 0; dbda8d6ce9 2007-07-21 drh: pMem->z = (char*)z; dbda8d6ce9 2007-07-21 drh: pMem->flags &= ~(MEM_Ephem|MEM_Static); dbda8d6ce9 2007-07-21 drh: assert(0==(1&(int)pMem->z)); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make sure the given Mem is \u0000 terminated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; /* Nothing to do */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pMem->flags & (MEM_Static|MEM_Ephem) ){ dbda8d6ce9 2007-07-21 drh: return sqlite3VdbeMemMakeWriteable(pMem); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemExpandBlob(pMem); c287665ba8 2007-09-14 drh: z = sqlite3DbMallocRaw(pMem->db, pMem->n+2); c287665ba8 2007-09-14 drh: if( !z ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(z, pMem->z, pMem->n); dbda8d6ce9 2007-07-21 drh: z[pMem->n] = 0; dbda8d6ce9 2007-07-21 drh: z[pMem->n+1] = 0; dbda8d6ce9 2007-07-21 drh: if( pMem->xDel ){ dbda8d6ce9 2007-07-21 drh: pMem->xDel(pMem->z); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: sqlite3_free(pMem->z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->xDel = 0; dbda8d6ce9 2007-07-21 drh: pMem->z = z; dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Term; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add MEM_Str to the set of representations for the given Mem. Numbers dbda8d6ce9 2007-07-21 drh: ** are converted using sqlite3_snprintf(). Converting a BLOB to a string dbda8d6ce9 2007-07-21 drh: ** is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Existing representations MEM_Int and MEM_Real are *not* invalidated. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A MEM_Null value will never be passed to this function. This function is dbda8d6ce9 2007-07-21 drh: ** used for converting values to text for returning to the user (i.e. via dbda8d6ce9 2007-07-21 drh: ** sqlite3_value_text()), or for ensuring that values to be used as btree dbda8d6ce9 2007-07-21 drh: ** keys are strings. In the former case a NULL pointer is returned the dbda8d6ce9 2007-07-21 drh: ** user and the later is an internal programming error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, int enc){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int fg = pMem->flags; dbda8d6ce9 2007-07-21 drh: char *z = pMem->zShort; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: assert( !(fg&MEM_Zero) ); dbda8d6ce9 2007-07-21 drh: assert( !(fg&(MEM_Str|MEM_Blob)) ); dbda8d6ce9 2007-07-21 drh: assert( fg&(MEM_Int|MEM_Real) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 dbda8d6ce9 2007-07-21 drh: ** string representation of the value. Then, if the required encoding dbda8d6ce9 2007-07-21 drh: ** is UTF-16le or UTF-16be do a translation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( fg & MEM_Int ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(NBFS, z, "%lld", pMem->u.i); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( fg & MEM_Real ); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->n = strlen(z); dbda8d6ce9 2007-07-21 drh: pMem->z = z; dbda8d6ce9 2007-07-21 drh: pMem->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Str | MEM_Short | MEM_Term; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeEncoding(pMem, enc); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Memory cell pMem contains the context of an aggregate function. dbda8d6ce9 2007-07-21 drh: ** This routine calls the finalize method for that function. The dbda8d6ce9 2007-07-21 drh: ** result of the aggregate is stored back into pMem. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK dbda8d6ce9 2007-07-21 drh: ** otherwise. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( pFunc && pFunc->xFinalize ){ dbda8d6ce9 2007-07-21 drh: sqlite3_context ctx; dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: ctx.s.flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: ctx.s.z = pMem->zShort; c287665ba8 2007-09-14 drh: ctx.s.db = pMem->db; dbda8d6ce9 2007-07-21 drh: ctx.pMem = pMem; dbda8d6ce9 2007-07-21 drh: ctx.pFunc = pFunc; dbda8d6ce9 2007-07-21 drh: ctx.isError = 0; dbda8d6ce9 2007-07-21 drh: pFunc->xFinalize(&ctx); dbda8d6ce9 2007-07-21 drh: if( pMem->z && pMem->z!=pMem->zShort ){ c287665ba8 2007-09-14 drh: sqlite3_free( pMem->z ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pMem = ctx.s; dbda8d6ce9 2007-07-21 drh: if( pMem->flags & MEM_Short ){ dbda8d6ce9 2007-07-21 drh: pMem->z = pMem->zShort; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: rc = (ctx.isError?SQLITE_ERROR:SQLITE_OK); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release any memory held by the Mem. This may leave the Mem in an dbda8d6ce9 2007-07-21 drh: ** inconsistent state, for example with (Mem.z==0) and dbda8d6ce9 2007-07-21 drh: ** (Mem.type==SQLITE_TEXT). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){ c287665ba8 2007-09-14 drh: assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); dbda8d6ce9 2007-07-21 drh: if( p->flags & (MEM_Dyn|MEM_Agg) ){ dbda8d6ce9 2007-07-21 drh: if( p->xDel ){ dbda8d6ce9 2007-07-21 drh: if( p->flags & MEM_Agg ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemFinalize(p, p->u.pDef); dbda8d6ce9 2007-07-21 drh: assert( (p->flags & MEM_Agg)==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(p); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: p->xDel((void *)p->z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: sqlite3_free(p->z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->z = 0; dbda8d6ce9 2007-07-21 drh: p->xDel = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return some kind of integer value which is the best we can do dbda8d6ce9 2007-07-21 drh: ** at representing the value that *pMem describes as an integer. dbda8d6ce9 2007-07-21 drh: ** If pMem is an integer, then the value is exact. If pMem is dbda8d6ce9 2007-07-21 drh: ** a floating-point then the value returned is the integer part. dbda8d6ce9 2007-07-21 drh: ** If pMem is a string or blob, then we make an attempt to convert dbda8d6ce9 2007-07-21 drh: ** it into a integer and return that. If pMem is NULL, return 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If pMem is a string, its encoding might be changed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ c287665ba8 2007-09-14 drh: int flags; c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); c287665ba8 2007-09-14 drh: flags = pMem->flags; dbda8d6ce9 2007-07-21 drh: if( flags & MEM_Int ){ dbda8d6ce9 2007-07-21 drh: return pMem->u.i; dbda8d6ce9 2007-07-21 drh: }else if( flags & MEM_Real ){ dbda8d6ce9 2007-07-21 drh: return (i64)pMem->r; dbda8d6ce9 2007-07-21 drh: }else if( flags & (MEM_Str|MEM_Blob) ){ dbda8d6ce9 2007-07-21 drh: i64 value; dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Str; dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8) dbda8d6ce9 2007-07-21 drh: || sqlite3VdbeMemNulTerminate(pMem) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pMem->z ); dbda8d6ce9 2007-07-21 drh: sqlite3Atoi64(pMem->z, &value); dbda8d6ce9 2007-07-21 drh: return value; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the best representation of pMem that we can get into a dbda8d6ce9 2007-07-21 drh: ** double. If pMem is already a double or an integer, return its dbda8d6ce9 2007-07-21 drh: ** value. If it is a string or blob, try to convert it to a double. dbda8d6ce9 2007-07-21 drh: ** If it is a NULL, return 0.0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pMem->flags & MEM_Real ){ dbda8d6ce9 2007-07-21 drh: return pMem->r; dbda8d6ce9 2007-07-21 drh: }else if( pMem->flags & MEM_Int ){ dbda8d6ce9 2007-07-21 drh: return (double)pMem->u.i; dbda8d6ce9 2007-07-21 drh: }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ dbda8d6ce9 2007-07-21 drh: double val = 0.0; dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Str; dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8) dbda8d6ce9 2007-07-21 drh: || sqlite3VdbeMemNulTerminate(pMem) ){ dbda8d6ce9 2007-07-21 drh: return 0.0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pMem->z ); dbda8d6ce9 2007-07-21 drh: sqlite3AtoF(pMem->z, &val); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 0.0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The MEM structure is already a MEM_Real. Try to also make it a dbda8d6ce9 2007-07-21 drh: ** MEM_Int if we can. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: assert( pMem->flags & MEM_Real ); c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: pMem->u.i = pMem->r; dbda8d6ce9 2007-07-21 drh: if( ((double)pMem->u.i)==pMem->r ){ dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Int; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert pMem to type integer. Invalidate any prior representations. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){ c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: pMem->u.i = sqlite3VdbeIntValue(pMem); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert pMem so that it is of type MEM_Real. dbda8d6ce9 2007-07-21 drh: ** Invalidate any prior representations. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: pMem->r = sqlite3VdbeRealValue(pMem); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Real; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert pMem so that it has types MEM_Real or MEM_Int or both. dbda8d6ce9 2007-07-21 drh: ** Invalidate any prior representations. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: double r1, r2; dbda8d6ce9 2007-07-21 drh: i64 i; dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ); dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: r1 = sqlite3VdbeRealValue(pMem); dbda8d6ce9 2007-07-21 drh: i = (i64)r1; dbda8d6ce9 2007-07-21 drh: r2 = (double)i; dbda8d6ce9 2007-07-21 drh: if( r1==r2 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pMem); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pMem->r = r1; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Real; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete any previous value and set the value stored in *pMem to NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_NULL; dbda8d6ce9 2007-07-21 drh: pMem->n = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete any previous value and set the value to be a BLOB of length dbda8d6ce9 2007-07-21 drh: ** n containing all zeros. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Blob|MEM_Zero|MEM_Short; dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_BLOB; dbda8d6ce9 2007-07-21 drh: pMem->n = 0; dbda8d6ce9 2007-07-21 drh: if( n<0 ) n = 0; dbda8d6ce9 2007-07-21 drh: pMem->u.i = n; dbda8d6ce9 2007-07-21 drh: pMem->z = pMem->zShort; dbda8d6ce9 2007-07-21 drh: pMem->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete any previous value and set the value stored in *pMem to val, dbda8d6ce9 2007-07-21 drh: ** manifest type INTEGER. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: pMem->u.i = val; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_INTEGER; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete any previous value and set the value stored in *pMem to val, dbda8d6ce9 2007-07-21 drh: ** manifest type REAL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ dbda8d6ce9 2007-07-21 drh: if( sqlite3_isnan(val) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetNull(pMem); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: pMem->r = val; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Real; dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_FLOAT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return true if the Mem object contains a TEXT or BLOB that is dbda8d6ce9 2007-07-21 drh: ** too large - whose size exceeds SQLITE_MAX_LENGTH. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){ dbda8d6ce9 2007-07-21 drh: if( p->flags & (MEM_Str|MEM_Blob) ){ dbda8d6ce9 2007-07-21 drh: int n = p->n; dbda8d6ce9 2007-07-21 drh: if( p->flags & MEM_Zero ){ dbda8d6ce9 2007-07-21 drh: n += p->u.i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return n>SQLITE_MAX_LENGTH; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make an shallow copy of pFrom into pTo. Prior contents of dbda8d6ce9 2007-07-21 drh: ** pTo are overwritten. The pFrom->z field is not duplicated. If dbda8d6ce9 2007-07-21 drh: ** pFrom->z is used, then pTo->z points to the same thing as pFrom->z dbda8d6ce9 2007-07-21 drh: ** and flags gets srcType (either MEM_Ephem or MEM_Static). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ dbda8d6ce9 2007-07-21 drh: memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); dbda8d6ce9 2007-07-21 drh: pTo->xDel = 0; dbda8d6ce9 2007-07-21 drh: if( pTo->flags & (MEM_Str|MEM_Blob) ){ dbda8d6ce9 2007-07-21 drh: pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short|MEM_Ephem); dbda8d6ce9 2007-07-21 drh: assert( srcType==MEM_Ephem || srcType==MEM_Static ); dbda8d6ce9 2007-07-21 drh: pTo->flags |= srcType; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make a full copy of pFrom into pTo. Prior contents of pTo are dbda8d6ce9 2007-07-21 drh: ** freed before the copy is made. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: if( pTo->flags & MEM_Dyn ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pTo); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem); dbda8d6ce9 2007-07-21 drh: if( pTo->flags & MEM_Ephem ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemMakeWriteable(pTo); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Transfer the contents of pFrom to pTo. Any existing value in pTo is dbda8d6ce9 2007-07-21 drh: ** freed. If pFrom contains ephemeral data, a copy is made. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pFrom contains an SQL NULL when this routine returns. SQLITE_NOMEM dbda8d6ce9 2007-07-21 drh: ** might be returned if pFrom held ephemeral data and we were unable dbda8d6ce9 2007-07-21 drh: ** to allocate enough space to make a copy. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: assert( pFrom->db==0 || sqlite3_mutex_held(pFrom->db->mutex) ); c287665ba8 2007-09-14 drh: assert( pTo->db==0 || sqlite3_mutex_held(pTo->db->mutex) ); c287665ba8 2007-09-14 drh: assert( pFrom->db==0 || pTo->db==0 || pFrom->db==pTo->db ); dbda8d6ce9 2007-07-21 drh: if( pTo->flags & MEM_Dyn ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pTo); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(pTo, pFrom, sizeof(Mem)); dbda8d6ce9 2007-07-21 drh: if( pFrom->flags & MEM_Short ){ dbda8d6ce9 2007-07-21 drh: pTo->z = pTo->zShort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pFrom->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: pFrom->xDel = 0; dbda8d6ce9 2007-07-21 drh: if( pTo->flags & MEM_Ephem ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemMakeWriteable(pTo); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the value of a Mem to be a string or a BLOB. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemSetStr( dbda8d6ce9 2007-07-21 drh: Mem *pMem, /* Memory cell to set to string value */ dbda8d6ce9 2007-07-21 drh: const char *z, /* String pointer */ dbda8d6ce9 2007-07-21 drh: int n, /* Bytes in string, or negative */ dbda8d6ce9 2007-07-21 drh: u8 enc, /* Encoding of z. 0 for BLOBs */ dbda8d6ce9 2007-07-21 drh: void (*xDel)(void*) /* Destructor function */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pMem); dbda8d6ce9 2007-07-21 drh: if( !z ){ dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_NULL; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->z = (char *)z; dbda8d6ce9 2007-07-21 drh: if( xDel==SQLITE_STATIC ){ dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Static; dbda8d6ce9 2007-07-21 drh: }else if( xDel==SQLITE_TRANSIENT ){ dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Ephem; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Dyn; dbda8d6ce9 2007-07-21 drh: pMem->xDel = xDel; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pMem->enc = enc; dbda8d6ce9 2007-07-21 drh: pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT; dbda8d6ce9 2007-07-21 drh: pMem->n = n; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( enc==0 || enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE dbda8d6ce9 2007-07-21 drh: || enc==SQLITE_UTF16BE ); dbda8d6ce9 2007-07-21 drh: switch( enc ){ dbda8d6ce9 2007-07-21 drh: case 0: dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Blob; dbda8d6ce9 2007-07-21 drh: pMem->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: case SQLITE_UTF8: dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Str; dbda8d6ce9 2007-07-21 drh: if( n<0 ){ dbda8d6ce9 2007-07-21 drh: pMem->n = strlen(z); dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Term; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: case SQLITE_UTF16LE: dbda8d6ce9 2007-07-21 drh: case SQLITE_UTF16BE: dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Str; dbda8d6ce9 2007-07-21 drh: if( pMem->n<0 ){ dbda8d6ce9 2007-07-21 drh: pMem->n = sqlite3Utf16ByteLen(pMem->z,-1); dbda8d6ce9 2007-07-21 drh: pMem->flags |= MEM_Term; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeMemHandleBom(pMem) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pMem->flags&MEM_Ephem ){ dbda8d6ce9 2007-07-21 drh: return sqlite3VdbeMemMakeWriteable(pMem); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compare the values contained by the two memory cells, returning dbda8d6ce9 2007-07-21 drh: ** negative, zero or positive if pMem1 is less than, equal to, or greater dbda8d6ce9 2007-07-21 drh: ** than pMem2. Sorting order is NULL's first, followed by numbers (integers dbda8d6ce9 2007-07-21 drh: ** and reals) sorted numerically, followed by text ordered by the collating dbda8d6ce9 2007-07-21 drh: ** sequence pColl and finally blob's ordered by memcmp(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Two NULL values are considered equal by this function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: int f1, f2; dbda8d6ce9 2007-07-21 drh: int combined_flags; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Interchange pMem1 and pMem2 if the collating sequence specifies dbda8d6ce9 2007-07-21 drh: ** DESC order. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: f1 = pMem1->flags; dbda8d6ce9 2007-07-21 drh: f2 = pMem2->flags; dbda8d6ce9 2007-07-21 drh: combined_flags = f1|f2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If one value is NULL, it is less than the other. If both values dbda8d6ce9 2007-07-21 drh: ** are NULL, return 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( combined_flags&MEM_Null ){ dbda8d6ce9 2007-07-21 drh: return (f2&MEM_Null) - (f1&MEM_Null); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If one value is a number and the other is not, the number is less. dbda8d6ce9 2007-07-21 drh: ** If both are numbers, compare as reals if one is a real, or as integers dbda8d6ce9 2007-07-21 drh: ** if both values are integers. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( combined_flags&(MEM_Int|MEM_Real) ){ dbda8d6ce9 2007-07-21 drh: if( !(f1&(MEM_Int|MEM_Real)) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !(f2&(MEM_Int|MEM_Real)) ){ dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (f1 & f2 & MEM_Int)==0 ){ dbda8d6ce9 2007-07-21 drh: double r1, r2; dbda8d6ce9 2007-07-21 drh: if( (f1&MEM_Real)==0 ){ dbda8d6ce9 2007-07-21 drh: r1 = pMem1->u.i; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: r1 = pMem1->r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (f2&MEM_Real)==0 ){ dbda8d6ce9 2007-07-21 drh: r2 = pMem2->u.i; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: r2 = pMem2->r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( r1<r2 ) return -1; dbda8d6ce9 2007-07-21 drh: if( r1>r2 ) return 1; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( f1&MEM_Int ); dbda8d6ce9 2007-07-21 drh: assert( f2&MEM_Int ); dbda8d6ce9 2007-07-21 drh: if( pMem1->u.i < pMem2->u.i ) return -1; dbda8d6ce9 2007-07-21 drh: if( pMem1->u.i > pMem2->u.i ) return 1; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If one value is a string and the other is a blob, the string is less. dbda8d6ce9 2007-07-21 drh: ** If both are strings, compare using the collating functions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( combined_flags&MEM_Str ){ dbda8d6ce9 2007-07-21 drh: if( (f1 & MEM_Str)==0 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (f2 & MEM_Str)==0 ){ dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pMem1->enc==pMem2->enc ); dbda8d6ce9 2007-07-21 drh: assert( pMem1->enc==SQLITE_UTF8 || dbda8d6ce9 2007-07-21 drh: pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The collation sequence must be defined at this point, even if dbda8d6ce9 2007-07-21 drh: ** the user deletes the collation sequence after the vdbe program is dbda8d6ce9 2007-07-21 drh: ** compiled (this was not always the case). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( !pColl || pColl->xCmp ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pColl ){ dbda8d6ce9 2007-07-21 drh: if( pMem1->enc==pColl->enc ){ dbda8d6ce9 2007-07-21 drh: /* The strings are already in the correct encoding. Call the dbda8d6ce9 2007-07-21 drh: ** comparison function directly */ dbda8d6ce9 2007-07-21 drh: return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: u8 origEnc = pMem1->enc; dbda8d6ce9 2007-07-21 drh: const void *v1, *v2; dbda8d6ce9 2007-07-21 drh: int n1, n2; dbda8d6ce9 2007-07-21 drh: /* Convert the strings into the encoding that the comparison dbda8d6ce9 2007-07-21 drh: ** function expects */ dbda8d6ce9 2007-07-21 drh: v1 = sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc); dbda8d6ce9 2007-07-21 drh: n1 = v1==0 ? 0 : pMem1->n; dbda8d6ce9 2007-07-21 drh: assert( n1==sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc) ); dbda8d6ce9 2007-07-21 drh: v2 = sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc); dbda8d6ce9 2007-07-21 drh: n2 = v2==0 ? 0 : pMem2->n; dbda8d6ce9 2007-07-21 drh: assert( n2==sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc) ); dbda8d6ce9 2007-07-21 drh: /* Do the comparison */ dbda8d6ce9 2007-07-21 drh: rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); dbda8d6ce9 2007-07-21 drh: /* Convert the strings back into the database encoding */ dbda8d6ce9 2007-07-21 drh: sqlite3ValueText((sqlite3_value*)pMem1, origEnc); dbda8d6ce9 2007-07-21 drh: sqlite3ValueText((sqlite3_value*)pMem2, origEnc); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* If a NULL pointer was passed as the collate function, fall through dbda8d6ce9 2007-07-21 drh: ** to the blob case and use memcmp(). */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Both values must be blobs. Compare using memcmp(). */ dbda8d6ce9 2007-07-21 drh: rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); dbda8d6ce9 2007-07-21 drh: if( rc==0 ){ dbda8d6ce9 2007-07-21 drh: rc = pMem1->n - pMem2->n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Move data out of a btree key or data field and into a Mem structure. dbda8d6ce9 2007-07-21 drh: ** The data or key is taken from the entry that pCur is currently pointing dbda8d6ce9 2007-07-21 drh: ** to. offset and amt determine what portion of the data or key to retrieve. dbda8d6ce9 2007-07-21 drh: ** key is true to get the key or false to get data. The result is written dbda8d6ce9 2007-07-21 drh: ** into the pMem element. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pMem structure is assumed to be uninitialized. Any prior content dbda8d6ce9 2007-07-21 drh: ** is overwritten without being freed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If this routine fails for any reason (malloc returns NULL or unable dbda8d6ce9 2007-07-21 drh: ** to read from the disk) then the pMem is left in an inconsistent state. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( dbda8d6ce9 2007-07-21 drh: BtCursor *pCur, /* Cursor pointing at record to retrieve. */ dbda8d6ce9 2007-07-21 drh: int offset, /* Offset from the start of data to return bytes from. */ dbda8d6ce9 2007-07-21 drh: int amt, /* Number of bytes to return. */ dbda8d6ce9 2007-07-21 drh: int key, /* If true, retrieve from the btree key, not data. */ dbda8d6ce9 2007-07-21 drh: Mem *pMem /* OUT: Return data in this Mem structure. */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: char *zData; /* Data from the btree layer */ dbda8d6ce9 2007-07-21 drh: int available = 0; /* Number of bytes available on the local btree page */ c287665ba8 2007-09-14 drh: sqlite3 *db; /* Database connection */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: db = sqlite3BtreeCursorDb(pCur); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: if( key ){ dbda8d6ce9 2007-07-21 drh: zData = (char *)sqlite3BtreeKeyFetch(pCur, &available); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zData = (char *)sqlite3BtreeDataFetch(pCur, &available); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( zData!=0 ); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pMem->db = db; dbda8d6ce9 2007-07-21 drh: pMem->n = amt; dbda8d6ce9 2007-07-21 drh: if( offset+amt<=available ){ dbda8d6ce9 2007-07-21 drh: pMem->z = &zData[offset]; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Blob|MEM_Ephem; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: if( amt>NBFS-2 ){ c287665ba8 2007-09-14 drh: zData = (char *)sqlite3DbMallocRaw(db, amt+2); dbda8d6ce9 2007-07-21 drh: if( !zData ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term; dbda8d6ce9 2007-07-21 drh: pMem->xDel = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zData = &(pMem->zShort[0]); dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Blob|MEM_Short|MEM_Term; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->z = zData; dbda8d6ce9 2007-07-21 drh: pMem->enc = 0; dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_BLOB; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( key ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeKey(pCur, offset, amt, zData); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeData(pCur, offset, amt, zData); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zData[amt] = 0; dbda8d6ce9 2007-07-21 drh: zData[amt+1] = 0; dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( amt>NBFS-2 ){ dbda8d6ce9 2007-07-21 drh: assert( zData!=pMem->zShort ); dbda8d6ce9 2007-07-21 drh: assert( pMem->flags & MEM_Dyn ); c287665ba8 2007-09-14 drh: sqlite3_free(zData); dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: assert( zData==pMem->zShort ); dbda8d6ce9 2007-07-21 drh: assert( pMem->flags & MEM_Short ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Perform various checks on the memory cell pMem. An assert() will dbda8d6ce9 2007-07-21 drh: ** fail if pMem is internally inconsistent. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemSanity(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: int flags = pMem->flags; dbda8d6ce9 2007-07-21 drh: assert( flags!=0 ); /* Must define some type */ dbda8d6ce9 2007-07-21 drh: if( flags & (MEM_Str|MEM_Blob) ){ dbda8d6ce9 2007-07-21 drh: int x = flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); dbda8d6ce9 2007-07-21 drh: assert( x!=0 ); /* Strings must define a string subtype */ dbda8d6ce9 2007-07-21 drh: assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */ dbda8d6ce9 2007-07-21 drh: assert( pMem->z!=0 ); /* Strings must have a value */ dbda8d6ce9 2007-07-21 drh: /* Mem.z points to Mem.zShort iff the subtype is MEM_Short */ dbda8d6ce9 2007-07-21 drh: assert( (x & MEM_Short)==0 || pMem->z==pMem->zShort ); dbda8d6ce9 2007-07-21 drh: assert( (x & MEM_Short)!=0 || pMem->z!=pMem->zShort ); dbda8d6ce9 2007-07-21 drh: /* No destructor unless there is MEM_Dyn */ dbda8d6ce9 2007-07-21 drh: assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( (flags & MEM_Str) ){ dbda8d6ce9 2007-07-21 drh: assert( pMem->enc==SQLITE_UTF8 || dbda8d6ce9 2007-07-21 drh: pMem->enc==SQLITE_UTF16BE || dbda8d6ce9 2007-07-21 drh: pMem->enc==SQLITE_UTF16LE dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: /* If the string is UTF-8 encoded and nul terminated, then pMem->n dbda8d6ce9 2007-07-21 drh: ** must be the length of the string. (Later:) If the database file dbda8d6ce9 2007-07-21 drh: ** has been corrupted, '\000' characters might have been inserted dbda8d6ce9 2007-07-21 drh: ** into the middle of the string. In that case, the strlen() might dbda8d6ce9 2007-07-21 drh: ** be less. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pMem->enc==SQLITE_UTF8 && (flags & MEM_Term) ){ dbda8d6ce9 2007-07-21 drh: assert( strlen(pMem->z)<=pMem->n ); dbda8d6ce9 2007-07-21 drh: assert( pMem->z[pMem->n]==0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Cannot define a string subtype for non-string objects */ dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short))==0 ); dbda8d6ce9 2007-07-21 drh: assert( pMem->xDel==0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* MEM_Null excludes all other types */ dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags&(MEM_Str|MEM_Int|MEM_Real|MEM_Blob))==0 dbda8d6ce9 2007-07-21 drh: || (pMem->flags&MEM_Null)==0 ); dbda8d6ce9 2007-07-21 drh: /* If the MEM is both real and integer, the values are equal */ dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) dbda8d6ce9 2007-07-21 drh: || pMem->r==pMem->u.i ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This function is only available internally, it is not part of the dbda8d6ce9 2007-07-21 drh: ** external API. It works in a similar way to sqlite3_value_text(), dbda8d6ce9 2007-07-21 drh: ** except the data returned is in the encoding specified by the second dbda8d6ce9 2007-07-21 drh: ** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or dbda8d6ce9 2007-07-21 drh: ** SQLITE_UTF8. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED. dbda8d6ce9 2007-07-21 drh: ** If that is the case, then the result must be aligned on an even byte dbda8d6ce9 2007-07-21 drh: ** boundary. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ dbda8d6ce9 2007-07-21 drh: if( !pVal ) return 0; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); dbda8d6ce9 2007-07-21 drh: assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pVal->flags&MEM_Null ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( (MEM_Blob>>3) == MEM_Str ); dbda8d6ce9 2007-07-21 drh: pVal->flags |= (pVal->flags & MEM_Blob)>>3; dbda8d6ce9 2007-07-21 drh: expandBlob(pVal); dbda8d6ce9 2007-07-21 drh: if( pVal->flags&MEM_Str ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); dbda8d6ce9 2007-07-21 drh: if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){ dbda8d6ce9 2007-07-21 drh: assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemNulTerminate(pVal); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( (pVal->flags&MEM_Blob)==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemStringify(pVal, enc); dbda8d6ce9 2007-07-21 drh: assert( 0==(1&(int)pVal->z) ); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 c287665ba8 2007-09-14 drh: || pVal->db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ dbda8d6ce9 2007-07-21 drh: return pVal->z; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new sqlite3_value object. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *db){ c287665ba8 2007-09-14 drh: Mem *p = sqlite3DbMallocZero(db, sizeof(*p)); dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: p->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: p->type = SQLITE_NULL; c287665ba8 2007-09-14 drh: p->db = db; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new sqlite3_value object, containing the value of pExpr. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This only works for very simple expressions that consist of one constant dbda8d6ce9 2007-07-21 drh: ** token (i.e. "5", "5.1", "NULL", "'a string'"). If the expression can dbda8d6ce9 2007-07-21 drh: ** be converted directly into a value, then the value is allocated and dbda8d6ce9 2007-07-21 drh: ** a pointer written to *ppVal. The caller is responsible for deallocating dbda8d6ce9 2007-07-21 drh: ** the value by passing it to sqlite3ValueFree() later on. If the expression dbda8d6ce9 2007-07-21 drh: ** cannot be converted to a value, then *ppVal is set to NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ValueFromExpr( c287665ba8 2007-09-14 drh: sqlite3 *db, /* The database connection */ c287665ba8 2007-09-14 drh: Expr *pExpr, /* The expression to evaluate */ c287665ba8 2007-09-14 drh: u8 enc, /* Encoding to use */ c287665ba8 2007-09-14 drh: u8 affinity, /* Affinity to use */ c287665ba8 2007-09-14 drh: sqlite3_value **ppVal /* Write the new value here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int op; dbda8d6ce9 2007-07-21 drh: char *zVal = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_value *pVal = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pExpr ){ dbda8d6ce9 2007-07-21 drh: *ppVal = 0; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: op = pExpr->op; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ c287665ba8 2007-09-14 drh: zVal = sqlite3StrNDup((char*)pExpr->token.z, pExpr->token.n); c287665ba8 2007-09-14 drh: pVal = sqlite3ValueNew(db); dbda8d6ce9 2007-07-21 drh: if( !zVal || !pVal ) goto no_mem; dbda8d6ce9 2007-07-21 drh: sqlite3Dequote(zVal); c287665ba8 2007-09-14 drh: sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, sqlite3_free); dbda8d6ce9 2007-07-21 drh: if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){ dbda8d6ce9 2007-07-21 drh: sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, enc); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ValueApplyAffinity(pVal, affinity, enc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( op==TK_UMINUS ) { c287665ba8 2007-09-14 drh: if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){ dbda8d6ce9 2007-07-21 drh: pVal->u.i = -1 * pVal->u.i; dbda8d6ce9 2007-07-21 drh: pVal->r = -1.0 * pVal->r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_BLOB_LITERAL dbda8d6ce9 2007-07-21 drh: else if( op==TK_BLOB ){ dbda8d6ce9 2007-07-21 drh: int nVal; c287665ba8 2007-09-14 drh: pVal = sqlite3ValueNew(db); c287665ba8 2007-09-14 drh: zVal = sqlite3StrNDup((char*)pExpr->token.z+1, pExpr->token.n-1); dbda8d6ce9 2007-07-21 drh: if( !zVal || !pVal ) goto no_mem; dbda8d6ce9 2007-07-21 drh: sqlite3Dequote(zVal); dbda8d6ce9 2007-07-21 drh: nVal = strlen(zVal)/2; c287665ba8 2007-09-14 drh: sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal), nVal,0,sqlite3_free); c287665ba8 2007-09-14 drh: sqlite3_free(zVal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: *ppVal = pVal; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: no_mem: c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: sqlite3_free(zVal); dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree(pVal); dbda8d6ce9 2007-07-21 drh: *ppVal = 0; dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the string value of an sqlite3_value object dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ValueSetStr( c287665ba8 2007-09-14 drh: sqlite3_value *v, /* Value to be set */ c287665ba8 2007-09-14 drh: int n, /* Length of string z */ c287665ba8 2007-09-14 drh: const void *z, /* Text of the new string */ c287665ba8 2007-09-14 drh: u8 enc, /* Encoding to use */ c287665ba8 2007-09-14 drh: void (*xDel)(void*) /* Destructor for the string */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( v ) sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, xDel); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Free an sqlite3_value object dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){ dbda8d6ce9 2007-07-21 drh: if( !v ) return; dbda8d6ce9 2007-07-21 drh: sqlite3ValueSetStr(v, 0, 0, SQLITE_UTF8, SQLITE_STATIC); c287665ba8 2007-09-14 drh: sqlite3_free(v); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of bytes in the sqlite3_value object assuming dbda8d6ce9 2007-07-21 drh: ** that it uses the encoding "enc" dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ dbda8d6ce9 2007-07-21 drh: Mem *p = (Mem*)pVal; dbda8d6ce9 2007-07-21 drh: if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){ dbda8d6ce9 2007-07-21 drh: if( p->flags & MEM_Zero ){ dbda8d6ce9 2007-07-21 drh: return p->n+p->u.i; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return p->n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vdbemem.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vdbeaux.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2003 September 6 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code used for creating, destroying, and populating dbda8d6ce9 2007-07-21 drh: ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior dbda8d6ce9 2007-07-21 drh: ** to version 2.8.7, all this code was combined into the vdbe.c source file. dbda8d6ce9 2007-07-21 drh: ** But that file was getting too big so this subroutines were split out. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** When debugging the code generator in a symbolic debugger, one can dbda8d6ce9 2007-07-21 drh: ** set the sqlite3_vdbe_addop_trace to 1 and all opcodes will be printed dbda8d6ce9 2007-07-21 drh: ** as they are added to the instruction stream. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_vdbe_addop_trace = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new virtual database engine. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: Vdbe *p; c287665ba8 2007-09-14 drh: p = sqlite3DbMallocZero(db, sizeof(Vdbe) ); dbda8d6ce9 2007-07-21 drh: if( p==0 ) return 0; dbda8d6ce9 2007-07-21 drh: p->db = db; dbda8d6ce9 2007-07-21 drh: if( db->pVdbe ){ dbda8d6ce9 2007-07-21 drh: db->pVdbe->pPrev = p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->pNext = db->pVdbe; dbda8d6ce9 2007-07-21 drh: p->pPrev = 0; dbda8d6ce9 2007-07-21 drh: db->pVdbe = p; dbda8d6ce9 2007-07-21 drh: p->magic = VDBE_MAGIC_INIT; dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Remember the SQL string for a prepared statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){ dbda8d6ce9 2007-07-21 drh: if( p==0 ) return; dbda8d6ce9 2007-07-21 drh: assert( p->zSql==0 ); c287665ba8 2007-09-14 drh: p->zSql = sqlite3DbStrNDup(p->db, z, n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the SQL associated with a prepared statement dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3VdbeGetSql(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: return p->zSql; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Swap all content between two VDBE structures. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ dbda8d6ce9 2007-07-21 drh: Vdbe tmp, *pTmp; dbda8d6ce9 2007-07-21 drh: char *zTmp; dbda8d6ce9 2007-07-21 drh: int nTmp; dbda8d6ce9 2007-07-21 drh: tmp = *pA; dbda8d6ce9 2007-07-21 drh: *pA = *pB; dbda8d6ce9 2007-07-21 drh: *pB = tmp; dbda8d6ce9 2007-07-21 drh: pTmp = pA->pNext; dbda8d6ce9 2007-07-21 drh: pA->pNext = pB->pNext; dbda8d6ce9 2007-07-21 drh: pB->pNext = pTmp; dbda8d6ce9 2007-07-21 drh: pTmp = pA->pPrev; dbda8d6ce9 2007-07-21 drh: pA->pPrev = pB->pPrev; dbda8d6ce9 2007-07-21 drh: pB->pPrev = pTmp; dbda8d6ce9 2007-07-21 drh: zTmp = pA->zSql; dbda8d6ce9 2007-07-21 drh: pA->zSql = pB->zSql; dbda8d6ce9 2007-07-21 drh: pB->zSql = zTmp; dbda8d6ce9 2007-07-21 drh: nTmp = pA->nSql; dbda8d6ce9 2007-07-21 drh: pA->nSql = pB->nSql; dbda8d6ce9 2007-07-21 drh: pB->nSql = nTmp; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Turn tracing on or off dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeTrace(Vdbe *p, FILE *trace){ dbda8d6ce9 2007-07-21 drh: p->trace = trace; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Resize the Vdbe.aOp array so that it contains at least N dbda8d6ce9 2007-07-21 drh: ** elements. If the Vdbe is in VDBE_MAGIC_RUN state, then dbda8d6ce9 2007-07-21 drh: ** the Vdbe.aOp array will be sized to contain exactly N dbda8d6ce9 2007-07-21 drh: ** elements. Vdbe.nOpAlloc is set to reflect the new size of dbda8d6ce9 2007-07-21 drh: ** the array. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an out-of-memory error occurs while resizing the array, dbda8d6ce9 2007-07-21 drh: ** Vdbe.aOp and Vdbe.nOpAlloc remain unchanged (this is so that dbda8d6ce9 2007-07-21 drh: ** any opcodes already allocated can be correctly deallocated dbda8d6ce9 2007-07-21 drh: ** along with the rest of the Vdbe). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void resizeOpArray(Vdbe *p, int N){ dbda8d6ce9 2007-07-21 drh: int runMode = p->magic==VDBE_MAGIC_RUN; dbda8d6ce9 2007-07-21 drh: if( runMode || p->nOpAlloc<N ){ dbda8d6ce9 2007-07-21 drh: VdbeOp *pNew; dbda8d6ce9 2007-07-21 drh: int nNew = N + 100*(!runMode); dbda8d6ce9 2007-07-21 drh: int oldSize = p->nOpAlloc; c287665ba8 2007-09-14 drh: pNew = sqlite3DbRealloc(p->db, p->aOp, nNew*sizeof(Op)); dbda8d6ce9 2007-07-21 drh: if( pNew ){ dbda8d6ce9 2007-07-21 drh: p->nOpAlloc = nNew; dbda8d6ce9 2007-07-21 drh: p->aOp = pNew; dbda8d6ce9 2007-07-21 drh: if( nNew>oldSize ){ dbda8d6ce9 2007-07-21 drh: memset(&p->aOp[oldSize], 0, (nNew-oldSize)*sizeof(Op)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a new instruction to the list of instructions current in the dbda8d6ce9 2007-07-21 drh: ** VDBE. Return the address of the new instruction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Parameters: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** p Pointer to the VDBE dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** op The opcode for this instruction dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** p1, p2 First two of the three possible operands. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Use the sqlite3VdbeResolveLabel() function to fix an address and dbda8d6ce9 2007-07-21 drh: ** the sqlite3VdbeChangeP3() function to change the value of the P3 dbda8d6ce9 2007-07-21 drh: ** operand. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: VdbeOp *pOp; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: i = p->nOp; dbda8d6ce9 2007-07-21 drh: assert( p->magic==VDBE_MAGIC_INIT ); dbda8d6ce9 2007-07-21 drh: if( p->nOpAlloc<=i ){ dbda8d6ce9 2007-07-21 drh: resizeOpArray(p, i+1); c287665ba8 2007-09-14 drh: if( p->db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->nOp++; dbda8d6ce9 2007-07-21 drh: pOp = &p->aOp[i]; dbda8d6ce9 2007-07-21 drh: pOp->opcode = op; dbda8d6ce9 2007-07-21 drh: pOp->p1 = p1; dbda8d6ce9 2007-07-21 drh: pOp->p2 = p2; dbda8d6ce9 2007-07-21 drh: pOp->p3 = 0; dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_NOTUSED; dbda8d6ce9 2007-07-21 drh: p->expired = 0; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add an opcode that includes the p3 value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3,int p3type){ dbda8d6ce9 2007-07-21 drh: int addr = sqlite3VdbeAddOp(p, op, p1, p2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(p, addr, zP3, p3type); dbda8d6ce9 2007-07-21 drh: return addr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new symbolic label for an instruction that has yet to be dbda8d6ce9 2007-07-21 drh: ** coded. The symbolic label is really just a negative number. The dbda8d6ce9 2007-07-21 drh: ** label can be used as the P2 value of an operation. Later, when dbda8d6ce9 2007-07-21 drh: ** the label is resolved to a specific address, the VDBE will scan dbda8d6ce9 2007-07-21 drh: ** through its operation list and change all values of P2 which match dbda8d6ce9 2007-07-21 drh: ** the label into the resolved address. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The VDBE knows that a P2 value is a label because labels are dbda8d6ce9 2007-07-21 drh: ** always negative and P2 values are suppose to be non-negative. dbda8d6ce9 2007-07-21 drh: ** Hence, a negative P2 value is a label that has yet to be resolved. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Zero is returned if a malloc() fails. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: i = p->nLabel++; dbda8d6ce9 2007-07-21 drh: assert( p->magic==VDBE_MAGIC_INIT ); dbda8d6ce9 2007-07-21 drh: if( i>=p->nLabelAlloc ){ dbda8d6ce9 2007-07-21 drh: p->nLabelAlloc = p->nLabelAlloc*2 + 10; c287665ba8 2007-09-14 drh: p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, dbda8d6ce9 2007-07-21 drh: p->nLabelAlloc*sizeof(p->aLabel[0])); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->aLabel ){ dbda8d6ce9 2007-07-21 drh: p->aLabel[i] = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return -1-i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Resolve label "x" to be the address of the next instruction to dbda8d6ce9 2007-07-21 drh: ** be inserted. The parameter "x" must have been obtained from dbda8d6ce9 2007-07-21 drh: ** a prior call to sqlite3VdbeMakeLabel(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *p, int x){ dbda8d6ce9 2007-07-21 drh: int j = -1-x; dbda8d6ce9 2007-07-21 drh: assert( p->magic==VDBE_MAGIC_INIT ); dbda8d6ce9 2007-07-21 drh: assert( j>=0 && j<p->nLabel ); dbda8d6ce9 2007-07-21 drh: if( p->aLabel ){ dbda8d6ce9 2007-07-21 drh: p->aLabel[j] = p->nOp; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return non-zero if opcode 'op' is guarenteed not to push more values dbda8d6ce9 2007-07-21 drh: ** onto the VDBE stack than it pops off. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int opcodeNoPush(u8 op){ dbda8d6ce9 2007-07-21 drh: /* The 10 NOPUSH_MASK_n constants are defined in the automatically dbda8d6ce9 2007-07-21 drh: ** generated header file opcodes.h. Each is a 16-bit bitmask, one dbda8d6ce9 2007-07-21 drh: ** bit corresponding to each opcode implemented by the virtual dbda8d6ce9 2007-07-21 drh: ** machine in vdbe.c. The bit is true if the word "no-push" appears dbda8d6ce9 2007-07-21 drh: ** in a comment on the same line as the "case OP_XXX:" in dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeExec() in vdbe.c. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the bit is true, then the corresponding opcode is guarenteed not dbda8d6ce9 2007-07-21 drh: ** to grow the stack when it is executed. Otherwise, it may grow the dbda8d6ce9 2007-07-21 drh: ** stack by at most one entry. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** NOPUSH_MASK_0 corresponds to opcodes 0 to 15. NOPUSH_MASK_1 contains dbda8d6ce9 2007-07-21 drh: ** one bit for opcodes 16 to 31, and so on. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 16-bit bitmasks (rather than 32-bit) are specified in opcodes.h dbda8d6ce9 2007-07-21 drh: ** because the file is generated by an awk program. Awk manipulates dbda8d6ce9 2007-07-21 drh: ** all numbers as floating-point and we don't want to risk a rounding dbda8d6ce9 2007-07-21 drh: ** error if someone builds with an awk that uses (for example) 32-bit dbda8d6ce9 2007-07-21 drh: ** IEEE floats. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const u32 masks[5] = { dbda8d6ce9 2007-07-21 drh: NOPUSH_MASK_0 + (((unsigned)NOPUSH_MASK_1)<<16), dbda8d6ce9 2007-07-21 drh: NOPUSH_MASK_2 + (((unsigned)NOPUSH_MASK_3)<<16), dbda8d6ce9 2007-07-21 drh: NOPUSH_MASK_4 + (((unsigned)NOPUSH_MASK_5)<<16), dbda8d6ce9 2007-07-21 drh: NOPUSH_MASK_6 + (((unsigned)NOPUSH_MASK_7)<<16), dbda8d6ce9 2007-07-21 drh: NOPUSH_MASK_8 + (((unsigned)NOPUSH_MASK_9)<<16) dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: assert( op<32*5 ); dbda8d6ce9 2007-07-21 drh: return (masks[op>>5] & (1<<(op&0x1F))); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeOpcodeNoPush(u8 op){ dbda8d6ce9 2007-07-21 drh: return opcodeNoPush(op); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Loop through the program looking for P2 values that are negative. dbda8d6ce9 2007-07-21 drh: ** Each such value is a label. Resolve the label by setting the P2 dbda8d6ce9 2007-07-21 drh: ** value to its correct non-zero value. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is called once after all opcodes have been inserted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument dbda8d6ce9 2007-07-21 drh: ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The integer *pMaxStack is set to the maximum number of vdbe stack dbda8d6ce9 2007-07-21 drh: ** entries that static analysis reveals this program might need. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine also does the following optimization: It scans for dbda8d6ce9 2007-07-21 drh: ** Halt instructions where P1==SQLITE_CONSTRAINT or P2==OE_Abort or for dbda8d6ce9 2007-07-21 drh: ** IdxInsert instructions where P2!=0. If no such instruction is dbda8d6ce9 2007-07-21 drh: ** found, then every Statement instruction is changed to a Noop. In dbda8d6ce9 2007-07-21 drh: ** this way, we avoid creating the statement journal file unnecessarily. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nMaxArgs = 0; dbda8d6ce9 2007-07-21 drh: int nMaxStack = p->nOp; dbda8d6ce9 2007-07-21 drh: Op *pOp; dbda8d6ce9 2007-07-21 drh: int *aLabel = p->aLabel; dbda8d6ce9 2007-07-21 drh: int doesStatementRollback = 0; dbda8d6ce9 2007-07-21 drh: int hasStatementBegin = 0; dbda8d6ce9 2007-07-21 drh: for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ dbda8d6ce9 2007-07-21 drh: u8 opcode = pOp->opcode; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( opcode==OP_Function || opcode==OP_AggStep dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: || opcode==OP_VUpdate dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( opcode==OP_Halt ){ dbda8d6ce9 2007-07-21 drh: if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ dbda8d6ce9 2007-07-21 drh: doesStatementRollback = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( opcode==OP_Statement ){ dbda8d6ce9 2007-07-21 drh: hasStatementBegin = 1; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: }else if( opcode==OP_VUpdate || opcode==OP_VRename ){ dbda8d6ce9 2007-07-21 drh: doesStatementRollback = 1; dbda8d6ce9 2007-07-21 drh: }else if( opcode==OP_VFilter ){ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: assert( p->nOp - i >= 3 ); dbda8d6ce9 2007-07-21 drh: assert( pOp[-2].opcode==OP_Integer ); dbda8d6ce9 2007-07-21 drh: n = pOp[-2].p1; dbda8d6ce9 2007-07-21 drh: if( n>nMaxArgs ) nMaxArgs = n; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( opcodeNoPush(opcode) ){ dbda8d6ce9 2007-07-21 drh: nMaxStack--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pOp->p2>=0 ) continue; dbda8d6ce9 2007-07-21 drh: assert( -1-pOp->p2<p->nLabel ); dbda8d6ce9 2007-07-21 drh: pOp->p2 = aLabel[-1-pOp->p2]; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(p->aLabel); dbda8d6ce9 2007-07-21 drh: p->aLabel = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: *pMaxFuncArgs = nMaxArgs; dbda8d6ce9 2007-07-21 drh: *pMaxStack = nMaxStack; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we never rollback a statement transaction, then statement dbda8d6ce9 2007-07-21 drh: ** transactions are not needed. So change every OP_Statement dbda8d6ce9 2007-07-21 drh: ** opcode into an OP_Noop. This avoid a call to sqlite3OsOpenExclusive() dbda8d6ce9 2007-07-21 drh: ** which can be expensive on some platforms. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( hasStatementBegin && !doesStatementRollback ){ dbda8d6ce9 2007-07-21 drh: for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_Statement ){ dbda8d6ce9 2007-07-21 drh: pOp->opcode = OP_Noop; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the address of the next instruction to be inserted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: assert( p->magic==VDBE_MAGIC_INIT ); dbda8d6ce9 2007-07-21 drh: return p->nOp; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a whole list of operations to the operation stack. Return the dbda8d6ce9 2007-07-21 drh: ** address of the first operation added. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: assert( p->magic==VDBE_MAGIC_INIT ); dbda8d6ce9 2007-07-21 drh: resizeOpArray(p, p->nOp + nOp); c287665ba8 2007-09-14 drh: if( p->db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: addr = p->nOp; dbda8d6ce9 2007-07-21 drh: if( nOp>0 ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: VdbeOpList const *pIn = aOp; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nOp; i++, pIn++){ dbda8d6ce9 2007-07-21 drh: int p2 = pIn->p2; dbda8d6ce9 2007-07-21 drh: VdbeOp *pOut = &p->aOp[i+addr]; dbda8d6ce9 2007-07-21 drh: pOut->opcode = pIn->opcode; dbda8d6ce9 2007-07-21 drh: pOut->p1 = pIn->p1; dbda8d6ce9 2007-07-21 drh: pOut->p2 = p2<0 ? addr + ADDR(p2) : p2; dbda8d6ce9 2007-07-21 drh: pOut->p3 = pIn->p3; dbda8d6ce9 2007-07-21 drh: pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: if( sqlite3_vdbe_addop_trace ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->nOp += nOp; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return addr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the value of the P1 operand for a specific instruction. dbda8d6ce9 2007-07-21 drh: ** This routine is useful when a large program is loaded from a dbda8d6ce9 2007-07-21 drh: ** static array using sqlite3VdbeAddOpList but we want to make a dbda8d6ce9 2007-07-21 drh: ** few minor changes to the program. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ dbda8d6ce9 2007-07-21 drh: assert( p==0 || p->magic==VDBE_MAGIC_INIT ); dbda8d6ce9 2007-07-21 drh: if( p && addr>=0 && p->nOp>addr && p->aOp ){ dbda8d6ce9 2007-07-21 drh: p->aOp[addr].p1 = val; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the value of the P2 operand for a specific instruction. dbda8d6ce9 2007-07-21 drh: ** This routine is useful for setting a jump destination. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ dbda8d6ce9 2007-07-21 drh: assert( val>=0 ); dbda8d6ce9 2007-07-21 drh: assert( p==0 || p->magic==VDBE_MAGIC_INIT ); dbda8d6ce9 2007-07-21 drh: if( p && addr>=0 && p->nOp>addr && p->aOp ){ dbda8d6ce9 2007-07-21 drh: p->aOp[addr].p2 = val; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the P2 operand of instruction addr so that it points to dbda8d6ce9 2007-07-21 drh: ** the address of the next instruction to be coded. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(p, addr, p->nOp); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the input FuncDef structure is ephemeral, then free it. If dbda8d6ce9 2007-07-21 drh: ** the FuncDef is not ephermal, then do nothing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void freeEphemeralFunction(FuncDef *pDef){ dbda8d6ce9 2007-07-21 drh: if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(pDef); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete a P3 value if necessary. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void freeP3(int p3type, void *p3){ dbda8d6ce9 2007-07-21 drh: if( p3 ){ dbda8d6ce9 2007-07-21 drh: switch( p3type ){ dbda8d6ce9 2007-07-21 drh: case P3_DYNAMIC: dbda8d6ce9 2007-07-21 drh: case P3_KEYINFO: dbda8d6ce9 2007-07-21 drh: case P3_KEYINFO_HANDOFF: { c287665ba8 2007-09-14 drh: sqlite3_free(p3); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case P3_MPRINTF: { dbda8d6ce9 2007-07-21 drh: sqlite3_free(p3); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case P3_VDBEFUNC: { dbda8d6ce9 2007-07-21 drh: VdbeFunc *pVdbeFunc = (VdbeFunc *)p3; dbda8d6ce9 2007-07-21 drh: freeEphemeralFunction(pVdbeFunc->pFunc); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); c287665ba8 2007-09-14 drh: sqlite3_free(pVdbeFunc); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case P3_FUNCDEF: { dbda8d6ce9 2007-07-21 drh: freeEphemeralFunction((FuncDef*)p3); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case P3_MEM: { dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree((sqlite3_value*)p3); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change N opcodes starting at addr to No-ops. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){ dbda8d6ce9 2007-07-21 drh: if( p && p->aOp ){ dbda8d6ce9 2007-07-21 drh: VdbeOp *pOp = &p->aOp[addr]; dbda8d6ce9 2007-07-21 drh: while( N-- ){ dbda8d6ce9 2007-07-21 drh: freeP3(pOp->p3type, pOp->p3); dbda8d6ce9 2007-07-21 drh: memset(pOp, 0, sizeof(pOp[0])); dbda8d6ce9 2007-07-21 drh: pOp->opcode = OP_Noop; dbda8d6ce9 2007-07-21 drh: pOp++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Change the value of the P3 operand for a specific instruction. dbda8d6ce9 2007-07-21 drh: ** This routine is useful when a large program is loaded from a dbda8d6ce9 2007-07-21 drh: ** static array using sqlite3VdbeAddOpList but we want to make a dbda8d6ce9 2007-07-21 drh: ** few minor changes to the program. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If n>=0 then the P3 operand is dynamic, meaning that a copy of c287665ba8 2007-09-14 drh: ** the string is made into memory obtained from sqlite3_malloc(). dbda8d6ce9 2007-07-21 drh: ** A value of n==0 means copy bytes of zP3 up to and including the dbda8d6ce9 2007-07-21 drh: ** first null byte. If n>0 then copy n+1 bytes of zP3. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If n==P3_KEYINFO it means that zP3 is a pointer to a KeyInfo structure. dbda8d6ce9 2007-07-21 drh: ** A copy is made of the KeyInfo structure into memory obtained from c287665ba8 2007-09-14 drh: ** sqlite3_malloc, to be freed when the Vdbe is finalized. dbda8d6ce9 2007-07-21 drh: ** n==P3_KEYINFO_HANDOFF indicates that zP3 points to a KeyInfo structure c287665ba8 2007-09-14 drh: ** stored in memory that the caller has obtained from sqlite3_malloc. The dbda8d6ce9 2007-07-21 drh: ** caller should not free the allocation, it will be freed when the Vdbe is dbda8d6ce9 2007-07-21 drh: ** finalized. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Other values of n (P3_STATIC, P3_COLLSEQ etc.) indicate that zP3 points dbda8d6ce9 2007-07-21 drh: ** to a string or structure that is guaranteed to exist for the lifetime of dbda8d6ce9 2007-07-21 drh: ** the Vdbe. In these cases we can just copy the pointer. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If addr<0 then change P3 on the most recently inserted instruction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ dbda8d6ce9 2007-07-21 drh: Op *pOp; dbda8d6ce9 2007-07-21 drh: assert( p==0 || p->magic==VDBE_MAGIC_INIT ); c287665ba8 2007-09-14 drh: if( p==0 || p->aOp==0 || p->db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: if (n != P3_KEYINFO) { dbda8d6ce9 2007-07-21 drh: freeP3(n, (void*)*(char**)&zP3); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( addr<0 || addr>=p->nOp ){ dbda8d6ce9 2007-07-21 drh: addr = p->nOp - 1; dbda8d6ce9 2007-07-21 drh: if( addr<0 ) return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pOp = &p->aOp[addr]; dbda8d6ce9 2007-07-21 drh: freeP3(pOp->p3type, pOp->p3); dbda8d6ce9 2007-07-21 drh: pOp->p3 = 0; dbda8d6ce9 2007-07-21 drh: if( zP3==0 ){ dbda8d6ce9 2007-07-21 drh: pOp->p3 = 0; dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_NOTUSED; dbda8d6ce9 2007-07-21 drh: }else if( n==P3_KEYINFO ){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo; dbda8d6ce9 2007-07-21 drh: int nField, nByte; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nField = ((KeyInfo*)zP3)->nField; dbda8d6ce9 2007-07-21 drh: nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField; c287665ba8 2007-09-14 drh: pKeyInfo = sqlite3_malloc( nByte ); dbda8d6ce9 2007-07-21 drh: pOp->p3 = (char*)pKeyInfo; dbda8d6ce9 2007-07-21 drh: if( pKeyInfo ){ dbda8d6ce9 2007-07-21 drh: unsigned char *aSortOrder; dbda8d6ce9 2007-07-21 drh: memcpy(pKeyInfo, zP3, nByte); dbda8d6ce9 2007-07-21 drh: aSortOrder = pKeyInfo->aSortOrder; dbda8d6ce9 2007-07-21 drh: if( aSortOrder ){ dbda8d6ce9 2007-07-21 drh: pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField]; dbda8d6ce9 2007-07-21 drh: memcpy(pKeyInfo->aSortOrder, aSortOrder, nField); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_KEYINFO; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: p->db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_NOTUSED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( n==P3_KEYINFO_HANDOFF ){ dbda8d6ce9 2007-07-21 drh: pOp->p3 = (char*)zP3; dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_KEYINFO; dbda8d6ce9 2007-07-21 drh: }else if( n<0 ){ dbda8d6ce9 2007-07-21 drh: pOp->p3 = (char*)zP3; dbda8d6ce9 2007-07-21 drh: pOp->p3type = n; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( n==0 ) n = strlen(zP3); c287665ba8 2007-09-14 drh: pOp->p3 = sqlite3DbStrNDup(p->db, zP3, n); dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_DYNAMIC; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Replace the P3 field of the most recently coded instruction with dbda8d6ce9 2007-07-21 drh: ** comment text. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: assert( p->nOp>0 || p->aOp==0 ); c287665ba8 2007-09-14 drh: assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 || p->db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: va_start(ap, zFormat); c287665ba8 2007-09-14 drh: sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(p->db, zFormat, ap), P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the opcode for a given address. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ dbda8d6ce9 2007-07-21 drh: assert( p->magic==VDBE_MAGIC_INIT ); c287665ba8 2007-09-14 drh: assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: return ((addr>=0 && addr<p->nOp)?(&p->aOp[addr]):0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \ dbda8d6ce9 2007-07-21 drh: || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute a string that describes the P3 parameter for an opcode. dbda8d6ce9 2007-07-21 drh: ** Use zTemp for any required temporary buffer space. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char *displayP3(Op *pOp, char *zTemp, int nTemp){ dbda8d6ce9 2007-07-21 drh: char *zP3; dbda8d6ce9 2007-07-21 drh: assert( nTemp>=20 ); dbda8d6ce9 2007-07-21 drh: switch( pOp->p3type ){ dbda8d6ce9 2007-07-21 drh: case P3_KEYINFO: { dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(nTemp, zTemp, "keyinfo(%d", pKeyInfo->nField); dbda8d6ce9 2007-07-21 drh: i = strlen(zTemp); dbda8d6ce9 2007-07-21 drh: for(j=0; j<pKeyInfo->nField; j++){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = pKeyInfo->aColl[j]; dbda8d6ce9 2007-07-21 drh: if( pColl ){ dbda8d6ce9 2007-07-21 drh: int n = strlen(pColl->zName); dbda8d6ce9 2007-07-21 drh: if( i+n>nTemp-6 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&zTemp[i],",...",4); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zTemp[i++] = ','; dbda8d6ce9 2007-07-21 drh: if( pKeyInfo->aSortOrder && pKeyInfo->aSortOrder[j] ){ dbda8d6ce9 2007-07-21 drh: zTemp[i++] = '-'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(&zTemp[i], pColl->zName,n+1); dbda8d6ce9 2007-07-21 drh: i += n; dbda8d6ce9 2007-07-21 drh: }else if( i+4<nTemp-6 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&zTemp[i],",nil",4); dbda8d6ce9 2007-07-21 drh: i += 4; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zTemp[i++] = ')'; dbda8d6ce9 2007-07-21 drh: zTemp[i] = 0; dbda8d6ce9 2007-07-21 drh: assert( i<nTemp ); dbda8d6ce9 2007-07-21 drh: zP3 = zTemp; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case P3_COLLSEQ: { dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = (CollSeq*)pOp->p3; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(nTemp, zTemp, "collseq(%.20s)", pColl->zName); dbda8d6ce9 2007-07-21 drh: zP3 = zTemp; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case P3_FUNCDEF: { dbda8d6ce9 2007-07-21 drh: FuncDef *pDef = (FuncDef*)pOp->p3; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg); dbda8d6ce9 2007-07-21 drh: zP3 = zTemp; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: case P3_VTAB: { dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab = (sqlite3_vtab*)pOp->p3; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule); dbda8d6ce9 2007-07-21 drh: zP3 = zTemp; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: zP3 = pOp->p3; dbda8d6ce9 2007-07-21 drh: if( zP3==0 || pOp->opcode==OP_Noop ){ dbda8d6ce9 2007-07-21 drh: zP3 = ""; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( zP3!=0 ); dbda8d6ce9 2007-07-21 drh: return zP3; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Declare to the Vdbe that the BTree object at db->aDb[i] is used. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){ c287665ba8 2007-09-14 drh: int mask; c287665ba8 2007-09-14 drh: assert( i>=0 && i<p->db->nDb ); c287665ba8 2007-09-14 drh: assert( i<sizeof(p->btreeMask)*8 ); c287665ba8 2007-09-14 drh: mask = 1<<i; c287665ba8 2007-09-14 drh: if( (p->btreeMask & mask)==0 ){ c287665ba8 2007-09-14 drh: p->btreeMask |= mask; c287665ba8 2007-09-14 drh: sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print a single opcode. This routine is used for debugging only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ dbda8d6ce9 2007-07-21 drh: char *zP3; dbda8d6ce9 2007-07-21 drh: char zPtr[50]; dbda8d6ce9 2007-07-21 drh: static const char *zFormat1 = "%4d %-13s %4d %4d %s\n"; dbda8d6ce9 2007-07-21 drh: if( pOut==0 ) pOut = stdout; dbda8d6ce9 2007-07-21 drh: zP3 = displayP3(pOp, zPtr, sizeof(zPtr)); dbda8d6ce9 2007-07-21 drh: fprintf(pOut, zFormat1, c287665ba8 2007-09-14 drh: pc, sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, zP3); dbda8d6ce9 2007-07-21 drh: fflush(pOut); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release an array of N Mem elements dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void releaseMemArray(Mem *p, int N){ dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: while( N-->0 ){ c287665ba8 2007-09-14 drh: assert( N<2 || p[0].db==p[1].db ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(p++); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_EXPLAIN dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Give a listing of the program in the virtual machine. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The interface is the same as sqlite3VdbeExec(). But instead of dbda8d6ce9 2007-07-21 drh: ** running the code, it invokes the callback once for each instruction. dbda8d6ce9 2007-07-21 drh: ** This feature is used to implement "EXPLAIN". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeList( dbda8d6ce9 2007-07-21 drh: Vdbe *p /* The VDBE */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = p->db; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( p->explain ); dbda8d6ce9 2007-07-21 drh: if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: assert( db->magic==SQLITE_MAGIC_BUSY ); dbda8d6ce9 2007-07-21 drh: assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Even though this opcode does not put dynamic strings onto the dbda8d6ce9 2007-07-21 drh: ** the stack, they may become dynamic if the user calls dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pTos==&p->aStack[4] ){ dbda8d6ce9 2007-07-21 drh: releaseMemArray(p->aStack, 5); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->resOnStack = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: i = p->pc++; dbda8d6ce9 2007-07-21 drh: }while( i<p->nOp && p->explain==2 && p->aOp[i].opcode!=OP_Explain ); dbda8d6ce9 2007-07-21 drh: if( i>=p->nOp ){ dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: }else if( db->u1.isInterrupted ){ dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_INTERRUPT; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Op *pOp = &p->aOp[i]; dbda8d6ce9 2007-07-21 drh: Mem *pMem = p->aStack; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_INTEGER; dbda8d6ce9 2007-07-21 drh: pMem->u.i = i; /* Program counter */ dbda8d6ce9 2007-07-21 drh: pMem++; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Static|MEM_Str|MEM_Term; c287665ba8 2007-09-14 drh: pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */ dbda8d6ce9 2007-07-21 drh: assert( pMem->z!=0 ); dbda8d6ce9 2007-07-21 drh: pMem->n = strlen(pMem->z); dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_TEXT; dbda8d6ce9 2007-07-21 drh: pMem->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: pMem++; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pMem->u.i = pOp->p1; /* P1 */ dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_INTEGER; dbda8d6ce9 2007-07-21 drh: pMem++; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pMem->u.i = pOp->p2; /* P2 */ dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_INTEGER; dbda8d6ce9 2007-07-21 drh: pMem++; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P3 */ dbda8d6ce9 2007-07-21 drh: pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort)); dbda8d6ce9 2007-07-21 drh: assert( pMem->z!=0 ); dbda8d6ce9 2007-07-21 drh: pMem->n = strlen(pMem->z); dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_TEXT; dbda8d6ce9 2007-07-21 drh: pMem->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: p->nResColumn = 5 - 2*(p->explain-1); dbda8d6ce9 2007-07-21 drh: p->pTos = pMem; dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: p->resOnStack = 1; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ROW; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_EXPLAIN */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print the SQL that was used to generate a VDBE program. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: int nOp = p->nOp; dbda8d6ce9 2007-07-21 drh: VdbeOp *pOp; dbda8d6ce9 2007-07-21 drh: if( nOp<1 ) return; dbda8d6ce9 2007-07-21 drh: pOp = &p->aOp[nOp-1]; dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_Noop && pOp->p3!=0 ){ dbda8d6ce9 2007-07-21 drh: const char *z = pOp->p3; dbda8d6ce9 2007-07-21 drh: while( isspace(*(u8*)z) ) z++; dbda8d6ce9 2007-07-21 drh: printf("SQL: [%s]\n", z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Print an IOTRACE message showing SQL content. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: int nOp = p->nOp; dbda8d6ce9 2007-07-21 drh: VdbeOp *pOp; dbda8d6ce9 2007-07-21 drh: if( sqlite3_io_trace==0 ) return; dbda8d6ce9 2007-07-21 drh: if( nOp<1 ) return; dbda8d6ce9 2007-07-21 drh: pOp = &p->aOp[nOp-1]; dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_Noop && pOp->p3!=0 ){ dbda8d6ce9 2007-07-21 drh: int i, j; c287665ba8 2007-09-14 drh: char z[1000]; c287665ba8 2007-09-14 drh: sqlite3_snprintf(sizeof(z), z, "%s", pOp->p3); dbda8d6ce9 2007-07-21 drh: for(i=0; isspace((unsigned char)z[i]); i++){} dbda8d6ce9 2007-07-21 drh: for(j=0; z[i]; i++){ dbda8d6ce9 2007-07-21 drh: if( isspace((unsigned char)z[i]) ){ dbda8d6ce9 2007-07-21 drh: if( z[i-1]!=' ' ){ dbda8d6ce9 2007-07-21 drh: z[j++] = ' '; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: z[j++] = z[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: z[j] = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_io_trace("SQL %s\n", z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Prepare a virtual machine for execution. This involves things such dbda8d6ce9 2007-07-21 drh: ** as allocating stack space and initializing the program counter. dbda8d6ce9 2007-07-21 drh: ** After the VDBE has be prepped, it can be executed by one or more dbda8d6ce9 2007-07-21 drh: ** calls to sqlite3VdbeExec(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is the only way to move a VDBE from VDBE_MAGIC_INIT to dbda8d6ce9 2007-07-21 drh: ** VDBE_MAGIC_RUN. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMakeReady( dbda8d6ce9 2007-07-21 drh: Vdbe *p, /* The VDBE */ dbda8d6ce9 2007-07-21 drh: int nVar, /* Number of '?' see in the SQL statement */ dbda8d6ce9 2007-07-21 drh: int nMem, /* Number of memory cells to allocate */ dbda8d6ce9 2007-07-21 drh: int nCursor, /* Number of cursors to allocate */ dbda8d6ce9 2007-07-21 drh: int isExplain /* True if the EXPLAIN keywords is present */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int n; c287665ba8 2007-09-14 drh: sqlite3 *db = p->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( p!=0 ); dbda8d6ce9 2007-07-21 drh: assert( p->magic==VDBE_MAGIC_INIT ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* There should be at least one opcode. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( p->nOp>0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. This dbda8d6ce9 2007-07-21 drh: * is because the call to resizeOpArray() below may shrink the dbda8d6ce9 2007-07-21 drh: * p->aOp[] array to save memory if called when in VDBE_MAGIC_RUN dbda8d6ce9 2007-07-21 drh: * state. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: p->magic = VDBE_MAGIC_RUN; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* No instruction ever pushes more than a single element onto the dbda8d6ce9 2007-07-21 drh: ** stack. And the stack never grows on successive executions of the dbda8d6ce9 2007-07-21 drh: ** same loop. So the total number of instructions is an upper bound dbda8d6ce9 2007-07-21 drh: ** on the maximum stack depth required. (Added later:) The dbda8d6ce9 2007-07-21 drh: ** resolveP2Values() call computes a tighter upper bound on the dbda8d6ce9 2007-07-21 drh: ** stack size. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Allocation all the stack space we will ever need. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->aStack==0 ){ dbda8d6ce9 2007-07-21 drh: int nArg; /* Maximum number of args passed to a user function. */ dbda8d6ce9 2007-07-21 drh: int nStack; /* Maximum number of stack entries required */ dbda8d6ce9 2007-07-21 drh: resolveP2Values(p, &nArg, &nStack); dbda8d6ce9 2007-07-21 drh: resizeOpArray(p, p->nOp); dbda8d6ce9 2007-07-21 drh: assert( nVar>=0 ); dbda8d6ce9 2007-07-21 drh: assert( nStack<p->nOp ); dbda8d6ce9 2007-07-21 drh: if( isExplain ){ dbda8d6ce9 2007-07-21 drh: nStack = 10; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: p->aStack = sqlite3DbMallocZero(db, dbda8d6ce9 2007-07-21 drh: nStack*sizeof(p->aStack[0]) /* aStack */ dbda8d6ce9 2007-07-21 drh: + nArg*sizeof(Mem*) /* apArg */ dbda8d6ce9 2007-07-21 drh: + nVar*sizeof(Mem) /* aVar */ dbda8d6ce9 2007-07-21 drh: + nVar*sizeof(char*) /* azVar */ dbda8d6ce9 2007-07-21 drh: + nMem*sizeof(Mem) /* aMem */ dbda8d6ce9 2007-07-21 drh: + nCursor*sizeof(Cursor*) /* apCsr */ dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: if( !db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: p->aMem = &p->aStack[nStack]; dbda8d6ce9 2007-07-21 drh: p->nMem = nMem; dbda8d6ce9 2007-07-21 drh: p->aVar = &p->aMem[nMem]; dbda8d6ce9 2007-07-21 drh: p->nVar = nVar; dbda8d6ce9 2007-07-21 drh: p->okVar = 0; dbda8d6ce9 2007-07-21 drh: p->apArg = (Mem**)&p->aVar[nVar]; dbda8d6ce9 2007-07-21 drh: p->azVar = (char**)&p->apArg[nArg]; dbda8d6ce9 2007-07-21 drh: p->apCsr = (Cursor**)&p->azVar[nVar]; dbda8d6ce9 2007-07-21 drh: p->nCursor = nCursor; dbda8d6ce9 2007-07-21 drh: for(n=0; n<nVar; n++){ dbda8d6ce9 2007-07-21 drh: p->aVar[n].flags = MEM_Null; c287665ba8 2007-09-14 drh: p->aVar[n].db = db; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: for(n=0; n<nStack; n++){ c287665ba8 2007-09-14 drh: p->aStack[n].db = db; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(n=0; n<p->nMem; n++){ dbda8d6ce9 2007-07-21 drh: p->aMem[n].flags = MEM_Null; c287665ba8 2007-09-14 drh: p->aMem[n].db = db; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: p->pTos = &p->aStack[-1]; dbda8d6ce9 2007-07-21 drh: p->pc = -1; dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: p->uniqueCnt = 0; dbda8d6ce9 2007-07-21 drh: p->returnDepth = 0; dbda8d6ce9 2007-07-21 drh: p->errorAction = OE_Abort; dbda8d6ce9 2007-07-21 drh: p->popStack = 0; dbda8d6ce9 2007-07-21 drh: p->explain |= isExplain; dbda8d6ce9 2007-07-21 drh: p->magic = VDBE_MAGIC_RUN; dbda8d6ce9 2007-07-21 drh: p->nChange = 0; dbda8d6ce9 2007-07-21 drh: p->cacheCtr = 1; dbda8d6ce9 2007-07-21 drh: p->minWriteFileFormat = 255; dbda8d6ce9 2007-07-21 drh: p->openedStatement = 0; dbda8d6ce9 2007-07-21 drh: #ifdef VDBE_PROFILE dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nOp; i++){ dbda8d6ce9 2007-07-21 drh: p->aOp[i].cnt = 0; dbda8d6ce9 2007-07-21 drh: p->aOp[i].cycles = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Close a VDBE cursor and release all the resources that cursor happens dbda8d6ce9 2007-07-21 drh: ** to hold. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){ dbda8d6ce9 2007-07-21 drh: if( pCx==0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCx->pCursor ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCloseCursor(pCx->pCursor); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCx->pBt ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeClose(pCx->pBt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( pCx->pVtabCursor ){ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule = pCx->pModule; dbda8d6ce9 2007-07-21 drh: p->inVtabMethod = 1; dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(p->db); dbda8d6ce9 2007-07-21 drh: pModule->xClose(pVtabCursor); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(p->db); dbda8d6ce9 2007-07-21 drh: p->inVtabMethod = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: sqlite3_free(pCx->pData); c287665ba8 2007-09-14 drh: sqlite3_free(pCx->aType); c287665ba8 2007-09-14 drh: sqlite3_free(pCx); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Close all cursors except for VTab cursors that are currently c287665ba8 2007-09-14 drh: ** in use. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void closeAllCursorsExceptActiveVtabs(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( p->apCsr==0 ) return; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nCursor; i++){ c287665ba8 2007-09-14 drh: Cursor *pC = p->apCsr[i]; c287665ba8 2007-09-14 drh: if( pC && (!p->inVtabMethod || !pC->pVtabCursor) ){ c287665ba8 2007-09-14 drh: sqlite3VdbeFreeCursor(p, pC); dbda8d6ce9 2007-07-21 drh: p->apCsr[i] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clean up the VM after execution. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine will automatically close any cursors, lists, and/or dbda8d6ce9 2007-07-21 drh: ** sorters that were left open. It also deletes the values of dbda8d6ce9 2007-07-21 drh: ** variables in the aVar[] array. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void Cleanup(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( p->aStack ){ dbda8d6ce9 2007-07-21 drh: releaseMemArray(p->aStack, 1 + (p->pTos - p->aStack)); dbda8d6ce9 2007-07-21 drh: p->pTos = &p->aStack[-1]; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: closeAllCursorsExceptActiveVtabs(p); dbda8d6ce9 2007-07-21 drh: releaseMemArray(p->aMem, p->nMem); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeFifoClear(&p->sFifo); dbda8d6ce9 2007-07-21 drh: if( p->contextStack ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->contextStackTop; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeFifoClear(&p->contextStack[i].sFifo); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(p->contextStack); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->contextStack = 0; dbda8d6ce9 2007-07-21 drh: p->contextStackDepth = 0; dbda8d6ce9 2007-07-21 drh: p->contextStackTop = 0; c287665ba8 2007-09-14 drh: sqlite3_free(p->zErrMsg); dbda8d6ce9 2007-07-21 drh: p->zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: p->resOnStack = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the number of result columns that will be returned by this SQL dbda8d6ce9 2007-07-21 drh: ** statement. This is now set at compile time, rather than during dbda8d6ce9 2007-07-21 drh: ** execution of the vdbe program so that sqlite3_column_count() can dbda8d6ce9 2007-07-21 drh: ** be called on an SQL statement before sqlite3_step(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ dbda8d6ce9 2007-07-21 drh: Mem *pColName; dbda8d6ce9 2007-07-21 drh: int n; c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); c287665ba8 2007-09-14 drh: sqlite3_free(p->aColName); dbda8d6ce9 2007-07-21 drh: n = nResColumn*COLNAME_N; dbda8d6ce9 2007-07-21 drh: p->nResColumn = nResColumn; c287665ba8 2007-09-14 drh: p->aColName = pColName = (Mem*)sqlite3DbMallocZero(p->db, sizeof(Mem)*n ); dbda8d6ce9 2007-07-21 drh: if( p->aColName==0 ) return; dbda8d6ce9 2007-07-21 drh: while( n-- > 0 ){ c287665ba8 2007-09-14 drh: pColName->flags = MEM_Null; c287665ba8 2007-09-14 drh: pColName->db = p->db; c287665ba8 2007-09-14 drh: pColName++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the name of the idx'th column to be returned by the SQL statement. dbda8d6ce9 2007-07-21 drh: ** zName must be a pointer to a nul terminated string. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This call must be made after a call to sqlite3VdbeSetNumCols(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If N==P3_STATIC it means that zName is a pointer to a constant static dbda8d6ce9 2007-07-21 drh: ** string and we can just copy the pointer. If it is P3_DYNAMIC, then c287665ba8 2007-09-14 drh: ** the string is freed using sqlite3_free() when the vdbe is finished with dbda8d6ce9 2007-07-21 drh: ** it. Otherwise, N bytes of zName are copied. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Mem *pColName; dbda8d6ce9 2007-07-21 drh: assert( idx<p->nResColumn ); dbda8d6ce9 2007-07-21 drh: assert( var<COLNAME_N ); c287665ba8 2007-09-14 drh: if( p->db->mallocFailed ) return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: assert( p->aColName!=0 ); dbda8d6ce9 2007-07-21 drh: pColName = &(p->aColName[idx+var*p->nResColumn]); dbda8d6ce9 2007-07-21 drh: if( N==P3_DYNAMIC || N==P3_STATIC ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8,SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && N==P3_DYNAMIC ){ dbda8d6ce9 2007-07-21 drh: pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn; dbda8d6ce9 2007-07-21 drh: pColName->xDel = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A read or write transaction may or may not be active on database handle dbda8d6ce9 2007-07-21 drh: ** db. If a transaction is active, commit it. If there is a dbda8d6ce9 2007-07-21 drh: ** write-transaction spanning more than one database file, this routine dbda8d6ce9 2007-07-21 drh: ** takes care of the master journal trickery. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int vdbeCommit(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nTrans = 0; /* Number of databases with an active write-transaction */ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int needXcommit = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Before doing anything else, call the xSync() callback for any dbda8d6ce9 2007-07-21 drh: ** virtual module tables written in this transaction. This has to dbda8d6ce9 2007-07-21 drh: ** be done before determining whether a master journal file is dbda8d6ce9 2007-07-21 drh: ** required, as an xSync() callback may add an attached database dbda8d6ce9 2007-07-21 drh: ** to the transaction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VtabSync(db, rc); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This loop determines (a) if the commit hook should be invoked and dbda8d6ce9 2007-07-21 drh: ** (b) how many database files have open write transactions, not dbda8d6ce9 2007-07-21 drh: ** including the temp database. (b) is important because if more than dbda8d6ce9 2007-07-21 drh: ** one database file has an open write transaction, a master journal dbda8d6ce9 2007-07-21 drh: ** file is required for an atomic commit. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[i].pBt; c287665ba8 2007-09-14 drh: if( sqlite3BtreeIsInTrans(pBt) ){ dbda8d6ce9 2007-07-21 drh: needXcommit = 1; dbda8d6ce9 2007-07-21 drh: if( i!=1 ) nTrans++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there are any write-transactions at all, invoke the commit hook */ dbda8d6ce9 2007-07-21 drh: if( needXcommit && db->xCommitCallback ){ dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: rc = db->xCommitCallback(db->pCommitArg); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CONSTRAINT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The simple case - no more than one database file (not counting the dbda8d6ce9 2007-07-21 drh: ** TEMP database) has a transaction active. There is no need for the dbda8d6ce9 2007-07-21 drh: ** master-journal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the return value of sqlite3BtreeGetFilename() is a zero length dbda8d6ce9 2007-07-21 drh: ** string, it means the main database is :memory:. In that case we do dbda8d6ce9 2007-07-21 drh: ** not support atomic multi-file commits, so use the simple case then dbda8d6ce9 2007-07-21 drh: ** too. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( 0==strlen(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){ dbda8d6ce9 2007-07-21 drh: for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[i].pBt; dbda8d6ce9 2007-07-21 drh: if( pBt ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCommitPhaseOne(pBt, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do the commit only if all databases successfully complete phase 1. dbda8d6ce9 2007-07-21 drh: ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an dbda8d6ce9 2007-07-21 drh: ** IO error while deleting or truncating a journal file. It is unlikely, dbda8d6ce9 2007-07-21 drh: ** but could happen. In this case abandon processing and return the error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[i].pBt; dbda8d6ce9 2007-07-21 drh: if( pBt ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCommitPhaseTwo(pBt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3VtabCommit(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The complex case - There is a multi-file write-transaction active. dbda8d6ce9 2007-07-21 drh: ** This requires a master journal file to ensure the transaction is dbda8d6ce9 2007-07-21 drh: ** committed atomicly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_DISKIO dbda8d6ce9 2007-07-21 drh: else{ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs = db->pVfs; dbda8d6ce9 2007-07-21 drh: int needSync = 0; dbda8d6ce9 2007-07-21 drh: char *zMaster = 0; /* File-name for the master journal */ dbda8d6ce9 2007-07-21 drh: char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); c287665ba8 2007-09-14 drh: sqlite3_file *pMaster = 0; c287665ba8 2007-09-14 drh: i64 offset = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Select a master journal file name */ dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: u32 random; c287665ba8 2007-09-14 drh: sqlite3_free(zMaster); dbda8d6ce9 2007-07-21 drh: sqlite3Randomness(sizeof(random), &random); c287665ba8 2007-09-14 drh: zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, random&0x7fffffff); dbda8d6ce9 2007-07-21 drh: if( !zMaster ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: }while( sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open the master journal. */ c287665ba8 2007-09-14 drh: rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, c287665ba8 2007-09-14 drh: SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE| c287665ba8 2007-09-14 drh: SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0 c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3_free(zMaster); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Write the name of each database file in the transaction into the new dbda8d6ce9 2007-07-21 drh: ** master journal file. If an error occurs at this point close dbda8d6ce9 2007-07-21 drh: ** and delete the master journal file. All the individual journal files dbda8d6ce9 2007-07-21 drh: ** still have 'null' as the master journal pointer, so they will roll dbda8d6ce9 2007-07-21 drh: ** back independently if a failure occurs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[i].pBt; dbda8d6ce9 2007-07-21 drh: if( i==1 ) continue; /* Ignore the TEMP database */ c287665ba8 2007-09-14 drh: if( sqlite3BtreeIsInTrans(pBt) ){ dbda8d6ce9 2007-07-21 drh: char const *zFile = sqlite3BtreeGetJournalname(pBt); dbda8d6ce9 2007-07-21 drh: if( zFile[0]==0 ) continue; /* Ignore :memory: databases */ dbda8d6ce9 2007-07-21 drh: if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){ dbda8d6ce9 2007-07-21 drh: needSync = 1; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(pMaster, zFile, strlen(zFile)+1, offset); c287665ba8 2007-09-14 drh: offset += strlen(zFile)+1; dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3OsCloseFree(pMaster); c287665ba8 2007-09-14 drh: sqlite3OsDelete(pVfs, zMaster, 0); c287665ba8 2007-09-14 drh: sqlite3_free(zMaster); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* Sync the master journal file. If the IOCAP_SEQUENTIAL device c287665ba8 2007-09-14 drh: ** flag is set this is not required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt); c287665ba8 2007-09-14 drh: if( (needSync c287665ba8 2007-09-14 drh: && (0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)) c287665ba8 2007-09-14 drh: && (rc=sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))!=SQLITE_OK) ){ c287665ba8 2007-09-14 drh: sqlite3OsCloseFree(pMaster); c287665ba8 2007-09-14 drh: sqlite3OsDelete(pVfs, zMaster, 0); c287665ba8 2007-09-14 drh: sqlite3_free(zMaster); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Sync all the db files involved in the transaction. The same call dbda8d6ce9 2007-07-21 drh: ** sets the master journal pointer in each individual journal. If dbda8d6ce9 2007-07-21 drh: ** an error occurs here, do not delete the master journal file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the error occurs during the first call to dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the dbda8d6ce9 2007-07-21 drh: ** master journal file will be orphaned. But we cannot delete it, dbda8d6ce9 2007-07-21 drh: ** in case the master journal file name was written into the journal dbda8d6ce9 2007-07-21 drh: ** file before the failure occured. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[i].pBt; c287665ba8 2007-09-14 drh: if( pBt ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3OsCloseFree(pMaster); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3_free(zMaster); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Delete the master journal file. This commits the transaction. After dbda8d6ce9 2007-07-21 drh: ** doing this the directory is synced again before any individual dbda8d6ce9 2007-07-21 drh: ** transaction files are deleted. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: rc = sqlite3OsDelete(pVfs, zMaster, 1); c287665ba8 2007-09-14 drh: sqlite3_free(zMaster); dbda8d6ce9 2007-07-21 drh: zMaster = 0; dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* All files and directories have already been synced, so the following dbda8d6ce9 2007-07-21 drh: ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and dbda8d6ce9 2007-07-21 drh: ** deleting or truncating journals. If something goes wrong while dbda8d6ce9 2007-07-21 drh: ** this is happening we don't really care. The integrity of the dbda8d6ce9 2007-07-21 drh: ** transaction is already guaranteed, but some stray 'cold' journals dbda8d6ce9 2007-07-21 drh: ** may be lying around. Returning an error code won't help matters. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: disable_simulated_io_errors(); dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[i].pBt; dbda8d6ce9 2007-07-21 drh: if( pBt ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCommitPhaseTwo(pBt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: enable_simulated_io_errors(); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VtabCommit(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine checks that the sqlite3.activeVdbeCnt count variable dbda8d6ce9 2007-07-21 drh: ** matches the number of vdbe's in the list sqlite3.pVdbe that are dbda8d6ce9 2007-07-21 drh: ** currently active. An assertion fails if the two counts do not match. dbda8d6ce9 2007-07-21 drh: ** This is an internal self-check only - it is not an essential processing dbda8d6ce9 2007-07-21 drh: ** step. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is a no-op if NDEBUG is defined. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: static void checkActiveVdbeCnt(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: Vdbe *p; dbda8d6ce9 2007-07-21 drh: int cnt = 0; dbda8d6ce9 2007-07-21 drh: p = db->pVdbe; dbda8d6ce9 2007-07-21 drh: while( p ){ dbda8d6ce9 2007-07-21 drh: if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){ dbda8d6ce9 2007-07-21 drh: cnt++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p = p->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( cnt==db->activeVdbeCnt ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define checkActiveVdbeCnt(x) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** For every Btree that in database connection db which c287665ba8 2007-09-14 drh: ** has been modified, "trip" or invalidate each cursor in c287665ba8 2007-09-14 drh: ** that Btree might have been modified so that the cursor c287665ba8 2007-09-14 drh: ** can never be used again. This happens when a rollback c287665ba8 2007-09-14 drh: *** occurs. We have to trip all the other cursors, even c287665ba8 2007-09-14 drh: ** cursor from other VMs in different database connections, c287665ba8 2007-09-14 drh: ** so that none of them try to use the data at which they c287665ba8 2007-09-14 drh: ** were pointing and which now may have been changed due c287665ba8 2007-09-14 drh: ** to the rollback. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Remember that a rollback can delete tables complete and c287665ba8 2007-09-14 drh: ** reorder rootpages. So it is not sufficient just to save c287665ba8 2007-09-14 drh: ** the state of the cursor. We have to invalidate the cursor c287665ba8 2007-09-14 drh: ** so that it is never used again. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: void invalidateCursorsOnModifiedBtrees(sqlite3 *db){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: for(i=0; i<db->nDb; i++){ c287665ba8 2007-09-14 drh: Btree *p = db->aDb[i].pBt; c287665ba8 2007-09-14 drh: if( p && sqlite3BtreeIsInTrans(p) ){ c287665ba8 2007-09-14 drh: sqlite3BtreeTripAllCursors(p, SQLITE_ABORT); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called the when a VDBE tries to halt. If the VDBE dbda8d6ce9 2007-07-21 drh: ** has made changes and is in autocommit mode, then commit those dbda8d6ce9 2007-07-21 drh: ** changes. If a rollback is needed, then do the rollback. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is the only way to move the state of a VM from c287665ba8 2007-09-14 drh: ** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to c287665ba8 2007-09-14 drh: ** call this on a VM that is in the SQLITE_MAGIC_HALT state. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return an error code. If the commit could not complete because of dbda8d6ce9 2007-07-21 drh: ** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it dbda8d6ce9 2007-07-21 drh: ** means the close did not happen and needs to be repeated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = p->db; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */ dbda8d6ce9 2007-07-21 drh: int isSpecialError; /* Set to true if SQLITE_NOMEM or IOERR */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This function contains the logic that determines if a statement or dbda8d6ce9 2007-07-21 drh: ** transaction will be committed or rolled back as a result of the dbda8d6ce9 2007-07-21 drh: ** execution of this virtual machine. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Special errors: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an SQLITE_NOMEM error has occured in a statement that writes to dbda8d6ce9 2007-07-21 drh: ** the database, then either a statement or transaction must be rolled dbda8d6ce9 2007-07-21 drh: ** back to ensure the tree-structures are in a consistent state. A dbda8d6ce9 2007-07-21 drh: ** statement transaction is rolled back if one is open, otherwise the dbda8d6ce9 2007-07-21 drh: ** entire transaction must be rolled back. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an SQLITE_IOERR error has occured in a statement that writes to dbda8d6ce9 2007-07-21 drh: ** the database, then the entire transaction must be rolled back. The dbda8d6ce9 2007-07-21 drh: ** I/O error may have caused garbage to be written to the journal dbda8d6ce9 2007-07-21 drh: ** file. Were the transaction to continue and eventually be rolled dbda8d6ce9 2007-07-21 drh: ** back that garbage might end up in the database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In both of the above cases, the Vdbe.errorAction variable is dbda8d6ce9 2007-07-21 drh: ** ignored. If the sqlite3.autoCommit flag is false and a transaction dbda8d6ce9 2007-07-21 drh: ** is rolled back, it will be set to true. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Other errors: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** No error: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( p->db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: closeAllCursorsExceptActiveVtabs(p); c287665ba8 2007-09-14 drh: if( p->magic!=VDBE_MAGIC_RUN ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: checkActiveVdbeCnt(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* No commit or rollback needed if the program never started */ dbda8d6ce9 2007-07-21 drh: if( p->pc>=0 ){ dbda8d6ce9 2007-07-21 drh: int mrc; /* Primary error code from p->rc */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Lock all btrees used by the statement */ c287665ba8 2007-09-14 drh: sqlite3BtreeMutexArrayEnter(&p->aMutex); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */ dbda8d6ce9 2007-07-21 drh: mrc = p->rc & 0xff; dbda8d6ce9 2007-07-21 drh: isSpecialError = ( dbda8d6ce9 2007-07-21 drh: (mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT)?1:0); dbda8d6ce9 2007-07-21 drh: if( isSpecialError ){ dbda8d6ce9 2007-07-21 drh: /* This loop does static analysis of the query to see which of the dbda8d6ce9 2007-07-21 drh: ** following three categories it falls into: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Read-only dbda8d6ce9 2007-07-21 drh: ** Query with statement journal dbda8d6ce9 2007-07-21 drh: ** Query without statement journal dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** We could do something more elegant than this static analysis (i.e. dbda8d6ce9 2007-07-21 drh: ** store the type of query as part of the compliation phase), but dbda8d6ce9 2007-07-21 drh: ** handling malloc() or IO failure is a fairly obscure edge case so dbda8d6ce9 2007-07-21 drh: ** this is probably easier. Todo: Might be an opportunity to reduce dbda8d6ce9 2007-07-21 drh: ** code size a very small amount though... dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int isReadOnly = 1; dbda8d6ce9 2007-07-21 drh: int isStatement = 0; dbda8d6ce9 2007-07-21 drh: assert(p->aOp || p->nOp==0); dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nOp; i++){ dbda8d6ce9 2007-07-21 drh: switch( p->aOp[i].opcode ){ dbda8d6ce9 2007-07-21 drh: case OP_Transaction: dbda8d6ce9 2007-07-21 drh: /* This is a bit strange. If we hit a malloc() or IO error and dbda8d6ce9 2007-07-21 drh: ** the statement did not open a statement transaction, we will dbda8d6ce9 2007-07-21 drh: ** rollback any active transaction and abort all other active dbda8d6ce9 2007-07-21 drh: ** statements. Or, if this is an SQLITE_INTERRUPT error, we dbda8d6ce9 2007-07-21 drh: ** will only rollback if the interrupted statement was a write. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It could be argued that read-only statements should never dbda8d6ce9 2007-07-21 drh: ** rollback anything. But careful analysis is required before dbda8d6ce9 2007-07-21 drh: ** making this change dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->aOp[i].p2 || mrc!=SQLITE_INTERRUPT ){ dbda8d6ce9 2007-07-21 drh: isReadOnly = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case OP_Statement: dbda8d6ce9 2007-07-21 drh: isStatement = 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* If the query was read-only, we need do no rollback at all. Otherwise, dbda8d6ce9 2007-07-21 drh: ** proceed with the special handling. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !isReadOnly ){ dbda8d6ce9 2007-07-21 drh: if( p->rc==SQLITE_IOERR_BLOCKED && isStatement ){ dbda8d6ce9 2007-07-21 drh: xFunc = sqlite3BtreeRollbackStmt; dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } else if( p->rc==SQLITE_NOMEM && isStatement ){ dbda8d6ce9 2007-07-21 drh: xFunc = sqlite3BtreeRollbackStmt; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* We are forced to roll back the active transaction. Before doing dbda8d6ce9 2007-07-21 drh: ** so, abort any other statements this handle currently has active. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: invalidateCursorsOnModifiedBtrees(db); dbda8d6ce9 2007-07-21 drh: sqlite3RollbackAll(db); dbda8d6ce9 2007-07-21 drh: db->autoCommit = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the auto-commit flag is set and this is the only active vdbe, then dbda8d6ce9 2007-07-21 drh: ** we do either a commit or rollback of the current transaction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note: This block also runs if one of the special errors handled dbda8d6ce9 2007-07-21 drh: ** above has occured. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->autoCommit && db->activeVdbeCnt==1 ){ dbda8d6ce9 2007-07-21 drh: if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ c287665ba8 2007-09-14 drh: /* The auto-commit flag is true, and the vdbe program was dbda8d6ce9 2007-07-21 drh: ** successful or hit an 'OR FAIL' constraint. This means a commit dbda8d6ce9 2007-07-21 drh: ** is required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int rc = vdbeCommit(db); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_BUSY ){ c287665ba8 2007-09-14 drh: sqlite3BtreeMutexArrayLeave(&p->aMutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: }else if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: p->rc = rc; dbda8d6ce9 2007-07-21 drh: sqlite3RollbackAll(db); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3CommitInternalChanges(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3RollbackAll(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( !xFunc ){ dbda8d6ce9 2007-07-21 drh: if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ dbda8d6ce9 2007-07-21 drh: if( p->openedStatement ){ dbda8d6ce9 2007-07-21 drh: xFunc = sqlite3BtreeCommitStmt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( p->errorAction==OE_Abort ){ dbda8d6ce9 2007-07-21 drh: xFunc = sqlite3BtreeRollbackStmt; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: invalidateCursorsOnModifiedBtrees(db); dbda8d6ce9 2007-07-21 drh: sqlite3RollbackAll(db); dbda8d6ce9 2007-07-21 drh: db->autoCommit = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs dbda8d6ce9 2007-07-21 drh: ** and the return code is still SQLITE_OK, set the return code to the new dbda8d6ce9 2007-07-21 drh: ** error value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert(!xFunc || dbda8d6ce9 2007-07-21 drh: xFunc==sqlite3BtreeCommitStmt || dbda8d6ce9 2007-07-21 drh: xFunc==sqlite3BtreeRollbackStmt dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: for(i=0; xFunc && i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[i].pBt; dbda8d6ce9 2007-07-21 drh: if( pBt ){ dbda8d6ce9 2007-07-21 drh: rc = xFunc(pBt); dbda8d6ce9 2007-07-21 drh: if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){ dbda8d6ce9 2007-07-21 drh: p->rc = rc; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this was an INSERT, UPDATE or DELETE and the statement was committed, dbda8d6ce9 2007-07-21 drh: ** set the change counter. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->changeCntOn && p->pc>=0 ){ dbda8d6ce9 2007-07-21 drh: if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetChanges(db, p->nChange); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetChanges(db, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->nChange = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Rollback or commit any schema changes that occurred. */ dbda8d6ce9 2007-07-21 drh: if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){ dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: db->flags = (db->flags | SQLITE_InternChanges); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* Release the locks */ c287665ba8 2007-09-14 drh: sqlite3BtreeMutexArrayLeave(&p->aMutex); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* We have successfully halted and closed the VM. Record this fact. */ dbda8d6ce9 2007-07-21 drh: if( p->pc>=0 ){ dbda8d6ce9 2007-07-21 drh: db->activeVdbeCnt--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->magic = VDBE_MAGIC_HALT; dbda8d6ce9 2007-07-21 drh: checkActiveVdbeCnt(db); c287665ba8 2007-09-14 drh: if( p->db->mallocFailed ){ c287665ba8 2007-09-14 drh: p->rc = SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: checkActiveVdbeCnt(db); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Each VDBE holds the result of the most recent sqlite3_step() call dbda8d6ce9 2007-07-21 drh: ** in p->rc. This routine sets that result back to SQLITE_OK. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clean up a VDBE after execution but do not delete the VDBE just yet. dbda8d6ce9 2007-07-21 drh: ** Write any error messages into *pzErrMsg. Return the result code. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After this routine is run, the VDBE should be ready to be executed dbda8d6ce9 2007-07-21 drh: ** again. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To look at it another way, this routine resets the state of the dbda8d6ce9 2007-07-21 drh: ** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to dbda8d6ce9 2007-07-21 drh: ** VDBE_MAGIC_INIT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: db = p->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the VM did not run to completion or if it encountered an dbda8d6ce9 2007-07-21 drh: ** error, then it might not have been halted properly. So halt dbda8d6ce9 2007-07-21 drh: ** it now. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeHalt(p); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the VDBE has be run even partially, then transfer the error code dbda8d6ce9 2007-07-21 drh: ** and error message from the VDBE into the main database structure. But dbda8d6ce9 2007-07-21 drh: ** if the VDBE has just been set to run but has not actually executed any dbda8d6ce9 2007-07-21 drh: ** instructions yet, leave the main database error information unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pc>=0 ){ dbda8d6ce9 2007-07-21 drh: if( p->zErrMsg ){ c287665ba8 2007-09-14 drh: sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,sqlite3_free); dbda8d6ce9 2007-07-21 drh: db->errCode = p->rc; dbda8d6ce9 2007-07-21 drh: p->zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: }else if( p->rc ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, p->rc, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_OK, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( p->rc && p->expired ){ dbda8d6ce9 2007-07-21 drh: /* The expired flag was set on the VDBE before the first call dbda8d6ce9 2007-07-21 drh: ** to sqlite3_step(). For consistency (since sqlite3_step() was dbda8d6ce9 2007-07-21 drh: ** called), set the database error in this case as well. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, p->rc, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Reclaim all memory used by the VDBE dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: Cleanup(p); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Save profiling information from this VDBE run. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || !p->aStack ); dbda8d6ce9 2007-07-21 drh: #ifdef VDBE_PROFILE dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: FILE *out = fopen("vdbe_profile.out", "a"); dbda8d6ce9 2007-07-21 drh: if( out ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: fprintf(out, "---- "); dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nOp; i++){ dbda8d6ce9 2007-07-21 drh: fprintf(out, "%02x", p->aOp[i].opcode); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: fprintf(out, "\n"); dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nOp; i++){ dbda8d6ce9 2007-07-21 drh: fprintf(out, "%6d %10lld %8lld ", dbda8d6ce9 2007-07-21 drh: p->aOp[i].cnt, dbda8d6ce9 2007-07-21 drh: p->aOp[i].cycles, dbda8d6ce9 2007-07-21 drh: p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0 dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbePrintOp(out, i, &p->aOp[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: fclose(out); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: p->magic = VDBE_MAGIC_INIT; dbda8d6ce9 2007-07-21 drh: p->aborted = 0; dbda8d6ce9 2007-07-21 drh: return p->rc & db->errMask; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clean up and delete a VDBE after execution. Return an integer which is dbda8d6ce9 2007-07-21 drh: ** the result code. Write any error message text into *pzErrMsg. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeReset(p); dbda8d6ce9 2007-07-21 drh: assert( (rc & p->db->errMask)==rc ); dbda8d6ce9 2007-07-21 drh: }else if( p->magic!=VDBE_MAGIC_INIT ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeDelete(p); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Call the destructor for each auxdata entry in pVdbeFunc for which dbda8d6ce9 2007-07-21 drh: ** the corresponding bit in mask is clear. Auxdata entries beyond 31 dbda8d6ce9 2007-07-21 drh: ** are always destroyed. To destroy all auxdata entries, call this dbda8d6ce9 2007-07-21 drh: ** routine with mask==0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pVdbeFunc->nAux; i++){ dbda8d6ce9 2007-07-21 drh: struct AuxData *pAux = &pVdbeFunc->apAux[i]; dbda8d6ce9 2007-07-21 drh: if( (i>31 || !(mask&(1<<i))) && pAux->pAux ){ dbda8d6ce9 2007-07-21 drh: if( pAux->xDelete ){ dbda8d6ce9 2007-07-21 drh: pAux->xDelete(pAux->pAux); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pAux->pAux = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete an entire VDBE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( p==0 ) return; dbda8d6ce9 2007-07-21 drh: Cleanup(p); dbda8d6ce9 2007-07-21 drh: if( p->pPrev ){ dbda8d6ce9 2007-07-21 drh: p->pPrev->pNext = p->pNext; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( p->db->pVdbe==p ); dbda8d6ce9 2007-07-21 drh: p->db->pVdbe = p->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pNext ){ dbda8d6ce9 2007-07-21 drh: p->pNext->pPrev = p->pPrev; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->aOp ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nOp; i++){ dbda8d6ce9 2007-07-21 drh: Op *pOp = &p->aOp[i]; dbda8d6ce9 2007-07-21 drh: freeP3(pOp->p3type, pOp->p3); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(p->aOp); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: releaseMemArray(p->aVar, p->nVar); c287665ba8 2007-09-14 drh: sqlite3_free(p->aLabel); c287665ba8 2007-09-14 drh: sqlite3_free(p->aStack); dbda8d6ce9 2007-07-21 drh: releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); c287665ba8 2007-09-14 drh: sqlite3_free(p->aColName); c287665ba8 2007-09-14 drh: sqlite3_free(p->zSql); dbda8d6ce9 2007-07-21 drh: p->magic = VDBE_MAGIC_DEAD; c287665ba8 2007-09-14 drh: sqlite3_free(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If a MoveTo operation is pending on the given cursor, then do that dbda8d6ce9 2007-07-21 drh: ** MoveTo now. Return an error code. If no MoveTo is pending, this dbda8d6ce9 2007-07-21 drh: ** routine does nothing and returns SQLITE_OK. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(Cursor *p){ dbda8d6ce9 2007-07-21 drh: if( p->deferredMoveto ){ dbda8d6ce9 2007-07-21 drh: int res, rc; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: extern int sqlite3_search_count; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: assert( p->isTable ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, 0, &res); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: *p->pIncrKey = 0; dbda8d6ce9 2007-07-21 drh: p->lastRowid = keyToInt(p->movetoTarget); dbda8d6ce9 2007-07-21 drh: p->rowidIsValid = res==0; dbda8d6ce9 2007-07-21 drh: if( res<0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeNext(p->pCursor, &res); dbda8d6ce9 2007-07-21 drh: if( rc ) return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: sqlite3_search_count++; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: p->deferredMoveto = 0; dbda8d6ce9 2007-07-21 drh: p->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following functions: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeSerialType() dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeSerialTypeLen() dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeSerialRead() dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeSerialLen() dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeSerialWrite() dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** encapsulate the code that serializes values for storage in SQLite dbda8d6ce9 2007-07-21 drh: ** data and index records. Each serialized value consists of a dbda8d6ce9 2007-07-21 drh: ** 'serial-type' and a blob of data. The serial type is an 8-byte unsigned dbda8d6ce9 2007-07-21 drh: ** integer, stored as a varint. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In an SQLite index record, the serial type is stored directly before dbda8d6ce9 2007-07-21 drh: ** the blob of data that it corresponds to. In a table record, all serial dbda8d6ce9 2007-07-21 drh: ** types are stored at the start of the record, and the blobs of data at dbda8d6ce9 2007-07-21 drh: ** the end. Hence these functions allow the caller to handle the dbda8d6ce9 2007-07-21 drh: ** serial-type and data blob seperately. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following table describes the various storage classes for data: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** serial type bytes of data type dbda8d6ce9 2007-07-21 drh: ** -------------- --------------- --------------- dbda8d6ce9 2007-07-21 drh: ** 0 0 NULL dbda8d6ce9 2007-07-21 drh: ** 1 1 signed integer dbda8d6ce9 2007-07-21 drh: ** 2 2 signed integer dbda8d6ce9 2007-07-21 drh: ** 3 3 signed integer dbda8d6ce9 2007-07-21 drh: ** 4 4 signed integer dbda8d6ce9 2007-07-21 drh: ** 5 6 signed integer dbda8d6ce9 2007-07-21 drh: ** 6 8 signed integer dbda8d6ce9 2007-07-21 drh: ** 7 8 IEEE float dbda8d6ce9 2007-07-21 drh: ** 8 0 Integer constant 0 dbda8d6ce9 2007-07-21 drh: ** 9 0 Integer constant 1 dbda8d6ce9 2007-07-21 drh: ** 10,11 reserved for expansion dbda8d6ce9 2007-07-21 drh: ** N>=12 and even (N-12)/2 BLOB dbda8d6ce9 2007-07-21 drh: ** N>=13 and odd (N-13)/2 text dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The 8 and 9 types were added in 3.3.0, file format 4. Prior versions dbda8d6ce9 2007-07-21 drh: ** of SQLite will not understand those serial types. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the serial-type for the value stored in pMem. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ dbda8d6ce9 2007-07-21 drh: int flags = pMem->flags; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( flags&MEM_Null ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( flags&MEM_Int ){ dbda8d6ce9 2007-07-21 drh: /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ dbda8d6ce9 2007-07-21 drh: # define MAX_6BYTE ((((i64)0x00001000)<<32)-1) dbda8d6ce9 2007-07-21 drh: i64 i = pMem->u.i; dbda8d6ce9 2007-07-21 drh: u64 u; dbda8d6ce9 2007-07-21 drh: if( file_format>=4 && (i&1)==i ){ dbda8d6ce9 2007-07-21 drh: return 8+i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: u = i<0 ? -i : i; dbda8d6ce9 2007-07-21 drh: if( u<=127 ) return 1; dbda8d6ce9 2007-07-21 drh: if( u<=32767 ) return 2; dbda8d6ce9 2007-07-21 drh: if( u<=8388607 ) return 3; dbda8d6ce9 2007-07-21 drh: if( u<=2147483647 ) return 4; dbda8d6ce9 2007-07-21 drh: if( u<=MAX_6BYTE ) return 5; dbda8d6ce9 2007-07-21 drh: return 6; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( flags&MEM_Real ){ dbda8d6ce9 2007-07-21 drh: return 7; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( flags&(MEM_Str|MEM_Blob) ); dbda8d6ce9 2007-07-21 drh: n = pMem->n; dbda8d6ce9 2007-07-21 drh: if( flags & MEM_Zero ){ dbda8d6ce9 2007-07-21 drh: n += pMem->u.i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( n>=0 ); dbda8d6ce9 2007-07-21 drh: return ((n*2) + 12 + ((flags&MEM_Str)!=0)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the length of the data corresponding to the supplied serial-type. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeSerialTypeLen(u32 serial_type){ dbda8d6ce9 2007-07-21 drh: if( serial_type>=12 ){ dbda8d6ce9 2007-07-21 drh: return (serial_type-12)/2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: static const u8 aSize[] = { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, 0, 0 }; dbda8d6ce9 2007-07-21 drh: return aSize[serial_type]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If we are on an architecture with mixed-endian floating dbda8d6ce9 2007-07-21 drh: ** points (ex: ARM7) then swap the lower 4 bytes with the dbda8d6ce9 2007-07-21 drh: ** upper 4 bytes. Return the result. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For most architectures, this is a no-op. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (later): It is reported to me that the mixed-endian problem dbda8d6ce9 2007-07-21 drh: ** on ARM7 is an issue with GCC, not with the ARM7 chip. It seems dbda8d6ce9 2007-07-21 drh: ** that early versions of GCC stored the two words of a 64-bit dbda8d6ce9 2007-07-21 drh: ** float in the wrong order. And that error has been propagated dbda8d6ce9 2007-07-21 drh: ** ever since. The blame is not necessarily with GCC, though. dbda8d6ce9 2007-07-21 drh: ** GCC might have just copying the problem from a prior compiler. dbda8d6ce9 2007-07-21 drh: ** I am also told that newer versions of GCC that follow a different dbda8d6ce9 2007-07-21 drh: ** ABI get the byte order right. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Developers using SQLite on an ARM7 should compile and run their dbda8d6ce9 2007-07-21 drh: ** application using -DSQLITE_DEBUG=1 at least once. With DEBUG dbda8d6ce9 2007-07-21 drh: ** enabled, some asserts below will ensure that the byte order of dbda8d6ce9 2007-07-21 drh: ** floating point values is correct. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (2007-08-30) Frank van Vugt has studied this problem closely c287665ba8 2007-09-14 drh: ** and has send his findings to the SQLite developers. Frank c287665ba8 2007-09-14 drh: ** writes that some Linux kernels offer floating point hardware c287665ba8 2007-09-14 drh: ** emulation that uses only 32-bit mantissas instead of a full c287665ba8 2007-09-14 drh: ** 48-bits as required by the IEEE standard. (This is the c287665ba8 2007-09-14 drh: ** CONFIG_FPE_FASTFPE option.) On such systems, floating point c287665ba8 2007-09-14 drh: ** byte swapping becomes very complicated. To avoid problems, c287665ba8 2007-09-14 drh: ** the necessary byte swapping is carried out using a 64-bit integer c287665ba8 2007-09-14 drh: ** rather than a 64-bit float. Frank assures us that the code here c287665ba8 2007-09-14 drh: ** works for him. We, the developers, have no way to independently c287665ba8 2007-09-14 drh: ** verify this, but Frank seems to know what he is talking about c287665ba8 2007-09-14 drh: ** so we trust him. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT c287665ba8 2007-09-14 drh: static u64 floatSwap(u64 in){ dbda8d6ce9 2007-07-21 drh: union { c287665ba8 2007-09-14 drh: u64 r; dbda8d6ce9 2007-07-21 drh: u32 i[2]; dbda8d6ce9 2007-07-21 drh: } u; dbda8d6ce9 2007-07-21 drh: u32 t; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: u.r = in; dbda8d6ce9 2007-07-21 drh: t = u.i[0]; dbda8d6ce9 2007-07-21 drh: u.i[0] = u.i[1]; dbda8d6ce9 2007-07-21 drh: u.i[1] = t; dbda8d6ce9 2007-07-21 drh: return u.r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: # define swapMixedEndianFloat(X) X = floatSwap(X) dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define swapMixedEndianFloat(X) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write the serialized data blob for the value stored in pMem into dbda8d6ce9 2007-07-21 drh: ** buf. It is assumed that the caller has allocated sufficient space. dbda8d6ce9 2007-07-21 drh: ** Return the number of bytes written. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** nBuf is the amount of space left in buf[]. nBuf must always be dbda8d6ce9 2007-07-21 drh: ** large enough to hold the entire field. Except, if the field is dbda8d6ce9 2007-07-21 drh: ** a blob with a zero-filled tail, then buf[] might be just the right dbda8d6ce9 2007-07-21 drh: ** size to hold everything except for the zero-filled tail. If buf[] dbda8d6ce9 2007-07-21 drh: ** is only big enough to hold the non-zero prefix, then only write that dbda8d6ce9 2007-07-21 drh: ** prefix into buf[]. But if buf[] is large enough to hold both the dbda8d6ce9 2007-07-21 drh: ** prefix and the tail then write the prefix and set the tail to all dbda8d6ce9 2007-07-21 drh: ** zeros. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the number of bytes actually written into buf[]. The number dbda8d6ce9 2007-07-21 drh: ** of bytes in the zero-filled tail is included in the return value only dbda8d6ce9 2007-07-21 drh: ** if those bytes were zeroed in buf[]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){ dbda8d6ce9 2007-07-21 drh: u32 serial_type = sqlite3VdbeSerialType(pMem, file_format); dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Integer and Real */ dbda8d6ce9 2007-07-21 drh: if( serial_type<=7 && serial_type>0 ){ dbda8d6ce9 2007-07-21 drh: u64 v; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( serial_type==7 ){ dbda8d6ce9 2007-07-21 drh: assert( sizeof(v)==sizeof(pMem->r) ); dbda8d6ce9 2007-07-21 drh: memcpy(&v, &pMem->r, sizeof(v)); c287665ba8 2007-09-14 drh: swapMixedEndianFloat(v); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: v = pMem->u.i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: len = i = sqlite3VdbeSerialTypeLen(serial_type); dbda8d6ce9 2007-07-21 drh: assert( len<=nBuf ); dbda8d6ce9 2007-07-21 drh: while( i-- ){ dbda8d6ce9 2007-07-21 drh: buf[i] = (v&0xFF); dbda8d6ce9 2007-07-21 drh: v >>= 8; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return len; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* String or blob */ dbda8d6ce9 2007-07-21 drh: if( serial_type>=12 ){ dbda8d6ce9 2007-07-21 drh: assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.i:0) dbda8d6ce9 2007-07-21 drh: == sqlite3VdbeSerialTypeLen(serial_type) ); dbda8d6ce9 2007-07-21 drh: assert( pMem->n<=nBuf ); dbda8d6ce9 2007-07-21 drh: len = pMem->n; dbda8d6ce9 2007-07-21 drh: memcpy(buf, pMem->z, len); dbda8d6ce9 2007-07-21 drh: if( pMem->flags & MEM_Zero ){ dbda8d6ce9 2007-07-21 drh: len += pMem->u.i; dbda8d6ce9 2007-07-21 drh: if( len>nBuf ){ dbda8d6ce9 2007-07-21 drh: len = nBuf; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memset(&buf[pMem->n], 0, len-pMem->n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return len; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* NULL or constants 0 or 1 */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Deserialize the data blob pointed to by buf as serial type serial_type dbda8d6ce9 2007-07-21 drh: ** and store the result in pMem. Return the number of bytes read. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeSerialGet( dbda8d6ce9 2007-07-21 drh: const unsigned char *buf, /* Buffer to deserialize from */ dbda8d6ce9 2007-07-21 drh: u32 serial_type, /* Serial type to deserialize */ dbda8d6ce9 2007-07-21 drh: Mem *pMem /* Memory cell to write value into */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: switch( serial_type ){ dbda8d6ce9 2007-07-21 drh: case 10: /* Reserved for future use */ dbda8d6ce9 2007-07-21 drh: case 11: /* Reserved for future use */ dbda8d6ce9 2007-07-21 drh: case 0: { /* NULL */ dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 1: { /* 1-byte signed integer */ dbda8d6ce9 2007-07-21 drh: pMem->u.i = (signed char)buf[0]; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 2: { /* 2-byte signed integer */ dbda8d6ce9 2007-07-21 drh: pMem->u.i = (((signed char)buf[0])<<8) | buf[1]; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 3: { /* 3-byte signed integer */ dbda8d6ce9 2007-07-21 drh: pMem->u.i = (((signed char)buf[0])<<16) | (buf[1]<<8) | buf[2]; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: return 3; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 4: { /* 4-byte signed integer */ dbda8d6ce9 2007-07-21 drh: pMem->u.i = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: return 4; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 5: { /* 6-byte signed integer */ dbda8d6ce9 2007-07-21 drh: u64 x = (((signed char)buf[0])<<8) | buf[1]; dbda8d6ce9 2007-07-21 drh: u32 y = (buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5]; dbda8d6ce9 2007-07-21 drh: x = (x<<32) | y; dbda8d6ce9 2007-07-21 drh: pMem->u.i = *(i64*)&x; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: return 6; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 6: /* 8-byte signed integer */ dbda8d6ce9 2007-07-21 drh: case 7: { /* IEEE floating point */ dbda8d6ce9 2007-07-21 drh: u64 x; dbda8d6ce9 2007-07-21 drh: u32 y; dbda8d6ce9 2007-07-21 drh: #if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) dbda8d6ce9 2007-07-21 drh: /* Verify that integers and floating point values use the same dbda8d6ce9 2007-07-21 drh: ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is dbda8d6ce9 2007-07-21 drh: ** defined that 64-bit floating point values really are mixed dbda8d6ce9 2007-07-21 drh: ** endian. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const u64 t1 = ((u64)0x3ff00000)<<32; dbda8d6ce9 2007-07-21 drh: static const double r1 = 1.0; c287665ba8 2007-09-14 drh: u64 t2 = t1; c287665ba8 2007-09-14 drh: swapMixedEndianFloat(t2); c287665ba8 2007-09-14 drh: assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; dbda8d6ce9 2007-07-21 drh: y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7]; dbda8d6ce9 2007-07-21 drh: x = (x<<32) | y; dbda8d6ce9 2007-07-21 drh: if( serial_type==6 ){ dbda8d6ce9 2007-07-21 drh: pMem->u.i = *(i64*)&x; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( sizeof(x)==8 && sizeof(pMem->r)==8 ); c287665ba8 2007-09-14 drh: swapMixedEndianFloat(x); c287665ba8 2007-09-14 drh: memcpy(&pMem->r, &x, sizeof(x)); dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Real; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 8; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case 8: /* Integer 0 */ dbda8d6ce9 2007-07-21 drh: case 9: { /* Integer 1 */ dbda8d6ce9 2007-07-21 drh: pMem->u.i = serial_type-8; dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: int len = (serial_type-12)/2; dbda8d6ce9 2007-07-21 drh: pMem->z = (char *)buf; dbda8d6ce9 2007-07-21 drh: pMem->n = len; dbda8d6ce9 2007-07-21 drh: pMem->xDel = 0; dbda8d6ce9 2007-07-21 drh: if( serial_type&0x01 ){ dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Str | MEM_Ephem; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Blob | MEM_Ephem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return len; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The header of a record consists of a sequence variable-length integers. dbda8d6ce9 2007-07-21 drh: ** These integers are almost always small and are encoded as a single byte. dbda8d6ce9 2007-07-21 drh: ** The following macro takes advantage this fact to provide a fast decode dbda8d6ce9 2007-07-21 drh: ** of the integers in a record header. It is faster for the common case dbda8d6ce9 2007-07-21 drh: ** where the integer is a single byte. It is a little slower when the dbda8d6ce9 2007-07-21 drh: ** integer is two or more bytes. But overall it is faster. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following expressions are equivalent: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** x = sqlite3GetVarint32( A, &B ); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** x = GetVarint( A, B ); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function compares the two table rows or index records specified by dbda8d6ce9 2007-07-21 drh: ** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero dbda8d6ce9 2007-07-21 drh: ** or positive integer if {nKey1, pKey1} is less than, equal to or dbda8d6ce9 2007-07-21 drh: ** greater than {nKey2, pKey2}. Both Key1 and Key2 must be byte strings dbda8d6ce9 2007-07-21 drh: ** composed by the OP_MakeRecord opcode of the VDBE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeRecordCompare( dbda8d6ce9 2007-07-21 drh: void *userData, dbda8d6ce9 2007-07-21 drh: int nKey1, const void *pKey1, dbda8d6ce9 2007-07-21 drh: int nKey2, const void *pKey2 dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo = (KeyInfo*)userData; dbda8d6ce9 2007-07-21 drh: u32 d1, d2; /* Offset into aKey[] of next data element */ dbda8d6ce9 2007-07-21 drh: u32 idx1, idx2; /* Offset into aKey[] of next header element */ dbda8d6ce9 2007-07-21 drh: u32 szHdr1, szHdr2; /* Number of bytes in header */ dbda8d6ce9 2007-07-21 drh: int i = 0; dbda8d6ce9 2007-07-21 drh: int nField; dbda8d6ce9 2007-07-21 drh: int rc = 0; dbda8d6ce9 2007-07-21 drh: const unsigned char *aKey1 = (const unsigned char *)pKey1; dbda8d6ce9 2007-07-21 drh: const unsigned char *aKey2 = (const unsigned char *)pKey2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: Mem mem1; dbda8d6ce9 2007-07-21 drh: Mem mem2; dbda8d6ce9 2007-07-21 drh: mem1.enc = pKeyInfo->enc; c287665ba8 2007-09-14 drh: mem1.db = pKeyInfo->db; dbda8d6ce9 2007-07-21 drh: mem2.enc = pKeyInfo->enc; c287665ba8 2007-09-14 drh: mem2.db = pKeyInfo->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: idx1 = GetVarint(aKey1, szHdr1); dbda8d6ce9 2007-07-21 drh: d1 = szHdr1; dbda8d6ce9 2007-07-21 drh: idx2 = GetVarint(aKey2, szHdr2); dbda8d6ce9 2007-07-21 drh: d2 = szHdr2; dbda8d6ce9 2007-07-21 drh: nField = pKeyInfo->nField; dbda8d6ce9 2007-07-21 drh: while( idx1<szHdr1 && idx2<szHdr2 ){ dbda8d6ce9 2007-07-21 drh: u32 serial_type1; dbda8d6ce9 2007-07-21 drh: u32 serial_type2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read the serial types for the next element in each key. */ dbda8d6ce9 2007-07-21 drh: idx1 += GetVarint( aKey1+idx1, serial_type1 ); dbda8d6ce9 2007-07-21 drh: if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break; dbda8d6ce9 2007-07-21 drh: idx2 += GetVarint( aKey2+idx2, serial_type2 ); dbda8d6ce9 2007-07-21 drh: if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Extract the values to be compared. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); dbda8d6ce9 2007-07-21 drh: d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do the comparison dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0); dbda8d6ce9 2007-07-21 drh: if( mem1.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem1); dbda8d6ce9 2007-07-21 drh: if( mem2.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem2); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* One of the keys ran out of fields, but all the fields up to that point dbda8d6ce9 2007-07-21 drh: ** were equal. If the incrKey flag is true, then the second key is dbda8d6ce9 2007-07-21 drh: ** treated as larger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc==0 ){ dbda8d6ce9 2007-07-21 drh: if( pKeyInfo->incrKey ){ dbda8d6ce9 2007-07-21 drh: rc = -1; dbda8d6ce9 2007-07-21 drh: }else if( d1<nKey1 ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: }else if( d2<nKey2 ){ dbda8d6ce9 2007-07-21 drh: rc = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField dbda8d6ce9 2007-07-21 drh: && pKeyInfo->aSortOrder[i] ){ dbda8d6ce9 2007-07-21 drh: rc = -rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The argument is an index entry composed using the OP_MakeRecord opcode. dbda8d6ce9 2007-07-21 drh: ** The last entry in this record should be an integer (specifically dbda8d6ce9 2007-07-21 drh: ** an integer rowid). This routine returns the number of bytes in dbda8d6ce9 2007-07-21 drh: ** that integer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeIdxRowidLen(const u8 *aKey){ dbda8d6ce9 2007-07-21 drh: u32 szHdr; /* Size of the header */ dbda8d6ce9 2007-07-21 drh: u32 typeRowid; /* Serial type of the rowid */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3GetVarint32(aKey, &szHdr); dbda8d6ce9 2007-07-21 drh: sqlite3GetVarint32(&aKey[szHdr-1], &typeRowid); dbda8d6ce9 2007-07-21 drh: return sqlite3VdbeSerialTypeLen(typeRowid); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pCur points at an index entry created using the OP_MakeRecord opcode. dbda8d6ce9 2007-07-21 drh: ** Read the rowid (the last field in the record) and store it in *rowid. dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK if everything works, or an error code otherwise. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ dbda8d6ce9 2007-07-21 drh: i64 nCellKey = 0; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: u32 szHdr; /* Size of the header */ dbda8d6ce9 2007-07-21 drh: u32 typeRowid; /* Serial type of the rowid */ dbda8d6ce9 2007-07-21 drh: u32 lenRowid; /* Size of the rowid */ dbda8d6ce9 2007-07-21 drh: Mem m, v; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3BtreeKeySize(pCur, &nCellKey); dbda8d6ce9 2007-07-21 drh: if( nCellKey<=0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3GetVarint32((u8*)m.z, &szHdr); dbda8d6ce9 2007-07-21 drh: sqlite3GetVarint32((u8*)&m.z[szHdr-1], &typeRowid); dbda8d6ce9 2007-07-21 drh: lenRowid = sqlite3VdbeSerialTypeLen(typeRowid); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v); dbda8d6ce9 2007-07-21 drh: *rowid = v.u.i; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(&m); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compare the key of the index entry that cursor pC is point to against dbda8d6ce9 2007-07-21 drh: ** the key string in pKey (of length nKey). Write into *pRes a number dbda8d6ce9 2007-07-21 drh: ** that is negative, zero, or positive if pC is less than, equal to, dbda8d6ce9 2007-07-21 drh: ** or greater than pKey. Return SQLITE_OK on success. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pKey is either created without a rowid or is truncated so that it dbda8d6ce9 2007-07-21 drh: ** omits the rowid at the end. The rowid at the end of the index entry dbda8d6ce9 2007-07-21 drh: ** is ignored as well. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( dbda8d6ce9 2007-07-21 drh: Cursor *pC, /* The cursor to compare against */ dbda8d6ce9 2007-07-21 drh: int nKey, const u8 *pKey, /* The key to compare */ dbda8d6ce9 2007-07-21 drh: int *res /* Write the comparison result here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: i64 nCellKey = 0; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: BtCursor *pCur = pC->pCursor; dbda8d6ce9 2007-07-21 drh: int lenRowid; dbda8d6ce9 2007-07-21 drh: Mem m; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3BtreeKeySize(pCur, &nCellKey); dbda8d6ce9 2007-07-21 drh: if( nCellKey<=0 ){ dbda8d6ce9 2007-07-21 drh: *res = 0; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z); dbda8d6ce9 2007-07-21 drh: *res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(&m); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine sets the value to be returned by subsequent calls to dbda8d6ce9 2007-07-21 drh: ** sqlite3_changes() on the database handle 'db'. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: db->nChange = nChange; dbda8d6ce9 2007-07-21 drh: db->nTotalChange += nChange; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set a flag in the vdbe to update the change counter when it is finalised dbda8d6ce9 2007-07-21 drh: ** or reset. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){ dbda8d6ce9 2007-07-21 drh: v->changeCntOn = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Mark every prepared statement associated with a database connection dbda8d6ce9 2007-07-21 drh: ** as expired. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An expired statement means that recompilation of the statement is dbda8d6ce9 2007-07-21 drh: ** recommend. Statements expire when things happen that make their dbda8d6ce9 2007-07-21 drh: ** programs obsolete. Removing user-defined functions or collating dbda8d6ce9 2007-07-21 drh: ** sequences, or changing an authorization function are the types of dbda8d6ce9 2007-07-21 drh: ** things that make prepared statements obsolete. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: Vdbe *p; dbda8d6ce9 2007-07-21 drh: for(p = db->pVdbe; p; p=p->pNext){ dbda8d6ce9 2007-07-21 drh: p->expired = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the database associated with the Vdbe. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){ dbda8d6ce9 2007-07-21 drh: return v->db; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vdbeaux.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vdbeapi.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2004 May 26 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains code use to implement APIs that are part of the dbda8d6ce9 2007-07-21 drh: ** VDBE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE (non-zero) of the statement supplied as an argument needs dbda8d6ce9 2007-07-21 drh: ** to be recompiled. A statement needs to be recompiled whenever the dbda8d6ce9 2007-07-21 drh: ** execution environment changes in a way that would alter the program dbda8d6ce9 2007-07-21 drh: ** that sqlite3_prepare() generates. For example, if new functions or dbda8d6ce9 2007-07-21 drh: ** collating sequences are registered or if an authorizer function is dbda8d6ce9 2007-07-21 drh: ** added or changed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){ dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe*)pStmt; dbda8d6ce9 2007-07-21 drh: return p==0 || p->expired; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The following routine destroys a virtual machine that is created by c287665ba8 2007-09-14 drh: ** the sqlite3_compile() routine. The integer returned is an SQLITE_ c287665ba8 2007-09-14 drh: ** success/failure code that describes the result of executing the virtual c287665ba8 2007-09-14 drh: ** machine. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine sets the error code and string returned by c287665ba8 2007-09-14 drh: ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: if( pStmt==0 ){ c287665ba8 2007-09-14 drh: rc = SQLITE_OK; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: Vdbe *v = (Vdbe*)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = v->db->mutex; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: rc = sqlite3VdbeFinalize(v); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Terminate the current execution of an SQL statement and reset it c287665ba8 2007-09-14 drh: ** back to its starting state so that it can be reused. A success code from c287665ba8 2007-09-14 drh: ** the prior execution is returned. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This routine sets the error code and string returned by c287665ba8 2007-09-14 drh: ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: if( pStmt==0 ){ c287665ba8 2007-09-14 drh: rc = SQLITE_OK; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: Vdbe *v = (Vdbe*)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(v->db->mutex); c287665ba8 2007-09-14 drh: rc = sqlite3VdbeReset(v); c287665ba8 2007-09-14 drh: sqlite3VdbeMakeReady(v, -1, 0, 0, 0); c287665ba8 2007-09-14 drh: assert( (rc & (v->db->errMask))==rc ); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(v->db->mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Set all the parameters in the compiled SQL statement to NULL. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ c287665ba8 2007-09-14 drh: int i; c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: Vdbe *v = (Vdbe*)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(v->db->mutex); c287665ba8 2007-09-14 drh: for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){ c287665ba8 2007-09-14 drh: rc = sqlite3_bind_null(pStmt, i); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(v->db->mutex); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /**************************** sqlite3_value_ ******************************* dbda8d6ce9 2007-07-21 drh: ** The following routines extract information from a Mem or sqlite3_value dbda8d6ce9 2007-07-21 drh: ** structure. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: Mem *p = (Mem*)pVal; dbda8d6ce9 2007-07-21 drh: if( p->flags & (MEM_Blob|MEM_Str) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemExpandBlob(p); dbda8d6ce9 2007-07-21 drh: p->flags &= ~MEM_Str; dbda8d6ce9 2007-07-21 drh: p->flags |= MEM_Blob; dbda8d6ce9 2007-07-21 drh: return p->z; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return sqlite3_value_text(pVal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: return sqlite3ValueBytes(pVal, SQLITE_UTF8); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: return sqlite3VdbeRealValue((Mem*)pVal); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: return sqlite3VdbeIntValue((Mem*)pVal); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: return sqlite3VdbeIntValue((Mem*)pVal); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){ dbda8d6ce9 2007-07-21 drh: return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: return sqlite3ValueText(pVal, SQLITE_UTF16BE); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: return sqlite3ValueText(pVal, SQLITE_UTF16LE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ dbda8d6ce9 2007-07-21 drh: return pVal->type; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /**************************** sqlite3_result_ ******************************* dbda8d6ce9 2007-07-21 drh: ** The following routines are used by user-defined functions to specify dbda8d6ce9 2007-07-21 drh: ** the function result. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_blob( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: const void *z, dbda8d6ce9 2007-07-21 drh: int n, dbda8d6ce9 2007-07-21 drh: void (*xDel)(void *) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: assert( n>=0 ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetDouble(&pCtx->s, rVal); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: pCtx->isError = 1; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: pCtx->isError = 1; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetInt64(&pCtx->s, iVal); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetNull(&pCtx->s); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_text( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: const char *z, dbda8d6ce9 2007-07-21 drh: int n, dbda8d6ce9 2007-07-21 drh: void (*xDel)(void *) dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_text16( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: const void *z, dbda8d6ce9 2007-07-21 drh: int n, dbda8d6ce9 2007-07-21 drh: void (*xDel)(void *) dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, xDel); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_text16be( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: const void *z, dbda8d6ce9 2007-07-21 drh: int n, dbda8d6ce9 2007-07-21 drh: void (*xDel)(void *) dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16BE, xDel); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_text16le( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: const void *z, dbda8d6ce9 2007-07-21 drh: int n, dbda8d6ce9 2007-07-21 drh: void (*xDel)(void *) dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemCopy(&pCtx->s, pValue); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetZeroBlob(&pCtx->s, n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Force an SQLITE_TOOBIG error. */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetZeroBlob(&pCtx->s, SQLITE_MAX_LENGTH+1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* An SQLITE_NOMEM error. */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); c287665ba8 2007-09-14 drh: sqlite3VdbeMemSetNull(&pCtx->s); c287665ba8 2007-09-14 drh: pCtx->isError = 1; c287665ba8 2007-09-14 drh: pCtx->s.db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Execute the statement pStmt, either until a row of data is ready, the dbda8d6ce9 2007-07-21 drh: ** statement is completely executed or an error occurs. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine implements the bulk of the logic behind the sqlite_step() dbda8d6ce9 2007-07-21 drh: ** API. The only thing omitted is the automatic recompile if a dbda8d6ce9 2007-07-21 drh: ** schema change has occurred. That detail is handled by the dbda8d6ce9 2007-07-21 drh: ** outer sqlite3_step() wrapper procedure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int sqlite3Step(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Assert that malloc() has not failed */ c287665ba8 2007-09-14 drh: db = p->db; c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( p==0 || p->magic!=VDBE_MAGIC_RUN ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->aborted ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ABORT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pc<=0 && p->expired ){ dbda8d6ce9 2007-07-21 drh: if( p->rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_SCHEMA; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: goto end_of_step; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ){ dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pc<0 ){ dbda8d6ce9 2007-07-21 drh: /* If there are no other statements currently running, then dbda8d6ce9 2007-07-21 drh: ** reset the interrupt flag. This prevents a call to sqlite3_interrupt dbda8d6ce9 2007-07-21 drh: ** from interrupting a statement that has not yet started. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->activeVdbeCnt==0 ){ dbda8d6ce9 2007-07-21 drh: db->u1.isInterrupted = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRACE dbda8d6ce9 2007-07-21 drh: /* Invoke the trace callback if there is one dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->xTrace && !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: assert( p->nOp>0 ); dbda8d6ce9 2007-07-21 drh: assert( p->aOp[p->nOp-1].opcode==OP_Noop ); dbda8d6ce9 2007-07-21 drh: assert( p->aOp[p->nOp-1].p3!=0 ); dbda8d6ce9 2007-07-21 drh: assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC ); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: db->xTrace(db->pTraceArg, p->aOp[p->nOp-1].p3); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ){ dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( db->xProfile && !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: double rNow; c287665ba8 2007-09-14 drh: sqlite3OsCurrentTime(db->pVfs, &rNow); dbda8d6ce9 2007-07-21 drh: p->startTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned dbda8d6ce9 2007-07-21 drh: ** on in debugging mode. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: if( (db->flags & SQLITE_SqlTrace)!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("SQL-trace: %s\n", p->aOp[p->nOp-1].p3); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_DEBUG */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: db->activeVdbeCnt++; dbda8d6ce9 2007-07-21 drh: p->pc = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_EXPLAIN dbda8d6ce9 2007-07-21 drh: if( p->explain ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeList(p); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_EXPLAIN */ dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeExec(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRACE dbda8d6ce9 2007-07-21 drh: /* Invoke the profile callback if there is one dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: double rNow; dbda8d6ce9 2007-07-21 drh: u64 elapseTime; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3OsCurrentTime(db->pVfs, &rNow); dbda8d6ce9 2007-07-21 drh: elapseTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0 - p->startTime; dbda8d6ce9 2007-07-21 drh: assert( p->nOp>0 ); dbda8d6ce9 2007-07-21 drh: assert( p->aOp[p->nOp-1].opcode==OP_Noop ); dbda8d6ce9 2007-07-21 drh: assert( p->aOp[p->nOp-1].p3!=0 ); dbda8d6ce9 2007-07-21 drh: assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC ); dbda8d6ce9 2007-07-21 drh: db->xProfile(db->pProfileArg, p->aOp[p->nOp-1].p3, elapseTime); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3Error(p->db, rc, 0); dbda8d6ce9 2007-07-21 drh: p->rc = sqlite3ApiExit(p->db, p->rc); dbda8d6ce9 2007-07-21 drh: end_of_step: dbda8d6ce9 2007-07-21 drh: assert( (rc&0xff)==rc ); dbda8d6ce9 2007-07-21 drh: if( p->zSql && (rc&0xff)<SQLITE_ROW ){ dbda8d6ce9 2007-07-21 drh: /* This behavior occurs if sqlite3_prepare_v2() was used to build dbda8d6ce9 2007-07-21 drh: ** the prepared statement. Return error codes directly */ dbda8d6ce9 2007-07-21 drh: sqlite3Error(p->db, p->rc, 0); dbda8d6ce9 2007-07-21 drh: return p->rc; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* This is for legacy sqlite3_prepare() builds and when the code dbda8d6ce9 2007-07-21 drh: ** is SQLITE_ROW or SQLITE_DONE */ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is the top-level implementation of sqlite3_step(). Call dbda8d6ce9 2007-07-21 drh: ** sqlite3Step() to do most of the work. If a schema error occurs, dbda8d6ce9 2007-07-21 drh: ** call sqlite3Reprepare() and try again. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_PARSER dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: Vdbe *v; c287665ba8 2007-09-14 drh: v = (Vdbe*)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(v->db->mutex); c287665ba8 2007-09-14 drh: rc = sqlite3Step(v); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(v->db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ dbda8d6ce9 2007-07-21 drh: int cnt = 0; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Vdbe *v = (Vdbe*)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(v->db->mutex); dbda8d6ce9 2007-07-21 drh: while( (rc = sqlite3Step(v))==SQLITE_SCHEMA dbda8d6ce9 2007-07-21 drh: && cnt++ < 5 dbda8d6ce9 2007-07-21 drh: && sqlite3Reprepare(v) ){ dbda8d6ce9 2007-07-21 drh: sqlite3_reset(pStmt); dbda8d6ce9 2007-07-21 drh: v->expired = 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(v->db->mutex); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Extract the user data from a sqlite3_context structure and return a dbda8d6ce9 2007-07-21 drh: ** pointer to it. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ dbda8d6ce9 2007-07-21 drh: assert( p && p->pFunc ); dbda8d6ce9 2007-07-21 drh: return p->pFunc->pUserData; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following is the implementation of an SQL function that always dbda8d6ce9 2007-07-21 drh: ** fails with an error message stating that the function is used in the dbda8d6ce9 2007-07-21 drh: ** wrong context. The sqlite3_overload_function() API might construct dbda8d6ce9 2007-07-21 drh: ** SQL function that use this routine so that the functions will exist dbda8d6ce9 2007-07-21 drh: ** for name resolution but are actually overloaded by the xFindFunction dbda8d6ce9 2007-07-21 drh: ** method of virtual tables. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3InvalidFunction( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, /* The function calling context */ dbda8d6ce9 2007-07-21 drh: int argc, /* Number of arguments to the function */ dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv /* Value of each argument */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const char *zName = context->pFunc->zName; dbda8d6ce9 2007-07-21 drh: char *zErr; c287665ba8 2007-09-14 drh: zErr = sqlite3MPrintf(0, dbda8d6ce9 2007-07-21 drh: "unable to use function %s in the requested context", zName); dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context, zErr, -1); c287665ba8 2007-09-14 drh: sqlite3_free(zErr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate or return the aggregate context for a user function. A new dbda8d6ce9 2007-07-21 drh: ** context is allocated on the first call. Subsequent calls return the dbda8d6ce9 2007-07-21 drh: ** same context that was returned on prior calls. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ c287665ba8 2007-09-14 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: assert( p && p->pFunc && p->pFunc->xStep ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(p->s.db->mutex) ); c287665ba8 2007-09-14 drh: pMem = p->pMem; dbda8d6ce9 2007-07-21 drh: if( (pMem->flags & MEM_Agg)==0 ){ dbda8d6ce9 2007-07-21 drh: if( nByte==0 ){ dbda8d6ce9 2007-07-21 drh: assert( pMem->flags==MEM_Null ); dbda8d6ce9 2007-07-21 drh: pMem->z = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pMem->flags = MEM_Agg; c287665ba8 2007-09-14 drh: pMem->xDel = sqlite3_free; dbda8d6ce9 2007-07-21 drh: pMem->u.pDef = p->pFunc; dbda8d6ce9 2007-07-21 drh: if( nByte<=NBFS ){ dbda8d6ce9 2007-07-21 drh: pMem->z = pMem->zShort; dbda8d6ce9 2007-07-21 drh: memset(pMem->z, 0, nByte); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: pMem->z = sqlite3DbMallocZero(p->s.db, nByte); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return (void*)pMem->z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the auxilary data pointer, if any, for the iArg'th argument to dbda8d6ce9 2007-07-21 drh: ** the user-function defined by pCtx. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ c287665ba8 2007-09-14 drh: VdbeFunc *pVdbeFunc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); c287665ba8 2007-09-14 drh: pVdbeFunc = pCtx->pVdbeFunc; dbda8d6ce9 2007-07-21 drh: if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pVdbeFunc->apAux[iArg].pAux; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the auxilary data pointer and delete function, for the iArg'th dbda8d6ce9 2007-07-21 drh: ** argument to the user-function defined by pCtx. Any previous value is dbda8d6ce9 2007-07-21 drh: ** deleted by calling the delete function specified when it was set. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_set_auxdata( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: int iArg, dbda8d6ce9 2007-07-21 drh: void *pAux, dbda8d6ce9 2007-07-21 drh: void (*xDelete)(void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: struct AuxData *pAuxData; dbda8d6ce9 2007-07-21 drh: VdbeFunc *pVdbeFunc; c287665ba8 2007-09-14 drh: if( iArg<0 ) goto failed; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); dbda8d6ce9 2007-07-21 drh: pVdbeFunc = pCtx->pVdbeFunc; dbda8d6ce9 2007-07-21 drh: if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){ c287665ba8 2007-09-14 drh: int nAux = (pVdbeFunc ? pVdbeFunc->nAux : 0); dbda8d6ce9 2007-07-21 drh: int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg; c287665ba8 2007-09-14 drh: pVdbeFunc = sqlite3DbRealloc(pCtx->s.db, pVdbeFunc, nMalloc); c287665ba8 2007-09-14 drh: if( !pVdbeFunc ){ c287665ba8 2007-09-14 drh: goto failed; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: pCtx->pVdbeFunc = pVdbeFunc; c287665ba8 2007-09-14 drh: memset(&pVdbeFunc->apAux[nAux], 0, sizeof(struct AuxData)*(iArg+1-nAux)); dbda8d6ce9 2007-07-21 drh: pVdbeFunc->nAux = iArg+1; dbda8d6ce9 2007-07-21 drh: pVdbeFunc->pFunc = pCtx->pFunc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pAuxData = &pVdbeFunc->apAux[iArg]; dbda8d6ce9 2007-07-21 drh: if( pAuxData->pAux && pAuxData->xDelete ){ dbda8d6ce9 2007-07-21 drh: pAuxData->xDelete(pAuxData->pAux); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pAuxData->pAux = pAux; dbda8d6ce9 2007-07-21 drh: pAuxData->xDelete = xDelete; c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: failed: c287665ba8 2007-09-14 drh: if( xDelete ){ c287665ba8 2007-09-14 drh: xDelete(pAux); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of times the Step function of a aggregate has been dbda8d6ce9 2007-07-21 drh: ** called. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This function is deprecated. Do not use it for new code. It is dbda8d6ce9 2007-07-21 drh: ** provide only to avoid breaking legacy code. New aggregate function dbda8d6ce9 2007-07-21 drh: ** implementations should keep their own counts within their aggregate dbda8d6ce9 2007-07-21 drh: ** context. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){ dbda8d6ce9 2007-07-21 drh: assert( p && p->pFunc && p->pFunc->xStep ); dbda8d6ce9 2007-07-21 drh: return p->pMem->n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of columns in the result set for the statement pStmt. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){ dbda8d6ce9 2007-07-21 drh: Vdbe *pVm = (Vdbe *)pStmt; dbda8d6ce9 2007-07-21 drh: return pVm ? pVm->nResColumn : 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of values available from the current row of the dbda8d6ce9 2007-07-21 drh: ** currently executing statement pStmt. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){ dbda8d6ce9 2007-07-21 drh: Vdbe *pVm = (Vdbe *)pStmt; dbda8d6ce9 2007-07-21 drh: if( pVm==0 || !pVm->resOnStack ) return 0; dbda8d6ce9 2007-07-21 drh: return pVm->nResColumn; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if column iCol of the given statement is valid. If dbda8d6ce9 2007-07-21 drh: ** it is, return a pointer to the Mem for the value of that column. dbda8d6ce9 2007-07-21 drh: ** If iCol is not valid, return a pointer to a Mem which has a value dbda8d6ce9 2007-07-21 drh: ** of NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static Mem *columnMem(sqlite3_stmt *pStmt, int i){ c287665ba8 2007-09-14 drh: Vdbe *pVm; c287665ba8 2007-09-14 drh: int vals; c287665ba8 2007-09-14 drh: Mem *pOut; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pVm = (Vdbe *)pStmt; c287665ba8 2007-09-14 drh: if( pVm && pVm->resOnStack && i<pVm->nResColumn && i>=0 ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(pVm->db->mutex); c287665ba8 2007-09-14 drh: vals = sqlite3_data_count(pStmt); c287665ba8 2007-09-14 drh: pOut = &pVm->pTos[(1-vals)+i]; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: static const Mem nullMem = {{0}, 0.0, 0, "", 0, MEM_Null, SQLITE_NULL }; c287665ba8 2007-09-14 drh: if( pVm->db ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(pVm->db->mutex); c287665ba8 2007-09-14 drh: sqlite3Error(pVm->db, SQLITE_RANGE, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pOut = (Mem*)&nullMem; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return pOut; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is called after invoking an sqlite3_value_XXX function on a dbda8d6ce9 2007-07-21 drh: ** column value (i.e. a value returned by evaluating an SQL expression in the dbda8d6ce9 2007-07-21 drh: ** select list of a SELECT statement) that may cause a malloc() failure. If dbda8d6ce9 2007-07-21 drh: ** malloc() has failed, the threads mallocFailed flag is cleared and the result dbda8d6ce9 2007-07-21 drh: ** code of statement pStmt set to SQLITE_NOMEM. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** Specifically, this is called from within: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_int() dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_int64() dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_text() dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_text16() dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_real() dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_bytes() dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_bytes16() dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** But not for sqlite3_column_blob(), which never calls malloc(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void columnMallocFailure(sqlite3_stmt *pStmt) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: /* If malloc() failed during an encoding conversion within an dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_XXX API, then set the return code of the statement to dbda8d6ce9 2007-07-21 drh: ** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR dbda8d6ce9 2007-07-21 drh: ** and _finalize() will return NOMEM. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe *)pStmt; c287665ba8 2007-09-14 drh: if( p ){ c287665ba8 2007-09-14 drh: p->rc = sqlite3ApiExit(p->db, p->rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /**************************** sqlite3_column_ ******************************* dbda8d6ce9 2007-07-21 drh: ** The following routines are used to access elements of the current row dbda8d6ce9 2007-07-21 drh: ** in the result set. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: const void *val; dbda8d6ce9 2007-07-21 drh: val = sqlite3_value_blob( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: /* Even though there is no encoding conversion, value_blob() might dbda8d6ce9 2007-07-21 drh: ** need to call malloc() to expand the result of a zeroblob() dbda8d6ce9 2007-07-21 drh: ** expression. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: columnMallocFailure(pStmt); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: int val = sqlite3_value_bytes( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: columnMallocFailure(pStmt); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: int val = sqlite3_value_bytes16( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: columnMallocFailure(pStmt); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: double val = sqlite3_value_double( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: columnMallocFailure(pStmt); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: int val = sqlite3_value_int( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: columnMallocFailure(pStmt); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: columnMallocFailure(pStmt); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: columnMallocFailure(pStmt); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){ c287665ba8 2007-09-14 drh: sqlite3_value *pOut = columnMem(pStmt, i); c287665ba8 2007-09-14 drh: columnMallocFailure(pStmt); c287665ba8 2007-09-14 drh: return pOut; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: const void *val = sqlite3_value_text16( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: columnMallocFailure(pStmt); dbda8d6ce9 2007-07-21 drh: return val; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ c287665ba8 2007-09-14 drh: int iType = sqlite3_value_type( columnMem(pStmt,i) ); c287665ba8 2007-09-14 drh: columnMallocFailure(pStmt); c287665ba8 2007-09-14 drh: return iType; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following function is experimental and subject to change or dbda8d6ce9 2007-07-21 drh: ** removal */ dbda8d6ce9 2007-07-21 drh: /*int sqlite3_column_numeric_type(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: ** return sqlite3_value_numeric_type( columnMem(pStmt,i) ); dbda8d6ce9 2007-07-21 drh: **} dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert the N-th element of pStmt->pColName[] into a string using dbda8d6ce9 2007-07-21 drh: ** xFunc() then return that string. If N is out of range, return 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There are up to 5 names for each column. useType determines which dbda8d6ce9 2007-07-21 drh: ** name is returned. Here are the names: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 0 The column name as it should be displayed for output dbda8d6ce9 2007-07-21 drh: ** 1 The datatype name for the column dbda8d6ce9 2007-07-21 drh: ** 2 The name of the database that the column derives from dbda8d6ce9 2007-07-21 drh: ** 3 The name of the table that the column derives from dbda8d6ce9 2007-07-21 drh: ** 4 The name of the table column that the result column derives from dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the result is not a simple column reference (if it is an expression dbda8d6ce9 2007-07-21 drh: ** or a constant) then useTypes 2, 3, and 4 return NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const void *columnName( dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pStmt, dbda8d6ce9 2007-07-21 drh: int N, dbda8d6ce9 2007-07-21 drh: const void *(*xFunc)(Mem*), dbda8d6ce9 2007-07-21 drh: int useType dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: const void *ret = 0; dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe *)pStmt; c287665ba8 2007-09-14 drh: int n; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( p!=0 ){ c287665ba8 2007-09-14 drh: n = sqlite3_column_count(pStmt); c287665ba8 2007-09-14 drh: if( N<n && N>=0 ){ c287665ba8 2007-09-14 drh: N += useType*n; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->db->mutex); c287665ba8 2007-09-14 drh: ret = xFunc(&p->aColName[N]); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* A malloc may have failed inside of the xFunc() call. If this c287665ba8 2007-09-14 drh: ** is the case, clear the mallocFailed flag and return NULL. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( p->db && p->db->mallocFailed ){ c287665ba8 2007-09-14 drh: p->db->mallocFailed = 0; c287665ba8 2007-09-14 drh: ret = 0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: return ret; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the name of the Nth column of the result set returned by SQL dbda8d6ce9 2007-07-21 drh: ** statement pStmt. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the column declaration type (if applicable) of the 'i'th column dbda8d6ce9 2007-07-21 drh: ** of the result set of SQL statement pStmt. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_COLUMN_METADATA dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the name of the database from which a result column derives. dbda8d6ce9 2007-07-21 drh: ** NULL is returned if the result column is an expression or constant or dbda8d6ce9 2007-07-21 drh: ** anything else which is not an unabiguous reference to a database column. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the name of the table from which a result column derives. dbda8d6ce9 2007-07-21 drh: ** NULL is returned if the result column is an expression or constant or dbda8d6ce9 2007-07-21 drh: ** anything else which is not an unabiguous reference to a database column. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the name of the table column from which a result column derives. dbda8d6ce9 2007-07-21 drh: ** NULL is returned if the result column is an expression or constant or dbda8d6ce9 2007-07-21 drh: ** anything else which is not an unabiguous reference to a database column. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ dbda8d6ce9 2007-07-21 drh: return columnName( dbda8d6ce9 2007-07-21 drh: pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ENABLE_COLUMN_METADATA */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /******************************* sqlite3_bind_ *************************** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Routines used to attach values to wildcards in a compiled SQL statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Unbind the value bound to variable i in virtual machine p. This is the dbda8d6ce9 2007-07-21 drh: ** the same as binding a NULL value to the column. If the "i" parameter is dbda8d6ce9 2007-07-21 drh: ** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The error code stored in database p->db is overwritten with the return dbda8d6ce9 2007-07-21 drh: ** value in any case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int vdbeUnbind(Vdbe *p, int i){ dbda8d6ce9 2007-07-21 drh: Mem *pVar; dbda8d6ce9 2007-07-21 drh: if( p==0 || p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){ dbda8d6ce9 2007-07-21 drh: if( p ) sqlite3Error(p->db, SQLITE_MISUSE, 0); dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<1 || i>p->nVar ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(p->db, SQLITE_RANGE, 0); dbda8d6ce9 2007-07-21 drh: return SQLITE_RANGE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i--; dbda8d6ce9 2007-07-21 drh: pVar = &p->aVar[i]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pVar); dbda8d6ce9 2007-07-21 drh: pVar->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: sqlite3Error(p->db, SQLITE_OK, 0); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Bind a text or BLOB value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int bindText( c287665ba8 2007-09-14 drh: sqlite3_stmt *pStmt, /* The statement to bind against */ c287665ba8 2007-09-14 drh: int i, /* Index of the parameter to bind */ c287665ba8 2007-09-14 drh: const void *zData, /* Pointer to the data to be bound */ c287665ba8 2007-09-14 drh: int nData, /* Number of bytes of data to be bound */ c287665ba8 2007-09-14 drh: void (*xDel)(void*), /* Destructor for the data */ c287665ba8 2007-09-14 drh: int encoding /* Encoding for the data */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe *)pStmt; dbda8d6ce9 2007-07-21 drh: Mem *pVar; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( p==0 ){ c287665ba8 2007-09-14 drh: return SQLITE_MISUSE; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->db->mutex); dbda8d6ce9 2007-07-21 drh: rc = vdbeUnbind(p, i); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK && zData!=0 ){ c287665ba8 2007-09-14 drh: pVar = &p->aVar[i-1]; c287665ba8 2007-09-14 drh: rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK && encoding!=0 ){ c287665ba8 2007-09-14 drh: rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3Error(p->db, rc, 0); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(p->db, rc); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Bind a blob value to an SQL statement variable. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_blob( dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pStmt, dbda8d6ce9 2007-07-21 drh: int i, dbda8d6ce9 2007-07-21 drh: const void *zData, dbda8d6ce9 2007-07-21 drh: int nData, dbda8d6ce9 2007-07-21 drh: void (*xDel)(void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return bindText(pStmt, i, zData, nData, xDel, 0); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe *)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->db->mutex); dbda8d6ce9 2007-07-21 drh: rc = vdbeUnbind(p, i); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){ dbda8d6ce9 2007-07-21 drh: return sqlite3_bind_int64(p, i, (i64)iValue); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe *)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->db->mutex); dbda8d6ce9 2007-07-21 drh: rc = vdbeUnbind(p, i); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: Vdbe *p = (Vdbe*)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->db->mutex); c287665ba8 2007-09-14 drh: rc = vdbeUnbind(p, i); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_text( dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pStmt, dbda8d6ce9 2007-07-21 drh: int i, dbda8d6ce9 2007-07-21 drh: const char *zData, dbda8d6ce9 2007-07-21 drh: int nData, dbda8d6ce9 2007-07-21 drh: void (*xDel)(void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_text16( dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pStmt, dbda8d6ce9 2007-07-21 drh: int i, dbda8d6ce9 2007-07-21 drh: const void *zData, dbda8d6ce9 2007-07-21 drh: int nData, dbda8d6ce9 2007-07-21 drh: void (*xDel)(void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe *)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->db->mutex); dbda8d6ce9 2007-07-21 drh: rc = vdbeUnbind(p, i); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = sqlite3VdbeMemCopy(&p->aVar[i-1], pValue); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe *)pStmt; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->db->mutex); dbda8d6ce9 2007-07-21 drh: rc = vdbeUnbind(p, i); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of wildcards that can be potentially bound to. dbda8d6ce9 2007-07-21 drh: ** This routine is added to support DBD::SQLite. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe*)pStmt; dbda8d6ce9 2007-07-21 drh: return p ? p->nVar : 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a mapping from variable numbers to variable names dbda8d6ce9 2007-07-21 drh: ** in the Vdbe.azVar[] array, if such a mapping does not already dbda8d6ce9 2007-07-21 drh: ** exist. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void createVarMap(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: if( !p->okVar ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(p->db->mutex); c287665ba8 2007-09-14 drh: if( !p->okVar ){ c287665ba8 2007-09-14 drh: int j; c287665ba8 2007-09-14 drh: Op *pOp; c287665ba8 2007-09-14 drh: for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){ c287665ba8 2007-09-14 drh: if( pOp->opcode==OP_Variable ){ c287665ba8 2007-09-14 drh: assert( pOp->p1>0 && pOp->p1<=p->nVar ); c287665ba8 2007-09-14 drh: p->azVar[pOp->p1-1] = pOp->p3; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p->okVar = 1; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(p->db->mutex); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the name of a wildcard parameter. Return NULL if the index dbda8d6ce9 2007-07-21 drh: ** is out of range or if the wildcard is unnamed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The result is always UTF-8. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe*)pStmt; dbda8d6ce9 2007-07-21 drh: if( p==0 || i<1 || i>p->nVar ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: createVarMap(p); dbda8d6ce9 2007-07-21 drh: return p->azVar[i-1]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given a wildcard parameter name, return the index of the variable dbda8d6ce9 2007-07-21 drh: ** with that name. If there is no variable with the given name, dbda8d6ce9 2007-07-21 drh: ** return 0. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){ dbda8d6ce9 2007-07-21 drh: Vdbe *p = (Vdbe*)pStmt; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( p==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: createVarMap(p); dbda8d6ce9 2007-07-21 drh: if( zName ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nVar; i++){ dbda8d6ce9 2007-07-21 drh: const char *z = p->azVar[i]; dbda8d6ce9 2007-07-21 drh: if( z && strcmp(z,zName)==0 ){ dbda8d6ce9 2007-07-21 drh: return i+1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Transfer all bindings from the first statement over to the second. dbda8d6ce9 2007-07-21 drh: ** If the two statements contain a different number of bindings, then dbda8d6ce9 2007-07-21 drh: ** an SQLITE_ERROR is returned. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ dbda8d6ce9 2007-07-21 drh: Vdbe *pFrom = (Vdbe*)pFromStmt; dbda8d6ce9 2007-07-21 drh: Vdbe *pTo = (Vdbe*)pToStmt; dbda8d6ce9 2007-07-21 drh: int i, rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( (pFrom->magic!=VDBE_MAGIC_RUN && pFrom->magic!=VDBE_MAGIC_HALT) c287665ba8 2007-09-14 drh: || (pTo->magic!=VDBE_MAGIC_RUN && pTo->magic!=VDBE_MAGIC_HALT) c287665ba8 2007-09-14 drh: || pTo->db!=pFrom->db ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pFrom->nVar!=pTo->nVar ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(pTo->db->mutex); dbda8d6ce9 2007-07-21 drh: for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3MallocDisallow(); dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]); dbda8d6ce9 2007-07-21 drh: sqlite3MallocAllow(); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(pTo->db->mutex); dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the sqlite3* database handle to which the prepared statement given dbda8d6ce9 2007-07-21 drh: ** in the argument belongs. This is the same database handle that was dbda8d6ce9 2007-07-21 drh: ** the first argument to the sqlite3_prepare() that was used to create dbda8d6ce9 2007-07-21 drh: ** the statement in the first place. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){ dbda8d6ce9 2007-07-21 drh: return pStmt ? ((Vdbe*)pStmt)->db : 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vdbeapi.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vdbe.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** The code in this file implements execution method of the dbda8d6ce9 2007-07-21 drh: ** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c") dbda8d6ce9 2007-07-21 drh: ** handles housekeeping details such as creating and deleting dbda8d6ce9 2007-07-21 drh: ** VDBE instances. This file is solely interested in executing dbda8d6ce9 2007-07-21 drh: ** the VDBE program. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the external interface, an "sqlite3_stmt*" is an opaque pointer dbda8d6ce9 2007-07-21 drh: ** to a VDBE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The SQL parser generates a program which is then executed by dbda8d6ce9 2007-07-21 drh: ** the VDBE to do the work of the SQL statement. VDBE programs are dbda8d6ce9 2007-07-21 drh: ** similar in form to assembly language. The program consists of dbda8d6ce9 2007-07-21 drh: ** a linear sequence of operations. Each operation has an opcode dbda8d6ce9 2007-07-21 drh: ** and 3 operands. Operands P1 and P2 are integers. Operand P3 dbda8d6ce9 2007-07-21 drh: ** is a null-terminated string. The P2 operand must be non-negative. dbda8d6ce9 2007-07-21 drh: ** Opcodes will typically ignore one or more operands. Many opcodes dbda8d6ce9 2007-07-21 drh: ** ignore all three operands. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Computation results are stored on a stack. Each entry on the dbda8d6ce9 2007-07-21 drh: ** stack is either an integer, a null-terminated string, a floating point dbda8d6ce9 2007-07-21 drh: ** number, or the SQL "NULL" value. An inplicit conversion from one dbda8d6ce9 2007-07-21 drh: ** type to the other occurs as necessary. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Most of the code in this file is taken up by the sqlite3VdbeExec() dbda8d6ce9 2007-07-21 drh: ** function which does the work of interpreting a VDBE program. dbda8d6ce9 2007-07-21 drh: ** But other routines are also provided to help in building up dbda8d6ce9 2007-07-21 drh: ** a program instruction by instruction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Various scripts scan this source file in order to generate HTML dbda8d6ce9 2007-07-21 drh: ** documentation, headers files, or other derived files. The formatting dbda8d6ce9 2007-07-21 drh: ** of the code in this file is, therefore, important. See other comments dbda8d6ce9 2007-07-21 drh: ** in this file for details. If in doubt, do not deviate from existing dbda8d6ce9 2007-07-21 drh: ** commenting and indentation practices when changing or adding code. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: vdbe.c,v 1.650 2007/09/03 15:19:36 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following global variable is incremented every time a cursor dbda8d6ce9 2007-07-21 drh: ** moves, either by the OP_MoveXX, OP_Next, or OP_Prev opcodes. The test dbda8d6ce9 2007-07-21 drh: ** procedures use this information to make sure that indices are dbda8d6ce9 2007-07-21 drh: ** working correctly. This variable has no function other than to dbda8d6ce9 2007-07-21 drh: ** help verify the correct operation of the library. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_search_count = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** When this global variable is positive, it gets decremented once before dbda8d6ce9 2007-07-21 drh: ** each instruction in the VDBE. When reaches zero, the u1.isInterrupted dbda8d6ce9 2007-07-21 drh: ** field of the sqlite3 structure is set in order to simulate and interrupt. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This facility is used for testing purposes only. It does not function dbda8d6ce9 2007-07-21 drh: ** in an ordinary build. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_interrupt_count = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The next global variable is incremented each type the OP_Sort opcode dbda8d6ce9 2007-07-21 drh: ** is executed. The test procedures use this information to make sure that dbda8d6ce9 2007-07-21 drh: ** sorting is occurring or not occuring at appropriate times. This variable dbda8d6ce9 2007-07-21 drh: ** has no function other than to help verify the correct operation of the dbda8d6ce9 2007-07-21 drh: ** library. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_sort_count = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The next global variable records the size of the largest MEM_Blob dbda8d6ce9 2007-07-21 drh: ** or MEM_Str that has appeared on the VDBE stack. The test procedures dbda8d6ce9 2007-07-21 drh: ** use this information to make sure that the zero-blob functionality dbda8d6ce9 2007-07-21 drh: ** is working correctly. This variable has no function other than to dbda8d6ce9 2007-07-21 drh: ** help verify the correct operation of the library. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_max_blobsize = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Release the memory associated with the given stack level. This dbda8d6ce9 2007-07-21 drh: ** leaves the Mem.flags field in an inconsistent state. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define Release(P) if((P)->flags&MEM_Dyn){ sqlite3VdbeMemRelease(P); } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert the given stack entity into a string if it isn't one dbda8d6ce9 2007-07-21 drh: ** already. Return non-zero if a malloc() fails. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define Stringify(P, enc) \ dbda8d6ce9 2007-07-21 drh: if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc)) \ dbda8d6ce9 2007-07-21 drh: { goto no_mem; } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The header of a record consists of a sequence variable-length integers. dbda8d6ce9 2007-07-21 drh: ** These integers are almost always small and are encoded as a single byte. dbda8d6ce9 2007-07-21 drh: ** The following macro takes advantage this fact to provide a fast decode dbda8d6ce9 2007-07-21 drh: ** of the integers in a record header. It is faster for the common case dbda8d6ce9 2007-07-21 drh: ** where the integer is a single byte. It is a little slower when the dbda8d6ce9 2007-07-21 drh: ** integer is two or more bytes. But overall it is faster. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following expressions are equivalent: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** x = sqlite3GetVarint32( A, &B ); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** x = GetVarint( A, B ); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An ephemeral string value (signified by the MEM_Ephem flag) contains dbda8d6ce9 2007-07-21 drh: ** a pointer to a dynamically allocated string where some other entity dbda8d6ce9 2007-07-21 drh: ** is responsible for deallocating that string. Because the stack entry dbda8d6ce9 2007-07-21 drh: ** does not control the string, it might be deleted without the stack dbda8d6ce9 2007-07-21 drh: ** entry knowing it. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine converts an ephemeral string into a dynamically allocated dbda8d6ce9 2007-07-21 drh: ** string that the stack entry itself controls. In other words, it dbda8d6ce9 2007-07-21 drh: ** converts an MEM_Ephem string into an MEM_Dyn string. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define Deephemeralize(P) \ dbda8d6ce9 2007-07-21 drh: if( ((P)->flags&MEM_Ephem)!=0 \ dbda8d6ce9 2007-07-21 drh: && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) dbda8d6ce9 2007-07-21 drh: ** P if required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Argument pMem points at a memory cell that will be passed to a dbda8d6ce9 2007-07-21 drh: ** user-defined function or returned to the user as the result of a query. dbda8d6ce9 2007-07-21 drh: ** The second argument, 'db_enc' is the text encoding used by the vdbe for dbda8d6ce9 2007-07-21 drh: ** stack variables. This routine sets the pMem->enc and pMem->type dbda8d6ce9 2007-07-21 drh: ** variables used by the sqlite3_value_*() routines. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define storeTypeInfo(A,B) _storeTypeInfo(A) dbda8d6ce9 2007-07-21 drh: static void _storeTypeInfo(Mem *pMem){ dbda8d6ce9 2007-07-21 drh: int flags = pMem->flags; dbda8d6ce9 2007-07-21 drh: if( flags & MEM_Null ){ dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_NULL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: else if( flags & MEM_Int ){ dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_INTEGER; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: else if( flags & MEM_Real ){ dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_FLOAT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: else if( flags & MEM_Str ){ dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_TEXT; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pMem->type = SQLITE_BLOB; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Pop the stack N times. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void popStack(Mem **ppTos, int N){ dbda8d6ce9 2007-07-21 drh: Mem *pTos = *ppTos; dbda8d6ce9 2007-07-21 drh: while( N>0 ){ dbda8d6ce9 2007-07-21 drh: N--; dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *ppTos = pTos; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate cursor number iCur. Return a pointer to it. Return NULL dbda8d6ce9 2007-07-21 drh: ** if we run out of memory. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static Cursor *allocateCursor(Vdbe *p, int iCur, int iDb){ dbda8d6ce9 2007-07-21 drh: Cursor *pCx; dbda8d6ce9 2007-07-21 drh: assert( iCur<p->nCursor ); dbda8d6ce9 2007-07-21 drh: if( p->apCsr[iCur] ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: p->apCsr[iCur] = pCx = sqlite3MallocZero( sizeof(Cursor) ); dbda8d6ce9 2007-07-21 drh: if( pCx ){ dbda8d6ce9 2007-07-21 drh: pCx->iDb = iDb; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pCx; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Try to convert a value into a numeric representation if we can dbda8d6ce9 2007-07-21 drh: ** do so without loss of information. In other words, if the string dbda8d6ce9 2007-07-21 drh: ** looks like a number, convert it into a number. If it does not dbda8d6ce9 2007-07-21 drh: ** look like a number, leave it alone. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void applyNumericAffinity(Mem *pRec){ dbda8d6ce9 2007-07-21 drh: if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){ dbda8d6ce9 2007-07-21 drh: int realnum; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemNulTerminate(pRec); dbda8d6ce9 2007-07-21 drh: if( (pRec->flags&MEM_Str) dbda8d6ce9 2007-07-21 drh: && sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){ dbda8d6ce9 2007-07-21 drh: i64 value; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8); dbda8d6ce9 2007-07-21 drh: if( !realnum && sqlite3Atoi64(pRec->z, &value) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pRec); dbda8d6ce9 2007-07-21 drh: pRec->u.i = value; dbda8d6ce9 2007-07-21 drh: pRec->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRealify(pRec); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Processing is determine by the affinity parameter: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_AFF_INTEGER: dbda8d6ce9 2007-07-21 drh: ** SQLITE_AFF_REAL: dbda8d6ce9 2007-07-21 drh: ** SQLITE_AFF_NUMERIC: dbda8d6ce9 2007-07-21 drh: ** Try to convert pRec to an integer representation or a dbda8d6ce9 2007-07-21 drh: ** floating-point representation if an integer representation dbda8d6ce9 2007-07-21 drh: ** is not possible. Note that the integer representation is dbda8d6ce9 2007-07-21 drh: ** always preferred, even if the affinity is REAL, because dbda8d6ce9 2007-07-21 drh: ** an integer representation is more space efficient on disk. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_AFF_TEXT: dbda8d6ce9 2007-07-21 drh: ** Convert pRec to a text representation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_AFF_NONE: dbda8d6ce9 2007-07-21 drh: ** No-op. pRec is unchanged. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static void applyAffinity( c287665ba8 2007-09-14 drh: Mem *pRec, /* The value to apply affinity to */ c287665ba8 2007-09-14 drh: char affinity, /* The affinity to be applied */ c287665ba8 2007-09-14 drh: u8 enc /* Use this text encoding */ c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: if( affinity==SQLITE_AFF_TEXT ){ dbda8d6ce9 2007-07-21 drh: /* Only attempt the conversion to TEXT if there is an integer or real dbda8d6ce9 2007-07-21 drh: ** representation (blob and NULL do not get converted) but no string dbda8d6ce9 2007-07-21 drh: ** representation. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemStringify(pRec, enc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pRec->flags &= ~(MEM_Real|MEM_Int); dbda8d6ce9 2007-07-21 drh: }else if( affinity!=SQLITE_AFF_NONE ){ dbda8d6ce9 2007-07-21 drh: assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL dbda8d6ce9 2007-07-21 drh: || affinity==SQLITE_AFF_NUMERIC ); dbda8d6ce9 2007-07-21 drh: applyNumericAffinity(pRec); dbda8d6ce9 2007-07-21 drh: if( pRec->flags & MEM_Real ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeIntegerAffinity(pRec); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Try to convert the type of a function argument or a result column dbda8d6ce9 2007-07-21 drh: ** into a numeric representation. Use either INTEGER or REAL whichever dbda8d6ce9 2007-07-21 drh: ** is appropriate. But only do the conversion if it is possible without dbda8d6ce9 2007-07-21 drh: ** loss of information and return the revised type of the argument. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is an EXPERIMENTAL api and is subject to change or removal. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ dbda8d6ce9 2007-07-21 drh: Mem *pMem = (Mem*)pVal; dbda8d6ce9 2007-07-21 drh: applyNumericAffinity(pMem); dbda8d6ce9 2007-07-21 drh: storeTypeInfo(pMem, 0); dbda8d6ce9 2007-07-21 drh: return pMem->type; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Exported version of applyAffinity(). This one works on sqlite3_value*, dbda8d6ce9 2007-07-21 drh: ** not the internal Mem* type. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3ValueApplyAffinity( c287665ba8 2007-09-14 drh: sqlite3_value *pVal, c287665ba8 2007-09-14 drh: u8 affinity, c287665ba8 2007-09-14 drh: u8 enc c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: applyAffinity((Mem *)pVal, affinity, enc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write a nice string representation of the contents of cell pMem dbda8d6ce9 2007-07-21 drh: ** into buffer zBuf, length nBuf. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ dbda8d6ce9 2007-07-21 drh: char *zCsr = zBuf; dbda8d6ce9 2007-07-21 drh: int f = pMem->flags; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"}; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( f&MEM_Blob ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: char c; dbda8d6ce9 2007-07-21 drh: if( f & MEM_Dyn ){ dbda8d6ce9 2007-07-21 drh: c = 'z'; dbda8d6ce9 2007-07-21 drh: assert( (f & (MEM_Static|MEM_Ephem))==0 ); dbda8d6ce9 2007-07-21 drh: }else if( f & MEM_Static ){ dbda8d6ce9 2007-07-21 drh: c = 't'; dbda8d6ce9 2007-07-21 drh: assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); dbda8d6ce9 2007-07-21 drh: }else if( f & MEM_Ephem ){ dbda8d6ce9 2007-07-21 drh: c = 'e'; dbda8d6ce9 2007-07-21 drh: assert( (f & (MEM_Static|MEM_Dyn))==0 ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: c = 's'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(100, zCsr, "%c", c); dbda8d6ce9 2007-07-21 drh: zCsr += strlen(zCsr); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(100, zCsr, "%d[", pMem->n); dbda8d6ce9 2007-07-21 drh: zCsr += strlen(zCsr); dbda8d6ce9 2007-07-21 drh: for(i=0; i<16 && i<pMem->n; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF)); dbda8d6ce9 2007-07-21 drh: zCsr += strlen(zCsr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<16 && i<pMem->n; i++){ dbda8d6ce9 2007-07-21 drh: char z = pMem->z[i]; dbda8d6ce9 2007-07-21 drh: if( z<32 || z>126 ) *zCsr++ = '.'; dbda8d6ce9 2007-07-21 drh: else *zCsr++ = z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]); dbda8d6ce9 2007-07-21 drh: zCsr += strlen(zCsr); dbda8d6ce9 2007-07-21 drh: if( f & MEM_Zero ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(100, zCsr,"+%lldz",pMem->u.i); dbda8d6ce9 2007-07-21 drh: zCsr += strlen(zCsr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *zCsr = '\0'; dbda8d6ce9 2007-07-21 drh: }else if( f & MEM_Str ){ dbda8d6ce9 2007-07-21 drh: int j, k; dbda8d6ce9 2007-07-21 drh: zBuf[0] = ' '; dbda8d6ce9 2007-07-21 drh: if( f & MEM_Dyn ){ dbda8d6ce9 2007-07-21 drh: zBuf[1] = 'z'; dbda8d6ce9 2007-07-21 drh: assert( (f & (MEM_Static|MEM_Ephem))==0 ); dbda8d6ce9 2007-07-21 drh: }else if( f & MEM_Static ){ dbda8d6ce9 2007-07-21 drh: zBuf[1] = 't'; dbda8d6ce9 2007-07-21 drh: assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); dbda8d6ce9 2007-07-21 drh: }else if( f & MEM_Ephem ){ dbda8d6ce9 2007-07-21 drh: zBuf[1] = 'e'; dbda8d6ce9 2007-07-21 drh: assert( (f & (MEM_Static|MEM_Dyn))==0 ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zBuf[1] = 's'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: k = 2; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n); dbda8d6ce9 2007-07-21 drh: k += strlen(&zBuf[k]); dbda8d6ce9 2007-07-21 drh: zBuf[k++] = '['; dbda8d6ce9 2007-07-21 drh: for(j=0; j<15 && j<pMem->n; j++){ dbda8d6ce9 2007-07-21 drh: u8 c = pMem->z[j]; dbda8d6ce9 2007-07-21 drh: if( c>=0x20 && c<0x7f ){ dbda8d6ce9 2007-07-21 drh: zBuf[k++] = c; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zBuf[k++] = '.'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zBuf[k++] = ']'; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(100,&zBuf[k], encnames[pMem->enc]); dbda8d6ce9 2007-07-21 drh: k += strlen(&zBuf[k]); dbda8d6ce9 2007-07-21 drh: zBuf[k++] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef VDBE_PROFILE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following routine only works on pentium-class processors. dbda8d6ce9 2007-07-21 drh: ** It uses the RDTSC opcode to read the cycle count value out of the dbda8d6ce9 2007-07-21 drh: ** processor and returns that value. This can be used for high-res dbda8d6ce9 2007-07-21 drh: ** profiling. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: __inline__ unsigned long long int hwtime(void){ dbda8d6ce9 2007-07-21 drh: unsigned long long int x; dbda8d6ce9 2007-07-21 drh: __asm__("rdtsc\n\t" dbda8d6ce9 2007-07-21 drh: "mov %%edx, %%ecx\n\t" dbda8d6ce9 2007-07-21 drh: :"=A" (x)); dbda8d6ce9 2007-07-21 drh: return x; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The CHECK_FOR_INTERRUPT macro defined here looks to see if the dbda8d6ce9 2007-07-21 drh: ** sqlite3_interrupt() routine has been called. If it has been, then dbda8d6ce9 2007-07-21 drh: ** processing of the VDBE program is interrupted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This macro added to every instruction that does a jump in order to dbda8d6ce9 2007-07-21 drh: ** implement a loop. This test used to be on every single instruction, dbda8d6ce9 2007-07-21 drh: ** but that meant we more testing that we needed. By only testing the dbda8d6ce9 2007-07-21 drh: ** flag on jump instructions, we get a (small) speed improvement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define CHECK_FOR_INTERRUPT \ dbda8d6ce9 2007-07-21 drh: if( db->u1.isInterrupted ) goto abort_due_to_interrupt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Execute as much of a VDBE program as we can then return. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeMakeReady() must be called before this routine in order to dbda8d6ce9 2007-07-21 drh: ** close the program with a final OP_Halt and to set up the callbacks dbda8d6ce9 2007-07-21 drh: ** and the error message pointer. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Whenever a row or result data is available, this routine will either dbda8d6ce9 2007-07-21 drh: ** invoke the result callback (if there is one) or return with dbda8d6ce9 2007-07-21 drh: ** SQLITE_ROW. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an attempt is made to open a locked database, then this routine dbda8d6ce9 2007-07-21 drh: ** will either invoke the busy callback (if there is one) or it will dbda8d6ce9 2007-07-21 drh: ** return SQLITE_BUSY. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an error occurs, an error message is written to memory obtained c287665ba8 2007-09-14 drh: ** from sqlite3_malloc() and p->zErrMsg is made to point to that memory. dbda8d6ce9 2007-07-21 drh: ** The error code is stored in p->rc and this routine returns SQLITE_ERROR. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the callback ever returns non-zero, then the program exits dbda8d6ce9 2007-07-21 drh: ** immediately. There will be no error message but the p->rc field is dbda8d6ce9 2007-07-21 drh: ** set to SQLITE_ABORT and this routine will return SQLITE_ERROR. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this dbda8d6ce9 2007-07-21 drh: ** routine to return SQLITE_ERROR. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Other fatal errors return SQLITE_ERROR. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After this routine has finished, sqlite3VdbeFinalize() should be dbda8d6ce9 2007-07-21 drh: ** used to clean up the mess that was left behind. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VdbeExec( dbda8d6ce9 2007-07-21 drh: Vdbe *p /* The VDBE */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int pc; /* The program counter */ dbda8d6ce9 2007-07-21 drh: Op *pOp; /* Current operation */ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; /* Value to return */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = p->db; /* The database */ dbda8d6ce9 2007-07-21 drh: u8 encoding = ENC(db); /* The database encoding */ dbda8d6ce9 2007-07-21 drh: Mem *pTos; /* Top entry in the operand stack */ dbda8d6ce9 2007-07-21 drh: #ifdef VDBE_PROFILE dbda8d6ce9 2007-07-21 drh: unsigned long long start; /* CPU clock count at start of opcode */ dbda8d6ce9 2007-07-21 drh: int origPc; /* Program counter at start of opcode */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PROGRESS_CALLBACK dbda8d6ce9 2007-07-21 drh: int nProgressOps = 0; /* Opcodes executed since progress callback. */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: Mem *pStackLimit; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: assert( db->magic==SQLITE_MAGIC_BUSY ); dbda8d6ce9 2007-07-21 drh: pTos = p->pTos; c287665ba8 2007-09-14 drh: sqlite3BtreeMutexArrayEnter(&p->aMutex); dbda8d6ce9 2007-07-21 drh: if( p->rc==SQLITE_NOMEM ){ dbda8d6ce9 2007-07-21 drh: /* This happens if a malloc() inside a call to sqlite3_column_text() or dbda8d6ce9 2007-07-21 drh: ** sqlite3_column_text16() failed. */ dbda8d6ce9 2007-07-21 drh: goto no_mem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY ); dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: assert( p->explain==0 ); dbda8d6ce9 2007-07-21 drh: if( p->popStack ){ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, p->popStack); dbda8d6ce9 2007-07-21 drh: p->popStack = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->resOnStack = 0; dbda8d6ce9 2007-07-21 drh: db->busyHandler.nBusy = 0; dbda8d6ce9 2007-07-21 drh: CHECK_FOR_INTERRUPT; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeIOTraceSql(p); dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: if( (p->db->flags & SQLITE_VdbeListing)!=0 c287665ba8 2007-09-14 drh: || sqlite3OsAccess(db->pVfs, "vdbe_explain", SQLITE_ACCESS_EXISTS) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: printf("VDBE Program Listing:\n"); dbda8d6ce9 2007-07-21 drh: sqlite3VdbePrintSql(p); dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nOp; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbePrintOp(stdout, i, &p->aOp[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( sqlite3OsAccess(db->pVfs, "vdbe_trace", SQLITE_ACCESS_EXISTS) ){ dbda8d6ce9 2007-07-21 drh: p->trace = stdout; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: for(pc=p->pc; rc==SQLITE_OK; pc++){ dbda8d6ce9 2007-07-21 drh: assert( pc>=0 && pc<p->nOp ); dbda8d6ce9 2007-07-21 drh: assert( pTos<=&p->aStack[pc] ); c287665ba8 2007-09-14 drh: if( db->mallocFailed ) goto no_mem; dbda8d6ce9 2007-07-21 drh: #ifdef VDBE_PROFILE dbda8d6ce9 2007-07-21 drh: origPc = pc; dbda8d6ce9 2007-07-21 drh: start = hwtime(); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: pOp = &p->aOp[pc]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Only allow tracing if SQLITE_DEBUG is defined. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: if( p->trace ){ dbda8d6ce9 2007-07-21 drh: if( pc==0 ){ dbda8d6ce9 2007-07-21 drh: printf("VDBE Execution Trace:\n"); dbda8d6ce9 2007-07-21 drh: sqlite3VdbePrintSql(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbePrintOp(p->trace, pc, pOp); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( p->trace==0 && pc==0 c287665ba8 2007-09-14 drh: && sqlite3OsAccess(db->pVfs, "vdbe_sqltrace", SQLITE_ACCESS_EXISTS) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbePrintSql(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to see if we need to simulate an interrupt. This only happens dbda8d6ce9 2007-07-21 drh: ** if we have a special test build. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: if( sqlite3_interrupt_count>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_interrupt_count--; dbda8d6ce9 2007-07-21 drh: if( sqlite3_interrupt_count==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_interrupt(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PROGRESS_CALLBACK dbda8d6ce9 2007-07-21 drh: /* Call the progress callback if it is configured and the required number dbda8d6ce9 2007-07-21 drh: ** of VDBE ops have been executed (either since this invocation of dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeExec() or since last time the progress callback was called). dbda8d6ce9 2007-07-21 drh: ** If the progress callback returns non-zero, exit the virtual machine with dbda8d6ce9 2007-07-21 drh: ** a return code SQLITE_ABORT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->xProgress ){ dbda8d6ce9 2007-07-21 drh: if( db->nProgressOps==nProgressOps ){ dbda8d6ce9 2007-07-21 drh: int prc; dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: prc =db->xProgress(db->pProgressArg); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: if( prc!=0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_INTERRUPT; dbda8d6ce9 2007-07-21 drh: goto vdbe_halt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nProgressOps = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nProgressOps++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* This is to check that the return value of static function dbda8d6ce9 2007-07-21 drh: ** opcodeNoPush() (see vdbeaux.c) returns values that match the dbda8d6ce9 2007-07-21 drh: ** implementation of the virtual machine in this file. If dbda8d6ce9 2007-07-21 drh: ** opcodeNoPush() returns non-zero, then the stack is guarenteed dbda8d6ce9 2007-07-21 drh: ** not to grow when the opcode is executed. If it returns zero, then dbda8d6ce9 2007-07-21 drh: ** the stack may grow by at most 1. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The global wrapper function sqlite3VdbeOpcodeUsesStack() is not dbda8d6ce9 2007-07-21 drh: ** available if NDEBUG is defined at build time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pStackLimit = pTos; dbda8d6ce9 2007-07-21 drh: if( !sqlite3VdbeOpcodeNoPush(pOp->opcode) ){ dbda8d6ce9 2007-07-21 drh: pStackLimit++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: switch( pOp->opcode ){ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /***************************************************************************** dbda8d6ce9 2007-07-21 drh: ** What follows is a massive switch statement where each case implements a dbda8d6ce9 2007-07-21 drh: ** separate instruction in the virtual machine. If we follow the usual dbda8d6ce9 2007-07-21 drh: ** indentation conventions, each case should be indented by 6 spaces. But dbda8d6ce9 2007-07-21 drh: ** that is a lot of wasted space on the left margin. So the code within dbda8d6ce9 2007-07-21 drh: ** the switch statement will break with convention and be flush-left. Another dbda8d6ce9 2007-07-21 drh: ** big comment (similar to this one) will mark the point in the code where dbda8d6ce9 2007-07-21 drh: ** we transition back to normal indentation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The formatting of each case is important. The makefile for SQLite dbda8d6ce9 2007-07-21 drh: ** generates two C files "opcodes.h" and "opcodes.c" by scanning this dbda8d6ce9 2007-07-21 drh: ** file looking for lines that begin with "case OP_". The opcodes.h files dbda8d6ce9 2007-07-21 drh: ** will be filled with #defines that give unique integer values to each dbda8d6ce9 2007-07-21 drh: ** opcode and the opcodes.c file is filled with an array of strings where dbda8d6ce9 2007-07-21 drh: ** each string is the symbolic name for the corresponding opcode. If the dbda8d6ce9 2007-07-21 drh: ** case statement is followed by a comment of the form "/# same as ... #/" dbda8d6ce9 2007-07-21 drh: ** that comment is used to determine the particular value of the opcode. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If a comment on the same line as the "case OP_" construction contains dbda8d6ce9 2007-07-21 drh: ** the word "no-push", then the opcode is guarenteed not to grow the dbda8d6ce9 2007-07-21 drh: ** vdbe stack when it is executed. See function opcode() in dbda8d6ce9 2007-07-21 drh: ** vdbeaux.c for details. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Documentation about VDBE opcodes is generated by scanning this file dbda8d6ce9 2007-07-21 drh: ** for lines of that contain "Opcode:". That line and all subsequent dbda8d6ce9 2007-07-21 drh: ** comment lines are used in the generation of the opcode.html documentation dbda8d6ce9 2007-07-21 drh: ** file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SUMMARY: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Formatting is important to scripts that scan this file. dbda8d6ce9 2007-07-21 drh: ** Do not deviate from the formatting style currently in use. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: *****************************************************************************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Goto * P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An unconditional jump to address P2. dbda8d6ce9 2007-07-21 drh: ** The next instruction executed will be dbda8d6ce9 2007-07-21 drh: ** the one at index P2 from the beginning of dbda8d6ce9 2007-07-21 drh: ** the program. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Goto: { /* no-push */ dbda8d6ce9 2007-07-21 drh: CHECK_FOR_INTERRUPT; dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Gosub * P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push the current address plus 1 onto the return address stack dbda8d6ce9 2007-07-21 drh: ** and then jump to address P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The return address stack is of limited depth. If too many dbda8d6ce9 2007-07-21 drh: ** OP_Gosub operations occur without intervening OP_Returns, then dbda8d6ce9 2007-07-21 drh: ** the return address stack will fill up and processing will abort dbda8d6ce9 2007-07-21 drh: ** with a fatal error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Gosub: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( p->returnDepth<sizeof(p->returnStack)/sizeof(p->returnStack[0]) ); dbda8d6ce9 2007-07-21 drh: p->returnStack[p->returnDepth++] = pc+1; dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Return * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Jump immediately to the next instruction after the last unreturned dbda8d6ce9 2007-07-21 drh: ** OP_Gosub. If an OP_Return has occurred for all OP_Gosubs, then dbda8d6ce9 2007-07-21 drh: ** processing aborts with a fatal error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Return: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( p->returnDepth>0 ); dbda8d6ce9 2007-07-21 drh: p->returnDepth--; dbda8d6ce9 2007-07-21 drh: pc = p->returnStack[p->returnDepth] - 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Halt P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Exit immediately. All open cursors, Fifos, etc are closed dbda8d6ce9 2007-07-21 drh: ** automatically. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(), dbda8d6ce9 2007-07-21 drh: ** or sqlite3_finalize(). For a normal halt, this should be SQLITE_OK (0). dbda8d6ce9 2007-07-21 drh: ** For errors, it can be some other value. If P1!=0 then P2 will determine dbda8d6ce9 2007-07-21 drh: ** whether or not to rollback the current transaction. Do not rollback dbda8d6ce9 2007-07-21 drh: ** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort, dbda8d6ce9 2007-07-21 drh: ** then back out all changes that have occurred during this execution of the dbda8d6ce9 2007-07-21 drh: ** VDBE, but do not rollback the transaction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P3 is not null then it is an error message string. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There is an implied "Halt 0 0 0" instruction inserted at the very end of dbda8d6ce9 2007-07-21 drh: ** every program. So a jump past the last instruction of the program dbda8d6ce9 2007-07-21 drh: ** is the same as executing Halt. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Halt: { /* no-push */ dbda8d6ce9 2007-07-21 drh: p->pTos = pTos; dbda8d6ce9 2007-07-21 drh: p->rc = pOp->p1; dbda8d6ce9 2007-07-21 drh: p->pc = pc; dbda8d6ce9 2007-07-21 drh: p->errorAction = pOp->p2; dbda8d6ce9 2007-07-21 drh: if( pOp->p3 ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeHalt(p); dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_BUSY || rc==SQLITE_OK ); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_BUSY ){ c287665ba8 2007-09-14 drh: p->rc = rc = SQLITE_BUSY; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: goto vdbe_return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Integer P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The 32-bit integer value P1 is pushed onto the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Integer: { dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pTos->u.i = pOp->p1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Int64 * * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is a string representation of an integer. Convert that integer dbda8d6ce9 2007-07-21 drh: ** to a 64-bit value and push it onto the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Int64: { dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: assert( pOp->p3!=0 ); dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Str|MEM_Static|MEM_Term; dbda8d6ce9 2007-07-21 drh: pTos->z = pOp->p3; dbda8d6ce9 2007-07-21 drh: pTos->n = strlen(pTos->z); dbda8d6ce9 2007-07-21 drh: pTos->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: pTos->u.i = sqlite3VdbeIntValue(pTos); dbda8d6ce9 2007-07-21 drh: pTos->flags |= MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Real * * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The string value P3 is converted to a real and pushed on to the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Real: { /* same as TK_FLOAT, */ dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Str|MEM_Static|MEM_Term; dbda8d6ce9 2007-07-21 drh: pTos->z = pOp->p3; dbda8d6ce9 2007-07-21 drh: pTos->n = strlen(pTos->z); dbda8d6ce9 2007-07-21 drh: pTos->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: pTos->r = sqlite3VdbeRealValue(pTos); dbda8d6ce9 2007-07-21 drh: pTos->flags |= MEM_Real; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeEncoding(pTos, encoding); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: String8 * * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 points to a nul terminated UTF-8 string. This opcode is transformed dbda8d6ce9 2007-07-21 drh: ** into an OP_String before it is executed for the first time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_String8: { /* same as TK_STRING */ dbda8d6ce9 2007-07-21 drh: assert( pOp->p3!=0 ); dbda8d6ce9 2007-07-21 drh: pOp->opcode = OP_String; dbda8d6ce9 2007-07-21 drh: pOp->p1 = strlen(pOp->p3); dbda8d6ce9 2007-07-21 drh: assert( SQLITE_MAX_SQL_LENGTH < SQLITE_MAX_LENGTH ); dbda8d6ce9 2007-07-21 drh: assert( pOp->p1 < SQLITE_MAX_LENGTH ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: if( encoding!=SQLITE_UTF8 ){ dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(pTos, pOp->p3, -1, SQLITE_UTF8, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pTos, encoding) ) goto no_mem; dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3VdbeMemDynamicify(pTos) ) goto no_mem; dbda8d6ce9 2007-07-21 drh: pTos->flags &= ~(MEM_Dyn); dbda8d6ce9 2007-07-21 drh: pTos->flags |= MEM_Static; dbda8d6ce9 2007-07-21 drh: if( pOp->p3type==P3_DYNAMIC ){ c287665ba8 2007-09-14 drh: sqlite3_free(pOp->p3); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_DYNAMIC; dbda8d6ce9 2007-07-21 drh: pOp->p3 = pTos->z; dbda8d6ce9 2007-07-21 drh: pOp->p1 = pTos->n; dbda8d6ce9 2007-07-21 drh: assert( pOp->p1 < SQLITE_MAX_LENGTH ); /* Due to SQLITE_MAX_SQL_LENGTH */ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: /* Otherwise fall through to the next case, OP_String */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: String P1 * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The string value P3 of length P1 (bytes) is pushed onto the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_String: { dbda8d6ce9 2007-07-21 drh: assert( pOp->p1 < SQLITE_MAX_LENGTH ); /* Due to SQLITE_MAX_SQL_LENGTH */ dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: assert( pOp->p3!=0 ); dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Str|MEM_Static|MEM_Term; dbda8d6ce9 2007-07-21 drh: pTos->z = pOp->p3; dbda8d6ce9 2007-07-21 drh: pTos->n = pOp->p1; dbda8d6ce9 2007-07-21 drh: pTos->enc = encoding; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Null * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push a NULL onto the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Null: { dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: pTos->n = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_BLOB_LITERAL dbda8d6ce9 2007-07-21 drh: /* Opcode: HexBlob * * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is an UTF-8 SQL hex encoding of a blob. The blob is pushed onto the dbda8d6ce9 2007-07-21 drh: ** vdbe stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first time this instruction executes, in transforms itself into a dbda8d6ce9 2007-07-21 drh: ** 'Blob' opcode with a binary blob as P3. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_HexBlob: { /* same as TK_BLOB */ dbda8d6ce9 2007-07-21 drh: pOp->opcode = OP_Blob; dbda8d6ce9 2007-07-21 drh: pOp->p1 = strlen(pOp->p3)/2; dbda8d6ce9 2007-07-21 drh: assert( SQLITE_MAX_SQL_LENGTH < SQLITE_MAX_LENGTH ); dbda8d6ce9 2007-07-21 drh: assert( pOp->p1 < SQLITE_MAX_LENGTH ); dbda8d6ce9 2007-07-21 drh: if( pOp->p1 ){ c287665ba8 2007-09-14 drh: char *zBlob = sqlite3HexToBlob(db, pOp->p3); dbda8d6ce9 2007-07-21 drh: if( !zBlob ) goto no_mem; dbda8d6ce9 2007-07-21 drh: if( pOp->p3type==P3_DYNAMIC ){ c287665ba8 2007-09-14 drh: sqlite3_free(pOp->p3); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pOp->p3 = zBlob; dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_DYNAMIC; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( pOp->p3type==P3_DYNAMIC ){ c287665ba8 2007-09-14 drh: sqlite3_free(pOp->p3); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_STATIC; dbda8d6ce9 2007-07-21 drh: pOp->p3 = ""; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Fall through to the next case, OP_Blob. */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Blob P1 * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 points to a blob of data P1 bytes long. Push this dbda8d6ce9 2007-07-21 drh: ** value onto the stack. This instruction is not coded directly dbda8d6ce9 2007-07-21 drh: ** by the compiler. Instead, the compiler layer specifies dbda8d6ce9 2007-07-21 drh: ** an OP_HexBlob opcode, with the hex string representation of dbda8d6ce9 2007-07-21 drh: ** the blob as P3. This opcode is transformed to an OP_Blob dbda8d6ce9 2007-07-21 drh: ** the first time it is executed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Blob: { dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: assert( pOp->p1 < SQLITE_MAX_LENGTH ); /* Due to SQLITE_MAX_SQL_LENGTH */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetStr(pTos, pOp->p3, pOp->p1, 0, 0); dbda8d6ce9 2007-07-21 drh: pTos->enc = encoding; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_BLOB_LITERAL */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Variable P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push the value of variable P1 onto the stack. A variable is dbda8d6ce9 2007-07-21 drh: ** an unknown in the original SQL string as handed to sqlite3_compile(). dbda8d6ce9 2007-07-21 drh: ** Any occurance of the '?' character in the original SQL is considered dbda8d6ce9 2007-07-21 drh: ** a variable. Variables in the SQL string are number from left to dbda8d6ce9 2007-07-21 drh: ** right beginning with 1. The values of variables are set using the dbda8d6ce9 2007-07-21 drh: ** sqlite3_bind() API. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Variable: { dbda8d6ce9 2007-07-21 drh: int j = pOp->p1 - 1; dbda8d6ce9 2007-07-21 drh: Mem *pVar; dbda8d6ce9 2007-07-21 drh: assert( j>=0 && j<p->nVar ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pVar = &p->aVar[j]; dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeMemTooBig(pVar) ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemShallowCopy(pTos, &p->aVar[j], MEM_Static); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Pop P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P1 elements are popped off of the top of stack and discarded. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Pop: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 ); dbda8d6ce9 2007-07-21 drh: popStack(&pTos, pOp->p1); dbda8d6ce9 2007-07-21 drh: assert( pTos>=&p->aStack[-1] ); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Dup P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A copy of the P1-th element of the stack dbda8d6ce9 2007-07-21 drh: ** is made and pushed onto the top of the stack. dbda8d6ce9 2007-07-21 drh: ** The top of the stack is element 0. So the dbda8d6ce9 2007-07-21 drh: ** instruction "Dup 0 0 0" will make a copy of the dbda8d6ce9 2007-07-21 drh: ** top of the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the content of the P1-th element is a dynamically dbda8d6ce9 2007-07-21 drh: ** allocated string, then a new copy of that string dbda8d6ce9 2007-07-21 drh: ** is made if P2==0. If P2!=0, then just a pointer dbda8d6ce9 2007-07-21 drh: ** to the string is copied. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Also see the Pull instruction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Dup: { dbda8d6ce9 2007-07-21 drh: Mem *pFrom = &pTos[-pOp->p1]; dbda8d6ce9 2007-07-21 drh: assert( pFrom<=pTos && pFrom>=p->aStack ); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemShallowCopy(pTos, pFrom, MEM_Ephem); dbda8d6ce9 2007-07-21 drh: if( pOp->p2 ){ dbda8d6ce9 2007-07-21 drh: Deephemeralize(pTos); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Pull P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The P1-th element is removed from its current location on dbda8d6ce9 2007-07-21 drh: ** the stack and pushed back on top of the stack. The dbda8d6ce9 2007-07-21 drh: ** top of the stack is element 0, so "Pull 0 0 0" is dbda8d6ce9 2007-07-21 drh: ** a no-op. "Pull 1 0 0" swaps the top two elements of dbda8d6ce9 2007-07-21 drh: ** the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also the Dup instruction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Pull: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pFrom = &pTos[-pOp->p1]; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Mem ts; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: ts = *pFrom; dbda8d6ce9 2007-07-21 drh: Deephemeralize(pTos); dbda8d6ce9 2007-07-21 drh: for(i=0; i<pOp->p1; i++, pFrom++){ dbda8d6ce9 2007-07-21 drh: Deephemeralize(&pFrom[1]); dbda8d6ce9 2007-07-21 drh: assert( (pFrom[1].flags & MEM_Ephem)==0 ); dbda8d6ce9 2007-07-21 drh: *pFrom = pFrom[1]; dbda8d6ce9 2007-07-21 drh: if( pFrom->flags & MEM_Short ){ dbda8d6ce9 2007-07-21 drh: assert( pFrom->flags & (MEM_Str|MEM_Blob) ); dbda8d6ce9 2007-07-21 drh: assert( pFrom->z==pFrom[1].zShort ); dbda8d6ce9 2007-07-21 drh: pFrom->z = pFrom->zShort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pTos = ts; dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Short ){ dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & (MEM_Str|MEM_Blob) ); dbda8d6ce9 2007-07-21 drh: assert( pTos->z==pTos[-pOp->p1].zShort ); dbda8d6ce9 2007-07-21 drh: pTos->z = pTos->zShort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Push P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Overwrite the value of the P1-th element down on the dbda8d6ce9 2007-07-21 drh: ** stack (P1==0 is the top of the stack) with the value dbda8d6ce9 2007-07-21 drh: ** of the top of the stack. Then pop the top of the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Push: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pTo = &pTos[-pOp->p1]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTo>=p->aStack ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemMove(pTo, pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Callback P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top P1 values on the stack represent a single result row from dbda8d6ce9 2007-07-21 drh: ** a query. This opcode causes the sqlite3_step() call to terminate dbda8d6ce9 2007-07-21 drh: ** with an SQLITE_ROW return code and it sets up the sqlite3_stmt dbda8d6ce9 2007-07-21 drh: ** structure to provide access to the top P1 values as the result dbda8d6ce9 2007-07-21 drh: ** row. When the sqlite3_step() function is run again, the top P1 dbda8d6ce9 2007-07-21 drh: ** values will be automatically popped from the stack before the next dbda8d6ce9 2007-07-21 drh: ** instruction executes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Callback: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: Mem *pFirstColumn; dbda8d6ce9 2007-07-21 drh: assert( p->nResColumn==pOp->p1 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Data in the pager might be moved or changed out from under us dbda8d6ce9 2007-07-21 drh: ** in between the return from this sqlite3_step() call and the dbda8d6ce9 2007-07-21 drh: ** next call to sqlite3_step(). So deephermeralize everything on dbda8d6ce9 2007-07-21 drh: ** the stack. Note that ephemeral data is never stored in memory dbda8d6ce9 2007-07-21 drh: ** cells so we do not have to worry about them. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pFirstColumn = &pTos[0-pOp->p1]; dbda8d6ce9 2007-07-21 drh: for(pMem = p->aStack; pMem<pFirstColumn; pMem++){ dbda8d6ce9 2007-07-21 drh: Deephemeralize(pMem); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Invalidate all ephemeral cursor row caches */ dbda8d6ce9 2007-07-21 drh: p->cacheCtr = (p->cacheCtr + 2)|1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the results of the current row are \000 terminated dbda8d6ce9 2007-07-21 drh: ** and have an assigned type. The results are deephemeralized as dbda8d6ce9 2007-07-21 drh: ** as side effect. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(; pMem<=pTos; pMem++ ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemNulTerminate(pMem); dbda8d6ce9 2007-07-21 drh: storeTypeInfo(pMem, encoding); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set up the statement structure so that it will pop the current dbda8d6ce9 2007-07-21 drh: ** results from the stack when the statement returns. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: p->resOnStack = 1; dbda8d6ce9 2007-07-21 drh: p->nCallback++; dbda8d6ce9 2007-07-21 drh: p->popStack = pOp->p1; dbda8d6ce9 2007-07-21 drh: p->pc = pc + 1; dbda8d6ce9 2007-07-21 drh: p->pTos = pTos; c287665ba8 2007-09-14 drh: rc = SQLITE_ROW; c287665ba8 2007-09-14 drh: goto vdbe_return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Concat P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Look at the first P1+2 elements of the stack. Append them all dbda8d6ce9 2007-07-21 drh: ** together with the lowest element first. The original P1+2 elements dbda8d6ce9 2007-07-21 drh: ** are popped from the stack if P2==0 and retained if P2==1. If dbda8d6ce9 2007-07-21 drh: ** any element of the stack is NULL, then the result is NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When P1==1, this routine makes a copy of the top stack element c287665ba8 2007-09-14 drh: ** into memory obtained from sqlite3_malloc(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Concat: { /* same as TK_CONCAT */ dbda8d6ce9 2007-07-21 drh: char *zNew; dbda8d6ce9 2007-07-21 drh: i64 nByte; dbda8d6ce9 2007-07-21 drh: int nField; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: Mem *pTerm; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Loop through the stack elements to see how long the result will be. */ dbda8d6ce9 2007-07-21 drh: nField = pOp->p1 + 2; dbda8d6ce9 2007-07-21 drh: pTerm = &pTos[1-nField]; dbda8d6ce9 2007-07-21 drh: nByte = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nField; i++, pTerm++){ dbda8d6ce9 2007-07-21 drh: assert( pOp->p2==0 || (pTerm->flags&MEM_Str) ); dbda8d6ce9 2007-07-21 drh: if( pTerm->flags&MEM_Null ){ dbda8d6ce9 2007-07-21 drh: nByte = -1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: ExpandBlob(pTerm); dbda8d6ce9 2007-07-21 drh: Stringify(pTerm, encoding); dbda8d6ce9 2007-07-21 drh: nByte += pTerm->n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( nByte<0 ){ dbda8d6ce9 2007-07-21 drh: /* If nByte is less than zero, then there is a NULL value on the stack. dbda8d6ce9 2007-07-21 drh: ** In this case just pop the values off the stack (if required) and dbda8d6ce9 2007-07-21 drh: ** push on a NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pOp->p2==0 ){ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, nField); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Otherwise malloc() space for the result and concatenate all the dbda8d6ce9 2007-07-21 drh: ** stack values. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( nByte+2>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: zNew = sqlite3DbMallocRaw(db, nByte+2 ); dbda8d6ce9 2007-07-21 drh: if( zNew==0 ) goto no_mem; dbda8d6ce9 2007-07-21 drh: j = 0; dbda8d6ce9 2007-07-21 drh: pTerm = &pTos[1-nField]; dbda8d6ce9 2007-07-21 drh: for(i=j=0; i<nField; i++, pTerm++){ dbda8d6ce9 2007-07-21 drh: int n = pTerm->n; dbda8d6ce9 2007-07-21 drh: assert( pTerm->flags & (MEM_Str|MEM_Blob) ); dbda8d6ce9 2007-07-21 drh: memcpy(&zNew[j], pTerm->z, n); dbda8d6ce9 2007-07-21 drh: j += n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zNew[j] = 0; dbda8d6ce9 2007-07-21 drh: zNew[j+1] = 0; dbda8d6ce9 2007-07-21 drh: assert( j==nByte ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pOp->p2==0 ){ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, nField); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->n = j; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Str|MEM_Dyn|MEM_Term; dbda8d6ce9 2007-07-21 drh: pTos->xDel = 0; dbda8d6ce9 2007-07-21 drh: pTos->enc = encoding; dbda8d6ce9 2007-07-21 drh: pTos->z = zNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Add * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack, add them together, dbda8d6ce9 2007-07-21 drh: ** and push the result back onto the stack. If either element dbda8d6ce9 2007-07-21 drh: ** is a string then it is converted to a double using the atof() dbda8d6ce9 2007-07-21 drh: ** function before the addition. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Multiply * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack, multiply them together, dbda8d6ce9 2007-07-21 drh: ** and push the result back onto the stack. If either element dbda8d6ce9 2007-07-21 drh: ** is a string then it is converted to a double using the atof() dbda8d6ce9 2007-07-21 drh: ** function before the multiplication. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Subtract * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack, subtract the dbda8d6ce9 2007-07-21 drh: ** first (what was on top of the stack) from the second (the dbda8d6ce9 2007-07-21 drh: ** next on stack) dbda8d6ce9 2007-07-21 drh: ** and push the result back onto the stack. If either element dbda8d6ce9 2007-07-21 drh: ** is a string then it is converted to a double using the atof() dbda8d6ce9 2007-07-21 drh: ** function before the subtraction. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Divide * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack, divide the dbda8d6ce9 2007-07-21 drh: ** first (what was on top of the stack) from the second (the dbda8d6ce9 2007-07-21 drh: ** next on stack) dbda8d6ce9 2007-07-21 drh: ** and push the result back onto the stack. If either element dbda8d6ce9 2007-07-21 drh: ** is a string then it is converted to a double using the atof() dbda8d6ce9 2007-07-21 drh: ** function before the division. Division by zero returns NULL. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Remainder * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack, divide the dbda8d6ce9 2007-07-21 drh: ** first (what was on top of the stack) from the second (the dbda8d6ce9 2007-07-21 drh: ** next on stack) dbda8d6ce9 2007-07-21 drh: ** and push the remainder after division onto the stack. If either element dbda8d6ce9 2007-07-21 drh: ** is a string then it is converted to a double using the atof() dbda8d6ce9 2007-07-21 drh: ** function before the division. Division by zero returns NULL. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Add: /* same as TK_PLUS, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Subtract: /* same as TK_MINUS, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Multiply: /* same as TK_STAR, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Divide: /* same as TK_SLASH, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Remainder: { /* same as TK_REM, no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pNos = &pTos[-1]; dbda8d6ce9 2007-07-21 drh: int flags; dbda8d6ce9 2007-07-21 drh: assert( pNos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: flags = pTos->flags | pNos->flags; dbda8d6ce9 2007-07-21 drh: if( (flags & MEM_Null)!=0 ){ dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: }else if( (pTos->flags & pNos->flags & MEM_Int)==MEM_Int ){ dbda8d6ce9 2007-07-21 drh: i64 a, b; dbda8d6ce9 2007-07-21 drh: a = pTos->u.i; dbda8d6ce9 2007-07-21 drh: b = pNos->u.i; dbda8d6ce9 2007-07-21 drh: switch( pOp->opcode ){ dbda8d6ce9 2007-07-21 drh: case OP_Add: b += a; break; dbda8d6ce9 2007-07-21 drh: case OP_Subtract: b -= a; break; dbda8d6ce9 2007-07-21 drh: case OP_Multiply: b *= a; break; dbda8d6ce9 2007-07-21 drh: case OP_Divide: { dbda8d6ce9 2007-07-21 drh: if( a==0 ) goto divide_by_zero; dbda8d6ce9 2007-07-21 drh: /* Dividing the largest possible negative 64-bit integer (1<<63) by dbda8d6ce9 2007-07-21 drh: ** -1 returns an integer to large to store in a 64-bit data-type. On dbda8d6ce9 2007-07-21 drh: ** some architectures, the value overflows to (1<<63). On others, dbda8d6ce9 2007-07-21 drh: ** a SIGFPE is issued. The following statement normalizes this dbda8d6ce9 2007-07-21 drh: ** behaviour so that all architectures behave as if integer dbda8d6ce9 2007-07-21 drh: ** overflow occured. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( a==-1 && b==(((i64)1)<<63) ) a = 1; dbda8d6ce9 2007-07-21 drh: b /= a; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: if( a==0 ) goto divide_by_zero; dbda8d6ce9 2007-07-21 drh: if( a==-1 ) a = 1; dbda8d6ce9 2007-07-21 drh: b %= a; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos->u.i = b; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: double a, b; dbda8d6ce9 2007-07-21 drh: a = sqlite3VdbeRealValue(pTos); dbda8d6ce9 2007-07-21 drh: b = sqlite3VdbeRealValue(pNos); dbda8d6ce9 2007-07-21 drh: switch( pOp->opcode ){ dbda8d6ce9 2007-07-21 drh: case OP_Add: b += a; break; dbda8d6ce9 2007-07-21 drh: case OP_Subtract: b -= a; break; dbda8d6ce9 2007-07-21 drh: case OP_Multiply: b *= a; break; dbda8d6ce9 2007-07-21 drh: case OP_Divide: { dbda8d6ce9 2007-07-21 drh: if( a==0.0 ) goto divide_by_zero; dbda8d6ce9 2007-07-21 drh: b /= a; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: i64 ia = (i64)a; dbda8d6ce9 2007-07-21 drh: i64 ib = (i64)b; dbda8d6ce9 2007-07-21 drh: if( ia==0 ) goto divide_by_zero; dbda8d6ce9 2007-07-21 drh: if( ia==-1 ) ia = 1; dbda8d6ce9 2007-07-21 drh: b = ib % ia; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3_isnan(b) ){ dbda8d6ce9 2007-07-21 drh: goto divide_by_zero; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos->r = b; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Real; dbda8d6ce9 2007-07-21 drh: if( (flags & MEM_Real)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeIntegerAffinity(pTos); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: divide_by_zero: dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: CollSeq * * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is a pointer to a CollSeq struct. If the next call to a user function dbda8d6ce9 2007-07-21 drh: ** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will dbda8d6ce9 2007-07-21 drh: ** be returned. This is used by the built-in min(), max() and nullif() dbda8d6ce9 2007-07-21 drh: ** functions. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The interface used by the implementation of the aforementioned functions dbda8d6ce9 2007-07-21 drh: ** to retrieve the collation sequence set by this opcode is not available dbda8d6ce9 2007-07-21 drh: ** publicly, only to user functions defined in func.c. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_CollSeq: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( pOp->p3type==P3_COLLSEQ ); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Function P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Invoke a user function (P3 is a pointer to a Function structure that dbda8d6ce9 2007-07-21 drh: ** defines the function) with P2 arguments taken from the stack. Pop all dbda8d6ce9 2007-07-21 drh: ** arguments from the stack and push back the result. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P1 is a 32-bit bitmask indicating whether or not each argument to the dbda8d6ce9 2007-07-21 drh: ** function was determined to be constant at compile time. If the first dbda8d6ce9 2007-07-21 drh: ** argument was constant then bit 0 of P1 is set. This is used to determine dbda8d6ce9 2007-07-21 drh: ** whether meta data associated with a user function argument using the dbda8d6ce9 2007-07-21 drh: ** sqlite3_set_auxdata() API may be safely retained until the next dbda8d6ce9 2007-07-21 drh: ** invocation of this opcode. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: AggStep and AggFinal dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Function: { dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Mem *pArg; dbda8d6ce9 2007-07-21 drh: sqlite3_context ctx; dbda8d6ce9 2007-07-21 drh: sqlite3_value **apVal; dbda8d6ce9 2007-07-21 drh: int n = pOp->p2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: apVal = p->apArg; dbda8d6ce9 2007-07-21 drh: assert( apVal || n==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pArg = &pTos[1-n]; dbda8d6ce9 2007-07-21 drh: for(i=0; i<n; i++, pArg++){ dbda8d6ce9 2007-07-21 drh: apVal[i] = pArg; dbda8d6ce9 2007-07-21 drh: storeTypeInfo(pArg, encoding); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pOp->p3type==P3_FUNCDEF || pOp->p3type==P3_VDBEFUNC ); dbda8d6ce9 2007-07-21 drh: if( pOp->p3type==P3_FUNCDEF ){ dbda8d6ce9 2007-07-21 drh: ctx.pFunc = (FuncDef*)pOp->p3; dbda8d6ce9 2007-07-21 drh: ctx.pVdbeFunc = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: ctx.pVdbeFunc = (VdbeFunc*)pOp->p3; dbda8d6ce9 2007-07-21 drh: ctx.pFunc = ctx.pVdbeFunc->pFunc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: ctx.s.flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: ctx.s.z = 0; dbda8d6ce9 2007-07-21 drh: ctx.s.xDel = 0; c287665ba8 2007-09-14 drh: ctx.s.db = db; dbda8d6ce9 2007-07-21 drh: ctx.isError = 0; dbda8d6ce9 2007-07-21 drh: if( ctx.pFunc->needCollSeq ){ dbda8d6ce9 2007-07-21 drh: assert( pOp>p->aOp ); dbda8d6ce9 2007-07-21 drh: assert( pOp[-1].p3type==P3_COLLSEQ ); dbda8d6ce9 2007-07-21 drh: assert( pOp[-1].opcode==OP_CollSeq ); dbda8d6ce9 2007-07-21 drh: ctx.pColl = (CollSeq *)pOp[-1].p3; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: (*ctx.pFunc->xFunc)(&ctx, n, apVal); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ c287665ba8 2007-09-14 drh: /* Even though a malloc() has failed, the implementation of the c287665ba8 2007-09-14 drh: ** user function may have called an sqlite3_result_XXX() function c287665ba8 2007-09-14 drh: ** to return a value. The following call releases any resources c287665ba8 2007-09-14 drh: ** associated with such a value. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Note: Maybe MemRelease() should be called if sqlite3SafetyOn() c287665ba8 2007-09-14 drh: ** fails also (the if(...) statement above). But if people are c287665ba8 2007-09-14 drh: ** misusing sqlite, they have bigger problems than a leaked value. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3VdbeMemRelease(&ctx.s); c287665ba8 2007-09-14 drh: goto no_mem; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: popStack(&pTos, n); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If any auxilary data functions have been called by this user function, dbda8d6ce9 2007-07-21 drh: ** immediately call the destructor for any non-static values. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( ctx.pVdbeFunc ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1); dbda8d6ce9 2007-07-21 drh: pOp->p3 = (char *)ctx.pVdbeFunc; dbda8d6ce9 2007-07-21 drh: pOp->p3type = P3_VDBEFUNC; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the function returned an error, throw an exception */ dbda8d6ce9 2007-07-21 drh: if( ctx.isError ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Copy the result of the function to the top of the stack */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeEncoding(&ctx.s, encoding); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = 0; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemMove(pTos, &ctx.s); dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeMemTooBig(pTos) ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: BitAnd * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack. Convert both elements dbda8d6ce9 2007-07-21 drh: ** to integers. Push back onto the stack the bit-wise AND of the dbda8d6ce9 2007-07-21 drh: ** two elements. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: BitOr * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack. Convert both elements dbda8d6ce9 2007-07-21 drh: ** to integers. Push back onto the stack the bit-wise OR of the dbda8d6ce9 2007-07-21 drh: ** two elements. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: ShiftLeft * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack. Convert both elements dbda8d6ce9 2007-07-21 drh: ** to integers. Push back onto the stack the second element shifted dbda8d6ce9 2007-07-21 drh: ** left by N bits where N is the top element on the stack. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: ShiftRight * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack. Convert both elements dbda8d6ce9 2007-07-21 drh: ** to integers. Push back onto the stack the second element shifted dbda8d6ce9 2007-07-21 drh: ** right by N bits where N is the top element on the stack. dbda8d6ce9 2007-07-21 drh: ** If either operand is NULL, the result is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_BitAnd: /* same as TK_BITAND, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_BitOr: /* same as TK_BITOR, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_ShiftLeft: /* same as TK_LSHIFT, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_ShiftRight: { /* same as TK_RSHIFT, no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pNos = &pTos[-1]; dbda8d6ce9 2007-07-21 drh: i64 a, b; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pNos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( (pTos->flags | pNos->flags) & MEM_Null ){ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, 2); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: a = sqlite3VdbeIntValue(pNos); dbda8d6ce9 2007-07-21 drh: b = sqlite3VdbeIntValue(pTos); dbda8d6ce9 2007-07-21 drh: switch( pOp->opcode ){ dbda8d6ce9 2007-07-21 drh: case OP_BitAnd: a &= b; break; dbda8d6ce9 2007-07-21 drh: case OP_BitOr: a |= b; break; dbda8d6ce9 2007-07-21 drh: case OP_ShiftLeft: a <<= b; break; dbda8d6ce9 2007-07-21 drh: case OP_ShiftRight: a >>= b; break; dbda8d6ce9 2007-07-21 drh: default: /* CANT HAPPEN */ break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos->u.i = a; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: AddImm P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Add the value P1 to whatever is on top of the stack. The result dbda8d6ce9 2007-07-21 drh: ** is always an integer. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To force the top of the stack to be an integer, just add 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_AddImm: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: pTos->u.i += pOp->p1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: ForceInt P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Convert the top of the stack into an integer. If the current top of dbda8d6ce9 2007-07-21 drh: ** the stack is not numeric (meaning that is is a NULL or a string that dbda8d6ce9 2007-07-21 drh: ** does not look like an integer or floating point number) then pop the dbda8d6ce9 2007-07-21 drh: ** stack and jump to P2. If the top of the stack is numeric then dbda8d6ce9 2007-07-21 drh: ** convert it into the least integer that is greater than or equal to its dbda8d6ce9 2007-07-21 drh: ** current value if P1==0, or to the least integer that is strictly dbda8d6ce9 2007-07-21 drh: ** greater than its current value if P1==1. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ForceInt: { /* no-push */ dbda8d6ce9 2007-07-21 drh: i64 v; dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding); dbda8d6ce9 2007-07-21 drh: if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){ dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Int ){ dbda8d6ce9 2007-07-21 drh: v = pTos->u.i + (pOp->p1!=0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* FIX ME: should this not be assert( pTos->flags & MEM_Real ) ??? */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRealify(pTos); dbda8d6ce9 2007-07-21 drh: v = (int)pTos->r; dbda8d6ce9 2007-07-21 drh: if( pTos->r>(double)v ) v++; dbda8d6ce9 2007-07-21 drh: if( pOp->p1 && pTos->r==(double)v ) v++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos->u.i = v; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: MustBeInt P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Force the top of the stack to be an integer. If the top of the dbda8d6ce9 2007-07-21 drh: ** stack is not an integer and cannot be converted into an integer dbda8d6ce9 2007-07-21 drh: ** with out data loss, then jump immediately to P2, or if P2==0 dbda8d6ce9 2007-07-21 drh: ** raise an SQLITE_MISMATCH exception. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the top of the stack is not an integer and P2 is not zero and dbda8d6ce9 2007-07-21 drh: ** P1 is 1, then the stack is popped. In all other cases, the depth dbda8d6ce9 2007-07-21 drh: ** of the stack is unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MustBeInt: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding); dbda8d6ce9 2007-07-21 drh: if( (pTos->flags & MEM_Int)==0 ){ dbda8d6ce9 2007-07-21 drh: if( pOp->p2==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_MISMATCH; dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( pOp->p1 ) popStack(&pTos, 1); dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: RealAffinity * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the top of the stack is an integer, convert it to a real value. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode is used when extracting information from a column that dbda8d6ce9 2007-07-21 drh: ** has REAL affinity. Such column values may still be stored as dbda8d6ce9 2007-07-21 drh: ** integers, for space efficiency, but after extraction we want them dbda8d6ce9 2007-07-21 drh: ** to have only a real value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_RealAffinity: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Int ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRealify(pTos); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CAST dbda8d6ce9 2007-07-21 drh: /* Opcode: ToText * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Force the value on the top of the stack to be text. dbda8d6ce9 2007-07-21 drh: ** If the value is numeric, convert it to a string using the dbda8d6ce9 2007-07-21 drh: ** equivalent of printf(). Blob values are unchanged and dbda8d6ce9 2007-07-21 drh: ** are afterwards simply interpreted as text. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A NULL value is not changed by this routine. It remains NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ToText: { /* same as TK_TO_TEXT, no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Null ) break; dbda8d6ce9 2007-07-21 drh: assert( MEM_Str==(MEM_Blob>>3) ); dbda8d6ce9 2007-07-21 drh: pTos->flags |= (pTos->flags&MEM_Blob)>>3; dbda8d6ce9 2007-07-21 drh: applyAffinity(pTos, SQLITE_AFF_TEXT, encoding); dbda8d6ce9 2007-07-21 drh: rc = ExpandBlob(pTos); dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Str ); dbda8d6ce9 2007-07-21 drh: pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Blob); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: ToBlob * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Force the value on the top of the stack to be a BLOB. dbda8d6ce9 2007-07-21 drh: ** If the value is numeric, convert it to a string first. dbda8d6ce9 2007-07-21 drh: ** Strings are simply reinterpreted as blobs with no change dbda8d6ce9 2007-07-21 drh: ** to the underlying data. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A NULL value is not changed by this routine. It remains NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ToBlob: { /* same as TK_TO_BLOB, no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Null ) break; dbda8d6ce9 2007-07-21 drh: if( (pTos->flags & MEM_Blob)==0 ){ dbda8d6ce9 2007-07-21 drh: applyAffinity(pTos, SQLITE_AFF_TEXT, encoding); dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Str ); dbda8d6ce9 2007-07-21 drh: pTos->flags |= MEM_Blob; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Str); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: ToNumeric * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Force the value on the top of the stack to be numeric (either an dbda8d6ce9 2007-07-21 drh: ** integer or a floating-point number.) dbda8d6ce9 2007-07-21 drh: ** If the value is text or blob, try to convert it to an using the dbda8d6ce9 2007-07-21 drh: ** equivalent of atoi() or atof() and store 0 if no such conversion dbda8d6ce9 2007-07-21 drh: ** is possible. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A NULL value is not changed by this routine. It remains NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ToNumeric: { /* same as TK_TO_NUMERIC, no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( (pTos->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemNumerify(pTos); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_CAST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: ToInt * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Force the value on the top of the stack to be an integer. If dbda8d6ce9 2007-07-21 drh: ** The value is currently a real number, drop its fractional part. dbda8d6ce9 2007-07-21 drh: ** If the value is text or blob, try to convert it to an integer using the dbda8d6ce9 2007-07-21 drh: ** equivalent of atoi() and store 0 if no such conversion is possible. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A NULL value is not changed by this routine. It remains NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ToInt: { /* same as TK_TO_INT, no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( (pTos->flags & MEM_Null)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CAST dbda8d6ce9 2007-07-21 drh: /* Opcode: ToReal * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Force the value on the top of the stack to be a floating point number. dbda8d6ce9 2007-07-21 drh: ** If The value is currently an integer, convert it. dbda8d6ce9 2007-07-21 drh: ** If the value is text or blob, try to convert it to an integer using the dbda8d6ce9 2007-07-21 drh: ** equivalent of atoi() and store 0 if no such conversion is possible. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A NULL value is not changed by this routine. It remains NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ToReal: { /* same as TK_TO_REAL, no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( (pTos->flags & MEM_Null)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRealify(pTos); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_CAST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Eq P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top two elements from the stack. If they are equal, then dbda8d6ce9 2007-07-21 drh: ** jump to instruction P2. Otherwise, continue to the next instruction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the 0x100 bit of P1 is true and either operand is NULL then take the dbda8d6ce9 2007-07-21 drh: ** jump. If the 0x100 bit of P1 is clear then fall thru if either operand dbda8d6ce9 2007-07-21 drh: ** is NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the 0x200 bit of P1 is set and either operand is NULL then dbda8d6ce9 2007-07-21 drh: ** both operands are converted to integers prior to comparison. dbda8d6ce9 2007-07-21 drh: ** NULL operands are converted to zero and non-NULL operands are dbda8d6ce9 2007-07-21 drh: ** converted to 1. Thus, for example, with 0x200 set, NULL==NULL is true dbda8d6ce9 2007-07-21 drh: ** whereas it would normally be NULL. Similarly, NULL==123 is false when dbda8d6ce9 2007-07-21 drh: ** 0x200 is set but is NULL when the 0x200 bit of P1 is clear. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The least significant byte of P1 (mask 0xff) must be an affinity character - dbda8d6ce9 2007-07-21 drh: ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made dbda8d6ce9 2007-07-21 drh: ** to coerce both values dbda8d6ce9 2007-07-21 drh: ** according to the affinity before the comparison is made. If the byte is dbda8d6ce9 2007-07-21 drh: ** 0x00, then numeric affinity is used. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Once any conversions have taken place, and neither value is NULL, dbda8d6ce9 2007-07-21 drh: ** the values are compared. If both values are blobs, or both are text, dbda8d6ce9 2007-07-21 drh: ** then memcmp() is used to determine the results of the comparison. If dbda8d6ce9 2007-07-21 drh: ** both values are numeric, then a numeric comparison is used. If the dbda8d6ce9 2007-07-21 drh: ** two values are of different types, then they are inequal. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P2 is zero, do not jump. Instead, push an integer 1 onto the dbda8d6ce9 2007-07-21 drh: ** stack if the jump would have been taken, or a 0 if not. Push a dbda8d6ce9 2007-07-21 drh: ** NULL if either operand was NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P3 is not NULL it is a pointer to a collating sequence (a CollSeq dbda8d6ce9 2007-07-21 drh: ** structure) that defines how to compare text. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Ne P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This works just like the Eq opcode except that the jump is taken if dbda8d6ce9 2007-07-21 drh: ** the operands from the stack are not equal. See the Eq opcode for dbda8d6ce9 2007-07-21 drh: ** additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Lt P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This works just like the Eq opcode except that the jump is taken if dbda8d6ce9 2007-07-21 drh: ** the 2nd element down on the stack is less than the top of the stack. dbda8d6ce9 2007-07-21 drh: ** See the Eq opcode for additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Le P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This works just like the Eq opcode except that the jump is taken if dbda8d6ce9 2007-07-21 drh: ** the 2nd element down on the stack is less than or equal to the dbda8d6ce9 2007-07-21 drh: ** top of the stack. See the Eq opcode for additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Gt P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This works just like the Eq opcode except that the jump is taken if dbda8d6ce9 2007-07-21 drh: ** the 2nd element down on the stack is greater than the top of the stack. dbda8d6ce9 2007-07-21 drh: ** See the Eq opcode for additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Ge P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This works just like the Eq opcode except that the jump is taken if dbda8d6ce9 2007-07-21 drh: ** the 2nd element down on the stack is greater than or equal to the dbda8d6ce9 2007-07-21 drh: ** top of the stack. See the Eq opcode for additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Eq: /* same as TK_EQ, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Ne: /* same as TK_NE, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Lt: /* same as TK_LT, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Le: /* same as TK_LE, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Gt: /* same as TK_GT, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Ge: { /* same as TK_GE, no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pNos; dbda8d6ce9 2007-07-21 drh: int flags; dbda8d6ce9 2007-07-21 drh: int res; dbda8d6ce9 2007-07-21 drh: char affinity; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pNos = &pTos[-1]; dbda8d6ce9 2007-07-21 drh: flags = pTos->flags|pNos->flags; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If either value is a NULL P2 is not zero, take the jump if the least dbda8d6ce9 2007-07-21 drh: ** significant byte of P1 is true. If P2 is zero, then push a NULL onto dbda8d6ce9 2007-07-21 drh: ** the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( flags&MEM_Null ){ dbda8d6ce9 2007-07-21 drh: if( (pOp->p1 & 0x200)!=0 ){ dbda8d6ce9 2007-07-21 drh: /* The 0x200 bit of P1 means, roughly "do not treat NULL as the dbda8d6ce9 2007-07-21 drh: ** magic SQL value it normally is - treat it as if it were another dbda8d6ce9 2007-07-21 drh: ** integer". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** With 0x200 set, if either operand is NULL then both operands dbda8d6ce9 2007-07-21 drh: ** are converted to integers prior to being passed down into the dbda8d6ce9 2007-07-21 drh: ** normal comparison logic below. NULL operands are converted to dbda8d6ce9 2007-07-21 drh: ** zero and non-NULL operands are converted to 1. Thus, for example, dbda8d6ce9 2007-07-21 drh: ** with 0x200 set, NULL==NULL is true whereas it would normally dbda8d6ce9 2007-07-21 drh: ** be NULL. Similarly, NULL!=123 is true. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetInt64(pTos, (pTos->flags & MEM_Null)==0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetInt64(pNos, (pNos->flags & MEM_Null)==0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* If the 0x200 bit of P1 is clear and either operand is NULL then dbda8d6ce9 2007-07-21 drh: ** the result is always NULL. The jump is taken if the 0x100 bit dbda8d6ce9 2007-07-21 drh: ** of P1 is set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, 2); dbda8d6ce9 2007-07-21 drh: if( pOp->p2 ){ dbda8d6ce9 2007-07-21 drh: if( pOp->p1 & 0x100 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2-1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: affinity = pOp->p1 & 0xFF; dbda8d6ce9 2007-07-21 drh: if( affinity ){ dbda8d6ce9 2007-07-21 drh: applyAffinity(pNos, affinity, encoding); dbda8d6ce9 2007-07-21 drh: applyAffinity(pTos, affinity, encoding); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 ); dbda8d6ce9 2007-07-21 drh: ExpandBlob(pNos); dbda8d6ce9 2007-07-21 drh: ExpandBlob(pTos); dbda8d6ce9 2007-07-21 drh: res = sqlite3MemCompare(pNos, pTos, (CollSeq*)pOp->p3); dbda8d6ce9 2007-07-21 drh: switch( pOp->opcode ){ dbda8d6ce9 2007-07-21 drh: case OP_Eq: res = res==0; break; dbda8d6ce9 2007-07-21 drh: case OP_Ne: res = res!=0; break; dbda8d6ce9 2007-07-21 drh: case OP_Lt: res = res<0; break; dbda8d6ce9 2007-07-21 drh: case OP_Le: res = res<=0; break; dbda8d6ce9 2007-07-21 drh: case OP_Gt: res = res>0; break; dbda8d6ce9 2007-07-21 drh: default: res = res>=0; break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: popStack(&pTos, 2); dbda8d6ce9 2007-07-21 drh: if( pOp->p2 ){ dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2-1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pTos->u.i = res; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: And * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop two values off the stack. Take the logical AND of the dbda8d6ce9 2007-07-21 drh: ** two values and push the resulting boolean value back onto the dbda8d6ce9 2007-07-21 drh: ** stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Or * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop two values off the stack. Take the logical OR of the dbda8d6ce9 2007-07-21 drh: ** two values and push the resulting boolean value back onto the dbda8d6ce9 2007-07-21 drh: ** stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_And: /* same as TK_AND, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Or: { /* same as TK_OR, no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pNos = &pTos[-1]; dbda8d6ce9 2007-07-21 drh: int v1, v2; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pNos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Null ){ dbda8d6ce9 2007-07-21 drh: v1 = 2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: v1 = pTos->u.i==0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pNos->flags & MEM_Null ){ dbda8d6ce9 2007-07-21 drh: v2 = 2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pNos); dbda8d6ce9 2007-07-21 drh: v2 = pNos->u.i==0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_And ){ dbda8d6ce9 2007-07-21 drh: static const unsigned char and_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 }; dbda8d6ce9 2007-07-21 drh: v1 = and_logic[v1*3+v2]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: static const unsigned char or_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 }; dbda8d6ce9 2007-07-21 drh: v1 = or_logic[v1*3+v2]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: popStack(&pTos, 2); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: if( v1==2 ){ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTos->u.i = v1==0; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Negative * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Treat the top of the stack as a numeric quantity. Replace it dbda8d6ce9 2007-07-21 drh: ** with its additive inverse. If the top of the stack is NULL dbda8d6ce9 2007-07-21 drh: ** its value is unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: AbsValue * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Treat the top of the stack as a numeric quantity. Replace it dbda8d6ce9 2007-07-21 drh: ** with its absolute value. If the top of the stack is NULL dbda8d6ce9 2007-07-21 drh: ** its value is unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Negative: /* same as TK_UMINUS, no-push */ dbda8d6ce9 2007-07-21 drh: case OP_AbsValue: { dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( (pTos->flags & (MEM_Real|MEM_Int|MEM_Null))==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemNumerify(pTos); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Real ){ dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_Negative || pTos->r<0.0 ){ dbda8d6ce9 2007-07-21 drh: pTos->r = -pTos->r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Real; dbda8d6ce9 2007-07-21 drh: }else if( pTos->flags & MEM_Int ){ dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_Negative || pTos->u.i<0 ){ dbda8d6ce9 2007-07-21 drh: pTos->u.i = -pTos->u.i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Not * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Interpret the top of the stack as a boolean value. Replace it dbda8d6ce9 2007-07-21 drh: ** with its complement. If the top of the stack is NULL its value dbda8d6ce9 2007-07-21 drh: ** is unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Not: { /* same as TK_NOT, no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: assert( (pTos->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: pTos->u.i = !pTos->u.i; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: BitNot * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Interpret the top of the stack as an value. Replace it dbda8d6ce9 2007-07-21 drh: ** with its ones-complement. If the top of the stack is NULL its dbda8d6ce9 2007-07-21 drh: ** value is unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_BitNot: { /* same as TK_BITNOT, no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: assert( (pTos->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: pTos->u.i = ~pTos->u.i; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Noop * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Do nothing. This instruction is often useful as a jump dbda8d6ce9 2007-07-21 drh: ** destination. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The magic Explain opcode are only inserted when explain==2 (which dbda8d6ce9 2007-07-21 drh: ** is to say when the EXPLAIN QUERY PLAN syntax is used.) dbda8d6ce9 2007-07-21 drh: ** This opcode records information from the optimizer. It is the dbda8d6ce9 2007-07-21 drh: ** the same as a no-op. This opcodesnever appears in a real VM program. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Explain: dbda8d6ce9 2007-07-21 drh: case OP_Noop: { /* no-push */ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: If P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop a single boolean from the stack. If the boolean popped is dbda8d6ce9 2007-07-21 drh: ** true, then jump to p2. Otherwise continue to the next instruction. dbda8d6ce9 2007-07-21 drh: ** An integer is false if zero and true otherwise. A string is dbda8d6ce9 2007-07-21 drh: ** false if it has zero length and true otherwise. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the value popped of the stack is NULL, then take the jump if P1 dbda8d6ce9 2007-07-21 drh: ** is true and fall through if P1 is false. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: IfNot P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop a single boolean from the stack. If the boolean popped is dbda8d6ce9 2007-07-21 drh: ** false, then jump to p2. Otherwise continue to the next instruction. dbda8d6ce9 2007-07-21 drh: ** An integer is false if zero and true otherwise. A string is dbda8d6ce9 2007-07-21 drh: ** false if it has zero length and true otherwise. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the value popped of the stack is NULL, then take the jump if P1 dbda8d6ce9 2007-07-21 drh: ** is true and fall through if P1 is false. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_If: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_IfNot: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int c; dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Null ){ dbda8d6ce9 2007-07-21 drh: c = pOp->p1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: c = sqlite3VdbeIntValue(pTos); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: c = sqlite3VdbeRealValue(pTos)!=0.0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_IfNot ) c = !c; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: if( c ) pc = pOp->p2-1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IsNull P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Check the top of the stack and jump to P2 if the top of the stack dbda8d6ce9 2007-07-21 drh: ** is NULL. If P1 is positive, then pop P1 elements from the stack dbda8d6ce9 2007-07-21 drh: ** regardless of whether or not the jump is taken. If P1 is negative, dbda8d6ce9 2007-07-21 drh: ** pop -P1 elements from the stack only if the jump is taken and leave dbda8d6ce9 2007-07-21 drh: ** the stack unchanged if the jump is not taken. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IsNull: { /* same as TK_ISNULL, no-push */ dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Null ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2-1; dbda8d6ce9 2007-07-21 drh: if( pOp->p1<0 ){ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, -pOp->p1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pOp->p1>0 ){ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, pOp->p1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: NotNull P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Jump to P2 if the top abs(P1) values on the stack are all not NULL. dbda8d6ce9 2007-07-21 drh: ** Regardless of whether or not the jump is taken, pop the stack dbda8d6ce9 2007-07-21 drh: ** P1 times if P1 is greater than zero. But if P1 is negative, dbda8d6ce9 2007-07-21 drh: ** leave the stack unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_NotNull: { /* same as TK_NOTNULL, no-push */ dbda8d6ce9 2007-07-21 drh: int i, cnt; dbda8d6ce9 2007-07-21 drh: cnt = pOp->p1; dbda8d6ce9 2007-07-21 drh: if( cnt<0 ) cnt = -cnt; dbda8d6ce9 2007-07-21 drh: assert( &pTos[1-cnt] >= p->aStack ); dbda8d6ce9 2007-07-21 drh: for(i=0; i<cnt && (pTos[1+i-cnt].flags & MEM_Null)==0; i++){} dbda8d6ce9 2007-07-21 drh: if( i>=cnt ) pc = pOp->p2-1; dbda8d6ce9 2007-07-21 drh: if( pOp->p1>0 ) popStack(&pTos, cnt); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: SetNumColumns P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Before the OP_Column opcode can be executed on a cursor, this dbda8d6ce9 2007-07-21 drh: ** opcode must be called to set the number of fields in the table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode sets the number of columns for cursor P1 to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If OP_KeyAsData is to be applied to cursor P1, it must be executed dbda8d6ce9 2007-07-21 drh: ** before this op-code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_SetNumColumns: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: assert( (pOp->p1)<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[pOp->p1]!=0 ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[pOp->p1]; dbda8d6ce9 2007-07-21 drh: pC->nField = pOp->p2; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Column P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Interpret the data that cursor P1 points to as a structure built using dbda8d6ce9 2007-07-21 drh: ** the MakeRecord instruction. (See the MakeRecord opcode for additional dbda8d6ce9 2007-07-21 drh: ** information about the format of the data.) Push onto the stack the value dbda8d6ce9 2007-07-21 drh: ** of the P2-th column contained in the data. If there are less that (P2+1) dbda8d6ce9 2007-07-21 drh: ** values in the record, push a NULL onto the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the KeyAsData opcode has previously executed on this cursor, then the dbda8d6ce9 2007-07-21 drh: ** field might be extracted from the key rather than the data. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the column contains fewer than P2 fields, then push a NULL. Or dbda8d6ce9 2007-07-21 drh: ** if P3 is of type P3_MEM, then push the P3 value. The P3 value will dbda8d6ce9 2007-07-21 drh: ** be default value for a column that has been added using the ALTER TABLE dbda8d6ce9 2007-07-21 drh: ** ADD COLUMN command. If P3 is an ordinary string, just push a NULL. dbda8d6ce9 2007-07-21 drh: ** When P3 is a string it is really just a comment describing the value dbda8d6ce9 2007-07-21 drh: ** to be pushed, not a default value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Column: { dbda8d6ce9 2007-07-21 drh: u32 payloadSize; /* Number of bytes in the record */ dbda8d6ce9 2007-07-21 drh: int p1 = pOp->p1; /* P1 value of the opcode */ dbda8d6ce9 2007-07-21 drh: int p2 = pOp->p2; /* column number to retrieve */ dbda8d6ce9 2007-07-21 drh: Cursor *pC = 0; /* The VDBE cursor */ dbda8d6ce9 2007-07-21 drh: char *zRec; /* Pointer to complete record-data */ dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; /* The BTree cursor */ dbda8d6ce9 2007-07-21 drh: u32 *aType; /* aType[i] holds the numeric type of the i-th column */ dbda8d6ce9 2007-07-21 drh: u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ dbda8d6ce9 2007-07-21 drh: u32 nField; /* number of fields in the record */ dbda8d6ce9 2007-07-21 drh: int len; /* The length of the serialized data for the column */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: char *zData; /* Part of the record being decoded */ dbda8d6ce9 2007-07-21 drh: Mem sMem; /* For storing the record being decoded */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sMem.flags = 0; dbda8d6ce9 2007-07-21 drh: assert( p1<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This block sets the variable payloadSize to be the total number of dbda8d6ce9 2007-07-21 drh: ** bytes in the record. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** zRec is set to be the complete text of the record if it is available. dbda8d6ce9 2007-07-21 drh: ** The complete record text is always available for pseudo-tables dbda8d6ce9 2007-07-21 drh: ** If the record is stored in a cursor, the complete record text dbda8d6ce9 2007-07-21 drh: ** might be available in the pC->aRow cache. Or it might not be. dbda8d6ce9 2007-07-21 drh: ** If the data is unavailable, zRec is set to NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** We also compute the number of columns in the record. For cursors, dbda8d6ce9 2007-07-21 drh: ** the number of columns is stored in the Cursor.nField element. For dbda8d6ce9 2007-07-21 drh: ** records on the stack, the next entry down on the stack is an integer dbda8d6ce9 2007-07-21 drh: ** which is the number of records. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[p1]; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: assert( pC->pVtabCursor==0 ); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: assert( pC!=0 ); dbda8d6ce9 2007-07-21 drh: if( pC->pCursor!=0 ){ dbda8d6ce9 2007-07-21 drh: /* The record is stored in a B-Tree */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeCursorMoveto(pC); dbda8d6ce9 2007-07-21 drh: if( rc ) goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: zRec = 0; dbda8d6ce9 2007-07-21 drh: pCrsr = pC->pCursor; dbda8d6ce9 2007-07-21 drh: if( pC->nullRow ){ dbda8d6ce9 2007-07-21 drh: payloadSize = 0; dbda8d6ce9 2007-07-21 drh: }else if( pC->cacheStatus==p->cacheCtr ){ dbda8d6ce9 2007-07-21 drh: payloadSize = pC->payloadSize; dbda8d6ce9 2007-07-21 drh: zRec = (char*)pC->aRow; dbda8d6ce9 2007-07-21 drh: }else if( pC->isIndex ){ dbda8d6ce9 2007-07-21 drh: i64 payloadSize64; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeKeySize(pCrsr, &payloadSize64); dbda8d6ce9 2007-07-21 drh: payloadSize = payloadSize64; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeDataSize(pCrsr, &payloadSize); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nField = pC->nField; dbda8d6ce9 2007-07-21 drh: }else if( pC->pseudoTable ){ dbda8d6ce9 2007-07-21 drh: /* The record is the sole entry of a pseudo-table */ dbda8d6ce9 2007-07-21 drh: payloadSize = pC->nData; dbda8d6ce9 2007-07-21 drh: zRec = pC->pData; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: assert( payloadSize==0 || zRec!=0 ); dbda8d6ce9 2007-07-21 drh: nField = pC->nField; dbda8d6ce9 2007-07-21 drh: pCrsr = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zRec = 0; dbda8d6ce9 2007-07-21 drh: payloadSize = 0; dbda8d6ce9 2007-07-21 drh: pCrsr = 0; dbda8d6ce9 2007-07-21 drh: nField = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If payloadSize is 0, then just push a NULL onto the stack. */ dbda8d6ce9 2007-07-21 drh: if( payloadSize==0 ){ dbda8d6ce9 2007-07-21 drh: assert( pTos->flags==MEM_Null ); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( payloadSize>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( p2<nField ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read and parse the table header. Store the results of the parse dbda8d6ce9 2007-07-21 drh: ** into the record header cache fields of the cursor. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pC && pC->cacheStatus==p->cacheCtr ){ dbda8d6ce9 2007-07-21 drh: aType = pC->aType; dbda8d6ce9 2007-07-21 drh: aOffset = pC->aOffset; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: u8 *zIdx; /* Index into header */ dbda8d6ce9 2007-07-21 drh: u8 *zEndHdr; /* Pointer to first byte after the header */ dbda8d6ce9 2007-07-21 drh: u32 offset; /* Offset into the data */ dbda8d6ce9 2007-07-21 drh: int szHdrSz; /* Size of the header size field at start of record */ dbda8d6ce9 2007-07-21 drh: int avail; /* Number of bytes of available data */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: aType = pC->aType; dbda8d6ce9 2007-07-21 drh: if( aType==0 ){ c287665ba8 2007-09-14 drh: pC->aType = aType = sqlite3DbMallocRaw(db, 2*nField*sizeof(aType) ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( aType==0 ){ dbda8d6ce9 2007-07-21 drh: goto no_mem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pC->aOffset = aOffset = &aType[nField]; dbda8d6ce9 2007-07-21 drh: pC->payloadSize = payloadSize; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = p->cacheCtr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out how many bytes are in the header */ dbda8d6ce9 2007-07-21 drh: if( zRec ){ dbda8d6ce9 2007-07-21 drh: zData = zRec; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( pC->isIndex ){ dbda8d6ce9 2007-07-21 drh: zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* If KeyFetch()/DataFetch() managed to get the entire payload, dbda8d6ce9 2007-07-21 drh: ** save the payload in the pC->aRow cache. That will save us from dbda8d6ce9 2007-07-21 drh: ** having to make additional calls to fetch the content portion of dbda8d6ce9 2007-07-21 drh: ** the record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( avail>=payloadSize ){ dbda8d6ce9 2007-07-21 drh: zRec = zData; dbda8d6ce9 2007-07-21 drh: pC->aRow = (u8*)zData; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pC->aRow = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* The following assert is true in all cases accept when dbda8d6ce9 2007-07-21 drh: ** the database file has been corrupted externally. dbda8d6ce9 2007-07-21 drh: ** assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */ dbda8d6ce9 2007-07-21 drh: szHdrSz = GetVarint((u8*)zData, offset); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The KeyFetch() or DataFetch() above are fast and will get the entire dbda8d6ce9 2007-07-21 drh: ** record header in most cases. But they will fail to get the complete dbda8d6ce9 2007-07-21 drh: ** record header if the record header does not fit on a single page dbda8d6ce9 2007-07-21 drh: ** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to dbda8d6ce9 2007-07-21 drh: ** acquire the complete header text. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !zRec && avail<offset ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemFromBtree(pCrsr, 0, offset, pC->isIndex, &sMem); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto op_column_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zData = sMem.z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zEndHdr = (u8 *)&zData[offset]; dbda8d6ce9 2007-07-21 drh: zIdx = (u8 *)&zData[szHdrSz]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Scan the header and use it to fill in the aType[] and aOffset[] dbda8d6ce9 2007-07-21 drh: ** arrays. aType[i] will contain the type integer for the i-th dbda8d6ce9 2007-07-21 drh: ** column and aOffset[i] will contain the offset from the beginning dbda8d6ce9 2007-07-21 drh: ** of the record to the start of the data for the i-th column dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nField; i++){ dbda8d6ce9 2007-07-21 drh: if( zIdx<zEndHdr ){ dbda8d6ce9 2007-07-21 drh: aOffset[i] = offset; dbda8d6ce9 2007-07-21 drh: zIdx += GetVarint(zIdx, aType[i]); dbda8d6ce9 2007-07-21 drh: offset += sqlite3VdbeSerialTypeLen(aType[i]); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* If i is less that nField, then there are less fields in this dbda8d6ce9 2007-07-21 drh: ** record than SetNumColumns indicated there are columns in the dbda8d6ce9 2007-07-21 drh: ** table. Set the offset for any extra columns not present in dbda8d6ce9 2007-07-21 drh: ** the record to 0. This tells code below to push a NULL onto the dbda8d6ce9 2007-07-21 drh: ** stack instead of deserializing a value from the record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: aOffset[i] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(&sMem); dbda8d6ce9 2007-07-21 drh: sMem.flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we have read more header data than was contained in the header, dbda8d6ce9 2007-07-21 drh: ** or if the end of the last field appears to be past the end of the dbda8d6ce9 2007-07-21 drh: ** record, then we must be dealing with a corrupt database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( zIdx>zEndHdr || offset>payloadSize ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: goto op_column_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Get the column information. If aOffset[p2] is non-zero, then dbda8d6ce9 2007-07-21 drh: ** deserialize the value from the record. If aOffset[p2] is zero, dbda8d6ce9 2007-07-21 drh: ** then there are not enough fields in the record to satisfy the dbda8d6ce9 2007-07-21 drh: ** request. In this case, set the value NULL or to P3 if P3 is dbda8d6ce9 2007-07-21 drh: ** a pointer to a Mem object. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( aOffset[p2] ){ dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_OK ); dbda8d6ce9 2007-07-21 drh: if( zRec ){ dbda8d6ce9 2007-07-21 drh: zData = &zRec[aOffset[p2]]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: len = sqlite3VdbeSerialTypeLen(aType[p2]); c287665ba8 2007-09-14 drh: rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex, &sMem); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto op_column_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zData = sMem.z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSerialGet((u8*)zData, aType[p2], pTos); dbda8d6ce9 2007-07-21 drh: pTos->enc = encoding; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( pOp->p3type==P3_MEM ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemShallowCopy(pTos, (Mem *)(pOp->p3), MEM_Static); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we dynamically allocated space to hold the data (in the dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeMemFromBtree() call above) then transfer control of that dbda8d6ce9 2007-07-21 drh: ** dynamically allocated space over to the pTos structure. dbda8d6ce9 2007-07-21 drh: ** This prevents a memory copy. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (sMem.flags & MEM_Dyn)!=0 ){ dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Ephem ); dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & (MEM_Str|MEM_Blob) ); dbda8d6ce9 2007-07-21 drh: assert( pTos->z==sMem.z ); dbda8d6ce9 2007-07-21 drh: assert( sMem.flags & MEM_Term ); dbda8d6ce9 2007-07-21 drh: pTos->flags &= ~MEM_Ephem; dbda8d6ce9 2007-07-21 drh: pTos->flags |= MEM_Dyn|MEM_Term; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* pTos->z might be pointing to sMem.zShort[]. Fix that so that we dbda8d6ce9 2007-07-21 drh: ** can abandon sMem */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemMakeWriteable(pTos); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: op_column_out: dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: MakeRecord P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Convert the top abs(P1) entries of the stack into a single entry dbda8d6ce9 2007-07-21 drh: ** suitable for use as a data record in a database table or as a key dbda8d6ce9 2007-07-21 drh: ** in an index. The details of the format are irrelavant as long as dbda8d6ce9 2007-07-21 drh: ** the OP_Column opcode can decode the record later and as long as the dbda8d6ce9 2007-07-21 drh: ** sqlite3VdbeRecordCompare function will correctly compare two encoded dbda8d6ce9 2007-07-21 drh: ** records. Refer to source code comments for the details of the record dbda8d6ce9 2007-07-21 drh: ** format. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The original stack entries are popped from the stack if P1>0 but dbda8d6ce9 2007-07-21 drh: ** remain on the stack if P1<0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P2 is not zero and one or more of the entries are NULL, then jump dbda8d6ce9 2007-07-21 drh: ** to the address given by P2. This feature can be used to skip a dbda8d6ce9 2007-07-21 drh: ** uniqueness test on indices. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 may be a string that is P1 characters long. The nth character of the dbda8d6ce9 2007-07-21 drh: ** string indicates the column affinity that should be used for the nth dbda8d6ce9 2007-07-21 drh: ** field of the index key (i.e. the first character of P3 corresponds to the dbda8d6ce9 2007-07-21 drh: ** lowest element on the stack). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The mapping from character to affinity is given by the SQLITE_AFF_ dbda8d6ce9 2007-07-21 drh: ** macros defined in sqliteInt.h. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P3 is NULL then all index fields have the affinity NONE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also OP_MakeIdxRec dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: MakeIdxRec P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode works just OP_MakeRecord except that it reads an extra dbda8d6ce9 2007-07-21 drh: ** integer from the stack (thus reading a total of abs(P1+1) entries) dbda8d6ce9 2007-07-21 drh: ** and appends that extra integer to the end of the record as a varint. dbda8d6ce9 2007-07-21 drh: ** This results in an index key. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MakeIdxRec: dbda8d6ce9 2007-07-21 drh: case OP_MakeRecord: { dbda8d6ce9 2007-07-21 drh: /* Assuming the record contains N fields, the record format looks dbda8d6ce9 2007-07-21 drh: ** like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ------------------------------------------------------------------------ dbda8d6ce9 2007-07-21 drh: ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 | dbda8d6ce9 2007-07-21 drh: ** ------------------------------------------------------------------------ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Data(0) is taken from the lowest element of the stack and data(N-1) is dbda8d6ce9 2007-07-21 drh: ** the top of the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each type field is a varint representing the serial type of the dbda8d6ce9 2007-07-21 drh: ** corresponding data element (see sqlite3VdbeSerialType()). The dbda8d6ce9 2007-07-21 drh: ** hdr-size field is also a varint which is the offset from the beginning dbda8d6ce9 2007-07-21 drh: ** of the record to data0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: u8 *zNewRecord; /* A buffer to hold the data for the new record */ dbda8d6ce9 2007-07-21 drh: Mem *pRec; /* The new record */ dbda8d6ce9 2007-07-21 drh: Mem *pRowid = 0; /* Rowid appended to the new record */ dbda8d6ce9 2007-07-21 drh: u64 nData = 0; /* Number of bytes of data space */ dbda8d6ce9 2007-07-21 drh: int nHdr = 0; /* Number of bytes of header space */ dbda8d6ce9 2007-07-21 drh: u64 nByte = 0; /* Data space required for this record */ dbda8d6ce9 2007-07-21 drh: int nZero = 0; /* Number of zero bytes at the end of the record */ dbda8d6ce9 2007-07-21 drh: int nVarint; /* Number of bytes in a varint */ dbda8d6ce9 2007-07-21 drh: u32 serial_type; /* Type field */ dbda8d6ce9 2007-07-21 drh: int containsNull = 0; /* True if any of the data fields are NULL */ dbda8d6ce9 2007-07-21 drh: Mem *pData0; /* Bottom of the stack */ dbda8d6ce9 2007-07-21 drh: int leaveOnStack; /* If true, leave the entries on the stack */ dbda8d6ce9 2007-07-21 drh: int nField; /* Number of fields in the record */ dbda8d6ce9 2007-07-21 drh: int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */ dbda8d6ce9 2007-07-21 drh: int addRowid; /* True to append a rowid column at the end */ dbda8d6ce9 2007-07-21 drh: char *zAffinity; /* The affinity string for the record */ dbda8d6ce9 2007-07-21 drh: int file_format; /* File format to use for encoding */ dbda8d6ce9 2007-07-21 drh: int i; /* Space used in zNewRecord[] */ dbda8d6ce9 2007-07-21 drh: char zTemp[NBFS]; /* Space to hold small records */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: leaveOnStack = ((pOp->p1<0)?1:0); dbda8d6ce9 2007-07-21 drh: nField = pOp->p1 * (leaveOnStack?-1:1); dbda8d6ce9 2007-07-21 drh: jumpIfNull = pOp->p2; dbda8d6ce9 2007-07-21 drh: addRowid = pOp->opcode==OP_MakeIdxRec; dbda8d6ce9 2007-07-21 drh: zAffinity = pOp->p3; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pData0 = &pTos[1-nField]; dbda8d6ce9 2007-07-21 drh: assert( pData0>=p->aStack ); dbda8d6ce9 2007-07-21 drh: containsNull = 0; dbda8d6ce9 2007-07-21 drh: file_format = p->minWriteFileFormat; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Loop through the elements that will make up the record to figure dbda8d6ce9 2007-07-21 drh: ** out how much space is required for the new record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(pRec=pData0; pRec<=pTos; pRec++){ dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: if( zAffinity ){ dbda8d6ce9 2007-07-21 drh: applyAffinity(pRec, zAffinity[pRec-pData0], encoding); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pRec->flags&MEM_Null ){ dbda8d6ce9 2007-07-21 drh: containsNull = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pRec->flags&MEM_Zero && pRec->n>0 ){ dbda8d6ce9 2007-07-21 drh: ExpandBlob(pRec); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: serial_type = sqlite3VdbeSerialType(pRec, file_format); dbda8d6ce9 2007-07-21 drh: len = sqlite3VdbeSerialTypeLen(serial_type); dbda8d6ce9 2007-07-21 drh: nData += len; dbda8d6ce9 2007-07-21 drh: nHdr += sqlite3VarintLen(serial_type); dbda8d6ce9 2007-07-21 drh: if( pRec->flags & MEM_Zero ){ dbda8d6ce9 2007-07-21 drh: /* Only pure zero-filled BLOBs can be input to this Opcode. dbda8d6ce9 2007-07-21 drh: ** We do not allow blobs with a prefix and a zero-filled tail. */ dbda8d6ce9 2007-07-21 drh: nZero += pRec->u.i; dbda8d6ce9 2007-07-21 drh: }else if( len ){ dbda8d6ce9 2007-07-21 drh: nZero = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we have to append a varint rowid to this record, set pRowid dbda8d6ce9 2007-07-21 drh: ** to the value of the rowid and increase nByte by the amount of space dbda8d6ce9 2007-07-21 drh: ** required to store it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( addRowid ){ dbda8d6ce9 2007-07-21 drh: pRowid = &pTos[0-nField]; dbda8d6ce9 2007-07-21 drh: assert( pRowid>=p->aStack ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pRowid); dbda8d6ce9 2007-07-21 drh: serial_type = sqlite3VdbeSerialType(pRowid, 0); dbda8d6ce9 2007-07-21 drh: nData += sqlite3VdbeSerialTypeLen(serial_type); dbda8d6ce9 2007-07-21 drh: nHdr += sqlite3VarintLen(serial_type); dbda8d6ce9 2007-07-21 drh: nZero = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add the initial header varint and total the size */ dbda8d6ce9 2007-07-21 drh: nHdr += nVarint = sqlite3VarintLen(nHdr); dbda8d6ce9 2007-07-21 drh: if( nVarint<sqlite3VarintLen(nHdr) ){ dbda8d6ce9 2007-07-21 drh: nHdr++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nByte = nHdr+nData-nZero; dbda8d6ce9 2007-07-21 drh: if( nByte>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate space for the new record. */ dbda8d6ce9 2007-07-21 drh: if( nByte>sizeof(zTemp) ){ c287665ba8 2007-09-14 drh: zNewRecord = sqlite3DbMallocRaw(db, nByte); dbda8d6ce9 2007-07-21 drh: if( !zNewRecord ){ dbda8d6ce9 2007-07-21 drh: goto no_mem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zNewRecord = (u8*)zTemp; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Write the record */ dbda8d6ce9 2007-07-21 drh: i = sqlite3PutVarint(zNewRecord, nHdr); dbda8d6ce9 2007-07-21 drh: for(pRec=pData0; pRec<=pTos; pRec++){ dbda8d6ce9 2007-07-21 drh: serial_type = sqlite3VdbeSerialType(pRec, file_format); dbda8d6ce9 2007-07-21 drh: i += sqlite3PutVarint(&zNewRecord[i], serial_type); /* serial type */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( addRowid ){ dbda8d6ce9 2007-07-21 drh: i += sqlite3PutVarint(&zNewRecord[i], sqlite3VdbeSerialType(pRowid, 0)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(pRec=pData0; pRec<=pTos; pRec++){ /* serial data */ dbda8d6ce9 2007-07-21 drh: i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( addRowid ){ dbda8d6ce9 2007-07-21 drh: i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRowid, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( i==nByte ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Pop entries off the stack if required. Push the new record on. */ dbda8d6ce9 2007-07-21 drh: if( !leaveOnStack ){ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, nField+addRowid); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->n = nByte; dbda8d6ce9 2007-07-21 drh: if( nByte<=sizeof(zTemp) ){ dbda8d6ce9 2007-07-21 drh: assert( zNewRecord==(unsigned char *)zTemp ); dbda8d6ce9 2007-07-21 drh: pTos->z = pTos->zShort; dbda8d6ce9 2007-07-21 drh: memcpy(pTos->zShort, zTemp, nByte); dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Blob | MEM_Short; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( zNewRecord!=(unsigned char *)zTemp ); dbda8d6ce9 2007-07-21 drh: pTos->z = (char*)zNewRecord; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Blob | MEM_Dyn; dbda8d6ce9 2007-07-21 drh: pTos->xDel = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nZero ){ dbda8d6ce9 2007-07-21 drh: pTos->u.i = nZero; dbda8d6ce9 2007-07-21 drh: pTos->flags |= MEM_Zero; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */ dbda8d6ce9 2007-07-21 drh: if( jumpIfNull && containsNull ){ dbda8d6ce9 2007-07-21 drh: pc = jumpIfNull - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Statement P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Begin an individual statement transaction which is part of a larger dbda8d6ce9 2007-07-21 drh: ** BEGIN..COMMIT transaction. This is needed so that the statement dbda8d6ce9 2007-07-21 drh: ** can be rolled back after an error without having to roll back the dbda8d6ce9 2007-07-21 drh: ** entire transaction. The statement transaction will automatically dbda8d6ce9 2007-07-21 drh: ** commit when the VDBE halts. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The statement is begun on the database file with index P1. The main dbda8d6ce9 2007-07-21 drh: ** database file has an index of 0 and the file used for temporary tables dbda8d6ce9 2007-07-21 drh: ** has an index of 1. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Statement: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Btree *pBt; dbda8d6ce9 2007-07-21 drh: if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt)!=0 && !(db->autoCommit) ){ dbda8d6ce9 2007-07-21 drh: assert( sqlite3BtreeIsInTrans(pBt) ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<i))!=0 ); dbda8d6ce9 2007-07-21 drh: if( !sqlite3BtreeIsInStmt(pBt) ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeBeginStmt(pBt); dbda8d6ce9 2007-07-21 drh: p->openedStatement = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: AutoCommit P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll dbda8d6ce9 2007-07-21 drh: ** back any currently active btree transactions. If there are any active dbda8d6ce9 2007-07-21 drh: ** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This instruction causes the VM to halt. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_AutoCommit: { /* no-push */ dbda8d6ce9 2007-07-21 drh: u8 i = pOp->p1; dbda8d6ce9 2007-07-21 drh: u8 rollback = pOp->p2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i==1 || i==0 ); dbda8d6ce9 2007-07-21 drh: assert( i==1 || rollback==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( db->activeVdbeCnt>1 && i && !db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: /* If this instruction implements a COMMIT or ROLLBACK, other VMs are dbda8d6ce9 2007-07-21 drh: ** still running, and a transaction is active, return an error indicating dbda8d6ce9 2007-07-21 drh: ** that the other VMs must complete first. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, "cannot ", rollback?"rollback":"commit", dbda8d6ce9 2007-07-21 drh: " transaction - SQL statements in progress", (char*)0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: }else if( i!=db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: if( pOp->p2 ){ dbda8d6ce9 2007-07-21 drh: assert( i==1 ); dbda8d6ce9 2007-07-21 drh: sqlite3RollbackAll(db); dbda8d6ce9 2007-07-21 drh: db->autoCommit = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: db->autoCommit = i; dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ dbda8d6ce9 2007-07-21 drh: p->pTos = pTos; dbda8d6ce9 2007-07-21 drh: p->pc = pc; dbda8d6ce9 2007-07-21 drh: db->autoCommit = 1-i; c287665ba8 2007-09-14 drh: p->rc = rc = SQLITE_BUSY; c287665ba8 2007-09-14 drh: goto vdbe_return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = SQLITE_DONE; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: rc = SQLITE_ERROR; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: goto vdbe_return; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, dbda8d6ce9 2007-07-21 drh: (!i)?"cannot start a transaction within a transaction":( dbda8d6ce9 2007-07-21 drh: (rollback)?"cannot rollback - no transaction is active": dbda8d6ce9 2007-07-21 drh: "cannot commit - no transaction is active"), (char*)0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Transaction P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Begin a transaction. The transaction ends when a Commit or Rollback dbda8d6ce9 2007-07-21 drh: ** opcode is encountered. Depending on the ON CONFLICT setting, the dbda8d6ce9 2007-07-21 drh: ** transaction might also be rolled back if an error is encountered. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P1 is the index of the database file on which the transaction is dbda8d6ce9 2007-07-21 drh: ** started. Index 0 is the main database file and index 1 is the dbda8d6ce9 2007-07-21 drh: ** file used for temporary tables. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is dbda8d6ce9 2007-07-21 drh: ** obtained on the database file when a write-transaction is started. No dbda8d6ce9 2007-07-21 drh: ** other process can start another write transaction while this transaction is dbda8d6ce9 2007-07-21 drh: ** underway. Starting a write transaction also creates a rollback journal. A dbda8d6ce9 2007-07-21 drh: ** write transaction must be started before any changes can be made to the dbda8d6ce9 2007-07-21 drh: ** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained dbda8d6ce9 2007-07-21 drh: ** on the file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P2 is zero, then a read-lock is obtained on the database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Transaction: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Btree *pBt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<db->nDb ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<i))!=0 ); dbda8d6ce9 2007-07-21 drh: pBt = db->aDb[i].pBt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pBt ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_BUSY ){ dbda8d6ce9 2007-07-21 drh: p->pc = pc; c287665ba8 2007-09-14 drh: p->rc = rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: p->pTos = pTos; c287665ba8 2007-09-14 drh: goto vdbe_return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: ReadCookie P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Read cookie number P2 from database P1 and push it onto the stack. dbda8d6ce9 2007-07-21 drh: ** P2==0 is the schema version. P2==1 is the database format. dbda8d6ce9 2007-07-21 drh: ** P2==2 is the recommended pager cache size, and so forth. P1==0 is dbda8d6ce9 2007-07-21 drh: ** the main database file and P1==1 is the database file used to store dbda8d6ce9 2007-07-21 drh: ** temporary tables. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P1 is negative, then this is a request to read the size of a dbda8d6ce9 2007-07-21 drh: ** databases free-list. P2 must be set to 1 in this case. The actual dbda8d6ce9 2007-07-21 drh: ** database accessed is ((P1+1)*-1). For example, a P1 parameter of -1 dbda8d6ce9 2007-07-21 drh: ** corresponds to database 0 ("main"), a P1 of -2 is database 1 ("temp"). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There must be a read-lock on the database (either a transaction dbda8d6ce9 2007-07-21 drh: ** must be started or there must be an open cursor) before dbda8d6ce9 2007-07-21 drh: ** executing this instruction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ReadCookie: { dbda8d6ce9 2007-07-21 drh: int iMeta; dbda8d6ce9 2007-07-21 drh: int iDb = pOp->p1; dbda8d6ce9 2007-07-21 drh: int iCookie = pOp->p2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pOp->p2<SQLITE_N_BTREE_META ); dbda8d6ce9 2007-07-21 drh: if( iDb<0 ){ dbda8d6ce9 2007-07-21 drh: iDb = (-1*(iDb+1)); dbda8d6ce9 2007-07-21 drh: iCookie *= -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: assert( db->aDb[iDb].pBt!=0 ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<iDb))!=0 ); dbda8d6ce9 2007-07-21 drh: /* The indexing of meta values at the schema layer is off by one from dbda8d6ce9 2007-07-21 drh: ** the indexing in the btree layer. The btree considers meta[0] to dbda8d6ce9 2007-07-21 drh: ** be the number of free pages in the database (a read-only value) dbda8d6ce9 2007-07-21 drh: ** and meta[1] to be the schema cookie. The schema layer considers dbda8d6ce9 2007-07-21 drh: ** meta[1] to be the schema cookie. So we have to shift the index dbda8d6ce9 2007-07-21 drh: ** by one in the following statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, 1 + iCookie, (u32 *)&iMeta); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->u.i = iMeta; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: SetCookie P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Write the top of the stack into cookie number P2 of database P1. dbda8d6ce9 2007-07-21 drh: ** P2==0 is the schema version. P2==1 is the database format. dbda8d6ce9 2007-07-21 drh: ** P2==2 is the recommended pager cache size, and so forth. P1==0 is dbda8d6ce9 2007-07-21 drh: ** the main database file and P1==1 is the database file used to store dbda8d6ce9 2007-07-21 drh: ** temporary tables. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A transaction must be started before executing this opcode. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_SetCookie: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Db *pDb; dbda8d6ce9 2007-07-21 drh: assert( pOp->p2<SQLITE_N_BTREE_META ); dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<db->nDb ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<pOp->p1))!=0 ); dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[pOp->p1]; dbda8d6ce9 2007-07-21 drh: assert( pDb->pBt!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: /* See note about index shifting on OP_ReadCookie */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->u.i); dbda8d6ce9 2007-07-21 drh: if( pOp->p2==0 ){ dbda8d6ce9 2007-07-21 drh: /* When the schema cookie changes, record the new cookie internally */ dbda8d6ce9 2007-07-21 drh: pDb->pSchema->schema_cookie = pTos->u.i; dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_InternChanges; dbda8d6ce9 2007-07-21 drh: }else if( pOp->p2==1 ){ dbda8d6ce9 2007-07-21 drh: /* Record changes in the file format */ dbda8d6ce9 2007-07-21 drh: pDb->pSchema->file_format = pTos->u.i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( (pTos->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: if( pOp->p1==1 ){ dbda8d6ce9 2007-07-21 drh: /* Invalidate all prepared statements whenever the TEMP database dbda8d6ce9 2007-07-21 drh: ** schema is changed. Ticket #1644 */ dbda8d6ce9 2007-07-21 drh: sqlite3ExpirePreparedStatements(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: VerifyCookie P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Check the value of global database parameter number 0 (the dbda8d6ce9 2007-07-21 drh: ** schema version) and make sure it is equal to P2. dbda8d6ce9 2007-07-21 drh: ** P1 is the database number which is 0 for the main database file dbda8d6ce9 2007-07-21 drh: ** and 1 for the file holding temporary tables and some higher number dbda8d6ce9 2007-07-21 drh: ** for auxiliary databases. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The cookie changes its value whenever the database schema changes. dbda8d6ce9 2007-07-21 drh: ** This operation is used to detect when that the cookie has changed dbda8d6ce9 2007-07-21 drh: ** and that the current process needs to reread the schema. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Either a transaction needs to have been started or an OP_Open needs dbda8d6ce9 2007-07-21 drh: ** to be executed (to establish a read lock) before this opcode is dbda8d6ce9 2007-07-21 drh: ** invoked. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VerifyCookie: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int iMeta; dbda8d6ce9 2007-07-21 drh: Btree *pBt; dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<db->nDb ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<pOp->p1))!=0 ); dbda8d6ce9 2007-07-21 drh: pBt = db->aDb[pOp->p1].pBt; dbda8d6ce9 2007-07-21 drh: if( pBt ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&iMeta); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: iMeta = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && iMeta!=pOp->p2 ){ c287665ba8 2007-09-14 drh: sqlite3_free(p->zErrMsg); c287665ba8 2007-09-14 drh: p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); dbda8d6ce9 2007-07-21 drh: /* If the schema-cookie from the database file matches the cookie dbda8d6ce9 2007-07-21 drh: ** stored with the in-memory representation of the schema, do dbda8d6ce9 2007-07-21 drh: ** not reload the schema from the database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If virtual-tables are in use, this is not just an optimisation. dbda8d6ce9 2007-07-21 drh: ** Often, v-tables store their data in other SQLite tables, which dbda8d6ce9 2007-07-21 drh: ** are queried from within xNext() and other v-table methods using dbda8d6ce9 2007-07-21 drh: ** prepared queries. If such a query is out-of-date, we do not want to dbda8d6ce9 2007-07-21 drh: ** discard the database schema, as the user code implementing the dbda8d6ce9 2007-07-21 drh: ** v-table would have to be ready for the sqlite3_vtab structure itself dbda8d6ce9 2007-07-21 drh: ** to be invalidated whenever sqlite3_step() is called from within dbda8d6ce9 2007-07-21 drh: ** a v-table method. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, pOp->p1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3ExpirePreparedStatements(db); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_SCHEMA; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: OpenRead P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Open a read-only cursor for the database table whose root page is dbda8d6ce9 2007-07-21 drh: ** P2 in a database file. The database file is determined by an dbda8d6ce9 2007-07-21 drh: ** integer from the top of the stack. 0 means the main database and dbda8d6ce9 2007-07-21 drh: ** 1 means the database used for temporary tables. Give the new dbda8d6ce9 2007-07-21 drh: ** cursor an identifier of P1. The P1 values need not be contiguous dbda8d6ce9 2007-07-21 drh: ** but all P1 values should be small integers. It is an error for dbda8d6ce9 2007-07-21 drh: ** P1 to be negative. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P2==0 then take the root page number from the next of the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There will be a read lock on the database whenever there is an dbda8d6ce9 2007-07-21 drh: ** open cursor. If the database was unlocked prior to this instruction dbda8d6ce9 2007-07-21 drh: ** then a read lock is acquired as part of this instruction. A read dbda8d6ce9 2007-07-21 drh: ** lock allows other processes to read the database but prohibits dbda8d6ce9 2007-07-21 drh: ** any other process from modifying the database. The read lock is dbda8d6ce9 2007-07-21 drh: ** released when all cursors are closed. If this instruction attempts dbda8d6ce9 2007-07-21 drh: ** to get a read lock but fails, the script terminates with an dbda8d6ce9 2007-07-21 drh: ** SQLITE_BUSY error code. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The P3 value is a pointer to a KeyInfo structure that defines the dbda8d6ce9 2007-07-21 drh: ** content and collating sequence of indices. P3 is NULL for cursors dbda8d6ce9 2007-07-21 drh: ** that are not pointing to indices. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also OpenWrite. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: OpenWrite P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Open a read/write cursor named P1 on the table or index whose root dbda8d6ce9 2007-07-21 drh: ** page is P2. If P2==0 then take the root page number from the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The P3 value is a pointer to a KeyInfo structure that defines the dbda8d6ce9 2007-07-21 drh: ** content and collating sequence of indices. P3 is NULL for cursors dbda8d6ce9 2007-07-21 drh: ** that are not pointing to indices. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This instruction works just like OpenRead except that it opens the cursor dbda8d6ce9 2007-07-21 drh: ** in read/write mode. For a given table, there can be one or more read-only dbda8d6ce9 2007-07-21 drh: ** cursors or a single read/write cursor but not both. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also OpenRead. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_OpenRead: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_OpenWrite: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: int p2 = pOp->p2; dbda8d6ce9 2007-07-21 drh: int wrFlag; dbda8d6ce9 2007-07-21 drh: Btree *pX; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: Cursor *pCur; dbda8d6ce9 2007-07-21 drh: Db *pDb; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: iDb = pTos->u.i; dbda8d6ce9 2007-07-21 drh: assert( (pTos->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<iDb))!=0 ); dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: pX = pDb->pBt; dbda8d6ce9 2007-07-21 drh: assert( pX!=0 ); dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_OpenWrite ){ dbda8d6ce9 2007-07-21 drh: wrFlag = 1; dbda8d6ce9 2007-07-21 drh: if( pDb->pSchema->file_format < p->minWriteFileFormat ){ dbda8d6ce9 2007-07-21 drh: p->minWriteFileFormat = pDb->pSchema->file_format; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: wrFlag = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p2<=0 ){ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: p2 = pTos->u.i; dbda8d6ce9 2007-07-21 drh: assert( (pTos->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: assert( p2>=2 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( i>=0 ); dbda8d6ce9 2007-07-21 drh: pCur = allocateCursor(p, i, iDb); dbda8d6ce9 2007-07-21 drh: if( pCur==0 ) goto no_mem; dbda8d6ce9 2007-07-21 drh: pCur->nullRow = 1; dbda8d6ce9 2007-07-21 drh: if( pX==0 ) break; dbda8d6ce9 2007-07-21 drh: /* We always provide a key comparison function. If the table being dbda8d6ce9 2007-07-21 drh: ** opened is of type INTKEY, the comparision function will be ignored. */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCursor(pX, p2, wrFlag, dbda8d6ce9 2007-07-21 drh: sqlite3VdbeRecordCompare, pOp->p3, dbda8d6ce9 2007-07-21 drh: &pCur->pCursor); dbda8d6ce9 2007-07-21 drh: if( pOp->p3type==P3_KEYINFO ){ dbda8d6ce9 2007-07-21 drh: pCur->pKeyInfo = (KeyInfo*)pOp->p3; dbda8d6ce9 2007-07-21 drh: pCur->pIncrKey = &pCur->pKeyInfo->incrKey; dbda8d6ce9 2007-07-21 drh: pCur->pKeyInfo->enc = ENC(p->db); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pCur->pKeyInfo = 0; dbda8d6ce9 2007-07-21 drh: pCur->pIncrKey = &pCur->bogusIncrKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: switch( rc ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_BUSY: { dbda8d6ce9 2007-07-21 drh: p->pc = pc; c287665ba8 2007-09-14 drh: p->rc = rc = SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */ c287665ba8 2007-09-14 drh: goto vdbe_return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case SQLITE_OK: { dbda8d6ce9 2007-07-21 drh: int flags = sqlite3BtreeFlags(pCur->pCursor); dbda8d6ce9 2007-07-21 drh: /* Sanity checking. Only the lower four bits of the flags byte should dbda8d6ce9 2007-07-21 drh: ** be used. Bit 3 (mask 0x08) is unpreditable. The lower 3 bits dbda8d6ce9 2007-07-21 drh: ** (mask 0x07) should be either 5 (intkey+leafdata for tables) or dbda8d6ce9 2007-07-21 drh: ** 2 (zerodata for indices). If these conditions are not met it can dbda8d6ce9 2007-07-21 drh: ** only mean that we are dealing with a corrupt database file dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (flags & 0xf0)!=0 || ((flags & 0x07)!=5 && (flags & 0x07)!=2) ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCur->isTable = (flags & BTREE_INTKEY)!=0; dbda8d6ce9 2007-07-21 drh: pCur->isIndex = (flags & BTREE_ZERODATA)!=0; dbda8d6ce9 2007-07-21 drh: /* If P3==0 it means we are expected to open a table. If P3!=0 then dbda8d6ce9 2007-07-21 drh: ** we expect to be opening an index. If this is not what happened, dbda8d6ce9 2007-07-21 drh: ** then the database is corrupt dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (pCur->isTable && pOp->p3type==P3_KEYINFO) dbda8d6ce9 2007-07-21 drh: || (pCur->isIndex && pOp->p3type!=P3_KEYINFO) ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case SQLITE_EMPTY: { dbda8d6ce9 2007-07-21 drh: pCur->isTable = pOp->p3type!=P3_KEYINFO; dbda8d6ce9 2007-07-21 drh: pCur->isIndex = !pCur->isTable; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: OpenEphemeral P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Open a new cursor P1 to a transient table. dbda8d6ce9 2007-07-21 drh: ** The cursor is always opened read/write even if dbda8d6ce9 2007-07-21 drh: ** the main database is read-only. The transient or virtual dbda8d6ce9 2007-07-21 drh: ** table is deleted automatically when the cursor is closed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P2 is the number of columns in the virtual table. dbda8d6ce9 2007-07-21 drh: ** The cursor points to a BTree table if P3==0 and to a BTree index dbda8d6ce9 2007-07-21 drh: ** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure dbda8d6ce9 2007-07-21 drh: ** that defines the format of keys in the index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode was once called OpenTemp. But that created dbda8d6ce9 2007-07-21 drh: ** confusion because the term "temp table", might refer either dbda8d6ce9 2007-07-21 drh: ** to a TEMP table at the SQL level, or to a table opened by dbda8d6ce9 2007-07-21 drh: ** this opcode. Then this opcode was call OpenVirtual. But dbda8d6ce9 2007-07-21 drh: ** that created confusion with the whole virtual-table idea. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_OpenEphemeral: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pCx; c287665ba8 2007-09-14 drh: static const int openFlags = c287665ba8 2007-09-14 drh: SQLITE_OPEN_READWRITE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_CREATE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_EXCLUSIVE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_DELETEONCLOSE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_TRANSIENT_DB; c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 ); dbda8d6ce9 2007-07-21 drh: pCx = allocateCursor(p, i, -1); dbda8d6ce9 2007-07-21 drh: if( pCx==0 ) goto no_mem; dbda8d6ce9 2007-07-21 drh: pCx->nullRow = 1; c287665ba8 2007-09-14 drh: rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags, c287665ba8 2007-09-14 drh: &pCx->pBt); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeBeginTrans(pCx->pBt, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: /* If a transient index is required, create it by calling dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeCreateTable() with the BTREE_ZERODATA flag before dbda8d6ce9 2007-07-21 drh: ** opening it. If a transient table is required, just use the dbda8d6ce9 2007-07-21 drh: ** automatically created table with root-page 1 (an INTKEY table). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pOp->p3 ){ dbda8d6ce9 2007-07-21 drh: int pgno; dbda8d6ce9 2007-07-21 drh: assert( pOp->p3type==P3_KEYINFO ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: assert( pgno==MASTER_ROOT+1 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeRecordCompare, dbda8d6ce9 2007-07-21 drh: pOp->p3, &pCx->pCursor); dbda8d6ce9 2007-07-21 drh: pCx->pKeyInfo = (KeyInfo*)pOp->p3; dbda8d6ce9 2007-07-21 drh: pCx->pKeyInfo->enc = ENC(p->db); dbda8d6ce9 2007-07-21 drh: pCx->pIncrKey = &pCx->pKeyInfo->incrKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCx->isTable = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, 0, &pCx->pCursor); dbda8d6ce9 2007-07-21 drh: pCx->isTable = 1; dbda8d6ce9 2007-07-21 drh: pCx->pIncrKey = &pCx->bogusIncrKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCx->nField = pOp->p2; dbda8d6ce9 2007-07-21 drh: pCx->isIndex = !pCx->isTable; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: OpenPseudo P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Open a new cursor that points to a fake table that contains a single dbda8d6ce9 2007-07-21 drh: ** row of data. Any attempt to write a second row of data causes the dbda8d6ce9 2007-07-21 drh: ** first row to be deleted. All data is deleted when the cursor is dbda8d6ce9 2007-07-21 drh: ** closed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A pseudo-table created by this opcode is useful for holding the dbda8d6ce9 2007-07-21 drh: ** NEW or OLD tables in a trigger. Also used to hold the a single dbda8d6ce9 2007-07-21 drh: ** row output from the sorter so that the row can be decomposed into dbda8d6ce9 2007-07-21 drh: ** individual columns using the OP_Column opcode. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_OpenPseudo: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pCx; dbda8d6ce9 2007-07-21 drh: assert( i>=0 ); dbda8d6ce9 2007-07-21 drh: pCx = allocateCursor(p, i, -1); dbda8d6ce9 2007-07-21 drh: if( pCx==0 ) goto no_mem; dbda8d6ce9 2007-07-21 drh: pCx->nullRow = 1; dbda8d6ce9 2007-07-21 drh: pCx->pseudoTable = 1; dbda8d6ce9 2007-07-21 drh: pCx->pIncrKey = &pCx->bogusIncrKey; dbda8d6ce9 2007-07-21 drh: pCx->isTable = 1; dbda8d6ce9 2007-07-21 drh: pCx->isIndex = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Close P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Close a cursor previously opened as P1. If P1 is not dbda8d6ce9 2007-07-21 drh: ** currently open, this instruction is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Close: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: if( i>=0 && i<p->nCursor ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeFreeCursor(p, p->apCsr[i]); dbda8d6ce9 2007-07-21 drh: p->apCsr[i] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: MoveGe P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top of the stack and use its value as a key. Reposition dbda8d6ce9 2007-07-21 drh: ** cursor P1 so that it points to the smallest entry that is greater dbda8d6ce9 2007-07-21 drh: ** than or equal to the key that was popped ffrom the stack. dbda8d6ce9 2007-07-21 drh: ** If there are no records greater than or equal to the key and P2 dbda8d6ce9 2007-07-21 drh: ** is not zero, then jump to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: MoveGt P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top of the stack and use its value as a key. Reposition dbda8d6ce9 2007-07-21 drh: ** cursor P1 so that it points to the smallest entry that is greater dbda8d6ce9 2007-07-21 drh: ** than the key from the stack. dbda8d6ce9 2007-07-21 drh: ** If there are no records greater than the key and P2 is not zero, dbda8d6ce9 2007-07-21 drh: ** then jump to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: MoveLt P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top of the stack and use its value as a key. Reposition dbda8d6ce9 2007-07-21 drh: ** cursor P1 so that it points to the largest entry that is less dbda8d6ce9 2007-07-21 drh: ** than the key from the stack. dbda8d6ce9 2007-07-21 drh: ** If there are no records less than the key and P2 is not zero, dbda8d6ce9 2007-07-21 drh: ** then jump to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: MoveLe P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pop the top of the stack and use its value as a key. Reposition dbda8d6ce9 2007-07-21 drh: ** cursor P1 so that it points to the largest entry that is less than dbda8d6ce9 2007-07-21 drh: ** or equal to the key that was popped from the stack. dbda8d6ce9 2007-07-21 drh: ** If there are no records less than or eqal to the key and P2 is not zero, dbda8d6ce9 2007-07-21 drh: ** then jump to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MoveLt: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_MoveLe: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_MoveGe: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_MoveGt: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[i]; dbda8d6ce9 2007-07-21 drh: assert( pC!=0 ); dbda8d6ce9 2007-07-21 drh: if( pC->pCursor!=0 ){ dbda8d6ce9 2007-07-21 drh: int res, oc; dbda8d6ce9 2007-07-21 drh: oc = pOp->opcode; dbda8d6ce9 2007-07-21 drh: pC->nullRow = 0; dbda8d6ce9 2007-07-21 drh: *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe; dbda8d6ce9 2007-07-21 drh: if( pC->isTable ){ dbda8d6ce9 2007-07-21 drh: i64 iKey; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: iKey = intToKey(pTos->u.i); dbda8d6ce9 2007-07-21 drh: if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){ dbda8d6ce9 2007-07-21 drh: pC->movetoTarget = iKey; dbda8d6ce9 2007-07-21 drh: pC->deferredMoveto = 1; dbda8d6ce9 2007-07-21 drh: assert( (pTos->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, 0, &res); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pC->lastRowid = pTos->u.i; dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = res==0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Blob ); dbda8d6ce9 2007-07-21 drh: ExpandBlob(pTos); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pC->deferredMoveto = 0; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: *pC->pIncrKey = 0; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: sqlite3_search_count++; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( oc==OP_MoveGe || oc==OP_MoveGt ){ dbda8d6ce9 2007-07-21 drh: if( res<0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeNext(pC->pCursor, &res); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: res = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( oc==OP_MoveLt || oc==OP_MoveLe ); dbda8d6ce9 2007-07-21 drh: if( res>=0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreePrevious(pC->pCursor, &res); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* res might be negative because the table is empty. Check to dbda8d6ce9 2007-07-21 drh: ** see if this is the case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: res = sqlite3BtreeEof(pC->pCursor); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: if( pOp->p2>0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pC->nullRow = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Distinct P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Use the top of the stack as a record created using MakeRecord. P1 is a dbda8d6ce9 2007-07-21 drh: ** cursor on a table that declared as an index. If that table contains an dbda8d6ce9 2007-07-21 drh: ** entry that matches the top of the stack fall thru. If the top of the stack dbda8d6ce9 2007-07-21 drh: ** matches no entry in P1 then jump to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The cursor is left pointing at the matching entry if it exists. The dbda8d6ce9 2007-07-21 drh: ** record on the top of the stack is not popped. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This instruction is similar to NotFound except that this operation dbda8d6ce9 2007-07-21 drh: ** does not pop the key from the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The instruction is used to implement the DISTINCT operator on SELECT dbda8d6ce9 2007-07-21 drh: ** statements. The P1 table is not a true index but rather a record of dbda8d6ce9 2007-07-21 drh: ** all results that have produced so far. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Found, NotFound, MoveTo, IsUnique, NotExists dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Found P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Top of the stack holds a blob constructed by MakeRecord. P1 is an index. dbda8d6ce9 2007-07-21 drh: ** If an entry that matches the top of the stack exists in P1 then dbda8d6ce9 2007-07-21 drh: ** jump to P2. If the top of the stack does not match any entry in P1 dbda8d6ce9 2007-07-21 drh: ** then fall thru. The P1 cursor is left pointing at the matching entry dbda8d6ce9 2007-07-21 drh: ** if it exists. The blob is popped off the top of the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This instruction is used to implement the IN operator where the dbda8d6ce9 2007-07-21 drh: ** left-hand side is a SELECT statement. P1 is not a true index but dbda8d6ce9 2007-07-21 drh: ** is instead a temporary index that holds the results of the SELECT dbda8d6ce9 2007-07-21 drh: ** statement. This instruction just checks to see if the left-hand side dbda8d6ce9 2007-07-21 drh: ** of the IN operator (stored on the top of the stack) exists in the dbda8d6ce9 2007-07-21 drh: ** result of the SELECT statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Distinct, NotFound, MoveTo, IsUnique, NotExists dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: NotFound P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack holds a blob constructed by MakeRecord. P1 is dbda8d6ce9 2007-07-21 drh: ** an index. If no entry exists in P1 that matches the blob then jump dbda8d6ce9 2007-07-21 drh: ** to P2. If an entry does existing, fall through. The cursor is left dbda8d6ce9 2007-07-21 drh: ** pointing to the entry that matches. The blob is popped from the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The difference between this operation and Distinct is that dbda8d6ce9 2007-07-21 drh: ** Distinct does not pop the key from the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Distinct, Found, MoveTo, NotExists, IsUnique dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Distinct: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_NotFound: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Found: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: int alreadyExists = 0; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: if( (pC = p->apCsr[i])->pCursor!=0 ){ c287665ba8 2007-09-14 drh: int res; dbda8d6ce9 2007-07-21 drh: assert( pC->isTable==0 ); dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Blob ); dbda8d6ce9 2007-07-21 drh: Stringify(pTos, encoding); c287665ba8 2007-09-14 drh: rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: alreadyExists = (res==0); dbda8d6ce9 2007-07-21 drh: pC->deferredMoveto = 0; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_Found ){ dbda8d6ce9 2007-07-21 drh: if( alreadyExists ) pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( !alreadyExists ) pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pOp->opcode!=OP_Distinct ){ dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IsUnique P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack is an integer record number. Call this dbda8d6ce9 2007-07-21 drh: ** record number R. The next on the stack is an index key created dbda8d6ce9 2007-07-21 drh: ** using MakeIdxRec. Call it K. This instruction pops R from the dbda8d6ce9 2007-07-21 drh: ** stack but it leaves K unchanged. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P1 is an index. So it has no data and its key consists of a dbda8d6ce9 2007-07-21 drh: ** record generated by OP_MakeRecord where the last field is the dbda8d6ce9 2007-07-21 drh: ** rowid of the entry that the index refers to. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This instruction asks if there is an entry in P1 where the dbda8d6ce9 2007-07-21 drh: ** fields matches K but the rowid is different from R. dbda8d6ce9 2007-07-21 drh: ** If there is no such entry, then there is an immediate dbda8d6ce9 2007-07-21 drh: ** jump to P2. If any entry does exist where the index string dbda8d6ce9 2007-07-21 drh: ** matches K but the record number is not R, then the record dbda8d6ce9 2007-07-21 drh: ** number for that entry is pushed onto the stack and control dbda8d6ce9 2007-07-21 drh: ** falls through to the next instruction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Distinct, NotFound, NotExists, Found dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IsUnique: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Mem *pNos = &pTos[-1]; dbda8d6ce9 2007-07-21 drh: Cursor *pCx; dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; dbda8d6ce9 2007-07-21 drh: i64 R; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Pop the value R off the top of the stack dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pNos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: R = pTos->u.i; dbda8d6ce9 2007-07-21 drh: assert( (pTos->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pCx = p->apCsr[i]; dbda8d6ce9 2007-07-21 drh: assert( pCx!=0 ); dbda8d6ce9 2007-07-21 drh: pCrsr = pCx->pCursor; dbda8d6ce9 2007-07-21 drh: if( pCrsr!=0 ){ dbda8d6ce9 2007-07-21 drh: int res; dbda8d6ce9 2007-07-21 drh: i64 v; /* The record number on the P1 entry that matches K */ dbda8d6ce9 2007-07-21 drh: char *zKey; /* The value of K */ dbda8d6ce9 2007-07-21 drh: int nKey; /* Number of bytes in K */ dbda8d6ce9 2007-07-21 drh: int len; /* Number of bytes in K without the rowid at the end */ dbda8d6ce9 2007-07-21 drh: int szRowid; /* Size of the rowid column at the end of zKey */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure K is a string and make zKey point to K dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pNos->flags & MEM_Blob ); dbda8d6ce9 2007-07-21 drh: Stringify(pNos, encoding); dbda8d6ce9 2007-07-21 drh: zKey = pNos->z; dbda8d6ce9 2007-07-21 drh: nKey = pNos->n; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: szRowid = sqlite3VdbeIdxRowidLen((u8*)zKey); dbda8d6ce9 2007-07-21 drh: len = nKey-szRowid; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Search for an entry in P1 where all but the last four bytes match K. dbda8d6ce9 2007-07-21 drh: ** If there is no such entry, jump immediately to P2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pCx->deferredMoveto==0 ); dbda8d6ce9 2007-07-21 drh: pCx->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeMoveto(pCrsr, zKey, len, 0, &res); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( res<0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeNext(pCrsr, &res); dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeIdxKeyCompare(pCx, len, (u8*)zKey, &res); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: if( res>0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* At this point, pCrsr is pointing to an entry in P1 where all but dbda8d6ce9 2007-07-21 drh: ** the final entry (the rowid) matches K. Check to see if the dbda8d6ce9 2007-07-21 drh: ** final rowid column is different from R. If it equals R then jump dbda8d6ce9 2007-07-21 drh: ** immediately to P2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeIdxRowid(pCrsr, &v); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( v==R ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The final varint of the key is different from R. Push it onto dbda8d6ce9 2007-07-21 drh: ** the stack. (The record number of an entry that violates a UNIQUE dbda8d6ce9 2007-07-21 drh: ** constraint.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->u.i = v; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: NotExists P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Use the top of the stack as a integer key. If a record with that key dbda8d6ce9 2007-07-21 drh: ** does not exist in table of P1, then jump to P2. If the record dbda8d6ce9 2007-07-21 drh: ** does exist, then fall thru. The cursor is left pointing to the dbda8d6ce9 2007-07-21 drh: ** record if it exists. The integer key is popped from the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The difference between this operation and NotFound is that this dbda8d6ce9 2007-07-21 drh: ** operation assumes the key is an integer and that P1 is a table whereas dbda8d6ce9 2007-07-21 drh: ** NotFound assumes key is a blob constructed from MakeRecord and dbda8d6ce9 2007-07-21 drh: ** P1 is an index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Distinct, Found, MoveTo, NotFound, IsUnique dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_NotExists: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ dbda8d6ce9 2007-07-21 drh: int res; dbda8d6ce9 2007-07-21 drh: u64 iKey; dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Int ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]->isTable ); dbda8d6ce9 2007-07-21 drh: iKey = intToKey(pTos->u.i); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, 0,&res); dbda8d6ce9 2007-07-21 drh: pC->lastRowid = pTos->u.i; dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = res==0; dbda8d6ce9 2007-07-21 drh: pC->nullRow = 0; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: /* res might be uninitialized if rc!=SQLITE_OK. But if rc!=SQLITE_OK dbda8d6ce9 2007-07-21 drh: ** processing is about to abort so we really do not care whether or not dbda8d6ce9 2007-07-21 drh: ** the following jump is taken. (In other words, do not stress over dbda8d6ce9 2007-07-21 drh: ** the error that valgrind sometimes shows on the next statement when dbda8d6ce9 2007-07-21 drh: ** running ioerr.test and similar failure-recovery test scripts.) */ dbda8d6ce9 2007-07-21 drh: if( res!=0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Sequence P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push an integer onto the stack which is the next available dbda8d6ce9 2007-07-21 drh: ** sequence number for cursor P1. The sequence number on the dbda8d6ce9 2007-07-21 drh: ** cursor is incremented after the push. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Sequence: { dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->u.i = p->apCsr[i]->seqCount++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: NewRowid P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Get a new integer record number (a.k.a "rowid") used as the key to a table. dbda8d6ce9 2007-07-21 drh: ** The record number is not previously used as a key in the database dbda8d6ce9 2007-07-21 drh: ** table that cursor P1 points to. The new record number is pushed dbda8d6ce9 2007-07-21 drh: ** onto the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P2>0 then P2 is a memory cell that holds the largest previously dbda8d6ce9 2007-07-21 drh: ** generated record number. No new record numbers are allowed to be less dbda8d6ce9 2007-07-21 drh: ** than this value. When this value reaches its maximum, a SQLITE_FULL dbda8d6ce9 2007-07-21 drh: ** error is generated. The P2 memory cell is updated with the generated dbda8d6ce9 2007-07-21 drh: ** record number. This P2 mechanism is used to help implement the dbda8d6ce9 2007-07-21 drh: ** AUTOINCREMENT feature. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_NewRowid: { dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: i64 v = 0; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: if( (pC = p->apCsr[i])->pCursor==0 ){ dbda8d6ce9 2007-07-21 drh: /* The zero initialization above is all that is needed */ dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The next rowid or record number (different terms for the same dbda8d6ce9 2007-07-21 drh: ** thing) is obtained in a two-step algorithm. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** First we attempt to find the largest existing rowid and add one dbda8d6ce9 2007-07-21 drh: ** to that. But if the largest existing rowid is already the maximum dbda8d6ce9 2007-07-21 drh: ** positive integer, we have to fall through to the second dbda8d6ce9 2007-07-21 drh: ** probabilistic algorithm dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The second algorithm is to select a rowid at random and see if dbda8d6ce9 2007-07-21 drh: ** it already exists in the table. If it does not exist, we have dbda8d6ce9 2007-07-21 drh: ** succeeded. If the random rowid does exist, we select a new one dbda8d6ce9 2007-07-21 drh: ** and try again, up to 1000 times. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For a table with less than 2 billion entries, the probability dbda8d6ce9 2007-07-21 drh: ** of not finding a unused rowid is about 1.0e-300. This is a dbda8d6ce9 2007-07-21 drh: ** non-zero probability, but it is still vanishingly small and should dbda8d6ce9 2007-07-21 drh: ** never cause a problem. You are much, much more likely to have a dbda8d6ce9 2007-07-21 drh: ** hardware failure than for this algorithm to fail. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The analysis in the previous paragraph assumes that you have a good dbda8d6ce9 2007-07-21 drh: ** source of random numbers. Is a library function like lrand48() dbda8d6ce9 2007-07-21 drh: ** good enough? Maybe. Maybe not. It's hard to know whether there dbda8d6ce9 2007-07-21 drh: ** might be subtle bugs is some implementations of lrand48() that dbda8d6ce9 2007-07-21 drh: ** could cause problems. To avoid uncertainty, SQLite uses its own dbda8d6ce9 2007-07-21 drh: ** random number generator based on the RC4 algorithm. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To promote locality of reference for repetitive inserts, the dbda8d6ce9 2007-07-21 drh: ** first few attempts at chosing a random rowid pick values just a little dbda8d6ce9 2007-07-21 drh: ** larger than the previous rowid. This has been shown experimentally dbda8d6ce9 2007-07-21 drh: ** to double the speed of the COPY operation. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int res, rx=SQLITE_OK, cnt; dbda8d6ce9 2007-07-21 drh: i64 x; dbda8d6ce9 2007-07-21 drh: cnt = 0; dbda8d6ce9 2007-07-21 drh: if( (sqlite3BtreeFlags(pC->pCursor)&(BTREE_INTKEY|BTREE_ZERODATA)) != dbda8d6ce9 2007-07-21 drh: BTREE_INTKEY ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_CORRUPT_BKPT; dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_INTKEY)!=0 ); dbda8d6ce9 2007-07-21 drh: assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_ZERODATA)==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_32BIT_ROWID dbda8d6ce9 2007-07-21 drh: # define MAX_ROWID 0x7fffffff dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: /* Some compilers complain about constants of the form 0x7fffffffffffffff. dbda8d6ce9 2007-07-21 drh: ** Others complain about 0x7ffffffffffffffffLL. The following macro seems dbda8d6ce9 2007-07-21 drh: ** to provide the constant while making all compilers happy. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: # define MAX_ROWID ( (((u64)0x7fffffff)<<32) | (u64)0xffffffff ) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pC->useRandomRowid ){ dbda8d6ce9 2007-07-21 drh: if( pC->nextRowidValid ){ dbda8d6ce9 2007-07-21 drh: v = pC->nextRowid; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeLast(pC->pCursor, &res); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: v = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeKeySize(pC->pCursor, &v); dbda8d6ce9 2007-07-21 drh: v = keyToInt(v); dbda8d6ce9 2007-07-21 drh: if( v==MAX_ROWID ){ dbda8d6ce9 2007-07-21 drh: pC->useRandomRowid = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: v++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: if( pOp->p2 ){ dbda8d6ce9 2007-07-21 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: assert( pOp->p2>0 && pOp->p2<p->nMem ); /* P2 is a valid memory cell */ dbda8d6ce9 2007-07-21 drh: pMem = &p->aMem[pOp->p2]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pMem); dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P2) holds an integer */ dbda8d6ce9 2007-07-21 drh: if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_FULL; dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( v<pMem->u.i+1 ){ dbda8d6ce9 2007-07-21 drh: v = pMem->u.i + 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMem->u.i = v; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( v<MAX_ROWID ){ dbda8d6ce9 2007-07-21 drh: pC->nextRowidValid = 1; dbda8d6ce9 2007-07-21 drh: pC->nextRowid = v+1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pC->nextRowidValid = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pC->useRandomRowid ){ dbda8d6ce9 2007-07-21 drh: assert( pOp->p2==0 ); /* SQLITE_FULL must have occurred prior to this */ dbda8d6ce9 2007-07-21 drh: v = db->priorNewRowid; dbda8d6ce9 2007-07-21 drh: cnt = 0; dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: if( v==0 || cnt>2 ){ dbda8d6ce9 2007-07-21 drh: sqlite3Randomness(sizeof(v), &v); dbda8d6ce9 2007-07-21 drh: if( cnt<5 ) v &= 0xffffff; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: unsigned char r; dbda8d6ce9 2007-07-21 drh: sqlite3Randomness(1, &r); dbda8d6ce9 2007-07-21 drh: v += r + 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( v==0 ) continue; dbda8d6ce9 2007-07-21 drh: x = intToKey(v); dbda8d6ce9 2007-07-21 drh: rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, 0, &res); dbda8d6ce9 2007-07-21 drh: cnt++; dbda8d6ce9 2007-07-21 drh: }while( cnt<1000 && rx==SQLITE_OK && res==0 ); dbda8d6ce9 2007-07-21 drh: db->priorNewRowid = v; dbda8d6ce9 2007-07-21 drh: if( rx==SQLITE_OK && res==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_FULL; dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = 0; dbda8d6ce9 2007-07-21 drh: pC->deferredMoveto = 0; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->u.i = v; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Insert P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Write an entry into the table of cursor P1. A new entry is dbda8d6ce9 2007-07-21 drh: ** created if it doesn't already exist or the data for an existing dbda8d6ce9 2007-07-21 drh: ** entry is overwritten. The data is the value on the top of the dbda8d6ce9 2007-07-21 drh: ** stack. The key is the next value down on the stack. The key must dbda8d6ce9 2007-07-21 drh: ** be an integer. The stack is popped twice by this instruction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is dbda8d6ce9 2007-07-21 drh: ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P2 is set, dbda8d6ce9 2007-07-21 drh: ** then rowid is stored for subsequent return by the dbda8d6ce9 2007-07-21 drh: ** sqlite3_last_insert_rowid() function (otherwise it's unmodified). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Parameter P3 may point to a string containing the table-name, or dbda8d6ce9 2007-07-21 drh: ** may be NULL. If it is not NULL, then the update-hook dbda8d6ce9 2007-07-21 drh: ** (sqlite3.xUpdateCallback) is invoked following a successful insert. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This instruction only works on tables. The equivalent instruction dbda8d6ce9 2007-07-21 drh: ** for indices is OP_IdxInsert. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Insert: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pNos = &pTos[-1]; dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: assert( pNos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){ dbda8d6ce9 2007-07-21 drh: i64 iKey; /* The integer ROWID or key for the record to be inserted */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pNos->flags & MEM_Int ); dbda8d6ce9 2007-07-21 drh: assert( pC->isTable ); dbda8d6ce9 2007-07-21 drh: iKey = intToKey(pNos->u.i); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; dbda8d6ce9 2007-07-21 drh: if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->u.i; dbda8d6ce9 2007-07-21 drh: if( pC->nextRowidValid && pNos->u.i>=pC->nextRowid ){ dbda8d6ce9 2007-07-21 drh: pC->nextRowidValid = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Null ){ dbda8d6ce9 2007-07-21 drh: pTos->z = 0; dbda8d6ce9 2007-07-21 drh: pTos->n = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & (MEM_Blob|MEM_Str) ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pC->pseudoTable ){ c287665ba8 2007-09-14 drh: sqlite3_free(pC->pData); dbda8d6ce9 2007-07-21 drh: pC->iKey = iKey; dbda8d6ce9 2007-07-21 drh: pC->nData = pTos->n; dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Dyn ){ dbda8d6ce9 2007-07-21 drh: pC->pData = pTos->z; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: pC->pData = sqlite3_malloc( pC->nData+2 ); dbda8d6ce9 2007-07-21 drh: if( !pC->pData ) goto no_mem; dbda8d6ce9 2007-07-21 drh: memcpy(pC->pData, pTos->z, pC->nData); dbda8d6ce9 2007-07-21 drh: pC->pData[pC->nData] = 0; dbda8d6ce9 2007-07-21 drh: pC->pData[pC->nData+1] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pC->nullRow = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int nZero; dbda8d6ce9 2007-07-21 drh: if( pTos->flags & MEM_Zero ){ dbda8d6ce9 2007-07-21 drh: nZero = pTos->u.i; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nZero = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, dbda8d6ce9 2007-07-21 drh: pTos->z, pTos->n, nZero, dbda8d6ce9 2007-07-21 drh: pOp->p2 & OPFLAG_APPEND); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = 0; dbda8d6ce9 2007-07-21 drh: pC->deferredMoveto = 0; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Invoke the update-hook if required. */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p3 ){ dbda8d6ce9 2007-07-21 drh: const char *zDb = db->aDb[pC->iDb].zName; dbda8d6ce9 2007-07-21 drh: const char *zTbl = pOp->p3; dbda8d6ce9 2007-07-21 drh: int op = ((pOp->p2 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); dbda8d6ce9 2007-07-21 drh: assert( pC->isTable ); dbda8d6ce9 2007-07-21 drh: db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey); dbda8d6ce9 2007-07-21 drh: assert( pC->iDb>=0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: popStack(&pTos, 2); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Delete P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Delete the record at which the P1 cursor is currently pointing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The cursor will be left pointing at either the next or the previous dbda8d6ce9 2007-07-21 drh: ** record in the table. If it is left pointing at the next record, then dbda8d6ce9 2007-07-21 drh: ** the next Next instruction will be a no-op. Hence it is OK to delete dbda8d6ce9 2007-07-21 drh: ** a record from within an Next loop. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is dbda8d6ce9 2007-07-21 drh: ** incremented (otherwise not). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P1 is a pseudo-table, then this instruction is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Delete: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[i]; dbda8d6ce9 2007-07-21 drh: assert( pC!=0 ); dbda8d6ce9 2007-07-21 drh: if( pC->pCursor!=0 ){ dbda8d6ce9 2007-07-21 drh: i64 iKey; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the update-hook will be invoked, set iKey to the rowid of the dbda8d6ce9 2007-07-21 drh: ** row being deleted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->xUpdateCallback && pOp->p3 ){ dbda8d6ce9 2007-07-21 drh: assert( pC->isTable ); dbda8d6ce9 2007-07-21 drh: if( pC->rowidIsValid ){ dbda8d6ce9 2007-07-21 drh: iKey = pC->lastRowid; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeKeySize(pC->pCursor, &iKey); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iKey = keyToInt(iKey); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeCursorMoveto(pC); dbda8d6ce9 2007-07-21 drh: if( rc ) goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeDelete(pC->pCursor); dbda8d6ce9 2007-07-21 drh: pC->nextRowidValid = 0; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Invoke the update-hook if required. */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p3 ){ dbda8d6ce9 2007-07-21 drh: const char *zDb = db->aDb[pC->iDb].zName; dbda8d6ce9 2007-07-21 drh: const char *zTbl = pOp->p3; dbda8d6ce9 2007-07-21 drh: db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey); dbda8d6ce9 2007-07-21 drh: assert( pC->iDb>=0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: ResetCount P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode resets the VMs internal change counter to 0. If P1 is true, dbda8d6ce9 2007-07-21 drh: ** then the value of the change counter is copied to the database handle dbda8d6ce9 2007-07-21 drh: ** change counter (returned by subsequent calls to sqlite3_changes()) dbda8d6ce9 2007-07-21 drh: ** before it is reset. This is used by trigger programs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ResetCount: { /* no-push */ dbda8d6ce9 2007-07-21 drh: if( pOp->p1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetChanges(db, p->nChange); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->nChange = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: RowData P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push onto the stack the complete row data for cursor P1. dbda8d6ce9 2007-07-21 drh: ** There is no interpretation of the data. It is just copied dbda8d6ce9 2007-07-21 drh: ** onto the stack exactly as it is found in the database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the cursor is not pointing to a valid row, a NULL is pushed dbda8d6ce9 2007-07-21 drh: ** onto the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: RowKey P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push onto the stack the complete row key for cursor P1. dbda8d6ce9 2007-07-21 drh: ** There is no interpretation of the key. It is just copied dbda8d6ce9 2007-07-21 drh: ** onto the stack exactly as it is found in the database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the cursor is not pointing to a valid row, a NULL is pushed dbda8d6ce9 2007-07-21 drh: ** onto the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_RowKey: dbda8d6ce9 2007-07-21 drh: case OP_RowData: { dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: u32 n; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Note that RowKey and RowData are really exactly the same instruction */ dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[i]; dbda8d6ce9 2007-07-21 drh: assert( pC->isTable || pOp->opcode==OP_RowKey ); dbda8d6ce9 2007-07-21 drh: assert( pC->isIndex || pOp->opcode==OP_RowData ); dbda8d6ce9 2007-07-21 drh: assert( pC!=0 ); dbda8d6ce9 2007-07-21 drh: if( pC->nullRow ){ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: }else if( pC->pCursor!=0 ){ dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr = pC->pCursor; dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeCursorMoveto(pC); dbda8d6ce9 2007-07-21 drh: if( rc ) goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: if( pC->nullRow ){ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }else if( pC->isIndex ){ dbda8d6ce9 2007-07-21 drh: i64 n64; dbda8d6ce9 2007-07-21 drh: assert( !pC->isTable ); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeKeySize(pCrsr, &n64); dbda8d6ce9 2007-07-21 drh: if( n64>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: n = n64; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeDataSize(pCrsr, &n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( n>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->n = n; dbda8d6ce9 2007-07-21 drh: if( n<=NBFS ){ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Blob | MEM_Short; dbda8d6ce9 2007-07-21 drh: pTos->z = pTos->zShort; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: char *z = sqlite3_malloc( n ); dbda8d6ce9 2007-07-21 drh: if( z==0 ) goto no_mem; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Blob | MEM_Dyn; dbda8d6ce9 2007-07-21 drh: pTos->xDel = 0; dbda8d6ce9 2007-07-21 drh: pTos->z = z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pC->isIndex ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeKey(pCrsr, 0, n, pTos->z); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeData(pCrsr, 0, n, pTos->z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pC->pseudoTable ){ dbda8d6ce9 2007-07-21 drh: pTos->n = pC->nData; dbda8d6ce9 2007-07-21 drh: assert( pC->nData<=SQLITE_MAX_LENGTH ); dbda8d6ce9 2007-07-21 drh: pTos->z = pC->pData; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Blob|MEM_Ephem; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Rowid P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push onto the stack an integer which is the key of the table entry that dbda8d6ce9 2007-07-21 drh: ** P1 is currently point to. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Rowid: { dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: i64 v; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[i]; dbda8d6ce9 2007-07-21 drh: assert( pC!=0 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeCursorMoveto(pC); dbda8d6ce9 2007-07-21 drh: if( rc ) goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: if( pC->rowidIsValid ){ dbda8d6ce9 2007-07-21 drh: v = pC->lastRowid; dbda8d6ce9 2007-07-21 drh: }else if( pC->pseudoTable ){ dbda8d6ce9 2007-07-21 drh: v = keyToInt(pC->iKey); dbda8d6ce9 2007-07-21 drh: }else if( pC->nullRow || pC->pCursor==0 ){ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pC->pCursor!=0 ); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeKeySize(pC->pCursor, &v); dbda8d6ce9 2007-07-21 drh: v = keyToInt(v); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->u.i = v; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: NullRow P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Move the cursor P1 to a null row. Any OP_Column operations dbda8d6ce9 2007-07-21 drh: ** that occur while the cursor is on the null row will always push dbda8d6ce9 2007-07-21 drh: ** a NULL onto the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_NullRow: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[i]; dbda8d6ce9 2007-07-21 drh: assert( pC!=0 ); dbda8d6ce9 2007-07-21 drh: pC->nullRow = 1; dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Last P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The next use of the Rowid or Column or Next instruction for P1 dbda8d6ce9 2007-07-21 drh: ** will refer to the last entry in the database table or index. dbda8d6ce9 2007-07-21 drh: ** If the table or index is empty and P2>0, then jump immediately to P2. dbda8d6ce9 2007-07-21 drh: ** If P2 is 0 or if the table or index is not empty, fall through dbda8d6ce9 2007-07-21 drh: ** to the following instruction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Last: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[i]; dbda8d6ce9 2007-07-21 drh: assert( pC!=0 ); dbda8d6ce9 2007-07-21 drh: if( (pCrsr = pC->pCursor)!=0 ){ dbda8d6ce9 2007-07-21 drh: int res; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeLast(pCrsr, &res); dbda8d6ce9 2007-07-21 drh: pC->nullRow = res; dbda8d6ce9 2007-07-21 drh: pC->deferredMoveto = 0; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: if( res && pOp->p2>0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pC->nullRow = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Sort P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode does exactly the same thing as OP_Rewind except that dbda8d6ce9 2007-07-21 drh: ** it increments an undocumented global variable used for testing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Sorting is accomplished by writing records into a sorting index, dbda8d6ce9 2007-07-21 drh: ** then rewinding that index and playing it back from beginning to dbda8d6ce9 2007-07-21 drh: ** end. We use the OP_Sort opcode instead of OP_Rewind to do the dbda8d6ce9 2007-07-21 drh: ** rewinding so that the global variable will be incremented and dbda8d6ce9 2007-07-21 drh: ** regression tests can determine whether or not the optimizer is dbda8d6ce9 2007-07-21 drh: ** correctly optimizing out sorts. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Sort: { /* no-push */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: sqlite3_sort_count++; dbda8d6ce9 2007-07-21 drh: sqlite3_search_count--; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: /* Fall through into OP_Rewind */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Opcode: Rewind P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The next use of the Rowid or Column or Next instruction for P1 dbda8d6ce9 2007-07-21 drh: ** will refer to the first entry in the database table or index. dbda8d6ce9 2007-07-21 drh: ** If the table or index is empty and P2>0, then jump immediately to P2. dbda8d6ce9 2007-07-21 drh: ** If P2 is 0 or if the table or index is not empty, fall through dbda8d6ce9 2007-07-21 drh: ** to the following instruction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Rewind: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; dbda8d6ce9 2007-07-21 drh: int res; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[i]; dbda8d6ce9 2007-07-21 drh: assert( pC!=0 ); dbda8d6ce9 2007-07-21 drh: if( (pCrsr = pC->pCursor)!=0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeFirst(pCrsr, &res); dbda8d6ce9 2007-07-21 drh: pC->atFirst = res==0; dbda8d6ce9 2007-07-21 drh: pC->deferredMoveto = 0; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: res = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pC->nullRow = res; dbda8d6ce9 2007-07-21 drh: if( res && pOp->p2>0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Next P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Advance cursor P1 so that it points to the next key/data pair in its dbda8d6ce9 2007-07-21 drh: ** table or index. If there are no more key/value pairs then fall through dbda8d6ce9 2007-07-21 drh: ** to the following instruction. But if the cursor advance was successful, dbda8d6ce9 2007-07-21 drh: ** jump immediately to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Prev dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: Prev P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Back up cursor P1 so that it points to the previous key/data pair in its dbda8d6ce9 2007-07-21 drh: ** table or index. If there is no previous key/value pairs then fall through dbda8d6ce9 2007-07-21 drh: ** to the following instruction. But if the cursor backup was successful, dbda8d6ce9 2007-07-21 drh: ** jump immediately to P2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Prev: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_Next: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: CHECK_FOR_INTERRUPT; dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<p->nCursor ); dbda8d6ce9 2007-07-21 drh: pC = p->apCsr[pOp->p1]; dbda8d6ce9 2007-07-21 drh: if( pC==0 ){ dbda8d6ce9 2007-07-21 drh: break; /* See ticket #2273 */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (pCrsr = pC->pCursor)!=0 ){ dbda8d6ce9 2007-07-21 drh: int res; dbda8d6ce9 2007-07-21 drh: if( pC->nullRow ){ dbda8d6ce9 2007-07-21 drh: res = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pC->deferredMoveto==0 ); dbda8d6ce9 2007-07-21 drh: rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : dbda8d6ce9 2007-07-21 drh: sqlite3BtreePrevious(pCrsr, &res); dbda8d6ce9 2007-07-21 drh: pC->nullRow = res; dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( res==0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: sqlite3_search_count++; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pC->nullRow = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pC->rowidIsValid = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IdxInsert P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack holds a SQL index key made using either the dbda8d6ce9 2007-07-21 drh: ** MakeIdxRec or MakeRecord instructions. This opcode writes that key dbda8d6ce9 2007-07-21 drh: ** into the index P1. Data for the entry is nil. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P2 is a flag that provides a hint to the b-tree layer that this dbda8d6ce9 2007-07-21 drh: ** insert is likely to be an append. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This instruction only works for indices. The equivalent instruction dbda8d6ce9 2007-07-21 drh: ** for tables is OP_Insert. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IdxInsert: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Blob ); dbda8d6ce9 2007-07-21 drh: if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ dbda8d6ce9 2007-07-21 drh: assert( pC->isTable==0 ); dbda8d6ce9 2007-07-21 drh: rc = ExpandBlob(pTos); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: int nKey = pTos->n; dbda8d6ce9 2007-07-21 drh: const char *zKey = pTos->z; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p2); dbda8d6ce9 2007-07-21 drh: assert( pC->deferredMoveto==0 ); dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IdxDelete P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack is an index key built using the either the dbda8d6ce9 2007-07-21 drh: ** MakeIdxRec or MakeRecord opcodes. dbda8d6ce9 2007-07-21 drh: ** This opcode removes that entry from the index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IdxDelete: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Blob ); dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ dbda8d6ce9 2007-07-21 drh: int res; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, 0, &res); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && res==0 ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeDelete(pCrsr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pC->deferredMoveto==0 ); dbda8d6ce9 2007-07-21 drh: pC->cacheStatus = CACHE_STALE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IdxRowid P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push onto the stack an integer which is the last entry in the record at dbda8d6ce9 2007-07-21 drh: ** the end of the index key pointed to by cursor P1. This integer should be dbda8d6ce9 2007-07-21 drh: ** the rowid of the table entry to which this index entry points. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Rowid, MakeIdxRec. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IdxRowid: { dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: BtCursor *pCrsr; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ dbda8d6ce9 2007-07-21 drh: i64 rowid; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pC->deferredMoveto==0 ); dbda8d6ce9 2007-07-21 drh: assert( pC->isTable==0 ); dbda8d6ce9 2007-07-21 drh: if( pC->nullRow ){ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeIdxRowid(pCrsr, &rowid); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pTos->u.i = rowid; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IdxGT P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack is an index entry that omits the ROWID. Compare dbda8d6ce9 2007-07-21 drh: ** the top of stack against the index that P1 is currently pointing to. dbda8d6ce9 2007-07-21 drh: ** Ignore the ROWID on the P1 index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack might have fewer columns that P1. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the P1 index entry is greater than the top of the stack dbda8d6ce9 2007-07-21 drh: ** then jump to P2. Otherwise fall through to the next instruction. dbda8d6ce9 2007-07-21 drh: ** In either case, the stack is popped once. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: IdxGE P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack is an index entry that omits the ROWID. Compare dbda8d6ce9 2007-07-21 drh: ** the top of stack against the index that P1 is currently pointing to. dbda8d6ce9 2007-07-21 drh: ** Ignore the ROWID on the P1 index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the P1 index entry is greater than or equal to the top of the stack dbda8d6ce9 2007-07-21 drh: ** then jump to P2. Otherwise fall through to the next instruction. dbda8d6ce9 2007-07-21 drh: ** In either case, the stack is popped once. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P3 is the "+" string (or any other non-NULL string) then the dbda8d6ce9 2007-07-21 drh: ** index taken from the top of the stack is temporarily increased by dbda8d6ce9 2007-07-21 drh: ** an epsilon prior to the comparison. This make the opcode work dbda8d6ce9 2007-07-21 drh: ** like IdxGT except that if the key from the stack is a prefix of dbda8d6ce9 2007-07-21 drh: ** the key in the cursor, the result is false whereas it would be dbda8d6ce9 2007-07-21 drh: ** true with IdxGT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: IdxLT P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack is an index entry that omits the ROWID. Compare dbda8d6ce9 2007-07-21 drh: ** the top of stack against the index that P1 is currently pointing to. dbda8d6ce9 2007-07-21 drh: ** Ignore the ROWID on the P1 index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the P1 index entry is less than the top of the stack dbda8d6ce9 2007-07-21 drh: ** then jump to P2. Otherwise fall through to the next instruction. dbda8d6ce9 2007-07-21 drh: ** In either case, the stack is popped once. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P3 is the "+" string (or any other non-NULL string) then the dbda8d6ce9 2007-07-21 drh: ** index taken from the top of the stack is temporarily increased by dbda8d6ce9 2007-07-21 drh: ** an epsilon prior to the comparison. This makes the opcode work dbda8d6ce9 2007-07-21 drh: ** like IdxLE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IdxLT: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_IdxGT: /* no-push */ dbda8d6ce9 2007-07-21 drh: case OP_IdxGE: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i= pOp->p1; dbda8d6ce9 2007-07-21 drh: Cursor *pC; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nCursor ); dbda8d6ce9 2007-07-21 drh: assert( p->apCsr[i]!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: if( (pC = p->apCsr[i])->pCursor!=0 ){ dbda8d6ce9 2007-07-21 drh: int res; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTos->flags & MEM_Blob ); /* Created using OP_MakeRecord */ dbda8d6ce9 2007-07-21 drh: assert( pC->deferredMoveto==0 ); dbda8d6ce9 2007-07-21 drh: ExpandBlob(pTos); dbda8d6ce9 2007-07-21 drh: *pC->pIncrKey = pOp->p3!=0; dbda8d6ce9 2007-07-21 drh: assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, (u8*)pTos->z, &res); dbda8d6ce9 2007-07-21 drh: *pC->pIncrKey = 0; dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_IdxLT ){ dbda8d6ce9 2007-07-21 drh: res = -res; dbda8d6ce9 2007-07-21 drh: }else if( pOp->opcode==OP_IdxGE ){ dbda8d6ce9 2007-07-21 drh: res++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( res>0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1 ; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: Release(pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Destroy P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Delete an entire database table or index whose root page in the database dbda8d6ce9 2007-07-21 drh: ** file is given by P1. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The table being destroyed is in the main database file if P2==0. If dbda8d6ce9 2007-07-21 drh: ** P2==1 then the table to be clear is in the auxiliary database file dbda8d6ce9 2007-07-21 drh: ** that is used to store tables create using CREATE TEMPORARY TABLE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If AUTOVACUUM is enabled then it is possible that another root page dbda8d6ce9 2007-07-21 drh: ** might be moved into the newly deleted root page in order to keep all dbda8d6ce9 2007-07-21 drh: ** root pages contiguous at the beginning of the database. The former dbda8d6ce9 2007-07-21 drh: ** value of the root page that moved - its value before the move occurred - dbda8d6ce9 2007-07-21 drh: ** is pushed onto the stack. If no page movement was required (because dbda8d6ce9 2007-07-21 drh: ** the table being dropped was already the last one in the database) then dbda8d6ce9 2007-07-21 drh: ** a zero is pushed onto the stack. If AUTOVACUUM is disabled dbda8d6ce9 2007-07-21 drh: ** then a zero is pushed onto the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Clear dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Destroy: { dbda8d6ce9 2007-07-21 drh: int iMoved; dbda8d6ce9 2007-07-21 drh: int iCnt; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: Vdbe *pVdbe; dbda8d6ce9 2007-07-21 drh: iCnt = 0; dbda8d6ce9 2007-07-21 drh: for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ dbda8d6ce9 2007-07-21 drh: if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){ dbda8d6ce9 2007-07-21 drh: iCnt++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: iCnt = db->activeVdbeCnt; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( iCnt>1 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_LOCKED; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( iCnt==1 ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<pOp->p2))!=0 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pTos->u.i = iMoved; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && iMoved!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Clear P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Delete all contents of the database table or index whose root page dbda8d6ce9 2007-07-21 drh: ** in the database file is given by P1. But, unlike Destroy, do not dbda8d6ce9 2007-07-21 drh: ** remove the table or index from the database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The table being clear is in the main database file if P2==0. If dbda8d6ce9 2007-07-21 drh: ** P2==1 then the table to be clear is in the auxiliary database file dbda8d6ce9 2007-07-21 drh: ** that is used to store tables create using CREATE TEMPORARY TABLE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: Destroy dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Clear: { /* no-push */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* For consistency with the way other features of SQLite operate dbda8d6ce9 2007-07-21 drh: ** with a truncate, we will also skip the update callback. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if 0 dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[pOp->p2].pBt; dbda8d6ce9 2007-07-21 drh: if( db->xUpdateCallback && pOp->p3 ){ dbda8d6ce9 2007-07-21 drh: const char *zDb = db->aDb[pOp->p2].zName; dbda8d6ce9 2007-07-21 drh: const char *zTbl = pOp->p3; dbda8d6ce9 2007-07-21 drh: BtCursor *pCur = 0; dbda8d6ce9 2007-07-21 drh: int fin = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCursor(pBt, pOp->p1, 0, 0, 0, &pCur); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for( dbda8d6ce9 2007-07-21 drh: rc=sqlite3BtreeFirst(pCur, &fin); dbda8d6ce9 2007-07-21 drh: rc==SQLITE_OK && !fin; dbda8d6ce9 2007-07-21 drh: rc=sqlite3BtreeNext(pCur, &fin) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: i64 iKey; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeKeySize(pCur, &iKey); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iKey = keyToInt(iKey); dbda8d6ce9 2007-07-21 drh: db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCloseCursor(pCur); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<pOp->p2))!=0 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: CreateTable P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Allocate a new table in the main database file if P2==0 or in the dbda8d6ce9 2007-07-21 drh: ** auxiliary database file if P2==1. Push the page number dbda8d6ce9 2007-07-21 drh: ** for the root page of the new table onto the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The difference between a table and an index is this: A table must dbda8d6ce9 2007-07-21 drh: ** have a 4-byte integer key and can have arbitrary data. An index dbda8d6ce9 2007-07-21 drh: ** has an arbitrary key but no data. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also: CreateIndex dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Opcode: CreateIndex P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Allocate a new index in the main database file if P2==0 or in the dbda8d6ce9 2007-07-21 drh: ** auxiliary database file if P2==1. Push the page number of the dbda8d6ce9 2007-07-21 drh: ** root page of the new index onto the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See documentation on OP_CreateTable for additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_CreateIndex: dbda8d6ce9 2007-07-21 drh: case OP_CreateTable: { dbda8d6ce9 2007-07-21 drh: int pgno; dbda8d6ce9 2007-07-21 drh: int flags; dbda8d6ce9 2007-07-21 drh: Db *pDb; dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<db->nDb ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<pOp->p1))!=0 ); dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[pOp->p1]; dbda8d6ce9 2007-07-21 drh: assert( pDb->pBt!=0 ); dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_CreateTable ){ dbda8d6ce9 2007-07-21 drh: /* flags = BTREE_INTKEY; */ dbda8d6ce9 2007-07-21 drh: flags = BTREE_LEAFDATA|BTREE_INTKEY; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: flags = BTREE_ZERODATA; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pTos->u.i = pgno; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: ParseSchema P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Read and parse all entries from the SQLITE_MASTER table of database P1 dbda8d6ce9 2007-07-21 drh: ** that match the WHERE clause P3. P2 is the "force" flag. Always do dbda8d6ce9 2007-07-21 drh: ** the parsing if P2 is true. If P2 is false, then this routine is a dbda8d6ce9 2007-07-21 drh: ** no-op if the schema is not currently loaded. In other words, if P2 dbda8d6ce9 2007-07-21 drh: ** is false, the SQLITE_MASTER table is only parsed if the rest of the dbda8d6ce9 2007-07-21 drh: ** schema is already loaded into the symbol table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode invokes the parser to create a new virtual machine, dbda8d6ce9 2007-07-21 drh: ** then runs the new virtual machine. It is thus a reentrant opcode. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ParseSchema: { /* no-push */ dbda8d6ce9 2007-07-21 drh: char *zSql; dbda8d6ce9 2007-07-21 drh: int iDb = pOp->p1; dbda8d6ce9 2007-07-21 drh: const char *zMaster; dbda8d6ce9 2007-07-21 drh: InitData initData; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: if( !pOp->p2 && !DbHasProperty(db, iDb, DB_SchemaLoaded) ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zMaster = SCHEMA_TABLE(iDb); dbda8d6ce9 2007-07-21 drh: initData.db = db; dbda8d6ce9 2007-07-21 drh: initData.iDb = pOp->p1; dbda8d6ce9 2007-07-21 drh: initData.pzErrMsg = &p->zErrMsg; c287665ba8 2007-09-14 drh: zSql = sqlite3MPrintf(db, dbda8d6ce9 2007-07-21 drh: "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s", dbda8d6ce9 2007-07-21 drh: db->aDb[iDb].zName, zMaster, pOp->p3); dbda8d6ce9 2007-07-21 drh: if( zSql==0 ) goto no_mem; dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: assert( db->init.busy==0 ); dbda8d6ce9 2007-07-21 drh: db->init.busy = 1; c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_ABORT ) rc = initData.rc; c287665ba8 2007-09-14 drh: sqlite3_free(zSql); dbda8d6ce9 2007-07-21 drh: db->init.busy = 0; dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_NOMEM ){ dbda8d6ce9 2007-07-21 drh: goto no_mem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER) dbda8d6ce9 2007-07-21 drh: /* Opcode: LoadAnalysis P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Read the sqlite_stat1 table for database P1 and load the content dbda8d6ce9 2007-07-21 drh: ** of that table into the internal index hash table. This will cause dbda8d6ce9 2007-07-21 drh: ** the analysis to be used when preparing all subsequent queries. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_LoadAnalysis: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int iDb = pOp->p1; dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3AnalysisLoad(db, iDb); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: DropTable P1 * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Remove the internal (in-memory) data structures that describe dbda8d6ce9 2007-07-21 drh: ** the table named P3 in database P1. This is called after a table dbda8d6ce9 2007-07-21 drh: ** is dropped in order to keep the internal representation of the dbda8d6ce9 2007-07-21 drh: ** schema consistent with what is on disk. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_DropTable: { /* no-push */ dbda8d6ce9 2007-07-21 drh: sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p3); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: DropIndex P1 * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Remove the internal (in-memory) data structures that describe dbda8d6ce9 2007-07-21 drh: ** the index named P3 in database P1. This is called after an index dbda8d6ce9 2007-07-21 drh: ** is dropped in order to keep the internal representation of the dbda8d6ce9 2007-07-21 drh: ** schema consistent with what is on disk. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_DropIndex: { /* no-push */ dbda8d6ce9 2007-07-21 drh: sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p3); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: DropTrigger P1 * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Remove the internal (in-memory) data structures that describe dbda8d6ce9 2007-07-21 drh: ** the trigger named P3 in database P1. This is called after a trigger dbda8d6ce9 2007-07-21 drh: ** is dropped in order to keep the internal representation of the dbda8d6ce9 2007-07-21 drh: ** schema consistent with what is on disk. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_DropTrigger: { /* no-push */ dbda8d6ce9 2007-07-21 drh: sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p3); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INTEGRITY_CHECK dbda8d6ce9 2007-07-21 drh: /* Opcode: IntegrityCk P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Do an analysis of the currently open database. Push onto the dbda8d6ce9 2007-07-21 drh: ** stack the text of an error message describing any problems. dbda8d6ce9 2007-07-21 drh: ** If no problems are found, push a NULL onto the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P1 is the address of a memory cell that contains the maximum dbda8d6ce9 2007-07-21 drh: ** number of allowed errors. At most mem[P1] errors will be reported. dbda8d6ce9 2007-07-21 drh: ** In other words, the analysis stops as soon as mem[P1] errors are dbda8d6ce9 2007-07-21 drh: ** seen. Mem[P1] is updated with the number of errors remaining. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The root page numbers of all tables in the database are integer dbda8d6ce9 2007-07-21 drh: ** values on the stack. This opcode pulls as many integers as it dbda8d6ce9 2007-07-21 drh: ** can off of the stack and uses those numbers as the root pages. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P2 is not zero, the check is done on the auxiliary database dbda8d6ce9 2007-07-21 drh: ** file, not the main database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode is used to implement the integrity_check pragma. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IntegrityCk: { dbda8d6ce9 2007-07-21 drh: int nRoot; dbda8d6ce9 2007-07-21 drh: int *aRoot; dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: int nErr; dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: Mem *pnErr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){ dbda8d6ce9 2007-07-21 drh: if( (pTos[-nRoot].flags & MEM_Int)==0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( nRoot>0 ); c287665ba8 2007-09-14 drh: aRoot = sqlite3_malloc( sizeof(int)*(nRoot+1) ); dbda8d6ce9 2007-07-21 drh: if( aRoot==0 ) goto no_mem; dbda8d6ce9 2007-07-21 drh: j = pOp->p1; dbda8d6ce9 2007-07-21 drh: assert( j>=0 && j<p->nMem ); dbda8d6ce9 2007-07-21 drh: pnErr = &p->aMem[j]; dbda8d6ce9 2007-07-21 drh: assert( (pnErr->flags & MEM_Int)!=0 ); dbda8d6ce9 2007-07-21 drh: for(j=0; j<nRoot; j++){ d8590e093f 2007-07-24 drh: aRoot[j] = (pTos-j)->u.i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: aRoot[j] = 0; dbda8d6ce9 2007-07-21 drh: popStack(&pTos, nRoot); dbda8d6ce9 2007-07-21 drh: pTos++; c287665ba8 2007-09-14 drh: assert( pOp->p2>=0 && pOp->p2<db->nDb ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<pOp->p2))!=0 ); dbda8d6ce9 2007-07-21 drh: z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot, dbda8d6ce9 2007-07-21 drh: pnErr->u.i, &nErr); dbda8d6ce9 2007-07-21 drh: pnErr->u.i -= nErr; dbda8d6ce9 2007-07-21 drh: if( nErr==0 ){ dbda8d6ce9 2007-07-21 drh: assert( z==0 ); dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTos->z = z; dbda8d6ce9 2007-07-21 drh: pTos->n = strlen(z); dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Str | MEM_Dyn | MEM_Term; dbda8d6ce9 2007-07-21 drh: pTos->xDel = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTos->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeEncoding(pTos, encoding); c287665ba8 2007-09-14 drh: sqlite3_free(aRoot); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: FifoWrite * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Write the integer on the top of the stack dbda8d6ce9 2007-07-21 drh: ** into the Fifo. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_FifoWrite: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); c287665ba8 2007-09-14 drh: if( sqlite3VdbeFifoPush(&p->sFifo, pTos->u.i)==SQLITE_NOMEM ){ c287665ba8 2007-09-14 drh: goto no_mem; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: assert( (pTos->flags & MEM_Dyn)==0 ); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: FifoRead * P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Attempt to read a single integer from the Fifo dbda8d6ce9 2007-07-21 drh: ** and push it onto the stack. If the Fifo is empty dbda8d6ce9 2007-07-21 drh: ** push nothing but instead jump to P2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_FifoRead: { dbda8d6ce9 2007-07-21 drh: i64 v; dbda8d6ce9 2007-07-21 drh: CHECK_FOR_INTERRUPT; dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeFifoPop(&p->sFifo, &v)==SQLITE_DONE ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->u.i = v; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: /* Opcode: ContextPush * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Save the current Vdbe context such that it can be restored by a ContextPop dbda8d6ce9 2007-07-21 drh: ** opcode. The context stores the last insert row id, the last statement change dbda8d6ce9 2007-07-21 drh: ** count, and the current statement change count. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ContextPush: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = p->contextStackTop++; dbda8d6ce9 2007-07-21 drh: Context *pContext; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( i>=0 ); dbda8d6ce9 2007-07-21 drh: /* FIX ME: This should be allocated as part of the vdbe at compile-time */ dbda8d6ce9 2007-07-21 drh: if( i>=p->contextStackDepth ){ dbda8d6ce9 2007-07-21 drh: p->contextStackDepth = i+1; c287665ba8 2007-09-14 drh: p->contextStack = sqlite3DbReallocOrFree(db, p->contextStack, dbda8d6ce9 2007-07-21 drh: sizeof(Context)*(i+1)); dbda8d6ce9 2007-07-21 drh: if( p->contextStack==0 ) goto no_mem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pContext = &p->contextStack[i]; dbda8d6ce9 2007-07-21 drh: pContext->lastRowid = db->lastRowid; dbda8d6ce9 2007-07-21 drh: pContext->nChange = p->nChange; dbda8d6ce9 2007-07-21 drh: pContext->sFifo = p->sFifo; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeFifoInit(&p->sFifo); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: ContextPop * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Restore the Vdbe context to the state it was in when contextPush was last dbda8d6ce9 2007-07-21 drh: ** executed. The context stores the last insert row id, the last statement dbda8d6ce9 2007-07-21 drh: ** change count, and the current statement change count. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_ContextPop: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Context *pContext = &p->contextStack[--p->contextStackTop]; dbda8d6ce9 2007-07-21 drh: assert( p->contextStackTop>=0 ); dbda8d6ce9 2007-07-21 drh: db->lastRowid = pContext->lastRowid; dbda8d6ce9 2007-07-21 drh: p->nChange = pContext->nChange; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeFifoClear(&p->sFifo); dbda8d6ce9 2007-07-21 drh: p->sFifo = pContext->sFifo; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* #ifndef SQLITE_OMIT_TRIGGER */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: MemStore P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Write the top of the stack into memory location P1. dbda8d6ce9 2007-07-21 drh: ** P1 should be a small integer since space is allocated dbda8d6ce9 2007-07-21 drh: ** for all memory locations between 0 and P1 inclusive. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After the data is stored in the memory location, the dbda8d6ce9 2007-07-21 drh: ** stack is popped once if P2 is 1. If P2 is zero, then dbda8d6ce9 2007-07-21 drh: ** the original data remains on the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MemStore: { /* no-push */ dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<p->nMem ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], pTos); dbda8d6ce9 2007-07-21 drh: pTos--; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If P2 is 0 then fall thru to the next opcode, OP_MemLoad, that will dbda8d6ce9 2007-07-21 drh: ** restore the top of the stack to its original value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pOp->p2 ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Opcode: MemLoad P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push a copy of the value in memory location P1 onto the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the value is a string, then the value pushed is a pointer to dbda8d6ce9 2007-07-21 drh: ** the string that is stored in the memory location. If the memory dbda8d6ce9 2007-07-21 drh: ** location is subsequently changed (using OP_MemStore) then the dbda8d6ce9 2007-07-21 drh: ** value pushed onto the stack will change too. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MemLoad: { dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nMem ); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemShallowCopy(pTos, &p->aMem[i], MEM_Ephem); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: /* Opcode: MemMax P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Set the value of memory cell P1 to the maximum of its current value dbda8d6ce9 2007-07-21 drh: ** and the value on the top of the stack. The stack is unchanged. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This instruction throws an error if the memory cell is not initially dbda8d6ce9 2007-07-21 drh: ** an integer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MemMax: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: assert( pTos>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nMem ); dbda8d6ce9 2007-07-21 drh: pMem = &p->aMem[i]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pMem); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemIntegerify(pTos); dbda8d6ce9 2007-07-21 drh: if( pMem->u.i<pTos->u.i){ dbda8d6ce9 2007-07-21 drh: pMem->u.i = pTos->u.i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_AUTOINCREMENT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: MemIncr P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Increment the integer valued memory cell P2 by the value in P1. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is illegal to use this instruction on a memory cell that does dbda8d6ce9 2007-07-21 drh: ** not contain an integer. An assertion fault will result if you try. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MemIncr: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p2; dbda8d6ce9 2007-07-21 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nMem ); dbda8d6ce9 2007-07-21 drh: pMem = &p->aMem[i]; dbda8d6ce9 2007-07-21 drh: assert( pMem->flags==MEM_Int ); dbda8d6ce9 2007-07-21 drh: pMem->u.i += pOp->p1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IfMemPos P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the value of memory cell P1 is 1 or greater, jump to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is illegal to use this instruction on a memory cell that does dbda8d6ce9 2007-07-21 drh: ** not contain an integer. An assertion fault will result if you try. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IfMemPos: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nMem ); dbda8d6ce9 2007-07-21 drh: pMem = &p->aMem[i]; dbda8d6ce9 2007-07-21 drh: assert( pMem->flags==MEM_Int ); dbda8d6ce9 2007-07-21 drh: if( pMem->u.i>0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IfMemNeg P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the value of memory cell P1 is less than zero, jump to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is illegal to use this instruction on a memory cell that does dbda8d6ce9 2007-07-21 drh: ** not contain an integer. An assertion fault will result if you try. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IfMemNeg: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nMem ); dbda8d6ce9 2007-07-21 drh: pMem = &p->aMem[i]; dbda8d6ce9 2007-07-21 drh: assert( pMem->flags==MEM_Int ); dbda8d6ce9 2007-07-21 drh: if( pMem->u.i<0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: IfMemZero P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the value of memory cell P1 is exactly 0, jump to P2. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is illegal to use this instruction on a memory cell that does dbda8d6ce9 2007-07-21 drh: ** not contain an integer. An assertion fault will result if you try. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IfMemZero: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int i = pOp->p1; dbda8d6ce9 2007-07-21 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: assert( i>=0 && i<p->nMem ); dbda8d6ce9 2007-07-21 drh: pMem = &p->aMem[i]; dbda8d6ce9 2007-07-21 drh: assert( pMem->flags==MEM_Int ); dbda8d6ce9 2007-07-21 drh: if( pMem->u.i==0 ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: MemNull P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Store a NULL in memory cell P1 dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MemNull: { dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<p->nMem ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetNull(&p->aMem[pOp->p1]); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: MemInt P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Store the integer value P1 in memory cell P2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MemInt: { dbda8d6ce9 2007-07-21 drh: assert( pOp->p2>=0 && pOp->p2<p->nMem ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSetInt64(&p->aMem[pOp->p2], pOp->p1); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: MemMove P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Move the content of memory cell P2 over to memory cell P1. dbda8d6ce9 2007-07-21 drh: ** Any prior content of P1 is erased. Memory cell P2 is left dbda8d6ce9 2007-07-21 drh: ** containing a NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_MemMove: { dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<p->nMem ); dbda8d6ce9 2007-07-21 drh: assert( pOp->p2>=0 && pOp->p2<p->nMem ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], &p->aMem[pOp->p2]); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: AggStep P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Execute the step function for an aggregate. The dbda8d6ce9 2007-07-21 drh: ** function has P2 arguments. P3 is a pointer to the FuncDef dbda8d6ce9 2007-07-21 drh: ** structure that specifies the function. Use memory location dbda8d6ce9 2007-07-21 drh: ** P1 as the accumulator. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The P2 arguments are popped from the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_AggStep: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int n = pOp->p2; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Mem *pMem, *pRec; dbda8d6ce9 2007-07-21 drh: sqlite3_context ctx; dbda8d6ce9 2007-07-21 drh: sqlite3_value **apVal; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( n>=0 ); dbda8d6ce9 2007-07-21 drh: pRec = &pTos[1-n]; dbda8d6ce9 2007-07-21 drh: assert( pRec>=p->aStack ); dbda8d6ce9 2007-07-21 drh: apVal = p->apArg; dbda8d6ce9 2007-07-21 drh: assert( apVal || n==0 ); dbda8d6ce9 2007-07-21 drh: for(i=0; i<n; i++, pRec++){ dbda8d6ce9 2007-07-21 drh: apVal[i] = pRec; dbda8d6ce9 2007-07-21 drh: storeTypeInfo(pRec, encoding); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: ctx.pFunc = (FuncDef*)pOp->p3; dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<p->nMem ); dbda8d6ce9 2007-07-21 drh: ctx.pMem = pMem = &p->aMem[pOp->p1]; dbda8d6ce9 2007-07-21 drh: pMem->n++; dbda8d6ce9 2007-07-21 drh: ctx.s.flags = MEM_Null; dbda8d6ce9 2007-07-21 drh: ctx.s.z = 0; dbda8d6ce9 2007-07-21 drh: ctx.s.xDel = 0; c287665ba8 2007-09-14 drh: ctx.s.db = db; dbda8d6ce9 2007-07-21 drh: ctx.isError = 0; dbda8d6ce9 2007-07-21 drh: ctx.pColl = 0; dbda8d6ce9 2007-07-21 drh: if( ctx.pFunc->needCollSeq ){ dbda8d6ce9 2007-07-21 drh: assert( pOp>p->aOp ); dbda8d6ce9 2007-07-21 drh: assert( pOp[-1].p3type==P3_COLLSEQ ); dbda8d6ce9 2007-07-21 drh: assert( pOp[-1].opcode==OP_CollSeq ); dbda8d6ce9 2007-07-21 drh: ctx.pColl = (CollSeq *)pOp[-1].p3; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: (ctx.pFunc->xStep)(&ctx, n, apVal); dbda8d6ce9 2007-07-21 drh: popStack(&pTos, n); dbda8d6ce9 2007-07-21 drh: if( ctx.isError ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(&ctx.s); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: AggFinal P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Execute the finalizer function for an aggregate. P1 is dbda8d6ce9 2007-07-21 drh: ** the memory location that is the accumulator for the aggregate. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P2 is the number of arguments that the step function takes and dbda8d6ce9 2007-07-21 drh: ** P3 is a pointer to the FuncDef for this function. The P2 dbda8d6ce9 2007-07-21 drh: ** argument is not used by this opcode. It is only there to disambiguate dbda8d6ce9 2007-07-21 drh: ** functions that can take varying numbers of arguments. The dbda8d6ce9 2007-07-21 drh: ** P3 argument is only needed for the degenerate case where dbda8d6ce9 2007-07-21 drh: ** the step function was not previously called. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_AggFinal: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Mem *pMem; dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<p->nMem ); dbda8d6ce9 2007-07-21 drh: pMem = &p->aMem[pOp->p1]; dbda8d6ce9 2007-07-21 drh: assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_ERROR ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeMemTooBig(pMem) ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) dbda8d6ce9 2007-07-21 drh: /* Opcode: Vacuum * * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Vacuum the entire database. This opcode will cause other virtual dbda8d6ce9 2007-07-21 drh: ** machines to be created and run. It may not be called from within dbda8d6ce9 2007-07-21 drh: ** a transaction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Vacuum: { /* no-push */ dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: rc = sqlite3RunVacuum(&p->zErrMsg, db); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_AUTOVACUUM) dbda8d6ce9 2007-07-21 drh: /* Opcode: IncrVacuum P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Perform a single step of the incremental vacuum procedure on dbda8d6ce9 2007-07-21 drh: ** the P1 database. If the vacuum has finished, jump to instruction dbda8d6ce9 2007-07-21 drh: ** P2. Otherwise, fall through to the next instruction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_IncrVacuum: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Btree *pBt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pOp->p1>=0 && pOp->p1<db->nDb ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<pOp->p1))!=0 ); dbda8d6ce9 2007-07-21 drh: pBt = db->aDb[pOp->p1].pBt; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeIncrVacuum(pBt); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_DONE ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Opcode: Expire P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Cause precompiled statements to become expired. An expired statement dbda8d6ce9 2007-07-21 drh: ** fails with an error code of SQLITE_SCHEMA if it is ever executed dbda8d6ce9 2007-07-21 drh: ** (via sqlite3_step()). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, dbda8d6ce9 2007-07-21 drh: ** then only the currently executing statement is affected. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_Expire: { /* no-push */ dbda8d6ce9 2007-07-21 drh: if( !pOp->p1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExpirePreparedStatements(db); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: p->expired = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: /* Opcode: TableLock P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Obtain a lock on a particular table. This instruction is only used when dbda8d6ce9 2007-07-21 drh: ** the shared-cache feature is enabled. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P1 is not negative, then it is the index of the database dbda8d6ce9 2007-07-21 drh: ** in sqlite3.aDb[] and a read-lock is required. If P1 is negative, a dbda8d6ce9 2007-07-21 drh: ** write-lock is required. In this case the index of the database is the dbda8d6ce9 2007-07-21 drh: ** absolute value of P1 minus one (iDb = abs(P1) - 1;) and a write-lock is dbda8d6ce9 2007-07-21 drh: ** required. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P2 contains the root-page of the table to lock. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 contains a pointer to the name of the table being locked. This is only dbda8d6ce9 2007-07-21 drh: ** used to generate an error message if the lock cannot be obtained. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_TableLock: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int p1 = pOp->p1; dbda8d6ce9 2007-07-21 drh: u8 isWriteLock = (p1<0); dbda8d6ce9 2007-07-21 drh: if( isWriteLock ){ dbda8d6ce9 2007-07-21 drh: p1 = (-1*p1)-1; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert( p1>=0 && p1<db->nDb ); c287665ba8 2007-09-14 drh: assert( (p->btreeMask & (1<<p1))!=0 ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_LOCKED ){ dbda8d6ce9 2007-07-21 drh: const char *z = (const char *)pOp->p3; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, "database table is locked: ", z, (char*)0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_SHARED_CACHE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VBegin * * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 a pointer to an sqlite3_vtab structure. Call the xBegin method dbda8d6ce9 2007-07-21 drh: ** for that table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VBegin: { /* no-push */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VtabBegin(db, (sqlite3_vtab *)pOp->p3); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VCreate P1 * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is the name of a virtual table in database P1. Call the xCreate method dbda8d6ce9 2007-07-21 drh: ** for that table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VCreate: { /* no-push */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p3, &p->zErrMsg); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VDestroy P1 * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is the name of a virtual table in database P1. Call the xDestroy method dbda8d6ce9 2007-07-21 drh: ** of that table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VDestroy: { /* no-push */ dbda8d6ce9 2007-07-21 drh: p->inVtabMethod = 2; dbda8d6ce9 2007-07-21 drh: rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p3); dbda8d6ce9 2007-07-21 drh: p->inVtabMethod = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VOpen P1 * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is a pointer to a virtual table object, an sqlite3_vtab structure. dbda8d6ce9 2007-07-21 drh: ** P1 is a cursor number. This opcode opens a cursor to the virtual dbda8d6ce9 2007-07-21 drh: ** table and stores that cursor in P1. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VOpen: { /* no-push */ dbda8d6ce9 2007-07-21 drh: Cursor *pCur = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_vtab_cursor *pVtabCursor = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3); dbda8d6ce9 2007-07-21 drh: sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert(pVtab && pModule); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: rc = pModule->xOpen(pVtab, &pVtabCursor); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK==rc ){ dbda8d6ce9 2007-07-21 drh: /* Initialise sqlite3_vtab_cursor base class */ dbda8d6ce9 2007-07-21 drh: pVtabCursor->pVtab = pVtab; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialise vdbe cursor object */ dbda8d6ce9 2007-07-21 drh: pCur = allocateCursor(p, pOp->p1, -1); dbda8d6ce9 2007-07-21 drh: if( pCur ){ dbda8d6ce9 2007-07-21 drh: pCur->pVtabCursor = pVtabCursor; dbda8d6ce9 2007-07-21 drh: pCur->pModule = pVtabCursor->pVtab->pModule; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: pModule->xClose(pVtabCursor); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VFilter P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P1 is a cursor opened using VOpen. P2 is an address to jump to if dbda8d6ce9 2007-07-21 drh: ** the filtered result set is empty. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is either NULL or a string that was generated by the xBestIndex dbda8d6ce9 2007-07-21 drh: ** method of the module. The interpretation of the P3 string is left dbda8d6ce9 2007-07-21 drh: ** to the module implementation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This opcode invokes the xFilter method on the virtual table specified dbda8d6ce9 2007-07-21 drh: ** by P1. The integer query plan parameter to xFilter is the top of the dbda8d6ce9 2007-07-21 drh: ** stack. Next down on the stack is the argc parameter. Beneath the dbda8d6ce9 2007-07-21 drh: ** next of stack are argc additional parameters which are passed to dbda8d6ce9 2007-07-21 drh: ** xFilter as argv. The topmost parameter (i.e. 3rd element popped from dbda8d6ce9 2007-07-21 drh: ** the stack) becomes argv[argc-1] when passed to xFilter. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The integer query plan parameter, argc, and all argv stack values dbda8d6ce9 2007-07-21 drh: ** are popped from the stack before this instruction completes. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A jump is made to P2 if the result set after filtering would be dbda8d6ce9 2007-07-21 drh: ** empty. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VFilter: { /* no-push */ dbda8d6ce9 2007-07-21 drh: int nArg; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: Cursor *pCur = p->apCsr[pOp->p1]; dbda8d6ce9 2007-07-21 drh: assert( pCur->pVtabCursor ); dbda8d6ce9 2007-07-21 drh: pModule = pCur->pVtabCursor->pVtab->pModule; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Grab the index number and argc parameters off the top of the stack. */ dbda8d6ce9 2007-07-21 drh: assert( (&pTos[-1])>=p->aStack ); dbda8d6ce9 2007-07-21 drh: assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int ); dbda8d6ce9 2007-07-21 drh: nArg = pTos[-1].u.i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Invoke the xFilter method */ dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int res = 0; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Mem **apArg = p->apArg; dbda8d6ce9 2007-07-21 drh: for(i = 0; i<nArg; i++){ dbda8d6ce9 2007-07-21 drh: apArg[i] = &pTos[i+1-2-nArg]; dbda8d6ce9 2007-07-21 drh: storeTypeInfo(apArg[i], 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: p->inVtabMethod = 1; dbda8d6ce9 2007-07-21 drh: rc = pModule->xFilter(pCur->pVtabCursor, pTos->u.i, pOp->p3, nArg, apArg); dbda8d6ce9 2007-07-21 drh: p->inVtabMethod = 0; dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: res = pModule->xEof(pCur->pVtabCursor); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( res ){ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Pop the index number, argc value and parameters off the stack */ dbda8d6ce9 2007-07-21 drh: popStack(&pTos, 2+nArg); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VRowid P1 * * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push an integer onto the stack which is the rowid of dbda8d6ce9 2007-07-21 drh: ** the virtual-table that the P1 cursor is pointing to. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VRowid: { dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: Cursor *pCur = p->apCsr[pOp->p1]; dbda8d6ce9 2007-07-21 drh: assert( pCur->pVtabCursor ); dbda8d6ce9 2007-07-21 drh: pModule = pCur->pVtabCursor->pVtab->pModule; dbda8d6ce9 2007-07-21 drh: if( pModule->xRowid==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xRowid", 0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: sqlite_int64 iRow; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: rc = pModule->xRowid(pCur->pVtabCursor, &iRow); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = MEM_Int; dbda8d6ce9 2007-07-21 drh: pTos->u.i = iRow; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VColumn P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Push onto the stack the value of the P2-th column of dbda8d6ce9 2007-07-21 drh: ** the row of the virtual-table that the P1 cursor is pointing to. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VColumn: { dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: Cursor *pCur = p->apCsr[pOp->p1]; dbda8d6ce9 2007-07-21 drh: assert( pCur->pVtabCursor ); dbda8d6ce9 2007-07-21 drh: pModule = pCur->pVtabCursor->pVtab->pModule; dbda8d6ce9 2007-07-21 drh: if( pModule->xColumn==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xColumn", 0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: sqlite3_context sContext; dbda8d6ce9 2007-07-21 drh: memset(&sContext, 0, sizeof(sContext)); dbda8d6ce9 2007-07-21 drh: sContext.s.flags = MEM_Null; c287665ba8 2007-09-14 drh: sContext.s.db = db; dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Copy the result of the function to the top of the stack. We dbda8d6ce9 2007-07-21 drh: ** do this regardless of whether or not an error occured to ensure any dbda8d6ce9 2007-07-21 drh: ** dynamic allocation in sContext.s (a Mem struct) is released. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeEncoding(&sContext.s, encoding); dbda8d6ce9 2007-07-21 drh: pTos++; dbda8d6ce9 2007-07-21 drh: pTos->flags = 0; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemMove(pTos, &sContext.s); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ){ dbda8d6ce9 2007-07-21 drh: goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3VdbeMemTooBig(pTos) ){ dbda8d6ce9 2007-07-21 drh: goto too_big; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VNext P1 P2 * dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Advance virtual table P1 to the next row in its result set and dbda8d6ce9 2007-07-21 drh: ** jump to instruction P2. Or, if the virtual table has reached dbda8d6ce9 2007-07-21 drh: ** the end of its result set, then fall through to the next instruction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VNext: { /* no-push */ dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule; dbda8d6ce9 2007-07-21 drh: int res = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: Cursor *pCur = p->apCsr[pOp->p1]; dbda8d6ce9 2007-07-21 drh: assert( pCur->pVtabCursor ); dbda8d6ce9 2007-07-21 drh: pModule = pCur->pVtabCursor->pVtab->pModule; dbda8d6ce9 2007-07-21 drh: if( pModule->xNext==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xNext", 0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: /* Invoke the xNext() method of the module. There is no way for the dbda8d6ce9 2007-07-21 drh: ** underlying implementation to return an error if one occurs during dbda8d6ce9 2007-07-21 drh: ** xNext(). Instead, if an error occurs, true is returned (indicating that dbda8d6ce9 2007-07-21 drh: ** data is available) and the error code returned when xColumn or dbda8d6ce9 2007-07-21 drh: ** some other method is next invoked on the save virtual table cursor. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: p->inVtabMethod = 1; dbda8d6ce9 2007-07-21 drh: rc = pModule->xNext(pCur->pVtabCursor); dbda8d6ce9 2007-07-21 drh: p->inVtabMethod = 0; dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: res = pModule->xEof(pCur->pVtabCursor); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !res ){ dbda8d6ce9 2007-07-21 drh: /* If there is data, jump to P2 */ dbda8d6ce9 2007-07-21 drh: pc = pOp->p2 - 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VRename * * P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is a pointer to a virtual table object, an sqlite3_vtab structure. dbda8d6ce9 2007-07-21 drh: ** This opcode invokes the corresponding xRename method. The value dbda8d6ce9 2007-07-21 drh: ** on the top of the stack is popped and passed as the zName argument dbda8d6ce9 2007-07-21 drh: ** to the xRename method. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VRename: { /* no-push */ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3); dbda8d6ce9 2007-07-21 drh: assert( pVtab->pModule->xRename ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: Stringify(pTos, encoding); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: sqlite3VtabLock(pVtab); dbda8d6ce9 2007-07-21 drh: rc = pVtab->pModule->xRename(pVtab, pTos->z); dbda8d6ce9 2007-07-21 drh: sqlite3VtabUnlock(db, pVtab); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: popStack(&pTos, 1); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Opcode: VUpdate P1 P2 P3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P3 is a pointer to a virtual table object, an sqlite3_vtab structure. dbda8d6ce9 2007-07-21 drh: ** This opcode invokes the corresponding xUpdate method. P2 values dbda8d6ce9 2007-07-21 drh: ** are taken from the stack to pass to the xUpdate invocation. The dbda8d6ce9 2007-07-21 drh: ** value on the top of the stack corresponds to the p2th element dbda8d6ce9 2007-07-21 drh: ** of the argv array passed to xUpdate. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The xUpdate method will do a DELETE or an INSERT or both. dbda8d6ce9 2007-07-21 drh: ** The argv[0] element (which corresponds to the P2-th element down dbda8d6ce9 2007-07-21 drh: ** on the stack) is the rowid of a row to delete. If argv[0] is dbda8d6ce9 2007-07-21 drh: ** NULL then no deletion occurs. The argv[1] element is the rowid dbda8d6ce9 2007-07-21 drh: ** of the new row. This can be NULL to have the virtual table dbda8d6ce9 2007-07-21 drh: ** select the new rowid for itself. The higher elements in the dbda8d6ce9 2007-07-21 drh: ** stack are the values of columns in the new row. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If P2==1 then no insert is performed. argv[0] is the rowid of dbda8d6ce9 2007-07-21 drh: ** a row to delete. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** P1 is a boolean flag. If it is set to true and the xUpdate call dbda8d6ce9 2007-07-21 drh: ** is successful, then the value returned by sqlite3_last_insert_rowid() dbda8d6ce9 2007-07-21 drh: ** is set to the value of the rowid for the row just inserted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case OP_VUpdate: { /* no-push */ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3); dbda8d6ce9 2007-07-21 drh: sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule; dbda8d6ce9 2007-07-21 drh: int nArg = pOp->p2; dbda8d6ce9 2007-07-21 drh: assert( pOp->p3type==P3_VTAB ); dbda8d6ce9 2007-07-21 drh: if( pModule->xUpdate==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, "read-only table", 0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: sqlite_int64 rowid; dbda8d6ce9 2007-07-21 drh: Mem **apArg = p->apArg; dbda8d6ce9 2007-07-21 drh: Mem *pX = &pTos[1-nArg]; dbda8d6ce9 2007-07-21 drh: for(i = 0; i<nArg; i++, pX++){ dbda8d6ce9 2007-07-21 drh: storeTypeInfo(pX, 0); dbda8d6ce9 2007-07-21 drh: apArg[i] = pX; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: sqlite3VtabLock(pVtab); dbda8d6ce9 2007-07-21 drh: rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); dbda8d6ce9 2007-07-21 drh: sqlite3VtabUnlock(db, pVtab); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; dbda8d6ce9 2007-07-21 drh: if( pOp->p1 && rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); dbda8d6ce9 2007-07-21 drh: db->lastRowid = rowid; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: popStack(&pTos, nArg); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* An other opcode is illegal... dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: assert( 0 ); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /***************************************************************************** dbda8d6ce9 2007-07-21 drh: ** The cases of the switch statement above this line should all be indented dbda8d6ce9 2007-07-21 drh: ** by 6 spaces. But the left-most 6 spaces have been removed to improve the dbda8d6ce9 2007-07-21 drh: ** readability. From this point on down, the normal indentation rules are dbda8d6ce9 2007-07-21 drh: ** restored. dbda8d6ce9 2007-07-21 drh: *****************************************************************************/ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the stack limit was not exceeded */ dbda8d6ce9 2007-07-21 drh: assert( pTos<=pStackLimit ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef VDBE_PROFILE dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: long long elapse = hwtime() - start; dbda8d6ce9 2007-07-21 drh: pOp->cycles += elapse; dbda8d6ce9 2007-07-21 drh: pOp->cnt++; dbda8d6ce9 2007-07-21 drh: #if 0 dbda8d6ce9 2007-07-21 drh: fprintf(stdout, "%10lld ", elapse); dbda8d6ce9 2007-07-21 drh: sqlite3VdbePrintOp(stdout, origPc, &p->aOp[origPc]); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: /* Keep track of the size of the largest BLOB or STR that has appeared dbda8d6ce9 2007-07-21 drh: ** on the top of the VDBE stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTos>=p->aStack && (pTos->flags & (MEM_Blob|MEM_Str))!=0 dbda8d6ce9 2007-07-21 drh: && pTos->n>sqlite3_max_blobsize ){ dbda8d6ce9 2007-07-21 drh: sqlite3_max_blobsize = pTos->n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following code adds nothing to the actual functionality dbda8d6ce9 2007-07-21 drh: ** of the program. It is only here for testing and debugging. dbda8d6ce9 2007-07-21 drh: ** On the other hand, it does burn CPU cycles every time through dbda8d6ce9 2007-07-21 drh: ** the evaluator loop. So we can leave it out when NDEBUG is defined. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* Sanity checking on the top element of the stack. If the previous dbda8d6ce9 2007-07-21 drh: ** instruction was VNoChange, then the flags field of the top dbda8d6ce9 2007-07-21 drh: ** of the stack is set to 0. This is technically invalid for a memory dbda8d6ce9 2007-07-21 drh: ** cell, so avoid calling MemSanity() in this case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTos>=p->aStack && pTos->flags ){ c287665ba8 2007-09-14 drh: assert( pTos->db==db ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemSanity(pTos); dbda8d6ce9 2007-07-21 drh: assert( !sqlite3VdbeMemTooBig(pTos) ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pc>=-1 && pc<p->nOp ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: /* Code for tracing the vdbe stack. */ dbda8d6ce9 2007-07-21 drh: if( p->trace && pTos>=p->aStack ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: fprintf(p->trace, "Stack:"); dbda8d6ce9 2007-07-21 drh: for(i=0; i>-5 && &pTos[i]>=p->aStack; i--){ dbda8d6ce9 2007-07-21 drh: if( pTos[i].flags & MEM_Null ){ dbda8d6ce9 2007-07-21 drh: fprintf(p->trace, " NULL"); dbda8d6ce9 2007-07-21 drh: }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ dbda8d6ce9 2007-07-21 drh: fprintf(p->trace, " si:%lld", pTos[i].u.i); dbda8d6ce9 2007-07-21 drh: }else if( pTos[i].flags & MEM_Int ){ dbda8d6ce9 2007-07-21 drh: fprintf(p->trace, " i:%lld", pTos[i].u.i); dbda8d6ce9 2007-07-21 drh: }else if( pTos[i].flags & MEM_Real ){ dbda8d6ce9 2007-07-21 drh: fprintf(p->trace, " r:%g", pTos[i].r); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: char zBuf[200]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf); dbda8d6ce9 2007-07-21 drh: fprintf(p->trace, " "); dbda8d6ce9 2007-07-21 drh: fprintf(p->trace, "%s", zBuf); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=0 ) fprintf(p->trace," rc=%d",rc); dbda8d6ce9 2007-07-21 drh: fprintf(p->trace,"\n"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_DEBUG */ dbda8d6ce9 2007-07-21 drh: #endif /* NDEBUG */ dbda8d6ce9 2007-07-21 drh: } /* The end of the for(;;) loop the loops through opcodes */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we reach this point, it means that execution is finished. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: vdbe_halt: dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: p->rc = rc; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeHalt(p); dbda8d6ce9 2007-07-21 drh: p->pTos = pTos; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* This is the only way out of this procedure. We have to c287665ba8 2007-09-14 drh: ** release the mutexes on btrees that were acquired at the c287665ba8 2007-09-14 drh: ** top. */ c287665ba8 2007-09-14 drh: vdbe_return: c287665ba8 2007-09-14 drh: sqlite3BtreeMutexArrayLeave(&p->aMutex); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH dbda8d6ce9 2007-07-21 drh: ** is encountered. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: too_big: dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, "string or blob too big", (char*)0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_TOOBIG; dbda8d6ce9 2007-07-21 drh: goto vdbe_halt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump to here if a malloc() fails. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: no_mem: c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, "out of memory", (char*)0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto vdbe_halt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump to here for an SQLITE_MISUSE error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: abort_due_to_misuse: dbda8d6ce9 2007-07-21 drh: rc = SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: /* Fall thru into abort_due_to_error */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump to here for any other kind of fatal error. The "rc" variable dbda8d6ce9 2007-07-21 drh: ** should hold the error number. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: abort_due_to_error: dbda8d6ce9 2007-07-21 drh: if( p->zErrMsg==0 ){ c287665ba8 2007-09-14 drh: if( db->mallocFailed ) rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto vdbe_halt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump to here if the sqlite3_interrupt() API sets the interrupt dbda8d6ce9 2007-07-21 drh: ** flag. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: abort_due_to_interrupt: dbda8d6ce9 2007-07-21 drh: assert( db->u1.isInterrupted ); dbda8d6ce9 2007-07-21 drh: if( db->magic!=SQLITE_MAGIC_BUSY ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_INTERRUPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->rc = rc; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0); dbda8d6ce9 2007-07-21 drh: goto vdbe_halt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vdbe.c ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vdbeblob.c ****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2007 May 1 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains code used to implement incremental BLOB I/O. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: vdbeblob.c,v 1.16 2007/08/30 01:19:59 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INCRBLOB dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Valid sqlite3_blob* handles point to Incrblob structures. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct Incrblob Incrblob; dbda8d6ce9 2007-07-21 drh: struct Incrblob { dbda8d6ce9 2007-07-21 drh: int flags; /* Copy of "flags" passed to sqlite3_blob_open() */ dbda8d6ce9 2007-07-21 drh: int nByte; /* Size of open blob, in bytes */ dbda8d6ce9 2007-07-21 drh: int iOffset; /* Byte offset of blob in cursor data */ dbda8d6ce9 2007-07-21 drh: BtCursor *pCsr; /* Cursor pointing at blob row */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pStmt; /* Statement holding cursor open */ c287665ba8 2007-09-14 drh: sqlite3 *db; /* The associated database */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Open a blob handle. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_open( dbda8d6ce9 2007-07-21 drh: sqlite3* db, /* The database connection */ dbda8d6ce9 2007-07-21 drh: const char *zDb, /* The attached database containing the blob */ dbda8d6ce9 2007-07-21 drh: const char *zTable, /* The table containing the blob */ dbda8d6ce9 2007-07-21 drh: const char *zColumn, /* The column containing the blob */ dbda8d6ce9 2007-07-21 drh: sqlite_int64 iRow, /* The row containing the glob */ dbda8d6ce9 2007-07-21 drh: int flags, /* True -> read/write access, false -> read-only */ dbda8d6ce9 2007-07-21 drh: sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int nAttempt = 0; dbda8d6ce9 2007-07-21 drh: int iCol; /* Index of zColumn in row-record */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This VDBE program seeks a btree cursor to the identified dbda8d6ce9 2007-07-21 drh: ** db/table/row entry. The reason for using a vdbe program instead dbda8d6ce9 2007-07-21 drh: ** of writing code to use the b-tree layer directly is that the dbda8d6ce9 2007-07-21 drh: ** vdbe program will take advantage of the various transaction, dbda8d6ce9 2007-07-21 drh: ** locking and error handling infrastructure built into the vdbe. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After seeking the cursor, the vdbe executes an OP_Callback. dbda8d6ce9 2007-07-21 drh: ** Code external to the Vdbe then "borrows" the b-tree cursor and dbda8d6ce9 2007-07-21 drh: ** uses it to implement the blob_read(), blob_write() and dbda8d6ce9 2007-07-21 drh: ** blob_bytes() functions. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The sqlite3_blob_close() function finalizes the vdbe program, dbda8d6ce9 2007-07-21 drh: ** which closes the b-tree cursor and (possibly) commits the dbda8d6ce9 2007-07-21 drh: ** transaction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const VdbeOpList openBlob[] = { dbda8d6ce9 2007-07-21 drh: {OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */ dbda8d6ce9 2007-07-21 drh: {OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */ dbda8d6ce9 2007-07-21 drh: {OP_Integer, 0, 0, 0}, /* 2: Database number */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* One of the following two instructions is replaced by an dbda8d6ce9 2007-07-21 drh: ** OP_Noop before exection. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: {OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */ dbda8d6ce9 2007-07-21 drh: {OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */ dbda8d6ce9 2007-07-21 drh: {OP_SetNumColumns, 0, 0, 0}, /* 5: Num cols for cursor */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: {OP_Variable, 1, 0, 0}, /* 6: Push the rowid to the stack */ dbda8d6ce9 2007-07-21 drh: {OP_NotExists, 0, 10, 0}, /* 7: Seek the cursor */ dbda8d6ce9 2007-07-21 drh: {OP_Column, 0, 0, 0}, /* 8 */ dbda8d6ce9 2007-07-21 drh: {OP_Callback, 0, 0, 0}, /* 9 */ dbda8d6ce9 2007-07-21 drh: {OP_Close, 0, 0, 0}, /* 10 */ dbda8d6ce9 2007-07-21 drh: {OP_Halt, 0, 0, 0}, /* 11 */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: Vdbe *v = 0; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: char zErr[128]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zErr[0] = 0; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: Parse sParse; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memset(&sParse, 0, sizeof(Parse)); dbda8d6ce9 2007-07-21 drh: sParse.db = db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeEnterAll(db); dbda8d6ce9 2007-07-21 drh: pTab = sqlite3LocateTable(&sParse, zTable, zDb); dbda8d6ce9 2007-07-21 drh: if( !pTab ){ dbda8d6ce9 2007-07-21 drh: if( sParse.zErrMsg ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(sParse.zErrMsg); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); c287665ba8 2007-09-14 drh: sqlite3BtreeLeaveAll(db); dbda8d6ce9 2007-07-21 drh: goto blob_open_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Now search pTab for the exact column. */ dbda8d6ce9 2007-07-21 drh: for(iCol=0; iCol < pTab->nCol; iCol++) { dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iCol==pTab->nCol ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, "no such column: \"%s\"", zColumn); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); c287665ba8 2007-09-14 drh: sqlite3BtreeLeaveAll(db); dbda8d6ce9 2007-07-21 drh: goto blob_open_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the value is being opened for writing, check that the dbda8d6ce9 2007-07-21 drh: ** column is not indexed. It is against the rules to open an dbda8d6ce9 2007-07-21 drh: ** indexed column for writing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( flags ){ dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: for(j=0; j<pIdx->nColumn; j++){ dbda8d6ce9 2007-07-21 drh: if( pIdx->aiColumn[j]==iCol ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, dbda8d6ce9 2007-07-21 drh: "cannot open indexed column for writing"); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); c287665ba8 2007-09-14 drh: sqlite3BtreeLeaveAll(db); dbda8d6ce9 2007-07-21 drh: goto blob_open_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3VdbeCreate(db); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Configure the OP_Transaction */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, 0, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, 0, (flags ? 1 : 0)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Configure the OP_VerifyCookie */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, 1, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: /* Make sure a mutex is held on the table to be accessed */ c287665ba8 2007-09-14 drh: sqlite3VdbeUsesBtree(v, iDb); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* Configure the db number pushed onto the stack */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, 2, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Remove either the OP_OpenWrite or OpenRead. Set the P2 dbda8d6ce9 2007-07-21 drh: ** parameter of the other to pTab->tnum. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeToNoop(v, (flags ? 3 : 4), 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, (flags ? 4 : 3), pTab->tnum); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Configure the OP_SetNumColumns. Configure the cursor to dbda8d6ce9 2007-07-21 drh: ** think that the table has one more column than it really dbda8d6ce9 2007-07-21 drh: ** does. An OP_Column to retrieve this imaginary column will dbda8d6ce9 2007-07-21 drh: ** always return an SQL NULL. This is useful because it means dbda8d6ce9 2007-07-21 drh: ** we can invoke OP_Column to fill in the vdbe cursors type dbda8d6ce9 2007-07-21 drh: ** and offset cache without causing any IO. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, 5, pTab->nCol+1); c287665ba8 2007-09-14 drh: if( !db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMakeReady(v, 1, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3BtreeLeaveAll(db); dbda8d6ce9 2007-07-21 drh: rc = sqlite3SafetyOff(db); c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto blob_open_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow); dbda8d6ce9 2007-07-21 drh: rc = sqlite3_step((sqlite3_stmt *)v); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_ROW ){ dbda8d6ce9 2007-07-21 drh: nAttempt++; dbda8d6ce9 2007-07-21 drh: rc = sqlite3_finalize((sqlite3_stmt *)v); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, sqlite3_errmsg(db)); dbda8d6ce9 2007-07-21 drh: v = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } while( nAttempt<5 && rc==SQLITE_SCHEMA ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_ROW ){ dbda8d6ce9 2007-07-21 drh: /* The row-record has been opened successfully. Check that the dbda8d6ce9 2007-07-21 drh: ** column in question contains text or a blob. If it contains dbda8d6ce9 2007-07-21 drh: ** text, it is up to the caller to get the encoding right. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: Incrblob *pBlob; dbda8d6ce9 2007-07-21 drh: u32 type = v->apCsr[0]->aType[iCol]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( type<12 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, "cannot open value of type %s", dbda8d6ce9 2007-07-21 drh: type==0?"null": type==7?"real": "integer" dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: goto blob_open_out; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ c287665ba8 2007-09-14 drh: sqlite3_free(pBlob); dbda8d6ce9 2007-07-21 drh: goto blob_open_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pBlob->flags = flags; dbda8d6ce9 2007-07-21 drh: pBlob->pCsr = v->apCsr[0]->pCursor; c287665ba8 2007-09-14 drh: sqlite3BtreeEnterCursor(pBlob->pCsr); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCacheOverflow(pBlob->pCsr); c287665ba8 2007-09-14 drh: sqlite3BtreeLeaveCursor(pBlob->pCsr); dbda8d6ce9 2007-07-21 drh: pBlob->pStmt = (sqlite3_stmt *)v; dbda8d6ce9 2007-07-21 drh: pBlob->iOffset = v->apCsr[0]->aOffset[iCol]; dbda8d6ce9 2007-07-21 drh: pBlob->nByte = sqlite3VdbeSerialTypeLen(type); c287665ba8 2007-09-14 drh: pBlob->db = db; dbda8d6ce9 2007-07-21 drh: *ppBlob = (sqlite3_blob *)pBlob; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: }else if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: blob_open_out: dbda8d6ce9 2007-07-21 drh: zErr[sizeof(zErr)-1] = '\0'; c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: sqlite3_finalize((sqlite3_stmt *)v); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr)); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close a blob handle that was previously created using dbda8d6ce9 2007-07-21 drh: ** sqlite3_blob_open(). dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){ dbda8d6ce9 2007-07-21 drh: Incrblob *p = (Incrblob *)pBlob; c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = sqlite3_finalize(p->pStmt); c287665ba8 2007-09-14 drh: sqlite3_free(p); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Perform a read or write operation on a blob c287665ba8 2007-09-14 drh: */ dbda8d6ce9 2007-07-21 drh: static int blobReadWrite( dbda8d6ce9 2007-07-21 drh: sqlite3_blob *pBlob, dbda8d6ce9 2007-07-21 drh: void *z, dbda8d6ce9 2007-07-21 drh: int n, dbda8d6ce9 2007-07-21 drh: int iOffset, dbda8d6ce9 2007-07-21 drh: int (*xCall)(BtCursor*, u32, u32, void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Incrblob *p = (Incrblob *)pBlob; c287665ba8 2007-09-14 drh: Vdbe *v; c287665ba8 2007-09-14 drh: sqlite3 *db = p->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Request is out of range. Return a transient error. */ dbda8d6ce9 2007-07-21 drh: if( (iOffset+n)>p->nByte ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* If there is no statement handle, then the blob-handle has c287665ba8 2007-09-14 drh: ** already been invalidated. Return SQLITE_ABORT in this case. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: v = (Vdbe*)p->pStmt; c287665ba8 2007-09-14 drh: if( v==0 ){ c287665ba8 2007-09-14 drh: rc = SQLITE_ABORT; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is c287665ba8 2007-09-14 drh: ** returned, clean-up the statement handle. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert( db == v->db ); c287665ba8 2007-09-14 drh: sqlite3BtreeEnterCursor(p->pCsr); c287665ba8 2007-09-14 drh: rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); c287665ba8 2007-09-14 drh: sqlite3BtreeLeaveCursor(p->pCsr); c287665ba8 2007-09-14 drh: if( rc==SQLITE_ABORT ){ c287665ba8 2007-09-14 drh: sqlite3VdbeFinalize(v); c287665ba8 2007-09-14 drh: p->pStmt = 0; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: db->errCode = rc; c287665ba8 2007-09-14 drh: v->rc = rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Read data from a blob handle. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){ dbda8d6ce9 2007-07-21 drh: return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write data to a blob handle. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){ dbda8d6ce9 2007-07-21 drh: return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Query a blob handle for the size of the data. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The Incrblob.nByte field is fixed for the lifetime of the Incrblob c287665ba8 2007-09-14 drh: ** so no mutex is required for access. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){ dbda8d6ce9 2007-07-21 drh: Incrblob *p = (Incrblob *)pBlob; dbda8d6ce9 2007-07-21 drh: return p->nByte; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vdbeblob.c ********************************************/ c287665ba8 2007-09-14 drh: /************** Begin file journal.c *****************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2007 August 22 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: journal.c,v 1.7 2007/09/06 13:49:37 drh Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_ATOMIC_WRITE c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This file implements a special kind of sqlite3_file object used c287665ba8 2007-09-14 drh: ** by SQLite to create journal files if the atomic-write optimization c287665ba8 2007-09-14 drh: ** is enabled. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The distinctive characteristic of this sqlite3_file is that the c287665ba8 2007-09-14 drh: ** actual on disk file is created lazily. When the file is created, c287665ba8 2007-09-14 drh: ** the caller specifies a buffer size for an in-memory buffer to c287665ba8 2007-09-14 drh: ** be used to service read() and write() requests. The actual file c287665ba8 2007-09-14 drh: ** on disk is not created or populated until either: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** 1) The in-memory representation grows too large for the allocated c287665ba8 2007-09-14 drh: ** buffer, or c287665ba8 2007-09-14 drh: ** 2) The xSync() method is called. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** A JournalFile object is a subclass of sqlite3_file used by c287665ba8 2007-09-14 drh: ** as an open file handle for journal files. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: struct JournalFile { c287665ba8 2007-09-14 drh: sqlite3_io_methods *pMethod; /* I/O methods on journal files */ c287665ba8 2007-09-14 drh: int nBuf; /* Size of zBuf[] in bytes */ c287665ba8 2007-09-14 drh: char *zBuf; /* Space to buffer journal writes */ c287665ba8 2007-09-14 drh: int iSize; /* Amount of zBuf[] currently used */ c287665ba8 2007-09-14 drh: int flags; /* xOpen flags */ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs; /* The "real" underlying VFS */ c287665ba8 2007-09-14 drh: sqlite3_file *pReal; /* The "real" underlying file descriptor */ c287665ba8 2007-09-14 drh: const char *zJournal; /* Name of the journal file */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: typedef struct JournalFile JournalFile; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** If it does not already exists, create and populate the on-disk file c287665ba8 2007-09-14 drh: ** for JournalFile p. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int createFile(JournalFile *p){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: if( !p->pReal ){ c287665ba8 2007-09-14 drh: sqlite3_file *pReal = (sqlite3_file *)&p[1]; c287665ba8 2007-09-14 drh: rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: p->pReal = pReal; c287665ba8 2007-09-14 drh: if( p->iSize>0 ){ c287665ba8 2007-09-14 drh: assert(p->iSize<=p->nBuf); c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Close the file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int jrnlClose(sqlite3_file *pJfd){ c287665ba8 2007-09-14 drh: JournalFile *p = (JournalFile *)pJfd; c287665ba8 2007-09-14 drh: if( p->pReal ){ c287665ba8 2007-09-14 drh: sqlite3OsClose(p->pReal); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(p->zBuf); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Read data from the file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int jrnlRead( c287665ba8 2007-09-14 drh: sqlite3_file *pJfd, /* The journal file from which to read */ c287665ba8 2007-09-14 drh: void *zBuf, /* Put the results here */ c287665ba8 2007-09-14 drh: int iAmt, /* Number of bytes to read */ c287665ba8 2007-09-14 drh: sqlite_int64 iOfst /* Begin reading at this offset */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: JournalFile *p = (JournalFile *)pJfd; c287665ba8 2007-09-14 drh: if( p->pReal ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: assert( iAmt+iOfst<=p->iSize ); c287665ba8 2007-09-14 drh: memcpy(zBuf, &p->zBuf[iOfst], iAmt); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Write data to the file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int jrnlWrite( c287665ba8 2007-09-14 drh: sqlite3_file *pJfd, /* The journal file into which to write */ c287665ba8 2007-09-14 drh: const void *zBuf, /* Take data to be written from here */ c287665ba8 2007-09-14 drh: int iAmt, /* Number of bytes to write */ c287665ba8 2007-09-14 drh: sqlite_int64 iOfst /* Begin writing at this offset into the file */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: JournalFile *p = (JournalFile *)pJfd; c287665ba8 2007-09-14 drh: if( !p->pReal && (iOfst+iAmt)>p->nBuf ){ c287665ba8 2007-09-14 drh: rc = createFile(p); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: if( p->pReal ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: memcpy(&p->zBuf[iOfst], zBuf, iAmt); c287665ba8 2007-09-14 drh: if( p->iSize<(iOfst+iAmt) ){ c287665ba8 2007-09-14 drh: p->iSize = (iOfst+iAmt); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Truncate the file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: JournalFile *p = (JournalFile *)pJfd; c287665ba8 2007-09-14 drh: if( p->pReal ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsTruncate(p->pReal, size); c287665ba8 2007-09-14 drh: }else if( size<p->iSize ){ c287665ba8 2007-09-14 drh: p->iSize = size; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Sync the file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int jrnlSync(sqlite3_file *pJfd, int flags){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: JournalFile *p = (JournalFile *)pJfd; c287665ba8 2007-09-14 drh: rc = createFile(p); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsSync(p->pReal, flags); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Query the size of the file in bytes. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){ c287665ba8 2007-09-14 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: JournalFile *p = (JournalFile *)pJfd; c287665ba8 2007-09-14 drh: if( p->pReal ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsFileSize(p->pReal, pSize); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: *pSize = (sqlite_int64) p->iSize; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Table of methods for JournalFile sqlite3_file object. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static struct sqlite3_io_methods JournalFileMethods = { c287665ba8 2007-09-14 drh: 1, /* iVersion */ c287665ba8 2007-09-14 drh: jrnlClose, /* xClose */ c287665ba8 2007-09-14 drh: jrnlRead, /* xRead */ c287665ba8 2007-09-14 drh: jrnlWrite, /* xWrite */ c287665ba8 2007-09-14 drh: jrnlTruncate, /* xTruncate */ c287665ba8 2007-09-14 drh: jrnlSync, /* xSync */ c287665ba8 2007-09-14 drh: jrnlFileSize, /* xFileSize */ c287665ba8 2007-09-14 drh: 0, /* xLock */ c287665ba8 2007-09-14 drh: 0, /* xUnlock */ c287665ba8 2007-09-14 drh: 0, /* xCheckReservedLock */ c287665ba8 2007-09-14 drh: 0, /* xFileControl */ c287665ba8 2007-09-14 drh: 0, /* xSectorSize */ c287665ba8 2007-09-14 drh: 0 /* xDeviceCharacteristics */ c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Open a journal file. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3JournalOpen( c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */ c287665ba8 2007-09-14 drh: const char *zName, /* Name of the journal file */ c287665ba8 2007-09-14 drh: sqlite3_file *pJfd, /* Preallocated, blank file handle */ c287665ba8 2007-09-14 drh: int flags, /* Opening flags */ c287665ba8 2007-09-14 drh: int nBuf /* Bytes buffered before opening the file */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: JournalFile *p = (JournalFile *)pJfd; c287665ba8 2007-09-14 drh: memset(p, 0, sqlite3JournalSize(pVfs)); c287665ba8 2007-09-14 drh: if( nBuf>0 ){ c287665ba8 2007-09-14 drh: p->zBuf = sqlite3MallocZero(nBuf); c287665ba8 2007-09-14 drh: if( !p->zBuf ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p->pMethod = &JournalFileMethods; c287665ba8 2007-09-14 drh: p->nBuf = nBuf; c287665ba8 2007-09-14 drh: p->flags = flags; c287665ba8 2007-09-14 drh: p->zJournal = zName; c287665ba8 2007-09-14 drh: p->pVfs = pVfs; c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** If the argument p points to a JournalFile structure, and the underlying c287665ba8 2007-09-14 drh: ** file has not yet been created, create it now. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){ c287665ba8 2007-09-14 drh: if( p->pMethods!=&JournalFileMethods ){ c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return createFile((JournalFile *)p); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return the number of bytes required to store a JournalFile that uses vfs c287665ba8 2007-09-14 drh: ** pVfs to create the underlying on-disk files. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ c287665ba8 2007-09-14 drh: return (pVfs->szOsFile+sizeof(JournalFile)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of journal.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file expr.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains routines used for analyzing expressions and dbda8d6ce9 2007-07-21 drh: ** for generating VDBE code that evaluates expressions in SQLite. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: expr.c,v 1.312 2007/09/01 18:24:55 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the 'affinity' of the expression pExpr if any. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If pExpr is a column, a reference to a column via an 'AS' alias, dbda8d6ce9 2007-07-21 drh: ** or a sub-select with a column as the return value, then the dbda8d6ce9 2007-07-21 drh: ** affinity of that column is returned. Otherwise, 0x00 is returned, dbda8d6ce9 2007-07-21 drh: ** indicating no affinity for the expression. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** i.e. the WHERE clause expresssions in the following statements all dbda8d6ce9 2007-07-21 drh: ** have an affinity: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE t1(a); dbda8d6ce9 2007-07-21 drh: ** SELECT * FROM t1 WHERE a; dbda8d6ce9 2007-07-21 drh: ** SELECT a AS b FROM t1 WHERE b; dbda8d6ce9 2007-07-21 drh: ** SELECT * FROM t1 WHERE (select a from t1); dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: int op = pExpr->op; dbda8d6ce9 2007-07-21 drh: if( op==TK_SELECT ){ dbda8d6ce9 2007-07-21 drh: return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CAST dbda8d6ce9 2007-07-21 drh: if( op==TK_CAST ){ dbda8d6ce9 2007-07-21 drh: return sqlite3AffinityType(&pExpr->token); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return pExpr->affinity; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the collating sequence for expression pExpr to be the collating dbda8d6ce9 2007-07-21 drh: ** sequence named by pToken. Return a pointer to the revised expression. dbda8d6ce9 2007-07-21 drh: ** The collating sequence is marked as "explicit" using the EP_ExpCollate dbda8d6ce9 2007-07-21 drh: ** flag. An explicit collating sequence will override implicit dbda8d6ce9 2007-07-21 drh: ** collating sequences. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) return 0; dbda8d6ce9 2007-07-21 drh: pColl = sqlite3LocateCollSeq(pParse, (char*)pName->z, pName->n); dbda8d6ce9 2007-07-21 drh: if( pColl ){ dbda8d6ce9 2007-07-21 drh: pExpr->pColl = pColl; dbda8d6ce9 2007-07-21 drh: pExpr->flags |= EP_ExpCollate; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pExpr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the default collation sequence for the expression pExpr. If dbda8d6ce9 2007-07-21 drh: ** there is no default collation type, return 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = 0; dbda8d6ce9 2007-07-21 drh: if( pExpr ){ dbda8d6ce9 2007-07-21 drh: int op; dbda8d6ce9 2007-07-21 drh: pColl = pExpr->pColl; dbda8d6ce9 2007-07-21 drh: op = pExpr->op; dbda8d6ce9 2007-07-21 drh: if( (op==TK_CAST || op==TK_UPLUS) && !pColl ){ dbda8d6ce9 2007-07-21 drh: return sqlite3ExprCollSeq(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3CheckCollSeq(pParse, pColl) ){ dbda8d6ce9 2007-07-21 drh: pColl = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pExpr is an operand of a comparison operator. aff2 is the dbda8d6ce9 2007-07-21 drh: ** type affinity of the other operand. This routine returns the dbda8d6ce9 2007-07-21 drh: ** type affinity that should be used for the comparison operator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){ dbda8d6ce9 2007-07-21 drh: char aff1 = sqlite3ExprAffinity(pExpr); dbda8d6ce9 2007-07-21 drh: if( aff1 && aff2 ){ dbda8d6ce9 2007-07-21 drh: /* Both sides of the comparison are columns. If one has numeric dbda8d6ce9 2007-07-21 drh: ** affinity, use that. Otherwise use no affinity. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_AFF_NUMERIC; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return SQLITE_AFF_NONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( !aff1 && !aff2 ){ dbda8d6ce9 2007-07-21 drh: /* Neither side of the comparison is a column. Compare the dbda8d6ce9 2007-07-21 drh: ** results directly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: return SQLITE_AFF_NONE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* One side is a column, the other is not. Use the columns affinity. */ dbda8d6ce9 2007-07-21 drh: assert( aff1==0 || aff2==0 ); dbda8d6ce9 2007-07-21 drh: return (aff1 + aff2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pExpr is a comparison operator. Return the type affinity that should dbda8d6ce9 2007-07-21 drh: ** be applied to both operands prior to doing the comparison. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char comparisonAffinity(Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: char aff; dbda8d6ce9 2007-07-21 drh: assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT || dbda8d6ce9 2007-07-21 drh: pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE || dbda8d6ce9 2007-07-21 drh: pExpr->op==TK_NE ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->pLeft ); dbda8d6ce9 2007-07-21 drh: aff = sqlite3ExprAffinity(pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: if( pExpr->pRight ){ dbda8d6ce9 2007-07-21 drh: aff = sqlite3CompareAffinity(pExpr->pRight, aff); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: else if( pExpr->pSelect ){ dbda8d6ce9 2007-07-21 drh: aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: else if( !aff ){ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_NONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return aff; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pExpr is a comparison expression, eg. '=', '<', IN(...) etc. dbda8d6ce9 2007-07-21 drh: ** idx_affinity is the affinity of an indexed column. Return true dbda8d6ce9 2007-07-21 drh: ** if the index with affinity idx_affinity may be used to implement dbda8d6ce9 2007-07-21 drh: ** the comparison in pExpr. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){ dbda8d6ce9 2007-07-21 drh: char aff = comparisonAffinity(pExpr); dbda8d6ce9 2007-07-21 drh: switch( aff ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_AFF_NONE: dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: case SQLITE_AFF_TEXT: dbda8d6ce9 2007-07-21 drh: return idx_affinity==SQLITE_AFF_TEXT; dbda8d6ce9 2007-07-21 drh: default: dbda8d6ce9 2007-07-21 drh: return sqlite3IsNumericAffinity(idx_affinity); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the P1 value that should be used for a binary comparison dbda8d6ce9 2007-07-21 drh: ** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2. dbda8d6ce9 2007-07-21 drh: ** If jumpIfNull is true, then set the low byte of the returned dbda8d6ce9 2007-07-21 drh: ** P1 value to tell the opcode to jump if either expression dbda8d6ce9 2007-07-21 drh: ** evaluates to NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){ dbda8d6ce9 2007-07-21 drh: char aff = sqlite3ExprAffinity(pExpr2); dbda8d6ce9 2007-07-21 drh: return ((int)sqlite3CompareAffinity(pExpr1, aff))+(jumpIfNull?0x100:0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a pointer to the collation sequence that should be used by dbda8d6ce9 2007-07-21 drh: ** a binary comparison operator comparing pLeft and pRight. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the left hand expression has a collating sequence type, then it is dbda8d6ce9 2007-07-21 drh: ** used. Otherwise the collation sequence for the right hand expression dbda8d6ce9 2007-07-21 drh: ** is used, or the default (BINARY) if neither expression has a collating dbda8d6ce9 2007-07-21 drh: ** type. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Argument pRight (but not pLeft) may be a null pointer. In this case, dbda8d6ce9 2007-07-21 drh: ** it is not considered. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq( dbda8d6ce9 2007-07-21 drh: Parse *pParse, dbda8d6ce9 2007-07-21 drh: Expr *pLeft, dbda8d6ce9 2007-07-21 drh: Expr *pRight dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: assert( pLeft ); dbda8d6ce9 2007-07-21 drh: if( pLeft->flags & EP_ExpCollate ){ dbda8d6ce9 2007-07-21 drh: assert( pLeft->pColl ); dbda8d6ce9 2007-07-21 drh: pColl = pLeft->pColl; dbda8d6ce9 2007-07-21 drh: }else if( pRight && pRight->flags & EP_ExpCollate ){ dbda8d6ce9 2007-07-21 drh: assert( pRight->pColl ); dbda8d6ce9 2007-07-21 drh: pColl = pRight->pColl; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pColl = sqlite3ExprCollSeq(pParse, pLeft); dbda8d6ce9 2007-07-21 drh: if( !pColl ){ dbda8d6ce9 2007-07-21 drh: pColl = sqlite3ExprCollSeq(pParse, pRight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for a comparison operator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int codeCompare( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing (and code generating) context */ dbda8d6ce9 2007-07-21 drh: Expr *pLeft, /* The left operand */ dbda8d6ce9 2007-07-21 drh: Expr *pRight, /* The right operand */ dbda8d6ce9 2007-07-21 drh: int opcode, /* The comparison opcode */ dbda8d6ce9 2007-07-21 drh: int dest, /* Jump here if true. */ dbda8d6ce9 2007-07-21 drh: int jumpIfNull /* If true, jump if either operand is NULL */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int p1 = binaryCompareP1(pLeft, pRight, jumpIfNull); dbda8d6ce9 2007-07-21 drh: CollSeq *p3 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight); dbda8d6ce9 2007-07-21 drh: return sqlite3VdbeOp3(pParse->pVdbe, opcode, p1, dest, (void*)p3, P3_COLLSEQ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Construct a new expression node and return a pointer to it. Memory c287665ba8 2007-09-14 drh: ** for this node is obtained from sqlite3_malloc(). The calling function dbda8d6ce9 2007-07-21 drh: ** is responsible for making sure the node eventually gets freed. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3Expr( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */ c287665ba8 2007-09-14 drh: int op, /* Expression opcode */ c287665ba8 2007-09-14 drh: Expr *pLeft, /* Left operand */ c287665ba8 2007-09-14 drh: Expr *pRight, /* Right operand */ c287665ba8 2007-09-14 drh: const Token *pToken /* Argument token */ c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: Expr *pNew; c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocZero(db, sizeof(Expr)); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: /* When malloc fails, delete pLeft and pRight. Expressions passed to dbda8d6ce9 2007-07-21 drh: ** this function must always be allocated with sqlite3Expr() for this dbda8d6ce9 2007-07-21 drh: ** reason. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pRight); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pNew->op = op; dbda8d6ce9 2007-07-21 drh: pNew->pLeft = pLeft; dbda8d6ce9 2007-07-21 drh: pNew->pRight = pRight; dbda8d6ce9 2007-07-21 drh: pNew->iAgg = -1; dbda8d6ce9 2007-07-21 drh: if( pToken ){ dbda8d6ce9 2007-07-21 drh: assert( pToken->dyn==0 ); dbda8d6ce9 2007-07-21 drh: pNew->span = pNew->token = *pToken; dbda8d6ce9 2007-07-21 drh: }else if( pLeft ){ dbda8d6ce9 2007-07-21 drh: if( pRight ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span); dbda8d6ce9 2007-07-21 drh: if( pRight->flags & EP_ExpCollate ){ dbda8d6ce9 2007-07-21 drh: pNew->flags |= EP_ExpCollate; dbda8d6ce9 2007-07-21 drh: pNew->pColl = pRight->pColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pLeft->flags & EP_ExpCollate ){ dbda8d6ce9 2007-07-21 drh: pNew->flags |= EP_ExpCollate; dbda8d6ce9 2007-07-21 drh: pNew->pColl = pLeft->pColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3ExprSetHeight(pNew); dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Works like sqlite3Expr() except that it takes an extra Parse* c287665ba8 2007-09-14 drh: ** argument and notifies the associated connection object if malloc fails. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3PExpr( c287665ba8 2007-09-14 drh: Parse *pParse, /* Parsing context */ c287665ba8 2007-09-14 drh: int op, /* Expression opcode */ c287665ba8 2007-09-14 drh: Expr *pLeft, /* Left operand */ c287665ba8 2007-09-14 drh: Expr *pRight, /* Right operand */ c287665ba8 2007-09-14 drh: const Token *pToken /* Argument token */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: return sqlite3Expr(pParse->db, op, pLeft, pRight, pToken); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** When doing a nested parse, you can include terms in an expression dbda8d6ce9 2007-07-21 drh: ** that look like this: #0 #1 #2 ... These terms refer to elements dbda8d6ce9 2007-07-21 drh: ** on the stack. "#0" means the top of the stack. dbda8d6ce9 2007-07-21 drh: ** "#1" means the next down on the stack. And so forth. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is called by the parser to deal with on of those terms. dbda8d6ce9 2007-07-21 drh: ** It immediately generates code to store the value in a memory location. dbda8d6ce9 2007-07-21 drh: ** The returns an expression that will code to extract the value from dbda8d6ce9 2007-07-21 drh: ** that memory location as needed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: Expr *p; dbda8d6ce9 2007-07-21 drh: int depth; dbda8d6ce9 2007-07-21 drh: if( pParse->nested==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken); c287665ba8 2007-09-14 drh: return sqlite3PExpr(pParse, TK_NULL, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( v==0 ) return 0; c287665ba8 2007-09-14 drh: p = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, pToken); dbda8d6ce9 2007-07-21 drh: if( p==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Malloc failed */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: depth = atoi((char*)&pToken->z[1]); dbda8d6ce9 2007-07-21 drh: p->iTable = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, depth, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1); dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Join two expressions using an AND operator. If either expression is dbda8d6ce9 2007-07-21 drh: ** NULL, then just return the other expression. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ dbda8d6ce9 2007-07-21 drh: if( pLeft==0 ){ dbda8d6ce9 2007-07-21 drh: return pRight; dbda8d6ce9 2007-07-21 drh: }else if( pRight==0 ){ dbda8d6ce9 2007-07-21 drh: return pLeft; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: return sqlite3Expr(db, TK_AND, pLeft, pRight, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the Expr.span field of the given expression to span all dbda8d6ce9 2007-07-21 drh: ** text between the two given tokens. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ dbda8d6ce9 2007-07-21 drh: assert( pRight!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pLeft!=0 ); c287665ba8 2007-09-14 drh: if( pExpr && pRight->z && pLeft->z ){ dbda8d6ce9 2007-07-21 drh: assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 ); dbda8d6ce9 2007-07-21 drh: if( pLeft->dyn==0 && pRight->dyn==0 ){ dbda8d6ce9 2007-07-21 drh: pExpr->span.z = pLeft->z; dbda8d6ce9 2007-07-21 drh: pExpr->span.n = pRight->n + (pRight->z - pLeft->z); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pExpr->span.z = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Construct a new expression node for a function with multiple dbda8d6ce9 2007-07-21 drh: ** arguments. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ dbda8d6ce9 2007-07-21 drh: Expr *pNew; dbda8d6ce9 2007-07-21 drh: assert( pToken ); c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocZero(pParse->db, sizeof(Expr) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pNew->op = TK_FUNCTION; dbda8d6ce9 2007-07-21 drh: pNew->pList = pList; dbda8d6ce9 2007-07-21 drh: assert( pToken->dyn==0 ); dbda8d6ce9 2007-07-21 drh: pNew->token = *pToken; dbda8d6ce9 2007-07-21 drh: pNew->span = pNew->token; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3ExprSetHeight(pNew); dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Assign a variable number to an expression that encodes a wildcard dbda8d6ce9 2007-07-21 drh: ** in the original SQL statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Wildcards consisting of a single "?" are assigned the next sequential dbda8d6ce9 2007-07-21 drh: ** variable number. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Wildcards of the form "?nnn" are assigned the number "nnn". We make dbda8d6ce9 2007-07-21 drh: ** sure "nnn" is not too be to avoid a denial of service attack when dbda8d6ce9 2007-07-21 drh: ** the SQL statement comes from an external source. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Wildcards of the form ":aaa" or "$aaa" are assigned the same number dbda8d6ce9 2007-07-21 drh: ** as the previous instance of the same wildcard. Or if this is the first dbda8d6ce9 2007-07-21 drh: ** instance of the wildcard, the next sequenial variable number is dbda8d6ce9 2007-07-21 drh: ** assigned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: Token *pToken; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) return; dbda8d6ce9 2007-07-21 drh: pToken = &pExpr->token; dbda8d6ce9 2007-07-21 drh: assert( pToken->n>=1 ); dbda8d6ce9 2007-07-21 drh: assert( pToken->z!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pToken->z[0]!=0 ); dbda8d6ce9 2007-07-21 drh: if( pToken->n==1 ){ dbda8d6ce9 2007-07-21 drh: /* Wildcard of the form "?". Assign the next variable number */ dbda8d6ce9 2007-07-21 drh: pExpr->iTable = ++pParse->nVar; dbda8d6ce9 2007-07-21 drh: }else if( pToken->z[0]=='?' ){ dbda8d6ce9 2007-07-21 drh: /* Wildcard of the form "?nnn". Convert "nnn" to an integer and dbda8d6ce9 2007-07-21 drh: ** use it as the variable number */ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: pExpr->iTable = i = atoi((char*)&pToken->z[1]); dbda8d6ce9 2007-07-21 drh: if( i<1 || i>SQLITE_MAX_VARIABLE_NUMBER ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", dbda8d6ce9 2007-07-21 drh: SQLITE_MAX_VARIABLE_NUMBER); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i>pParse->nVar ){ dbda8d6ce9 2007-07-21 drh: pParse->nVar = i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Wildcards of the form ":aaa" or "$aaa". Reuse the same variable dbda8d6ce9 2007-07-21 drh: ** number as the prior appearance of the same name, or if the name dbda8d6ce9 2007-07-21 drh: ** has never appeared before, reuse the same variable number dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int i, n; dbda8d6ce9 2007-07-21 drh: n = pToken->n; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pParse->nVarExpr; i++){ dbda8d6ce9 2007-07-21 drh: Expr *pE; dbda8d6ce9 2007-07-21 drh: if( (pE = pParse->apVarExpr[i])!=0 dbda8d6ce9 2007-07-21 drh: && pE->token.n==n dbda8d6ce9 2007-07-21 drh: && memcmp(pE->token.z, pToken->z, n)==0 ){ dbda8d6ce9 2007-07-21 drh: pExpr->iTable = pE->iTable; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i>=pParse->nVarExpr ){ dbda8d6ce9 2007-07-21 drh: pExpr->iTable = ++pParse->nVar; dbda8d6ce9 2007-07-21 drh: if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){ dbda8d6ce9 2007-07-21 drh: pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10; c287665ba8 2007-09-14 drh: pParse->apVarExpr = c287665ba8 2007-09-14 drh: sqlite3DbReallocOrFree( c287665ba8 2007-09-14 drh: db, c287665ba8 2007-09-14 drh: pParse->apVarExpr, c287665ba8 2007-09-14 drh: pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) c287665ba8 2007-09-14 drh: ); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( !db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: assert( pParse->apVarExpr!=0 ); dbda8d6ce9 2007-07-21 drh: pParse->apVarExpr[pParse->nVarExpr++] = pExpr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pParse->nErr && pParse->nVar>SQLITE_MAX_VARIABLE_NUMBER ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "too many SQL variables"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Recursively delete an expression tree. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprDelete(Expr *p){ dbda8d6ce9 2007-07-21 drh: if( p==0 ) return; c287665ba8 2007-09-14 drh: if( p->span.dyn ) sqlite3_free((char*)p->span.z); c287665ba8 2007-09-14 drh: if( p->token.dyn ) sqlite3_free((char*)p->token.z); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pRight); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(p->pList); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(p->pSelect); c287665ba8 2007-09-14 drh: sqlite3_free(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The Expr.token field might be a string literal that is quoted. dbda8d6ce9 2007-07-21 drh: ** If so, remove the quotation marks. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3DequoteExpr(sqlite3 *db, Expr *p){ dbda8d6ce9 2007-07-21 drh: if( ExprHasAnyProperty(p, EP_Dequoted) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: ExprSetProperty(p, EP_Dequoted); dbda8d6ce9 2007-07-21 drh: if( p->token.dyn==0 ){ c287665ba8 2007-09-14 drh: sqlite3TokenCopy(db, &p->token, &p->token); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3Dequote((char*)p->token.z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following group of routines make deep copies of expressions, dbda8d6ce9 2007-07-21 drh: ** expression lists, ID lists, and select statements. The copies can dbda8d6ce9 2007-07-21 drh: ** be deleted (by being passed to their respective ...Delete() routines) dbda8d6ce9 2007-07-21 drh: ** without effecting the originals. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The expression list, ID, and source lists return by sqlite3ExprListDup(), dbda8d6ce9 2007-07-21 drh: ** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded dbda8d6ce9 2007-07-21 drh: ** by subsequent calls to sqlite*ListAppend() routines. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Any tables that the SrcList might point to are not duplicated. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p){ dbda8d6ce9 2007-07-21 drh: Expr *pNew; dbda8d6ce9 2007-07-21 drh: if( p==0 ) return 0; c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocRaw(db, sizeof(*p) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ) return 0; dbda8d6ce9 2007-07-21 drh: memcpy(pNew, p, sizeof(*pNew)); dbda8d6ce9 2007-07-21 drh: if( p->token.z!=0 ){ c287665ba8 2007-09-14 drh: pNew->token.z = (u8*)sqlite3DbStrNDup(db, (char*)p->token.z, p->token.n); dbda8d6ce9 2007-07-21 drh: pNew->token.dyn = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pNew->token.z==0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pNew->span.z = 0; c287665ba8 2007-09-14 drh: pNew->pLeft = sqlite3ExprDup(db, p->pLeft); c287665ba8 2007-09-14 drh: pNew->pRight = sqlite3ExprDup(db, p->pRight); c287665ba8 2007-09-14 drh: pNew->pList = sqlite3ExprListDup(db, p->pList); c287665ba8 2007-09-14 drh: pNew->pSelect = sqlite3SelectDup(db, p->pSelect); dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){ c287665ba8 2007-09-14 drh: if( pTo->dyn ) sqlite3_free((char*)pTo->z); dbda8d6ce9 2007-07-21 drh: if( pFrom->z ){ dbda8d6ce9 2007-07-21 drh: pTo->n = pFrom->n; c287665ba8 2007-09-14 drh: pTo->z = (u8*)sqlite3DbStrNDup(db, (char*)pFrom->z, pFrom->n); dbda8d6ce9 2007-07-21 drh: pTo->dyn = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTo->z = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){ dbda8d6ce9 2007-07-21 drh: ExprList *pNew; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem, *pOldItem; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( p==0 ) return 0; c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ) return 0; c287665ba8 2007-09-14 drh: pNew->iECursor = 0; dbda8d6ce9 2007-07-21 drh: pNew->nExpr = pNew->nAlloc = p->nExpr; c287665ba8 2007-09-14 drh: pNew->a = pItem = sqlite3DbMallocRaw(db, p->nExpr*sizeof(p->a[0]) ); dbda8d6ce9 2007-07-21 drh: if( pItem==0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(pNew); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pOldItem = p->a; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){ dbda8d6ce9 2007-07-21 drh: Expr *pNewExpr, *pOldExpr; c287665ba8 2007-09-14 drh: pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr = pOldItem->pExpr); dbda8d6ce9 2007-07-21 drh: if( pOldExpr->span.z!=0 && pNewExpr ){ dbda8d6ce9 2007-07-21 drh: /* Always make a copy of the span for top-level expressions in the dbda8d6ce9 2007-07-21 drh: ** expression list. The logic in SELECT processing that determines dbda8d6ce9 2007-07-21 drh: ** the names of columns in the result set needs this information */ c287665ba8 2007-09-14 drh: sqlite3TokenCopy(db, &pNewExpr->span, &pOldExpr->span); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pNewExpr==0 || pNewExpr->span.z!=0 dbda8d6ce9 2007-07-21 drh: || pOldExpr->span.z==0 c287665ba8 2007-09-14 drh: || db->mallocFailed ); c287665ba8 2007-09-14 drh: pItem->zName = sqlite3DbStrDup(db, pOldItem->zName); dbda8d6ce9 2007-07-21 drh: pItem->sortOrder = pOldItem->sortOrder; dbda8d6ce9 2007-07-21 drh: pItem->isAgg = pOldItem->isAgg; dbda8d6ce9 2007-07-21 drh: pItem->done = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If cursors, triggers, views and subqueries are all omitted from dbda8d6ce9 2007-07-21 drh: ** the build, then none of the following routines, except for dbda8d6ce9 2007-07-21 drh: ** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes dbda8d6ce9 2007-07-21 drh: ** called with a NULL argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \ dbda8d6ce9 2007-07-21 drh: || !defined(SQLITE_OMIT_SUBQUERY) c287665ba8 2007-09-14 drh: SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){ dbda8d6ce9 2007-07-21 drh: SrcList *pNew; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nByte; dbda8d6ce9 2007-07-21 drh: if( p==0 ) return 0; dbda8d6ce9 2007-07-21 drh: nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocRaw(db, nByte ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ) return 0; dbda8d6ce9 2007-07-21 drh: pNew->nSrc = pNew->nAlloc = p->nSrc; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nSrc; i++){ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pNewItem = &pNew->a[i]; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pOldItem = &p->a[i]; dbda8d6ce9 2007-07-21 drh: Table *pTab; c287665ba8 2007-09-14 drh: pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); c287665ba8 2007-09-14 drh: pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); c287665ba8 2007-09-14 drh: pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); dbda8d6ce9 2007-07-21 drh: pNewItem->jointype = pOldItem->jointype; dbda8d6ce9 2007-07-21 drh: pNewItem->iCursor = pOldItem->iCursor; dbda8d6ce9 2007-07-21 drh: pNewItem->isPopulated = pOldItem->isPopulated; dbda8d6ce9 2007-07-21 drh: pTab = pNewItem->pTab = pOldItem->pTab; dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: pTab->nRef++; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect); c287665ba8 2007-09-14 drh: pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn); c287665ba8 2007-09-14 drh: pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing); dbda8d6ce9 2007-07-21 drh: pNewItem->colUsed = pOldItem->colUsed; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ dbda8d6ce9 2007-07-21 drh: IdList *pNew; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( p==0 ) return 0; c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ) return 0; dbda8d6ce9 2007-07-21 drh: pNew->nId = pNew->nAlloc = p->nId; c287665ba8 2007-09-14 drh: pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) ); dbda8d6ce9 2007-07-21 drh: if( pNew->a==0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(pNew); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nId; i++){ dbda8d6ce9 2007-07-21 drh: struct IdList_item *pNewItem = &pNew->a[i]; dbda8d6ce9 2007-07-21 drh: struct IdList_item *pOldItem = &p->a[i]; c287665ba8 2007-09-14 drh: pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); dbda8d6ce9 2007-07-21 drh: pNewItem->idx = pOldItem->idx; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p){ dbda8d6ce9 2007-07-21 drh: Select *pNew; dbda8d6ce9 2007-07-21 drh: if( p==0 ) return 0; c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocRaw(db, sizeof(*p) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ) return 0; dbda8d6ce9 2007-07-21 drh: pNew->isDistinct = p->isDistinct; c287665ba8 2007-09-14 drh: pNew->pEList = sqlite3ExprListDup(db, p->pEList); c287665ba8 2007-09-14 drh: pNew->pSrc = sqlite3SrcListDup(db, p->pSrc); c287665ba8 2007-09-14 drh: pNew->pWhere = sqlite3ExprDup(db, p->pWhere); c287665ba8 2007-09-14 drh: pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy); c287665ba8 2007-09-14 drh: pNew->pHaving = sqlite3ExprDup(db, p->pHaving); c287665ba8 2007-09-14 drh: pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy); dbda8d6ce9 2007-07-21 drh: pNew->op = p->op; c287665ba8 2007-09-14 drh: pNew->pPrior = sqlite3SelectDup(db, p->pPrior); c287665ba8 2007-09-14 drh: pNew->pLimit = sqlite3ExprDup(db, p->pLimit); c287665ba8 2007-09-14 drh: pNew->pOffset = sqlite3ExprDup(db, p->pOffset); dbda8d6ce9 2007-07-21 drh: pNew->iLimit = -1; dbda8d6ce9 2007-07-21 drh: pNew->iOffset = -1; dbda8d6ce9 2007-07-21 drh: pNew->isResolved = p->isResolved; dbda8d6ce9 2007-07-21 drh: pNew->isAgg = p->isAgg; dbda8d6ce9 2007-07-21 drh: pNew->usesEphm = 0; dbda8d6ce9 2007-07-21 drh: pNew->disallowOrderBy = 0; dbda8d6ce9 2007-07-21 drh: pNew->pRightmost = 0; dbda8d6ce9 2007-07-21 drh: pNew->addrOpenEphm[0] = -1; dbda8d6ce9 2007-07-21 drh: pNew->addrOpenEphm[1] = -1; dbda8d6ce9 2007-07-21 drh: pNew->addrOpenEphm[2] = -1; dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p){ dbda8d6ce9 2007-07-21 drh: assert( p==0 ); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a new element to the end of an expression list. If pList is dbda8d6ce9 2007-07-21 drh: ** initially NULL, then create a new expression list. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE ExprList *sqlite3ExprListAppend( c287665ba8 2007-09-14 drh: Parse *pParse, /* Parsing context */ c287665ba8 2007-09-14 drh: ExprList *pList, /* List to which to append. Might be NULL */ c287665ba8 2007-09-14 drh: Expr *pExpr, /* Expression to be appended */ c287665ba8 2007-09-14 drh: Token *pName /* AS keyword for the expression */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: if( pList==0 ){ c287665ba8 2007-09-14 drh: pList = sqlite3DbMallocZero(db, sizeof(ExprList) ); dbda8d6ce9 2007-07-21 drh: if( pList==0 ){ dbda8d6ce9 2007-07-21 drh: goto no_mem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pList->nAlloc==0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pList->nAlloc<=pList->nExpr ){ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *a; dbda8d6ce9 2007-07-21 drh: int n = pList->nAlloc*2 + 4; c287665ba8 2007-09-14 drh: a = sqlite3DbRealloc(db, pList->a, n*sizeof(pList->a[0])); dbda8d6ce9 2007-07-21 drh: if( a==0 ){ dbda8d6ce9 2007-07-21 drh: goto no_mem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pList->a = a; dbda8d6ce9 2007-07-21 drh: pList->nAlloc = n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pList->a!=0 ); dbda8d6ce9 2007-07-21 drh: if( pExpr || pName ){ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem = &pList->a[pList->nExpr++]; dbda8d6ce9 2007-07-21 drh: memset(pItem, 0, sizeof(*pItem)); c287665ba8 2007-09-14 drh: pItem->zName = sqlite3NameFromToken(db, pName); dbda8d6ce9 2007-07-21 drh: pItem->pExpr = pExpr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pList; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: no_mem: dbda8d6ce9 2007-07-21 drh: /* Avoid leaking memory if malloc has failed. */ dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pExpr); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pList); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the expression list pEList contains more than iLimit elements, dbda8d6ce9 2007-07-21 drh: ** leave an error message in pParse. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprListCheckLength( dbda8d6ce9 2007-07-21 drh: Parse *pParse, dbda8d6ce9 2007-07-21 drh: ExprList *pEList, dbda8d6ce9 2007-07-21 drh: int iLimit, dbda8d6ce9 2007-07-21 drh: const char *zObject dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( pEList && pEList->nExpr>iLimit ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "too many columns in %s", zObject); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 dbda8d6ce9 2007-07-21 drh: /* The following three functions, heightOfExpr(), heightOfExprList() dbda8d6ce9 2007-07-21 drh: ** and heightOfSelect(), are used to determine the maximum height dbda8d6ce9 2007-07-21 drh: ** of any expression tree referenced by the structure passed as the dbda8d6ce9 2007-07-21 drh: ** first argument. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If this maximum height is greater than the current value pointed dbda8d6ce9 2007-07-21 drh: ** to by pnHeight, the second parameter, then set *pnHeight to that dbda8d6ce9 2007-07-21 drh: ** value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void heightOfExpr(Expr *p, int *pnHeight){ dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: if( p->nHeight>*pnHeight ){ dbda8d6ce9 2007-07-21 drh: *pnHeight = p->nHeight; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void heightOfExprList(ExprList *p, int *pnHeight){ dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: heightOfExpr(p->a[i].pExpr, pnHeight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void heightOfSelect(Select *p, int *pnHeight){ dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: heightOfExpr(p->pWhere, pnHeight); dbda8d6ce9 2007-07-21 drh: heightOfExpr(p->pHaving, pnHeight); dbda8d6ce9 2007-07-21 drh: heightOfExpr(p->pLimit, pnHeight); dbda8d6ce9 2007-07-21 drh: heightOfExpr(p->pOffset, pnHeight); dbda8d6ce9 2007-07-21 drh: heightOfExprList(p->pEList, pnHeight); dbda8d6ce9 2007-07-21 drh: heightOfExprList(p->pGroupBy, pnHeight); dbda8d6ce9 2007-07-21 drh: heightOfExprList(p->pOrderBy, pnHeight); dbda8d6ce9 2007-07-21 drh: heightOfSelect(p->pPrior, pnHeight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the Expr.nHeight variable in the structure passed as an dbda8d6ce9 2007-07-21 drh: ** argument. An expression with no children, Expr.pList or dbda8d6ce9 2007-07-21 drh: ** Expr.pSelect member has a height of 1. Any other expression dbda8d6ce9 2007-07-21 drh: ** has a height equal to the maximum height of any other dbda8d6ce9 2007-07-21 drh: ** referenced Expr plus one. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprSetHeight(Expr *p){ dbda8d6ce9 2007-07-21 drh: int nHeight = 0; dbda8d6ce9 2007-07-21 drh: heightOfExpr(p->pLeft, &nHeight); dbda8d6ce9 2007-07-21 drh: heightOfExpr(p->pRight, &nHeight); dbda8d6ce9 2007-07-21 drh: heightOfExprList(p->pList, &nHeight); dbda8d6ce9 2007-07-21 drh: heightOfSelect(p->pSelect, &nHeight); dbda8d6ce9 2007-07-21 drh: p->nHeight = nHeight + 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the maximum height of any expression tree referenced dbda8d6ce9 2007-07-21 drh: ** by the select statement passed as an argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){ dbda8d6ce9 2007-07-21 drh: int nHeight = 0; dbda8d6ce9 2007-07-21 drh: heightOfSelect(p, &nHeight); dbda8d6ce9 2007-07-21 drh: return nHeight; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete an entire expression list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprListDelete(ExprList *pList){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return; dbda8d6ce9 2007-07-21 drh: assert( pList->a!=0 || (pList->nExpr==0 && pList->nAlloc==0) ); dbda8d6ce9 2007-07-21 drh: assert( pList->nExpr<=pList->nAlloc ); dbda8d6ce9 2007-07-21 drh: for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pItem->pExpr); c287665ba8 2007-09-14 drh: sqlite3_free(pItem->zName); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pList->a); c287665ba8 2007-09-14 drh: sqlite3_free(pList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Walk an expression tree. Call xFunc for each node visited. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The return value from xFunc determines whether the tree walk continues. dbda8d6ce9 2007-07-21 drh: ** 0 means continue walking the tree. 1 means do not walk children dbda8d6ce9 2007-07-21 drh: ** of the current node but continue with siblings. 2 means abandon dbda8d6ce9 2007-07-21 drh: ** the tree walk completely. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The return value from this routine is 1 to abandon the tree walk dbda8d6ce9 2007-07-21 drh: ** and 0 to continue. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** NOTICE: This routine does *not* descend into subqueries. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int walkExprList(ExprList *, int (*)(void *, Expr*), void *); dbda8d6ce9 2007-07-21 drh: static int walkExprTree(Expr *pExpr, int (*xFunc)(void*,Expr*), void *pArg){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) return 0; dbda8d6ce9 2007-07-21 drh: rc = (*xFunc)(pArg, pExpr); dbda8d6ce9 2007-07-21 drh: if( rc==0 ){ dbda8d6ce9 2007-07-21 drh: if( walkExprTree(pExpr->pLeft, xFunc, pArg) ) return 1; dbda8d6ce9 2007-07-21 drh: if( walkExprTree(pExpr->pRight, xFunc, pArg) ) return 1; dbda8d6ce9 2007-07-21 drh: if( walkExprList(pExpr->pList, xFunc, pArg) ) return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc>1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Call walkExprTree() for every expression in list p. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int walkExprList(ExprList *p, int (*xFunc)(void *, Expr*), void *pArg){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: if( !p ) return 0; dbda8d6ce9 2007-07-21 drh: for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){ dbda8d6ce9 2007-07-21 drh: if( walkExprTree(pItem->pExpr, xFunc, pArg) ) return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Call walkExprTree() for every expression in Select p, not including dbda8d6ce9 2007-07-21 drh: ** expressions that are part of sub-selects in any FROM clause or the LIMIT dbda8d6ce9 2007-07-21 drh: ** or OFFSET expressions.. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int walkSelectExpr(Select *p, int (*xFunc)(void *, Expr*), void *pArg){ dbda8d6ce9 2007-07-21 drh: walkExprList(p->pEList, xFunc, pArg); dbda8d6ce9 2007-07-21 drh: walkExprTree(p->pWhere, xFunc, pArg); dbda8d6ce9 2007-07-21 drh: walkExprList(p->pGroupBy, xFunc, pArg); dbda8d6ce9 2007-07-21 drh: walkExprTree(p->pHaving, xFunc, pArg); dbda8d6ce9 2007-07-21 drh: walkExprList(p->pOrderBy, xFunc, pArg); dbda8d6ce9 2007-07-21 drh: if( p->pPrior ){ dbda8d6ce9 2007-07-21 drh: walkSelectExpr(p->pPrior, xFunc, pArg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is designed as an xFunc for walkExprTree(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pArg is really a pointer to an integer. If we can tell by looking dbda8d6ce9 2007-07-21 drh: ** at pExpr that the expression that contains pExpr is not a constant dbda8d6ce9 2007-07-21 drh: ** expression, then set *pArg to 0 and return 2 to abandon the tree walk. dbda8d6ce9 2007-07-21 drh: ** If pExpr does does not disqualify the expression from being a constant dbda8d6ce9 2007-07-21 drh: ** then do nothing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After walking the whole tree, if no nodes are found that disqualify dbda8d6ce9 2007-07-21 drh: ** the expression as constant, then we assume the whole expression dbda8d6ce9 2007-07-21 drh: ** is constant. See sqlite3ExprIsConstant() for additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int exprNodeIsConstant(void *pArg, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: int *pN = (int*)pArg; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If *pArg is 3 then any term of the expression that comes from dbda8d6ce9 2007-07-21 drh: ** the ON or USING clauses of a join disqualifies the expression dbda8d6ce9 2007-07-21 drh: ** from being considered constant. */ dbda8d6ce9 2007-07-21 drh: if( (*pN)==3 && ExprHasAnyProperty(pExpr, EP_FromJoin) ){ dbda8d6ce9 2007-07-21 drh: *pN = 0; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: switch( pExpr->op ){ dbda8d6ce9 2007-07-21 drh: /* Consider functions to be constant if all their arguments are constant dbda8d6ce9 2007-07-21 drh: ** and *pArg==2 */ dbda8d6ce9 2007-07-21 drh: case TK_FUNCTION: dbda8d6ce9 2007-07-21 drh: if( (*pN)==2 ) return 0; dbda8d6ce9 2007-07-21 drh: /* Fall through */ dbda8d6ce9 2007-07-21 drh: case TK_ID: dbda8d6ce9 2007-07-21 drh: case TK_COLUMN: dbda8d6ce9 2007-07-21 drh: case TK_DOT: dbda8d6ce9 2007-07-21 drh: case TK_AGG_FUNCTION: dbda8d6ce9 2007-07-21 drh: case TK_AGG_COLUMN: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: case TK_SELECT: dbda8d6ce9 2007-07-21 drh: case TK_EXISTS: dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: *pN = 0; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: case TK_IN: dbda8d6ce9 2007-07-21 drh: if( pExpr->pSelect ){ dbda8d6ce9 2007-07-21 drh: *pN = 0; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Walk an expression tree. Return 1 if the expression is constant dbda8d6ce9 2007-07-21 drh: ** and 0 if it involves variables or function calls. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For the purposes of this function, a double-quoted string (ex: "abc") dbda8d6ce9 2007-07-21 drh: ** is considered a variable but a single-quoted string (ex: 'abc') is dbda8d6ce9 2007-07-21 drh: ** a constant. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){ dbda8d6ce9 2007-07-21 drh: int isConst = 1; dbda8d6ce9 2007-07-21 drh: walkExprTree(p, exprNodeIsConstant, &isConst); dbda8d6ce9 2007-07-21 drh: return isConst; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Walk an expression tree. Return 1 if the expression is constant dbda8d6ce9 2007-07-21 drh: ** that does no originate from the ON or USING clauses of a join. dbda8d6ce9 2007-07-21 drh: ** Return 0 if it involves variables or function calls or terms from dbda8d6ce9 2007-07-21 drh: ** an ON or USING clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ dbda8d6ce9 2007-07-21 drh: int isConst = 3; dbda8d6ce9 2007-07-21 drh: walkExprTree(p, exprNodeIsConstant, &isConst); dbda8d6ce9 2007-07-21 drh: return isConst!=0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Walk an expression tree. Return 1 if the expression is constant dbda8d6ce9 2007-07-21 drh: ** or a function call with constant arguments. Return and 0 if there dbda8d6ce9 2007-07-21 drh: ** are any variables. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For the purposes of this function, a double-quoted string (ex: "abc") dbda8d6ce9 2007-07-21 drh: ** is considered a variable but a single-quoted string (ex: 'abc') is dbda8d6ce9 2007-07-21 drh: ** a constant. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p){ dbda8d6ce9 2007-07-21 drh: int isConst = 2; dbda8d6ce9 2007-07-21 drh: walkExprTree(p, exprNodeIsConstant, &isConst); dbda8d6ce9 2007-07-21 drh: return isConst!=0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the expression p codes a constant integer that is small enough dbda8d6ce9 2007-07-21 drh: ** to fit in a 32-bit integer, return 1 and put the value of the integer dbda8d6ce9 2007-07-21 drh: ** in *pValue. If the expression is not an integer or if it is too big dbda8d6ce9 2007-07-21 drh: ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ dbda8d6ce9 2007-07-21 drh: switch( p->op ){ dbda8d6ce9 2007-07-21 drh: case TK_INTEGER: { dbda8d6ce9 2007-07-21 drh: if( sqlite3GetInt32((char*)p->token.z, pValue) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_UPLUS: { dbda8d6ce9 2007-07-21 drh: return sqlite3ExprIsInteger(p->pLeft, pValue); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_UMINUS: { dbda8d6ce9 2007-07-21 drh: int v; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprIsInteger(p->pLeft, &v) ){ dbda8d6ce9 2007-07-21 drh: *pValue = -v; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the given string is a row-id column name. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IsRowid(const char *z){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(z, "_ROWID_")==0 ) return 1; dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(z, "ROWID")==0 ) return 1; dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(z, "OID")==0 ) return 1; dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up dbda8d6ce9 2007-07-21 drh: ** that name in the set of source tables in pSrcList and make the pExpr dbda8d6ce9 2007-07-21 drh: ** expression node refer back to that source column. The following changes dbda8d6ce9 2007-07-21 drh: ** are made to pExpr: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pExpr->iDb Set the index in db->aDb[] of the database holding dbda8d6ce9 2007-07-21 drh: ** the table. dbda8d6ce9 2007-07-21 drh: ** pExpr->iTable Set to the cursor number for the table obtained dbda8d6ce9 2007-07-21 drh: ** from pSrcList. dbda8d6ce9 2007-07-21 drh: ** pExpr->iColumn Set to the column number within the table. dbda8d6ce9 2007-07-21 drh: ** pExpr->op Set to TK_COLUMN. dbda8d6ce9 2007-07-21 drh: ** pExpr->pLeft Any expression this points to is deleted dbda8d6ce9 2007-07-21 drh: ** pExpr->pRight Any expression this points to is deleted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pDbToken is the name of the database (the "X"). This value may be dbda8d6ce9 2007-07-21 drh: ** NULL meaning that name is of the form Y.Z or Z. Any available database dbda8d6ce9 2007-07-21 drh: ** can be used. The pTableToken is the name of the table (the "Y"). This dbda8d6ce9 2007-07-21 drh: ** value can be NULL if pDbToken is also NULL. If pTableToken is NULL it dbda8d6ce9 2007-07-21 drh: ** means that the form of the name is Z and that columns from any table dbda8d6ce9 2007-07-21 drh: ** can be used. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the name cannot be resolved unambiguously, leave an error message dbda8d6ce9 2007-07-21 drh: ** in pParse and return non-zero. Return zero on success. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int lookupName( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: Token *pDbToken, /* Name of the database containing table, or NULL */ dbda8d6ce9 2007-07-21 drh: Token *pTableToken, /* Name of table containing column, or NULL */ dbda8d6ce9 2007-07-21 drh: Token *pColumnToken, /* Name of the column. */ dbda8d6ce9 2007-07-21 drh: NameContext *pNC, /* The name context used to resolve the name */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr /* Make this EXPR node point to the selected column */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: char *zDb = 0; /* Name of the database. The "X" in X.Y.Z */ dbda8d6ce9 2007-07-21 drh: char *zTab = 0; /* Name of the table. The "Y" in X.Y.Z or Y.Z */ dbda8d6ce9 2007-07-21 drh: char *zCol = 0; /* Name of the column. The "Z" */ dbda8d6ce9 2007-07-21 drh: int i, j; /* Loop counters */ dbda8d6ce9 2007-07-21 drh: int cnt = 0; /* Number of matching column names */ dbda8d6ce9 2007-07-21 drh: int cntTab = 0; /* Number of matching table names */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; /* The database */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; /* Use for looping over pSrcList items */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pMatch = 0; /* The matching pSrcList item */ dbda8d6ce9 2007-07-21 drh: NameContext *pTopNC = pNC; /* First namecontext in the list */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */ c287665ba8 2007-09-14 drh: zDb = sqlite3NameFromToken(db, pDbToken); c287665ba8 2007-09-14 drh: zTab = sqlite3NameFromToken(db, pTableToken); c287665ba8 2007-09-14 drh: zCol = sqlite3NameFromToken(db, pColumnToken); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto lookupname_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pExpr->iTable = -1; dbda8d6ce9 2007-07-21 drh: while( pNC && cnt==0 ){ dbda8d6ce9 2007-07-21 drh: ExprList *pEList; dbda8d6ce9 2007-07-21 drh: SrcList *pSrcList = pNC->pSrcList; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pSrcList ){ dbda8d6ce9 2007-07-21 drh: for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: Column *pCol; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTab = pItem->pTab; dbda8d6ce9 2007-07-21 drh: assert( pTab!=0 ); dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: assert( pTab->nCol>0 ); dbda8d6ce9 2007-07-21 drh: if( zTab ){ dbda8d6ce9 2007-07-21 drh: if( pItem->zAlias ){ dbda8d6ce9 2007-07-21 drh: char *zTabName = pItem->zAlias; dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: char *zTabName = pTab->zName; dbda8d6ce9 2007-07-21 drh: if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue; dbda8d6ce9 2007-07-21 drh: if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){ dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( 0==(cntTab++) ){ dbda8d6ce9 2007-07-21 drh: pExpr->iTable = pItem->iCursor; dbda8d6ce9 2007-07-21 drh: pExpr->pSchema = pTab->pSchema; dbda8d6ce9 2007-07-21 drh: pMatch = pItem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ dbda8d6ce9 2007-07-21 drh: const char *zColl = pTab->aCol[j].zColl; dbda8d6ce9 2007-07-21 drh: IdList *pUsing; dbda8d6ce9 2007-07-21 drh: cnt++; dbda8d6ce9 2007-07-21 drh: pExpr->iTable = pItem->iCursor; dbda8d6ce9 2007-07-21 drh: pMatch = pItem; dbda8d6ce9 2007-07-21 drh: pExpr->pSchema = pTab->pSchema; dbda8d6ce9 2007-07-21 drh: /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ dbda8d6ce9 2007-07-21 drh: pExpr->iColumn = j==pTab->iPKey ? -1 : j; dbda8d6ce9 2007-07-21 drh: pExpr->affinity = pTab->aCol[j].affinity; dbda8d6ce9 2007-07-21 drh: if( (pExpr->flags & EP_ExpCollate)==0 ){ dbda8d6ce9 2007-07-21 drh: pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<pSrcList->nSrc-1 ){ dbda8d6ce9 2007-07-21 drh: if( pItem[1].jointype & JT_NATURAL ){ dbda8d6ce9 2007-07-21 drh: /* If this match occurred in the left table of a natural join, dbda8d6ce9 2007-07-21 drh: ** then skip the right table to avoid a duplicate match */ dbda8d6ce9 2007-07-21 drh: pItem++; dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: }else if( (pUsing = pItem[1].pUsing)!=0 ){ dbda8d6ce9 2007-07-21 drh: /* If this match occurs on a column that is in the USING clause dbda8d6ce9 2007-07-21 drh: ** of a join, skip the search of the right table of the join dbda8d6ce9 2007-07-21 drh: ** to avoid a duplicate match there. */ dbda8d6ce9 2007-07-21 drh: int k; dbda8d6ce9 2007-07-21 drh: for(k=0; k<pUsing->nId; k++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){ dbda8d6ce9 2007-07-21 drh: pItem++; dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: /* If we have not already resolved the name, then maybe dbda8d6ce9 2007-07-21 drh: ** it is a new.* or old.* trigger argument reference dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){ dbda8d6ce9 2007-07-21 drh: TriggerStack *pTriggerStack = pParse->trigStack; dbda8d6ce9 2007-07-21 drh: Table *pTab = 0; dbda8d6ce9 2007-07-21 drh: if( pTriggerStack->newIdx != -1 && sqlite3StrICmp("new", zTab) == 0 ){ dbda8d6ce9 2007-07-21 drh: pExpr->iTable = pTriggerStack->newIdx; dbda8d6ce9 2007-07-21 drh: assert( pTriggerStack->pTab ); dbda8d6ce9 2007-07-21 drh: pTab = pTriggerStack->pTab; dbda8d6ce9 2007-07-21 drh: }else if( pTriggerStack->oldIdx != -1 && sqlite3StrICmp("old", zTab)==0 ){ dbda8d6ce9 2007-07-21 drh: pExpr->iTable = pTriggerStack->oldIdx; dbda8d6ce9 2007-07-21 drh: assert( pTriggerStack->pTab ); dbda8d6ce9 2007-07-21 drh: pTab = pTriggerStack->pTab; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: int iCol; dbda8d6ce9 2007-07-21 drh: Column *pCol = pTab->aCol; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pExpr->pSchema = pTab->pSchema; dbda8d6ce9 2007-07-21 drh: cntTab++; dbda8d6ce9 2007-07-21 drh: for(iCol=0; iCol < pTab->nCol; iCol++, pCol++) { dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ dbda8d6ce9 2007-07-21 drh: const char *zColl = pTab->aCol[iCol].zColl; dbda8d6ce9 2007-07-21 drh: cnt++; dbda8d6ce9 2007-07-21 drh: pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol; dbda8d6ce9 2007-07-21 drh: pExpr->affinity = pTab->aCol[iCol].affinity; dbda8d6ce9 2007-07-21 drh: if( (pExpr->flags & EP_ExpCollate)==0 ){ dbda8d6ce9 2007-07-21 drh: pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pExpr->pTab = pTab; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_TRIGGER) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Perhaps the name is a reference to the ROWID dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){ dbda8d6ce9 2007-07-21 drh: cnt = 1; dbda8d6ce9 2007-07-21 drh: pExpr->iColumn = -1; dbda8d6ce9 2007-07-21 drh: pExpr->affinity = SQLITE_AFF_INTEGER; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z dbda8d6ce9 2007-07-21 drh: ** might refer to an result-set alias. This happens, for example, when dbda8d6ce9 2007-07-21 drh: ** we are resolving names in the WHERE clause of the following command: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT a+b AS x FROM table WHERE x<10; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In cases like this, replace pExpr with a copy of the expression that dbda8d6ce9 2007-07-21 drh: ** forms the result set entry ("a+b" in the example) and return immediately. dbda8d6ce9 2007-07-21 drh: ** Note that the expression in the result set should have already been dbda8d6ce9 2007-07-21 drh: ** resolved by the time the WHERE clause is resolved. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){ dbda8d6ce9 2007-07-21 drh: for(j=0; j<pEList->nExpr; j++){ dbda8d6ce9 2007-07-21 drh: char *zAs = pEList->a[j].zName; dbda8d6ce9 2007-07-21 drh: if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ d8590e093f 2007-07-24 drh: Expr *pDup, *pOrig; dbda8d6ce9 2007-07-21 drh: assert( pExpr->pLeft==0 && pExpr->pRight==0 ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->pList==0 ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->pSelect==0 ); d8590e093f 2007-07-24 drh: pOrig = pEList->a[j].pExpr; d8590e093f 2007-07-24 drh: if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){ d8590e093f 2007-07-24 drh: sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); c287665ba8 2007-09-14 drh: sqlite3_free(zCol); d8590e093f 2007-07-24 drh: return 2; d8590e093f 2007-07-24 drh: } c287665ba8 2007-09-14 drh: pDup = sqlite3ExprDup(db, pOrig); dbda8d6ce9 2007-07-21 drh: if( pExpr->flags & EP_ExpCollate ){ dbda8d6ce9 2007-07-21 drh: pDup->pColl = pExpr->pColl; dbda8d6ce9 2007-07-21 drh: pDup->flags |= EP_ExpCollate; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( pExpr->span.dyn ) sqlite3_free((char*)pExpr->span.z); c287665ba8 2007-09-14 drh: if( pExpr->token.dyn ) sqlite3_free((char*)pExpr->token.z); dbda8d6ce9 2007-07-21 drh: memcpy(pExpr, pDup, sizeof(*pExpr)); c287665ba8 2007-09-14 drh: sqlite3_free(pDup); dbda8d6ce9 2007-07-21 drh: cnt = 1; dbda8d6ce9 2007-07-21 drh: pMatch = 0; dbda8d6ce9 2007-07-21 drh: assert( zTab==0 && zDb==0 ); dbda8d6ce9 2007-07-21 drh: goto lookupname_end_2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Advance to the next name context. The loop will exit when either dbda8d6ce9 2007-07-21 drh: ** we have a match (cnt>0) or when we run out of name contexts. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( cnt==0 ){ dbda8d6ce9 2007-07-21 drh: pNC = pNC->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If X and Y are NULL (in other words if only the column name Z is dbda8d6ce9 2007-07-21 drh: ** supplied) and the value of Z is enclosed in double-quotes, then dbda8d6ce9 2007-07-21 drh: ** Z is a string literal if it doesn't match any column names. In that dbda8d6ce9 2007-07-21 drh: ** case, we need to return right away and not make any changes to dbda8d6ce9 2007-07-21 drh: ** pExpr. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Because no reference was made to outer contexts, the pNC->nRef dbda8d6ce9 2007-07-21 drh: ** fields are not changed in any context. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){ c287665ba8 2007-09-14 drh: sqlite3_free(zCol); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** cnt==0 means there was not match. cnt>1 means there were two or dbda8d6ce9 2007-07-21 drh: ** more matches. Either way, we have an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( cnt!=1 ){ dbda8d6ce9 2007-07-21 drh: char *z = 0; dbda8d6ce9 2007-07-21 drh: char *zErr; dbda8d6ce9 2007-07-21 drh: zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s"; dbda8d6ce9 2007-07-21 drh: if( zDb ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, (char*)0); dbda8d6ce9 2007-07-21 drh: }else if( zTab ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&z, zTab, ".", zCol, (char*)0); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: z = sqlite3StrDup(zCol); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( z ){ c287665ba8 2007-09-14 drh: sqlite3ErrorMsg(pParse, zErr, z); c287665ba8 2007-09-14 drh: sqlite3_free(z); c287665ba8 2007-09-14 drh: pTopNC->nErr++; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a column from a table in pSrcList is referenced, then record dbda8d6ce9 2007-07-21 drh: ** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes dbda8d6ce9 2007-07-21 drh: ** bit 0 to be set. Column 1 sets bit 1. And so forth. If the dbda8d6ce9 2007-07-21 drh: ** column number is greater than the number of bits in the bitmask dbda8d6ce9 2007-07-21 drh: ** then set the high-order bit of the bitmask. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pExpr->iColumn>=0 && pMatch!=0 ){ dbda8d6ce9 2007-07-21 drh: int n = pExpr->iColumn; dbda8d6ce9 2007-07-21 drh: if( n>=sizeof(Bitmask)*8 ){ dbda8d6ce9 2007-07-21 drh: n = sizeof(Bitmask)*8-1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pMatch->iCursor==pExpr->iTable ); dbda8d6ce9 2007-07-21 drh: pMatch->colUsed |= ((Bitmask)1)<<n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: lookupname_end: dbda8d6ce9 2007-07-21 drh: /* Clean up and return dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: sqlite3_free(zDb); c287665ba8 2007-09-14 drh: sqlite3_free(zTab); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: pExpr->pLeft = 0; dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pExpr->pRight); dbda8d6ce9 2007-07-21 drh: pExpr->pRight = 0; dbda8d6ce9 2007-07-21 drh: pExpr->op = TK_COLUMN; dbda8d6ce9 2007-07-21 drh: lookupname_end_2: c287665ba8 2007-09-14 drh: sqlite3_free(zCol); dbda8d6ce9 2007-07-21 drh: if( cnt==1 ){ dbda8d6ce9 2007-07-21 drh: assert( pNC!=0 ); dbda8d6ce9 2007-07-21 drh: sqlite3AuthRead(pParse, pExpr, pNC->pSrcList); dbda8d6ce9 2007-07-21 drh: if( pMatch && !pMatch->pSelect ){ dbda8d6ce9 2007-07-21 drh: pExpr->pTab = pMatch->pTab; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Increment the nRef value on all name contexts from TopNC up to dbda8d6ce9 2007-07-21 drh: ** the point where the name matched. */ dbda8d6ce9 2007-07-21 drh: for(;;){ dbda8d6ce9 2007-07-21 drh: assert( pTopNC!=0 ); dbda8d6ce9 2007-07-21 drh: pTopNC->nRef++; dbda8d6ce9 2007-07-21 drh: if( pTopNC==pNC ) break; dbda8d6ce9 2007-07-21 drh: pTopNC = pTopNC->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is designed as an xFunc for walkExprTree(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Resolve symbolic names into TK_COLUMN operators for the current dbda8d6ce9 2007-07-21 drh: ** node in the expression tree. Return 0 to continue the search down dbda8d6ce9 2007-07-21 drh: ** the tree or 2 to abort the tree walk. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine also does error checking and name resolution for dbda8d6ce9 2007-07-21 drh: ** function names. The operator for aggregate functions is changed dbda8d6ce9 2007-07-21 drh: ** to TK_AGG_FUNCTION. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int nameResolverStep(void *pArg, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: NameContext *pNC = (NameContext*)pArg; dbda8d6ce9 2007-07-21 drh: Parse *pParse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) return 1; dbda8d6ce9 2007-07-21 drh: assert( pNC!=0 ); dbda8d6ce9 2007-07-21 drh: pParse = pNC->pParse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1; dbda8d6ce9 2007-07-21 drh: ExprSetProperty(pExpr, EP_Resolved); dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ dbda8d6ce9 2007-07-21 drh: SrcList *pSrcList = pNC->pSrcList; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pNC->pSrcList->nSrc; i++){ dbda8d6ce9 2007-07-21 drh: assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: switch( pExpr->op ){ dbda8d6ce9 2007-07-21 drh: /* Double-quoted strings (ex: "abc") are used as identifiers if dbda8d6ce9 2007-07-21 drh: ** possible. Otherwise they remain as strings. Single-quoted dbda8d6ce9 2007-07-21 drh: ** strings (ex: 'abc') are always string literals. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case TK_STRING: { dbda8d6ce9 2007-07-21 drh: if( pExpr->token.z[0]=='\'' ) break; dbda8d6ce9 2007-07-21 drh: /* Fall thru into the TK_ID case if this is a double-quoted string */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* A lone identifier is the name of a column. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case TK_ID: { dbda8d6ce9 2007-07-21 drh: lookupName(pParse, 0, 0, &pExpr->token, pNC, pExpr); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A table name and column name: ID.ID dbda8d6ce9 2007-07-21 drh: ** Or a database, table and column: ID.ID.ID dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case TK_DOT: { dbda8d6ce9 2007-07-21 drh: Token *pColumn; dbda8d6ce9 2007-07-21 drh: Token *pTable; dbda8d6ce9 2007-07-21 drh: Token *pDb; dbda8d6ce9 2007-07-21 drh: Expr *pRight; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* if( pSrcList==0 ) break; */ dbda8d6ce9 2007-07-21 drh: pRight = pExpr->pRight; dbda8d6ce9 2007-07-21 drh: if( pRight->op==TK_ID ){ dbda8d6ce9 2007-07-21 drh: pDb = 0; dbda8d6ce9 2007-07-21 drh: pTable = &pExpr->pLeft->token; dbda8d6ce9 2007-07-21 drh: pColumn = &pRight->token; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pRight->op==TK_DOT ); dbda8d6ce9 2007-07-21 drh: pDb = &pExpr->pLeft->token; dbda8d6ce9 2007-07-21 drh: pTable = &pRight->pLeft->token; dbda8d6ce9 2007-07-21 drh: pColumn = &pRight->pRight->token; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: lookupName(pParse, pDb, pTable, pColumn, pNC, pExpr); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Resolve function names dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case TK_CONST_FUNC: dbda8d6ce9 2007-07-21 drh: case TK_FUNCTION: { dbda8d6ce9 2007-07-21 drh: ExprList *pList = pExpr->pList; /* The argument list */ dbda8d6ce9 2007-07-21 drh: int n = pList ? pList->nExpr : 0; /* Number of arguments */ dbda8d6ce9 2007-07-21 drh: int no_such_func = 0; /* True if no such function exists */ dbda8d6ce9 2007-07-21 drh: int wrong_num_args = 0; /* True if wrong number of arguments */ dbda8d6ce9 2007-07-21 drh: int is_agg = 0; /* True if is an aggregate function */ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int auth; /* Authorization to use the function */ dbda8d6ce9 2007-07-21 drh: int nId; /* Number of characters in function name */ dbda8d6ce9 2007-07-21 drh: const char *zId; /* The function name. */ dbda8d6ce9 2007-07-21 drh: FuncDef *pDef; /* Information about the function */ dbda8d6ce9 2007-07-21 drh: int enc = ENC(pParse->db); /* The database encoding */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zId = (char*)pExpr->token.z; dbda8d6ce9 2007-07-21 drh: nId = pExpr->token.n; dbda8d6ce9 2007-07-21 drh: pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); dbda8d6ce9 2007-07-21 drh: if( pDef==0 ){ dbda8d6ce9 2007-07-21 drh: pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); dbda8d6ce9 2007-07-21 drh: if( pDef==0 ){ dbda8d6ce9 2007-07-21 drh: no_such_func = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: wrong_num_args = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: is_agg = pDef->xFunc==0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: if( pDef ){ dbda8d6ce9 2007-07-21 drh: auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0); dbda8d6ce9 2007-07-21 drh: if( auth!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( auth==SQLITE_DENY ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "not authorized to use function: %s", dbda8d6ce9 2007-07-21 drh: pDef->zName); dbda8d6ce9 2007-07-21 drh: pNC->nErr++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pExpr->op = TK_NULL; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( is_agg && !pNC->allowAgg ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); dbda8d6ce9 2007-07-21 drh: pNC->nErr++; dbda8d6ce9 2007-07-21 drh: is_agg = 0; dbda8d6ce9 2007-07-21 drh: }else if( no_such_func ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); dbda8d6ce9 2007-07-21 drh: pNC->nErr++; dbda8d6ce9 2007-07-21 drh: }else if( wrong_num_args ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", dbda8d6ce9 2007-07-21 drh: nId, zId); dbda8d6ce9 2007-07-21 drh: pNC->nErr++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( is_agg ){ dbda8d6ce9 2007-07-21 drh: pExpr->op = TK_AGG_FUNCTION; dbda8d6ce9 2007-07-21 drh: pNC->hasAgg = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( is_agg ) pNC->allowAgg = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; pNC->nErr==0 && i<n; i++){ dbda8d6ce9 2007-07-21 drh: walkExprTree(pList->a[i].pExpr, nameResolverStep, pNC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( is_agg ) pNC->allowAgg = 1; dbda8d6ce9 2007-07-21 drh: /* FIX ME: Compute pExpr->affinity based on the expected return dbda8d6ce9 2007-07-21 drh: ** type of the function dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: return is_agg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: case TK_SELECT: dbda8d6ce9 2007-07-21 drh: case TK_EXISTS: dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: case TK_IN: { dbda8d6ce9 2007-07-21 drh: if( pExpr->pSelect ){ dbda8d6ce9 2007-07-21 drh: int nRef = pNC->nRef; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: if( pNC->isCheck ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3SelectResolve(pParse, pExpr->pSelect, pNC); dbda8d6ce9 2007-07-21 drh: assert( pNC->nRef>=nRef ); dbda8d6ce9 2007-07-21 drh: if( nRef!=pNC->nRef ){ dbda8d6ce9 2007-07-21 drh: ExprSetProperty(pExpr, EP_VarSelect); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: case TK_VARIABLE: { dbda8d6ce9 2007-07-21 drh: if( pNC->isCheck ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine walks an expression tree and resolves references to dbda8d6ce9 2007-07-21 drh: ** table columns. Nodes of the form ID.ID or ID resolve into an dbda8d6ce9 2007-07-21 drh: ** index to the table in the table list and a column offset. The dbda8d6ce9 2007-07-21 drh: ** Expr.opcode for such nodes is changed to TK_COLUMN. The Expr.iTable dbda8d6ce9 2007-07-21 drh: ** value is changed to the index of the referenced table in pTabList dbda8d6ce9 2007-07-21 drh: ** plus the "base" value. The base value will ultimately become the dbda8d6ce9 2007-07-21 drh: ** VDBE cursor number for a cursor that is pointing into the referenced dbda8d6ce9 2007-07-21 drh: ** table. The Expr.iColumn value is changed to the index of the column dbda8d6ce9 2007-07-21 drh: ** of the referenced table. The Expr.iColumn value for the special dbda8d6ce9 2007-07-21 drh: ** ROWID column is -1. Any INTEGER PRIMARY KEY column is tried as an dbda8d6ce9 2007-07-21 drh: ** alias for ROWID. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Also resolve function names and check the functions for proper dbda8d6ce9 2007-07-21 drh: ** usage. Make sure all function names are recognized and all functions dbda8d6ce9 2007-07-21 drh: ** have the correct number of arguments. Leave an error message dbda8d6ce9 2007-07-21 drh: ** in pParse->zErrMsg if anything is amiss. Return the number of errors. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the expression contains aggregate functions then set the EP_Agg dbda8d6ce9 2007-07-21 drh: ** property on the expression. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprResolveNames( dbda8d6ce9 2007-07-21 drh: NameContext *pNC, /* Namespace to resolve expressions in. */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr /* The expression to be analyzed. */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int savedHasAgg; dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) return 0; c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 dbda8d6ce9 2007-07-21 drh: if( (pExpr->nHeight+pNC->pParse->nHeight)>SQLITE_MAX_EXPR_DEPTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pNC->pParse, dbda8d6ce9 2007-07-21 drh: "Expression tree is too large (maximum depth %d)", dbda8d6ce9 2007-07-21 drh: SQLITE_MAX_EXPR_DEPTH dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pNC->pParse->nHeight += pExpr->nHeight; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: savedHasAgg = pNC->hasAgg; dbda8d6ce9 2007-07-21 drh: pNC->hasAgg = 0; dbda8d6ce9 2007-07-21 drh: walkExprTree(pExpr, nameResolverStep, pNC); c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 dbda8d6ce9 2007-07-21 drh: pNC->pParse->nHeight -= pExpr->nHeight; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( pNC->nErr>0 ){ dbda8d6ce9 2007-07-21 drh: ExprSetProperty(pExpr, EP_Error); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pNC->hasAgg ){ dbda8d6ce9 2007-07-21 drh: ExprSetProperty(pExpr, EP_Agg); dbda8d6ce9 2007-07-21 drh: }else if( savedHasAgg ){ dbda8d6ce9 2007-07-21 drh: pNC->hasAgg = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return ExprHasProperty(pExpr, EP_Error); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A pointer instance of this structure is used to pass information dbda8d6ce9 2007-07-21 drh: ** through walkExprTree into codeSubqueryStep(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct QueryCoder QueryCoder; dbda8d6ce9 2007-07-21 drh: struct QueryCoder { dbda8d6ce9 2007-07-21 drh: Parse *pParse; /* The parsing context */ dbda8d6ce9 2007-07-21 drh: NameContext *pNC; /* Namespace of first enclosing query */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for scalar subqueries used as an expression dbda8d6ce9 2007-07-21 drh: ** and IN operators. Examples: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (SELECT a FROM b) -- subquery dbda8d6ce9 2007-07-21 drh: ** EXISTS (SELECT a FROM b) -- EXISTS subquery dbda8d6ce9 2007-07-21 drh: ** x IN (4,5,11) -- IN operator with list on right-hand side dbda8d6ce9 2007-07-21 drh: ** x IN (SELECT a FROM b) -- IN operator with subquery on the right dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pExpr parameter describes the expression that contains the IN dbda8d6ce9 2007-07-21 drh: ** operator or subquery. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: int testAddr = 0; /* One-time test address */ dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This code must be run in its entirety every time it is encountered dbda8d6ce9 2007-07-21 drh: ** if any of the following is true: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * The right-hand side is a correlated subquery dbda8d6ce9 2007-07-21 drh: ** * The right-hand side is an expression list containing variables dbda8d6ce9 2007-07-21 drh: ** * We are inside a trigger dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If all of the above are false, then we can run this code just once dbda8d6ce9 2007-07-21 drh: ** save the results, and reuse the same result on subsequent invocations. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ dbda8d6ce9 2007-07-21 drh: int mem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); dbda8d6ce9 2007-07-21 drh: testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); c287665ba8 2007-09-14 drh: assert( testAddr>0 || pParse->db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 1, mem); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: switch( pExpr->op ){ dbda8d6ce9 2007-07-21 drh: case TK_IN: { dbda8d6ce9 2007-07-21 drh: char affinity; dbda8d6ce9 2007-07-21 drh: KeyInfo keyInfo; dbda8d6ce9 2007-07-21 drh: int addr; /* Address of OP_OpenEphemeral instruction */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: affinity = sqlite3ExprAffinity(pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)' dbda8d6ce9 2007-07-21 drh: ** expression it is handled the same way. A virtual table is dbda8d6ce9 2007-07-21 drh: ** filled with single-field index keys representing the results dbda8d6ce9 2007-07-21 drh: ** from the SELECT or the <exprlist>. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the 'x' expression is a column value, or the SELECT... dbda8d6ce9 2007-07-21 drh: ** statement returns a column value, then the affinity of that dbda8d6ce9 2007-07-21 drh: ** column is used to build the index keys. If both 'x' and the dbda8d6ce9 2007-07-21 drh: ** SELECT... statement are columns, then numeric affinity is used dbda8d6ce9 2007-07-21 drh: ** if either column has NUMERIC or INTEGER affinity. If neither dbda8d6ce9 2007-07-21 drh: ** 'x' nor the SELECT... statement are columns, then numeric affinity dbda8d6ce9 2007-07-21 drh: ** is used. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pExpr->iTable = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, pExpr->iTable, 0); dbda8d6ce9 2007-07-21 drh: memset(&keyInfo, 0, sizeof(keyInfo)); dbda8d6ce9 2007-07-21 drh: keyInfo.nField = 1; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pExpr->pSelect ){ dbda8d6ce9 2007-07-21 drh: /* Case 1: expr IN (SELECT ...) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Generate code to write the results of the select into the temporary dbda8d6ce9 2007-07-21 drh: ** table allocated and opened above. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int iParm = pExpr->iTable + (((int)affinity)<<16); dbda8d6ce9 2007-07-21 drh: ExprList *pEList; dbda8d6ce9 2007-07-21 drh: assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); dbda8d6ce9 2007-07-21 drh: if( sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pEList = pExpr->pSelect->pEList; dbda8d6ce9 2007-07-21 drh: if( pEList && pEList->nExpr>0 ){ dbda8d6ce9 2007-07-21 drh: keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, dbda8d6ce9 2007-07-21 drh: pEList->a[0].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pExpr->pList ){ dbda8d6ce9 2007-07-21 drh: /* Case 2: expr IN (exprlist) dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** For each expression, build an index key from the evaluation and dbda8d6ce9 2007-07-21 drh: ** store it in the temporary table. If <expr> is a column, then use dbda8d6ce9 2007-07-21 drh: ** that columns affinity when building index keys. If <expr> is not dbda8d6ce9 2007-07-21 drh: ** a column, use numeric affinity. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: ExprList *pList = pExpr->pList; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !affinity ){ dbda8d6ce9 2007-07-21 drh: affinity = SQLITE_AFF_NONE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: keyInfo.aColl[0] = pExpr->pLeft->pColl; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Loop through each expression in <exprlist>. */ dbda8d6ce9 2007-07-21 drh: for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ dbda8d6ce9 2007-07-21 drh: Expr *pE2 = pItem->pExpr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the expression is not constant then we will need to dbda8d6ce9 2007-07-21 drh: ** disable the test that was generated above that makes sure dbda8d6ce9 2007-07-21 drh: ** this code only executes once. Because for a non-constant dbda8d6ce9 2007-07-21 drh: ** expression we need to rerun this code each time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeToNoop(v, testAddr-1, 3); dbda8d6ce9 2007-07-21 drh: testAddr = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Evaluate the expression and insert it into the temp table */ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pE2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, pExpr->iTable, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: case TK_EXISTS: dbda8d6ce9 2007-07-21 drh: case TK_SELECT: { dbda8d6ce9 2007-07-21 drh: /* This has to be a scalar SELECT. Generate code to put the dbda8d6ce9 2007-07-21 drh: ** value of this select in a memory cell and record the number dbda8d6ce9 2007-07-21 drh: ** of the memory cell in iColumn. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const Token one = { (u8*)"1", 0, 1 }; dbda8d6ce9 2007-07-21 drh: Select *pSel; dbda8d6ce9 2007-07-21 drh: int iMem; dbda8d6ce9 2007-07-21 drh: int sop; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pExpr->iColumn = iMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: pSel = pExpr->pSelect; dbda8d6ce9 2007-07-21 drh: if( pExpr->op==TK_SELECT ){ dbda8d6ce9 2007-07-21 drh: sop = SRT_Mem; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# Init subquery result")); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sop = SRT_Exists; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# Init EXISTS result")); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pSel->pLimit); c287665ba8 2007-09-14 drh: pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one); dbda8d6ce9 2007-07-21 drh: if( sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( testAddr ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, testAddr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_SUBQUERY */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate an instruction that will put the integer describe by dbda8d6ce9 2007-07-21 drh: ** text z[0..n-1] on the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void codeInteger(Vdbe *v, const char *z, int n){ c287665ba8 2007-09-14 drh: assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed ); dbda8d6ce9 2007-07-21 drh: if( z ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( sqlite3GetInt32(z, &i) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, i, 0); dbda8d6ce9 2007-07-21 drh: }else if( sqlite3FitsIn64Bits(z) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will extract the iColumn-th column from dbda8d6ce9 2007-07-21 drh: ** table pTab and push that column value on the stack. There dbda8d6ce9 2007-07-21 drh: ** is an open cursor to pTab in iTable. If iColumn<0 then dbda8d6ce9 2007-07-21 drh: ** code is generated that extracts the rowid. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprCodeGetColumn(Vdbe *v, Table *pTab, int iColumn, int iTable){ dbda8d6ce9 2007-07-21 drh: if( iColumn<0 ){ dbda8d6ce9 2007-07-21 drh: int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, iTable, 0); dbda8d6ce9 2007-07-21 drh: }else if( pTab==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iTable, iColumn); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, iTable, iColumn); dbda8d6ce9 2007-07-21 drh: sqlite3ColumnDefault(v, pTab, iColumn); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: if( pTab->aCol[iColumn].affinity==SQLITE_AFF_REAL ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code into the current Vdbe to evaluate the given dbda8d6ce9 2007-07-21 drh: ** expression and leave the result on the top of stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This code depends on the fact that certain token values (ex: TK_EQ) dbda8d6ce9 2007-07-21 drh: ** are the same as opcode values (ex: OP_Eq) that implement the corresponding dbda8d6ce9 2007-07-21 drh: ** operation. Special comments in vdbe.c and the mkopcodeh.awk script in dbda8d6ce9 2007-07-21 drh: ** the make process cause these values to align. Assert()s in the code dbda8d6ce9 2007-07-21 drh: ** below verify that the numbers are aligned correctly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int op; dbda8d6ce9 2007-07-21 drh: int stackChng = 1; /* Amount of change to stack depth */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: op = pExpr->op; dbda8d6ce9 2007-07-21 drh: switch( op ){ dbda8d6ce9 2007-07-21 drh: case TK_AGG_COLUMN: { dbda8d6ce9 2007-07-21 drh: AggInfo *pAggInfo = pExpr->pAggInfo; dbda8d6ce9 2007-07-21 drh: struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; dbda8d6ce9 2007-07-21 drh: if( !pAggInfo->directMode ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, pCol->iMem, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }else if( pAggInfo->useSortingIdx ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, pAggInfo->sortingIdx, dbda8d6ce9 2007-07-21 drh: pCol->iSorterColumn); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Otherwise, fall thru into the TK_COLUMN case */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_COLUMN: { dbda8d6ce9 2007-07-21 drh: if( pExpr->iTable<0 ){ dbda8d6ce9 2007-07-21 drh: /* This only happens when coding check constraints */ dbda8d6ce9 2007-07-21 drh: assert( pParse->ckOffset>0 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeGetColumn(v, pExpr->pTab, pExpr->iColumn, pExpr->iTable); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_INTEGER: { dbda8d6ce9 2007-07-21 drh: codeInteger(v, (char*)pExpr->token.z, pExpr->token.n); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_FLOAT: dbda8d6ce9 2007-07-21 drh: case TK_STRING: { dbda8d6ce9 2007-07-21 drh: assert( TK_FLOAT==OP_Real ); dbda8d6ce9 2007-07-21 drh: assert( TK_STRING==OP_String8 ); c287665ba8 2007-09-14 drh: sqlite3DequoteExpr(pParse->db, pExpr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_NULL: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_BLOB_LITERAL dbda8d6ce9 2007-07-21 drh: case TK_BLOB: { dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: const char *z; dbda8d6ce9 2007-07-21 drh: assert( TK_BLOB==OP_HexBlob ); dbda8d6ce9 2007-07-21 drh: n = pExpr->token.n - 3; dbda8d6ce9 2007-07-21 drh: z = (char*)pExpr->token.z + 2; dbda8d6ce9 2007-07-21 drh: assert( n>=0 ); dbda8d6ce9 2007-07-21 drh: if( n==0 ){ dbda8d6ce9 2007-07-21 drh: z = ""; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, op, 0, 0, z, n); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: case TK_VARIABLE: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0); dbda8d6ce9 2007-07-21 drh: if( pExpr->token.n>1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, (char*)pExpr->token.z, pExpr->token.n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_REGISTER: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iTable, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CAST dbda8d6ce9 2007-07-21 drh: case TK_CAST: { dbda8d6ce9 2007-07-21 drh: /* Expressions of the form: CAST(pLeft AS token) */ dbda8d6ce9 2007-07-21 drh: int aff, to_op; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: aff = sqlite3AffinityType(&pExpr->token); dbda8d6ce9 2007-07-21 drh: to_op = aff - SQLITE_AFF_TEXT + OP_ToText; dbda8d6ce9 2007-07-21 drh: assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT ); dbda8d6ce9 2007-07-21 drh: assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE ); dbda8d6ce9 2007-07-21 drh: assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); dbda8d6ce9 2007-07-21 drh: assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); dbda8d6ce9 2007-07-21 drh: assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, to_op, 0, 0); dbda8d6ce9 2007-07-21 drh: stackChng = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_CAST */ dbda8d6ce9 2007-07-21 drh: case TK_LT: dbda8d6ce9 2007-07-21 drh: case TK_LE: dbda8d6ce9 2007-07-21 drh: case TK_GT: dbda8d6ce9 2007-07-21 drh: case TK_GE: dbda8d6ce9 2007-07-21 drh: case TK_NE: dbda8d6ce9 2007-07-21 drh: case TK_EQ: { dbda8d6ce9 2007-07-21 drh: assert( TK_LT==OP_Lt ); dbda8d6ce9 2007-07-21 drh: assert( TK_LE==OP_Le ); dbda8d6ce9 2007-07-21 drh: assert( TK_GT==OP_Gt ); dbda8d6ce9 2007-07-21 drh: assert( TK_GE==OP_Ge ); dbda8d6ce9 2007-07-21 drh: assert( TK_EQ==OP_Eq ); dbda8d6ce9 2007-07-21 drh: assert( TK_NE==OP_Ne ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pRight); dbda8d6ce9 2007-07-21 drh: codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0); dbda8d6ce9 2007-07-21 drh: stackChng = -1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_AND: dbda8d6ce9 2007-07-21 drh: case TK_OR: dbda8d6ce9 2007-07-21 drh: case TK_PLUS: dbda8d6ce9 2007-07-21 drh: case TK_STAR: dbda8d6ce9 2007-07-21 drh: case TK_MINUS: dbda8d6ce9 2007-07-21 drh: case TK_REM: dbda8d6ce9 2007-07-21 drh: case TK_BITAND: dbda8d6ce9 2007-07-21 drh: case TK_BITOR: dbda8d6ce9 2007-07-21 drh: case TK_SLASH: dbda8d6ce9 2007-07-21 drh: case TK_LSHIFT: dbda8d6ce9 2007-07-21 drh: case TK_RSHIFT: dbda8d6ce9 2007-07-21 drh: case TK_CONCAT: { dbda8d6ce9 2007-07-21 drh: assert( TK_AND==OP_And ); dbda8d6ce9 2007-07-21 drh: assert( TK_OR==OP_Or ); dbda8d6ce9 2007-07-21 drh: assert( TK_PLUS==OP_Add ); dbda8d6ce9 2007-07-21 drh: assert( TK_MINUS==OP_Subtract ); dbda8d6ce9 2007-07-21 drh: assert( TK_REM==OP_Remainder ); dbda8d6ce9 2007-07-21 drh: assert( TK_BITAND==OP_BitAnd ); dbda8d6ce9 2007-07-21 drh: assert( TK_BITOR==OP_BitOr ); dbda8d6ce9 2007-07-21 drh: assert( TK_SLASH==OP_Divide ); dbda8d6ce9 2007-07-21 drh: assert( TK_LSHIFT==OP_ShiftLeft ); dbda8d6ce9 2007-07-21 drh: assert( TK_RSHIFT==OP_ShiftRight ); dbda8d6ce9 2007-07-21 drh: assert( TK_CONCAT==OP_Concat ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pRight); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, 0, 0); dbda8d6ce9 2007-07-21 drh: stackChng = -1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_UMINUS: { dbda8d6ce9 2007-07-21 drh: Expr *pLeft = pExpr->pLeft; dbda8d6ce9 2007-07-21 drh: assert( pLeft ); dbda8d6ce9 2007-07-21 drh: if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){ dbda8d6ce9 2007-07-21 drh: Token *p = &pLeft->token; c287665ba8 2007-09-14 drh: char *z = sqlite3MPrintf(pParse->db, "-%.*s", p->n, p->z); dbda8d6ce9 2007-07-21 drh: if( pLeft->op==TK_FLOAT ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: codeInteger(v, z, p->n+1); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(z); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Fall through into TK_NOT */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_BITNOT: dbda8d6ce9 2007-07-21 drh: case TK_NOT: { dbda8d6ce9 2007-07-21 drh: assert( TK_BITNOT==OP_BitNot ); dbda8d6ce9 2007-07-21 drh: assert( TK_NOT==OP_Not ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, 0, 0); dbda8d6ce9 2007-07-21 drh: stackChng = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_ISNULL: dbda8d6ce9 2007-07-21 drh: case TK_NOTNULL: { dbda8d6ce9 2007-07-21 drh: int dest; dbda8d6ce9 2007-07-21 drh: assert( TK_ISNULL==OP_IsNull ); dbda8d6ce9 2007-07-21 drh: assert( TK_NOTNULL==OP_NotNull ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: dest = sqlite3VdbeCurrentAddr(v) + 2; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, 1, dest); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); dbda8d6ce9 2007-07-21 drh: stackChng = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_AGG_FUNCTION: { dbda8d6ce9 2007-07-21 drh: AggInfo *pInfo = pExpr->pAggInfo; dbda8d6ce9 2007-07-21 drh: if( pInfo==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "misuse of aggregate: %T", dbda8d6ce9 2007-07-21 drh: &pExpr->span); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_CONST_FUNC: dbda8d6ce9 2007-07-21 drh: case TK_FUNCTION: { dbda8d6ce9 2007-07-21 drh: ExprList *pList = pExpr->pList; dbda8d6ce9 2007-07-21 drh: int nExpr = pList ? pList->nExpr : 0; dbda8d6ce9 2007-07-21 drh: FuncDef *pDef; dbda8d6ce9 2007-07-21 drh: int nId; dbda8d6ce9 2007-07-21 drh: const char *zId; dbda8d6ce9 2007-07-21 drh: int constMask = 0; dbda8d6ce9 2007-07-21 drh: int i; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; c287665ba8 2007-09-14 drh: u8 enc = ENC(db); dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = 0; c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: zId = (char*)pExpr->token.z; dbda8d6ce9 2007-07-21 drh: nId = pExpr->token.n; dbda8d6ce9 2007-07-21 drh: pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0); dbda8d6ce9 2007-07-21 drh: assert( pDef!=0 ); dbda8d6ce9 2007-07-21 drh: nExpr = sqlite3ExprCodeExprList(pParse, pList); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Possibly overload the function if the first argument is dbda8d6ce9 2007-07-21 drh: ** a virtual table column. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For infix functions (LIKE, GLOB, REGEXP, and MATCH) use the dbda8d6ce9 2007-07-21 drh: ** second argument, not the first, as the argument to test to dbda8d6ce9 2007-07-21 drh: ** see if it is a column in a virtual table. This is done because dbda8d6ce9 2007-07-21 drh: ** the left operand of infix functions (the operand we want to dbda8d6ce9 2007-07-21 drh: ** control overloading) ends up as the second argument to the dbda8d6ce9 2007-07-21 drh: ** function. The expression "A glob B" is equivalent to dbda8d6ce9 2007-07-21 drh: ** "glob(B,A). We want to use the A in "A glob B" to test dbda8d6ce9 2007-07-21 drh: ** for function overloading. But we use the B term in "glob(B,A)". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( nExpr>=2 && (pExpr->flags & EP_InfixFunc) ){ c287665ba8 2007-09-14 drh: pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[1].pExpr); dbda8d6ce9 2007-07-21 drh: }else if( nExpr>0 ){ c287665ba8 2007-09-14 drh: pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[0].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: for(i=0; i<nExpr && i<32; i++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){ dbda8d6ce9 2007-07-21 drh: constMask |= (1<<i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDef->needCollSeq && !pColl ){ dbda8d6ce9 2007-07-21 drh: pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDef->needCollSeq ){ dbda8d6ce9 2007-07-21 drh: if( !pColl ) pColl = pParse->db->pDfltColl; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF); dbda8d6ce9 2007-07-21 drh: stackChng = 1-nExpr; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: case TK_EXISTS: dbda8d6ce9 2007-07-21 drh: case TK_SELECT: { dbda8d6ce9 2007-07-21 drh: if( pExpr->iColumn==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3CodeSubselect(pParse, pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# load subquery result")); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_IN: { dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: char affinity; dbda8d6ce9 2007-07-21 drh: int ckOffset = pParse->ckOffset; dbda8d6ce9 2007-07-21 drh: sqlite3CodeSubselect(pParse, pExpr); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out the affinity to use to create a key from the results dbda8d6ce9 2007-07-21 drh: ** of the expression. affinityStr stores a static string suitable for dbda8d6ce9 2007-07-21 drh: ** P3 of OP_MakeRecord. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: affinity = comparisonAffinity(pExpr); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, 1, 0); dbda8d6ce9 2007-07-21 drh: pParse->ckOffset = (ckOffset ? (ckOffset+1) : 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Code the <expr> from "<expr> IN (...)". The temporary table dbda8d6ce9 2007-07-21 drh: ** pExpr->iTable contains the values that make up the (...) set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+4); /* addr + 0 */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 2, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, addr+7); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); /* addr + 4 */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Found, pExpr->iTable, addr+7); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); /* addr + 6 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: case TK_BETWEEN: { dbda8d6ce9 2007-07-21 drh: Expr *pLeft = pExpr->pLeft; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pLItem = pExpr->pList->a; dbda8d6ce9 2007-07-21 drh: Expr *pRight = pLItem->pExpr; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pRight); dbda8d6ce9 2007-07-21 drh: codeCompare(pParse, pLeft, pRight, OP_Ge, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pull, 1, 0); dbda8d6ce9 2007-07-21 drh: pLItem++; dbda8d6ce9 2007-07-21 drh: pRight = pLItem->pExpr; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pRight); dbda8d6ce9 2007-07-21 drh: codeCompare(pParse, pLeft, pRight, OP_Le, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_And, 0, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_UPLUS: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: stackChng = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_CASE: { dbda8d6ce9 2007-07-21 drh: int expr_end_label; dbda8d6ce9 2007-07-21 drh: int jumpInst; dbda8d6ce9 2007-07-21 drh: int nExpr; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: ExprList *pEList; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *aListelem; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert(pExpr->pList); dbda8d6ce9 2007-07-21 drh: assert((pExpr->pList->nExpr % 2) == 0); dbda8d6ce9 2007-07-21 drh: assert(pExpr->pList->nExpr > 0); dbda8d6ce9 2007-07-21 drh: pEList = pExpr->pList; dbda8d6ce9 2007-07-21 drh: aListelem = pEList->a; dbda8d6ce9 2007-07-21 drh: nExpr = pEList->nExpr; dbda8d6ce9 2007-07-21 drh: expr_end_label = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: if( pExpr->pLeft ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<nExpr; i=i+2){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, aListelem[i].pExpr); dbda8d6ce9 2007-07-21 drh: if( pExpr->pLeft ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 1, 1); dbda8d6ce9 2007-07-21 drh: jumpInst = codeCompare(pParse, pExpr->pLeft, aListelem[i].pExpr, dbda8d6ce9 2007-07-21 drh: OP_Ne, 0, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: jumpInst = sqlite3VdbeAddOp(v, OP_IfNot, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, aListelem[i+1].pExpr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, jumpInst); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pExpr->pLeft ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pExpr->pRight ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pRight); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, expr_end_label); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: case TK_RAISE: { dbda8d6ce9 2007-07-21 drh: if( !pParse->trigStack ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "RAISE() may only be used within a trigger-program"); c287665ba8 2007-09-14 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pExpr->iColumn!=OE_Ignore ){ dbda8d6ce9 2007-07-21 drh: assert( pExpr->iColumn==OE_Rollback || dbda8d6ce9 2007-07-21 drh: pExpr->iColumn == OE_Abort || dbda8d6ce9 2007-07-21 drh: pExpr->iColumn == OE_Fail ); c287665ba8 2007-09-14 drh: sqlite3DequoteExpr(pParse->db, pExpr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, dbda8d6ce9 2007-07-21 drh: (char*)pExpr->token.z, pExpr->token.n); dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: assert( pExpr->iColumn == OE_Ignore ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# raise(IGNORE)")); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: stackChng = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParse->ckOffset ){ dbda8d6ce9 2007-07-21 drh: pParse->ckOffset += stackChng; dbda8d6ce9 2007-07-21 drh: assert( pParse->ckOffset ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that evalutes the given expression and leaves the result dbda8d6ce9 2007-07-21 drh: ** on the stack. See also sqlite3ExprCode(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine might also cache the result and modify the pExpr tree dbda8d6ce9 2007-07-21 drh: ** so that it will make use of the cached result on subsequent evaluations dbda8d6ce9 2007-07-21 drh: ** rather than evaluate the whole expression again. Trivial expressions are dbda8d6ce9 2007-07-21 drh: ** not cached. If the expression is cached, its result is stored in a dbda8d6ce9 2007-07-21 drh: ** memory location. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int iMem; dbda8d6ce9 2007-07-21 drh: int addr1, addr2; dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr); dbda8d6ce9 2007-07-21 drh: addr2 = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: if( addr2>addr1+1 || sqlite3VdbeGetOp(v, addr1)->opcode==OP_Function ){ dbda8d6ce9 2007-07-21 drh: iMem = pExpr->iTable = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iMem, 0); dbda8d6ce9 2007-07-21 drh: pExpr->op = TK_REGISTER; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that pushes the value of every element of the given dbda8d6ce9 2007-07-21 drh: ** expression list onto the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the number of elements pushed onto the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprCodeExprList( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: ExprList *pList /* The expression list to be coded */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: int i, n; dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return 0; dbda8d6ce9 2007-07-21 drh: n = pList->nExpr; dbda8d6ce9 2007-07-21 drh: for(pItem=pList->a, i=n; i>0; i--, pItem++){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pItem->pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for a boolean expression such that a jump is made dbda8d6ce9 2007-07-21 drh: ** to the label "dest" if the expression is true but execution dbda8d6ce9 2007-07-21 drh: ** continues straight thru if the expression is false. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the expression evaluates to NULL (neither true nor false), then dbda8d6ce9 2007-07-21 drh: ** take the jump if the jumpIfNull flag is true. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This code depends on the fact that certain token values (ex: TK_EQ) dbda8d6ce9 2007-07-21 drh: ** are the same as opcode values (ex: OP_Eq) that implement the corresponding dbda8d6ce9 2007-07-21 drh: ** operation. Special comments in vdbe.c and the mkopcodeh.awk script in dbda8d6ce9 2007-07-21 drh: ** the make process cause these values to align. Assert()s in the code dbda8d6ce9 2007-07-21 drh: ** below verify that the numbers are aligned correctly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int op = 0; dbda8d6ce9 2007-07-21 drh: int ckOffset = pParse->ckOffset; dbda8d6ce9 2007-07-21 drh: if( v==0 || pExpr==0 ) return; dbda8d6ce9 2007-07-21 drh: op = pExpr->op; dbda8d6ce9 2007-07-21 drh: switch( op ){ dbda8d6ce9 2007-07-21 drh: case TK_AND: { dbda8d6ce9 2007-07-21 drh: int d2 = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull); dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, d2); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_OR: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_NOT: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_LT: dbda8d6ce9 2007-07-21 drh: case TK_LE: dbda8d6ce9 2007-07-21 drh: case TK_GT: dbda8d6ce9 2007-07-21 drh: case TK_GE: dbda8d6ce9 2007-07-21 drh: case TK_NE: dbda8d6ce9 2007-07-21 drh: case TK_EQ: { dbda8d6ce9 2007-07-21 drh: assert( TK_LT==OP_Lt ); dbda8d6ce9 2007-07-21 drh: assert( TK_LE==OP_Le ); dbda8d6ce9 2007-07-21 drh: assert( TK_GT==OP_Gt ); dbda8d6ce9 2007-07-21 drh: assert( TK_GE==OP_Ge ); dbda8d6ce9 2007-07-21 drh: assert( TK_EQ==OP_Eq ); dbda8d6ce9 2007-07-21 drh: assert( TK_NE==OP_Ne ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pRight); dbda8d6ce9 2007-07-21 drh: codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_ISNULL: dbda8d6ce9 2007-07-21 drh: case TK_NOTNULL: { dbda8d6ce9 2007-07-21 drh: assert( TK_ISNULL==OP_IsNull ); dbda8d6ce9 2007-07-21 drh: assert( TK_NOTNULL==OP_NotNull ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, 1, dest); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_BETWEEN: { dbda8d6ce9 2007-07-21 drh: /* The expression "x BETWEEN y AND z" is implemented as: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1 IF (x < y) GOTO 3 dbda8d6ce9 2007-07-21 drh: ** 2 IF (x <= z) GOTO <dest> dbda8d6ce9 2007-07-21 drh: ** 3 ... dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: Expr *pLeft = pExpr->pLeft; dbda8d6ce9 2007-07-21 drh: Expr *pRight = pExpr->pList->a[0].pExpr; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pRight); dbda8d6ce9 2007-07-21 drh: addr = codeCompare(pParse, pLeft, pRight, OP_Lt, 0, !jumpIfNull); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pRight = pExpr->pList->a[1].pExpr; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pRight); dbda8d6ce9 2007-07-21 drh: codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_If, jumpIfNull, dest); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->ckOffset = ckOffset; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for a boolean expression such that a jump is made dbda8d6ce9 2007-07-21 drh: ** to the label "dest" if the expression is false but execution dbda8d6ce9 2007-07-21 drh: ** continues straight thru if the expression is true. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the expression evaluates to NULL (neither true nor false) then dbda8d6ce9 2007-07-21 drh: ** jump if jumpIfNull is true or fall through if jumpIfNull is false. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int op = 0; dbda8d6ce9 2007-07-21 drh: int ckOffset = pParse->ckOffset; dbda8d6ce9 2007-07-21 drh: if( v==0 || pExpr==0 ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The value of pExpr->op and op are related as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pExpr->op op dbda8d6ce9 2007-07-21 drh: ** --------- ---------- dbda8d6ce9 2007-07-21 drh: ** TK_ISNULL OP_NotNull dbda8d6ce9 2007-07-21 drh: ** TK_NOTNULL OP_IsNull dbda8d6ce9 2007-07-21 drh: ** TK_NE OP_Eq dbda8d6ce9 2007-07-21 drh: ** TK_EQ OP_Ne dbda8d6ce9 2007-07-21 drh: ** TK_GT OP_Le dbda8d6ce9 2007-07-21 drh: ** TK_LE OP_Gt dbda8d6ce9 2007-07-21 drh: ** TK_GE OP_Lt dbda8d6ce9 2007-07-21 drh: ** TK_LT OP_Ge dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For other values of pExpr->op, op is undefined and unused. dbda8d6ce9 2007-07-21 drh: ** The value of TK_ and OP_ constants are arranged such that we dbda8d6ce9 2007-07-21 drh: ** can compute the mapping above using the following expression. dbda8d6ce9 2007-07-21 drh: ** Assert()s verify that the computation is correct. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: op = ((pExpr->op+(TK_ISNULL&1))^1)-(TK_ISNULL&1); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Verify correct alignment of TK_ and OP_ constants dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pExpr->op!=TK_ISNULL || op==OP_NotNull ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->op!=TK_NOTNULL || op==OP_IsNull ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->op!=TK_NE || op==OP_Eq ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->op!=TK_EQ || op==OP_Ne ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->op!=TK_LT || op==OP_Ge ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->op!=TK_LE || op==OP_Gt ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->op!=TK_GT || op==OP_Le ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->op!=TK_GE || op==OP_Lt ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: switch( pExpr->op ){ dbda8d6ce9 2007-07-21 drh: case TK_AND: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_OR: { dbda8d6ce9 2007-07-21 drh: int d2 = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, !jumpIfNull); dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, d2); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_NOT: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_LT: dbda8d6ce9 2007-07-21 drh: case TK_LE: dbda8d6ce9 2007-07-21 drh: case TK_GT: dbda8d6ce9 2007-07-21 drh: case TK_GE: dbda8d6ce9 2007-07-21 drh: case TK_NE: dbda8d6ce9 2007-07-21 drh: case TK_EQ: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pRight); dbda8d6ce9 2007-07-21 drh: codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_ISNULL: dbda8d6ce9 2007-07-21 drh: case TK_NOTNULL: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, 1, dest); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_BETWEEN: { dbda8d6ce9 2007-07-21 drh: /* The expression is "x BETWEEN y AND z". It is implemented as: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1 IF (x >= y) GOTO 3 dbda8d6ce9 2007-07-21 drh: ** 2 GOTO <dest> dbda8d6ce9 2007-07-21 drh: ** 3 IF (x > z) GOTO <dest> dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: Expr *pLeft = pExpr->pLeft; dbda8d6ce9 2007-07-21 drh: Expr *pRight = pExpr->pList->a[0].pExpr; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pLeft); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pRight); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: codeCompare(pParse, pLeft, pRight, OP_Ge, addr+3, !jumpIfNull); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, dest); dbda8d6ce9 2007-07-21 drh: pRight = pExpr->pList->a[1].pExpr; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pRight); dbda8d6ce9 2007-07-21 drh: codeCompare(pParse, pLeft, pRight, OP_Gt, dest, jumpIfNull); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pExpr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IfNot, jumpIfNull, dest); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->ckOffset = ckOffset; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Do a deep comparison of two expression trees. Return TRUE (non-zero) dbda8d6ce9 2007-07-21 drh: ** if they are identical and return FALSE if they differ in any way. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Sometimes this routine will return FALSE even if the two expressions dbda8d6ce9 2007-07-21 drh: ** really are equivalent. If we cannot prove that the expressions are dbda8d6ce9 2007-07-21 drh: ** identical, we return FALSE just to be safe. So if this routine dbda8d6ce9 2007-07-21 drh: ** returns false, then you do not really know for certain if the two dbda8d6ce9 2007-07-21 drh: ** expressions are the same. But if you get a TRUE return, then you dbda8d6ce9 2007-07-21 drh: ** can be sure the expressions are the same. In the places where dbda8d6ce9 2007-07-21 drh: ** this routine is used, it does not hurt to get an extra FALSE - that dbda8d6ce9 2007-07-21 drh: ** just might result in some slightly slower code. But returning dbda8d6ce9 2007-07-21 drh: ** an incorrect TRUE could lead to a malfunction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( pA==0||pB==0 ){ dbda8d6ce9 2007-07-21 drh: return pB==pA; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pA->op!=pB->op ) return 0; dbda8d6ce9 2007-07-21 drh: if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0; dbda8d6ce9 2007-07-21 drh: if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0; dbda8d6ce9 2007-07-21 drh: if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0; dbda8d6ce9 2007-07-21 drh: if( pA->pList ){ dbda8d6ce9 2007-07-21 drh: if( pB->pList==0 ) return 0; dbda8d6ce9 2007-07-21 drh: if( pA->pList->nExpr!=pB->pList->nExpr ) return 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pA->pList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: if( !sqlite3ExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pB->pList ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pA->pSelect || pB->pSelect ) return 0; dbda8d6ce9 2007-07-21 drh: if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0; dbda8d6ce9 2007-07-21 drh: if( pA->op!=TK_COLUMN && pA->token.z ){ dbda8d6ce9 2007-07-21 drh: if( pB->token.z==0 ) return 0; dbda8d6ce9 2007-07-21 drh: if( pB->token.n!=pA->token.n ) return 0; dbda8d6ce9 2007-07-21 drh: if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a new element to the pAggInfo->aCol[] array. Return the index of dbda8d6ce9 2007-07-21 drh: ** the new element. Return a negative number if malloc fails. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: pInfo->aCol = sqlite3ArrayAllocate( c287665ba8 2007-09-14 drh: db, dbda8d6ce9 2007-07-21 drh: pInfo->aCol, dbda8d6ce9 2007-07-21 drh: sizeof(pInfo->aCol[0]), dbda8d6ce9 2007-07-21 drh: 3, dbda8d6ce9 2007-07-21 drh: &pInfo->nColumn, dbda8d6ce9 2007-07-21 drh: &pInfo->nColumnAlloc, dbda8d6ce9 2007-07-21 drh: &i dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a new element to the pAggInfo->aFunc[] array. Return the index of dbda8d6ce9 2007-07-21 drh: ** the new element. Return a negative number if malloc fails. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: pInfo->aFunc = sqlite3ArrayAllocate( c287665ba8 2007-09-14 drh: db, dbda8d6ce9 2007-07-21 drh: pInfo->aFunc, dbda8d6ce9 2007-07-21 drh: sizeof(pInfo->aFunc[0]), dbda8d6ce9 2007-07-21 drh: 3, dbda8d6ce9 2007-07-21 drh: &pInfo->nFunc, dbda8d6ce9 2007-07-21 drh: &pInfo->nFuncAlloc, dbda8d6ce9 2007-07-21 drh: &i dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is an xFunc for walkExprTree() used to implement dbda8d6ce9 2007-07-21 drh: ** sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates dbda8d6ce9 2007-07-21 drh: ** for additional information. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine analyzes the aggregate function at pExpr. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int analyzeAggregate(void *pArg, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: NameContext *pNC = (NameContext *)pArg; dbda8d6ce9 2007-07-21 drh: Parse *pParse = pNC->pParse; dbda8d6ce9 2007-07-21 drh: SrcList *pSrcList = pNC->pSrcList; dbda8d6ce9 2007-07-21 drh: AggInfo *pAggInfo = pNC->pAggInfo; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: switch( pExpr->op ){ dbda8d6ce9 2007-07-21 drh: case TK_AGG_COLUMN: dbda8d6ce9 2007-07-21 drh: case TK_COLUMN: { dbda8d6ce9 2007-07-21 drh: /* Check to see if the column is in one of the tables in the FROM dbda8d6ce9 2007-07-21 drh: ** clause of the aggregate query */ dbda8d6ce9 2007-07-21 drh: if( pSrcList ){ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem = pSrcList->a; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pSrcList->nSrc; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: struct AggInfo_col *pCol; dbda8d6ce9 2007-07-21 drh: if( pExpr->iTable==pItem->iCursor ){ dbda8d6ce9 2007-07-21 drh: /* If we reach this point, it means that pExpr refers to a table dbda8d6ce9 2007-07-21 drh: ** that is in the FROM clause of the aggregate query. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Make an entry for the column in pAggInfo->aCol[] if there dbda8d6ce9 2007-07-21 drh: ** is not an entry there already. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int k; dbda8d6ce9 2007-07-21 drh: pCol = pAggInfo->aCol; dbda8d6ce9 2007-07-21 drh: for(k=0; k<pAggInfo->nColumn; k++, pCol++){ dbda8d6ce9 2007-07-21 drh: if( pCol->iTable==pExpr->iTable && dbda8d6ce9 2007-07-21 drh: pCol->iColumn==pExpr->iColumn ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( (k>=pAggInfo->nColumn) c287665ba8 2007-09-14 drh: && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: pCol = &pAggInfo->aCol[k]; dbda8d6ce9 2007-07-21 drh: pCol->pTab = pExpr->pTab; dbda8d6ce9 2007-07-21 drh: pCol->iTable = pExpr->iTable; dbda8d6ce9 2007-07-21 drh: pCol->iColumn = pExpr->iColumn; dbda8d6ce9 2007-07-21 drh: pCol->iMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: pCol->iSorterColumn = -1; dbda8d6ce9 2007-07-21 drh: pCol->pExpr = pExpr; dbda8d6ce9 2007-07-21 drh: if( pAggInfo->pGroupBy ){ dbda8d6ce9 2007-07-21 drh: int j, n; dbda8d6ce9 2007-07-21 drh: ExprList *pGB = pAggInfo->pGroupBy; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pTerm = pGB->a; dbda8d6ce9 2007-07-21 drh: n = pGB->nExpr; dbda8d6ce9 2007-07-21 drh: for(j=0; j<n; j++, pTerm++){ dbda8d6ce9 2007-07-21 drh: Expr *pE = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable && dbda8d6ce9 2007-07-21 drh: pE->iColumn==pExpr->iColumn ){ dbda8d6ce9 2007-07-21 drh: pCol->iSorterColumn = j; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCol->iSorterColumn<0 ){ dbda8d6ce9 2007-07-21 drh: pCol->iSorterColumn = pAggInfo->nSortingColumn++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* There is now an entry for pExpr in pAggInfo->aCol[] (either dbda8d6ce9 2007-07-21 drh: ** because it was there before or because we just created it). dbda8d6ce9 2007-07-21 drh: ** Convert the pExpr to be a TK_AGG_COLUMN referring to that dbda8d6ce9 2007-07-21 drh: ** pAggInfo->aCol[] entry. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pExpr->pAggInfo = pAggInfo; dbda8d6ce9 2007-07-21 drh: pExpr->op = TK_AGG_COLUMN; dbda8d6ce9 2007-07-21 drh: pExpr->iAgg = k; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } /* endif pExpr->iTable==pItem->iCursor */ dbda8d6ce9 2007-07-21 drh: } /* end loop over pSrcList */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_AGG_FUNCTION: { dbda8d6ce9 2007-07-21 drh: /* The pNC->nDepth==0 test causes aggregate functions in subqueries dbda8d6ce9 2007-07-21 drh: ** to be ignored */ dbda8d6ce9 2007-07-21 drh: if( pNC->nDepth==0 ){ dbda8d6ce9 2007-07-21 drh: /* Check to see if pExpr is a duplicate of another aggregate dbda8d6ce9 2007-07-21 drh: ** function that is already in the pAggInfo structure dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct AggInfo_func *pItem = pAggInfo->aFunc; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pAggInfo->nFunc; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i>=pAggInfo->nFunc ){ dbda8d6ce9 2007-07-21 drh: /* pExpr is original. Make a new entry in pAggInfo->aFunc[] dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: u8 enc = ENC(pParse->db); c287665ba8 2007-09-14 drh: i = addAggInfoFunc(pParse->db, pAggInfo); dbda8d6ce9 2007-07-21 drh: if( i>=0 ){ dbda8d6ce9 2007-07-21 drh: pItem = &pAggInfo->aFunc[i]; dbda8d6ce9 2007-07-21 drh: pItem->pExpr = pExpr; dbda8d6ce9 2007-07-21 drh: pItem->iMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: pItem->pFunc = sqlite3FindFunction(pParse->db, dbda8d6ce9 2007-07-21 drh: (char*)pExpr->token.z, pExpr->token.n, dbda8d6ce9 2007-07-21 drh: pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); dbda8d6ce9 2007-07-21 drh: if( pExpr->flags & EP_Distinct ){ dbda8d6ce9 2007-07-21 drh: pItem->iDistinct = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pItem->iDistinct = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Make pExpr point to the appropriate pAggInfo->aFunc[] entry dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pExpr->iAgg = i; dbda8d6ce9 2007-07-21 drh: pExpr->pAggInfo = pAggInfo; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Recursively walk subqueries looking for TK_COLUMN nodes that need dbda8d6ce9 2007-07-21 drh: ** to be changed to TK_AGG_COLUMN. But increment nDepth so that dbda8d6ce9 2007-07-21 drh: ** TK_AGG_FUNCTION nodes in subqueries will be unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pExpr->pSelect ){ dbda8d6ce9 2007-07-21 drh: pNC->nDepth++; dbda8d6ce9 2007-07-21 drh: walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC); dbda8d6ce9 2007-07-21 drh: pNC->nDepth--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Analyze the given expression looking for aggregate functions and dbda8d6ce9 2007-07-21 drh: ** for variables that need to be added to the pParse->aAgg[] array. dbda8d6ce9 2007-07-21 drh: ** Make additional entries to the pParse->aAgg[] array as necessary. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine should only be called after the expression has been dbda8d6ce9 2007-07-21 drh: ** analyzed by sqlite3ExprResolveNames(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If errors are seen, leave an error message in zErrMsg and return dbda8d6ce9 2007-07-21 drh: ** the number of errors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: int nErr = pNC->pParse->nErr; dbda8d6ce9 2007-07-21 drh: walkExprTree(pExpr, analyzeAggregate, pNC); dbda8d6ce9 2007-07-21 drh: return pNC->pParse->nErr - nErr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Call sqlite3ExprAnalyzeAggregates() for every expression in an dbda8d6ce9 2007-07-21 drh: ** expression list. Return the number of errors. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an error is found, the analysis is cut short. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nErr = 0; dbda8d6ce9 2007-07-21 drh: if( pList ){ dbda8d6ce9 2007-07-21 drh: for(pItem=pList->a, i=0; nErr==0 && i<pList->nExpr; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: nErr += sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return nErr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of expr.c ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file alter.c *******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2005 February 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains C code routines that used to generate VDBE code dbda8d6ce9 2007-07-21 drh: ** that implements the ALTER TABLE command. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: alter.c,v 1.32 2007/08/29 14:06:23 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The code in this file only exists if we are not omitting the dbda8d6ce9 2007-07-21 drh: ** ALTER TABLE logic from the build. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_ALTERTABLE dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is used by SQL generated to implement the dbda8d6ce9 2007-07-21 drh: ** ALTER TABLE command. The first argument is the text of a CREATE TABLE or dbda8d6ce9 2007-07-21 drh: ** CREATE INDEX command. The second is a table name. The table name in dbda8d6ce9 2007-07-21 drh: ** the CREATE TABLE or CREATE INDEX statement is replaced with the third dbda8d6ce9 2007-07-21 drh: ** argument and the result returned. Examples: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') dbda8d6ce9 2007-07-21 drh: ** -> 'CREATE TABLE def(a, b, c)' dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def') dbda8d6ce9 2007-07-21 drh: ** -> 'CREATE INDEX i ON def(a, b, c)' dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void renameTableFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: unsigned char const *zSql = sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: unsigned char const *zTableName = sqlite3_value_text(argv[1]); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int token; dbda8d6ce9 2007-07-21 drh: Token tname; dbda8d6ce9 2007-07-21 drh: unsigned char const *zCsr = zSql; dbda8d6ce9 2007-07-21 drh: int len = 0; dbda8d6ce9 2007-07-21 drh: char *zRet; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3 *db = sqlite3_user_data(context); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* The principle used to locate the table name in the CREATE TABLE dbda8d6ce9 2007-07-21 drh: ** statement is that the table name is the first token that is immediatedly dbda8d6ce9 2007-07-21 drh: ** followed by a left parenthesis - TK_LP - or "USING" TK_USING. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( zSql ){ dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: if( !*zCsr ){ dbda8d6ce9 2007-07-21 drh: /* Ran out of input before finding an opening bracket. Return NULL. */ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Store the token that zCsr points to in tname. */ dbda8d6ce9 2007-07-21 drh: tname.z = zCsr; dbda8d6ce9 2007-07-21 drh: tname.n = len; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Advance zCsr to the next token. Store that token type in 'token', dbda8d6ce9 2007-07-21 drh: ** and it's length in 'len' (to be used next iteration of this loop). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: zCsr += len; dbda8d6ce9 2007-07-21 drh: len = sqlite3GetToken(zCsr, &token); dbda8d6ce9 2007-07-21 drh: } while( token==TK_SPACE ); dbda8d6ce9 2007-07-21 drh: assert( len>0 ); dbda8d6ce9 2007-07-21 drh: } while( token!=TK_LP && token!=TK_USING ); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: zRet = sqlite3MPrintf(db, "%.*s%Q%s", tname.z - zSql, zSql, dbda8d6ce9 2007-07-21 drh: zTableName, tname.z+tname.n); c287665ba8 2007-09-14 drh: sqlite3_result_text(context, zRet, -1, sqlite3_free); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: /* This function is used by SQL generated to implement the dbda8d6ce9 2007-07-21 drh: ** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER dbda8d6ce9 2007-07-21 drh: ** statement. The second is a table name. The table name in the CREATE dbda8d6ce9 2007-07-21 drh: ** TRIGGER statement is replaced with the third argument and the result dbda8d6ce9 2007-07-21 drh: ** returned. This is analagous to renameTableFunc() above, except for CREATE dbda8d6ce9 2007-07-21 drh: ** TRIGGER, not CREATE INDEX and CREATE TABLE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void renameTriggerFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: unsigned char const *zSql = sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: unsigned char const *zTableName = sqlite3_value_text(argv[1]); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int token; dbda8d6ce9 2007-07-21 drh: Token tname; dbda8d6ce9 2007-07-21 drh: int dist = 3; dbda8d6ce9 2007-07-21 drh: unsigned char const *zCsr = zSql; dbda8d6ce9 2007-07-21 drh: int len = 0; dbda8d6ce9 2007-07-21 drh: char *zRet; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3 *db = sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The principle used to locate the table name in the CREATE TRIGGER dbda8d6ce9 2007-07-21 drh: ** statement is that the table name is the first token that is immediatedly dbda8d6ce9 2007-07-21 drh: ** preceded by either TK_ON or TK_DOT and immediatedly followed by one dbda8d6ce9 2007-07-21 drh: ** of TK_WHEN, TK_BEGIN or TK_FOR. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( zSql ){ dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !*zCsr ){ dbda8d6ce9 2007-07-21 drh: /* Ran out of input before finding the table name. Return NULL. */ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Store the token that zCsr points to in tname. */ dbda8d6ce9 2007-07-21 drh: tname.z = zCsr; dbda8d6ce9 2007-07-21 drh: tname.n = len; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Advance zCsr to the next token. Store that token type in 'token', dbda8d6ce9 2007-07-21 drh: ** and it's length in 'len' (to be used next iteration of this loop). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: zCsr += len; dbda8d6ce9 2007-07-21 drh: len = sqlite3GetToken(zCsr, &token); dbda8d6ce9 2007-07-21 drh: }while( token==TK_SPACE ); dbda8d6ce9 2007-07-21 drh: assert( len>0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Variable 'dist' stores the number of tokens read since the most dbda8d6ce9 2007-07-21 drh: ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN dbda8d6ce9 2007-07-21 drh: ** token is read and 'dist' equals 2, the condition stated above dbda8d6ce9 2007-07-21 drh: ** to be met. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that ON cannot be a database, table or column name, so dbda8d6ce9 2007-07-21 drh: ** there is no need to worry about syntax like dbda8d6ce9 2007-07-21 drh: ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dist++; dbda8d6ce9 2007-07-21 drh: if( token==TK_DOT || token==TK_ON ){ dbda8d6ce9 2007-07-21 drh: dist = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Variable tname now contains the token that is the old table-name dbda8d6ce9 2007-07-21 drh: ** in the CREATE TRIGGER statement. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: zRet = sqlite3MPrintf(db, "%.*s%Q%s", tname.z - zSql, zSql, dbda8d6ce9 2007-07-21 drh: zTableName, tname.z+tname.n); c287665ba8 2007-09-14 drh: sqlite3_result_text(context, zRet, -1, sqlite3_free); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !SQLITE_OMIT_TRIGGER */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register built-in functions used to help implement ALTER TABLE dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AlterFunctions(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: static const struct { dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: signed char nArg; dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value **); dbda8d6ce9 2007-07-21 drh: } aFuncs[] = { dbda8d6ce9 2007-07-21 drh: { "sqlite_rename_table", 2, renameTableFunc}, dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: { "sqlite_rename_trigger", 2, renameTriggerFunc}, dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg, c287665ba8 2007-09-14 drh: SQLITE_UTF8, (void *)db, aFuncs[i].xFunc, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate the text of a WHERE expression which can be used to select all dbda8d6ce9 2007-07-21 drh: ** temporary triggers on table pTab from the sqlite_temp_master table. If dbda8d6ce9 2007-07-21 drh: ** table pTab has no temporary triggers, or is itself stored in the dbda8d6ce9 2007-07-21 drh: ** temporary database, NULL is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char *whereTempTriggers(Parse *pParse, Table *pTab){ dbda8d6ce9 2007-07-21 drh: Trigger *pTrig; dbda8d6ce9 2007-07-21 drh: char *zWhere = 0; dbda8d6ce9 2007-07-21 drh: char *tmp = 0; dbda8d6ce9 2007-07-21 drh: const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the table is not located in the temp-db (in which case NULL is dbda8d6ce9 2007-07-21 drh: ** returned, loop through the tables list of triggers. For each trigger dbda8d6ce9 2007-07-21 drh: ** that is not part of the temp-db schema, add a clause to the WHERE dbda8d6ce9 2007-07-21 drh: ** expression being built up in zWhere. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTab->pSchema!=pTempSchema ){ c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ dbda8d6ce9 2007-07-21 drh: if( pTrig->pSchema==pTempSchema ){ dbda8d6ce9 2007-07-21 drh: if( !zWhere ){ c287665ba8 2007-09-14 drh: zWhere = sqlite3MPrintf(db, "name=%Q", pTrig->name); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: tmp = zWhere; c287665ba8 2007-09-14 drh: zWhere = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, pTrig->name); c287665ba8 2007-09-14 drh: sqlite3_free(tmp); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zWhere; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code to drop and reload the internal representation of table dbda8d6ce9 2007-07-21 drh: ** pTab from the database, including triggers and temporary triggers. dbda8d6ce9 2007-07-21 drh: ** Argument zName is the name of the table in the database schema at dbda8d6ce9 2007-07-21 drh: ** the time the generated code is executed. This can be different from dbda8d6ce9 2007-07-21 drh: ** pTab->zName if this function is being called to code part of an dbda8d6ce9 2007-07-21 drh: ** "ALTER TABLE RENAME TO" statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: char *zWhere; dbda8d6ce9 2007-07-21 drh: int iDb; /* Index of database containing pTab */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: Trigger *pTrig; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( !v ) return; c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: /* Drop any table triggers from the internal schema. */ dbda8d6ce9 2007-07-21 drh: for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){ dbda8d6ce9 2007-07-21 drh: int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iTrigDb==iDb || iTrigDb==1 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Drop the table and index from the internal schema */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Reload the table, index and permanent trigger schemas. */ c287665ba8 2007-09-14 drh: zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName); dbda8d6ce9 2007-07-21 drh: if( !zWhere ) return; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: /* Now, if the table is not stored in the temp database, reload any temp dbda8d6ce9 2007-07-21 drh: ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" dbda8d6ce9 2007-07-21 drh: ** command. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AlterRenameTable( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context. */ dbda8d6ce9 2007-07-21 drh: SrcList *pSrc, /* The table to rename. */ dbda8d6ce9 2007-07-21 drh: Token *pName /* The new table name. */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int iDb; /* Database that contains the table */ dbda8d6ce9 2007-07-21 drh: char *zDb; /* Name of database iDb */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* Table being renamed */ dbda8d6ce9 2007-07-21 drh: char *zName = 0; /* NULL-terminated version of pName */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; /* Database connection */ dbda8d6ce9 2007-07-21 drh: int nTabName; /* Number of UTF-8 characters in zTabName */ dbda8d6ce9 2007-07-21 drh: const char *zTabName; /* Original name of the table */ dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: char *zWhere = 0; /* Where clause to locate temp triggers */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: int isVirtualRename = 0; /* True if this is a v-table with an xRename() */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( db->mallocFailed ) goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: assert( pSrc->nSrc==1 ); c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); dbda8d6ce9 2007-07-21 drh: if( !pTab ) goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Get a NULL terminated version of the new table name. */ c287665ba8 2007-09-14 drh: zName = sqlite3NameFromToken(db, pName); dbda8d6ce9 2007-07-21 drh: if( !zName ) goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check that a table or index named 'zName' does not already exist dbda8d6ce9 2007-07-21 drh: ** in database iDb. If so, this is an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "there is already another table or index with this name: %s", zName); dbda8d6ce9 2007-07-21 drh: goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure it is not a system table being altered, or a reserved name dbda8d6ce9 2007-07-21 drh: ** that the table is being renamed to. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( strlen(pTab->zName)>6 && 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName); dbda8d6ce9 2007-07-21 drh: goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ dbda8d6ce9 2007-07-21 drh: goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: /* Invoke the authorization callback. */ dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ dbda8d6ce9 2007-07-21 drh: goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( sqlite3ViewGetColumnNames(pParse, pTab) ){ dbda8d6ce9 2007-07-21 drh: goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) && pTab->pMod->pModule->xRename ){ dbda8d6ce9 2007-07-21 drh: isVirtualRename = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin a transaction and code the VerifyCookie for database iDb. dbda8d6ce9 2007-07-21 drh: ** Then modify the schema cookie (since the ALTER TABLE modifies the dbda8d6ce9 2007-07-21 drh: ** schema). Open a statement transaction if the table is a virtual dbda8d6ce9 2007-07-21 drh: ** table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ){ dbda8d6ce9 2007-07-21 drh: goto exit_rename_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is a virtual table, invoke the xRename() function if dbda8d6ce9 2007-07-21 drh: ** one is defined. The xRename() callback will modify the names dbda8d6ce9 2007-07-21 drh: ** of any resources used by the v-table implementation (including other dbda8d6ce9 2007-07-21 drh: ** SQLite tables) that are identified by the name of the virtual table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( isVirtualRename ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VRename, 0, 0, (const char*)pTab->pVtab, P3_VTAB); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* figure out how many UTF-8 characters are in zName */ dbda8d6ce9 2007-07-21 drh: zTabName = pTab->zName; dbda8d6ce9 2007-07-21 drh: nTabName = sqlite3Utf8CharLen(zTabName, -1); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Modify the sqlite_master table to use the new table name. */ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "UPDATE %Q.%s SET " dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: "sql = sqlite_rename_table(sql, %Q), " dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: "sql = CASE " dbda8d6ce9 2007-07-21 drh: "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" dbda8d6ce9 2007-07-21 drh: "ELSE sqlite_rename_table(sql, %Q) END, " dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: "tbl_name = %Q, " dbda8d6ce9 2007-07-21 drh: "name = CASE " dbda8d6ce9 2007-07-21 drh: "WHEN type='table' THEN %Q " dbda8d6ce9 2007-07-21 drh: "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " dbda8d6ce9 2007-07-21 drh: "'sqlite_autoindex_' || %Q || substr(name,%d+18,10) " dbda8d6ce9 2007-07-21 drh: "ELSE name END " dbda8d6ce9 2007-07-21 drh: "WHERE tbl_name=%Q AND " dbda8d6ce9 2007-07-21 drh: "(type='table' OR type='index' OR type='trigger');", dbda8d6ce9 2007-07-21 drh: zDb, SCHEMA_TABLE(iDb), zName, zName, zName, dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: zName, dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: zName, nTabName, zTabName dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: /* If the sqlite_sequence table exists in this database, then update dbda8d6ce9 2007-07-21 drh: ** it with the new table name. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "UPDATE %Q.sqlite_sequence set name = %Q WHERE name = %Q", dbda8d6ce9 2007-07-21 drh: zDb, zName, pTab->zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: /* If there are TEMP triggers on this table, modify the sqlite_temp_master dbda8d6ce9 2007-07-21 drh: ** table. Don't do this if the table being ALTERed is itself located in dbda8d6ce9 2007-07-21 drh: ** the temp database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "UPDATE sqlite_temp_master SET " dbda8d6ce9 2007-07-21 drh: "sql = sqlite_rename_trigger(sql, %Q), " dbda8d6ce9 2007-07-21 drh: "tbl_name = %Q " dbda8d6ce9 2007-07-21 drh: "WHERE %s;", zName, zName, zWhere); c287665ba8 2007-09-14 drh: sqlite3_free(zWhere); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Drop and reload the internal table schema. */ dbda8d6ce9 2007-07-21 drh: reloadTableSchema(pParse, pTab, zName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: exit_rename_table: dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pSrc); c287665ba8 2007-09-14 drh: sqlite3_free(zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is called after an "ALTER TABLE ... ADD" statement dbda8d6ce9 2007-07-21 drh: ** has been parsed. Argument pColDef contains the text of the new dbda8d6ce9 2007-07-21 drh: ** column definition. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The Table structure pParse->pNewTable was extended to include dbda8d6ce9 2007-07-21 drh: ** the new column during parsing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ dbda8d6ce9 2007-07-21 drh: Table *pNew; /* Copy of pParse->pNewTable */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* Table being altered */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Database number */ dbda8d6ce9 2007-07-21 drh: const char *zDb; /* Database name */ dbda8d6ce9 2007-07-21 drh: const char *zTab; /* Table name */ dbda8d6ce9 2007-07-21 drh: char *zCol; /* Null-terminated column definition */ dbda8d6ce9 2007-07-21 drh: Column *pCol; /* The new column */ dbda8d6ce9 2007-07-21 drh: Expr *pDflt; /* Default value for the new column */ c287665ba8 2007-09-14 drh: sqlite3 *db; /* The database connection; */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParse->nErr ) return; dbda8d6ce9 2007-07-21 drh: pNew = pParse->pNewTable; dbda8d6ce9 2007-07-21 drh: assert( pNew ); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: db = pParse->db; c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsAllMutexes(db) ); c287665ba8 2007-09-14 drh: iDb = sqlite3SchemaToIndex(db, pNew->pSchema); c287665ba8 2007-09-14 drh: zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: zTab = pNew->zName; dbda8d6ce9 2007-07-21 drh: pCol = &pNew->aCol[pNew->nCol-1]; dbda8d6ce9 2007-07-21 drh: pDflt = pCol->pDflt; c287665ba8 2007-09-14 drh: pTab = sqlite3FindTable(db, zTab, zDb); dbda8d6ce9 2007-07-21 drh: assert( pTab ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: /* Invoke the authorization callback. */ dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the default value for the new column was specified with a dbda8d6ce9 2007-07-21 drh: ** literal NULL, then set pDflt to 0. This simplifies checking dbda8d6ce9 2007-07-21 drh: ** for an SQL NULL default below. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pDflt && pDflt->op==TK_NULL ){ dbda8d6ce9 2007-07-21 drh: pDflt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. dbda8d6ce9 2007-07-21 drh: ** If there is a NOT NULL constraint, then the default value for the dbda8d6ce9 2007-07-21 drh: ** column must not be NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pCol->isPrimKey ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pNew->pIndex ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pCol->notNull && !pDflt ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "Cannot add a NOT NULL column with default value NULL"); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Ensure the default expression is something that sqlite3ValueFromExpr() dbda8d6ce9 2007-07-21 drh: ** can handle (i.e. not CURRENT_TIME etc.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pDflt ){ dbda8d6ce9 2007-07-21 drh: sqlite3_value *pVal; c287665ba8 2007-09-14 drh: if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pVal ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree(pVal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Modify the CREATE TABLE statement. */ c287665ba8 2007-09-14 drh: zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); dbda8d6ce9 2007-07-21 drh: if( zCol ){ dbda8d6ce9 2007-07-21 drh: char *zEnd = &zCol[pColDef->n-1]; dbda8d6ce9 2007-07-21 drh: while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){ dbda8d6ce9 2007-07-21 drh: *zEnd-- = '\0'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "UPDATE %Q.%s SET " dbda8d6ce9 2007-07-21 drh: "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d,length(sql)) " dbda8d6ce9 2007-07-21 drh: "WHERE type = 'table' AND name = %Q", dbda8d6ce9 2007-07-21 drh: zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, dbda8d6ce9 2007-07-21 drh: zTab dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: sqlite3_free(zCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the default value of the new column is NULL, then set the file dbda8d6ce9 2007-07-21 drh: ** format to 2. If the default value of the new column is not NULL, dbda8d6ce9 2007-07-21 drh: ** the file format becomes 3. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Reload the schema of the modified table. */ dbda8d6ce9 2007-07-21 drh: reloadTableSchema(pParse, pTab, pTab->zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is called by the parser after the table-name in dbda8d6ce9 2007-07-21 drh: ** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument dbda8d6ce9 2007-07-21 drh: ** pSrc is the full-name of the table being altered. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine makes a (partial) copy of the Table structure dbda8d6ce9 2007-07-21 drh: ** for the table being altered and sets Parse.pNewTable to point dbda8d6ce9 2007-07-21 drh: ** to it. Routines called by the parser as the column definition dbda8d6ce9 2007-07-21 drh: ** is parsed (i.e. sqlite3AddColumn()) add the new Column data to dbda8d6ce9 2007-07-21 drh: ** the copy. The copy of the Table structure is deleted by tokenize.c dbda8d6ce9 2007-07-21 drh: ** after parsing is finished. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Routine sqlite3AlterFinishAddColumn() will be called to complete dbda8d6ce9 2007-07-21 drh: ** coding the "ALTER TABLE ... ADD" statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ dbda8d6ce9 2007-07-21 drh: Table *pNew; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nAlloc; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Look up the table being altered. */ dbda8d6ce9 2007-07-21 drh: assert( pParse->pNewTable==0 ); c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsAllMutexes(db) ); c287665ba8 2007-09-14 drh: if( db->mallocFailed ) goto exit_begin_add_column; dbda8d6ce9 2007-07-21 drh: pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); dbda8d6ce9 2007-07-21 drh: if( !pTab ) goto exit_begin_add_column; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "virtual tables may not be altered"); dbda8d6ce9 2007-07-21 drh: goto exit_begin_add_column; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure this is not an attempt to ALTER a view. */ dbda8d6ce9 2007-07-21 drh: if( pTab->pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); dbda8d6ce9 2007-07-21 drh: goto exit_begin_add_column; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTab->addColOffset>0 ); c287665ba8 2007-09-14 drh: iDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Put a copy of the Table struct in Parse.pNewTable for the dbda8d6ce9 2007-07-21 drh: ** sqlite3AddColumn() function and friends to modify. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table)); dbda8d6ce9 2007-07-21 drh: if( !pNew ) goto exit_begin_add_column; dbda8d6ce9 2007-07-21 drh: pParse->pNewTable = pNew; dbda8d6ce9 2007-07-21 drh: pNew->nRef = 1; dbda8d6ce9 2007-07-21 drh: pNew->nCol = pTab->nCol; dbda8d6ce9 2007-07-21 drh: assert( pNew->nCol>0 ); dbda8d6ce9 2007-07-21 drh: nAlloc = (((pNew->nCol-1)/8)*8)+8; dbda8d6ce9 2007-07-21 drh: assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); c287665ba8 2007-09-14 drh: pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc); c287665ba8 2007-09-14 drh: pNew->zName = sqlite3DbStrDup(db, pTab->zName); dbda8d6ce9 2007-07-21 drh: if( !pNew->aCol || !pNew->zName ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: goto exit_begin_add_column; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); dbda8d6ce9 2007-07-21 drh: for(i=0; i<pNew->nCol; i++){ dbda8d6ce9 2007-07-21 drh: Column *pCol = &pNew->aCol[i]; c287665ba8 2007-09-14 drh: pCol->zName = sqlite3DbStrDup(db, pCol->zName); dbda8d6ce9 2007-07-21 drh: pCol->zColl = 0; dbda8d6ce9 2007-07-21 drh: pCol->zType = 0; dbda8d6ce9 2007-07-21 drh: pCol->pDflt = 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pNew->pSchema = db->aDb[iDb].pSchema; dbda8d6ce9 2007-07-21 drh: pNew->addColOffset = pTab->addColOffset; dbda8d6ce9 2007-07-21 drh: pNew->nRef = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin a transaction and increment the schema cookie. */ dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( !v ) goto exit_begin_add_column; c287665ba8 2007-09-14 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: exit_begin_add_column: dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pSrc); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_ALTER_TABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of alter.c ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file analyze.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2005 July 8 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code associated with the ANALYZE command. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: analyze.c,v 1.23 2007/08/29 17:43:20 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_ANALYZE dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine generates code that opens the sqlite_stat1 table on cursor dbda8d6ce9 2007-07-21 drh: ** iStatCur. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the sqlite_stat1 tables does not previously exist, it is created. dbda8d6ce9 2007-07-21 drh: ** If it does previously exist, all entires associated with table zWhere dbda8d6ce9 2007-07-21 drh: ** are removed. If zWhere==0 then all entries are removed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void openStatTable( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: int iDb, /* The database we are looking in */ dbda8d6ce9 2007-07-21 drh: int iStatCur, /* Open the sqlite_stat1 table on this cursor */ dbda8d6ce9 2007-07-21 drh: const char *zWhere /* Delete entries associated with this table */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: Db *pDb; dbda8d6ce9 2007-07-21 drh: int iRootPage; dbda8d6ce9 2007-07-21 drh: Table *pStat; dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsAllMutexes(db) ); c287665ba8 2007-09-14 drh: assert( sqlite3VdbeDb(v)==db ); dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){ dbda8d6ce9 2007-07-21 drh: /* The sqlite_stat1 tables does not exist. Create it. dbda8d6ce9 2007-07-21 drh: ** Note that a side-effect of the CREATE TABLE statement is to leave dbda8d6ce9 2007-07-21 drh: ** the rootpage of the new table on the top of the stack. This is dbda8d6ce9 2007-07-21 drh: ** important because the OpenWrite opcode below will be needing it. */ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)", dbda8d6ce9 2007-07-21 drh: pDb->zName dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: iRootPage = 0; /* Cause rootpage to be taken from top of stack */ dbda8d6ce9 2007-07-21 drh: }else if( zWhere ){ dbda8d6ce9 2007-07-21 drh: /* The sqlite_stat1 table exists. Delete all entries associated with dbda8d6ce9 2007-07-21 drh: ** the table zWhere. */ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q", dbda8d6ce9 2007-07-21 drh: pDb->zName, zWhere dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: iRootPage = pStat->tnum; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* The sqlite_stat1 table already exists. Delete all rows. */ dbda8d6ce9 2007-07-21 drh: iRootPage = pStat->tnum; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open the sqlite_stat1 table for writing. Unless it was created dbda8d6ce9 2007-07-21 drh: ** by this vdbe program, lock it for writing at the shared-cache level. dbda8d6ce9 2007-07-21 drh: ** If this vdbe did create the sqlite_stat1 table, then it must have dbda8d6ce9 2007-07-21 drh: ** already obtained a schema-lock, making the write-lock redundant. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( iRootPage>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code to do an analysis of all indices associated with dbda8d6ce9 2007-07-21 drh: ** a single table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void analyzeOneTable( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* Table whose indices are to be analyzed */ dbda8d6ce9 2007-07-21 drh: int iStatCur, /* Cursor that writes to the sqlite_stat1 table */ dbda8d6ce9 2007-07-21 drh: int iMem /* Available memory locations begin here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Index *pIdx; /* An index to being analyzed */ dbda8d6ce9 2007-07-21 drh: int iIdxCur; /* Cursor number for index being analyzed */ dbda8d6ce9 2007-07-21 drh: int nCol; /* Number of columns in the index */ dbda8d6ce9 2007-07-21 drh: Vdbe *v; /* The virtual machine being built up */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: int topOfLoop; /* The top of the loop */ dbda8d6ce9 2007-07-21 drh: int endOfLoop; /* The end of the loop */ dbda8d6ce9 2007-07-21 drh: int addr; /* The address of an instruction */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Index of database containing pTab */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 || pTab==0 || pTab->pIndex==0 ){ dbda8d6ce9 2007-07-21 drh: /* Do no analysis for tables that have no indices */ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 ); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, dbda8d6ce9 2007-07-21 drh: pParse->db->aDb[iDb].zName ) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Establish a read-lock on the table at the shared-cache level. */ dbda8d6ce9 2007-07-21 drh: sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: iIdxCur = pParse->nTab; dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open a cursor to the index to be analyzed dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# %s", pIdx->zName)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, dbda8d6ce9 2007-07-21 drh: (char *)pKey, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: nCol = pIdx->nColumn; dbda8d6ce9 2007-07-21 drh: if( iMem+nCol*2>=pParse->nMem ){ dbda8d6ce9 2007-07-21 drh: pParse->nMem = iMem+nCol*2+1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, nCol+1); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Memory cells are used as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** mem[iMem]: The total number of rows in the table. dbda8d6ce9 2007-07-21 drh: ** mem[iMem+1]: Number of distinct values in column 1 dbda8d6ce9 2007-07-21 drh: ** ... dbda8d6ce9 2007-07-21 drh: ** mem[iMem+nCol]: Number of distinct values in column N dbda8d6ce9 2007-07-21 drh: ** mem[iMem+nCol+1] Last observed value of column 1 dbda8d6ce9 2007-07-21 drh: ** ... dbda8d6ce9 2007-07-21 drh: ** mem[iMem+nCol+nCol]: Last observed value of column N dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Cells iMem through iMem+nCol are initialized to 0. The others dbda8d6ce9 2007-07-21 drh: ** are initialized to NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<=nCol; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemNull, iMem+nCol+i+1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do the analysis. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: endOfLoop = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop); dbda8d6ce9 2007-07-21 drh: topOfLoop = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem); dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Ne, 0x100, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop); dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem+i+1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, endOfLoop); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, iIdxCur, topOfLoop); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iIdxCur, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Store the results. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The result is a single row of the sqlite_stat1 table. The first dbda8d6ce9 2007-07-21 drh: ** two columns are the names of the table and index. The third column dbda8d6ce9 2007-07-21 drh: ** is a string composed of a list of integer statistics about the dbda8d6ce9 2007-07-21 drh: ** index. The first integer in the list is the total number of entires dbda8d6ce9 2007-07-21 drh: ** in the index. There is one additional integer in the list for each dbda8d6ce9 2007-07-21 drh: ** column of the table. This additional integer is a guess of how many dbda8d6ce9 2007-07-21 drh: ** rows of the table the index will select. If D is the count of distinct dbda8d6ce9 2007-07-21 drh: ** values and K is the total number of rows, then the integer is computed dbda8d6ce9 2007-07-21 drh: ** as: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** I = (K+D-1)/D dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If K==0 then no entry is made into the sqlite_stat1 table. dbda8d6ce9 2007-07-21 drh: ** If K>0 then it is always the case the D>0 so division by zero dbda8d6ce9 2007-07-21 drh: ** is never possible. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IfNot, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NewRowid, iStatCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, " ", 0); dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Add, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Divide, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ToInt, 0, 0); dbda8d6ce9 2007-07-21 drh: if( i==nCol-1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Concat, nCol*2-1, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "aaa", 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, iStatCur, OPFLAG_APPEND); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will cause the most recent index analysis to dbda8d6ce9 2007-07-21 drh: ** be laoded into internal hash tables where is can be used. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void loadAnalysis(Parse *pParse, int iDb){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_LoadAnalysis, iDb, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will do an analysis of an entire database dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void analyzeDatabase(Parse *pParse, int iDb){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ dbda8d6ce9 2007-07-21 drh: HashElem *k; dbda8d6ce9 2007-07-21 drh: int iStatCur; dbda8d6ce9 2007-07-21 drh: int iMem; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: iStatCur = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: openStatTable(pParse, iDb, iStatCur, 0); dbda8d6ce9 2007-07-21 drh: iMem = pParse->nMem; dbda8d6ce9 2007-07-21 drh: for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ dbda8d6ce9 2007-07-21 drh: Table *pTab = (Table*)sqliteHashData(k); dbda8d6ce9 2007-07-21 drh: analyzeOneTable(pParse, pTab, iStatCur, iMem); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: loadAnalysis(pParse, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will do an analysis of a single table in dbda8d6ce9 2007-07-21 drh: ** a database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void analyzeTable(Parse *pParse, Table *pTab){ dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: int iStatCur; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTab!=0 ); c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: iStatCur = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: openStatTable(pParse, iDb, iStatCur, pTab->zName); dbda8d6ce9 2007-07-21 drh: analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem); dbda8d6ce9 2007-07-21 drh: loadAnalysis(pParse, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for the ANALYZE command. The parser calls this routine dbda8d6ce9 2007-07-21 drh: ** when it recognizes an ANALYZE command. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ANALYZE -- 1 dbda8d6ce9 2007-07-21 drh: ** ANALYZE <database> -- 2 dbda8d6ce9 2007-07-21 drh: ** ANALYZE ?<database>.?<tablename> -- 3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Form 1 causes all indices in all attached databases to be analyzed. dbda8d6ce9 2007-07-21 drh: ** Form 2 analyzes all indices the single database named. dbda8d6ce9 2007-07-21 drh: ** Form 3 analyzes all indices associated with the named table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: char *z, *zDb; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: Token *pTableName; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read the database schema. If an error occurs, leave an error message dbda8d6ce9 2007-07-21 drh: ** and code in pParse and return NULL. */ c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pName1==0 ){ dbda8d6ce9 2007-07-21 drh: /* Form 1: Analyze everything */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: if( i==1 ) continue; /* Do not analyze the TEMP database */ dbda8d6ce9 2007-07-21 drh: analyzeDatabase(pParse, i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pName2==0 || pName2->n==0 ){ dbda8d6ce9 2007-07-21 drh: /* Form 2: Analyze the database or table named */ dbda8d6ce9 2007-07-21 drh: iDb = sqlite3FindDb(db, pName1); dbda8d6ce9 2007-07-21 drh: if( iDb>=0 ){ dbda8d6ce9 2007-07-21 drh: analyzeDatabase(pParse, iDb); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: z = sqlite3NameFromToken(db, pName1); dbda8d6ce9 2007-07-21 drh: pTab = sqlite3LocateTable(pParse, z, 0); c287665ba8 2007-09-14 drh: sqlite3_free(z); dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: analyzeTable(pParse, pTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Form 3: Analyze the fully qualified table name */ dbda8d6ce9 2007-07-21 drh: iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); dbda8d6ce9 2007-07-21 drh: if( iDb>=0 ){ dbda8d6ce9 2007-07-21 drh: zDb = db->aDb[iDb].zName; c287665ba8 2007-09-14 drh: z = sqlite3NameFromToken(db, pTableName); dbda8d6ce9 2007-07-21 drh: if( z ){ dbda8d6ce9 2007-07-21 drh: pTab = sqlite3LocateTable(pParse, z, zDb); c287665ba8 2007-09-14 drh: sqlite3_free(z); dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: analyzeTable(pParse, pTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Used to pass information from the analyzer reader through to the dbda8d6ce9 2007-07-21 drh: ** callback routine. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct analysisInfo analysisInfo; dbda8d6ce9 2007-07-21 drh: struct analysisInfo { dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: const char *zDatabase; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This callback is invoked once for each index when reading the dbda8d6ce9 2007-07-21 drh: ** sqlite_stat1 table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** argv[0] = name of the index dbda8d6ce9 2007-07-21 drh: ** argv[1] = results of analysis - on integer for each column dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){ dbda8d6ce9 2007-07-21 drh: analysisInfo *pInfo = (analysisInfo*)pData; dbda8d6ce9 2007-07-21 drh: Index *pIndex; dbda8d6ce9 2007-07-21 drh: int i, c; dbda8d6ce9 2007-07-21 drh: unsigned int v; dbda8d6ce9 2007-07-21 drh: const char *z; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( argc==2 ); dbda8d6ce9 2007-07-21 drh: if( argv==0 || argv[0]==0 || argv[1]==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase); dbda8d6ce9 2007-07-21 drh: if( pIndex==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: z = argv[1]; dbda8d6ce9 2007-07-21 drh: for(i=0; *z && i<=pIndex->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: v = 0; dbda8d6ce9 2007-07-21 drh: while( (c=z[0])>='0' && c<='9' ){ dbda8d6ce9 2007-07-21 drh: v = v*10 + c - '0'; dbda8d6ce9 2007-07-21 drh: z++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIndex->aiRowEst[i] = v; dbda8d6ce9 2007-07-21 drh: if( *z==' ' ) z++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Load the content of the sqlite_stat1 table into the index hash tables. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ dbda8d6ce9 2007-07-21 drh: analysisInfo sInfo; dbda8d6ce9 2007-07-21 drh: HashElem *i; dbda8d6ce9 2007-07-21 drh: char *zSql; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( iDb>=0 && iDb<db->nDb ); c287665ba8 2007-09-14 drh: assert( db->aDb[iDb].pBt!=0 ); c287665ba8 2007-09-14 drh: assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* Clear any prior statistics */ dbda8d6ce9 2007-07-21 drh: for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ dbda8d6ce9 2007-07-21 drh: Index *pIdx = sqliteHashData(i); dbda8d6ce9 2007-07-21 drh: sqlite3DefaultRowEst(pIdx); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to make sure the sqlite_stat1 table existss */ dbda8d6ce9 2007-07-21 drh: sInfo.db = db; dbda8d6ce9 2007-07-21 drh: sInfo.zDatabase = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Load new statistics out of the sqlite_stat1 table */ c287665ba8 2007-09-14 drh: zSql = sqlite3MPrintf(db, "SELECT idx, stat FROM %Q.sqlite_stat1", dbda8d6ce9 2007-07-21 drh: sInfo.zDatabase); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); c287665ba8 2007-09-14 drh: sqlite3_free(zSql); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_ANALYZE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of analyze.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file attach.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2003 April 6 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code used to implement the ATTACH and DETACH commands. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: attach.c,v 1.62 2007/09/03 15:19:35 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_ATTACH dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Resolve an expression that was part of an ATTACH or DETACH statement. This dbda8d6ce9 2007-07-21 drh: ** is slightly different from resolving a normal SQL expression, because simple dbda8d6ce9 2007-07-21 drh: ** identifiers are treated as strings, not possible column names or aliases. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** i.e. if the parser sees: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ATTACH DATABASE abc AS def dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** it treats the two expressions as literal strings 'abc' and 'def' instead of dbda8d6ce9 2007-07-21 drh: ** looking for columns of the same name. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This only applies to the root node of pExpr, so the statement: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ATTACH DATABASE abc||def AS 'db2' dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** will fail because neither abc or def can be resolved. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int resolveAttachExpr(NameContext *pName, Expr *pExpr) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( pExpr ){ dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_ID ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3ExprResolveNames(pName, pExpr); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pName->pParse, "invalid name: \"%T\"", &pExpr->span); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pExpr->op = TK_STRING; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An SQL user-function registered to do the work of an ATTACH statement. The dbda8d6ce9 2007-07-21 drh: ** three arguments to the function come directly from an attach statement: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ATTACH DATABASE x AS y KEY z dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT sqlite_attach(x, y, z) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the dbda8d6ce9 2007-07-21 drh: ** third argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void attachFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int rc = 0; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: const char *zName; dbda8d6ce9 2007-07-21 drh: const char *zFile; dbda8d6ce9 2007-07-21 drh: Db *aNew; dbda8d6ce9 2007-07-21 drh: char *zErrDyn = 0; c287665ba8 2007-09-14 drh: char zErr[128]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zFile = (const char *)sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: zName = (const char *)sqlite3_value_text(argv[1]); dbda8d6ce9 2007-07-21 drh: if( zFile==0 ) zFile = ""; dbda8d6ce9 2007-07-21 drh: if( zName==0 ) zName = ""; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check for the following errors: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Too many attached databases, dbda8d6ce9 2007-07-21 drh: ** * Transaction currently open dbda8d6ce9 2007-07-21 drh: ** * Specified database name already being used. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->nDb>=SQLITE_MAX_ATTACHED+2 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf( dbda8d6ce9 2007-07-21 drh: sizeof(zErr), zErr, "too many attached databases - max %d", dbda8d6ce9 2007-07-21 drh: SQLITE_MAX_ATTACHED dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: goto attach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, dbda8d6ce9 2007-07-21 drh: "cannot ATTACH database within transaction"); dbda8d6ce9 2007-07-21 drh: goto attach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: char *z = db->aDb[i].zName; dbda8d6ce9 2007-07-21 drh: if( z && zName && sqlite3StrICmp(z, zName)==0 ){ c287665ba8 2007-09-14 drh: sqlite3_snprintf(sizeof(zErr), zErr, c287665ba8 2007-09-14 drh: "database %s is already in use", zName); dbda8d6ce9 2007-07-21 drh: goto attach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate the new entry in the db->aDb[] array and initialise the schema dbda8d6ce9 2007-07-21 drh: ** hash tables. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->aDb==db->aDbStatic ){ c287665ba8 2007-09-14 drh: aNew = sqlite3_malloc( sizeof(db->aDb[0])*3 ); dbda8d6ce9 2007-07-21 drh: if( aNew==0 ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: aNew = sqlite3_realloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); dbda8d6ce9 2007-07-21 drh: if( aNew==0 ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db->aDb = aNew; dbda8d6ce9 2007-07-21 drh: aNew = &db->aDb[db->nDb++]; dbda8d6ce9 2007-07-21 drh: memset(aNew, 0, sizeof(*aNew)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open the database file. If the btree is successfully opened, use dbda8d6ce9 2007-07-21 drh: ** it to obtain the database schema. At this point the schema may dbda8d6ce9 2007-07-21 drh: ** or may not be initialised. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE, c287665ba8 2007-09-14 drh: db->openFlags | SQLITE_OPEN_MAIN_DB, c287665ba8 2007-09-14 drh: &aNew->pBt); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); dbda8d6ce9 2007-07-21 drh: if( !aNew->pSchema ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, dbda8d6ce9 2007-07-21 drh: "attached databases must use the same text encoding as main database"); dbda8d6ce9 2007-07-21 drh: goto attach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: aNew->zName = sqlite3DbStrDup(db, zName); dbda8d6ce9 2007-07-21 drh: aNew->safety_level = 3; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if SQLITE_HAS_CODEC dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); dbda8d6ce9 2007-07-21 drh: extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); dbda8d6ce9 2007-07-21 drh: int nKey; dbda8d6ce9 2007-07-21 drh: char *zKey; dbda8d6ce9 2007-07-21 drh: int t = sqlite3_value_type(argv[2]); dbda8d6ce9 2007-07-21 drh: switch( t ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_INTEGER: dbda8d6ce9 2007-07-21 drh: case SQLITE_FLOAT: c287665ba8 2007-09-14 drh: zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: case SQLITE_TEXT: dbda8d6ce9 2007-07-21 drh: case SQLITE_BLOB: dbda8d6ce9 2007-07-21 drh: nKey = sqlite3_value_bytes(argv[2]); dbda8d6ce9 2007-07-21 drh: zKey = (char *)sqlite3_value_blob(argv[2]); dbda8d6ce9 2007-07-21 drh: sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: case SQLITE_NULL: dbda8d6ce9 2007-07-21 drh: /* No key specified. Use the key from the main database */ dbda8d6ce9 2007-07-21 drh: sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); dbda8d6ce9 2007-07-21 drh: sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the file was opened successfully, read the schema for the new database. dbda8d6ce9 2007-07-21 drh: ** If this fails, or if opening the file failed, then close the file and dbda8d6ce9 2007-07-21 drh: ** remove the entry from the db->aDb[] array. i.e. put everything back the way dbda8d6ce9 2007-07-21 drh: ** we found it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: rc = sqlite3Init(db, &zErrDyn); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: int iDb = db->nDb - 1; dbda8d6ce9 2007-07-21 drh: assert( iDb>=2 ); dbda8d6ce9 2007-07-21 drh: if( db->aDb[iDb].pBt ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeClose(db->aDb[iDb].pBt); dbda8d6ce9 2007-07-21 drh: db->aDb[iDb].pBt = 0; dbda8d6ce9 2007-07-21 drh: db->aDb[iDb].pSchema = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: db->nDb = iDb; dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_NOMEM ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr),zErr, "out of memory"); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto attach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: attach_error: dbda8d6ce9 2007-07-21 drh: /* Return an error if we get here */ dbda8d6ce9 2007-07-21 drh: if( zErrDyn ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context, zErrDyn, -1); c287665ba8 2007-09-14 drh: sqlite3_free(zErrDyn); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zErr[sizeof(zErr)-1] = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context, zErr, -1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An SQL user-function registered to do the work of an DETACH statement. The dbda8d6ce9 2007-07-21 drh: ** three arguments to the function come directly from a detach statement: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** DETACH DATABASE x dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT sqlite_detach(x) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void detachFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const char *zName = (const char *)sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: sqlite3 *db = sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Db *pDb = 0; dbda8d6ce9 2007-07-21 drh: char zErr[128]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( zName==0 ) zName = ""; dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[i]; dbda8d6ce9 2007-07-21 drh: if( pDb->pBt==0 ) continue; dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( i>=db->nDb ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); dbda8d6ce9 2007-07-21 drh: goto detach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<2 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); dbda8d6ce9 2007-07-21 drh: goto detach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr), zErr, dbda8d6ce9 2007-07-21 drh: "cannot DETACH database within transaction"); dbda8d6ce9 2007-07-21 drh: goto detach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3BtreeIsInReadTrans(pDb->pBt) ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); dbda8d6ce9 2007-07-21 drh: goto detach_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3BtreeClose(pDb->pBt); dbda8d6ce9 2007-07-21 drh: pDb->pBt = 0; dbda8d6ce9 2007-07-21 drh: pDb->pSchema = 0; dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: detach_error: dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context, zErr, -1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This procedure generates VDBE code for a single invocation of either the dbda8d6ce9 2007-07-21 drh: ** sqlite_detach() or sqlite_attach() SQL user functions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void codeAttach( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ dbda8d6ce9 2007-07-21 drh: const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */ dbda8d6ce9 2007-07-21 drh: int nFunc, /* Number of args to pass to zFunc */ dbda8d6ce9 2007-07-21 drh: Expr *pAuthArg, /* Expression to pass to authorization callback */ dbda8d6ce9 2007-07-21 drh: Expr *pFilename, /* Name of database file */ dbda8d6ce9 2007-07-21 drh: Expr *pDbname, /* Name of the database to use internally */ dbda8d6ce9 2007-07-21 drh: Expr *pKey /* Database key for encryption extension */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: NameContext sName; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: FuncDef *pFunc; dbda8d6ce9 2007-07-21 drh: sqlite3* db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION c287665ba8 2007-09-14 drh: assert( db->mallocFailed || pAuthArg ); dbda8d6ce9 2007-07-21 drh: if( pAuthArg ){ c287665ba8 2007-09-14 drh: char *zAuthArg = sqlite3NameFromToken(db, &pAuthArg->span); dbda8d6ce9 2007-07-21 drh: if( !zAuthArg ){ dbda8d6ce9 2007-07-21 drh: goto attach_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); c287665ba8 2007-09-14 drh: sqlite3_free(zAuthArg); dbda8d6ce9 2007-07-21 drh: if(rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto attach_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_AUTHORIZATION */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memset(&sName, 0, sizeof(NameContext)); dbda8d6ce9 2007-07-21 drh: sName.pParse = pParse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || dbda8d6ce9 2007-07-21 drh: SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || dbda8d6ce9 2007-07-21 drh: SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: pParse->nErr++; dbda8d6ce9 2007-07-21 drh: goto attach_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pFilename); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pDbname); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pKey); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( v || db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Function, 0, nFunc); dbda8d6ce9 2007-07-21 drh: pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this dbda8d6ce9 2007-07-21 drh: ** statement only). For DETACH, set it to false (expire all existing dbda8d6ce9 2007-07-21 drh: ** statements). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: attach_end: dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pFilename); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pDbname); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pKey); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Called by the parser to compile a DETACH statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** DETACH pDbname dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){ dbda8d6ce9 2007-07-21 drh: codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Called by the parser to compile an ATTACH statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ATTACH p AS pDbname KEY pKey dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ dbda8d6ce9 2007-07-21 drh: codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_ATTACH */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register the functions sqlite_attach and sqlite_detach. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AttachFunctions(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_ATTACH dbda8d6ce9 2007-07-21 drh: static const int enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Initialize a DbFixer structure. This routine must be called prior dbda8d6ce9 2007-07-21 drh: ** to passing the structure to one of the sqliteFixAAAA() routines below. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The return value indicates whether or not fixation is required. TRUE dbda8d6ce9 2007-07-21 drh: ** means we do need to fix the database references, FALSE means we do not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixInit( dbda8d6ce9 2007-07-21 drh: DbFixer *pFix, /* The fixer to be initialized */ dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Error messages will be written here */ dbda8d6ce9 2007-07-21 drh: int iDb, /* This is the database that must be used */ dbda8d6ce9 2007-07-21 drh: const char *zType, /* "view", "trigger", or "index" */ dbda8d6ce9 2007-07-21 drh: const Token *pName /* Name of the view, trigger, or index */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( iDb<0 || iDb==1 ) return 0; dbda8d6ce9 2007-07-21 drh: db = pParse->db; dbda8d6ce9 2007-07-21 drh: assert( db->nDb>iDb ); dbda8d6ce9 2007-07-21 drh: pFix->pParse = pParse; dbda8d6ce9 2007-07-21 drh: pFix->zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: pFix->zType = zType; dbda8d6ce9 2007-07-21 drh: pFix->pName = pName; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following set of routines walk through the parse tree and assign dbda8d6ce9 2007-07-21 drh: ** a specific database to all table references where the database name dbda8d6ce9 2007-07-21 drh: ** was left unspecified in the original SQL statement. The pFix structure dbda8d6ce9 2007-07-21 drh: ** must have been initialized by a prior call to sqlite3FixInit(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines are used to make sure that an index, trigger, or dbda8d6ce9 2007-07-21 drh: ** view in one database does not refer to objects in a different database. dbda8d6ce9 2007-07-21 drh: ** (Exception: indices, triggers, and views in the TEMP database are dbda8d6ce9 2007-07-21 drh: ** allowed to refer to anything.) If a reference is explicitly made dbda8d6ce9 2007-07-21 drh: ** to an object in a different database, an error message is added to dbda8d6ce9 2007-07-21 drh: ** pParse->zErrMsg and these routines return non-zero. If everything dbda8d6ce9 2007-07-21 drh: ** checks out, these routines return 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixSrcList( dbda8d6ce9 2007-07-21 drh: DbFixer *pFix, /* Context of the fixation */ dbda8d6ce9 2007-07-21 drh: SrcList *pList /* The Source list to check and modify */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: const char *zDb; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return 0; dbda8d6ce9 2007-07-21 drh: zDb = pFix->zDb; dbda8d6ce9 2007-07-21 drh: for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: if( pItem->zDatabase==0 ){ c287665ba8 2007-09-14 drh: pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb); dbda8d6ce9 2007-07-21 drh: }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pFix->pParse, dbda8d6ce9 2007-07-21 drh: "%s %T cannot reference objects in database %s", dbda8d6ce9 2007-07-21 drh: pFix->zType, pFix->pName, pItem->zDatabase); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) dbda8d6ce9 2007-07-21 drh: if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixSelect( dbda8d6ce9 2007-07-21 drh: DbFixer *pFix, /* Context of the fixation */ dbda8d6ce9 2007-07-21 drh: Select *pSelect /* The SELECT statement to be fixed to one database */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: while( pSelect ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExprList(pFix, pSelect->pEList) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExpr(pFix, pSelect->pWhere) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExpr(pFix, pSelect->pHaving) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pSelect = pSelect->pPrior; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixExpr( dbda8d6ce9 2007-07-21 drh: DbFixer *pFix, /* Context of the fixation */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr /* The expression to be fixed to one database */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: while( pExpr ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3FixSelect(pFix, pExpr->pSelect) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExprList(pFix, pExpr->pList) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExpr(pFix, pExpr->pRight) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pExpr = pExpr->pLeft; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixExprList( dbda8d6ce9 2007-07-21 drh: DbFixer *pFix, /* Context of the fixation */ dbda8d6ce9 2007-07-21 drh: ExprList *pList /* The expression to be fixed to one database */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return 0; dbda8d6ce9 2007-07-21 drh: for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExpr(pFix, pItem->pExpr) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FixTriggerStep( dbda8d6ce9 2007-07-21 drh: DbFixer *pFix, /* Context of the fixation */ dbda8d6ce9 2007-07-21 drh: TriggerStep *pStep /* The trigger step be fixed to one database */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: while( pStep ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3FixSelect(pFix, pStep->pSelect) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExpr(pFix, pStep->pWhere) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FixExprList(pFix, pStep->pExprList) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pStep = pStep->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of attach.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file auth.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2003 January 11 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code used to implement the sqlite3_set_authorizer() dbda8d6ce9 2007-07-21 drh: ** API. This facility is an optional feature of the library. Embedded dbda8d6ce9 2007-07-21 drh: ** systems that do not need this facility may omit it by recompiling dbda8d6ce9 2007-07-21 drh: ** the library with -DSQLITE_OMIT_AUTHORIZATION=1 dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: auth.c,v 1.28 2007/09/01 18:24:55 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** All of the code in this file may be omitted by defining a single dbda8d6ce9 2007-07-21 drh: ** macro. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set or clear the access authorization function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The access authorization function is be called during the compilation dbda8d6ce9 2007-07-21 drh: ** phase to verify that the user has read and/or write access permission on dbda8d6ce9 2007-07-21 drh: ** various fields of the database. The first argument to the auth function dbda8d6ce9 2007-07-21 drh: ** is a copy of the 3rd argument to this routine. The second argument dbda8d6ce9 2007-07-21 drh: ** to the auth function is one of these constants: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQLITE_CREATE_INDEX dbda8d6ce9 2007-07-21 drh: ** SQLITE_CREATE_TABLE dbda8d6ce9 2007-07-21 drh: ** SQLITE_CREATE_TEMP_INDEX dbda8d6ce9 2007-07-21 drh: ** SQLITE_CREATE_TEMP_TABLE dbda8d6ce9 2007-07-21 drh: ** SQLITE_CREATE_TEMP_TRIGGER dbda8d6ce9 2007-07-21 drh: ** SQLITE_CREATE_TEMP_VIEW dbda8d6ce9 2007-07-21 drh: ** SQLITE_CREATE_TRIGGER dbda8d6ce9 2007-07-21 drh: ** SQLITE_CREATE_VIEW dbda8d6ce9 2007-07-21 drh: ** SQLITE_DELETE dbda8d6ce9 2007-07-21 drh: ** SQLITE_DROP_INDEX dbda8d6ce9 2007-07-21 drh: ** SQLITE_DROP_TABLE dbda8d6ce9 2007-07-21 drh: ** SQLITE_DROP_TEMP_INDEX dbda8d6ce9 2007-07-21 drh: ** SQLITE_DROP_TEMP_TABLE dbda8d6ce9 2007-07-21 drh: ** SQLITE_DROP_TEMP_TRIGGER dbda8d6ce9 2007-07-21 drh: ** SQLITE_DROP_TEMP_VIEW dbda8d6ce9 2007-07-21 drh: ** SQLITE_DROP_TRIGGER dbda8d6ce9 2007-07-21 drh: ** SQLITE_DROP_VIEW dbda8d6ce9 2007-07-21 drh: ** SQLITE_INSERT dbda8d6ce9 2007-07-21 drh: ** SQLITE_PRAGMA dbda8d6ce9 2007-07-21 drh: ** SQLITE_READ dbda8d6ce9 2007-07-21 drh: ** SQLITE_SELECT dbda8d6ce9 2007-07-21 drh: ** SQLITE_TRANSACTION dbda8d6ce9 2007-07-21 drh: ** SQLITE_UPDATE dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The third and fourth arguments to the auth function are the name of dbda8d6ce9 2007-07-21 drh: ** the table and the column that are being accessed. The auth function dbda8d6ce9 2007-07-21 drh: ** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If dbda8d6ce9 2007-07-21 drh: ** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY dbda8d6ce9 2007-07-21 drh: ** means that the SQL statement will never-run - the sqlite3_exec() call dbda8d6ce9 2007-07-21 drh: ** will return with an error. SQLITE_IGNORE means that the SQL statement dbda8d6ce9 2007-07-21 drh: ** should run but attempts to read the specified column will return NULL dbda8d6ce9 2007-07-21 drh: ** and attempts to write the column will be ignored. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Setting the auth function to NULL disables this hook. The default dbda8d6ce9 2007-07-21 drh: ** setting of the auth function is NULL. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_set_authorizer( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), dbda8d6ce9 2007-07-21 drh: void *pArg dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: db->xAuth = xAuth; dbda8d6ce9 2007-07-21 drh: db->pAuthArg = pArg; dbda8d6ce9 2007-07-21 drh: sqlite3ExpirePreparedStatements(db); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write an error message into pParse->zErrMsg that explains that the dbda8d6ce9 2007-07-21 drh: ** user-supplied authorization function returned an illegal value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void sqliteAuthBadReturnCode(Parse *pParse, int rc){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "illegal return value (%d) from the " dbda8d6ce9 2007-07-21 drh: "authorization function - should be SQLITE_OK, SQLITE_IGNORE, " dbda8d6ce9 2007-07-21 drh: "or SQLITE_DENY", rc); dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The pExpr should be a TK_COLUMN expression. The table referred to dbda8d6ce9 2007-07-21 drh: ** is in pTabList or else it is the NEW or OLD table of a trigger. dbda8d6ce9 2007-07-21 drh: ** Check to see if it is OK to read this particular column. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN dbda8d6ce9 2007-07-21 drh: ** instruction into a TK_NULL. If the auth function returns SQLITE_DENY, dbda8d6ce9 2007-07-21 drh: ** then generate an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AuthRead( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr, /* The expression to check authorization on */ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList /* All table that pExpr might refer to */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: Table *pTab = 0; /* The table being read */ dbda8d6ce9 2007-07-21 drh: const char *zCol; /* Name of the column of the table */ dbda8d6ce9 2007-07-21 drh: int iSrc; /* Index in pTabList->a[] of table being read */ dbda8d6ce9 2007-07-21 drh: const char *zDBase; /* Name of database being accessed */ dbda8d6ce9 2007-07-21 drh: TriggerStack *pStack; /* The stack of current triggers */ dbda8d6ce9 2007-07-21 drh: int iDb; /* The index of the database the expression refers to */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( db->xAuth==0 ) return; dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_COLUMN ) return; dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pExpr->pSchema); dbda8d6ce9 2007-07-21 drh: if( iDb<0 ){ dbda8d6ce9 2007-07-21 drh: /* An attempt to read a column out of a subquery or other dbda8d6ce9 2007-07-21 drh: ** temporary table. */ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){ dbda8d6ce9 2007-07-21 drh: if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iSrc>=0 && pTabList && iSrc<pTabList->nSrc ){ dbda8d6ce9 2007-07-21 drh: pTab = pTabList->a[iSrc].pTab; dbda8d6ce9 2007-07-21 drh: }else if( (pStack = pParse->trigStack)!=0 ){ dbda8d6ce9 2007-07-21 drh: /* This must be an attempt to read the NEW or OLD pseudo-tables dbda8d6ce9 2007-07-21 drh: ** of a trigger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx ); dbda8d6ce9 2007-07-21 drh: pTab = pStack->pTab; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pTab==0 ) return; dbda8d6ce9 2007-07-21 drh: if( pExpr->iColumn>=0 ){ dbda8d6ce9 2007-07-21 drh: assert( pExpr->iColumn<pTab->nCol ); dbda8d6ce9 2007-07-21 drh: zCol = pTab->aCol[pExpr->iColumn].zName; dbda8d6ce9 2007-07-21 drh: }else if( pTab->iPKey>=0 ){ dbda8d6ce9 2007-07-21 drh: assert( pTab->iPKey<pTab->nCol ); dbda8d6ce9 2007-07-21 drh: zCol = pTab->aCol[pTab->iPKey].zName; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zCol = "ROWID"; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: zDBase = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase, dbda8d6ce9 2007-07-21 drh: pParse->zAuthContext); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_IGNORE ){ dbda8d6ce9 2007-07-21 drh: pExpr->op = TK_NULL; dbda8d6ce9 2007-07-21 drh: }else if( rc==SQLITE_DENY ){ dbda8d6ce9 2007-07-21 drh: if( db->nDb>2 || iDb!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited", dbda8d6ce9 2007-07-21 drh: zDBase, pTab->zName, zCol); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited",pTab->zName,zCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_AUTH; dbda8d6ce9 2007-07-21 drh: }else if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqliteAuthBadReturnCode(pParse, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Do an authorization check using the code and arguments given. Return dbda8d6ce9 2007-07-21 drh: ** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY dbda8d6ce9 2007-07-21 drh: ** is returned, then the error count and error message in pParse are dbda8d6ce9 2007-07-21 drh: ** modified appropriately. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3AuthCheck( dbda8d6ce9 2007-07-21 drh: Parse *pParse, dbda8d6ce9 2007-07-21 drh: int code, dbda8d6ce9 2007-07-21 drh: const char *zArg1, dbda8d6ce9 2007-07-21 drh: const char *zArg2, dbda8d6ce9 2007-07-21 drh: const char *zArg3 dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Don't do any authorization checks if the database is initialising dbda8d6ce9 2007-07-21 drh: ** or if the parser is being invoked from within sqlite3_declare_vtab. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->init.busy || IN_DECLARE_VTAB ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( db->xAuth==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_DENY ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "not authorized"); dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_AUTH; dbda8d6ce9 2007-07-21 drh: }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_DENY; dbda8d6ce9 2007-07-21 drh: sqliteAuthBadReturnCode(pParse, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Push an authorization context. After this routine is called, the dbda8d6ce9 2007-07-21 drh: ** zArg3 argument to authorization callbacks will be zContext until dbda8d6ce9 2007-07-21 drh: ** popped. Or if pParse==0, this routine is a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AuthContextPush( dbda8d6ce9 2007-07-21 drh: Parse *pParse, dbda8d6ce9 2007-07-21 drh: AuthContext *pContext, dbda8d6ce9 2007-07-21 drh: const char *zContext dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: pContext->pParse = pParse; dbda8d6ce9 2007-07-21 drh: if( pParse ){ dbda8d6ce9 2007-07-21 drh: pContext->zAuthContext = pParse->zAuthContext; dbda8d6ce9 2007-07-21 drh: pParse->zAuthContext = zContext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Pop an authorization context that was previously pushed dbda8d6ce9 2007-07-21 drh: ** by sqlite3AuthContextPush dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){ dbda8d6ce9 2007-07-21 drh: if( pContext->pParse ){ dbda8d6ce9 2007-07-21 drh: pContext->pParse->zAuthContext = pContext->zAuthContext; dbda8d6ce9 2007-07-21 drh: pContext->pParse = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_AUTHORIZATION */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of auth.c ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file build.c *******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains C code routines that are called by the SQLite parser dbda8d6ce9 2007-07-21 drh: ** when syntax rules are reduced. The routines in this file handle the dbda8d6ce9 2007-07-21 drh: ** following kinds of SQL syntax: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE dbda8d6ce9 2007-07-21 drh: ** DROP TABLE dbda8d6ce9 2007-07-21 drh: ** CREATE INDEX dbda8d6ce9 2007-07-21 drh: ** DROP INDEX dbda8d6ce9 2007-07-21 drh: ** creating ID lists dbda8d6ce9 2007-07-21 drh: ** BEGIN TRANSACTION dbda8d6ce9 2007-07-21 drh: ** COMMIT dbda8d6ce9 2007-07-21 drh: ** ROLLBACK dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: build.c,v 1.444 2007/09/03 15:19:35 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called when a new SQL statement is beginning to dbda8d6ce9 2007-07-21 drh: ** be parsed. Initialize the pParse structure as needed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){ dbda8d6ce9 2007-07-21 drh: pParse->explain = explainFlag; dbda8d6ce9 2007-07-21 drh: pParse->nVar = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The TableLock structure is only used by the sqlite3TableLock() and dbda8d6ce9 2007-07-21 drh: ** codeTableLocks() functions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct TableLock { dbda8d6ce9 2007-07-21 drh: int iDb; /* The database containing the table to be locked */ dbda8d6ce9 2007-07-21 drh: int iTab; /* The root page of the table to be locked */ dbda8d6ce9 2007-07-21 drh: u8 isWriteLock; /* True for write lock. False for a read lock */ dbda8d6ce9 2007-07-21 drh: const char *zName; /* Name of the table */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Record the fact that we want to lock a table at run-time. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The table to be locked has root page iTab and is found in database iDb. dbda8d6ce9 2007-07-21 drh: ** A read or a write lock can be taken depending on isWritelock. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine just records the fact that the lock is desired. The dbda8d6ce9 2007-07-21 drh: ** code to make the lock occur is generated by a later call to dbda8d6ce9 2007-07-21 drh: ** codeTableLocks() which occurs during sqlite3FinishCoding(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3TableLock( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: int iDb, /* Index of the database containing the table to lock */ dbda8d6ce9 2007-07-21 drh: int iTab, /* Root page number of the table to be locked */ dbda8d6ce9 2007-07-21 drh: u8 isWriteLock, /* True for a write lock */ dbda8d6ce9 2007-07-21 drh: const char *zName /* Name of the table to be locked */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nBytes; dbda8d6ce9 2007-07-21 drh: TableLock *p; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( iDb<0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<pParse->nTableLock; i++){ dbda8d6ce9 2007-07-21 drh: p = &pParse->aTableLock[i]; dbda8d6ce9 2007-07-21 drh: if( p->iDb==iDb && p->iTab==iTab ){ dbda8d6ce9 2007-07-21 drh: p->isWriteLock = (p->isWriteLock || isWriteLock); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nBytes = sizeof(TableLock) * (pParse->nTableLock+1); c287665ba8 2007-09-14 drh: pParse->aTableLock = c287665ba8 2007-09-14 drh: sqlite3DbReallocOrFree(pParse->db, pParse->aTableLock, nBytes); dbda8d6ce9 2007-07-21 drh: if( pParse->aTableLock ){ dbda8d6ce9 2007-07-21 drh: p = &pParse->aTableLock[pParse->nTableLock++]; dbda8d6ce9 2007-07-21 drh: p->iDb = iDb; dbda8d6ce9 2007-07-21 drh: p->iTab = iTab; dbda8d6ce9 2007-07-21 drh: p->isWriteLock = isWriteLock; dbda8d6ce9 2007-07-21 drh: p->zName = zName; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pParse->nTableLock = 0; c287665ba8 2007-09-14 drh: pParse->db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Code an OP_TableLock instruction for each table locked by the dbda8d6ce9 2007-07-21 drh: ** statement (configured by calls to sqlite3TableLock()). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void codeTableLocks(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Vdbe *pVdbe; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<pParse->nTableLock; i++){ dbda8d6ce9 2007-07-21 drh: TableLock *p = &pParse->aTableLock[i]; dbda8d6ce9 2007-07-21 drh: int p1 = p->iDb; dbda8d6ce9 2007-07-21 drh: if( p->isWriteLock ){ dbda8d6ce9 2007-07-21 drh: p1 = -1*(p1+1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define codeTableLocks(x) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called after a single SQL statement has been dbda8d6ce9 2007-07-21 drh: ** parsed and a VDBE program to execute that statement has been dbda8d6ce9 2007-07-21 drh: ** prepared. This routine puts the finishing touches on the dbda8d6ce9 2007-07-21 drh: ** VDBE program and resets the pParse structure for the next dbda8d6ce9 2007-07-21 drh: ** parse. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that if an error occurred, it might be the case that dbda8d6ce9 2007-07-21 drh: ** no VDBE code was generated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: db = pParse->db; c287665ba8 2007-09-14 drh: if( db->mallocFailed ) return; dbda8d6ce9 2007-07-21 drh: if( pParse->nested ) return; dbda8d6ce9 2007-07-21 drh: if( !pParse->pVdbe ){ dbda8d6ce9 2007-07-21 drh: if( pParse->rc==SQLITE_OK && pParse->nErr ){ dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin by generating some termination code at the end of the dbda8d6ce9 2007-07-21 drh: ** vdbe program dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Halt, 0, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The cookie mask contains one bit for each database file open. dbda8d6ce9 2007-07-21 drh: ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are dbda8d6ce9 2007-07-21 drh: ** set for each database that is used. Generate code to start a dbda8d6ce9 2007-07-21 drh: ** transaction on each used database and to verify the schema cookie dbda8d6ce9 2007-07-21 drh: ** on each used database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pParse->cookieGoto>0 ){ dbda8d6ce9 2007-07-21 drh: u32 mask; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, pParse->cookieGoto-1); dbda8d6ce9 2007-07-21 drh: for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){ dbda8d6ce9 2007-07-21 drh: if( (mask & pParse->cookieMask)==0 ) continue; c287665ba8 2007-09-14 drh: sqlite3VdbeUsesBtree(v, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( pParse->pVirtualLock ){ dbda8d6ce9 2007-07-21 drh: char *vtab = (char *)pParse->pVirtualLock->pVtab; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VBegin, 0, 0, vtab, P3_VTAB); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Once all the cookies have been verified and transactions opened, dbda8d6ce9 2007-07-21 drh: ** obtain the required table-locks. This is a no-op unless the dbda8d6ce9 2007-07-21 drh: ** shared-cache feature is enabled. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: codeTableLocks(pParse); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRACE dbda8d6ce9 2007-07-21 drh: /* Add a No-op that contains the complete text of the compiled SQL dbda8d6ce9 2007-07-21 drh: ** statement as its P3 argument. This does not change the functionality dbda8d6ce9 2007-07-21 drh: ** of the program. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is used to implement sqlite3_trace(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql); dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_TRACE */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Get the VDBE program ready for execution dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: if( v && pParse->nErr==0 && !db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeTrace(v, trace); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3, dbda8d6ce9 2007-07-21 drh: pParse->nTab+3, pParse->explain); dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_DONE; dbda8d6ce9 2007-07-21 drh: pParse->colNamesSet = 0; dbda8d6ce9 2007-07-21 drh: }else if( pParse->rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->nTab = 0; dbda8d6ce9 2007-07-21 drh: pParse->nMem = 0; dbda8d6ce9 2007-07-21 drh: pParse->nSet = 0; dbda8d6ce9 2007-07-21 drh: pParse->nVar = 0; dbda8d6ce9 2007-07-21 drh: pParse->cookieMask = 0; dbda8d6ce9 2007-07-21 drh: pParse->cookieGoto = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Run the parser and code generator recursively in order to generate dbda8d6ce9 2007-07-21 drh: ** code for the SQL statement given onto the end of the pParse context dbda8d6ce9 2007-07-21 drh: ** currently under construction. When the parser is run recursively dbda8d6ce9 2007-07-21 drh: ** this way, the final OP_Halt is not appended and other initialization dbda8d6ce9 2007-07-21 drh: ** and finalization steps are omitted because those are handling by the dbda8d6ce9 2007-07-21 drh: ** outermost parser. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Not everything is nestable. This facility is designed to permit dbda8d6ce9 2007-07-21 drh: ** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use dbda8d6ce9 2007-07-21 drh: ** care if you decide to try to use this routine for some other purposes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ dbda8d6ce9 2007-07-21 drh: va_list ap; dbda8d6ce9 2007-07-21 drh: char *zSql; dbda8d6ce9 2007-07-21 drh: # define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar)) dbda8d6ce9 2007-07-21 drh: char saveBuf[SAVE_SZ]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParse->nErr ) return; dbda8d6ce9 2007-07-21 drh: assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ dbda8d6ce9 2007-07-21 drh: va_start(ap, zFormat); c287665ba8 2007-09-14 drh: zSql = sqlite3VMPrintf(pParse->db, zFormat, ap); dbda8d6ce9 2007-07-21 drh: va_end(ap); dbda8d6ce9 2007-07-21 drh: if( zSql==0 ){ c287665ba8 2007-09-14 drh: pParse->db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: return; /* A malloc must have failed */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->nested++; dbda8d6ce9 2007-07-21 drh: memcpy(saveBuf, &pParse->nVar, SAVE_SZ); dbda8d6ce9 2007-07-21 drh: memset(&pParse->nVar, 0, SAVE_SZ); dbda8d6ce9 2007-07-21 drh: sqlite3RunParser(pParse, zSql, 0); c287665ba8 2007-09-14 drh: sqlite3_free(zSql); dbda8d6ce9 2007-07-21 drh: memcpy(&pParse->nVar, saveBuf, SAVE_SZ); dbda8d6ce9 2007-07-21 drh: pParse->nested--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Locate the in-memory structure that describes a particular database dbda8d6ce9 2007-07-21 drh: ** table given the name of that table and (optionally) the name of the dbda8d6ce9 2007-07-21 drh: ** database containing the table. Return NULL if not found. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If zDatabase is 0, all databases are searched for the table and the dbda8d6ce9 2007-07-21 drh: ** first matching table is returned. (No checking for duplicate table dbda8d6ce9 2007-07-21 drh: ** names is done.) The search order is TEMP first, then MAIN, then any dbda8d6ce9 2007-07-21 drh: ** auxiliary databases added using the ATTACH command. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also sqlite3LocateTable(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ dbda8d6ce9 2007-07-21 drh: Table *p = 0; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: assert( zName!=0 ); dbda8d6ce9 2007-07-21 drh: for(i=OMIT_TEMPDB; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ dbda8d6ce9 2007-07-21 drh: if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; dbda8d6ce9 2007-07-21 drh: p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, strlen(zName)+1); dbda8d6ce9 2007-07-21 drh: if( p ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Locate the in-memory structure that describes a particular database dbda8d6ce9 2007-07-21 drh: ** table given the name of that table and (optionally) the name of the dbda8d6ce9 2007-07-21 drh: ** database containing the table. Return NULL if not found. Also leave an dbda8d6ce9 2007-07-21 drh: ** error message in pParse->zErrMsg. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The difference between this routine and sqlite3FindTable() is that this dbda8d6ce9 2007-07-21 drh: ** routine leaves an error message in pParse->zErrMsg where dbda8d6ce9 2007-07-21 drh: ** sqlite3FindTable() does not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read the database schema. If an error occurs, leave an error message dbda8d6ce9 2007-07-21 drh: ** and code in pParse and return NULL. */ dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: p = sqlite3FindTable(pParse->db, zName, zDbase); dbda8d6ce9 2007-07-21 drh: if( p==0 ){ dbda8d6ce9 2007-07-21 drh: if( zDbase ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such table: %s.%s", zDbase, zName); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such table: %s", zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->checkSchema = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Locate the in-memory structure that describes dbda8d6ce9 2007-07-21 drh: ** a particular index given the name of that index dbda8d6ce9 2007-07-21 drh: ** and the name of the database that contains the index. dbda8d6ce9 2007-07-21 drh: ** Return NULL if not found. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If zDatabase is 0, all databases are searched for the dbda8d6ce9 2007-07-21 drh: ** table and the first matching index is returned. (No checking dbda8d6ce9 2007-07-21 drh: ** for duplicate index names is done.) The search order is dbda8d6ce9 2007-07-21 drh: ** TEMP first, then MAIN, then any auxiliary databases added dbda8d6ce9 2007-07-21 drh: ** using the ATTACH command. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){ dbda8d6ce9 2007-07-21 drh: Index *p = 0; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=OMIT_TEMPDB; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ dbda8d6ce9 2007-07-21 drh: Schema *pSchema = db->aDb[j].pSchema; dbda8d6ce9 2007-07-21 drh: if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; dbda8d6ce9 2007-07-21 drh: assert( pSchema || (j==1 && !db->aDb[1].pBt) ); dbda8d6ce9 2007-07-21 drh: if( pSchema ){ dbda8d6ce9 2007-07-21 drh: p = sqlite3HashFind(&pSchema->idxHash, zName, strlen(zName)+1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Reclaim the memory used by an index dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void freeIndex(Index *p){ c287665ba8 2007-09-14 drh: sqlite3_free(p->zColAff); c287665ba8 2007-09-14 drh: sqlite3_free(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Remove the given index from the index hash table, and free dbda8d6ce9 2007-07-21 drh: ** its memory structures. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The index is removed from the database hash tables but dbda8d6ce9 2007-07-21 drh: ** it is not unlinked from the Table that it indexes. dbda8d6ce9 2007-07-21 drh: ** Unlinking from the Table must be done by the calling function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void sqliteDeleteIndex(Index *p){ dbda8d6ce9 2007-07-21 drh: Index *pOld; dbda8d6ce9 2007-07-21 drh: const char *zName = p->zName; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName, strlen( zName)+1, 0); dbda8d6ce9 2007-07-21 drh: assert( pOld==0 || pOld==p ); dbda8d6ce9 2007-07-21 drh: freeIndex(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** For the index called zIdxName which is found in the database iDb, dbda8d6ce9 2007-07-21 drh: ** unlike that index from its Table then remove the index from dbda8d6ce9 2007-07-21 drh: ** the index hash table and free all memory structures associated dbda8d6ce9 2007-07-21 drh: ** with the index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ dbda8d6ce9 2007-07-21 drh: Index *pIndex; dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: Hash *pHash = &db->aDb[iDb].pSchema->idxHash; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: len = strlen(zIdxName); dbda8d6ce9 2007-07-21 drh: pIndex = sqlite3HashInsert(pHash, zIdxName, len+1, 0); dbda8d6ce9 2007-07-21 drh: if( pIndex ){ dbda8d6ce9 2007-07-21 drh: if( pIndex->pTable->pIndex==pIndex ){ dbda8d6ce9 2007-07-21 drh: pIndex->pTable->pIndex = pIndex->pNext; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Index *p; dbda8d6ce9 2007-07-21 drh: for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){} dbda8d6ce9 2007-07-21 drh: if( p && p->pNext==pIndex ){ dbda8d6ce9 2007-07-21 drh: p->pNext = pIndex->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: freeIndex(pIndex); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_InternChanges; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Erase all schema information from the in-memory hash tables of dbda8d6ce9 2007-07-21 drh: ** a single database. This routine is called to reclaim memory dbda8d6ce9 2007-07-21 drh: ** before the database closes. It is also called during a rollback dbda8d6ce9 2007-07-21 drh: ** if there were schema changes during the transaction or if a dbda8d6ce9 2007-07-21 drh: ** schema-cookie mismatch occurs. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If iDb<=0 then reset the internal schema tables for all database dbda8d6ce9 2007-07-21 drh: ** files. If iDb>=2 then reset the internal schema for only the dbda8d6ce9 2007-07-21 drh: ** single file indicated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: for(i=iDb; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: Db *pDb = &db->aDb[i]; dbda8d6ce9 2007-07-21 drh: if( pDb->pSchema ){ dbda8d6ce9 2007-07-21 drh: sqlite3SchemaFree(pDb->pSchema); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iDb>0 ) return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( iDb==0 ); dbda8d6ce9 2007-07-21 drh: db->flags &= ~SQLITE_InternChanges; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If one or more of the auxiliary database files has been closed, dbda8d6ce9 2007-07-21 drh: ** then remove them from the auxiliary database list. We take the dbda8d6ce9 2007-07-21 drh: ** opportunity to do this here since we have just deleted all of the dbda8d6ce9 2007-07-21 drh: ** schema hash tables and therefore do not have to make any changes dbda8d6ce9 2007-07-21 drh: ** to any of those tables. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: struct Db *pDb = &db->aDb[i]; dbda8d6ce9 2007-07-21 drh: if( pDb->pBt==0 ){ dbda8d6ce9 2007-07-21 drh: if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux); dbda8d6ce9 2007-07-21 drh: pDb->pAux = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=j=2; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: struct Db *pDb = &db->aDb[i]; dbda8d6ce9 2007-07-21 drh: if( pDb->pBt==0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(pDb->zName); dbda8d6ce9 2007-07-21 drh: pDb->zName = 0; dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( j<i ){ dbda8d6ce9 2007-07-21 drh: db->aDb[j] = db->aDb[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: j++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j])); dbda8d6ce9 2007-07-21 drh: db->nDb = j; dbda8d6ce9 2007-07-21 drh: if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ dbda8d6ce9 2007-07-21 drh: memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); c287665ba8 2007-09-14 drh: sqlite3_free(db->aDb); dbda8d6ce9 2007-07-21 drh: db->aDb = db->aDbStatic; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called when a commit occurs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: db->flags &= ~SQLITE_InternChanges; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear the column names from a table or view. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void sqliteResetColumnNames(Table *pTable){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Column *pCol; dbda8d6ce9 2007-07-21 drh: assert( pTable!=0 ); dbda8d6ce9 2007-07-21 drh: if( (pCol = pTable->aCol)!=0 ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTable->nCol; i++, pCol++){ c287665ba8 2007-09-14 drh: sqlite3_free(pCol->zName); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pCol->pDflt); c287665ba8 2007-09-14 drh: sqlite3_free(pCol->zType); c287665ba8 2007-09-14 drh: sqlite3_free(pCol->zColl); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pTable->aCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTable->aCol = 0; dbda8d6ce9 2007-07-21 drh: pTable->nCol = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Remove the memory data structures associated with the given dbda8d6ce9 2007-07-21 drh: ** Table. No changes are made to disk by this routine. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine just deletes the data structure. It does not unlink dbda8d6ce9 2007-07-21 drh: ** the table data structure from the hash table. Nor does it remove dbda8d6ce9 2007-07-21 drh: ** foreign keys from the sqlite.aFKey hash table. But it does destroy dbda8d6ce9 2007-07-21 drh: ** memory structures of the indices and foreign keys associated with dbda8d6ce9 2007-07-21 drh: ** the table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeleteTable(Table *pTable){ dbda8d6ce9 2007-07-21 drh: Index *pIndex, *pNext; dbda8d6ce9 2007-07-21 drh: FKey *pFKey, *pNextFKey; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pTable==0 ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do not delete the table until the reference count reaches zero. */ dbda8d6ce9 2007-07-21 drh: pTable->nRef--; dbda8d6ce9 2007-07-21 drh: if( pTable->nRef>0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pTable->nRef==0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Delete all indices associated with this table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ dbda8d6ce9 2007-07-21 drh: pNext = pIndex->pNext; dbda8d6ce9 2007-07-21 drh: assert( pIndex->pSchema==pTable->pSchema ); dbda8d6ce9 2007-07-21 drh: sqliteDeleteIndex(pIndex); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FOREIGN_KEY dbda8d6ce9 2007-07-21 drh: /* Delete all foreign keys associated with this table. The keys dbda8d6ce9 2007-07-21 drh: ** should have already been unlinked from the pSchema->aFKey hash table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){ dbda8d6ce9 2007-07-21 drh: pNextFKey = pFKey->pNextFrom; dbda8d6ce9 2007-07-21 drh: assert( sqlite3HashFind(&pTable->pSchema->aFKey, dbda8d6ce9 2007-07-21 drh: pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey ); c287665ba8 2007-09-14 drh: sqlite3_free(pFKey); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Delete the Table structure itself. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqliteResetColumnNames(pTable); c287665ba8 2007-09-14 drh: sqlite3_free(pTable->zName); c287665ba8 2007-09-14 drh: sqlite3_free(pTable->zColAff); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pTable->pSelect); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pTable->pCheck); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3VtabClear(pTable); c287665ba8 2007-09-14 drh: sqlite3_free(pTable); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Unlink the given table from the hash tables and the delete the dbda8d6ce9 2007-07-21 drh: ** table structure with all its indices and foreign keys. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: FKey *pF1, *pF2; dbda8d6ce9 2007-07-21 drh: Db *pDb; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( db!=0 ); dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: assert( zTabName && zTabName[0] ); dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, strlen(zTabName)+1,0); dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FOREIGN_KEY dbda8d6ce9 2007-07-21 drh: for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){ dbda8d6ce9 2007-07-21 drh: int nTo = strlen(pF1->zTo) + 1; dbda8d6ce9 2007-07-21 drh: pF2 = sqlite3HashFind(&pDb->pSchema->aFKey, pF1->zTo, nTo); dbda8d6ce9 2007-07-21 drh: if( pF2==pF1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3HashInsert(&pDb->pSchema->aFKey, pF1->zTo, nTo, pF1->pNextTo); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; } dbda8d6ce9 2007-07-21 drh: if( pF2 ){ dbda8d6ce9 2007-07-21 drh: pF2->pNextTo = pF1->pNextTo; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_InternChanges; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given a token, return a string that consists of the text of that dbda8d6ce9 2007-07-21 drh: ** token with any quotations removed. Space to hold the returned string dbda8d6ce9 2007-07-21 drh: ** is obtained from sqliteMalloc() and must be freed by the calling dbda8d6ce9 2007-07-21 drh: ** function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Tokens are often just pointers into the original SQL text and so dbda8d6ce9 2007-07-21 drh: ** are not \000 terminated and are not persistent. The returned string dbda8d6ce9 2007-07-21 drh: ** is \000 terminated and is persistent. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){ dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: if( pName ){ c287665ba8 2007-09-14 drh: zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n); dbda8d6ce9 2007-07-21 drh: sqlite3Dequote(zName); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zName = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zName; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Open the sqlite_master table stored in database number iDb for dbda8d6ce9 2007-07-21 drh: ** writing. The table is opened using cursor 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(p); dbda8d6ce9 2007-07-21 drh: sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The token *pName contains the name of a database (either "main" or dbda8d6ce9 2007-07-21 drh: ** "temp" or the name of an attached db). This routine returns the dbda8d6ce9 2007-07-21 drh: ** index of the named database in db->aDb[], or -1 if the named db dbda8d6ce9 2007-07-21 drh: ** does not exist. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){ dbda8d6ce9 2007-07-21 drh: int i = -1; /* Database number */ dbda8d6ce9 2007-07-21 drh: int n; /* Number of characters in the name */ dbda8d6ce9 2007-07-21 drh: Db *pDb; /* A database whose name space is being searched */ dbda8d6ce9 2007-07-21 drh: char *zName; /* Name we are searching for */ dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: zName = sqlite3NameFromToken(db, pName); dbda8d6ce9 2007-07-21 drh: if( zName ){ dbda8d6ce9 2007-07-21 drh: n = strlen(zName); dbda8d6ce9 2007-07-21 drh: for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ dbda8d6ce9 2007-07-21 drh: if( (!OMIT_TEMPDB || i!=1 ) && n==strlen(pDb->zName) && dbda8d6ce9 2007-07-21 drh: 0==sqlite3StrICmp(pDb->zName, zName) ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The table or view or trigger name is passed to this routine via tokens dbda8d6ce9 2007-07-21 drh: ** pName1 and pName2. If the table name was fully qualified, for example: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE xxx.yyy (...); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if dbda8d6ce9 2007-07-21 drh: ** the table name is not fully qualified, i.e.: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE yyy(...); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then pName1 is set to "yyy" and pName2 is "". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine sets the *ppUnqual pointer to point at the token (pName1 or dbda8d6ce9 2007-07-21 drh: ** pName2) that stores the unqualified table name. The index of the dbda8d6ce9 2007-07-21 drh: ** database "xxx" is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3TwoPartName( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing and code generating context */ dbda8d6ce9 2007-07-21 drh: Token *pName1, /* The "xxx" in the name "xxx.yyy" or "xxx" */ dbda8d6ce9 2007-07-21 drh: Token *pName2, /* The "yyy" in the name "xxx.yyy" */ dbda8d6ce9 2007-07-21 drh: Token **pUnqual /* Write the unqualified object name here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int iDb; /* Database holding the object */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pName2 && pName2->n>0 ){ dbda8d6ce9 2007-07-21 drh: assert( !db->init.busy ); dbda8d6ce9 2007-07-21 drh: *pUnqual = pName2; dbda8d6ce9 2007-07-21 drh: iDb = sqlite3FindDb(db, pName1); dbda8d6ce9 2007-07-21 drh: if( iDb<0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "unknown database %T", pName1); dbda8d6ce9 2007-07-21 drh: pParse->nErr++; dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( db->init.iDb==0 || db->init.busy ); dbda8d6ce9 2007-07-21 drh: iDb = db->init.iDb; dbda8d6ce9 2007-07-21 drh: *pUnqual = pName1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return iDb; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is used to check if the UTF-8 string zName is a legal dbda8d6ce9 2007-07-21 drh: ** unqualified name for a new schema object (table, index, view or dbda8d6ce9 2007-07-21 drh: ** trigger). All names are legal except those that begin with the string dbda8d6ce9 2007-07-21 drh: ** "sqlite_" (in upper, lower or mixed case). This portion of the namespace dbda8d6ce9 2007-07-21 drh: ** is reserved for internal use. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){ dbda8d6ce9 2007-07-21 drh: if( !pParse->db->init.busy && pParse->nested==0 dbda8d6ce9 2007-07-21 drh: && (pParse->db->flags & SQLITE_WriteSchema)==0 dbda8d6ce9 2007-07-21 drh: && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Begin constructing a new table representation in memory. This is dbda8d6ce9 2007-07-21 drh: ** the first of several action routines that get called in response dbda8d6ce9 2007-07-21 drh: ** to a CREATE TABLE statement. In particular, this routine is called dbda8d6ce9 2007-07-21 drh: ** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp dbda8d6ce9 2007-07-21 drh: ** flag is true if the table should be stored in the auxiliary database dbda8d6ce9 2007-07-21 drh: ** file instead of in the main database file. This is normally the case dbda8d6ce9 2007-07-21 drh: ** when the "TEMP" or "TEMPORARY" keyword occurs in between dbda8d6ce9 2007-07-21 drh: ** CREATE and TABLE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The new table record is initialized and put in pParse->pNewTable. dbda8d6ce9 2007-07-21 drh: ** As more of the CREATE TABLE statement is parsed, additional action dbda8d6ce9 2007-07-21 drh: ** routines will be called to add more information to this record. dbda8d6ce9 2007-07-21 drh: ** At the end of the CREATE TABLE statement, the sqlite3EndTable() routine dbda8d6ce9 2007-07-21 drh: ** is called to complete the construction of the new table record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3StartTable( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: Token *pName1, /* First part of the name of the table or view */ dbda8d6ce9 2007-07-21 drh: Token *pName2, /* Second part of the name of the table or view */ dbda8d6ce9 2007-07-21 drh: int isTemp, /* True if this is a TEMP table */ dbda8d6ce9 2007-07-21 drh: int isView, /* True if this is a VIEW */ dbda8d6ce9 2007-07-21 drh: int isVirtual, /* True if this is a VIRTUAL table */ dbda8d6ce9 2007-07-21 drh: int noErr /* Do nothing if table already exists */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Table *pTable; dbda8d6ce9 2007-07-21 drh: char *zName = 0; /* The name of the new table */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: int iDb; /* Database number to create the table in */ dbda8d6ce9 2007-07-21 drh: Token *pName; /* Unqualified name of the table to create */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The table or view name to create is passed to this routine via tokens dbda8d6ce9 2007-07-21 drh: ** pName1 and pName2. If the table name was fully qualified, for example: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE xxx.yyy (...); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if dbda8d6ce9 2007-07-21 drh: ** the table name is not fully qualified, i.e.: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE yyy(...); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then pName1 is set to "yyy" and pName2 is "". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The call below sets the pName pointer to point at the token (pName1 or dbda8d6ce9 2007-07-21 drh: ** pName2) that stores the unqualified table name. The variable iDb is dbda8d6ce9 2007-07-21 drh: ** set to the index of the database that the table or view is to be dbda8d6ce9 2007-07-21 drh: ** created in. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); dbda8d6ce9 2007-07-21 drh: if( iDb<0 ) return; dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && isTemp && iDb>1 ){ dbda8d6ce9 2007-07-21 drh: /* If creating a temp table, the name may not be qualified */ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && isTemp ) iDb = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pParse->sNameToken = *pName; c287665ba8 2007-09-14 drh: zName = sqlite3NameFromToken(db, pName); dbda8d6ce9 2007-07-21 drh: if( zName==0 ) return; dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ dbda8d6ce9 2007-07-21 drh: goto begin_table_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( db->init.iDb==1 ) isTemp = 1; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: assert( (isTemp & 1)==isTemp ); dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int code; dbda8d6ce9 2007-07-21 drh: char *zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto begin_table_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( isView ){ dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && isTemp ){ dbda8d6ce9 2007-07-21 drh: code = SQLITE_CREATE_TEMP_VIEW; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: code = SQLITE_CREATE_VIEW; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && isTemp ){ dbda8d6ce9 2007-07-21 drh: code = SQLITE_CREATE_TEMP_TABLE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: code = SQLITE_CREATE_TABLE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto begin_table_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the new table name does not collide with an existing dbda8d6ce9 2007-07-21 drh: ** index or table name in the same database. Issue an error message if dbda8d6ce9 2007-07-21 drh: ** it does. The exception is if the statement being parsed was passed dbda8d6ce9 2007-07-21 drh: ** to an sqlite3_declare_vtab() call. In that case only the column names dbda8d6ce9 2007-07-21 drh: ** and types will be used, so there is no need to test for namespace dbda8d6ce9 2007-07-21 drh: ** collisions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !IN_DECLARE_VTAB ){ dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ dbda8d6ce9 2007-07-21 drh: goto begin_table_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName); dbda8d6ce9 2007-07-21 drh: if( pTable ){ dbda8d6ce9 2007-07-21 drh: if( !noErr ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "table %T already exists", pName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto begin_table_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); dbda8d6ce9 2007-07-21 drh: goto begin_table_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pTable = sqlite3DbMallocZero(db, sizeof(Table)); dbda8d6ce9 2007-07-21 drh: if( pTable==0 ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: pParse->nErr++; dbda8d6ce9 2007-07-21 drh: goto begin_table_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTable->zName = zName; dbda8d6ce9 2007-07-21 drh: pTable->iPKey = -1; dbda8d6ce9 2007-07-21 drh: pTable->pSchema = db->aDb[iDb].pSchema; dbda8d6ce9 2007-07-21 drh: pTable->nRef = 1; dbda8d6ce9 2007-07-21 drh: if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable); dbda8d6ce9 2007-07-21 drh: pParse->pNewTable = pTable; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is the magic sqlite_sequence table used by autoincrement, dbda8d6ce9 2007-07-21 drh: ** then record a pointer to this table in the main database structure dbda8d6ce9 2007-07-21 drh: ** so that INSERT can find the table easily. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){ dbda8d6ce9 2007-07-21 drh: pTable->pSchema->pSeqTab = pTable; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin generating the code that will insert the table record into dbda8d6ce9 2007-07-21 drh: ** the SQLITE_MASTER table. Note in particular that we must go ahead dbda8d6ce9 2007-07-21 drh: ** and allocate the record number for the table entry now. Before any dbda8d6ce9 2007-07-21 drh: ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause dbda8d6ce9 2007-07-21 drh: ** indices to be created and the table record must come before the dbda8d6ce9 2007-07-21 drh: ** indices. Hence, the record number for the table must be allocated dbda8d6ce9 2007-07-21 drh: ** now. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){ dbda8d6ce9 2007-07-21 drh: int lbl; dbda8d6ce9 2007-07-21 drh: int fileFormat; dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( isVirtual ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_VBegin, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the file format and encoding in the database have not been set, dbda8d6ce9 2007-07-21 drh: ** set them now. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */ c287665ba8 2007-09-14 drh: sqlite3VdbeUsesBtree(v, iDb); dbda8d6ce9 2007-07-21 drh: lbl = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_If, 0, lbl); dbda8d6ce9 2007-07-21 drh: fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? dbda8d6ce9 2007-07-21 drh: 1 : SQLITE_MAX_FILE_FORMAT; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, fileFormat, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, lbl); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This just creates a place-holder record in the sqlite_master table. dbda8d6ce9 2007-07-21 drh: ** The record created does not contain anything yet. It will be replaced dbda8d6ce9 2007-07-21 drh: ** by the real entry in code generated at sqlite3EndTable(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The rowid for the new entry is left on the top of the stack. dbda8d6ce9 2007-07-21 drh: ** The rowid value is needed by the code that sqlite3EndTable will dbda8d6ce9 2007-07-21 drh: ** generate. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) dbda8d6ce9 2007-07-21 drh: if( isView || isVirtual ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, 0, 0); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3OpenMasterTable(pParse, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, 0, OPFLAG_APPEND); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pull, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Normal (non-error) return. */ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If an error occurs, we jump here */ dbda8d6ce9 2007-07-21 drh: begin_table_error: c287665ba8 2007-09-14 drh: sqlite3_free(zName); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This macro is used to compare two strings in a case-insensitive manner. dbda8d6ce9 2007-07-21 drh: ** It is slightly faster than calling sqlite3StrICmp() directly, but dbda8d6ce9 2007-07-21 drh: ** produces larger code. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** WARNING: This macro is not compatible with the strcmp() family. It dbda8d6ce9 2007-07-21 drh: ** returns true if the two strings are equal, otherwise false. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define STRICMP(x, y) (\ dbda8d6ce9 2007-07-21 drh: sqlite3UpperToLower[*(unsigned char *)(x)]== \ dbda8d6ce9 2007-07-21 drh: sqlite3UpperToLower[*(unsigned char *)(y)] \ dbda8d6ce9 2007-07-21 drh: && sqlite3StrICmp((x)+1,(y)+1)==0 ) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a new column to the table currently being constructed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The parser calls this routine once for each column declaration dbda8d6ce9 2007-07-21 drh: ** in a CREATE TABLE statement. sqlite3StartTable() gets called dbda8d6ce9 2007-07-21 drh: ** first to get things going. Then this routine is called for each dbda8d6ce9 2007-07-21 drh: ** column. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: Column *pCol; dbda8d6ce9 2007-07-21 drh: if( (p = pParse->pNewTable)==0 ) return; dbda8d6ce9 2007-07-21 drh: if( p->nCol+1>SQLITE_MAX_COLUMN ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: z = sqlite3NameFromToken(pParse->db, pName); dbda8d6ce9 2007-07-21 drh: if( z==0 ) return; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( STRICMP(z, p->aCol[i].zName) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); c287665ba8 2007-09-14 drh: sqlite3_free(z); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (p->nCol & 0x7)==0 ){ dbda8d6ce9 2007-07-21 drh: Column *aNew; c287665ba8 2007-09-14 drh: aNew = sqlite3DbRealloc(pParse->db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0])); dbda8d6ce9 2007-07-21 drh: if( aNew==0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(z); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->aCol = aNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCol = &p->aCol[p->nCol]; dbda8d6ce9 2007-07-21 drh: memset(pCol, 0, sizeof(p->aCol[0])); dbda8d6ce9 2007-07-21 drh: pCol->zName = z; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there is no type specified, columns have the default affinity dbda8d6ce9 2007-07-21 drh: ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will dbda8d6ce9 2007-07-21 drh: ** be called next to set pCol->affinity correctly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pCol->affinity = SQLITE_AFF_NONE; dbda8d6ce9 2007-07-21 drh: p->nCol++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called by the parser while in the middle of dbda8d6ce9 2007-07-21 drh: ** parsing a CREATE TABLE statement. A "NOT NULL" constraint has dbda8d6ce9 2007-07-21 drh: ** been seen on a column. This routine sets the notNull flag on dbda8d6ce9 2007-07-21 drh: ** the column currently under construction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( (p = pParse->pNewTable)==0 ) return; dbda8d6ce9 2007-07-21 drh: i = p->nCol-1; dbda8d6ce9 2007-07-21 drh: if( i>=0 ) p->aCol[i].notNull = onError; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Scan the column type name zType (length nType) and return the dbda8d6ce9 2007-07-21 drh: ** associated affinity type. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine does a case-independent search of zType for the dbda8d6ce9 2007-07-21 drh: ** substrings in the following table. If one of the substrings is dbda8d6ce9 2007-07-21 drh: ** found, the corresponding affinity is returned. If zType contains dbda8d6ce9 2007-07-21 drh: ** more than one of the substrings, entries toward the top of dbda8d6ce9 2007-07-21 drh: ** the table take priority. For example, if zType is 'BLOBINT', dbda8d6ce9 2007-07-21 drh: ** SQLITE_AFF_INTEGER is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Substring | Affinity dbda8d6ce9 2007-07-21 drh: ** -------------------------------- dbda8d6ce9 2007-07-21 drh: ** 'INT' | SQLITE_AFF_INTEGER dbda8d6ce9 2007-07-21 drh: ** 'CHAR' | SQLITE_AFF_TEXT dbda8d6ce9 2007-07-21 drh: ** 'CLOB' | SQLITE_AFF_TEXT dbda8d6ce9 2007-07-21 drh: ** 'TEXT' | SQLITE_AFF_TEXT dbda8d6ce9 2007-07-21 drh: ** 'BLOB' | SQLITE_AFF_NONE dbda8d6ce9 2007-07-21 drh: ** 'REAL' | SQLITE_AFF_REAL dbda8d6ce9 2007-07-21 drh: ** 'FLOA' | SQLITE_AFF_REAL dbda8d6ce9 2007-07-21 drh: ** 'DOUB' | SQLITE_AFF_REAL dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If none of the substrings in the above table are found, dbda8d6ce9 2007-07-21 drh: ** SQLITE_AFF_NUMERIC is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE char sqlite3AffinityType(const Token *pType){ dbda8d6ce9 2007-07-21 drh: u32 h = 0; dbda8d6ce9 2007-07-21 drh: char aff = SQLITE_AFF_NUMERIC; dbda8d6ce9 2007-07-21 drh: const unsigned char *zIn = pType->z; dbda8d6ce9 2007-07-21 drh: const unsigned char *zEnd = &pType->z[pType->n]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( zIn!=zEnd ){ dbda8d6ce9 2007-07-21 drh: h = (h<<8) + sqlite3UpperToLower[*zIn]; dbda8d6ce9 2007-07-21 drh: zIn++; dbda8d6ce9 2007-07-21 drh: if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_TEXT; dbda8d6ce9 2007-07-21 drh: }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_TEXT; dbda8d6ce9 2007-07-21 drh: }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_TEXT; dbda8d6ce9 2007-07-21 drh: }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ dbda8d6ce9 2007-07-21 drh: && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_NONE; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */ dbda8d6ce9 2007-07-21 drh: && aff==SQLITE_AFF_NUMERIC ){ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_REAL; dbda8d6ce9 2007-07-21 drh: }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */ dbda8d6ce9 2007-07-21 drh: && aff==SQLITE_AFF_NUMERIC ){ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_REAL; dbda8d6ce9 2007-07-21 drh: }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */ dbda8d6ce9 2007-07-21 drh: && aff==SQLITE_AFF_NUMERIC ){ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_REAL; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */ dbda8d6ce9 2007-07-21 drh: aff = SQLITE_AFF_INTEGER; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return aff; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called by the parser while in the middle of dbda8d6ce9 2007-07-21 drh: ** parsing a CREATE TABLE statement. The pFirst token is the first dbda8d6ce9 2007-07-21 drh: ** token in the sequence of tokens that describe the type of the dbda8d6ce9 2007-07-21 drh: ** column currently under construction. pLast is the last token dbda8d6ce9 2007-07-21 drh: ** in the sequence. Use this information to construct a string dbda8d6ce9 2007-07-21 drh: ** that contains the typename of the column and store that string dbda8d6ce9 2007-07-21 drh: ** in zType. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Column *pCol; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( (p = pParse->pNewTable)==0 ) return; dbda8d6ce9 2007-07-21 drh: i = p->nCol-1; dbda8d6ce9 2007-07-21 drh: if( i<0 ) return; dbda8d6ce9 2007-07-21 drh: pCol = &p->aCol[i]; c287665ba8 2007-09-14 drh: sqlite3_free(pCol->zType); c287665ba8 2007-09-14 drh: pCol->zType = sqlite3NameFromToken(pParse->db, pType); dbda8d6ce9 2007-07-21 drh: pCol->affinity = sqlite3AffinityType(pType); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The expression is the default value for the most recently added column dbda8d6ce9 2007-07-21 drh: ** of the table currently under construction. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Default value expressions must be constant. Raise an exception if this dbda8d6ce9 2007-07-21 drh: ** is not the case. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is called by the parser while in the middle of dbda8d6ce9 2007-07-21 drh: ** parsing a CREATE TABLE statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: Column *pCol; dbda8d6ce9 2007-07-21 drh: if( (p = pParse->pNewTable)!=0 ){ dbda8d6ce9 2007-07-21 drh: pCol = &(p->aCol[p->nCol-1]); dbda8d6ce9 2007-07-21 drh: if( !sqlite3ExprIsConstantOrFunction(pExpr) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", dbda8d6ce9 2007-07-21 drh: pCol->zName); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Expr *pCopy; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pCol->pDflt); c287665ba8 2007-09-14 drh: pCol->pDflt = pCopy = sqlite3ExprDup(db, pExpr); dbda8d6ce9 2007-07-21 drh: if( pCopy ){ c287665ba8 2007-09-14 drh: sqlite3TokenCopy(db, &pCopy->span, &pExpr->span); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Designate the PRIMARY KEY for the table. pList is a list of names dbda8d6ce9 2007-07-21 drh: ** of columns that form the primary key. If pList is NULL, then the dbda8d6ce9 2007-07-21 drh: ** most recently added column of the table is the primary key. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A table can have at most one primary key. If the table already has dbda8d6ce9 2007-07-21 drh: ** a primary key (and this is the second primary key) then create an dbda8d6ce9 2007-07-21 drh: ** error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the PRIMARY KEY is on a single column whose datatype is INTEGER, dbda8d6ce9 2007-07-21 drh: ** then we will try to use that column as the rowid. Set the Table.iPKey dbda8d6ce9 2007-07-21 drh: ** field of the table under construction to be the index of the dbda8d6ce9 2007-07-21 drh: ** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is dbda8d6ce9 2007-07-21 drh: ** no INTEGER PRIMARY KEY. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the key is not an INTEGER PRIMARY KEY, then create a unique dbda8d6ce9 2007-07-21 drh: ** index for the key. No index is created for INTEGER PRIMARY KEYs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddPrimaryKey( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: ExprList *pList, /* List of field names to be indexed */ dbda8d6ce9 2007-07-21 drh: int onError, /* What to do with a uniqueness conflict */ dbda8d6ce9 2007-07-21 drh: int autoInc, /* True if the AUTOINCREMENT keyword is present */ dbda8d6ce9 2007-07-21 drh: int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Table *pTab = pParse->pNewTable; dbda8d6ce9 2007-07-21 drh: char *zType = 0; dbda8d6ce9 2007-07-21 drh: int iCol = -1, i; dbda8d6ce9 2007-07-21 drh: if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit; dbda8d6ce9 2007-07-21 drh: if( pTab->hasPrimKey ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "table \"%s\" has more than one primary key", pTab->zName); dbda8d6ce9 2007-07-21 drh: goto primary_key_exit; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab->hasPrimKey = 1; dbda8d6ce9 2007-07-21 drh: if( pList==0 ){ dbda8d6ce9 2007-07-21 drh: iCol = pTab->nCol - 1; dbda8d6ce9 2007-07-21 drh: pTab->aCol[iCol].isPrimKey = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: for(iCol=0; iCol<pTab->nCol; iCol++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iCol<pTab->nCol ){ dbda8d6ce9 2007-07-21 drh: pTab->aCol[iCol].isPrimKey = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pList->nExpr>1 ) iCol = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iCol>=0 && iCol<pTab->nCol ){ dbda8d6ce9 2007-07-21 drh: zType = pTab->aCol[iCol].zType; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zType && sqlite3StrICmp(zType, "INTEGER")==0 dbda8d6ce9 2007-07-21 drh: && sortOrder==SQLITE_SO_ASC ){ dbda8d6ce9 2007-07-21 drh: pTab->iPKey = iCol; dbda8d6ce9 2007-07-21 drh: pTab->keyConf = onError; dbda8d6ce9 2007-07-21 drh: pTab->autoInc = autoInc; dbda8d6ce9 2007-07-21 drh: }else if( autoInc ){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " dbda8d6ce9 2007-07-21 drh: "INTEGER PRIMARY KEY"); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); dbda8d6ce9 2007-07-21 drh: pList = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: primary_key_exit: dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pList); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a new CHECK constraint to the table currently under construction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddCheckConstraint( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: Expr *pCheckExpr /* The check expression */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: Table *pTab = pParse->pNewTable; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: if( pTab && !IN_DECLARE_VTAB ){ dbda8d6ce9 2007-07-21 drh: /* The CHECK expression must be duplicated so that tokens refer dbda8d6ce9 2007-07-21 drh: ** to malloced space and not the (ephemeral) text of the CREATE TABLE dbda8d6ce9 2007-07-21 drh: ** statement */ c287665ba8 2007-09-14 drh: pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck, c287665ba8 2007-09-14 drh: sqlite3ExprDup(db, pCheckExpr)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pCheckExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the collation function of the most recently parsed table column dbda8d6ce9 2007-07-21 drh: ** to the CollSeq given. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( (p = pParse->pNewTable)==0 ) return; dbda8d6ce9 2007-07-21 drh: i = p->nCol-1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3LocateCollSeq(pParse, zType, nType) ){ dbda8d6ce9 2007-07-21 drh: Index *pIdx; c287665ba8 2007-09-14 drh: p->aCol[i].zColl = sqlite3DbStrNDup(pParse->db, zType, nType); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>", dbda8d6ce9 2007-07-21 drh: ** then an index may have been created on this column before the dbda8d6ce9 2007-07-21 drh: ** collation type was added. Correct this if it is the case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: assert( pIdx->nColumn==1 ); dbda8d6ce9 2007-07-21 drh: if( pIdx->aiColumn[0]==i ){ dbda8d6ce9 2007-07-21 drh: pIdx->azColl[0] = p->aCol[i].zColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function returns the collation sequence for database native text dbda8d6ce9 2007-07-21 drh: ** encoding identified by the string zName, length nName. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the requested collation sequence is not available, or not available dbda8d6ce9 2007-07-21 drh: ** in the database native encoding, the collation factory is invoked to dbda8d6ce9 2007-07-21 drh: ** request it. If the collation factory does not supply such a sequence, dbda8d6ce9 2007-07-21 drh: ** and the sequence is available in another text encoding, then that is dbda8d6ce9 2007-07-21 drh: ** returned instead. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If no versions of the requested collations sequence are available, or dbda8d6ce9 2007-07-21 drh: ** another error occurs, NULL is returned and an error message written into dbda8d6ce9 2007-07-21 drh: ** pParse. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is a wrapper around sqlite3FindCollSeq(). This routine dbda8d6ce9 2007-07-21 drh: ** invokes the collation factory if the named collation cannot be found dbda8d6ce9 2007-07-21 drh: ** and generates an error message. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: u8 enc = ENC(db); dbda8d6ce9 2007-07-21 drh: u8 initbusy = db->init.busy; dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy); dbda8d6ce9 2007-07-21 drh: if( !initbusy && (!pColl || !pColl->xCmp) ){ dbda8d6ce9 2007-07-21 drh: pColl = sqlite3GetCollSeq(db, pColl, zName, nName); dbda8d6ce9 2007-07-21 drh: if( !pColl ){ dbda8d6ce9 2007-07-21 drh: if( nName<0 ){ dbda8d6ce9 2007-07-21 drh: nName = strlen(zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such collation sequence: %.*s", nName, zName); dbda8d6ce9 2007-07-21 drh: pColl = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return pColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will increment the schema cookie. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The schema cookie is used to determine when the schema for the dbda8d6ce9 2007-07-21 drh: ** database changes. After each schema change, the cookie value dbda8d6ce9 2007-07-21 drh: ** changes. When a process first reads the schema it records the dbda8d6ce9 2007-07-21 drh: ** cookie. Thereafter, whenever it goes to access the database, dbda8d6ce9 2007-07-21 drh: ** it checks the cookie to make sure the schema has not changed dbda8d6ce9 2007-07-21 drh: ** since it was last read. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This plan is not completely bullet-proof. It is possible for dbda8d6ce9 2007-07-21 drh: ** the schema to change multiple times and for the cookie to be dbda8d6ce9 2007-07-21 drh: ** set back to prior value. But schema changes are infrequent dbda8d6ce9 2007-07-21 drh: ** and the probability of hitting the same cookie value is only dbda8d6ce9 2007-07-21 drh: ** 1 chance in 2^32. So we're safe enough. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ChangeCookie(sqlite3 *db, Vdbe *v, int iDb){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Measure the number of characters needed to output the given dbda8d6ce9 2007-07-21 drh: ** identifier. The number returned includes any quotes used dbda8d6ce9 2007-07-21 drh: ** but does not include the null terminator. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The estimate is conservative. It might be larger that what is dbda8d6ce9 2007-07-21 drh: ** really needed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int identLength(const char *z){ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: for(n=0; *z; n++, z++){ dbda8d6ce9 2007-07-21 drh: if( *z=='"' ){ n++; } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return n + 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write an identifier onto the end of the given string. Add dbda8d6ce9 2007-07-21 drh: ** quote characters as needed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void identPut(char *z, int *pIdx, char *zSignedIdent){ dbda8d6ce9 2007-07-21 drh: unsigned char *zIdent = (unsigned char*)zSignedIdent; dbda8d6ce9 2007-07-21 drh: int i, j, needQuote; dbda8d6ce9 2007-07-21 drh: i = *pIdx; dbda8d6ce9 2007-07-21 drh: for(j=0; zIdent[j]; j++){ dbda8d6ce9 2007-07-21 drh: if( !isalnum(zIdent[j]) && zIdent[j]!='_' ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: needQuote = zIdent[j]!=0 || isdigit(zIdent[0]) dbda8d6ce9 2007-07-21 drh: || sqlite3KeywordCode(zIdent, j)!=TK_ID; dbda8d6ce9 2007-07-21 drh: if( needQuote ) z[i++] = '"'; dbda8d6ce9 2007-07-21 drh: for(j=0; zIdent[j]; j++){ dbda8d6ce9 2007-07-21 drh: z[i++] = zIdent[j]; dbda8d6ce9 2007-07-21 drh: if( zIdent[j]=='"' ) z[i++] = '"'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( needQuote ) z[i++] = '"'; dbda8d6ce9 2007-07-21 drh: z[i] = 0; dbda8d6ce9 2007-07-21 drh: *pIdx = i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate a CREATE TABLE statement appropriate for the given dbda8d6ce9 2007-07-21 drh: ** table. Memory to hold the text of the statement is obtained dbda8d6ce9 2007-07-21 drh: ** from sqliteMalloc() and must be freed by the calling function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static char *createTableStmt(Table *p, int isTemp){ dbda8d6ce9 2007-07-21 drh: int i, k, n; dbda8d6ce9 2007-07-21 drh: char *zStmt; dbda8d6ce9 2007-07-21 drh: char *zSep, *zSep2, *zEnd, *z; dbda8d6ce9 2007-07-21 drh: Column *pCol; dbda8d6ce9 2007-07-21 drh: n = 0; dbda8d6ce9 2007-07-21 drh: for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){ dbda8d6ce9 2007-07-21 drh: n += identLength(pCol->zName); dbda8d6ce9 2007-07-21 drh: z = pCol->zType; dbda8d6ce9 2007-07-21 drh: if( z ){ dbda8d6ce9 2007-07-21 drh: n += (strlen(z) + 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: n += identLength(p->zName); dbda8d6ce9 2007-07-21 drh: if( n<50 ){ dbda8d6ce9 2007-07-21 drh: zSep = ""; dbda8d6ce9 2007-07-21 drh: zSep2 = ","; dbda8d6ce9 2007-07-21 drh: zEnd = ")"; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zSep = "\n "; dbda8d6ce9 2007-07-21 drh: zSep2 = ",\n "; dbda8d6ce9 2007-07-21 drh: zEnd = "\n)"; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: n += 35 + 6*p->nCol; c287665ba8 2007-09-14 drh: zStmt = sqlite3_malloc( n ); dbda8d6ce9 2007-07-21 drh: if( zStmt==0 ) return 0; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(n, zStmt, dbda8d6ce9 2007-07-21 drh: !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE "); dbda8d6ce9 2007-07-21 drh: k = strlen(zStmt); dbda8d6ce9 2007-07-21 drh: identPut(zStmt, &k, p->zName); dbda8d6ce9 2007-07-21 drh: zStmt[k++] = '('; dbda8d6ce9 2007-07-21 drh: for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(n-k, &zStmt[k], zSep); dbda8d6ce9 2007-07-21 drh: k += strlen(&zStmt[k]); dbda8d6ce9 2007-07-21 drh: zSep = zSep2; dbda8d6ce9 2007-07-21 drh: identPut(zStmt, &k, pCol->zName); dbda8d6ce9 2007-07-21 drh: if( (z = pCol->zType)!=0 ){ dbda8d6ce9 2007-07-21 drh: zStmt[k++] = ' '; dbda8d6ce9 2007-07-21 drh: assert( strlen(z)+k+1<=n ); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(n-k, &zStmt[k], "%s", z); dbda8d6ce9 2007-07-21 drh: k += strlen(z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd); dbda8d6ce9 2007-07-21 drh: return zStmt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called to report the final ")" that terminates dbda8d6ce9 2007-07-21 drh: ** a CREATE TABLE statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The table structure that other action routines have been building dbda8d6ce9 2007-07-21 drh: ** is added to the internal hash tables, assuming no errors have dbda8d6ce9 2007-07-21 drh: ** occurred. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An entry for the table is made in the master table on disk, unless dbda8d6ce9 2007-07-21 drh: ** this is a temporary table or db->init.busy==1. When db->init.busy==1 dbda8d6ce9 2007-07-21 drh: ** it means we are reading the sqlite_master table because we just dbda8d6ce9 2007-07-21 drh: ** connected to the database or because the sqlite_master table has dbda8d6ce9 2007-07-21 drh: ** recently changed, so the entry for this table already exists in dbda8d6ce9 2007-07-21 drh: ** the sqlite_master table. We do not want to create it again. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the pSelect argument is not NULL, it means that this routine dbda8d6ce9 2007-07-21 drh: ** was called to create a table generated from a dbda8d6ce9 2007-07-21 drh: ** "CREATE TABLE ... AS SELECT ..." statement. The column names of dbda8d6ce9 2007-07-21 drh: ** the new table will match the result set of the SELECT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3EndTable( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parse context */ dbda8d6ce9 2007-07-21 drh: Token *pCons, /* The ',' token after the last column defn. */ dbda8d6ce9 2007-07-21 drh: Token *pEnd, /* The final ')' token in the CREATE TABLE */ dbda8d6ce9 2007-07-21 drh: Select *pSelect /* Select from a "CREATE ... AS SELECT" */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( (pEnd==0 && pSelect==0) || pParse->nErr || db->mallocFailed ) { dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p = pParse->pNewTable; dbda8d6ce9 2007-07-21 drh: if( p==0 ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( !db->init.busy || !pSelect ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(db, p->pSchema); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: /* Resolve names in all CHECK constraint expressions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pCheck ){ dbda8d6ce9 2007-07-21 drh: SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ dbda8d6ce9 2007-07-21 drh: NameContext sNC; /* Name context for pParse->pNewTable */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memset(&sNC, 0, sizeof(sNC)); dbda8d6ce9 2007-07-21 drh: memset(&sSrc, 0, sizeof(sSrc)); dbda8d6ce9 2007-07-21 drh: sSrc.nSrc = 1; dbda8d6ce9 2007-07-21 drh: sSrc.a[0].zName = p->zName; dbda8d6ce9 2007-07-21 drh: sSrc.a[0].pTab = p; dbda8d6ce9 2007-07-21 drh: sSrc.a[0].iCursor = -1; dbda8d6ce9 2007-07-21 drh: sNC.pParse = pParse; dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = &sSrc; dbda8d6ce9 2007-07-21 drh: sNC.isCheck = 1; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, p->pCheck) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_CHECK) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the db->init.busy is 1 it means we are reading the SQL off the dbda8d6ce9 2007-07-21 drh: ** "sqlite_master" or "sqlite_temp_master" table on the disk. dbda8d6ce9 2007-07-21 drh: ** So do not write to the disk again. Extract the root page number dbda8d6ce9 2007-07-21 drh: ** for the table from the db->init.newTnum field. (The page number dbda8d6ce9 2007-07-21 drh: ** should have been put there by the sqliteOpenCb routine.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->init.busy ){ dbda8d6ce9 2007-07-21 drh: p->tnum = db->init.newTnum; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If not initializing, then create a record for the new table dbda8d6ce9 2007-07-21 drh: ** in the SQLITE_MASTER table of the database. The record number dbda8d6ce9 2007-07-21 drh: ** for the new table entry should already be on the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If this is a TEMPORARY table, write the entry into the auxiliary dbda8d6ce9 2007-07-21 drh: ** file instead of into the main database file. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: char *zType; /* "view" or "table" */ dbda8d6ce9 2007-07-21 drh: char *zType2; /* "VIEW" or "TABLE" */ dbda8d6ce9 2007-07-21 drh: char *zStmt; /* Text of the CREATE TABLE or CREATE VIEW statement */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, 0, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create the rootpage for the new table and push it onto the stack. dbda8d6ce9 2007-07-21 drh: ** A view has no rootpage, so just push a zero onto the stack for dbda8d6ce9 2007-07-21 drh: ** views. Initialize zType at the same time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pSelect==0 ){ dbda8d6ce9 2007-07-21 drh: /* A regular table */ dbda8d6ce9 2007-07-21 drh: zType = "table"; dbda8d6ce9 2007-07-21 drh: zType2 = "TABLE"; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* A view */ dbda8d6ce9 2007-07-21 drh: zType = "view"; dbda8d6ce9 2007-07-21 drh: zType2 = "VIEW"; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT dbda8d6ce9 2007-07-21 drh: ** statement to populate the new table. The root-page number for the dbda8d6ce9 2007-07-21 drh: ** new table is on the top of the vdbe stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Once the SELECT has been coded by sqlite3Select(), it is in a dbda8d6ce9 2007-07-21 drh: ** suitable state to query for the column names and types to be used dbda8d6ce9 2007-07-21 drh: ** by the new table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A shared-cache write-lock is not required to write to the new table, dbda8d6ce9 2007-07-21 drh: ** as a schema-lock must have already been obtained to create it. Since dbda8d6ce9 2007-07-21 drh: ** a schema-lock excludes all other database users, the write-lock would dbda8d6ce9 2007-07-21 drh: ** be redundant. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pSelect ){ dbda8d6ce9 2007-07-21 drh: Table *pSelTab; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0); dbda8d6ce9 2007-07-21 drh: pParse->nTab = 2; dbda8d6ce9 2007-07-21 drh: sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, 1, 0); dbda8d6ce9 2007-07-21 drh: if( pParse->nErr==0 ){ dbda8d6ce9 2007-07-21 drh: pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSelect); dbda8d6ce9 2007-07-21 drh: if( pSelTab==0 ) return; dbda8d6ce9 2007-07-21 drh: assert( p->aCol==0 ); dbda8d6ce9 2007-07-21 drh: p->nCol = pSelTab->nCol; dbda8d6ce9 2007-07-21 drh: p->aCol = pSelTab->aCol; dbda8d6ce9 2007-07-21 drh: pSelTab->nCol = 0; dbda8d6ce9 2007-07-21 drh: pSelTab->aCol = 0; dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(pSelTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Compute the complete text of the CREATE statement */ dbda8d6ce9 2007-07-21 drh: if( pSelect ){ c287665ba8 2007-09-14 drh: zStmt = createTableStmt(p, p->pSchema==db->aDb[1].pSchema); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: n = pEnd->z - pParse->sNameToken.z + 1; c287665ba8 2007-09-14 drh: zStmt = sqlite3MPrintf(db, c287665ba8 2007-09-14 drh: "CREATE %s %.*s", zType2, n, pParse->sNameToken.z c287665ba8 2007-09-14 drh: ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A slot for the record has already been allocated in the dbda8d6ce9 2007-07-21 drh: ** SQLITE_MASTER table. We just need to update that slot with all dbda8d6ce9 2007-07-21 drh: ** the information we've collected. The rowid for the preallocated dbda8d6ce9 2007-07-21 drh: ** slot is the 2nd item on the stack. The top of the stack is the dbda8d6ce9 2007-07-21 drh: ** root page for the new table (or a 0 if this is a view). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "UPDATE %Q.%s " dbda8d6ce9 2007-07-21 drh: "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q " dbda8d6ce9 2007-07-21 drh: "WHERE rowid=#1", dbda8d6ce9 2007-07-21 drh: db->aDb[iDb].zName, SCHEMA_TABLE(iDb), dbda8d6ce9 2007-07-21 drh: zType, dbda8d6ce9 2007-07-21 drh: p->zName, dbda8d6ce9 2007-07-21 drh: p->zName, dbda8d6ce9 2007-07-21 drh: zStmt dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: sqlite3_free(zStmt); dbda8d6ce9 2007-07-21 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: /* Check to see if we need to create an sqlite_sequence table for dbda8d6ce9 2007-07-21 drh: ** keeping track of autoincrement keys. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->autoInc ){ dbda8d6ce9 2007-07-21 drh: Db *pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: if( pDb->pSchema->pSeqTab==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "CREATE TABLE %Q.sqlite_sequence(name,seq)", dbda8d6ce9 2007-07-21 drh: pDb->zName dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Reparse everything to update our internal data structures */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, c287665ba8 2007-09-14 drh: sqlite3MPrintf(db, "tbl_name='%q'",p->zName), P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add the table to the in-memory representation of the database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->init.busy && pParse->nErr==0 ){ dbda8d6ce9 2007-07-21 drh: Table *pOld; dbda8d6ce9 2007-07-21 drh: FKey *pFKey; dbda8d6ce9 2007-07-21 drh: Schema *pSchema = p->pSchema; dbda8d6ce9 2007-07-21 drh: pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, strlen(p->zName)+1,p); dbda8d6ce9 2007-07-21 drh: if( pOld ){ dbda8d6ce9 2007-07-21 drh: assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FOREIGN_KEY dbda8d6ce9 2007-07-21 drh: for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){ c287665ba8 2007-09-14 drh: void *data; dbda8d6ce9 2007-07-21 drh: int nTo = strlen(pFKey->zTo) + 1; dbda8d6ce9 2007-07-21 drh: pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo); c287665ba8 2007-09-14 drh: data = sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey); c287665ba8 2007-09-14 drh: if( data==(void *)pFKey ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: pParse->pNewTable = 0; dbda8d6ce9 2007-07-21 drh: db->nTable++; dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_InternChanges; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_ALTERTABLE dbda8d6ce9 2007-07-21 drh: if( !p->pSelect ){ dbda8d6ce9 2007-07-21 drh: const char *zName = (const char *)pParse->sNameToken.z; dbda8d6ce9 2007-07-21 drh: int nName; dbda8d6ce9 2007-07-21 drh: assert( !pSelect && pCons && pEnd ); dbda8d6ce9 2007-07-21 drh: if( pCons->z==0 ){ dbda8d6ce9 2007-07-21 drh: pCons = pEnd; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nName = (const char *)pCons->z - zName; dbda8d6ce9 2007-07-21 drh: p->addColOffset = 13 + sqlite3Utf8CharLen(zName, nName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The parser calls this routine in order to create a new VIEW dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CreateView( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: Token *pBegin, /* The CREATE token that begins the statement */ dbda8d6ce9 2007-07-21 drh: Token *pName1, /* The token that holds the name of the view */ dbda8d6ce9 2007-07-21 drh: Token *pName2, /* The token that holds the name of the view */ dbda8d6ce9 2007-07-21 drh: Select *pSelect, /* A SELECT statement that will become the new view */ dbda8d6ce9 2007-07-21 drh: int isTemp, /* TRUE for a TEMPORARY view */ dbda8d6ce9 2007-07-21 drh: int noErr /* Suppress error messages if VIEW already exists */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Table *p; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: const unsigned char *z; dbda8d6ce9 2007-07-21 drh: Token sEnd; dbda8d6ce9 2007-07-21 drh: DbFixer sFix; dbda8d6ce9 2007-07-21 drh: Token *pName; dbda8d6ce9 2007-07-21 drh: int iDb; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParse->nVar>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSelect); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); dbda8d6ce9 2007-07-21 drh: p = pParse->pNewTable; dbda8d6ce9 2007-07-21 drh: if( p==0 || pParse->nErr ){ dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSelect); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3TwoPartName(pParse, pName1, pName2, &pName); c287665ba8 2007-09-14 drh: iDb = sqlite3SchemaToIndex(db, p->pSchema); dbda8d6ce9 2007-07-21 drh: if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName) dbda8d6ce9 2007-07-21 drh: && sqlite3FixSelect(&sFix, pSelect) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSelect); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make a copy of the entire SELECT statement that defines the view. dbda8d6ce9 2007-07-21 drh: ** This will force all the Expr.token.z values to be dynamically dbda8d6ce9 2007-07-21 drh: ** allocated rather than point to the input string - which means that dbda8d6ce9 2007-07-21 drh: ** they will persist after the current sqlite3_exec() call returns. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: p->pSelect = sqlite3SelectDup(db, pSelect); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSelect); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: sqlite3ViewGetColumnNames(pParse, p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Locate the end of the CREATE VIEW statement. Make sEnd point to dbda8d6ce9 2007-07-21 drh: ** the end. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sEnd = pParse->sLastToken; dbda8d6ce9 2007-07-21 drh: if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){ dbda8d6ce9 2007-07-21 drh: sEnd.z += sEnd.n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sEnd.n = 0; dbda8d6ce9 2007-07-21 drh: n = sEnd.z - pBegin->z; dbda8d6ce9 2007-07-21 drh: z = (const unsigned char*)pBegin->z; dbda8d6ce9 2007-07-21 drh: while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; } dbda8d6ce9 2007-07-21 drh: sEnd.z = &z[n-1]; dbda8d6ce9 2007-07-21 drh: sEnd.n = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ dbda8d6ce9 2007-07-21 drh: sqlite3EndTable(pParse, 0, &sEnd, 0); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIEW */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The Table structure pTable is really a VIEW. Fill in the names of dbda8d6ce9 2007-07-21 drh: ** the columns of the view in the pTable structure. Return the number dbda8d6ce9 2007-07-21 drh: ** of errors. If an error is seen leave an error message in pParse->zErrMsg. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ dbda8d6ce9 2007-07-21 drh: Table *pSelTab; /* A fake table from which we get the result set */ dbda8d6ce9 2007-07-21 drh: Select *pSel; /* Copy of the SELECT that implements the view */ dbda8d6ce9 2007-07-21 drh: int nErr = 0; /* Number of errors encountered */ dbda8d6ce9 2007-07-21 drh: int n; /* Temporarily holds the number of cursors assigned */ c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; /* Database connection for malloc errors */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTable ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( sqlite3VtabCallConnect(pParse, pTable) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTable) ) return 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: /* A positive nCol means the columns names for this view are dbda8d6ce9 2007-07-21 drh: ** already known. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTable->nCol>0 ) return 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A negative nCol is a special marker meaning that we are currently dbda8d6ce9 2007-07-21 drh: ** trying to compute the column names. If we enter this routine with dbda8d6ce9 2007-07-21 drh: ** a negative nCol, it means two or more views form a loop, like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE VIEW one AS SELECT * FROM two; dbda8d6ce9 2007-07-21 drh: ** CREATE VIEW two AS SELECT * FROM one; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Actually, this error is caught previously and so the following test dbda8d6ce9 2007-07-21 drh: ** should always fail. But we will leave it in place just to be safe. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTable->nCol<0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pTable->nCol>=0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we get this far, it means we need to compute the table names. dbda8d6ce9 2007-07-21 drh: ** Note that the call to sqlite3ResultSetOfSelect() will expand any dbda8d6ce9 2007-07-21 drh: ** "*" elements in the results set of the view and will assign cursors dbda8d6ce9 2007-07-21 drh: ** to the elements of the FROM clause. But we do not want these changes dbda8d6ce9 2007-07-21 drh: ** to be permanent. So the computation is done on a copy of the SELECT dbda8d6ce9 2007-07-21 drh: ** statement that defines the view. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pTable->pSelect ); c287665ba8 2007-09-14 drh: pSel = sqlite3SelectDup(db, pTable->pSelect); dbda8d6ce9 2007-07-21 drh: if( pSel ){ dbda8d6ce9 2007-07-21 drh: n = pParse->nTab; dbda8d6ce9 2007-07-21 drh: sqlite3SrcListAssignCursors(pParse, pSel->pSrc); dbda8d6ce9 2007-07-21 drh: pTable->nCol = -1; dbda8d6ce9 2007-07-21 drh: pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel); dbda8d6ce9 2007-07-21 drh: pParse->nTab = n; dbda8d6ce9 2007-07-21 drh: if( pSelTab ){ dbda8d6ce9 2007-07-21 drh: assert( pTable->aCol==0 ); dbda8d6ce9 2007-07-21 drh: pTable->nCol = pSelTab->nCol; dbda8d6ce9 2007-07-21 drh: pTable->aCol = pSelTab->aCol; dbda8d6ce9 2007-07-21 drh: pSelTab->nCol = 0; dbda8d6ce9 2007-07-21 drh: pSelTab->aCol = 0; dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(pSelTab); dbda8d6ce9 2007-07-21 drh: pTable->pSchema->flags |= DB_UnresetViews; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTable->nCol = 0; dbda8d6ce9 2007-07-21 drh: nErr++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSel); dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: nErr++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIEW */ dbda8d6ce9 2007-07-21 drh: return nErr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear the column names from every VIEW in database idx. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void sqliteViewResetAll(sqlite3 *db, int idx){ dbda8d6ce9 2007-07-21 drh: HashElem *i; dbda8d6ce9 2007-07-21 drh: if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; dbda8d6ce9 2007-07-21 drh: for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ dbda8d6ce9 2007-07-21 drh: Table *pTab = sqliteHashData(i); dbda8d6ce9 2007-07-21 drh: if( pTab->pSelect ){ dbda8d6ce9 2007-07-21 drh: sqliteResetColumnNames(pTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: DbClearProperty(db, idx, DB_UnresetViews); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define sqliteViewResetAll(A,B) dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIEW */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is called by the VDBE to adjust the internal schema dbda8d6ce9 2007-07-21 drh: ** used by SQLite when the btree layer moves a table root page. The dbda8d6ce9 2007-07-21 drh: ** root-page of a table or index in database iDb has changed from iFrom dbda8d6ce9 2007-07-21 drh: ** to iTo. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Ticket #1728: The symbol table might still contain information dbda8d6ce9 2007-07-21 drh: ** on tables and/or indices that are the process of being deleted. dbda8d6ce9 2007-07-21 drh: ** If you are unlucky, one of those deleted indices or tables might dbda8d6ce9 2007-07-21 drh: ** have the same rootpage number as the real table or index that is dbda8d6ce9 2007-07-21 drh: ** being moved. So we cannot stop searching after the first match dbda8d6ce9 2007-07-21 drh: ** because the first match might be for one of the deleted indices dbda8d6ce9 2007-07-21 drh: ** or tables and not the table/index that is actually being moved. dbda8d6ce9 2007-07-21 drh: ** We must continue looping until all tables and indices with dbda8d6ce9 2007-07-21 drh: ** rootpage==iFrom have been converted to have a rootpage of iTo dbda8d6ce9 2007-07-21 drh: ** in order to be certain that we got the right one. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){ dbda8d6ce9 2007-07-21 drh: HashElem *pElem; dbda8d6ce9 2007-07-21 drh: Hash *pHash; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pHash = &pDb->pSchema->tblHash; dbda8d6ce9 2007-07-21 drh: for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ dbda8d6ce9 2007-07-21 drh: Table *pTab = sqliteHashData(pElem); dbda8d6ce9 2007-07-21 drh: if( pTab->tnum==iFrom ){ dbda8d6ce9 2007-07-21 drh: pTab->tnum = iTo; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pHash = &pDb->pSchema->idxHash; dbda8d6ce9 2007-07-21 drh: for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ dbda8d6ce9 2007-07-21 drh: Index *pIdx = sqliteHashData(pElem); dbda8d6ce9 2007-07-21 drh: if( pIdx->tnum==iFrom ){ dbda8d6ce9 2007-07-21 drh: pIdx->tnum = iTo; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write code to erase the table with root-page iTable from database iDb. dbda8d6ce9 2007-07-21 drh: ** Also write code to modify the sqlite_master table and internal schema dbda8d6ce9 2007-07-21 drh: ** if a root-page of another table is moved by the btree-layer whilst dbda8d6ce9 2007-07-21 drh: ** erasing iTable (this can happen with an auto-vacuum database). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void destroyRootPage(Parse *pParse, int iTable, int iDb){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Destroy, iTable, iDb); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* OP_Destroy pushes an integer onto the stack. If this integer dbda8d6ce9 2007-07-21 drh: ** is non-zero, then it is the root page number of a table moved to dbda8d6ce9 2007-07-21 drh: ** location iTable. The following code modifies the sqlite_master table to dbda8d6ce9 2007-07-21 drh: ** reflect this. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The "#0" in the SQL is a special constant that means whatever value dbda8d6ce9 2007-07-21 drh: ** is on the top of the stack. See sqlite3RegisterExpr(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "UPDATE %Q.%s SET rootpage=%d WHERE #0 AND rootpage=#0", dbda8d6ce9 2007-07-21 drh: pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write VDBE code to erase table pTab and all associated indices on disk. dbda8d6ce9 2007-07-21 drh: ** Code to update the sqlite_master tables and internal schema definitions dbda8d6ce9 2007-07-21 drh: ** in case a root-page belonging to another table is moved by the btree layer dbda8d6ce9 2007-07-21 drh: ** is also added (this can happen with an auto-vacuum database). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void destroyTable(Parse *pParse, Table *pTab){ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: destroyRootPage(pParse, pTab->tnum, iDb); dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: destroyRootPage(pParse, pIdx->tnum, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: ** is not defined), then it is important to call OP_Destroy on the dbda8d6ce9 2007-07-21 drh: ** table and index root-pages in order, starting with the numerically dbda8d6ce9 2007-07-21 drh: ** largest root-page number. This guarantees that none of the root-pages dbda8d6ce9 2007-07-21 drh: ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the dbda8d6ce9 2007-07-21 drh: ** following were coded: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** OP_Destroy 4 0 dbda8d6ce9 2007-07-21 drh: ** ... dbda8d6ce9 2007-07-21 drh: ** OP_Destroy 5 0 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** and root page 5 happened to be the largest root-page number in the dbda8d6ce9 2007-07-21 drh: ** database, then root page 5 would be moved to page 4 by the dbda8d6ce9 2007-07-21 drh: ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit dbda8d6ce9 2007-07-21 drh: ** a free-list page. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int iTab = pTab->tnum; dbda8d6ce9 2007-07-21 drh: int iDestroyed = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( 1 ){ dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: int iLargest = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( iDestroyed==0 || iTab<iDestroyed ){ dbda8d6ce9 2007-07-21 drh: iLargest = iTab; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: int iIdx = pIdx->tnum; dbda8d6ce9 2007-07-21 drh: assert( pIdx->pSchema==pTab->pSchema ); dbda8d6ce9 2007-07-21 drh: if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){ dbda8d6ce9 2007-07-21 drh: iLargest = iIdx; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iLargest==0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: destroyRootPage(pParse, iLargest, iDb); dbda8d6ce9 2007-07-21 drh: iDestroyed = iLargest; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called to do the work of a DROP TABLE statement. dbda8d6ce9 2007-07-21 drh: ** pName is the name of the table to be dropped. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pName->nSrc==1 ); dbda8d6ce9 2007-07-21 drh: pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pTab==0 ){ dbda8d6ce9 2007-07-21 drh: if( noErr ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorClear(pParse); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int code; dbda8d6ce9 2007-07-21 drh: const char *zTab = SCHEMA_TABLE(iDb); dbda8d6ce9 2007-07-21 drh: const char *zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: const char *zArg2 = 0; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( isView ){ dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && iDb==1 ){ dbda8d6ce9 2007-07-21 drh: code = SQLITE_DROP_TEMP_VIEW; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: code = SQLITE_DROP_VIEW; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: }else if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3ViewGetColumnNames(pParse, pTab) ){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: code = SQLITE_DROP_VTABLE; dbda8d6ce9 2007-07-21 drh: zArg2 = pTab->pMod->zName; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && iDb==1 ){ dbda8d6ce9 2007-07-21 drh: code = SQLITE_DROP_TEMP_TABLE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: code = SQLITE_DROP_TABLE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( pTab->readOnly || pTab==db->aDb[iDb].pSchema->pSeqTab ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used dbda8d6ce9 2007-07-21 drh: ** on a table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( isView && pTab->pSelect==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !isView && pTab->pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); dbda8d6ce9 2007-07-21 drh: goto exit_drop_table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code to remove the table from the master table dbda8d6ce9 2007-07-21 drh: ** on disk. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: Trigger *pTrigger; dbda8d6ce9 2007-07-21 drh: Db *pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_VBegin, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Drop all triggers associated with the table being dropped. Code dbda8d6ce9 2007-07-21 drh: ** is generated to remove entries from sqlite_master and/or dbda8d6ce9 2007-07-21 drh: ** sqlite_temp_master if required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTrigger = pTab->pTrigger; dbda8d6ce9 2007-07-21 drh: while( pTrigger ){ dbda8d6ce9 2007-07-21 drh: assert( pTrigger->pSchema==pTab->pSchema || dbda8d6ce9 2007-07-21 drh: pTrigger->pSchema==db->aDb[1].pSchema ); dbda8d6ce9 2007-07-21 drh: sqlite3DropTriggerPtr(pParse, pTrigger); dbda8d6ce9 2007-07-21 drh: pTrigger = pTrigger->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: /* Remove any entries of the sqlite_sequence table associated with dbda8d6ce9 2007-07-21 drh: ** the table being dropped. This is done before the table is dropped dbda8d6ce9 2007-07-21 drh: ** at the btree level, in case the sqlite_sequence table needs to dbda8d6ce9 2007-07-21 drh: ** move as a result of the drop (can happen in auto-vacuum mode). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTab->autoInc ){ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "DELETE FROM %s.sqlite_sequence WHERE name=%Q", dbda8d6ce9 2007-07-21 drh: pDb->zName, pTab->zName dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Drop all SQLITE_MASTER table and index entries that refer to the dbda8d6ce9 2007-07-21 drh: ** table. The program name loops through the master table and deletes dbda8d6ce9 2007-07-21 drh: ** every row that refers to a table of the same name as the one being dbda8d6ce9 2007-07-21 drh: ** dropped. Triggers are handled seperately because a trigger can be dbda8d6ce9 2007-07-21 drh: ** created in the temp database that refers to a table in another dbda8d6ce9 2007-07-21 drh: ** database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", dbda8d6ce9 2007-07-21 drh: pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); dbda8d6ce9 2007-07-21 drh: if( !isView && !IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: destroyTable(pParse, pTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Remove the table entry from SQLite's internal schema and modify dbda8d6ce9 2007-07-21 drh: ** the schema cookie. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqliteViewResetAll(db, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: exit_drop_table: dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called to create a new foreign key on the table dbda8d6ce9 2007-07-21 drh: ** currently under construction. pFromCol determines which columns dbda8d6ce9 2007-07-21 drh: ** in the current table point to the foreign key. If pFromCol==0 then dbda8d6ce9 2007-07-21 drh: ** connect the key to the last column inserted. pTo is the name of dbda8d6ce9 2007-07-21 drh: ** the table referred to. pToCol is a list of tables in the other dbda8d6ce9 2007-07-21 drh: ** pTo table that the foreign key points to. flags contains all dbda8d6ce9 2007-07-21 drh: ** information about the conflict resolution algorithms specified dbda8d6ce9 2007-07-21 drh: ** in the ON DELETE, ON UPDATE and ON INSERT clauses. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An FKey structure is created and added to the table currently dbda8d6ce9 2007-07-21 drh: ** under construction in the pParse->pNewTable field. The new FKey dbda8d6ce9 2007-07-21 drh: ** is not linked into db->aFKey at this point - that does not happen dbda8d6ce9 2007-07-21 drh: ** until sqlite3EndTable(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The foreign key is set for IMMEDIATE processing. A subsequent call dbda8d6ce9 2007-07-21 drh: ** to sqlite3DeferForeignKey() might change this to DEFERRED. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CreateForeignKey( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: ExprList *pFromCol, /* Columns in this table that point to other table */ dbda8d6ce9 2007-07-21 drh: Token *pTo, /* Name of the other table */ dbda8d6ce9 2007-07-21 drh: ExprList *pToCol, /* Columns in the other table */ dbda8d6ce9 2007-07-21 drh: int flags /* Conflict resolution algorithms. */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FOREIGN_KEY dbda8d6ce9 2007-07-21 drh: FKey *pFKey = 0; dbda8d6ce9 2007-07-21 drh: Table *p = pParse->pNewTable; dbda8d6ce9 2007-07-21 drh: int nByte; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nCol; dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTo!=0 ); dbda8d6ce9 2007-07-21 drh: if( p==0 || pParse->nErr || IN_DECLARE_VTAB ) goto fk_end; dbda8d6ce9 2007-07-21 drh: if( pFromCol==0 ){ dbda8d6ce9 2007-07-21 drh: int iCol = p->nCol-1; dbda8d6ce9 2007-07-21 drh: if( iCol<0 ) goto fk_end; dbda8d6ce9 2007-07-21 drh: if( pToCol && pToCol->nExpr!=1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "foreign key on %s" dbda8d6ce9 2007-07-21 drh: " should reference only one column of table %T", dbda8d6ce9 2007-07-21 drh: p->aCol[iCol].zName, pTo); dbda8d6ce9 2007-07-21 drh: goto fk_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nCol = 1; dbda8d6ce9 2007-07-21 drh: }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "number of columns in foreign key does not match the number of " dbda8d6ce9 2007-07-21 drh: "columns in the referenced table"); dbda8d6ce9 2007-07-21 drh: goto fk_end; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nCol = pFromCol->nExpr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1; dbda8d6ce9 2007-07-21 drh: if( pToCol ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pToCol->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: nByte += strlen(pToCol->a[i].zName) + 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pFKey = sqlite3DbMallocZero(pParse->db, nByte ); c287665ba8 2007-09-14 drh: if( pFKey==0 ){ c287665ba8 2007-09-14 drh: goto fk_end; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: pFKey->pFrom = p; dbda8d6ce9 2007-07-21 drh: pFKey->pNextFrom = p->pFKey; dbda8d6ce9 2007-07-21 drh: z = (char*)&pFKey[1]; dbda8d6ce9 2007-07-21 drh: pFKey->aCol = (struct sColMap*)z; dbda8d6ce9 2007-07-21 drh: z += sizeof(struct sColMap)*nCol; dbda8d6ce9 2007-07-21 drh: pFKey->zTo = z; dbda8d6ce9 2007-07-21 drh: memcpy(z, pTo->z, pTo->n); dbda8d6ce9 2007-07-21 drh: z[pTo->n] = 0; dbda8d6ce9 2007-07-21 drh: z += pTo->n+1; dbda8d6ce9 2007-07-21 drh: pFKey->pNextTo = 0; dbda8d6ce9 2007-07-21 drh: pFKey->nCol = nCol; dbda8d6ce9 2007-07-21 drh: if( pFromCol==0 ){ dbda8d6ce9 2007-07-21 drh: pFKey->aCol[0].iFrom = p->nCol-1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: for(j=0; j<p->nCol; j++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){ dbda8d6ce9 2007-07-21 drh: pFKey->aCol[i].iFrom = j; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( j>=p->nCol ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "unknown column \"%s\" in foreign key definition", dbda8d6ce9 2007-07-21 drh: pFromCol->a[i].zName); dbda8d6ce9 2007-07-21 drh: goto fk_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pToCol ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: int n = strlen(pToCol->a[i].zName); dbda8d6ce9 2007-07-21 drh: pFKey->aCol[i].zCol = z; dbda8d6ce9 2007-07-21 drh: memcpy(z, pToCol->a[i].zName, n); dbda8d6ce9 2007-07-21 drh: z[n] = 0; dbda8d6ce9 2007-07-21 drh: z += n+1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pFKey->isDeferred = 0; dbda8d6ce9 2007-07-21 drh: pFKey->deleteConf = flags & 0xff; dbda8d6ce9 2007-07-21 drh: pFKey->updateConf = (flags >> 8 ) & 0xff; dbda8d6ce9 2007-07-21 drh: pFKey->insertConf = (flags >> 16 ) & 0xff; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Link the foreign key to the table as the last step. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: p->pFKey = pFKey; dbda8d6ce9 2007-07-21 drh: pFKey = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: fk_end: c287665ba8 2007-09-14 drh: sqlite3_free(pFKey); dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pFromCol); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pToCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED dbda8d6ce9 2007-07-21 drh: ** clause is seen as part of a foreign key definition. The isDeferred dbda8d6ce9 2007-07-21 drh: ** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE. dbda8d6ce9 2007-07-21 drh: ** The behavior of the most recently created foreign key is adjusted dbda8d6ce9 2007-07-21 drh: ** accordingly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FOREIGN_KEY dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: FKey *pFKey; dbda8d6ce9 2007-07-21 drh: if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return; dbda8d6ce9 2007-07-21 drh: pFKey->isDeferred = isDeferred; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will erase and refill index *pIdx. This is dbda8d6ce9 2007-07-21 drh: ** used to initialize a newly created index or to recompute the dbda8d6ce9 2007-07-21 drh: ** content of an index in response to a REINDEX command. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** if memRootPage is not negative, it means that the index is newly dbda8d6ce9 2007-07-21 drh: ** created. The memory cell specified by memRootPage contains the dbda8d6ce9 2007-07-21 drh: ** root page number of the index. If memRootPage is negative, then dbda8d6ce9 2007-07-21 drh: ** the index already exists and must be cleared before being refilled and dbda8d6ce9 2007-07-21 drh: ** the root page number of the index is taken from pIndex->tnum. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ dbda8d6ce9 2007-07-21 drh: Table *pTab = pIndex->pTable; /* The table that is indexed */ dbda8d6ce9 2007-07-21 drh: int iTab = pParse->nTab; /* Btree cursor used for pTab */ dbda8d6ce9 2007-07-21 drh: int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */ dbda8d6ce9 2007-07-21 drh: int addr1; /* Address of top of loop */ dbda8d6ce9 2007-07-21 drh: int tnum; /* Root page of index */ dbda8d6ce9 2007-07-21 drh: Vdbe *v; /* Generate code into this virtual machine */ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKey; /* KeyInfo for index */ c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; /* The database connection */ c287665ba8 2007-09-14 drh: int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, c287665ba8 2007-09-14 drh: db->aDb[iDb].zName ) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Require a write-lock on the table to perform this operation */ dbda8d6ce9 2007-07-21 drh: sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: if( memRootPage>=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, memRootPage, 0); dbda8d6ce9 2007-07-21 drh: tnum = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: tnum = pIndex->tnum; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Clear, tnum, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: pKey = sqlite3IndexKeyinfo(pParse, pIndex); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char *)pKey, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); dbda8d6ce9 2007-07-21 drh: sqlite3GenerateIndexKey(v, pIndex, iTab); dbda8d6ce9 2007-07-21 drh: if( pIndex->onError!=OE_None ){ dbda8d6ce9 2007-07-21 drh: int curaddr = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: int addr2 = curaddr+4; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, curaddr-1, addr2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rowid, iTab, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, dbda8d6ce9 2007-07-21 drh: "indexed columns are not unique", P3_STATIC); c287665ba8 2007-09-14 drh: assert( db->mallocFailed || addr2==sqlite3VdbeCurrentAddr(v) ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iTab, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iIdx, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new index for an SQL table. pName1.pName2 is the name of the index dbda8d6ce9 2007-07-21 drh: ** and pTblList is the name of the table that is to be indexed. Both will dbda8d6ce9 2007-07-21 drh: ** be NULL for a primary key or an index that is created to satisfy a dbda8d6ce9 2007-07-21 drh: ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable dbda8d6ce9 2007-07-21 drh: ** as the table to be indexed. pParse->pNewTable is a table that is dbda8d6ce9 2007-07-21 drh: ** currently being constructed by a CREATE TABLE statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pList is a list of columns to be indexed. pList will be NULL if this dbda8d6ce9 2007-07-21 drh: ** is a primary key or unique-constraint on the most recent column added dbda8d6ce9 2007-07-21 drh: ** to the table currently under construction. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CreateIndex( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* All information about this parse */ dbda8d6ce9 2007-07-21 drh: Token *pName1, /* First part of index name. May be NULL */ dbda8d6ce9 2007-07-21 drh: Token *pName2, /* Second part of index name. May be NULL */ dbda8d6ce9 2007-07-21 drh: SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ dbda8d6ce9 2007-07-21 drh: ExprList *pList, /* A list of columns to be indexed */ dbda8d6ce9 2007-07-21 drh: int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ dbda8d6ce9 2007-07-21 drh: Token *pStart, /* The CREATE token that begins this statement */ dbda8d6ce9 2007-07-21 drh: Token *pEnd, /* The ")" that closes the CREATE INDEX statement */ dbda8d6ce9 2007-07-21 drh: int sortOrder, /* Sort order of primary key when pList==NULL */ dbda8d6ce9 2007-07-21 drh: int ifNotExist /* Omit error if index already exists */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Table *pTab = 0; /* Table to be indexed */ dbda8d6ce9 2007-07-21 drh: Index *pIndex = 0; /* The index to be created */ dbda8d6ce9 2007-07-21 drh: char *zName = 0; /* Name of the index */ dbda8d6ce9 2007-07-21 drh: int nName; /* Number of characters in zName */ dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: Token nullId; /* Fake token for an empty ID list */ dbda8d6ce9 2007-07-21 drh: DbFixer sFix; /* For assigning database names to pTable */ dbda8d6ce9 2007-07-21 drh: int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: Db *pDb; /* The specific table containing the indexed database */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Index of the database that is being written */ dbda8d6ce9 2007-07-21 drh: Token *pName = 0; /* Unqualified name of the index to create */ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pListItem; /* For looping over pList */ dbda8d6ce9 2007-07-21 drh: int nCol; dbda8d6ce9 2007-07-21 drh: int nExtra = 0; dbda8d6ce9 2007-07-21 drh: char *zExtra; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed || IN_DECLARE_VTAB ){ dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the table that is to be indexed. Return early if not found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTblName!=0 ){ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Use the two-part index name to determine the database dbda8d6ce9 2007-07-21 drh: ** to search for the table. 'Fix' the table name to this db dbda8d6ce9 2007-07-21 drh: ** before looking up the table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pName1 && pName2 ); dbda8d6ce9 2007-07-21 drh: iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); dbda8d6ce9 2007-07-21 drh: if( iDb<0 ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TEMPDB dbda8d6ce9 2007-07-21 drh: /* If the index name was unqualified, check if the the table dbda8d6ce9 2007-07-21 drh: ** is a temp table. If so, set the database to 1. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTab = sqlite3SrcListLookup(pParse, pTblName); dbda8d6ce9 2007-07-21 drh: if( pName2 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ dbda8d6ce9 2007-07-21 drh: iDb = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) && dbda8d6ce9 2007-07-21 drh: sqlite3FixSrcList(&sFix, pTblName) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: /* Because the parser constructs pTblName from a single identifier, dbda8d6ce9 2007-07-21 drh: ** sqlite3FixSrcList can never fail. */ dbda8d6ce9 2007-07-21 drh: assert(0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName, dbda8d6ce9 2007-07-21 drh: pTblName->a[0].zDatabase); dbda8d6ce9 2007-07-21 drh: if( !pTab ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: assert( db->aDb[iDb].pSchema==pTab->pSchema ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pName==0 ); dbda8d6ce9 2007-07-21 drh: pTab = pParse->pNewTable; dbda8d6ce9 2007-07-21 drh: if( !pTab ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pTab==0 || pParse->nErr ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: if( pTab->readOnly ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: if( pTab->pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "views may not be indexed"); dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "virtual tables may not be indexed"); dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the name of the index. Make sure there is not already another dbda8d6ce9 2007-07-21 drh: ** index or table with the same name. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Exception: If we are reading the names of permanent indices from the dbda8d6ce9 2007-07-21 drh: ** sqlite_master table (because some other process changed the schema) and dbda8d6ce9 2007-07-21 drh: ** one of the index names collides with the name of a temporary table or dbda8d6ce9 2007-07-21 drh: ** index, then we will continue to process this index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If pName==0 it means that we are dbda8d6ce9 2007-07-21 drh: ** dealing with a primary key or UNIQUE constraint. We have to invent our dbda8d6ce9 2007-07-21 drh: ** own name. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pName ){ c287665ba8 2007-09-14 drh: zName = sqlite3NameFromToken(db, pName); dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: if( zName==0 ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: if( sqlite3FindTable(db, zName, 0)!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ dbda8d6ce9 2007-07-21 drh: if( !ifNotExist ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "index %s already exists", zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: char zBuf[30]; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: Index *pLoop; dbda8d6ce9 2007-07-21 drh: for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zBuf),zBuf,"_%d",n); dbda8d6ce9 2007-07-21 drh: zName = 0; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&zName, "sqlite_autoindex_", pTab->zName, zBuf, (char*)0); c287665ba8 2007-09-14 drh: if( zName==0 ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: goto exit_create_index; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check for authorization to create an index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: const char *zDb = pDb->zName; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i = SQLITE_CREATE_INDEX; dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, i, zName, pTab->zName, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If pList==0, it means this routine was called to make a primary dbda8d6ce9 2007-07-21 drh: ** key out of the last column added to the table under construction. dbda8d6ce9 2007-07-21 drh: ** So create a fake list to simulate this. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pList==0 ){ dbda8d6ce9 2007-07-21 drh: nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName; dbda8d6ce9 2007-07-21 drh: nullId.n = strlen((char*)nullId.z); c287665ba8 2007-09-14 drh: pList = sqlite3ExprListAppend(pParse, 0, 0, &nullId); dbda8d6ce9 2007-07-21 drh: if( pList==0 ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: pList->a[0].sortOrder = sortOrder; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out how many bytes of space are required to store explicitly dbda8d6ce9 2007-07-21 drh: ** specified collation sequence names. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr = pList->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: if( pExpr ){ dbda8d6ce9 2007-07-21 drh: nExtra += (1 + strlen(pExpr->pColl->zName)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate the index structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nName = strlen(zName); dbda8d6ce9 2007-07-21 drh: nCol = pList->nExpr; c287665ba8 2007-09-14 drh: pIndex = sqlite3DbMallocZero(db, dbda8d6ce9 2007-07-21 drh: sizeof(Index) + /* Index structure */ dbda8d6ce9 2007-07-21 drh: sizeof(int)*nCol + /* Index.aiColumn */ dbda8d6ce9 2007-07-21 drh: sizeof(int)*(nCol+1) + /* Index.aiRowEst */ dbda8d6ce9 2007-07-21 drh: sizeof(char *)*nCol + /* Index.azColl */ dbda8d6ce9 2007-07-21 drh: sizeof(u8)*nCol + /* Index.aSortOrder */ dbda8d6ce9 2007-07-21 drh: nName + 1 + /* Index.zName */ dbda8d6ce9 2007-07-21 drh: nExtra /* Collation sequence names */ dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ c287665ba8 2007-09-14 drh: goto exit_create_index; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: pIndex->azColl = (char**)(&pIndex[1]); dbda8d6ce9 2007-07-21 drh: pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]); dbda8d6ce9 2007-07-21 drh: pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]); dbda8d6ce9 2007-07-21 drh: pIndex->aSortOrder = (u8 *)(&pIndex->aiRowEst[nCol+1]); dbda8d6ce9 2007-07-21 drh: pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]); dbda8d6ce9 2007-07-21 drh: zExtra = (char *)(&pIndex->zName[nName+1]); dbda8d6ce9 2007-07-21 drh: memcpy(pIndex->zName, zName, nName+1); dbda8d6ce9 2007-07-21 drh: pIndex->pTable = pTab; dbda8d6ce9 2007-07-21 drh: pIndex->nColumn = pList->nExpr; dbda8d6ce9 2007-07-21 drh: pIndex->onError = onError; dbda8d6ce9 2007-07-21 drh: pIndex->autoIndex = pName==0; dbda8d6ce9 2007-07-21 drh: pIndex->pSchema = db->aDb[iDb].pSchema; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to see if we should honor DESC requests on index columns dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pDb->pSchema->file_format>=4 ){ dbda8d6ce9 2007-07-21 drh: sortOrderMask = -1; /* Honor DESC */ dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sortOrderMask = 0; /* Ignore DESC */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Scan the names of the columns of the table to be indexed and dbda8d6ce9 2007-07-21 drh: ** load the column indices into the Index structure. Report an error dbda8d6ce9 2007-07-21 drh: ** if any column is not found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){ dbda8d6ce9 2007-07-21 drh: const char *zColName = pListItem->zName; dbda8d6ce9 2007-07-21 drh: Column *pTabCol; dbda8d6ce9 2007-07-21 drh: int requestedSortOrder; dbda8d6ce9 2007-07-21 drh: char *zColl; /* Collation sequence name */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( j>=pTab->nCol ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "table %s has no column named %s", dbda8d6ce9 2007-07-21 drh: pTab->zName, zColName); dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* TODO: Add a test to make sure that the same column is not named dbda8d6ce9 2007-07-21 drh: ** more than once within the same index. Only the first instance of dbda8d6ce9 2007-07-21 drh: ** the column will ever be used by the optimizer. Note that using the dbda8d6ce9 2007-07-21 drh: ** same column more than once cannot be an error because that would dbda8d6ce9 2007-07-21 drh: ** break backwards compatibility - it needs to be a warning. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pIndex->aiColumn[i] = j; dbda8d6ce9 2007-07-21 drh: if( pListItem->pExpr ){ dbda8d6ce9 2007-07-21 drh: assert( pListItem->pExpr->pColl ); dbda8d6ce9 2007-07-21 drh: zColl = zExtra; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(nExtra, zExtra, "%s", pListItem->pExpr->pColl->zName); dbda8d6ce9 2007-07-21 drh: zExtra += (strlen(zColl) + 1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zColl = pTab->aCol[j].zColl; dbda8d6ce9 2007-07-21 drh: if( !zColl ){ dbda8d6ce9 2007-07-21 drh: zColl = db->pDfltColl->zName; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl, -1) ){ dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIndex->azColl[i] = zColl; dbda8d6ce9 2007-07-21 drh: requestedSortOrder = pListItem->sortOrder & sortOrderMask; dbda8d6ce9 2007-07-21 drh: pIndex->aSortOrder[i] = requestedSortOrder; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3DefaultRowEst(pIndex); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pTab==pParse->pNewTable ){ dbda8d6ce9 2007-07-21 drh: /* This routine has been called to create an automatic index as a dbda8d6ce9 2007-07-21 drh: ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or dbda8d6ce9 2007-07-21 drh: ** a PRIMARY KEY or UNIQUE clause following the column definitions. dbda8d6ce9 2007-07-21 drh: ** i.e. one of: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE t(x PRIMARY KEY, y); dbda8d6ce9 2007-07-21 drh: ** CREATE TABLE t(x, y, UNIQUE(x, y)); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Either way, check to see if the table already has such an index. If dbda8d6ce9 2007-07-21 drh: ** so, don't bother creating this one. This only applies to dbda8d6ce9 2007-07-21 drh: ** automatically created indices. Users can do as they wish with dbda8d6ce9 2007-07-21 drh: ** explicit indices. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: int k; dbda8d6ce9 2007-07-21 drh: assert( pIdx->onError!=OE_None ); dbda8d6ce9 2007-07-21 drh: assert( pIdx->autoIndex ); dbda8d6ce9 2007-07-21 drh: assert( pIndex->onError!=OE_None ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pIdx->nColumn!=pIndex->nColumn ) continue; dbda8d6ce9 2007-07-21 drh: for(k=0; k<pIdx->nColumn; k++){ dbda8d6ce9 2007-07-21 drh: const char *z1 = pIdx->azColl[k]; dbda8d6ce9 2007-07-21 drh: const char *z2 = pIndex->azColl[k]; dbda8d6ce9 2007-07-21 drh: if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; dbda8d6ce9 2007-07-21 drh: if( pIdx->aSortOrder[k]!=pIndex->aSortOrder[k] ) break; dbda8d6ce9 2007-07-21 drh: if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( k==pIdx->nColumn ){ dbda8d6ce9 2007-07-21 drh: if( pIdx->onError!=pIndex->onError ){ dbda8d6ce9 2007-07-21 drh: /* This constraint creates the same index as a previous dbda8d6ce9 2007-07-21 drh: ** constraint specified somewhere in the CREATE TABLE statement. dbda8d6ce9 2007-07-21 drh: ** However the ON CONFLICT clauses are different. If both this dbda8d6ce9 2007-07-21 drh: ** constraint and the previous equivalent constraint have explicit dbda8d6ce9 2007-07-21 drh: ** ON CONFLICT clauses this is an error. Otherwise, use the dbda8d6ce9 2007-07-21 drh: ** explicitly specified behaviour for the index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "conflicting ON CONFLICT clauses specified", 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pIdx->onError==OE_Default ){ dbda8d6ce9 2007-07-21 drh: pIdx->onError = pIndex->onError; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Link the new Index structure to its table and to the other dbda8d6ce9 2007-07-21 drh: ** in-memory database structures. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->init.busy ){ dbda8d6ce9 2007-07-21 drh: Index *p; dbda8d6ce9 2007-07-21 drh: p = sqlite3HashInsert(&pIndex->pSchema->idxHash, dbda8d6ce9 2007-07-21 drh: pIndex->zName, strlen(pIndex->zName)+1, pIndex); dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: assert( p==pIndex ); /* Malloc must have failed */ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: goto exit_create_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_InternChanges; dbda8d6ce9 2007-07-21 drh: if( pTblName!=0 ){ dbda8d6ce9 2007-07-21 drh: pIndex->tnum = db->init.newTnum; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the db->init.busy is 0 then create the index on disk. This dbda8d6ce9 2007-07-21 drh: ** involves writing the index into the master table and filling in the dbda8d6ce9 2007-07-21 drh: ** index with the current table contents. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The db->init.busy is 0 when the user first enters a CREATE INDEX dbda8d6ce9 2007-07-21 drh: ** command. db->init.busy is 1 when a database is opened and dbda8d6ce9 2007-07-21 drh: ** CREATE INDEX statements are read out of the master table. In dbda8d6ce9 2007-07-21 drh: ** the latter case the index already exists on disk, which is why dbda8d6ce9 2007-07-21 drh: ** we don't want to recreate it. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If pTblName==0 it means this index is generated as a primary key dbda8d6ce9 2007-07-21 drh: ** or UNIQUE constraint of a CREATE TABLE statement. Since the table dbda8d6ce9 2007-07-21 drh: ** has just been created, it contains no data and the index initialization dbda8d6ce9 2007-07-21 drh: ** step can be skipped. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: else if( db->init.busy==0 ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: char *zStmt; dbda8d6ce9 2007-07-21 drh: int iMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) goto exit_create_index; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create the rootpage for the index dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 1, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_CreateIndex, iDb, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iMem, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Gather the complete text of the CREATE INDEX statement into dbda8d6ce9 2007-07-21 drh: ** the zStmt variable dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pStart && pEnd ){ dbda8d6ce9 2007-07-21 drh: /* A named index with an explicit CREATE INDEX statement */ c287665ba8 2007-09-14 drh: zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", dbda8d6ce9 2007-07-21 drh: onError==OE_None ? "" : " UNIQUE", dbda8d6ce9 2007-07-21 drh: pEnd->z - pName->z + 1, dbda8d6ce9 2007-07-21 drh: pName->z); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ dbda8d6ce9 2007-07-21 drh: /* zStmt = sqlite3MPrintf(""); */ dbda8d6ce9 2007-07-21 drh: zStmt = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add an entry in sqlite_master for this index dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#0,%Q);", dbda8d6ce9 2007-07-21 drh: db->aDb[iDb].zName, SCHEMA_TABLE(iDb), dbda8d6ce9 2007-07-21 drh: pIndex->zName, dbda8d6ce9 2007-07-21 drh: pTab->zName, dbda8d6ce9 2007-07-21 drh: zStmt dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); c287665ba8 2007-09-14 drh: sqlite3_free(zStmt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Fill the index with data and reparse the schema. Code an OP_Expire dbda8d6ce9 2007-07-21 drh: ** to invalidate all pre-compiled statements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTblName ){ dbda8d6ce9 2007-07-21 drh: sqlite3RefillIndex(pParse, pIndex, iMem); dbda8d6ce9 2007-07-21 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, c287665ba8 2007-09-14 drh: sqlite3MPrintf(db, "name='%q'", pIndex->zName), P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Expire, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* When adding an index to the list of indices for a table, make dbda8d6ce9 2007-07-21 drh: ** sure all indices labeled OE_Replace come after all those labeled dbda8d6ce9 2007-07-21 drh: ** OE_Ignore. This is necessary for the correct operation of UPDATE dbda8d6ce9 2007-07-21 drh: ** and INSERT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->init.busy || pTblName==0 ){ dbda8d6ce9 2007-07-21 drh: if( onError!=OE_Replace || pTab->pIndex==0 dbda8d6ce9 2007-07-21 drh: || pTab->pIndex->onError==OE_Replace){ dbda8d6ce9 2007-07-21 drh: pIndex->pNext = pTab->pIndex; dbda8d6ce9 2007-07-21 drh: pTab->pIndex = pIndex; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Index *pOther = pTab->pIndex; dbda8d6ce9 2007-07-21 drh: while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ dbda8d6ce9 2007-07-21 drh: pOther = pOther->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIndex->pNext = pOther->pNext; dbda8d6ce9 2007-07-21 drh: pOther->pNext = pIndex; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIndex = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Clean up before exiting */ dbda8d6ce9 2007-07-21 drh: exit_create_index: dbda8d6ce9 2007-07-21 drh: if( pIndex ){ dbda8d6ce9 2007-07-21 drh: freeIndex(pIndex); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pList); dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pTblName); c287665ba8 2007-09-14 drh: sqlite3_free(zName); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code to make sure the file format number is at least minFormat. dbda8d6ce9 2007-07-21 drh: ** The generated code will increase the file format number if necessary. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); c287665ba8 2007-09-14 drh: sqlite3VdbeUsesBtree(v, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Fill the Index.aiRowEst[] array with default information - information dbda8d6ce9 2007-07-21 drh: ** to be used when we have not run the ANALYZE command. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** aiRowEst[0] is suppose to contain the number of elements in the index. dbda8d6ce9 2007-07-21 drh: ** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the dbda8d6ce9 2007-07-21 drh: ** number of rows in the table that match any particular value of the dbda8d6ce9 2007-07-21 drh: ** first column of the index. aiRowEst[2] is an estimate of the number dbda8d6ce9 2007-07-21 drh: ** of rows that match any particular combiniation of the first 2 columns dbda8d6ce9 2007-07-21 drh: ** of the index. And so forth. It must always be the case that dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: ** aiRowEst[N]<=aiRowEst[N-1] dbda8d6ce9 2007-07-21 drh: ** aiRowEst[N]>=1 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Apart from that, we have little to go on besides intuition as to dbda8d6ce9 2007-07-21 drh: ** how aiRowEst[] should be initialized. The numbers generated here dbda8d6ce9 2007-07-21 drh: ** are based on typical values found in actual indices. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ dbda8d6ce9 2007-07-21 drh: unsigned *a = pIdx->aiRowEst; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: assert( a!=0 ); dbda8d6ce9 2007-07-21 drh: a[0] = 1000000; dbda8d6ce9 2007-07-21 drh: for(i=pIdx->nColumn; i>=5; i--){ dbda8d6ce9 2007-07-21 drh: a[i] = 5; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( i>=1 ){ dbda8d6ce9 2007-07-21 drh: a[i] = 11 - i; dbda8d6ce9 2007-07-21 drh: i--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pIdx->onError!=OE_None ){ dbda8d6ce9 2007-07-21 drh: a[pIdx->nColumn] = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine will drop an existing named index. This routine dbda8d6ce9 2007-07-21 drh: ** implements the DROP INDEX statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ dbda8d6ce9 2007-07-21 drh: Index *pIndex; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pName->nSrc==1 ); dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); dbda8d6ce9 2007-07-21 drh: if( pIndex==0 ){ dbda8d6ce9 2007-07-21 drh: if( !ifExists ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->checkSchema = 1; dbda8d6ce9 2007-07-21 drh: goto exit_drop_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pIndex->autoIndex ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "index associated with UNIQUE " dbda8d6ce9 2007-07-21 drh: "or PRIMARY KEY constraint cannot be dropped", 0); dbda8d6ce9 2007-07-21 drh: goto exit_drop_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int code = SQLITE_DROP_INDEX; dbda8d6ce9 2007-07-21 drh: Table *pTab = pIndex->pTable; dbda8d6ce9 2007-07-21 drh: const char *zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: const char *zTab = SCHEMA_TABLE(iDb); dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto exit_drop_index; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code to remove the index and from the master table */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "DELETE FROM %Q.%s WHERE name=%Q", dbda8d6ce9 2007-07-21 drh: db->aDb[iDb].zName, SCHEMA_TABLE(iDb), dbda8d6ce9 2007-07-21 drh: pIndex->zName dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: destroyRootPage(pParse, pIndex->tnum, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_DropIndex, iDb, 0, pIndex->zName, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: exit_drop_index: dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pArray is a pointer to an array of objects. Each object in the dbda8d6ce9 2007-07-21 drh: ** array is szEntry bytes in size. This routine allocates a new dbda8d6ce9 2007-07-21 drh: ** object on the end of the array. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** *pnEntry is the number of entries already in use. *pnAlloc is dbda8d6ce9 2007-07-21 drh: ** the previously allocated size of the array. initSize is the dbda8d6ce9 2007-07-21 drh: ** suggested initial array size allocation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The index of the new entry is returned in *pIdx. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns a pointer to the array of objects. This dbda8d6ce9 2007-07-21 drh: ** might be the same as the pArray parameter or it might be a different dbda8d6ce9 2007-07-21 drh: ** pointer if the array was resized. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3ArrayAllocate( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Connection to notify of malloc failures */ dbda8d6ce9 2007-07-21 drh: void *pArray, /* Array of objects. Might be reallocated */ dbda8d6ce9 2007-07-21 drh: int szEntry, /* Size of each object in the array */ dbda8d6ce9 2007-07-21 drh: int initSize, /* Suggested initial allocation, in elements */ dbda8d6ce9 2007-07-21 drh: int *pnEntry, /* Number of objects currently in use */ dbda8d6ce9 2007-07-21 drh: int *pnAlloc, /* Current size of the allocation, in elements */ dbda8d6ce9 2007-07-21 drh: int *pIdx /* Write the index of a new slot here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: if( *pnEntry >= *pnAlloc ){ dbda8d6ce9 2007-07-21 drh: void *pNew; dbda8d6ce9 2007-07-21 drh: int newSize; dbda8d6ce9 2007-07-21 drh: newSize = (*pnAlloc)*2 + initSize; c287665ba8 2007-09-14 drh: pNew = sqlite3DbRealloc(db, pArray, newSize*szEntry); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: *pIdx = -1; dbda8d6ce9 2007-07-21 drh: return pArray; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pnAlloc = newSize; dbda8d6ce9 2007-07-21 drh: pArray = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: z = (char*)pArray; dbda8d6ce9 2007-07-21 drh: memset(&z[*pnEntry * szEntry], 0, szEntry); dbda8d6ce9 2007-07-21 drh: *pIdx = *pnEntry; dbda8d6ce9 2007-07-21 drh: ++*pnEntry; dbda8d6ce9 2007-07-21 drh: return pArray; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Append a new element to the given IdList. Create a new IdList if dbda8d6ce9 2007-07-21 drh: ** need be. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A new IdList is returned, or NULL if malloc() fails. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( pList==0 ){ c287665ba8 2007-09-14 drh: pList = sqlite3DbMallocZero(db, sizeof(IdList) ); dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return 0; dbda8d6ce9 2007-07-21 drh: pList->nAlloc = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pList->a = sqlite3ArrayAllocate( c287665ba8 2007-09-14 drh: db, dbda8d6ce9 2007-07-21 drh: pList->a, dbda8d6ce9 2007-07-21 drh: sizeof(pList->a[0]), dbda8d6ce9 2007-07-21 drh: 5, dbda8d6ce9 2007-07-21 drh: &pList->nId, dbda8d6ce9 2007-07-21 drh: &pList->nAlloc, dbda8d6ce9 2007-07-21 drh: &i dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( i<0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(pList); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pList->a[i].zName = sqlite3NameFromToken(db, pToken); dbda8d6ce9 2007-07-21 drh: return pList; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete an IdList. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3IdListDelete(IdList *pList){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pList->nId; i++){ c287665ba8 2007-09-14 drh: sqlite3_free(pList->a[i].zName); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pList->a); c287665ba8 2007-09-14 drh: sqlite3_free(pList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the index in pList of the identifier named zId. Return -1 dbda8d6ce9 2007-07-21 drh: ** if not found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return -1; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pList->nId; i++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Append a new table name to the given SrcList. Create a new SrcList if dbda8d6ce9 2007-07-21 drh: ** need be. A new entry is created in the SrcList even if pToken is NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A new SrcList is returned, or NULL if malloc() fails. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If pDatabase is not null, it means that the table has an optional dbda8d6ce9 2007-07-21 drh: ** database name prefix. Like this: "database.table". The pDatabase dbda8d6ce9 2007-07-21 drh: ** points to the table name and the pTable points to the database name. dbda8d6ce9 2007-07-21 drh: ** The SrcList.a[].zName field is filled with the table name which might dbda8d6ce9 2007-07-21 drh: ** come from pTable (if pDatabase is NULL) or from pDatabase. dbda8d6ce9 2007-07-21 drh: ** SrcList.a[].zDatabase is filled with the database name from pTable, dbda8d6ce9 2007-07-21 drh: ** or with NULL if no database is specified. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In other words, if call like this: dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** sqlite3SrcListAppend(D,A,B,0); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then B is a table name and the database name is unspecified. If called dbda8d6ce9 2007-07-21 drh: ** like this: dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** sqlite3SrcListAppend(D,A,B,C); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then C is the table name and B is the database name. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Connection to notify of malloc failures */ c287665ba8 2007-09-14 drh: SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */ c287665ba8 2007-09-14 drh: Token *pTable, /* Table to append */ c287665ba8 2007-09-14 drh: Token *pDatabase /* Database of the table */ c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; dbda8d6ce9 2007-07-21 drh: if( pList==0 ){ c287665ba8 2007-09-14 drh: pList = sqlite3DbMallocZero(db, sizeof(SrcList) ); dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return 0; dbda8d6ce9 2007-07-21 drh: pList->nAlloc = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pList->nSrc>=pList->nAlloc ){ dbda8d6ce9 2007-07-21 drh: SrcList *pNew; dbda8d6ce9 2007-07-21 drh: pList->nAlloc *= 2; c287665ba8 2007-09-14 drh: pNew = sqlite3DbRealloc(db, pList, dbda8d6ce9 2007-07-21 drh: sizeof(*pList) + (pList->nAlloc-1)*sizeof(pList->a[0]) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pList); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pList = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pItem = &pList->a[pList->nSrc]; dbda8d6ce9 2007-07-21 drh: memset(pItem, 0, sizeof(pList->a[0])); dbda8d6ce9 2007-07-21 drh: if( pDatabase && pDatabase->z==0 ){ dbda8d6ce9 2007-07-21 drh: pDatabase = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDatabase && pTable ){ dbda8d6ce9 2007-07-21 drh: Token *pTemp = pDatabase; dbda8d6ce9 2007-07-21 drh: pDatabase = pTable; dbda8d6ce9 2007-07-21 drh: pTable = pTemp; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pItem->zName = sqlite3NameFromToken(db, pTable); c287665ba8 2007-09-14 drh: pItem->zDatabase = sqlite3NameFromToken(db, pDatabase); dbda8d6ce9 2007-07-21 drh: pItem->iCursor = -1; dbda8d6ce9 2007-07-21 drh: pItem->isPopulated = 0; dbda8d6ce9 2007-07-21 drh: pList->nSrc++; dbda8d6ce9 2007-07-21 drh: return pList; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Assign cursors to all tables in a SrcList dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; c287665ba8 2007-09-14 drh: assert(pList || pParse->db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: if( pList ){ dbda8d6ce9 2007-07-21 drh: for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: if( pItem->iCursor>=0 ) break; dbda8d6ce9 2007-07-21 drh: pItem->iCursor = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: if( pItem->pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete an entire SrcList including all its substructure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SrcListDelete(SrcList *pList){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return; dbda8d6ce9 2007-07-21 drh: for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){ c287665ba8 2007-09-14 drh: sqlite3_free(pItem->zDatabase); c287665ba8 2007-09-14 drh: sqlite3_free(pItem->zName); c287665ba8 2007-09-14 drh: sqlite3_free(pItem->zAlias); dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(pItem->pTab); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pItem->pSelect); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pItem->pOn); dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(pItem->pUsing); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called by the parser to add a new term to the dbda8d6ce9 2007-07-21 drh: ** end of a growing FROM clause. The "p" parameter is the part of dbda8d6ce9 2007-07-21 drh: ** the FROM clause that has already been constructed. "p" is NULL dbda8d6ce9 2007-07-21 drh: ** if this is the first term of the FROM clause. pTable and pDatabase dbda8d6ce9 2007-07-21 drh: ** are the name of the table and database named in the FROM clause term. dbda8d6ce9 2007-07-21 drh: ** pDatabase is NULL if the database name qualifier is missing - the dbda8d6ce9 2007-07-21 drh: ** usual case. If the term has a alias, then pAlias points to the dbda8d6ce9 2007-07-21 drh: ** alias token. If the term is a subquery, then pSubquery is the dbda8d6ce9 2007-07-21 drh: ** SELECT statement that the subquery encodes. The pTable and dbda8d6ce9 2007-07-21 drh: ** pDatabase parameters are NULL for subqueries. The pOn and pUsing dbda8d6ce9 2007-07-21 drh: ** parameters are the content of the ON and USING clauses. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return a new SrcList which encodes is the FROM with the new dbda8d6ce9 2007-07-21 drh: ** term added. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( c287665ba8 2007-09-14 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: SrcList *p, /* The left part of the FROM clause already seen */ dbda8d6ce9 2007-07-21 drh: Token *pTable, /* Name of the table to add to the FROM clause */ dbda8d6ce9 2007-07-21 drh: Token *pDatabase, /* Name of the database containing pTable */ dbda8d6ce9 2007-07-21 drh: Token *pAlias, /* The right-hand side of the AS subexpression */ dbda8d6ce9 2007-07-21 drh: Select *pSubquery, /* A subquery used in place of a table name */ dbda8d6ce9 2007-07-21 drh: Expr *pOn, /* The ON clause of a join */ dbda8d6ce9 2007-07-21 drh: IdList *pUsing /* The USING clause of a join */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; c287665ba8 2007-09-14 drh: p = sqlite3SrcListAppend(db, p, pTable, pDatabase); dbda8d6ce9 2007-07-21 drh: if( p==0 || p->nSrc==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pOn); dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(pUsing); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSubquery); dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pItem = &p->a[p->nSrc-1]; dbda8d6ce9 2007-07-21 drh: if( pAlias && pAlias->n ){ c287665ba8 2007-09-14 drh: pItem->zAlias = sqlite3NameFromToken(db, pAlias); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pItem->pSelect = pSubquery; dbda8d6ce9 2007-07-21 drh: pItem->pOn = pOn; dbda8d6ce9 2007-07-21 drh: pItem->pUsing = pUsing; dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** When building up a FROM clause in the parser, the join operator dbda8d6ce9 2007-07-21 drh: ** is initially attached to the left operand. But the code generator dbda8d6ce9 2007-07-21 drh: ** expects the join operator to be on the right operand. This routine dbda8d6ce9 2007-07-21 drh: ** Shifts all join operators from left to right for an entire FROM dbda8d6ce9 2007-07-21 drh: ** clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Example: Suppose the join is like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A natural cross join B dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The operator is "natural cross join". The A and B operands are stored dbda8d6ce9 2007-07-21 drh: ** in p->a[0] and p->a[1], respectively. The parser initially stores the dbda8d6ce9 2007-07-21 drh: ** operator with A. This routine shifts that operator over to B. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){ dbda8d6ce9 2007-07-21 drh: if( p && p->a ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=p->nSrc-1; i>0; i--){ dbda8d6ce9 2007-07-21 drh: p->a[i].jointype = p->a[i-1].jointype; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->a[0].jointype = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Begin a transaction dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed ) return; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( !v ) return; dbda8d6ce9 2007-07-21 drh: if( type!=TK_DEFERRED ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1); c287665ba8 2007-09-14 drh: sqlite3VdbeUsesBtree(v, i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Commit a transaction dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed ) return; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Rollback a transaction dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed ) return; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make sure the TEMP database is open and available for use. Return dbda8d6ce9 2007-07-21 drh: ** the number of errors. Leave any error messages in the pParse structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: if( db->aDb[1].pBt==0 && !pParse->explain ){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: static const int flags = c287665ba8 2007-09-14 drh: SQLITE_OPEN_READWRITE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_CREATE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_EXCLUSIVE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_DELETEONCLOSE | c287665ba8 2007-09-14 drh: SQLITE_OPEN_TEMP_DB; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags, dbda8d6ce9 2007-07-21 drh: &db->aDb[1].pBt); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "unable to open a temporary database " dbda8d6ce9 2007-07-21 drh: "file for storing temporary tables"); dbda8d6ce9 2007-07-21 drh: pParse->rc = rc; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( db->flags & !db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeBeginTrans(db->aDb[1].pBt, 1); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "unable to get a write lock on " dbda8d6ce9 2007-07-21 drh: "the temporary database file"); dbda8d6ce9 2007-07-21 drh: pParse->rc = rc; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( db->aDb[1].pSchema ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate VDBE code that will verify the schema cookie and start dbda8d6ce9 2007-07-21 drh: ** a read-transaction for all named database files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It is important that all schema cookies be verified and all dbda8d6ce9 2007-07-21 drh: ** read transactions be started before anything else happens in dbda8d6ce9 2007-07-21 drh: ** the VDBE program. But this routine can be called after much other dbda8d6ce9 2007-07-21 drh: ** code has been generated. So here is what we do: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first time this routine is called, we code an OP_Goto that dbda8d6ce9 2007-07-21 drh: ** will jump to a subroutine at the end of the program. Then we dbda8d6ce9 2007-07-21 drh: ** record every database that needs its schema verified in the dbda8d6ce9 2007-07-21 drh: ** pParse->cookieMask field. Later, after all other code has been dbda8d6ce9 2007-07-21 drh: ** generated, the subroutine that does the cookie verifications and dbda8d6ce9 2007-07-21 drh: ** starts the transactions will be coded and the OP_Goto P2 value dbda8d6ce9 2007-07-21 drh: ** will be made to point to that subroutine. The generation of the dbda8d6ce9 2007-07-21 drh: ** cookie verification subroutine code happens in sqlite3FinishCoding(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If iDb<0 then code the OP_Goto only - don't set flag to verify the dbda8d6ce9 2007-07-21 drh: ** schema on any databases. This can be used to position the OP_Goto dbda8d6ce9 2007-07-21 drh: ** early in the code, before we know if any database tables will be used. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: int mask; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; /* This only happens if there was a prior error */ dbda8d6ce9 2007-07-21 drh: db = pParse->db; dbda8d6ce9 2007-07-21 drh: if( pParse->cookieGoto==0 ){ dbda8d6ce9 2007-07-21 drh: pParse->cookieGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0)+1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iDb>=0 ){ dbda8d6ce9 2007-07-21 drh: assert( iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: assert( db->aDb[iDb].pBt!=0 || iDb==1 ); dbda8d6ce9 2007-07-21 drh: assert( iDb<SQLITE_MAX_ATTACHED+2 ); dbda8d6ce9 2007-07-21 drh: mask = 1<<iDb; dbda8d6ce9 2007-07-21 drh: if( (pParse->cookieMask & mask)==0 ){ dbda8d6ce9 2007-07-21 drh: pParse->cookieMask |= mask; dbda8d6ce9 2007-07-21 drh: pParse->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && iDb==1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3OpenTempDatabase(pParse); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate VDBE code that prepares for doing an operation that dbda8d6ce9 2007-07-21 drh: ** might change the database. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine starts a new transaction if we are not already within dbda8d6ce9 2007-07-21 drh: ** a transaction. If we are already within a transaction, then a checkpoint dbda8d6ce9 2007-07-21 drh: ** is set if the setStatement parameter is true. A checkpoint should dbda8d6ce9 2007-07-21 drh: ** be set for operations that might fail (due to a constraint) part of dbda8d6ce9 2007-07-21 drh: ** the way through and which will need to undo some writes without having to dbda8d6ce9 2007-07-21 drh: ** rollback the whole transaction. For operations where all constraints dbda8d6ce9 2007-07-21 drh: ** can be checked before any changes are made to the database, it is never dbda8d6ce9 2007-07-21 drh: ** necessary to undo a write and the checkpoint should not be set. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Only database iDb and the temp database are made writable by this call. dbda8d6ce9 2007-07-21 drh: ** If iDb==0, then the main and temp databases are made writable. If dbda8d6ce9 2007-07-21 drh: ** iDb==1 then only the temp database is made writable. If iDb>1 then the dbda8d6ce9 2007-07-21 drh: ** specified auxiliary database and the temp database are made writable. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: sqlite3CodeVerifySchema(pParse, iDb); dbda8d6ce9 2007-07-21 drh: pParse->writeMask |= 1<<iDb; dbda8d6ce9 2007-07-21 drh: if( setStatement && pParse->nested==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Statement, iDb, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (OMIT_TEMPDB || iDb!=1) && pParse->db->aDb[1].pBt!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, setStatement, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if pIndex uses the collating sequence pColl. Return dbda8d6ce9 2007-07-21 drh: ** true if it does and false if it does not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_REINDEX dbda8d6ce9 2007-07-21 drh: static int collationMatch(const char *zColl, Index *pIndex){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pIndex->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: const char *z = pIndex->azColl[i]; dbda8d6ce9 2007-07-21 drh: if( z==zColl || (z && zColl && 0==sqlite3StrICmp(z, zColl)) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Recompute all indices of pTab that use the collating sequence pColl. dbda8d6ce9 2007-07-21 drh: ** If pColl==0 then recompute all indices of pTab. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_REINDEX dbda8d6ce9 2007-07-21 drh: static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ dbda8d6ce9 2007-07-21 drh: Index *pIndex; /* An index associated with pTab */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ dbda8d6ce9 2007-07-21 drh: if( zColl==0 || collationMatch(zColl, pIndex) ){ dbda8d6ce9 2007-07-21 drh: int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3RefillIndex(pParse, pIndex, -1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Recompute all indices of all tables in all databases where the dbda8d6ce9 2007-07-21 drh: ** indices use the collating sequence pColl. If pColl==0 then recompute dbda8d6ce9 2007-07-21 drh: ** all indices everywhere. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_REINDEX dbda8d6ce9 2007-07-21 drh: static void reindexDatabases(Parse *pParse, char const *zColl){ dbda8d6ce9 2007-07-21 drh: Db *pDb; /* A single database */ dbda8d6ce9 2007-07-21 drh: int iDb; /* The database index number */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; /* The database connection */ dbda8d6ce9 2007-07-21 drh: HashElem *k; /* For looping over tables in pDb */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* A table in the database */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){ dbda8d6ce9 2007-07-21 drh: assert( pDb!=0 ); dbda8d6ce9 2007-07-21 drh: for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ dbda8d6ce9 2007-07-21 drh: pTab = (Table*)sqliteHashData(k); dbda8d6ce9 2007-07-21 drh: reindexTable(pParse, pTab, zColl); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for the REINDEX command. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** REINDEX -- 1 dbda8d6ce9 2007-07-21 drh: ** REINDEX <collation> -- 2 dbda8d6ce9 2007-07-21 drh: ** REINDEX ?<database>.?<tablename> -- 3 dbda8d6ce9 2007-07-21 drh: ** REINDEX ?<database>.?<indexname> -- 4 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Form 1 causes all indices in all attached databases to be rebuilt. dbda8d6ce9 2007-07-21 drh: ** Form 2 rebuilds all indices in all databases that use the named dbda8d6ce9 2007-07-21 drh: ** collating function. Forms 3 and 4 rebuild the named index or all dbda8d6ce9 2007-07-21 drh: ** indices associated with the named table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_REINDEX dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */ dbda8d6ce9 2007-07-21 drh: char *z; /* Name of a table or index */ dbda8d6ce9 2007-07-21 drh: const char *zDb; /* Name of the database */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* A table in the database */ dbda8d6ce9 2007-07-21 drh: Index *pIndex; /* An index associated with pTab */ dbda8d6ce9 2007-07-21 drh: int iDb; /* The database index number */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; /* The database connection */ dbda8d6ce9 2007-07-21 drh: Token *pObjName; /* Name of the table or index to be reindexed */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read the database schema. If an error occurs, leave an error message dbda8d6ce9 2007-07-21 drh: ** and code in pParse and return NULL. */ dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pName1==0 || pName1->z==0 ){ dbda8d6ce9 2007-07-21 drh: reindexDatabases(pParse, 0); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: }else if( pName2==0 || pName2->z==0 ){ dbda8d6ce9 2007-07-21 drh: assert( pName1->z ); dbda8d6ce9 2007-07-21 drh: pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0); dbda8d6ce9 2007-07-21 drh: if( pColl ){ c287665ba8 2007-09-14 drh: char *zColl = sqlite3DbStrNDup(db, (const char *)pName1->z, pName1->n); dbda8d6ce9 2007-07-21 drh: if( zColl ){ dbda8d6ce9 2007-07-21 drh: reindexDatabases(pParse, zColl); c287665ba8 2007-09-14 drh: sqlite3_free(zColl); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); dbda8d6ce9 2007-07-21 drh: if( iDb<0 ) return; c287665ba8 2007-09-14 drh: z = sqlite3NameFromToken(db, pObjName); dbda8d6ce9 2007-07-21 drh: if( z==0 ) return; dbda8d6ce9 2007-07-21 drh: zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: pTab = sqlite3FindTable(db, z, zDb); dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: reindexTable(pParse, pTab, 0); c287665ba8 2007-09-14 drh: sqlite3_free(z); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIndex = sqlite3FindIndex(db, z, zDb); c287665ba8 2007-09-14 drh: sqlite3_free(z); dbda8d6ce9 2007-07-21 drh: if( pIndex ){ dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3RefillIndex(pParse, pIndex, -1); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a dynamicly allocated KeyInfo structure that can be used dbda8d6ce9 2007-07-21 drh: ** with OP_OpenRead or OP_OpenWrite to access database index pIdx. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If successful, a pointer to the new structure is returned. In this case c287665ba8 2007-09-14 drh: ** the caller is responsible for calling sqlite3_free() on the returned dbda8d6ce9 2007-07-21 drh: ** pointer. If an error occurs (out of memory or missing collation dbda8d6ce9 2007-07-21 drh: ** sequence), NULL is returned and the state of pParse updated to reflect dbda8d6ce9 2007-07-21 drh: ** the error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nCol = pIdx->nColumn; dbda8d6ce9 2007-07-21 drh: int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol; c287665ba8 2007-09-14 drh: KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(pParse->db, nBytes); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pKey ){ c287665ba8 2007-09-14 drh: pKey->db = pParse->db; dbda8d6ce9 2007-07-21 drh: pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]); dbda8d6ce9 2007-07-21 drh: assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) ); dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: char *zColl = pIdx->azColl[i]; dbda8d6ce9 2007-07-21 drh: assert( zColl ); dbda8d6ce9 2007-07-21 drh: pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl, -1); dbda8d6ce9 2007-07-21 drh: pKey->aSortOrder[i] = pIdx->aSortOrder[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pKey->nField = nCol; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParse->nErr ){ c287665ba8 2007-09-14 drh: sqlite3_free(pKey); dbda8d6ce9 2007-07-21 drh: pKey = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of build.c ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file callback.c ****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2005 May 23 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains functions used to access the internal hash tables dbda8d6ce9 2007-07-21 drh: ** of user defined functions and collation sequences. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: callback.c,v 1.23 2007/08/29 12:31:26 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invoke the 'collation needed' callback to request a collation sequence dbda8d6ce9 2007-07-21 drh: ** in the database text encoding of name zName, length nName. dbda8d6ce9 2007-07-21 drh: ** If the collation sequence dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void callCollNeeded(sqlite3 *db, const char *zName, int nName){ dbda8d6ce9 2007-07-21 drh: assert( !db->xCollNeeded || !db->xCollNeeded16 ); dbda8d6ce9 2007-07-21 drh: if( nName<0 ) nName = strlen(zName); dbda8d6ce9 2007-07-21 drh: if( db->xCollNeeded ){ c287665ba8 2007-09-14 drh: char *zExternal = sqlite3DbStrNDup(db, zName, nName); dbda8d6ce9 2007-07-21 drh: if( !zExternal ) return; dbda8d6ce9 2007-07-21 drh: db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal); c287665ba8 2007-09-14 drh: sqlite3_free(zExternal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: if( db->xCollNeeded16 ){ dbda8d6ce9 2007-07-21 drh: char const *zExternal; c287665ba8 2007-09-14 drh: sqlite3_value *pTmp = sqlite3ValueNew(db); dbda8d6ce9 2007-07-21 drh: sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE); dbda8d6ce9 2007-07-21 drh: if( zExternal ){ dbda8d6ce9 2007-07-21 drh: db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree(pTmp); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called if the collation factory fails to deliver a dbda8d6ce9 2007-07-21 drh: ** collation function in the best encoding but there may be other versions dbda8d6ce9 2007-07-21 drh: ** of this collation function (for other text encodings) available. Use one dbda8d6ce9 2007-07-21 drh: ** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if dbda8d6ce9 2007-07-21 drh: ** possible. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int synthCollSeq(sqlite3 *db, CollSeq *pColl){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl2; dbda8d6ce9 2007-07-21 drh: char *z = pColl->zName; dbda8d6ce9 2007-07-21 drh: int n = strlen(z); dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 }; dbda8d6ce9 2007-07-21 drh: for(i=0; i<3; i++){ dbda8d6ce9 2007-07-21 drh: pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, n, 0); dbda8d6ce9 2007-07-21 drh: if( pColl2->xCmp!=0 ){ dbda8d6ce9 2007-07-21 drh: memcpy(pColl, pColl2, sizeof(CollSeq)); dbda8d6ce9 2007-07-21 drh: pColl->xDel = 0; /* Do not copy the destructor */ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is responsible for invoking the collation factory callback dbda8d6ce9 2007-07-21 drh: ** or substituting a collation sequence of a different encoding when the dbda8d6ce9 2007-07-21 drh: ** requested collation sequence is not available in the database native dbda8d6ce9 2007-07-21 drh: ** encoding. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If it is not NULL, then pColl must point to the database native encoding dbda8d6ce9 2007-07-21 drh: ** collation sequence with name zName, length nName. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The return value is either the collation sequence to be used in database dbda8d6ce9 2007-07-21 drh: ** db for collation type name zName, length nName, or NULL, if no collation dbda8d6ce9 2007-07-21 drh: ** sequence can be found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( dbda8d6ce9 2007-07-21 drh: sqlite3* db, dbda8d6ce9 2007-07-21 drh: CollSeq *pColl, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int nName dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: CollSeq *p; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: p = pColl; dbda8d6ce9 2007-07-21 drh: if( !p ){ dbda8d6ce9 2007-07-21 drh: p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !p || !p->xCmp ){ dbda8d6ce9 2007-07-21 drh: /* No collation sequence of this type for this encoding is registered. dbda8d6ce9 2007-07-21 drh: ** Call the collation factory to see if it can supply us with one. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: callCollNeeded(db, zName, nName); dbda8d6ce9 2007-07-21 drh: p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p && !p->xCmp && synthCollSeq(db, p) ){ dbda8d6ce9 2007-07-21 drh: p = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( !p || p->xCmp ); dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called on a collation sequence before it is used to dbda8d6ce9 2007-07-21 drh: ** check that it is defined. An undefined collation sequence exists when dbda8d6ce9 2007-07-21 drh: ** a database is loaded that contains references to collation sequences dbda8d6ce9 2007-07-21 drh: ** that have not been defined by sqlite3_create_collation() etc. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If required, this routine calls the 'collation needed' callback to dbda8d6ce9 2007-07-21 drh: ** request a definition of the collating sequence. If this doesn't work, dbda8d6ce9 2007-07-21 drh: ** an equivalent collating sequence that uses a text encoding different dbda8d6ce9 2007-07-21 drh: ** from the main database is substituted, if one is available. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ dbda8d6ce9 2007-07-21 drh: if( pColl ){ dbda8d6ce9 2007-07-21 drh: const char *zName = pColl->zName; dbda8d6ce9 2007-07-21 drh: CollSeq *p = sqlite3GetCollSeq(pParse->db, pColl, zName, -1); dbda8d6ce9 2007-07-21 drh: if( !p ){ dbda8d6ce9 2007-07-21 drh: if( pParse->nErr==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->nErr++; dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( p==pColl ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Locate and return an entry from the db.aCollSeq hash table. If the entry dbda8d6ce9 2007-07-21 drh: ** specified by zName and nName is not found and parameter 'create' is dbda8d6ce9 2007-07-21 drh: ** true, then create a new entry. Otherwise return NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each pointer stored in the sqlite3.aCollSeq hash table contains an dbda8d6ce9 2007-07-21 drh: ** array of three CollSeq structures. The first is the collation sequence dbda8d6ce9 2007-07-21 drh: ** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Stored immediately after the three collation sequences is a copy of dbda8d6ce9 2007-07-21 drh: ** the collation sequence name. A pointer to this string is stored in dbda8d6ce9 2007-07-21 drh: ** each collation sequence structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static CollSeq *findCollSeqEntry( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int nName, dbda8d6ce9 2007-07-21 drh: int create dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: if( nName<0 ) nName = strlen(zName); dbda8d6ce9 2007-07-21 drh: pColl = sqlite3HashFind(&db->aCollSeq, zName, nName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( 0==pColl && create ){ c287665ba8 2007-09-14 drh: pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 ); dbda8d6ce9 2007-07-21 drh: if( pColl ){ dbda8d6ce9 2007-07-21 drh: CollSeq *pDel = 0; dbda8d6ce9 2007-07-21 drh: pColl[0].zName = (char*)&pColl[3]; dbda8d6ce9 2007-07-21 drh: pColl[0].enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: pColl[1].zName = (char*)&pColl[3]; dbda8d6ce9 2007-07-21 drh: pColl[1].enc = SQLITE_UTF16LE; dbda8d6ce9 2007-07-21 drh: pColl[2].zName = (char*)&pColl[3]; dbda8d6ce9 2007-07-21 drh: pColl[2].enc = SQLITE_UTF16BE; dbda8d6ce9 2007-07-21 drh: memcpy(pColl[0].zName, zName, nName); dbda8d6ce9 2007-07-21 drh: pColl[0].zName[nName] = 0; dbda8d6ce9 2007-07-21 drh: pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a malloc() failure occured in sqlite3HashInsert(), it will dbda8d6ce9 2007-07-21 drh: ** return the pColl pointer to be deleted (because it wasn't added dbda8d6ce9 2007-07-21 drh: ** to the hash table). dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: assert( pDel==0 || pDel==pColl ); c287665ba8 2007-09-14 drh: if( pDel!=0 ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: sqlite3_free(pDel); dbda8d6ce9 2007-07-21 drh: pColl = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Parameter zName points to a UTF-8 encoded string nName bytes long. dbda8d6ce9 2007-07-21 drh: ** Return the CollSeq* pointer for the collation sequence named zName dbda8d6ce9 2007-07-21 drh: ** for the encoding 'enc' from the database 'db'. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the entry specified is not found and 'create' is true, then create a dbda8d6ce9 2007-07-21 drh: ** new entry. Otherwise return NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A separate function sqlite3LocateCollSeq() is a wrapper around dbda8d6ce9 2007-07-21 drh: ** this routine. sqlite3LocateCollSeq() invokes the collation factory dbda8d6ce9 2007-07-21 drh: ** if necessary and generates an error message if the collating sequence dbda8d6ce9 2007-07-21 drh: ** cannot be found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: u8 enc, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int nName, dbda8d6ce9 2007-07-21 drh: int create dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: if( zName ){ dbda8d6ce9 2007-07-21 drh: pColl = findCollSeqEntry(db, zName, nName, create); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pColl = db->pDfltColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); dbda8d6ce9 2007-07-21 drh: assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); dbda8d6ce9 2007-07-21 drh: if( pColl ) pColl += enc-1; dbda8d6ce9 2007-07-21 drh: return pColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Locate a user function given a name, a number of arguments and a flag dbda8d6ce9 2007-07-21 drh: ** indicating whether the function prefers UTF-16 over UTF-8. Return a dbda8d6ce9 2007-07-21 drh: ** pointer to the FuncDef structure that defines that function, or return dbda8d6ce9 2007-07-21 drh: ** NULL if the function does not exist. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the createFlag argument is true, then a new (blank) FuncDef dbda8d6ce9 2007-07-21 drh: ** structure is created and liked into the "db" structure if a dbda8d6ce9 2007-07-21 drh: ** no matching function previously existed. When createFlag is true dbda8d6ce9 2007-07-21 drh: ** and the nArg parameter is -1, then only a function that accepts dbda8d6ce9 2007-07-21 drh: ** any number of arguments will be returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If createFlag is false and nArg is -1, then the first valid dbda8d6ce9 2007-07-21 drh: ** function found is returned. A function is valid if either xFunc dbda8d6ce9 2007-07-21 drh: ** or xStep is non-zero. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If createFlag is false, then a function with the required name and dbda8d6ce9 2007-07-21 drh: ** number of arguments may be returned even if the eTextRep flag does not dbda8d6ce9 2007-07-21 drh: ** match that requested. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE FuncDef *sqlite3FindFunction( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* An open database */ dbda8d6ce9 2007-07-21 drh: const char *zName, /* Name of the function. Not null-terminated */ dbda8d6ce9 2007-07-21 drh: int nName, /* Number of characters in the name */ dbda8d6ce9 2007-07-21 drh: int nArg, /* Number of arguments. -1 means any number */ dbda8d6ce9 2007-07-21 drh: u8 enc, /* Preferred text encoding */ dbda8d6ce9 2007-07-21 drh: int createFlag /* Create new entry if true and does not otherwise exist */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: FuncDef *p; /* Iterator variable */ dbda8d6ce9 2007-07-21 drh: FuncDef *pFirst; /* First function with this name */ dbda8d6ce9 2007-07-21 drh: FuncDef *pBest = 0; /* Best match found so far */ dbda8d6ce9 2007-07-21 drh: int bestmatch = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); dbda8d6ce9 2007-07-21 drh: if( nArg<-1 ) nArg = -1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName); dbda8d6ce9 2007-07-21 drh: for(p=pFirst; p; p=p->pNext){ dbda8d6ce9 2007-07-21 drh: /* During the search for the best function definition, bestmatch is set dbda8d6ce9 2007-07-21 drh: ** as follows to indicate the quality of the match with the definition dbda8d6ce9 2007-07-21 drh: ** pointed to by pBest: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 0: pBest is NULL. No match has been found. dbda8d6ce9 2007-07-21 drh: ** 1: A variable arguments function that prefers UTF-8 when a UTF-16 dbda8d6ce9 2007-07-21 drh: ** encoding is requested, or vice versa. dbda8d6ce9 2007-07-21 drh: ** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is dbda8d6ce9 2007-07-21 drh: ** requested, or vice versa. dbda8d6ce9 2007-07-21 drh: ** 3: A variable arguments function using the same text encoding. dbda8d6ce9 2007-07-21 drh: ** 4: A function with the exact number of arguments requested that dbda8d6ce9 2007-07-21 drh: ** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa. dbda8d6ce9 2007-07-21 drh: ** 5: A function with the exact number of arguments requested that dbda8d6ce9 2007-07-21 drh: ** prefers UTF-16LE when UTF-16BE is requested, or vice versa. dbda8d6ce9 2007-07-21 drh: ** 6: An exact match. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A larger value of 'matchqual' indicates a more desirable match. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->nArg==-1 || p->nArg==nArg || nArg==-1 ){ dbda8d6ce9 2007-07-21 drh: int match = 1; /* Quality of this match */ dbda8d6ce9 2007-07-21 drh: if( p->nArg==nArg || nArg==-1 ){ dbda8d6ce9 2007-07-21 drh: match = 4; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( enc==p->iPrefEnc ){ dbda8d6ce9 2007-07-21 drh: match += 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) || dbda8d6ce9 2007-07-21 drh: (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){ dbda8d6ce9 2007-07-21 drh: match += 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( match>bestmatch ){ dbda8d6ce9 2007-07-21 drh: pBest = p; dbda8d6ce9 2007-07-21 drh: bestmatch = match; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the createFlag parameter is true, and the seach did not reveal an dbda8d6ce9 2007-07-21 drh: ** exact match for the name, number of arguments and encoding, then add a dbda8d6ce9 2007-07-21 drh: ** new entry to the hash table and return it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( createFlag && bestmatch<6 && c287665ba8 2007-09-14 drh: (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName))!=0 ){ dbda8d6ce9 2007-07-21 drh: pBest->nArg = nArg; dbda8d6ce9 2007-07-21 drh: pBest->pNext = pFirst; dbda8d6ce9 2007-07-21 drh: pBest->iPrefEnc = enc; dbda8d6ce9 2007-07-21 drh: memcpy(pBest->zName, zName, nName); dbda8d6ce9 2007-07-21 drh: pBest->zName[nName] = 0; dbda8d6ce9 2007-07-21 drh: if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: sqlite3_free(pBest); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){ dbda8d6ce9 2007-07-21 drh: return pBest; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Free all resources held by the schema structure. The void* argument points c287665ba8 2007-09-14 drh: ** at a Schema struct. This function does not call sqlite3_free() on the dbda8d6ce9 2007-07-21 drh: ** pointer itself, it just cleans up subsiduary resources (i.e. the contents dbda8d6ce9 2007-07-21 drh: ** of the schema hash tables). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SchemaFree(void *p){ dbda8d6ce9 2007-07-21 drh: Hash temp1; dbda8d6ce9 2007-07-21 drh: Hash temp2; dbda8d6ce9 2007-07-21 drh: HashElem *pElem; dbda8d6ce9 2007-07-21 drh: Schema *pSchema = (Schema *)p; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: temp1 = pSchema->tblHash; dbda8d6ce9 2007-07-21 drh: temp2 = pSchema->trigHash; dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0); dbda8d6ce9 2007-07-21 drh: sqlite3HashClear(&pSchema->aFKey); dbda8d6ce9 2007-07-21 drh: sqlite3HashClear(&pSchema->idxHash); dbda8d6ce9 2007-07-21 drh: for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3HashClear(&temp2); dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0); dbda8d6ce9 2007-07-21 drh: for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ dbda8d6ce9 2007-07-21 drh: Table *pTab = sqliteHashData(pElem); dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(pTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3HashClear(&temp1); dbda8d6ce9 2007-07-21 drh: pSchema->pSeqTab = 0; dbda8d6ce9 2007-07-21 drh: pSchema->flags &= ~DB_SchemaLoaded; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find and return the schema associated with a BTree. Create dbda8d6ce9 2007-07-21 drh: ** a new one if necessary. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ dbda8d6ce9 2007-07-21 drh: Schema * p; dbda8d6ce9 2007-07-21 drh: if( pBt ){ c287665ba8 2007-09-14 drh: p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaFree); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: p = (Schema *)sqlite3MallocZero(sizeof(Schema)); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( !p ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: }else if ( 0==p->file_format ){ dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0); dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0); dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0); dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1); dbda8d6ce9 2007-07-21 drh: p->enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of callback.c ********************************************/ c287665ba8 2007-09-14 drh: /************** Begin file delete.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains C code routines that are called by the parser dbda8d6ce9 2007-07-21 drh: ** in order to generate code for DELETE FROM statements. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: delete.c,v 1.130 2007/08/16 04:30:40 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Look up every table that is named in pSrc. If any table is not found, dbda8d6ce9 2007-07-21 drh: ** add an error message to pParse->zErrMsg and return NULL. If all tables dbda8d6ce9 2007-07-21 drh: ** are found, return a pointer to the last table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ dbda8d6ce9 2007-07-21 drh: Table *pTab = 0; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; dbda8d6ce9 2007-07-21 drh: for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase); dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(pItem->pTab); dbda8d6ce9 2007-07-21 drh: pItem->pTab = pTab; dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: pTab->nRef++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pTab; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to make sure the given table is writable. If it is not dbda8d6ce9 2007-07-21 drh: ** writable, generate an error message and return 1. If it is dbda8d6ce9 2007-07-21 drh: ** writable return 0; dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ dbda8d6ce9 2007-07-21 drh: if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0 dbda8d6ce9 2007-07-21 drh: && pParse->nested==0) dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: || (pTab->pMod && pTab->pMod->pModule->xUpdate==0) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: if( !viewOk && pTab->pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will open a table for reading. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3OpenTable( dbda8d6ce9 2007-07-21 drh: Parse *p, /* Generate code into this VDBE */ dbda8d6ce9 2007-07-21 drh: int iCur, /* The cursor number of the table */ dbda8d6ce9 2007-07-21 drh: int iDb, /* The database index in sqlite3.aDb[] */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* The table to be opened */ dbda8d6ce9 2007-07-21 drh: int opcode /* OP_OpenRead or OP_OpenWrite */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ) return; dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(p); dbda8d6ce9 2007-07-21 drh: assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); dbda8d6ce9 2007-07-21 drh: sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# %s", pTab->zName)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for a DELETE FROM statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL; dbda8d6ce9 2007-07-21 drh: ** \________/ \________________/ dbda8d6ce9 2007-07-21 drh: ** pTabList pWhere dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeleteFrom( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList, /* The table from which we should delete things */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere /* The WHERE clause. May be null */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v; /* The virtual database engine */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* The table from which records will be deleted */ dbda8d6ce9 2007-07-21 drh: const char *zDb; /* Name of database holding pTab */ dbda8d6ce9 2007-07-21 drh: int end, addr = 0; /* A couple addresses of generated code */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: WhereInfo *pWInfo; /* Information about the WHERE clause */ dbda8d6ce9 2007-07-21 drh: Index *pIdx; /* For looping over indices of the table */ dbda8d6ce9 2007-07-21 drh: int iCur; /* VDBE Cursor number for pTab */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; /* Main database structure */ dbda8d6ce9 2007-07-21 drh: AuthContext sContext; /* Authorization context */ dbda8d6ce9 2007-07-21 drh: int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ dbda8d6ce9 2007-07-21 drh: NameContext sNC; /* Name context to resolve expressions in */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Database number */ dbda8d6ce9 2007-07-21 drh: int memCnt = 0; /* Memory cell used for change counting */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: int isView; /* True if attempting to delete from a view */ dbda8d6ce9 2007-07-21 drh: int triggers_exist = 0; /* True if any triggers exist */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sContext.pParse = 0; c287665ba8 2007-09-14 drh: db = pParse->db; c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto delete_from_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pTabList->nSrc==1 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Locate the table which we want to delete. This table has to be dbda8d6ce9 2007-07-21 drh: ** put in an SrcList structure because some of the subroutines we dbda8d6ce9 2007-07-21 drh: ** will be calling are designed to work with multiple tables and expect dbda8d6ce9 2007-07-21 drh: ** an SrcList* parameter instead of just a Table* parameter. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTab = sqlite3SrcListLookup(pParse, pTabList); dbda8d6ce9 2007-07-21 drh: if( pTab==0 ) goto delete_from_cleanup; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out if we have any triggers and if the table being dbda8d6ce9 2007-07-21 drh: ** deleted from is a view dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0); dbda8d6ce9 2007-07-21 drh: isView = pTab->pSelect!=0; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define triggers_exist 0 dbda8d6ce9 2007-07-21 drh: # define isView 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: # undef isView dbda8d6ce9 2007-07-21 drh: # define isView 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){ dbda8d6ce9 2007-07-21 drh: goto delete_from_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto delete_from_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If pTab is really a view, make sure it has been initialized. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3ViewGetColumnNames(pParse, pTab) ){ dbda8d6ce9 2007-07-21 drh: goto delete_from_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate a cursor used to store the old.* data for a trigger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: oldIdx = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Resolve the column names in the WHERE clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pTabList->nSrc==1 ); dbda8d6ce9 2007-07-21 drh: iCur = pTabList->a[0].iCursor = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: memset(&sNC, 0, sizeof(sNC)); dbda8d6ce9 2007-07-21 drh: sNC.pParse = pParse; dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = pTabList; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, pWhere) ){ dbda8d6ce9 2007-07-21 drh: goto delete_from_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Start the view context dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3AuthContextPush(pParse, &sContext, pTab->zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin generating code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ){ dbda8d6ce9 2007-07-21 drh: goto delete_from_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, triggers_exist, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we are trying to delete from a view, realize that view into dbda8d6ce9 2007-07-21 drh: ** a ephemeral table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( isView ){ c287665ba8 2007-09-14 drh: Select *pView = sqlite3SelectDup(db, pTab->pSelect); dbda8d6ce9 2007-07-21 drh: sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pView); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the counter of the number of rows deleted, if dbda8d6ce9 2007-07-21 drh: ** we are counting rows. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows ){ dbda8d6ce9 2007-07-21 drh: memCnt = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Special case: A DELETE without a WHERE clause deletes everything. dbda8d6ce9 2007-07-21 drh: ** It is easier just to erase the whole table. Note, however, that dbda8d6ce9 2007-07-21 drh: ** this means that the row change count will be incorrect. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows ){ dbda8d6ce9 2007-07-21 drh: /* If counting rows deleted, just count the total number of dbda8d6ce9 2007-07-21 drh: ** entries in the table. */ dbda8d6ce9 2007-07-21 drh: int endOfLoop = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: int addr2; dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2); dbda8d6ce9 2007-07-21 drh: addr2 = sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, iCur, addr2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, endOfLoop); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb); dbda8d6ce9 2007-07-21 drh: if( !pParse->nested ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: assert( pIdx->pSchema==pTab->pSchema ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* The usual case: There is a WHERE clause so we have to scan through dbda8d6ce9 2007-07-21 drh: ** the table and pick which records to delete. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: else{ dbda8d6ce9 2007-07-21 drh: /* Begin the database scan dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); dbda8d6ce9 2007-07-21 drh: if( pWInfo==0 ) goto delete_from_cleanup; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Remember the rowid of every item to be deleted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* End the database scan loop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3WhereEnd(pWInfo); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open the pseudo-table used to store OLD if there are triggers. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Delete every item whose key was written to the list during the dbda8d6ce9 2007-07-21 drh: ** database scan. We have to delete items after the scan is complete dbda8d6ce9 2007-07-21 drh: ** because deleting an item can change the scan order. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: end = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This is the beginning of the delete loop when there are dbda8d6ce9 2007-07-21 drh: ** row triggers. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0); dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab, dbda8d6ce9 2007-07-21 drh: -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, dbda8d6ce9 2007-07-21 drh: addr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: /* Open cursors for the table we are deleting from and all its dbda8d6ce9 2007-07-21 drh: ** indices. If there are row triggers, this happens inside the dbda8d6ce9 2007-07-21 drh: ** OP_FifoRead loop because the cursor have to all be closed dbda8d6ce9 2007-07-21 drh: ** before the trigger fires. If there are no row triggers, the dbda8d6ce9 2007-07-21 drh: ** cursors are opened only once on the outside the loop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This is the beginning of the delete loop when there are no dbda8d6ce9 2007-07-21 drh: ** row triggers */ dbda8d6ce9 2007-07-21 drh: if( !triggers_exist ){ dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Delete the row */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: pParse->pVirtualLock = pTab; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there are row triggers, close all cursors then invoke dbda8d6ce9 2007-07-21 drh: ** the AFTER triggers dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, dbda8d6ce9 2007-07-21 drh: oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, dbda8d6ce9 2007-07-21 drh: addr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* End of the delete loop */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, addr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, end); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Close the cursors after the loop if there are no row triggers */ dbda8d6ce9 2007-07-21 drh: if( !triggers_exist && !IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of rows that were deleted. If this routine is dbda8d6ce9 2007-07-21 drh: ** generating code because of a call to sqlite3NestedParse(), do not dbda8d6ce9 2007-07-21 drh: ** invoke the callback function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: delete_from_cleanup: dbda8d6ce9 2007-07-21 drh: sqlite3AuthContextPop(&sContext); dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pTabList); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pWhere); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine generates VDBE code that causes a single row of a dbda8d6ce9 2007-07-21 drh: ** single table to be deleted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The VDBE must be in a particular state when this routine is called. dbda8d6ce9 2007-07-21 drh: ** These are the requirements: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1. A read/write cursor pointing to pTab, the table containing the row dbda8d6ce9 2007-07-21 drh: ** to be deleted, must be opened as cursor number "base". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2. Read/write cursors for all indices of pTab must be open as dbda8d6ce9 2007-07-21 drh: ** cursor number base+i for the i-th index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 3. The record number of the row to be deleted must be on the top dbda8d6ce9 2007-07-21 drh: ** of the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine pops the top of the stack to remove the record number dbda8d6ce9 2007-07-21 drh: ** and then generates code to remove both the table record and all index dbda8d6ce9 2007-07-21 drh: ** entries that point to that record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3GenerateRowDelete( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* The database containing the index */ dbda8d6ce9 2007-07-21 drh: Vdbe *v, /* Generate code into this VDBE */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* Table containing the row to be deleted */ dbda8d6ce9 2007-07-21 drh: int iCur, /* Cursor number for the table */ dbda8d6ce9 2007-07-21 drh: int count /* Increment the row change counter */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); dbda8d6ce9 2007-07-21 drh: if( count ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine generates VDBE code that causes the deletion of all dbda8d6ce9 2007-07-21 drh: ** index entries associated with a single row of a single table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The VDBE must be in a particular state when this routine is called. dbda8d6ce9 2007-07-21 drh: ** These are the requirements: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1. A read/write cursor pointing to pTab, the table containing the row dbda8d6ce9 2007-07-21 drh: ** to be deleted, must be opened as cursor number "iCur". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2. Read/write cursors for all indices of pTab must be open as dbda8d6ce9 2007-07-21 drh: ** cursor number iCur+i for the i-th index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 3. The "iCur" cursor must be pointing to the row that is to be dbda8d6ce9 2007-07-21 drh: ** deleted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( dbda8d6ce9 2007-07-21 drh: Vdbe *v, /* Generate code into this VDBE */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* Table containing the row to be deleted */ dbda8d6ce9 2007-07-21 drh: int iCur, /* Cursor number for the table */ dbda8d6ce9 2007-07-21 drh: char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue; dbda8d6ce9 2007-07-21 drh: sqlite3GenerateIndexKey(v, pIdx, iCur); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will assemble an index key and put it on the top dbda8d6ce9 2007-07-21 drh: ** of the tack. The key with be for index pIdx which is an index on pTab. dbda8d6ce9 2007-07-21 drh: ** iCur is the index of a cursor open on the pTab table and pointing to dbda8d6ce9 2007-07-21 drh: ** the entry that needs indexing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3GenerateIndexKey( dbda8d6ce9 2007-07-21 drh: Vdbe *v, /* Generate code into this VDBE */ dbda8d6ce9 2007-07-21 drh: Index *pIdx, /* The index for which to generate a key */ dbda8d6ce9 2007-07-21 drh: int iCur /* Cursor number for the pIdx->pTable table */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: Table *pTab = pIdx->pTable; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: for(j=0; j<pIdx->nColumn; j++){ dbda8d6ce9 2007-07-21 drh: int idx = pIdx->aiColumn[j]; dbda8d6ce9 2007-07-21 drh: if( idx==pTab->iPKey ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, j, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iCur, idx); dbda8d6ce9 2007-07-21 drh: sqlite3ColumnDefault(v, pTab, idx); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0); dbda8d6ce9 2007-07-21 drh: sqlite3IndexAffinityStr(v, pIdx); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of delete.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file func.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2002 February 23 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains the C functions that implement various SQL dbda8d6ce9 2007-07-21 drh: ** functions of SQLite. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There is only one exported symbol in this file - the function dbda8d6ce9 2007-07-21 drh: ** sqliteRegisterBuildinFunctions() found at the bottom of the file. dbda8d6ce9 2007-07-21 drh: ** All other code has file scope. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: func.c,v 1.174 2007/09/03 11:04:22 danielk1977 Exp $ c287665ba8 2007-09-14 drh: */ d8590e093f 2007-07-24 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the collating function associated with a function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ dbda8d6ce9 2007-07-21 drh: return context->pColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the non-aggregate min() and max() functions dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void minmaxFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int mask; /* 0 for min() or 0xffffffff for max() */ dbda8d6ce9 2007-07-21 drh: int iBest; dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( argc==0 ) return; dbda8d6ce9 2007-07-21 drh: mask = sqlite3_user_data(context)==0 ? 0 : -1; dbda8d6ce9 2007-07-21 drh: pColl = sqlite3GetFuncCollSeq(context); dbda8d6ce9 2007-07-21 drh: assert( pColl ); dbda8d6ce9 2007-07-21 drh: assert( mask==-1 || mask==0 ); dbda8d6ce9 2007-07-21 drh: iBest = 0; dbda8d6ce9 2007-07-21 drh: if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; dbda8d6ce9 2007-07-21 drh: for(i=1; i<argc; i++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3_value_type(argv[i])==SQLITE_NULL ) return; dbda8d6ce9 2007-07-21 drh: if( (sqlite3MemCompare(argv[iBest], argv[i], pColl)^mask)>=0 ){ dbda8d6ce9 2007-07-21 drh: iBest = i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_value(context, argv[iBest]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the type of the argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void typeofFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const char *z = 0; dbda8d6ce9 2007-07-21 drh: switch( sqlite3_value_type(argv[0]) ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_NULL: z = "null"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_INTEGER: z = "integer"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_TEXT: z = "text"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_FLOAT: z = "real"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_BLOB: z = "blob"; break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, z, -1, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the length() function dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void lengthFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( argc==1 ); dbda8d6ce9 2007-07-21 drh: switch( sqlite3_value_type(argv[0]) ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_BLOB: dbda8d6ce9 2007-07-21 drh: case SQLITE_INTEGER: dbda8d6ce9 2007-07-21 drh: case SQLITE_FLOAT: { dbda8d6ce9 2007-07-21 drh: sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case SQLITE_TEXT: { dbda8d6ce9 2007-07-21 drh: const unsigned char *z = sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: if( z==0 ) return; dbda8d6ce9 2007-07-21 drh: len = 0; dbda8d6ce9 2007-07-21 drh: while( *z ){ dbda8d6ce9 2007-07-21 drh: len++; dbda8d6ce9 2007-07-21 drh: SQLITE_SKIP_UTF8(z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_int(context, len); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: sqlite3_result_null(context); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the abs() function dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: assert( argc==1 ); dbda8d6ce9 2007-07-21 drh: switch( sqlite3_value_type(argv[0]) ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_INTEGER: { dbda8d6ce9 2007-07-21 drh: i64 iVal = sqlite3_value_int64(argv[0]); dbda8d6ce9 2007-07-21 drh: if( iVal<0 ){ dbda8d6ce9 2007-07-21 drh: if( (iVal<<1)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context, "integer overflow", -1); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iVal = -iVal; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_int64(context, iVal); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case SQLITE_NULL: { dbda8d6ce9 2007-07-21 drh: sqlite3_result_null(context); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: double rVal = sqlite3_value_double(argv[0]); dbda8d6ce9 2007-07-21 drh: if( rVal<0 ) rVal = -rVal; dbda8d6ce9 2007-07-21 drh: sqlite3_result_double(context, rVal); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the substr() function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** substr(x,p1,p2) returns p2 characters of x[] beginning with p1. dbda8d6ce9 2007-07-21 drh: ** p1 is 1-indexed. So substr(x,1,1) returns the first character dbda8d6ce9 2007-07-21 drh: ** of x. If x is text, then we actually count UTF-8 characters. dbda8d6ce9 2007-07-21 drh: ** If x is a blob, then we count bytes. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If p1 is negative, then we begin abs(p1) from the end of x[]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void substrFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const unsigned char *z; dbda8d6ce9 2007-07-21 drh: const unsigned char *z2; dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: int p0type; dbda8d6ce9 2007-07-21 drh: i64 p1, p2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( argc==3 ); dbda8d6ce9 2007-07-21 drh: p0type = sqlite3_value_type(argv[0]); dbda8d6ce9 2007-07-21 drh: if( p0type==SQLITE_BLOB ){ dbda8d6ce9 2007-07-21 drh: len = sqlite3_value_bytes(argv[0]); dbda8d6ce9 2007-07-21 drh: z = sqlite3_value_blob(argv[0]); dbda8d6ce9 2007-07-21 drh: if( z==0 ) return; dbda8d6ce9 2007-07-21 drh: assert( len==sqlite3_value_bytes(argv[0]) ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: z = sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: if( z==0 ) return; dbda8d6ce9 2007-07-21 drh: len = 0; dbda8d6ce9 2007-07-21 drh: for(z2=z; *z2; len++){ dbda8d6ce9 2007-07-21 drh: SQLITE_SKIP_UTF8(z2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p1 = sqlite3_value_int(argv[1]); dbda8d6ce9 2007-07-21 drh: p2 = sqlite3_value_int(argv[2]); dbda8d6ce9 2007-07-21 drh: if( p1<0 ){ dbda8d6ce9 2007-07-21 drh: p1 += len; dbda8d6ce9 2007-07-21 drh: if( p1<0 ){ dbda8d6ce9 2007-07-21 drh: p2 += p1; dbda8d6ce9 2007-07-21 drh: p1 = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( p1>0 ){ dbda8d6ce9 2007-07-21 drh: p1--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p1+p2>len ){ dbda8d6ce9 2007-07-21 drh: p2 = len-p1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p0type!=SQLITE_BLOB ){ dbda8d6ce9 2007-07-21 drh: while( *z && p1 ){ dbda8d6ce9 2007-07-21 drh: SQLITE_SKIP_UTF8(z); dbda8d6ce9 2007-07-21 drh: p1--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(z2=z; *z2 && p2; p2--){ dbda8d6ce9 2007-07-21 drh: SQLITE_SKIP_UTF8(z2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, (char*)z, z2-z, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( p2<0 ) p2 = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_result_blob(context, (char*)&z[p1], p2, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the round() function dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: int n = 0; dbda8d6ce9 2007-07-21 drh: double r; dbda8d6ce9 2007-07-21 drh: char zBuf[500]; /* larger than the %f representation of the largest double */ dbda8d6ce9 2007-07-21 drh: assert( argc==1 || argc==2 ); dbda8d6ce9 2007-07-21 drh: if( argc==2 ){ dbda8d6ce9 2007-07-21 drh: if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return; dbda8d6ce9 2007-07-21 drh: n = sqlite3_value_int(argv[1]); dbda8d6ce9 2007-07-21 drh: if( n>30 ) n = 30; dbda8d6ce9 2007-07-21 drh: if( n<0 ) n = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; dbda8d6ce9 2007-07-21 drh: r = sqlite3_value_double(argv[0]); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r); dbda8d6ce9 2007-07-21 drh: sqlite3AtoF(zBuf, &r); dbda8d6ce9 2007-07-21 drh: sqlite3_result_double(context, r); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Allocate nByte bytes of space using sqlite3_malloc(). If the c287665ba8 2007-09-14 drh: ** allocation fails, call sqlite3_result_error_nomem() to notify c287665ba8 2007-09-14 drh: ** the database handle that malloc() has failed. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static void *contextMalloc(sqlite3_context *context, int nByte){ c287665ba8 2007-09-14 drh: char *z = sqlite3_malloc(nByte); c287665ba8 2007-09-14 drh: if( !z && nByte>0 ){ c287665ba8 2007-09-14 drh: sqlite3_result_error_nomem(context); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return z; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the upper() and lower() SQL functions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: char *z1; dbda8d6ce9 2007-07-21 drh: const char *z2; dbda8d6ce9 2007-07-21 drh: int i, n; dbda8d6ce9 2007-07-21 drh: if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; dbda8d6ce9 2007-07-21 drh: z2 = (char*)sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: n = sqlite3_value_bytes(argv[0]); dbda8d6ce9 2007-07-21 drh: /* Verify that the call to _bytes() does not invalidate the _text() pointer */ dbda8d6ce9 2007-07-21 drh: assert( z2==(char*)sqlite3_value_text(argv[0]) ); dbda8d6ce9 2007-07-21 drh: if( z2 ){ c287665ba8 2007-09-14 drh: z1 = contextMalloc(context, n+1); dbda8d6ce9 2007-07-21 drh: if( z1 ){ dbda8d6ce9 2007-07-21 drh: memcpy(z1, z2, n+1); dbda8d6ce9 2007-07-21 drh: for(i=0; z1[i]; i++){ dbda8d6ce9 2007-07-21 drh: z1[i] = toupper(z1[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, z1, -1, sqlite3_free); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: char *z1; dbda8d6ce9 2007-07-21 drh: const char *z2; dbda8d6ce9 2007-07-21 drh: int i, n; dbda8d6ce9 2007-07-21 drh: if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; dbda8d6ce9 2007-07-21 drh: z2 = (char*)sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: n = sqlite3_value_bytes(argv[0]); dbda8d6ce9 2007-07-21 drh: /* Verify that the call to _bytes() does not invalidate the _text() pointer */ dbda8d6ce9 2007-07-21 drh: assert( z2==(char*)sqlite3_value_text(argv[0]) ); dbda8d6ce9 2007-07-21 drh: if( z2 ){ c287665ba8 2007-09-14 drh: z1 = contextMalloc(context, n+1); dbda8d6ce9 2007-07-21 drh: if( z1 ){ dbda8d6ce9 2007-07-21 drh: memcpy(z1, z2, n+1); dbda8d6ce9 2007-07-21 drh: for(i=0; z1[i]; i++){ dbda8d6ce9 2007-07-21 drh: z1[i] = tolower(z1[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, z1, -1, sqlite3_free); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the IFNULL(), NVL(), and COALESCE() functions. dbda8d6ce9 2007-07-21 drh: ** All three do the same thing. They return the first non-NULL dbda8d6ce9 2007-07-21 drh: ** argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void ifnullFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<argc; i++){ dbda8d6ce9 2007-07-21 drh: if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_value(context, argv[i]); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of random(). Return a random integer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void randomFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite_int64 r; dbda8d6ce9 2007-07-21 drh: sqlite3Randomness(sizeof(r), &r); dbda8d6ce9 2007-07-21 drh: if( (r<<1)==0 ) r = 0; /* Prevent 0x8000.... as the result so that we */ dbda8d6ce9 2007-07-21 drh: /* can always do abs() of the result */ dbda8d6ce9 2007-07-21 drh: sqlite3_result_int64(context, r); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of randomblob(N). Return a random blob dbda8d6ce9 2007-07-21 drh: ** that is N bytes long. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void randomBlob( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: unsigned char *p; dbda8d6ce9 2007-07-21 drh: assert( argc==1 ); dbda8d6ce9 2007-07-21 drh: n = sqlite3_value_int(argv[0]); dbda8d6ce9 2007-07-21 drh: if( n<1 ){ dbda8d6ce9 2007-07-21 drh: n = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( n>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error_toobig(context); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: p = contextMalloc(context, n); dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: sqlite3Randomness(n, p); c287665ba8 2007-09-14 drh: sqlite3_result_blob(context, (char*)p, n, sqlite3_free); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the last_insert_rowid() SQL function. The return dbda8d6ce9 2007-07-21 drh: ** value is the same as the sqlite3_last_insert_rowid() API function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void last_insert_rowid( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int arg, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the changes() SQL function. The return value is the dbda8d6ce9 2007-07-21 drh: ** same as the sqlite3_changes() API function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void changes( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int arg, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: sqlite3_result_int(context, sqlite3_changes(db)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the total_changes() SQL function. The return value is dbda8d6ce9 2007-07-21 drh: ** the same as the sqlite3_total_changes() API function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void total_changes( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int arg, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: sqlite3_result_int(context, sqlite3_total_changes(db)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A structure defining how to do GLOB-style comparisons. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct compareInfo { dbda8d6ce9 2007-07-21 drh: u8 matchAll; dbda8d6ce9 2007-07-21 drh: u8 matchOne; dbda8d6ce9 2007-07-21 drh: u8 matchSet; dbda8d6ce9 2007-07-21 drh: u8 noCase; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: static const struct compareInfo globInfo = { '*', '?', '[', 0 }; dbda8d6ce9 2007-07-21 drh: /* The correct SQL-92 behavior is for the LIKE operator to ignore dbda8d6ce9 2007-07-21 drh: ** case. Thus 'a' LIKE 'A' would be true. */ dbda8d6ce9 2007-07-21 drh: static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 }; dbda8d6ce9 2007-07-21 drh: /* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator dbda8d6ce9 2007-07-21 drh: ** is case sensitive causing 'a' LIKE 'A' to be false */ dbda8d6ce9 2007-07-21 drh: static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compare two UTF-8 strings for equality where the first string can dbda8d6ce9 2007-07-21 drh: ** potentially be a "glob" expression. Return true (1) if they dbda8d6ce9 2007-07-21 drh: ** are the same and false (0) if they are different. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Globbing rules: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** '*' Matches any sequence of zero or more characters. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** '?' Matches exactly one character. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** [...] Matches one character from the enclosed list of dbda8d6ce9 2007-07-21 drh: ** characters. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** [^...] Matches one character not in the enclosed list. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** With the [...] and [^...] matching, a ']' character can be included dbda8d6ce9 2007-07-21 drh: ** in the list by making it the first character after '[' or '^'. A dbda8d6ce9 2007-07-21 drh: ** range of characters can be specified using '-'. Example: dbda8d6ce9 2007-07-21 drh: ** "[a-z]" matches any single lower-case letter. To match a '-', make dbda8d6ce9 2007-07-21 drh: ** it the last character in the list. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is usually quick, but can be N**2 in the worst case. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Hints: to match '*' or '?', put them in "[]". Like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** abc[*]xyz Matches "abc*xyz" only dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int patternCompare( dbda8d6ce9 2007-07-21 drh: const u8 *zPattern, /* The glob pattern */ dbda8d6ce9 2007-07-21 drh: const u8 *zString, /* The string to compare against the glob */ dbda8d6ce9 2007-07-21 drh: const struct compareInfo *pInfo, /* Information about how to do the compare */ dbda8d6ce9 2007-07-21 drh: const int esc /* The escape character */ dbda8d6ce9 2007-07-21 drh: ){ d8590e093f 2007-07-24 drh: int c, c2; dbda8d6ce9 2007-07-21 drh: int invert; dbda8d6ce9 2007-07-21 drh: int seen; dbda8d6ce9 2007-07-21 drh: u8 matchOne = pInfo->matchOne; dbda8d6ce9 2007-07-21 drh: u8 matchAll = pInfo->matchAll; dbda8d6ce9 2007-07-21 drh: u8 matchSet = pInfo->matchSet; dbda8d6ce9 2007-07-21 drh: u8 noCase = pInfo->noCase; dbda8d6ce9 2007-07-21 drh: int prevEscape = 0; /* True if the previous character was 'escape' */ dbda8d6ce9 2007-07-21 drh: d8590e093f 2007-07-24 drh: while( (c = sqlite3Utf8Read(zPattern,0,&zPattern))!=0 ){ dbda8d6ce9 2007-07-21 drh: if( !prevEscape && c==matchAll ){ d8590e093f 2007-07-24 drh: while( (c=sqlite3Utf8Read(zPattern,0,&zPattern)) == matchAll d8590e093f 2007-07-24 drh: || c == matchOne ){ d8590e093f 2007-07-24 drh: if( c==matchOne && sqlite3Utf8Read(zString, 0, &zString)==0 ){ d8590e093f 2007-07-24 drh: return 0; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: if( c==0 ){ d8590e093f 2007-07-24 drh: return 1; d8590e093f 2007-07-24 drh: }else if( c==esc ){ d8590e093f 2007-07-24 drh: c = sqlite3Utf8Read(zPattern, 0, &zPattern); d8590e093f 2007-07-24 drh: if( c==0 ){ d8590e093f 2007-07-24 drh: return 0; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: }else if( c==matchSet ){ d8590e093f 2007-07-24 drh: assert( esc==0 ); /* This is GLOB, not LIKE */ d8590e093f 2007-07-24 drh: assert( matchSet<0x80 ); /* '[' is a single-byte character */ d8590e093f 2007-07-24 drh: while( *zString && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ dbda8d6ce9 2007-07-21 drh: SQLITE_SKIP_UTF8(zString); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return *zString!=0; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: while( (c2 = sqlite3Utf8Read(zString,0,&zString))!=0 ){ d8590e093f 2007-07-24 drh: if( noCase ){ d8590e093f 2007-07-24 drh: c2 = c2<0x80 ? sqlite3UpperToLower[c2] : c2; d8590e093f 2007-07-24 drh: c = c<0x80 ? sqlite3UpperToLower[c] : c; d8590e093f 2007-07-24 drh: while( c2 != 0 && c2 != c ){ d8590e093f 2007-07-24 drh: c2 = sqlite3Utf8Read(zString, 0, &zString); d8590e093f 2007-07-24 drh: if( c2<0x80 ) c2 = sqlite3UpperToLower[c2]; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: }else{ d8590e093f 2007-07-24 drh: while( c2 != 0 && c2 != c ){ d8590e093f 2007-07-24 drh: c2 = sqlite3Utf8Read(zString, 0, &zString); d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: if( c2==0 ) return 0; d8590e093f 2007-07-24 drh: if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: return 0; d8590e093f 2007-07-24 drh: }else if( !prevEscape && c==matchOne ){ d8590e093f 2007-07-24 drh: if( sqlite3Utf8Read(zString, 0, &zString)==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( c==matchSet ){ dbda8d6ce9 2007-07-21 drh: int prior_c = 0; dbda8d6ce9 2007-07-21 drh: assert( esc==0 ); /* This only occurs for GLOB, not LIKE */ dbda8d6ce9 2007-07-21 drh: seen = 0; dbda8d6ce9 2007-07-21 drh: invert = 0; d8590e093f 2007-07-24 drh: c = sqlite3Utf8Read(zString, 0, &zString); dbda8d6ce9 2007-07-21 drh: if( c==0 ) return 0; d8590e093f 2007-07-24 drh: c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); d8590e093f 2007-07-24 drh: if( c2=='^' ){ d8590e093f 2007-07-24 drh: invert = 1; d8590e093f 2007-07-24 drh: c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); d8590e093f 2007-07-24 drh: } dbda8d6ce9 2007-07-21 drh: if( c2==']' ){ dbda8d6ce9 2007-07-21 drh: if( c==']' ) seen = 1; d8590e093f 2007-07-24 drh: c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: while( c2 && c2!=']' ){ d8590e093f 2007-07-24 drh: if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ d8590e093f 2007-07-24 drh: c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); dbda8d6ce9 2007-07-21 drh: if( c>=prior_c && c<=c2 ) seen = 1; dbda8d6ce9 2007-07-21 drh: prior_c = 0; d8590e093f 2007-07-24 drh: }else{ d8590e093f 2007-07-24 drh: if( c==c2 ){ d8590e093f 2007-07-24 drh: seen = 1; d8590e093f 2007-07-24 drh: } dbda8d6ce9 2007-07-21 drh: prior_c = c2; dbda8d6ce9 2007-07-21 drh: } d8590e093f 2007-07-24 drh: c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: if( c2==0 || (seen ^ invert)==0 ){ d8590e093f 2007-07-24 drh: return 0; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: }else if( esc==c && !prevEscape ){ dbda8d6ce9 2007-07-21 drh: prevEscape = 1; d8590e093f 2007-07-24 drh: }else{ d8590e093f 2007-07-24 drh: c2 = sqlite3Utf8Read(zString, 0, &zString); dbda8d6ce9 2007-07-21 drh: if( noCase ){ d8590e093f 2007-07-24 drh: c = c<0x80 ? sqlite3UpperToLower[c] : c; d8590e093f 2007-07-24 drh: c2 = c2<0x80 ? sqlite3UpperToLower[c2] : c2; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: if( c!=c2 ){ d8590e093f 2007-07-24 drh: return 0; d8590e093f 2007-07-24 drh: } dbda8d6ce9 2007-07-21 drh: prevEscape = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return *zString==0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Count the number of times that the LIKE operator (or GLOB which is dbda8d6ce9 2007-07-21 drh: ** just a variation of LIKE) gets called. This is used for testing dbda8d6ce9 2007-07-21 drh: ** only. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_like_count = 0; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the like() SQL function. This function implements dbda8d6ce9 2007-07-21 drh: ** the build-in LIKE operator. The first argument to the function is the dbda8d6ce9 2007-07-21 drh: ** pattern and the second argument is the string. So, the SQL statements: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A LIKE B dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** is implemented as like(B,A). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This same function (with a different compareInfo structure) computes dbda8d6ce9 2007-07-21 drh: ** the GLOB operator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void likeFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const unsigned char *zA, *zB; dbda8d6ce9 2007-07-21 drh: int escape = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zB = sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: zA = sqlite3_value_text(argv[1]); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Limit the length of the LIKE or GLOB pattern to avoid problems dbda8d6ce9 2007-07-21 drh: ** of deep recursion and N*N behavior in patternCompare(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( argc==3 ){ dbda8d6ce9 2007-07-21 drh: /* The escape character string must consist of a single UTF-8 character. dbda8d6ce9 2007-07-21 drh: ** Otherwise, return an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: const unsigned char *zEsc = sqlite3_value_text(argv[2]); dbda8d6ce9 2007-07-21 drh: if( zEsc==0 ) return; dbda8d6ce9 2007-07-21 drh: if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context, dbda8d6ce9 2007-07-21 drh: "ESCAPE expression must be a single character", -1); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } d8590e093f 2007-07-24 drh: escape = sqlite3Utf8Read(zEsc, 0, &zEsc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zA && zB ){ dbda8d6ce9 2007-07-21 drh: struct compareInfo *pInfo = sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: sqlite3_like_count++; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the NULLIF(x,y) function. The result is the first dbda8d6ce9 2007-07-21 drh: ** argument if the arguments are different. The result is NULL if the dbda8d6ce9 2007-07-21 drh: ** arguments are equal to each other. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void nullifFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = sqlite3GetFuncCollSeq(context); dbda8d6ce9 2007-07-21 drh: if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_value(context, argv[0]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the VERSION(*) function. The result is the version dbda8d6ce9 2007-07-21 drh: ** of the SQLite library that is running. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void versionFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Array for converting from half-bytes (nybbles) into ASCII hex dbda8d6ce9 2007-07-21 drh: ** digits. */ dbda8d6ce9 2007-07-21 drh: static const char hexdigits[] = { dbda8d6ce9 2007-07-21 drh: '0', '1', '2', '3', '4', '5', '6', '7', dbda8d6ce9 2007-07-21 drh: '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** EXPERIMENTAL - This is not an official function. The interface may dbda8d6ce9 2007-07-21 drh: ** change. This function may disappear. Do not write code that depends dbda8d6ce9 2007-07-21 drh: ** on this function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Implementation of the QUOTE() function. This function takes a single dbda8d6ce9 2007-07-21 drh: ** argument. If the argument is numeric, the return value is the same as dbda8d6ce9 2007-07-21 drh: ** the argument. If the argument is NULL, the return value is the string dbda8d6ce9 2007-07-21 drh: ** "NULL". Otherwise, the argument is enclosed in single quotes with dbda8d6ce9 2007-07-21 drh: ** single-quote escapes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: if( argc<1 ) return; dbda8d6ce9 2007-07-21 drh: switch( sqlite3_value_type(argv[0]) ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_NULL: { dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case SQLITE_INTEGER: dbda8d6ce9 2007-07-21 drh: case SQLITE_FLOAT: { dbda8d6ce9 2007-07-21 drh: sqlite3_result_value(context, argv[0]); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case SQLITE_BLOB: { dbda8d6ce9 2007-07-21 drh: char *zText = 0; dbda8d6ce9 2007-07-21 drh: char const *zBlob = sqlite3_value_blob(argv[0]); dbda8d6ce9 2007-07-21 drh: int nBlob = sqlite3_value_bytes(argv[0]); dbda8d6ce9 2007-07-21 drh: assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( 2*nBlob+4>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error_toobig(context); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: zText = (char *)contextMalloc(context, (2*nBlob)+4); c287665ba8 2007-09-14 drh: if( zText ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nBlob; i++){ dbda8d6ce9 2007-07-21 drh: zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F]; dbda8d6ce9 2007-07-21 drh: zText[(i*2)+3] = hexdigits[(zBlob[i])&0x0F]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zText[(nBlob*2)+2] = '\''; dbda8d6ce9 2007-07-21 drh: zText[(nBlob*2)+3] = '\0'; dbda8d6ce9 2007-07-21 drh: zText[0] = 'X'; dbda8d6ce9 2007-07-21 drh: zText[1] = '\''; dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); c287665ba8 2007-09-14 drh: sqlite3_free(zText); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case SQLITE_TEXT: { dbda8d6ce9 2007-07-21 drh: int i,j; dbda8d6ce9 2007-07-21 drh: u64 n; dbda8d6ce9 2007-07-21 drh: const unsigned char *zArg = sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( zArg==0 ) return; dbda8d6ce9 2007-07-21 drh: for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; } dbda8d6ce9 2007-07-21 drh: if( i+n+3>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error_toobig(context); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: z = contextMalloc(context, i+n+3); c287665ba8 2007-09-14 drh: if( z ){ c287665ba8 2007-09-14 drh: z[0] = '\''; c287665ba8 2007-09-14 drh: for(i=0, j=1; zArg[i]; i++){ c287665ba8 2007-09-14 drh: z[j++] = zArg[i]; c287665ba8 2007-09-14 drh: if( zArg[i]=='\'' ){ c287665ba8 2007-09-14 drh: z[j++] = '\''; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: z[j++] = '\''; c287665ba8 2007-09-14 drh: z[j] = 0; c287665ba8 2007-09-14 drh: sqlite3_result_text(context, z, j, sqlite3_free); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The hex() function. Interpret the argument as a blob. Return dbda8d6ce9 2007-07-21 drh: ** a hexadecimal rendering as text. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void hexFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i, n; dbda8d6ce9 2007-07-21 drh: const unsigned char *pBlob; dbda8d6ce9 2007-07-21 drh: char *zHex, *z; dbda8d6ce9 2007-07-21 drh: assert( argc==1 ); dbda8d6ce9 2007-07-21 drh: pBlob = sqlite3_value_blob(argv[0]); dbda8d6ce9 2007-07-21 drh: n = sqlite3_value_bytes(argv[0]); dbda8d6ce9 2007-07-21 drh: if( n*2+1>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error_toobig(context); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ c287665ba8 2007-09-14 drh: z = zHex = contextMalloc(context, n*2 + 1); c287665ba8 2007-09-14 drh: if( zHex ){ c287665ba8 2007-09-14 drh: for(i=0; i<n; i++, pBlob++){ c287665ba8 2007-09-14 drh: unsigned char c = *pBlob; c287665ba8 2007-09-14 drh: *(z++) = hexdigits[(c>>4)&0xf]; c287665ba8 2007-09-14 drh: *(z++) = hexdigits[c&0xf]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: *z = 0; c287665ba8 2007-09-14 drh: sqlite3_result_text(context, zHex, n*2, sqlite3_free); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The zeroblob(N) function returns a zero-filled blob of size N bytes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void zeroblobFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: i64 n; dbda8d6ce9 2007-07-21 drh: assert( argc==1 ); dbda8d6ce9 2007-07-21 drh: n = sqlite3_value_int64(argv[0]); dbda8d6ce9 2007-07-21 drh: if( n>SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error_toobig(context); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_result_zeroblob(context, n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The replace() function. Three arguments are all strings: call dbda8d6ce9 2007-07-21 drh: ** them A, B, and C. The result is also a string which is derived dbda8d6ce9 2007-07-21 drh: ** from A by replacing every occurance of B with C. The match dbda8d6ce9 2007-07-21 drh: ** must be exact. Collating sequences are not used. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void replaceFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const unsigned char *zStr; /* The input string A */ dbda8d6ce9 2007-07-21 drh: const unsigned char *zPattern; /* The pattern string B */ dbda8d6ce9 2007-07-21 drh: const unsigned char *zRep; /* The replacement string C */ dbda8d6ce9 2007-07-21 drh: unsigned char *zOut; /* The output */ dbda8d6ce9 2007-07-21 drh: int nStr; /* Size of zStr */ dbda8d6ce9 2007-07-21 drh: int nPattern; /* Size of zPattern */ dbda8d6ce9 2007-07-21 drh: int nRep; /* Size of zRep */ dbda8d6ce9 2007-07-21 drh: i64 nOut; /* Maximum size of zOut */ dbda8d6ce9 2007-07-21 drh: int loopLimit; /* Last zStr[] that might match zPattern[] */ dbda8d6ce9 2007-07-21 drh: int i, j; /* Loop counters */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( argc==3 ); dbda8d6ce9 2007-07-21 drh: zStr = sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: if( zStr==0 ) return; dbda8d6ce9 2007-07-21 drh: nStr = sqlite3_value_bytes(argv[0]); dbda8d6ce9 2007-07-21 drh: assert( zStr==sqlite3_value_text(argv[0]) ); /* No encoding change */ dbda8d6ce9 2007-07-21 drh: zPattern = sqlite3_value_text(argv[1]); dbda8d6ce9 2007-07-21 drh: if( zPattern==0 || zPattern[0]==0 ) return; dbda8d6ce9 2007-07-21 drh: nPattern = sqlite3_value_bytes(argv[1]); dbda8d6ce9 2007-07-21 drh: assert( zPattern==sqlite3_value_text(argv[1]) ); /* No encoding change */ dbda8d6ce9 2007-07-21 drh: zRep = sqlite3_value_text(argv[2]); dbda8d6ce9 2007-07-21 drh: if( zRep==0 ) return; dbda8d6ce9 2007-07-21 drh: nRep = sqlite3_value_bytes(argv[2]); dbda8d6ce9 2007-07-21 drh: assert( zRep==sqlite3_value_text(argv[2]) ); dbda8d6ce9 2007-07-21 drh: nOut = nStr + 1; dbda8d6ce9 2007-07-21 drh: assert( nOut<SQLITE_MAX_LENGTH ); c287665ba8 2007-09-14 drh: zOut = contextMalloc(context, (int)nOut); dbda8d6ce9 2007-07-21 drh: if( zOut==0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: loopLimit = nStr - nPattern; dbda8d6ce9 2007-07-21 drh: for(i=j=0; i<=loopLimit; i++){ dbda8d6ce9 2007-07-21 drh: if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){ dbda8d6ce9 2007-07-21 drh: zOut[j++] = zStr[i]; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: u8 *zOld; dbda8d6ce9 2007-07-21 drh: nOut += nRep - nPattern; dbda8d6ce9 2007-07-21 drh: if( nOut>=SQLITE_MAX_LENGTH ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error_toobig(context); dbda8d6ce9 2007-07-21 drh: sqlite3_free(zOut); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: zOld = zOut; dbda8d6ce9 2007-07-21 drh: zOut = sqlite3_realloc(zOut, (int)nOut); dbda8d6ce9 2007-07-21 drh: if( zOut==0 ){ c287665ba8 2007-09-14 drh: sqlite3_result_error_nomem(context); c287665ba8 2007-09-14 drh: sqlite3_free(zOld); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(&zOut[j], zRep, nRep); dbda8d6ce9 2007-07-21 drh: j += nRep; dbda8d6ce9 2007-07-21 drh: i += nPattern-1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( j+nStr-i+1==nOut ); dbda8d6ce9 2007-07-21 drh: memcpy(&zOut[j], &zStr[i], nStr-i); dbda8d6ce9 2007-07-21 drh: j += nStr - i; dbda8d6ce9 2007-07-21 drh: assert( j<=nOut ); dbda8d6ce9 2007-07-21 drh: zOut[j] = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, (char*)zOut, j, sqlite3_free); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Implementation of the TRIM(), LTRIM(), and RTRIM() functions. dbda8d6ce9 2007-07-21 drh: ** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void trimFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const unsigned char *zIn; /* Input string */ dbda8d6ce9 2007-07-21 drh: const unsigned char *zCharSet; /* Set of characters to trim */ dbda8d6ce9 2007-07-21 drh: int nIn; /* Number of bytes in input */ dbda8d6ce9 2007-07-21 drh: int flags; /* 1: trimleft 2: trimright 3: trim */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: unsigned char *aLen; /* Length of each character in zCharSet */ dbda8d6ce9 2007-07-21 drh: const unsigned char **azChar; /* Individual characters in zCharSet */ dbda8d6ce9 2007-07-21 drh: int nChar; /* Number of characters in zCharSet */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zIn = sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: if( zIn==0 ) return; dbda8d6ce9 2007-07-21 drh: nIn = sqlite3_value_bytes(argv[0]); dbda8d6ce9 2007-07-21 drh: assert( zIn==sqlite3_value_text(argv[0]) ); dbda8d6ce9 2007-07-21 drh: if( argc==1 ){ dbda8d6ce9 2007-07-21 drh: static const unsigned char lenOne[] = { 1 }; dbda8d6ce9 2007-07-21 drh: static const unsigned char *azOne[] = { (u8*)" " }; dbda8d6ce9 2007-07-21 drh: nChar = 1; dbda8d6ce9 2007-07-21 drh: aLen = (u8*)lenOne; dbda8d6ce9 2007-07-21 drh: azChar = azOne; dbda8d6ce9 2007-07-21 drh: zCharSet = 0; dbda8d6ce9 2007-07-21 drh: }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: const unsigned char *z; dbda8d6ce9 2007-07-21 drh: for(z=zCharSet, nChar=0; *z; nChar++){ dbda8d6ce9 2007-07-21 drh: SQLITE_SKIP_UTF8(z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nChar>0 ){ c287665ba8 2007-09-14 drh: azChar = contextMalloc(context, nChar*(sizeof(char*)+1)); dbda8d6ce9 2007-07-21 drh: if( azChar==0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: aLen = (unsigned char*)&azChar[nChar]; dbda8d6ce9 2007-07-21 drh: for(z=zCharSet, nChar=0; *z; nChar++){ dbda8d6ce9 2007-07-21 drh: azChar[nChar] = z; dbda8d6ce9 2007-07-21 drh: SQLITE_SKIP_UTF8(z); dbda8d6ce9 2007-07-21 drh: aLen[nChar] = z - azChar[nChar]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nChar>0 ){ dbda8d6ce9 2007-07-21 drh: flags = (int)sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: if( flags & 1 ){ dbda8d6ce9 2007-07-21 drh: while( nIn>0 ){ dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nChar; i++){ dbda8d6ce9 2007-07-21 drh: len = aLen[i]; dbda8d6ce9 2007-07-21 drh: if( memcmp(zIn, azChar[i], len)==0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i>=nChar ) break; dbda8d6ce9 2007-07-21 drh: zIn += len; dbda8d6ce9 2007-07-21 drh: nIn -= len; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( flags & 2 ){ dbda8d6ce9 2007-07-21 drh: while( nIn>0 ){ dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nChar; i++){ dbda8d6ce9 2007-07-21 drh: len = aLen[i]; dbda8d6ce9 2007-07-21 drh: if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i>=nChar ) break; dbda8d6ce9 2007-07-21 drh: nIn -= len; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zCharSet ){ dbda8d6ce9 2007-07-21 drh: sqlite3_free(azChar); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SOUNDEX dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the soundex encoding of a word. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void soundexFunc( dbda8d6ce9 2007-07-21 drh: sqlite3_context *context, dbda8d6ce9 2007-07-21 drh: int argc, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: char zResult[8]; dbda8d6ce9 2007-07-21 drh: const u8 *zIn; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: static const unsigned char iCode[] = { dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, dbda8d6ce9 2007-07-21 drh: 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, dbda8d6ce9 2007-07-21 drh: 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: assert( argc==1 ); dbda8d6ce9 2007-07-21 drh: zIn = (u8*)sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: if( zIn==0 ) zIn = (u8*)""; dbda8d6ce9 2007-07-21 drh: for(i=0; zIn[i] && !isalpha(zIn[i]); i++){} dbda8d6ce9 2007-07-21 drh: if( zIn[i] ){ dbda8d6ce9 2007-07-21 drh: u8 prevcode = iCode[zIn[i]&0x7f]; dbda8d6ce9 2007-07-21 drh: zResult[0] = toupper(zIn[i]); dbda8d6ce9 2007-07-21 drh: for(j=1; j<4 && zIn[i]; i++){ dbda8d6ce9 2007-07-21 drh: int code = iCode[zIn[i]&0x7f]; dbda8d6ce9 2007-07-21 drh: if( code>0 ){ dbda8d6ce9 2007-07-21 drh: if( code!=prevcode ){ dbda8d6ce9 2007-07-21 drh: prevcode = code; dbda8d6ce9 2007-07-21 drh: zResult[j++] = code + '0'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: prevcode = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( j<4 ){ dbda8d6ce9 2007-07-21 drh: zResult[j++] = '0'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zResult[j] = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, "?000", 4, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_LOAD_EXTENSION dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A function that loads a shared-library extension then returns NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: const char *zFile = (const char *)sqlite3_value_text(argv[0]); dbda8d6ce9 2007-07-21 drh: const char *zProc; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = sqlite3_user_data(context); dbda8d6ce9 2007-07-21 drh: char *zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( argc==2 ){ dbda8d6ce9 2007-07-21 drh: zProc = (const char *)sqlite3_value_text(argv[1]); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zProc = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zFile && sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context, zErrMsg, -1); dbda8d6ce9 2007-07-21 drh: sqlite3_free(zErrMsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function generates a string of random characters. Used for dbda8d6ce9 2007-07-21 drh: ** generating test data. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: static const unsigned char zSrc[] = dbda8d6ce9 2007-07-21 drh: "abcdefghijklmnopqrstuvwxyz" dbda8d6ce9 2007-07-21 drh: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" dbda8d6ce9 2007-07-21 drh: "0123456789" dbda8d6ce9 2007-07-21 drh: ".-!,:*^+=_|?/<> "; dbda8d6ce9 2007-07-21 drh: int iMin, iMax, n, r, i; dbda8d6ce9 2007-07-21 drh: unsigned char zBuf[1000]; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* It used to be possible to call randstr() with any number of arguments, c287665ba8 2007-09-14 drh: ** but now it is registered with SQLite as requiring exactly 2. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: assert(argc==2); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: iMin = sqlite3_value_int(argv[0]); c287665ba8 2007-09-14 drh: if( iMin<0 ) iMin = 0; c287665ba8 2007-09-14 drh: if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1; c287665ba8 2007-09-14 drh: iMax = sqlite3_value_int(argv[1]); c287665ba8 2007-09-14 drh: if( iMax<iMin ) iMax = iMin; c287665ba8 2007-09-14 drh: if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1; dbda8d6ce9 2007-07-21 drh: n = iMin; dbda8d6ce9 2007-07-21 drh: if( iMax>iMin ){ dbda8d6ce9 2007-07-21 drh: sqlite3Randomness(sizeof(r), &r); dbda8d6ce9 2007-07-21 drh: r &= 0x7fffffff; dbda8d6ce9 2007-07-21 drh: n += r%(iMax + 1 - iMin); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( n<sizeof(zBuf) ); dbda8d6ce9 2007-07-21 drh: sqlite3Randomness(n, zBuf); dbda8d6ce9 2007-07-21 drh: for(i=0; i<n; i++){ dbda8d6ce9 2007-07-21 drh: zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zBuf[n] = 0; dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(context, (char*)zBuf, n, SQLITE_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_TEST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following two SQL functions are used to test returning a text dbda8d6ce9 2007-07-21 drh: ** result with a destructor. Function 'test_destructor' takes one argument dbda8d6ce9 2007-07-21 drh: ** and returns the same argument interpreted as TEXT. A destructor is dbda8d6ce9 2007-07-21 drh: ** passed with the sqlite3_result_text() call. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SQL function 'test_destructor_count' returns the number of outstanding dbda8d6ce9 2007-07-21 drh: ** allocations made by 'test_destructor'; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** WARNING: Not threadsafe. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int test_destructor_count_var = 0; dbda8d6ce9 2007-07-21 drh: static void destructor(void *p){ dbda8d6ce9 2007-07-21 drh: char *zVal = (char *)p; dbda8d6ce9 2007-07-21 drh: assert(zVal); dbda8d6ce9 2007-07-21 drh: zVal--; c287665ba8 2007-09-14 drh: sqlite3_free(zVal); dbda8d6ce9 2007-07-21 drh: test_destructor_count_var--; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void test_destructor( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: char *zVal; dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = sqlite3_user_data(pCtx); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: test_destructor_count_var++; dbda8d6ce9 2007-07-21 drh: assert( nArg==1 ); dbda8d6ce9 2007-07-21 drh: if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; dbda8d6ce9 2007-07-21 drh: len = sqlite3ValueBytes(argv[0], ENC(db)); c287665ba8 2007-09-14 drh: zVal = contextMalloc(pCtx, len+3); c287665ba8 2007-09-14 drh: if( !zVal ){ c287665ba8 2007-09-14 drh: return; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: zVal[len+1] = 0; c287665ba8 2007-09-14 drh: zVal[len+2] = 0; dbda8d6ce9 2007-07-21 drh: zVal++; dbda8d6ce9 2007-07-21 drh: memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len); dbda8d6ce9 2007-07-21 drh: if( ENC(db)==SQLITE_UTF8 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(pCtx, zVal, -1, destructor); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: }else if( ENC(db)==SQLITE_UTF16LE ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_text16le(pCtx, zVal, -1, destructor); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_result_text16be(pCtx, zVal, -1, destructor); dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void test_destructor_count( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_int(pCtx, test_destructor_count_var); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_TEST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata() dbda8d6ce9 2007-07-21 drh: ** interface. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The test_auxdata() SQL function attempts to register each of its arguments dbda8d6ce9 2007-07-21 drh: ** as auxiliary data. If there are no prior registrations of aux data for dbda8d6ce9 2007-07-21 drh: ** that argument (meaning the argument is not a constant or this is its first dbda8d6ce9 2007-07-21 drh: ** call) then the result for that argument is 0. If there is a prior dbda8d6ce9 2007-07-21 drh: ** registration, the result for that argument is 1. The overall result dbda8d6ce9 2007-07-21 drh: ** is the individual argument results separated by spaces. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static void free_test_auxdata(void *p) {sqlite3_free(p);} dbda8d6ce9 2007-07-21 drh: static void test_auxdata( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; c287665ba8 2007-09-14 drh: char *zRet = contextMalloc(pCtx, nArg*2); dbda8d6ce9 2007-07-21 drh: if( !zRet ) return; c287665ba8 2007-09-14 drh: memset(zRet, 0, nArg*2); dbda8d6ce9 2007-07-21 drh: for(i=0; i<nArg; i++){ dbda8d6ce9 2007-07-21 drh: char const *z = (char*)sqlite3_value_text(argv[i]); dbda8d6ce9 2007-07-21 drh: if( z ){ dbda8d6ce9 2007-07-21 drh: char *zAux = sqlite3_get_auxdata(pCtx, i); dbda8d6ce9 2007-07-21 drh: if( zAux ){ dbda8d6ce9 2007-07-21 drh: zRet[i*2] = '1'; dbda8d6ce9 2007-07-21 drh: if( strcmp(zAux, z) ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(pCtx, "Auxilary data corruption", -1); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: }else { dbda8d6ce9 2007-07-21 drh: zRet[i*2] = '0'; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: zAux = contextMalloc(pCtx, strlen(z)+1); c287665ba8 2007-09-14 drh: if( zAux ){ c287665ba8 2007-09-14 drh: strcpy(zAux, z); dbda8d6ce9 2007-07-21 drh: sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zRet[i*2+1] = ' '; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_result_text(pCtx, zRet, 2*nArg-1, free_test_auxdata); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_TEST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** A function to test error reporting from user functions. This function dbda8d6ce9 2007-07-21 drh: ** returns a copy of it's first argument as an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void test_error( dbda8d6ce9 2007-07-21 drh: sqlite3_context *pCtx, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: sqlite3_value **argv dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(pCtx, (char*)sqlite3_value_text(argv[0]), 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_TEST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure holds the context of a dbda8d6ce9 2007-07-21 drh: ** sum() or avg() aggregate computation. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct SumCtx SumCtx; dbda8d6ce9 2007-07-21 drh: struct SumCtx { dbda8d6ce9 2007-07-21 drh: double rSum; /* Floating point sum */ dbda8d6ce9 2007-07-21 drh: i64 iSum; /* Integer sum */ dbda8d6ce9 2007-07-21 drh: i64 cnt; /* Number of elements summed */ dbda8d6ce9 2007-07-21 drh: u8 overflow; /* True if integer overflow seen */ dbda8d6ce9 2007-07-21 drh: u8 approx; /* True if non-integer value was input to the sum */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Routines used to compute the sum, average, and total. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The SUM() function follows the (broken) SQL standard which means dbda8d6ce9 2007-07-21 drh: ** that it returns NULL if it sums over no inputs. TOTAL returns dbda8d6ce9 2007-07-21 drh: ** 0.0 in that case. In addition, TOTAL always returns a float where dbda8d6ce9 2007-07-21 drh: ** SUM might return an integer if it never encounters a floating point dbda8d6ce9 2007-07-21 drh: ** value. TOTAL never fails, but SUM might through an exception if dbda8d6ce9 2007-07-21 drh: ** it overflows an integer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: SumCtx *p; dbda8d6ce9 2007-07-21 drh: int type; dbda8d6ce9 2007-07-21 drh: assert( argc==1 ); dbda8d6ce9 2007-07-21 drh: p = sqlite3_aggregate_context(context, sizeof(*p)); dbda8d6ce9 2007-07-21 drh: type = sqlite3_value_numeric_type(argv[0]); dbda8d6ce9 2007-07-21 drh: if( p && type!=SQLITE_NULL ){ dbda8d6ce9 2007-07-21 drh: p->cnt++; dbda8d6ce9 2007-07-21 drh: if( type==SQLITE_INTEGER ){ dbda8d6ce9 2007-07-21 drh: i64 v = sqlite3_value_int64(argv[0]); dbda8d6ce9 2007-07-21 drh: p->rSum += v; dbda8d6ce9 2007-07-21 drh: if( (p->approx|p->overflow)==0 ){ dbda8d6ce9 2007-07-21 drh: i64 iNewSum = p->iSum + v; dbda8d6ce9 2007-07-21 drh: int s1 = p->iSum >> (sizeof(i64)*8-1); dbda8d6ce9 2007-07-21 drh: int s2 = v >> (sizeof(i64)*8-1); dbda8d6ce9 2007-07-21 drh: int s3 = iNewSum >> (sizeof(i64)*8-1); dbda8d6ce9 2007-07-21 drh: p->overflow = (s1&s2&~s3) | (~s1&~s2&s3); dbda8d6ce9 2007-07-21 drh: p->iSum = iNewSum; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: p->rSum += sqlite3_value_double(argv[0]); dbda8d6ce9 2007-07-21 drh: p->approx = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void sumFinalize(sqlite3_context *context){ dbda8d6ce9 2007-07-21 drh: SumCtx *p; dbda8d6ce9 2007-07-21 drh: p = sqlite3_aggregate_context(context, 0); dbda8d6ce9 2007-07-21 drh: if( p && p->cnt>0 ){ dbda8d6ce9 2007-07-21 drh: if( p->overflow ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_error(context,"integer overflow",-1); dbda8d6ce9 2007-07-21 drh: }else if( p->approx ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_double(context, p->rSum); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_result_int64(context, p->iSum); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void avgFinalize(sqlite3_context *context){ dbda8d6ce9 2007-07-21 drh: SumCtx *p; dbda8d6ce9 2007-07-21 drh: p = sqlite3_aggregate_context(context, 0); dbda8d6ce9 2007-07-21 drh: if( p && p->cnt>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_double(context, p->rSum/(double)p->cnt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void totalFinalize(sqlite3_context *context){ dbda8d6ce9 2007-07-21 drh: SumCtx *p; dbda8d6ce9 2007-07-21 drh: p = sqlite3_aggregate_context(context, 0); dbda8d6ce9 2007-07-21 drh: sqlite3_result_double(context, p ? p->rSum : 0.0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following structure keeps track of state information for the dbda8d6ce9 2007-07-21 drh: ** count() aggregate function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct CountCtx CountCtx; dbda8d6ce9 2007-07-21 drh: struct CountCtx { dbda8d6ce9 2007-07-21 drh: i64 n; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Routines to implement the count() aggregate function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: CountCtx *p; dbda8d6ce9 2007-07-21 drh: p = sqlite3_aggregate_context(context, sizeof(*p)); dbda8d6ce9 2007-07-21 drh: if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){ dbda8d6ce9 2007-07-21 drh: p->n++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void countFinalize(sqlite3_context *context){ dbda8d6ce9 2007-07-21 drh: CountCtx *p; dbda8d6ce9 2007-07-21 drh: p = sqlite3_aggregate_context(context, 0); dbda8d6ce9 2007-07-21 drh: sqlite3_result_int64(context, p ? p->n : 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Routines to implement min() and max() aggregate functions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv){ dbda8d6ce9 2007-07-21 drh: Mem *pArg = (Mem *)argv[0]; dbda8d6ce9 2007-07-21 drh: Mem *pBest; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; dbda8d6ce9 2007-07-21 drh: pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest)); dbda8d6ce9 2007-07-21 drh: if( !pBest ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pBest->flags ){ dbda8d6ce9 2007-07-21 drh: int max; dbda8d6ce9 2007-07-21 drh: int cmp; dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = sqlite3GetFuncCollSeq(context); dbda8d6ce9 2007-07-21 drh: /* This step function is used for both the min() and max() aggregates, dbda8d6ce9 2007-07-21 drh: ** the only difference between the two being that the sense of the dbda8d6ce9 2007-07-21 drh: ** comparison is inverted. For the max() aggregate, the dbda8d6ce9 2007-07-21 drh: ** sqlite3_user_data() function returns (void *)-1. For min() it dbda8d6ce9 2007-07-21 drh: ** returns (void *)db, where db is the sqlite3* database pointer. dbda8d6ce9 2007-07-21 drh: ** Therefore the next statement sets variable 'max' to 1 for the max() dbda8d6ce9 2007-07-21 drh: ** aggregate, or 0 for min(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: max = sqlite3_user_data(context)!=0; dbda8d6ce9 2007-07-21 drh: cmp = sqlite3MemCompare(pBest, pArg, pColl); dbda8d6ce9 2007-07-21 drh: if( (max && cmp<0) || (!max && cmp>0) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemCopy(pBest, pArg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemCopy(pBest, pArg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void minMaxFinalize(sqlite3_context *context){ dbda8d6ce9 2007-07-21 drh: sqlite3_value *pRes; dbda8d6ce9 2007-07-21 drh: pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0); dbda8d6ce9 2007-07-21 drh: if( pRes ){ dbda8d6ce9 2007-07-21 drh: if( pRes->flags ){ dbda8d6ce9 2007-07-21 drh: sqlite3_result_value(context, pRes); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeMemRelease(pRes); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function registered all of the above C functions as SQL dbda8d6ce9 2007-07-21 drh: ** functions. This should be the only routine in this file with dbda8d6ce9 2007-07-21 drh: ** external linkage. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: static const struct { dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: signed char nArg; dbda8d6ce9 2007-07-21 drh: u8 argType; /* ff: db 1: 0, 2: 1, 3: 2,... N: N-1. */ dbda8d6ce9 2007-07-21 drh: u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */ dbda8d6ce9 2007-07-21 drh: u8 needCollSeq; dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value **); dbda8d6ce9 2007-07-21 drh: } aFuncs[] = { dbda8d6ce9 2007-07-21 drh: { "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc }, dbda8d6ce9 2007-07-21 drh: { "min", 0, 0, SQLITE_UTF8, 1, 0 }, dbda8d6ce9 2007-07-21 drh: { "max", -1, 1, SQLITE_UTF8, 1, minmaxFunc }, dbda8d6ce9 2007-07-21 drh: { "max", 0, 1, SQLITE_UTF8, 1, 0 }, dbda8d6ce9 2007-07-21 drh: { "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc }, dbda8d6ce9 2007-07-21 drh: { "length", 1, 0, SQLITE_UTF8, 0, lengthFunc }, dbda8d6ce9 2007-07-21 drh: { "substr", 3, 0, SQLITE_UTF8, 0, substrFunc }, dbda8d6ce9 2007-07-21 drh: { "abs", 1, 0, SQLITE_UTF8, 0, absFunc }, dbda8d6ce9 2007-07-21 drh: { "round", 1, 0, SQLITE_UTF8, 0, roundFunc }, dbda8d6ce9 2007-07-21 drh: { "round", 2, 0, SQLITE_UTF8, 0, roundFunc }, dbda8d6ce9 2007-07-21 drh: { "upper", 1, 0, SQLITE_UTF8, 0, upperFunc }, dbda8d6ce9 2007-07-21 drh: { "lower", 1, 0, SQLITE_UTF8, 0, lowerFunc }, dbda8d6ce9 2007-07-21 drh: { "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc }, dbda8d6ce9 2007-07-21 drh: { "coalesce", 0, 0, SQLITE_UTF8, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { "coalesce", 1, 0, SQLITE_UTF8, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { "hex", 1, 0, SQLITE_UTF8, 0, hexFunc }, dbda8d6ce9 2007-07-21 drh: { "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc }, dbda8d6ce9 2007-07-21 drh: { "random", -1, 0, SQLITE_UTF8, 0, randomFunc }, dbda8d6ce9 2007-07-21 drh: { "randomblob", 1, 0, SQLITE_UTF8, 0, randomBlob }, dbda8d6ce9 2007-07-21 drh: { "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc }, dbda8d6ce9 2007-07-21 drh: { "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc}, dbda8d6ce9 2007-07-21 drh: { "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc }, dbda8d6ce9 2007-07-21 drh: { "last_insert_rowid", 0, 0xff, SQLITE_UTF8, 0, last_insert_rowid }, dbda8d6ce9 2007-07-21 drh: { "changes", 0, 0xff, SQLITE_UTF8, 0, changes }, dbda8d6ce9 2007-07-21 drh: { "total_changes", 0, 0xff, SQLITE_UTF8, 0, total_changes }, dbda8d6ce9 2007-07-21 drh: { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc }, dbda8d6ce9 2007-07-21 drh: { "ltrim", 1, 1, SQLITE_UTF8, 0, trimFunc }, dbda8d6ce9 2007-07-21 drh: { "ltrim", 2, 1, SQLITE_UTF8, 0, trimFunc }, dbda8d6ce9 2007-07-21 drh: { "rtrim", 1, 2, SQLITE_UTF8, 0, trimFunc }, dbda8d6ce9 2007-07-21 drh: { "rtrim", 2, 2, SQLITE_UTF8, 0, trimFunc }, dbda8d6ce9 2007-07-21 drh: { "trim", 1, 3, SQLITE_UTF8, 0, trimFunc }, dbda8d6ce9 2007-07-21 drh: { "trim", 2, 3, SQLITE_UTF8, 0, trimFunc }, dbda8d6ce9 2007-07-21 drh: { "zeroblob", 1, 0, SQLITE_UTF8, 0, zeroblobFunc }, dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SOUNDEX dbda8d6ce9 2007-07-21 drh: { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_LOAD_EXTENSION dbda8d6ce9 2007-07-21 drh: { "load_extension", 1, 0xff, SQLITE_UTF8, 0, loadExt }, dbda8d6ce9 2007-07-21 drh: { "load_extension", 2, 0xff, SQLITE_UTF8, 0, loadExt }, dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: { "randstr", 2, 0, SQLITE_UTF8, 0, randStr }, dbda8d6ce9 2007-07-21 drh: { "test_destructor", 1, 0xff, SQLITE_UTF8, 0, test_destructor}, dbda8d6ce9 2007-07-21 drh: { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count}, dbda8d6ce9 2007-07-21 drh: { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata}, dbda8d6ce9 2007-07-21 drh: { "test_error", 1, 0, SQLITE_UTF8, 0, test_error}, dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: static const struct { dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: signed char nArg; dbda8d6ce9 2007-07-21 drh: u8 argType; dbda8d6ce9 2007-07-21 drh: u8 needCollSeq; dbda8d6ce9 2007-07-21 drh: void (*xStep)(sqlite3_context*,int,sqlite3_value**); dbda8d6ce9 2007-07-21 drh: void (*xFinalize)(sqlite3_context*); dbda8d6ce9 2007-07-21 drh: } aAggs[] = { dbda8d6ce9 2007-07-21 drh: { "min", 1, 0, 1, minmaxStep, minMaxFinalize }, dbda8d6ce9 2007-07-21 drh: { "max", 1, 1, 1, minmaxStep, minMaxFinalize }, dbda8d6ce9 2007-07-21 drh: { "sum", 1, 0, 0, sumStep, sumFinalize }, dbda8d6ce9 2007-07-21 drh: { "total", 1, 0, 0, sumStep, totalFinalize }, dbda8d6ce9 2007-07-21 drh: { "avg", 1, 0, 0, sumStep, avgFinalize }, dbda8d6ce9 2007-07-21 drh: { "count", 0, 0, 0, countStep, countFinalize }, dbda8d6ce9 2007-07-21 drh: { "count", 1, 0, 0, countStep, countFinalize }, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ dbda8d6ce9 2007-07-21 drh: void *pArg; dbda8d6ce9 2007-07-21 drh: u8 argType = aFuncs[i].argType; dbda8d6ce9 2007-07-21 drh: if( argType==0xff ){ dbda8d6ce9 2007-07-21 drh: pArg = db; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pArg = (void*)(int)argType; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg, dbda8d6ce9 2007-07-21 drh: aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0); dbda8d6ce9 2007-07-21 drh: if( aFuncs[i].needCollSeq ){ dbda8d6ce9 2007-07-21 drh: FuncDef *pFunc = sqlite3FindFunction(db, aFuncs[i].zName, dbda8d6ce9 2007-07-21 drh: strlen(aFuncs[i].zName), aFuncs[i].nArg, aFuncs[i].eTextRep, 0); dbda8d6ce9 2007-07-21 drh: if( pFunc && aFuncs[i].needCollSeq ){ dbda8d6ce9 2007-07-21 drh: pFunc->needCollSeq = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_ALTERTABLE dbda8d6ce9 2007-07-21 drh: sqlite3AlterFunctions(db); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PARSER dbda8d6ce9 2007-07-21 drh: sqlite3AttachFunctions(db); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){ dbda8d6ce9 2007-07-21 drh: void *pArg = (void*)(int)aAggs[i].argType; dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8, dbda8d6ce9 2007-07-21 drh: pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize); dbda8d6ce9 2007-07-21 drh: if( aAggs[i].needCollSeq ){ dbda8d6ce9 2007-07-21 drh: FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName, dbda8d6ce9 2007-07-21 drh: strlen(aAggs[i].zName), aAggs[i].nArg, SQLITE_UTF8, 0); dbda8d6ce9 2007-07-21 drh: if( pFunc && aAggs[i].needCollSeq ){ dbda8d6ce9 2007-07-21 drh: pFunc->needCollSeq = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3RegisterDateTimeFunctions(db); c287665ba8 2007-09-14 drh: if( !db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: int rc = sqlite3_overload_function(db, "MATCH", 2); dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_NOMEM ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SSE dbda8d6ce9 2007-07-21 drh: (void)sqlite3SseFunctions(db); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_CASE_SENSITIVE_LIKE dbda8d6ce9 2007-07-21 drh: sqlite3RegisterLikeFunctions(db, 1); dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: sqlite3RegisterLikeFunctions(db, 0); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the LIKEOPT flag on the 2-argument function with the given name. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void setLikeOptFlag(sqlite3 *db, const char *zName, int flagVal){ dbda8d6ce9 2007-07-21 drh: FuncDef *pDef; dbda8d6ce9 2007-07-21 drh: pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0); dbda8d6ce9 2007-07-21 drh: if( pDef ){ dbda8d6ce9 2007-07-21 drh: pDef->flags = flagVal; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register the built-in LIKE and GLOB functions. The caseSensitive dbda8d6ce9 2007-07-21 drh: ** parameter determines whether or not the LIKE operator is case dbda8d6ce9 2007-07-21 drh: ** sensitive. GLOB is always case sensitive. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ dbda8d6ce9 2007-07-21 drh: struct compareInfo *pInfo; dbda8d6ce9 2007-07-21 drh: if( caseSensitive ){ dbda8d6ce9 2007-07-21 drh: pInfo = (struct compareInfo*)&likeInfoAlt; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pInfo = (struct compareInfo*)&likeInfoNorm; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, dbda8d6ce9 2007-07-21 drh: (struct compareInfo*)&globInfo, likeFunc, 0,0); dbda8d6ce9 2007-07-21 drh: setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); dbda8d6ce9 2007-07-21 drh: setLikeOptFlag(db, "like", dbda8d6ce9 2007-07-21 drh: caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pExpr points to an expression which implements a function. If dbda8d6ce9 2007-07-21 drh: ** it is appropriate to apply the LIKE optimization to that function dbda8d6ce9 2007-07-21 drh: ** then set aWc[0] through aWc[2] to the wildcard characters and dbda8d6ce9 2007-07-21 drh: ** return TRUE. If the function is not a LIKE-style function then dbda8d6ce9 2007-07-21 drh: ** return FALSE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ dbda8d6ce9 2007-07-21 drh: FuncDef *pDef; dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_FUNCTION || !pExpr->pList ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pExpr->pList->nExpr!=2 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2, dbda8d6ce9 2007-07-21 drh: SQLITE_UTF8, 0); dbda8d6ce9 2007-07-21 drh: if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The memcpy() statement assumes that the wildcard characters are dbda8d6ce9 2007-07-21 drh: ** the first three statements in the compareInfo structure. The dbda8d6ce9 2007-07-21 drh: ** asserts() that follow verify that assumption dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: memcpy(aWc, pDef->pUserData, 3); dbda8d6ce9 2007-07-21 drh: assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll ); dbda8d6ce9 2007-07-21 drh: assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne ); dbda8d6ce9 2007-07-21 drh: assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet ); dbda8d6ce9 2007-07-21 drh: *pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of func.c ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file insert.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains C code routines that are called by the parser dbda8d6ce9 2007-07-21 drh: ** to handle INSERT statements in SQLite. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: insert.c,v 1.192 2007/09/03 17:30:07 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set P3 of the most recently inserted opcode to a column affinity dbda8d6ce9 2007-07-21 drh: ** string for index pIdx. A column affinity string has one character dbda8d6ce9 2007-07-21 drh: ** for each column in the table, according to the affinity of the column: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Character Column affinity dbda8d6ce9 2007-07-21 drh: ** ------------------------------ dbda8d6ce9 2007-07-21 drh: ** 'a' TEXT dbda8d6ce9 2007-07-21 drh: ** 'b' NONE dbda8d6ce9 2007-07-21 drh: ** 'c' NUMERIC dbda8d6ce9 2007-07-21 drh: ** 'd' INTEGER dbda8d6ce9 2007-07-21 drh: ** 'e' REAL dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ dbda8d6ce9 2007-07-21 drh: if( !pIdx->zColAff ){ dbda8d6ce9 2007-07-21 drh: /* The first time a column affinity string for a particular index is dbda8d6ce9 2007-07-21 drh: ** required, it is allocated and populated here. It is then stored as dbda8d6ce9 2007-07-21 drh: ** a member of the Index structure for subsequent use. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The column affinity string will eventually be deleted by dbda8d6ce9 2007-07-21 drh: ** sqliteDeleteIndex() when the Index structure itself is cleaned dbda8d6ce9 2007-07-21 drh: ** up. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: Table *pTab = pIdx->pTable; c287665ba8 2007-09-14 drh: sqlite3 *db = sqlite3VdbeDb(v); c287665ba8 2007-09-14 drh: pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+1); dbda8d6ce9 2007-07-21 drh: if( !pIdx->zColAff ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(n=0; n<pIdx->nColumn; n++){ dbda8d6ce9 2007-07-21 drh: pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIdx->zColAff[pIdx->nColumn] = '\0'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, pIdx->zColAff, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set P3 of the most recently inserted opcode to a column affinity dbda8d6ce9 2007-07-21 drh: ** string for table pTab. A column affinity string has one character dbda8d6ce9 2007-07-21 drh: ** for each column indexed by the index, according to the affinity of the dbda8d6ce9 2007-07-21 drh: ** column: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Character Column affinity dbda8d6ce9 2007-07-21 drh: ** ------------------------------ dbda8d6ce9 2007-07-21 drh: ** 'a' TEXT dbda8d6ce9 2007-07-21 drh: ** 'b' NONE dbda8d6ce9 2007-07-21 drh: ** 'c' NUMERIC dbda8d6ce9 2007-07-21 drh: ** 'd' INTEGER dbda8d6ce9 2007-07-21 drh: ** 'e' REAL dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){ dbda8d6ce9 2007-07-21 drh: /* The first time a column affinity string for a particular table dbda8d6ce9 2007-07-21 drh: ** is required, it is allocated and populated here. It is then dbda8d6ce9 2007-07-21 drh: ** stored as a member of the Table structure for subsequent use. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The column affinity string will eventually be deleted by dbda8d6ce9 2007-07-21 drh: ** sqlite3DeleteTable() when the Table structure itself is cleaned up. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !pTab->zColAff ){ dbda8d6ce9 2007-07-21 drh: char *zColAff; dbda8d6ce9 2007-07-21 drh: int i; c287665ba8 2007-09-14 drh: sqlite3 *db = sqlite3VdbeDb(v); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: zColAff = (char *)sqlite3DbMallocZero(db, pTab->nCol+1); dbda8d6ce9 2007-07-21 drh: if( !zColAff ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: zColAff[i] = pTab->aCol[i].affinity; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zColAff[pTab->nCol] = '\0'; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTab->zColAff = zColAff; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, pTab->zColAff, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return non-zero if SELECT statement p opens the table with rootpage dbda8d6ce9 2007-07-21 drh: ** iTab in database iDb. This is used to see if a statement of the form dbda8d6ce9 2007-07-21 drh: ** "INSERT INTO <iDb, iTab> SELECT ..." can run without using temporary dbda8d6ce9 2007-07-21 drh: ** table for the results of the SELECT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** No checking is done for sub-selects that are part of expressions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int selectReadsTable(Select *p, Schema *pSchema, int iTab){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; dbda8d6ce9 2007-07-21 drh: if( p->pSrc==0 ) return 0; dbda8d6ce9 2007-07-21 drh: for(i=0, pItem=p->pSrc->a; i<p->pSrc->nSrc; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: if( pItem->pSelect ){ dbda8d6ce9 2007-07-21 drh: if( selectReadsTable(pItem->pSelect, pSchema, iTab) ) return 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( pItem->pTab->pSchema==pSchema && pItem->pTab->tnum==iTab ) return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOINCREMENT dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Write out code to initialize the autoincrement logic. This code dbda8d6ce9 2007-07-21 drh: ** looks up the current autoincrement value in the sqlite_sequence dbda8d6ce9 2007-07-21 drh: ** table and stores that value in a memory cell. Code generated by dbda8d6ce9 2007-07-21 drh: ** autoIncStep() will keep that memory cell holding the largest dbda8d6ce9 2007-07-21 drh: ** rowid value. Code generated by autoIncEnd() will write the new dbda8d6ce9 2007-07-21 drh: ** largest value of the counter back into the sqlite_sequence table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns the index of the mem[] cell that contains dbda8d6ce9 2007-07-21 drh: ** the maximum rowid counter. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Two memory cells are allocated. The next memory cell after the dbda8d6ce9 2007-07-21 drh: ** one returned holds the rowid in sqlite_sequence where we will dbda8d6ce9 2007-07-21 drh: ** write back the revised maximum rowid. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int autoIncBegin( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: int iDb, /* Index of the database holding pTab */ dbda8d6ce9 2007-07-21 drh: Table *pTab /* The table we are writing to */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int memId = 0; dbda8d6ce9 2007-07-21 drh: if( pTab->autoInc ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: Db *pDb = &pParse->db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: int iCur = pParse->nTab; dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: assert( v ); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: memId = pParse->nMem+1; dbda8d6ce9 2007-07-21 drh: pParse->nMem += 2; dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, iCur, addr+13); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Ne, 0x100, addr+12); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, memId-1, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iCur, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, memId, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, addr+13); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return memId; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Update the maximum rowid for an autoincrement calculation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine should be called when the top of the stack holds a dbda8d6ce9 2007-07-21 drh: ** new rowid that is about to be inserted. If that new rowid is dbda8d6ce9 2007-07-21 drh: ** larger than the maximum rowid in the memId memory cell, then the dbda8d6ce9 2007-07-21 drh: ** memory cell is updated. The stack is unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void autoIncStep(Parse *pParse, int memId){ dbda8d6ce9 2007-07-21 drh: if( memId>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(pParse->pVdbe, OP_MemMax, memId, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** After doing one or more inserts, the maximum rowid is stored dbda8d6ce9 2007-07-21 drh: ** in mem[memId]. Generate code to write this value back into the dbda8d6ce9 2007-07-21 drh: ** the sqlite_sequence table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void autoIncEnd( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: int iDb, /* Index of the database holding pTab */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* Table we are inserting into */ dbda8d6ce9 2007-07-21 drh: int memId /* Memory cell holding the maximum rowid */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( pTab->autoInc ){ dbda8d6ce9 2007-07-21 drh: int iCur = pParse->nTab; dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: Db *pDb = &pParse->db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: assert( v ); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, memId-1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+7); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, memId, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, iCur, OPFLAG_APPEND); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines dbda8d6ce9 2007-07-21 drh: ** above are all no-ops dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: # define autoIncBegin(A,B,C) (0) dbda8d6ce9 2007-07-21 drh: # define autoIncStep(A,B) dbda8d6ce9 2007-07-21 drh: # define autoIncEnd(A,B,C,D) dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_AUTOINCREMENT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward declaration */ dbda8d6ce9 2007-07-21 drh: static int xferOptimization( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: Table *pDest, /* The table we are inserting into */ dbda8d6ce9 2007-07-21 drh: Select *pSelect, /* A SELECT statement to use as the data source */ dbda8d6ce9 2007-07-21 drh: int onError, /* How to handle constraint errors */ dbda8d6ce9 2007-07-21 drh: int iDbDest /* The database of pDest */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is call to handle SQL of the following forms: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** insert into TABLE (IDLIST) values(EXPRLIST) dbda8d6ce9 2007-07-21 drh: ** insert into TABLE (IDLIST) select dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The IDLIST following the table name is always optional. If omitted, dbda8d6ce9 2007-07-21 drh: ** then a list of all columns for the table is substituted. The IDLIST dbda8d6ce9 2007-07-21 drh: ** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pList parameter holds EXPRLIST in the first form of the INSERT dbda8d6ce9 2007-07-21 drh: ** statement above, and pSelect is NULL. For the second form, pList is dbda8d6ce9 2007-07-21 drh: ** NULL and pSelect is a pointer to the select statement used to generate dbda8d6ce9 2007-07-21 drh: ** data for the insert. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code generated follows one of four templates. For a simple dbda8d6ce9 2007-07-21 drh: ** select with data coming from a VALUES clause, the code executes dbda8d6ce9 2007-07-21 drh: ** once straight down through. The template looks like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** open write cursor to <table> and its indices dbda8d6ce9 2007-07-21 drh: ** puts VALUES clause expressions onto the stack dbda8d6ce9 2007-07-21 drh: ** write the resulting record into <table> dbda8d6ce9 2007-07-21 drh: ** cleanup dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The three remaining templates assume the statement is of the form dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** INSERT INTO <table> SELECT ... dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the SELECT clause is of the restricted form "SELECT * FROM <table2>" - dbda8d6ce9 2007-07-21 drh: ** in other words if the SELECT pulls all columns from a single table dbda8d6ce9 2007-07-21 drh: ** and there is no WHERE or LIMIT or GROUP BY or ORDER BY clauses, and dbda8d6ce9 2007-07-21 drh: ** if <table2> and <table1> are distinct tables but have identical dbda8d6ce9 2007-07-21 drh: ** schemas, including all the same indices, then a special optimization dbda8d6ce9 2007-07-21 drh: ** is invoked that copies raw records from <table2> over to <table1>. dbda8d6ce9 2007-07-21 drh: ** See the xferOptimization() function for the implementation of this dbda8d6ce9 2007-07-21 drh: ** template. This is the second template. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** open a write cursor to <table> dbda8d6ce9 2007-07-21 drh: ** open read cursor on <table2> dbda8d6ce9 2007-07-21 drh: ** transfer all records in <table2> over to <table> dbda8d6ce9 2007-07-21 drh: ** close cursors dbda8d6ce9 2007-07-21 drh: ** foreach index on <table> dbda8d6ce9 2007-07-21 drh: ** open a write cursor on the <table> index dbda8d6ce9 2007-07-21 drh: ** open a read cursor on the corresponding <table2> index dbda8d6ce9 2007-07-21 drh: ** transfer all records from the read to the write cursors dbda8d6ce9 2007-07-21 drh: ** close cursors dbda8d6ce9 2007-07-21 drh: ** end foreach dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The third template is for when the second template does not apply dbda8d6ce9 2007-07-21 drh: ** and the SELECT clause does not read from <table> at any time. dbda8d6ce9 2007-07-21 drh: ** The generated code follows this template: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** goto B dbda8d6ce9 2007-07-21 drh: ** A: setup for the SELECT dbda8d6ce9 2007-07-21 drh: ** loop over the rows in the SELECT dbda8d6ce9 2007-07-21 drh: ** gosub C dbda8d6ce9 2007-07-21 drh: ** end loop dbda8d6ce9 2007-07-21 drh: ** cleanup after the SELECT dbda8d6ce9 2007-07-21 drh: ** goto D dbda8d6ce9 2007-07-21 drh: ** B: open write cursor to <table> and its indices dbda8d6ce9 2007-07-21 drh: ** goto A dbda8d6ce9 2007-07-21 drh: ** C: insert the select result into <table> dbda8d6ce9 2007-07-21 drh: ** return dbda8d6ce9 2007-07-21 drh: ** D: cleanup dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The fourth template is used if the insert statement takes its dbda8d6ce9 2007-07-21 drh: ** values from a SELECT but the data is being inserted into a table dbda8d6ce9 2007-07-21 drh: ** that is also read as part of the SELECT. In the third form, dbda8d6ce9 2007-07-21 drh: ** we have to use a intermediate table to store the results of dbda8d6ce9 2007-07-21 drh: ** the select. The template is like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** goto B dbda8d6ce9 2007-07-21 drh: ** A: setup for the SELECT dbda8d6ce9 2007-07-21 drh: ** loop over the tables in the SELECT dbda8d6ce9 2007-07-21 drh: ** gosub C dbda8d6ce9 2007-07-21 drh: ** end loop dbda8d6ce9 2007-07-21 drh: ** cleanup after the SELECT dbda8d6ce9 2007-07-21 drh: ** goto D dbda8d6ce9 2007-07-21 drh: ** C: insert the select result into the intermediate table dbda8d6ce9 2007-07-21 drh: ** return dbda8d6ce9 2007-07-21 drh: ** B: open a cursor to an intermediate table dbda8d6ce9 2007-07-21 drh: ** goto A dbda8d6ce9 2007-07-21 drh: ** D: open write cursor to <table> and its indices dbda8d6ce9 2007-07-21 drh: ** loop over the intermediate table dbda8d6ce9 2007-07-21 drh: ** transfer values form intermediate table into <table> dbda8d6ce9 2007-07-21 drh: ** end the loop dbda8d6ce9 2007-07-21 drh: ** cleanup dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Insert( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList, /* Name of table into which we are inserting */ dbda8d6ce9 2007-07-21 drh: ExprList *pList, /* List of values to be inserted */ dbda8d6ce9 2007-07-21 drh: Select *pSelect, /* A SELECT statement to use as the data source */ dbda8d6ce9 2007-07-21 drh: IdList *pColumn, /* Column names corresponding to IDLIST. */ dbda8d6ce9 2007-07-21 drh: int onError /* How to handle constraint errors */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* The table to insert into */ dbda8d6ce9 2007-07-21 drh: char *zTab; /* Name of the table into which we are inserting */ dbda8d6ce9 2007-07-21 drh: const char *zDb; /* Name of the database holding this table */ dbda8d6ce9 2007-07-21 drh: int i, j, idx; /* Loop counters */ dbda8d6ce9 2007-07-21 drh: Vdbe *v; /* Generate code into this virtual machine */ dbda8d6ce9 2007-07-21 drh: Index *pIdx; /* For looping over indices of the table */ dbda8d6ce9 2007-07-21 drh: int nColumn; /* Number of columns in the data */ dbda8d6ce9 2007-07-21 drh: int base = 0; /* VDBE Cursor number for pTab */ dbda8d6ce9 2007-07-21 drh: int iCont=0,iBreak=0; /* Beginning and end of the loop over srcTab */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; /* The main database structure */ dbda8d6ce9 2007-07-21 drh: int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ dbda8d6ce9 2007-07-21 drh: int endOfLoop; /* Label for the end of the insertion loop */ dbda8d6ce9 2007-07-21 drh: int useTempTable = 0; /* Store SELECT results in intermediate table */ dbda8d6ce9 2007-07-21 drh: int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ dbda8d6ce9 2007-07-21 drh: int iSelectLoop = 0; /* Address of code that implements the SELECT */ dbda8d6ce9 2007-07-21 drh: int iCleanup = 0; /* Address of the cleanup code */ dbda8d6ce9 2007-07-21 drh: int iInsertBlock = 0; /* Address of the subroutine used to insert data */ dbda8d6ce9 2007-07-21 drh: int iCntMem = 0; /* Memory cell used for the row counter */ dbda8d6ce9 2007-07-21 drh: int newIdx = -1; /* Cursor for the NEW table */ dbda8d6ce9 2007-07-21 drh: Db *pDb; /* The database containing table being inserted into */ dbda8d6ce9 2007-07-21 drh: int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */ dbda8d6ce9 2007-07-21 drh: int appendFlag = 0; /* True if the insert is likely to be an append */ dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int nHidden = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: int isView; /* True if attempting to insert into a view */ dbda8d6ce9 2007-07-21 drh: int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: db = pParse->db; c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Locate the table into which we will be inserting new information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pTabList->nSrc==1 ); dbda8d6ce9 2007-07-21 drh: zTab = pTabList->a[0].zName; dbda8d6ce9 2007-07-21 drh: if( zTab==0 ) goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: pTab = sqlite3SrcListLookup(pParse, pTabList); dbda8d6ce9 2007-07-21 drh: if( pTab==0 ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: zDb = pDb->zName; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out if we have any triggers and if the table being dbda8d6ce9 2007-07-21 drh: ** inserted into is a view dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0); dbda8d6ce9 2007-07-21 drh: isView = pTab->pSelect!=0; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define triggers_exist 0 dbda8d6ce9 2007-07-21 drh: # define isView 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: # undef isView dbda8d6ce9 2007-07-21 drh: # define isView 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Ensure that: dbda8d6ce9 2007-07-21 drh: * (a) the table is not read-only, dbda8d6ce9 2007-07-21 drh: * (b) that if it is a view then ON INSERT triggers exist dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pTab!=0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If pTab is really a view, make sure it has been initialized. dbda8d6ce9 2007-07-21 drh: ** ViewGetColumnNames() is a no-op if pTab is not a view (or virtual dbda8d6ce9 2007-07-21 drh: ** module table). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3ViewGetColumnNames(pParse, pTab) ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate a VDBE dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* if there are row triggers, allocate a temp table for new.* references. */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: newIdx = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_XFER_OPT dbda8d6ce9 2007-07-21 drh: /* If the statement is of the form dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** INSERT INTO <table1> SELECT * FROM <table2>; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then special optimizations can be applied that make the transfer dbda8d6ce9 2007-07-21 drh: ** very fast and which reduce fragmentation of indices. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){ dbda8d6ce9 2007-07-21 drh: assert( !triggers_exist ); dbda8d6ce9 2007-07-21 drh: assert( pList==0 ); dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_XFER_OPT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is an AUTOINCREMENT table, look up the sequence number in the dbda8d6ce9 2007-07-21 drh: ** sqlite_sequence table and store it in memory cell counterMem. Also dbda8d6ce9 2007-07-21 drh: ** remember the rowid of the sqlite_sequence table entry in memory cell dbda8d6ce9 2007-07-21 drh: ** counterRowid. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: counterMem = autoIncBegin(pParse, iDb, pTab); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out how many columns of data are supplied. If the data dbda8d6ce9 2007-07-21 drh: ** is coming from a SELECT statement, then this step also generates dbda8d6ce9 2007-07-21 drh: ** all the code to implement the SELECT statement and invoke a subroutine dbda8d6ce9 2007-07-21 drh: ** to process each row of the result. (Template 2.) If the SELECT dbda8d6ce9 2007-07-21 drh: ** statement uses the the table that is being inserted into, then the dbda8d6ce9 2007-07-21 drh: ** subroutine is also coded here. That subroutine stores the SELECT dbda8d6ce9 2007-07-21 drh: ** results in a temporary table. (Template 3.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pSelect ){ dbda8d6ce9 2007-07-21 drh: /* Data is coming from a SELECT. Generate code to implement that SELECT dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int rc, iInitCode; dbda8d6ce9 2007-07-21 drh: iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); dbda8d6ce9 2007-07-21 drh: iSelectLoop = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: iInsertBlock = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Resolve the expressions in the SELECT statement and execute it. */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0); c287665ba8 2007-09-14 drh: if( rc || pParse->nErr || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: iCleanup = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup); dbda8d6ce9 2007-07-21 drh: assert( pSelect->pEList ); dbda8d6ce9 2007-07-21 drh: nColumn = pSelect->pEList->nExpr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set useTempTable to TRUE if the result of the SELECT statement dbda8d6ce9 2007-07-21 drh: ** should be written into a temporary table. Set to FALSE if each dbda8d6ce9 2007-07-21 drh: ** row of the SELECT can be written directly into the result table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A temp table must be used if the table being updated is also one dbda8d6ce9 2007-07-21 drh: ** of the tables being read by the SELECT statement. Also use a dbda8d6ce9 2007-07-21 drh: ** temp table in the case of row triggers. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist || selectReadsTable(pSelect,pTab->pSchema,pTab->tnum) ){ dbda8d6ce9 2007-07-21 drh: useTempTable = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( useTempTable ){ dbda8d6ce9 2007-07-21 drh: /* Generate the subroutine that SELECT calls to process each row of dbda8d6ce9 2007-07-21 drh: ** the result. Store the result in a temporary table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: srcTab = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iInsertBlock); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pull, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, srcTab, OPFLAG_APPEND); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Return, 0, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following code runs first because the GOTO at the very top dbda8d6ce9 2007-07-21 drh: ** of the program jumps to it. Create the temporary table, then jump dbda8d6ce9 2007-07-21 drh: ** back up and execute the SELECT code above. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, iInitCode); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenEphemeral, srcTab, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iCleanup); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, iInitCode); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* This is the case if the data for the INSERT is coming from a VALUES dbda8d6ce9 2007-07-21 drh: ** clause dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: NameContext sNC; dbda8d6ce9 2007-07-21 drh: memset(&sNC, 0, sizeof(sNC)); dbda8d6ce9 2007-07-21 drh: sNC.pParse = pParse; dbda8d6ce9 2007-07-21 drh: srcTab = -1; dbda8d6ce9 2007-07-21 drh: useTempTable = 0; dbda8d6ce9 2007-07-21 drh: nColumn = pList ? pList->nExpr : 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nColumn; i++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the number of columns in the source data matches the number dbda8d6ce9 2007-07-21 drh: ** of columns to be inserted into the table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "table %S has %d columns but %d values were supplied", dbda8d6ce9 2007-07-21 drh: pTabList, 0, pTab->nCol, nColumn); dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pColumn!=0 && nColumn!=pColumn->nId ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId); dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the INSERT statement included an IDLIST term, then make sure dbda8d6ce9 2007-07-21 drh: ** all elements of the IDLIST really are columns of the table and dbda8d6ce9 2007-07-21 drh: ** remember the column indices. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the table has an INTEGER PRIMARY KEY column and that column dbda8d6ce9 2007-07-21 drh: ** is named in the IDLIST, then record in the keyColumn variable dbda8d6ce9 2007-07-21 drh: ** the index into IDLIST of the primary key column. keyColumn is dbda8d6ce9 2007-07-21 drh: ** the index of the primary key as it appears in IDLIST, not as dbda8d6ce9 2007-07-21 drh: ** is appears in the original table. (The index of the primary dbda8d6ce9 2007-07-21 drh: ** key in the original table is pTab->iPKey.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pColumn ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pColumn->nId; i++){ dbda8d6ce9 2007-07-21 drh: pColumn->a[i].idx = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<pColumn->nId; i++){ dbda8d6ce9 2007-07-21 drh: for(j=0; j<pTab->nCol; j++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ dbda8d6ce9 2007-07-21 drh: pColumn->a[i].idx = j; dbda8d6ce9 2007-07-21 drh: if( j==pTab->iPKey ){ dbda8d6ce9 2007-07-21 drh: keyColumn = i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( j>=pTab->nCol ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3IsRowid(pColumn->a[i].zName) ){ dbda8d6ce9 2007-07-21 drh: keyColumn = i; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "table %S has no column named %s", dbda8d6ce9 2007-07-21 drh: pTabList, 0, pColumn->a[i].zName); dbda8d6ce9 2007-07-21 drh: pParse->nErr++; dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there is no IDLIST term but the table has an integer primary dbda8d6ce9 2007-07-21 drh: ** key, the set the keyColumn variable to the primary key column index dbda8d6ce9 2007-07-21 drh: ** in the original table definition. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pColumn==0 && nColumn>0 ){ dbda8d6ce9 2007-07-21 drh: keyColumn = pTab->iPKey; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open the temp table for FOR EACH ROW triggers dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the count of rows to be inserted dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows ){ dbda8d6ce9 2007-07-21 drh: iCntMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open tables and indices if there are no row triggers */ dbda8d6ce9 2007-07-21 drh: if( !triggers_exist ){ dbda8d6ce9 2007-07-21 drh: base = pParse->nTab; dbda8d6ce9 2007-07-21 drh: sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the data source is a temporary table, then we have to create dbda8d6ce9 2007-07-21 drh: ** a loop because there might be multiple rows of data. If the data dbda8d6ce9 2007-07-21 drh: ** source is a subroutine call from the SELECT statement, then we need dbda8d6ce9 2007-07-21 drh: ** to launch the SELECT statement processing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( useTempTable ){ dbda8d6ce9 2007-07-21 drh: iBreak = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, srcTab, iBreak); dbda8d6ce9 2007-07-21 drh: iCont = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: }else if( pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iInsertBlock); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Run the BEFORE and INSTEAD OF triggers, if there are any dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: endOfLoop = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: if( triggers_exist & TRIGGER_BEFORE ){ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* build the NEW.* reference row. Note that if there is an INTEGER dbda8d6ce9 2007-07-21 drh: ** PRIMARY KEY into which a NULL is being inserted, that NULL will be dbda8d6ce9 2007-07-21 drh: ** translated into a unique ID for the row. But on a BEFORE trigger, dbda8d6ce9 2007-07-21 drh: ** we do not know what the unique ID will be (because the insert has dbda8d6ce9 2007-07-21 drh: ** not happened yet) so we substitute a rowid of -1 dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( keyColumn<0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, -1, 0); dbda8d6ce9 2007-07-21 drh: }else if( useTempTable ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pSelect==0 ); /* Otherwise useTempTable is true */ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, -1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Cannot have triggers on a virtual table. If it were possible, dbda8d6ce9 2007-07-21 drh: ** this block would have to account for hidden column. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert(!IsVirtual(pTab)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create the new column data dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( pColumn==0 ){ dbda8d6ce9 2007-07-21 drh: j = i; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(j=0; j<pColumn->nId; j++){ dbda8d6ce9 2007-07-21 drh: if( pColumn->a[j].idx==i ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pColumn && j>=pColumn->nId ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pTab->aCol[i].pDflt); dbda8d6ce9 2007-07-21 drh: }else if( useTempTable ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, srcTab, j); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pSelect==0 ); /* Otherwise useTempTable is true */ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, dbda8d6ce9 2007-07-21 drh: ** do not attempt any conversions before assembling the record. dbda8d6ce9 2007-07-21 drh: ** If this is a real table, attempt conversions as required by the dbda8d6ce9 2007-07-21 drh: ** table column affinities. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3TableAffinityStr(v, pTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Fire BEFORE or INSTEAD OF triggers */ dbda8d6ce9 2007-07-21 drh: if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab, dbda8d6ce9 2007-07-21 drh: newIdx, -1, onError, endOfLoop) ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If any triggers exists, the opening of tables and indices is deferred dbda8d6ce9 2007-07-21 drh: ** until now. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist && !isView ){ dbda8d6ce9 2007-07-21 drh: base = pParse->nTab; dbda8d6ce9 2007-07-21 drh: sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Push the record number for the new entry onto the stack. The dbda8d6ce9 2007-07-21 drh: ** record number is a randomly generate integer created by NewRowid dbda8d6ce9 2007-07-21 drh: ** except when the table has an INTEGER PRIMARY KEY column, in which dbda8d6ce9 2007-07-21 drh: ** case the record number is the same as that column. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: /* The row that the VUpdate opcode will delete: none */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( keyColumn>=0 ){ dbda8d6ce9 2007-07-21 drh: if( useTempTable ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn); dbda8d6ce9 2007-07-21 drh: }else if( pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: VdbeOp *pOp; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr); dbda8d6ce9 2007-07-21 drh: pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1); dbda8d6ce9 2007-07-21 drh: if( pOp && pOp->opcode==OP_Null ){ dbda8d6ce9 2007-07-21 drh: appendFlag = 1; dbda8d6ce9 2007-07-21 drh: pOp->opcode = OP_NewRowid; dbda8d6ce9 2007-07-21 drh: pOp->p1 = base; dbda8d6ce9 2007-07-21 drh: pOp->p2 = counterMem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid dbda8d6ce9 2007-07-21 drh: ** to generate a unique primary key value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !appendFlag ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem); dbda8d6ce9 2007-07-21 drh: appendFlag = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: autoIncStep(pParse, counterMem); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Push onto the stack, data for all columns of the new entry, beginning dbda8d6ce9 2007-07-21 drh: ** with the first column. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nHidden = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( i==pTab->iPKey ){ dbda8d6ce9 2007-07-21 drh: /* The value of the INTEGER PRIMARY KEY column is always a NULL. dbda8d6ce9 2007-07-21 drh: ** Whenever this column is read, the record number will be substituted dbda8d6ce9 2007-07-21 drh: ** in its place. So will fill this column with a NULL to avoid dbda8d6ce9 2007-07-21 drh: ** taking up data space with information that will never be used. */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pColumn==0 ){ dbda8d6ce9 2007-07-21 drh: if( IsHiddenColumn(&pTab->aCol[i]) ){ dbda8d6ce9 2007-07-21 drh: assert( IsVirtual(pTab) ); dbda8d6ce9 2007-07-21 drh: j = -1; dbda8d6ce9 2007-07-21 drh: nHidden++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: j = i - nHidden; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(j=0; j<pColumn->nId; j++){ dbda8d6ce9 2007-07-21 drh: if( pColumn->a[j].idx==i ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pTab->aCol[i].pDflt); dbda8d6ce9 2007-07-21 drh: }else if( useTempTable ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, srcTab, j); dbda8d6ce9 2007-07-21 drh: }else if( pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j+IsVirtual(pTab), 1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pList->a[j].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code to check constraints and generate index keys and dbda8d6ce9 2007-07-21 drh: ** do the insertion. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: pParse->pVirtualLock = pTab; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VUpdate, 1, pTab->nCol+2, dbda8d6ce9 2007-07-21 drh: (const char*)pTab->pVtab, P3_VTAB); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0, dbda8d6ce9 2007-07-21 drh: 0, onError, endOfLoop); dbda8d6ce9 2007-07-21 drh: sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0, dbda8d6ce9 2007-07-21 drh: (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1, dbda8d6ce9 2007-07-21 drh: appendFlag); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update the count of rows that are inserted dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (db->flags & SQLITE_CountRows)!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, 1, iCntMem); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: /* Close all tables opened */ dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, base, 0); dbda8d6ce9 2007-07-21 drh: for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, idx+base, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Code AFTER triggers */ dbda8d6ce9 2007-07-21 drh: if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab, dbda8d6ce9 2007-07-21 drh: newIdx, -1, onError, endOfLoop) ){ dbda8d6ce9 2007-07-21 drh: goto insert_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The bottom of the loop, if the data source is a SELECT statement dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, endOfLoop); dbda8d6ce9 2007-07-21 drh: if( useTempTable ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, srcTab, iCont); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iBreak); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, srcTab, 0); dbda8d6ce9 2007-07-21 drh: }else if( pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Return, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iCleanup); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !triggers_exist && !IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: /* Close all tables opened */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, base, 0); dbda8d6ce9 2007-07-21 drh: for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, idx+base, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update the sqlite_sequence table by storing the content of the dbda8d6ce9 2007-07-21 drh: ** counter value in memory counterMem back into the sqlite_sequence dbda8d6ce9 2007-07-21 drh: ** table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: autoIncEnd(pParse, iDb, pTab, counterMem); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of rows inserted. If this routine is dbda8d6ce9 2007-07-21 drh: ** generating code because of a call to sqlite3NestedParse(), do not dbda8d6ce9 2007-07-21 drh: ** invoke the callback function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: insert_cleanup: dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pTabList); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pList); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSelect); dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(pColumn); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code to do a constraint check prior to an INSERT or an UPDATE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When this routine is called, the stack contains (from bottom to top) dbda8d6ce9 2007-07-21 drh: ** the following values: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1. The rowid of the row to be updated before the update. This dbda8d6ce9 2007-07-21 drh: ** value is omitted unless we are doing an UPDATE that involves a dbda8d6ce9 2007-07-21 drh: ** change to the record number. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2. The rowid of the row after the update. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 3. The data in the first column of the entry after the update. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** i. Data from middle columns... dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** N. The data in the last column of the entry after the update. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The old rowid shown as entry (1) above is omitted unless both isUpdate dbda8d6ce9 2007-07-21 drh: ** and rowidChng are 1. isUpdate is true for UPDATEs and false for dbda8d6ce9 2007-07-21 drh: ** INSERTs and rowidChng is true if the record number is being changed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code generated by this routine pushes additional entries onto dbda8d6ce9 2007-07-21 drh: ** the stack which are the keys for new index entries for the new record. dbda8d6ce9 2007-07-21 drh: ** The order of index keys is the same as the order of the indices on dbda8d6ce9 2007-07-21 drh: ** the pTable->pIndex list. A key is only created for index i if dbda8d6ce9 2007-07-21 drh: ** aIdxUsed!=0 and aIdxUsed[i]!=0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine also generates code to check constraints. NOT NULL, dbda8d6ce9 2007-07-21 drh: ** CHECK, and UNIQUE constraints are all checked. If a constraint fails, dbda8d6ce9 2007-07-21 drh: ** then the appropriate action is performed. There are five possible dbda8d6ce9 2007-07-21 drh: ** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Constraint type Action What Happens dbda8d6ce9 2007-07-21 drh: ** --------------- ---------- ---------------------------------------- dbda8d6ce9 2007-07-21 drh: ** any ROLLBACK The current transaction is rolled back and dbda8d6ce9 2007-07-21 drh: ** sqlite3_exec() returns immediately with a dbda8d6ce9 2007-07-21 drh: ** return code of SQLITE_CONSTRAINT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** any ABORT Back out changes from the current command dbda8d6ce9 2007-07-21 drh: ** only (do not do a complete rollback) then dbda8d6ce9 2007-07-21 drh: ** cause sqlite3_exec() to return immediately dbda8d6ce9 2007-07-21 drh: ** with SQLITE_CONSTRAINT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** any FAIL Sqlite_exec() returns immediately with a dbda8d6ce9 2007-07-21 drh: ** return code of SQLITE_CONSTRAINT. The dbda8d6ce9 2007-07-21 drh: ** transaction is not rolled back and any dbda8d6ce9 2007-07-21 drh: ** prior changes are retained. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** any IGNORE The record number and data is popped from dbda8d6ce9 2007-07-21 drh: ** the stack and there is an immediate jump dbda8d6ce9 2007-07-21 drh: ** to label ignoreDest. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** NOT NULL REPLACE The NULL value is replace by the default dbda8d6ce9 2007-07-21 drh: ** value for that column. If the default value dbda8d6ce9 2007-07-21 drh: ** is NULL, the action is the same as ABORT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** UNIQUE REPLACE The other row that conflicts with the row dbda8d6ce9 2007-07-21 drh: ** being inserted is removed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** CHECK REPLACE Illegal. The results in an exception. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Which action to take is determined by the overrideError parameter. dbda8d6ce9 2007-07-21 drh: ** Or if overrideError==OE_Default, then the pParse->onError parameter dbda8d6ce9 2007-07-21 drh: ** is used. Or if pParse->onError==OE_Default then the onError value dbda8d6ce9 2007-07-21 drh: ** for the constraint is used. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The calling routine must open a read/write cursor for pTab with dbda8d6ce9 2007-07-21 drh: ** cursor number "base". All indices of pTab must also have open dbda8d6ce9 2007-07-21 drh: ** read/write cursors with cursor number base+i for the i-th cursor. dbda8d6ce9 2007-07-21 drh: ** Except, if there is no possibility of a REPLACE action then dbda8d6ce9 2007-07-21 drh: ** cursors do not need to be open for indices where aIdxUsed[i]==0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the isUpdate flag is true, it means that the "base" cursor is dbda8d6ce9 2007-07-21 drh: ** initially pointing to an entry that is being updated. The isUpdate dbda8d6ce9 2007-07-21 drh: ** flag causes extra code to be generated so that the "base" cursor dbda8d6ce9 2007-07-21 drh: ** is still pointing at the same entry after the routine returns. dbda8d6ce9 2007-07-21 drh: ** Without the isUpdate flag, the "base" cursor might be moved. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* the table into which we are inserting */ dbda8d6ce9 2007-07-21 drh: int base, /* Index of a read/write cursor pointing at pTab */ dbda8d6ce9 2007-07-21 drh: char *aIdxUsed, /* Which indices are used. NULL means all are used */ dbda8d6ce9 2007-07-21 drh: int rowidChng, /* True if the record number will change */ dbda8d6ce9 2007-07-21 drh: int isUpdate, /* True for UPDATE, False for INSERT */ dbda8d6ce9 2007-07-21 drh: int overrideError, /* Override onError to this if not OE_Default */ dbda8d6ce9 2007-07-21 drh: int ignoreDest /* Jump to this label on an OE_Ignore resolution */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: int nCol; dbda8d6ce9 2007-07-21 drh: int onError; dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: int extra; dbda8d6ce9 2007-07-21 drh: int iCur; dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: int seenReplace = 0; dbda8d6ce9 2007-07-21 drh: int jumpInst1=0, jumpInst2; dbda8d6ce9 2007-07-21 drh: int hasTwoRowids = (isUpdate && rowidChng); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: assert( v!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pTab->pSelect==0 ); /* This table is not a VIEW */ dbda8d6ce9 2007-07-21 drh: nCol = pTab->nCol; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Test all NOT NULL constraints. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( i==pTab->iPKey ){ dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: onError = pTab->aCol[i].notNull; dbda8d6ce9 2007-07-21 drh: if( onError==OE_None ) continue; dbda8d6ce9 2007-07-21 drh: if( overrideError!=OE_Default ){ dbda8d6ce9 2007-07-21 drh: onError = overrideError; dbda8d6ce9 2007-07-21 drh: }else if( onError==OE_Default ){ dbda8d6ce9 2007-07-21 drh: onError = OE_Abort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ dbda8d6ce9 2007-07-21 drh: onError = OE_Abort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nCol-1-i, 1); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_NotNull, 1, 0); dbda8d6ce9 2007-07-21 drh: assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail dbda8d6ce9 2007-07-21 drh: || onError==OE_Ignore || onError==OE_Replace ); dbda8d6ce9 2007-07-21 drh: switch( onError ){ dbda8d6ce9 2007-07-21 drh: case OE_Rollback: dbda8d6ce9 2007-07-21 drh: case OE_Abort: dbda8d6ce9 2007-07-21 drh: case OE_Fail: { dbda8d6ce9 2007-07-21 drh: char *zMsg = 0; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName, dbda8d6ce9 2007-07-21 drh: " may not be NULL", (char*)0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, zMsg, P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case OE_Ignore: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case OE_Replace: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pTab->aCol[i].pDflt); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Push, nCol-i, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Test all CHECK constraints dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){ dbda8d6ce9 2007-07-21 drh: int allOk = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: assert( pParse->ckOffset==0 ); dbda8d6ce9 2007-07-21 drh: pParse->ckOffset = nCol; dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1); dbda8d6ce9 2007-07-21 drh: assert( pParse->ckOffset==nCol ); dbda8d6ce9 2007-07-21 drh: pParse->ckOffset = 0; dbda8d6ce9 2007-07-21 drh: onError = overrideError!=OE_Default ? overrideError : OE_Abort; d8590e093f 2007-07-24 drh: if( onError==OE_Ignore ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, allOk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_CHECK) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we have an INTEGER PRIMARY KEY, make sure the primary key dbda8d6ce9 2007-07-21 drh: ** of the new record does not previously exist. Except, if this dbda8d6ce9 2007-07-21 drh: ** is an UPDATE and the primary key is not changing, that is OK. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rowidChng ){ dbda8d6ce9 2007-07-21 drh: onError = pTab->keyConf; dbda8d6ce9 2007-07-21 drh: if( overrideError!=OE_Default ){ dbda8d6ce9 2007-07-21 drh: onError = overrideError; dbda8d6ce9 2007-07-21 drh: }else if( onError==OE_Default ){ dbda8d6ce9 2007-07-21 drh: onError = OE_Abort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( isUpdate ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1); dbda8d6ce9 2007-07-21 drh: jumpInst1 = sqlite3VdbeAddOp(v, OP_Eq, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nCol, 1); dbda8d6ce9 2007-07-21 drh: jumpInst2 = sqlite3VdbeAddOp(v, OP_NotExists, base, 0); dbda8d6ce9 2007-07-21 drh: switch( onError ){ dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: onError = OE_Abort; dbda8d6ce9 2007-07-21 drh: /* Fall thru into the next case */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case OE_Rollback: dbda8d6ce9 2007-07-21 drh: case OE_Abort: dbda8d6ce9 2007-07-21 drh: case OE_Fail: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, dbda8d6ce9 2007-07-21 drh: "PRIMARY KEY must be unique", P3_STATIC); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case OE_Replace: { dbda8d6ce9 2007-07-21 drh: sqlite3GenerateRowIndexDelete(v, pTab, base, 0); dbda8d6ce9 2007-07-21 drh: if( isUpdate ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRowids, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: seenReplace = 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case OE_Ignore: { dbda8d6ce9 2007-07-21 drh: assert( seenReplace==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, jumpInst2); dbda8d6ce9 2007-07-21 drh: if( isUpdate ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, jumpInst1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Test all UNIQUE constraints by creating entries for each UNIQUE dbda8d6ce9 2007-07-21 drh: ** index and making sure that duplicate entries do not already exist. dbda8d6ce9 2007-07-21 drh: ** Add the new records to the indices as we go. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: extra = -1; dbda8d6ce9 2007-07-21 drh: for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ dbda8d6ce9 2007-07-21 drh: if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */ dbda8d6ce9 2007-07-21 drh: extra++; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create a key for accessing the index entry */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nCol+extra, 1); dbda8d6ce9 2007-07-21 drh: for(i=0; i<pIdx->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: int idx = pIdx->aiColumn[i]; dbda8d6ce9 2007-07-21 drh: if( idx==pTab->iPKey ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0); dbda8d6ce9 2007-07-21 drh: sqlite3IndexAffinityStr(v, pIdx); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Find out what action to take in case there is an indexing conflict */ dbda8d6ce9 2007-07-21 drh: onError = pIdx->onError; dbda8d6ce9 2007-07-21 drh: if( onError==OE_None ) continue; /* pIdx is not a UNIQUE index */ dbda8d6ce9 2007-07-21 drh: if( overrideError!=OE_Default ){ dbda8d6ce9 2007-07-21 drh: onError = overrideError; dbda8d6ce9 2007-07-21 drh: }else if( onError==OE_Default ){ dbda8d6ce9 2007-07-21 drh: onError = OE_Abort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( seenReplace ){ dbda8d6ce9 2007-07-21 drh: if( onError==OE_Ignore ) onError = OE_Replace; dbda8d6ce9 2007-07-21 drh: else if( onError==OE_Fail ) onError = OE_Abort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to see if the new index entry will be unique */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRowids, 1); dbda8d6ce9 2007-07-21 drh: jumpInst2 = sqlite3VdbeAddOp(v, OP_IsUnique, base+iCur+1, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code that executes if the new index entry is not unique */ dbda8d6ce9 2007-07-21 drh: assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail dbda8d6ce9 2007-07-21 drh: || onError==OE_Ignore || onError==OE_Replace ); dbda8d6ce9 2007-07-21 drh: switch( onError ){ dbda8d6ce9 2007-07-21 drh: case OE_Rollback: dbda8d6ce9 2007-07-21 drh: case OE_Abort: dbda8d6ce9 2007-07-21 drh: case OE_Fail: { dbda8d6ce9 2007-07-21 drh: int j, n1, n2; dbda8d6ce9 2007-07-21 drh: char zErrMsg[200]; dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErrMsg), zErrMsg, dbda8d6ce9 2007-07-21 drh: pIdx->nColumn>1 ? "columns " : "column "); dbda8d6ce9 2007-07-21 drh: n1 = strlen(zErrMsg); dbda8d6ce9 2007-07-21 drh: for(j=0; j<pIdx->nColumn && n1<sizeof(zErrMsg)-30; j++){ dbda8d6ce9 2007-07-21 drh: char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName; dbda8d6ce9 2007-07-21 drh: n2 = strlen(zCol); dbda8d6ce9 2007-07-21 drh: if( j>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], ", "); dbda8d6ce9 2007-07-21 drh: n1 += 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( n1+n2>sizeof(zErrMsg)-30 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], "..."); dbda8d6ce9 2007-07-21 drh: n1 += 3; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], "%s", zCol); dbda8d6ce9 2007-07-21 drh: n1 += n2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], dbda8d6ce9 2007-07-21 drh: pIdx->nColumn>1 ? " are not unique" : " is not unique"); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case OE_Ignore: { dbda8d6ce9 2007-07-21 drh: assert( seenReplace==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRowids, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case OE_Replace: { dbda8d6ce9 2007-07-21 drh: sqlite3GenerateRowDelete(pParse->db, v, pTab, base, 0); dbda8d6ce9 2007-07-21 drh: if( isUpdate ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRowids, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: seenReplace = 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #if NULL_DISTINCT_FOR_UNIQUE dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, jumpInst1); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, jumpInst2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine generates code to finish the INSERT or UPDATE operation dbda8d6ce9 2007-07-21 drh: ** that was started by a prior call to sqlite3GenerateConstraintChecks. dbda8d6ce9 2007-07-21 drh: ** The stack must contain keys for all active indices followed by data dbda8d6ce9 2007-07-21 drh: ** and the rowid for the new entry. This routine creates the new dbda8d6ce9 2007-07-21 drh: ** entries in all indices and in the main table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The arguments to this routine should be the same as the first six dbda8d6ce9 2007-07-21 drh: ** arguments to sqlite3GenerateConstraintChecks. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CompleteInsertion( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* the table into which we are inserting */ dbda8d6ce9 2007-07-21 drh: int base, /* Index of a read/write cursor pointing at pTab */ dbda8d6ce9 2007-07-21 drh: char *aIdxUsed, /* Which indices are used. NULL means all are used */ dbda8d6ce9 2007-07-21 drh: int rowidChng, /* True if the record number will change */ dbda8d6ce9 2007-07-21 drh: int isUpdate, /* True for UPDATE, False for INSERT */ dbda8d6ce9 2007-07-21 drh: int newIdx, /* Index of NEW table for triggers. -1 if none */ dbda8d6ce9 2007-07-21 drh: int appendBias /* True if this is likely to be an append */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: int nIdx; dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: int pik_flags; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: assert( v!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pTab->pSelect==0 ); /* This table is not a VIEW */ dbda8d6ce9 2007-07-21 drh: for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} dbda8d6ce9 2007-07-21 drh: for(i=nIdx-1; i>=0; i--){ dbda8d6ce9 2007-07-21 drh: if( aIdxUsed && aIdxUsed[i]==0 ) continue; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, base+i+1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); dbda8d6ce9 2007-07-21 drh: sqlite3TableAffinityStr(v, pTab); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: if( newIdx>=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( pParse->nested ){ dbda8d6ce9 2007-07-21 drh: pik_flags = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pik_flags = OPFLAG_NCHANGE; dbda8d6ce9 2007-07-21 drh: pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( appendBias ){ dbda8d6ce9 2007-07-21 drh: pik_flags |= OPFLAG_APPEND; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags); dbda8d6ce9 2007-07-21 drh: if( !pParse->nested ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( isUpdate && rowidChng ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will open cursors for a table and for all dbda8d6ce9 2007-07-21 drh: ** indices of that table. The "base" parameter is the cursor number used dbda8d6ce9 2007-07-21 drh: ** for the table. Indices are opened on subsequent cursors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3OpenTableAndIndices( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* Table to be opened */ dbda8d6ce9 2007-07-21 drh: int base, /* Cursor number assigned to the table */ dbda8d6ce9 2007-07-21 drh: int op /* OP_OpenRead or OP_OpenWrite */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ) return; dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: assert( v!=0 ); dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, base, iDb, pTab, op); dbda8d6ce9 2007-07-21 drh: for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); dbda8d6ce9 2007-07-21 drh: assert( pIdx->pSchema==pTab->pSchema ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# %s", pIdx->zName)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, (char*)pKey, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pParse->nTab<=base+i ){ dbda8d6ce9 2007-07-21 drh: pParse->nTab = base+i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following global variable is incremented whenever the dbda8d6ce9 2007-07-21 drh: ** transfer optimization is used. This is used for testing dbda8d6ce9 2007-07-21 drh: ** purposes only - to make sure the transfer optimization really dbda8d6ce9 2007-07-21 drh: ** is happening when it is suppose to. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_xferopt_count; dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_TEST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_XFER_OPT dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to collation names to see if they are compatible. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int xferCompatibleCollation(const char *z1, const char *z2){ dbda8d6ce9 2007-07-21 drh: if( z1==0 ){ dbda8d6ce9 2007-07-21 drh: return z2==0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( z2==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return sqlite3StrICmp(z1, z2)==0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if index pSrc is compatible as a source of data dbda8d6ce9 2007-07-21 drh: ** for index pDest in an insert transfer optimization. The rules dbda8d6ce9 2007-07-21 drh: ** for a compatible index: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * The index is over the same set of columns dbda8d6ce9 2007-07-21 drh: ** * The same DESC and ASC markings occurs on all columns dbda8d6ce9 2007-07-21 drh: ** * The same onError processing (OE_Abort, OE_Ignore, etc) dbda8d6ce9 2007-07-21 drh: ** * The same collating sequence on each column dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int xferCompatibleIndex(Index *pDest, Index *pSrc){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: assert( pDest && pSrc ); dbda8d6ce9 2007-07-21 drh: assert( pDest->pTable!=pSrc->pTable ); dbda8d6ce9 2007-07-21 drh: if( pDest->nColumn!=pSrc->nColumn ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Different number of columns */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDest->onError!=pSrc->onError ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Different conflict resolution strategies */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<pSrc->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Different columns indexed */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Different sort orders */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSrc->azColl[i]!=pDest->azColl[i] ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Different sort orders */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If no test above fails then the indices must be compatible */ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt the transfer optimization on INSERTs of the form dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** INSERT INTO tab1 SELECT * FROM tab2; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This optimization is only attempted if dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) tab1 and tab2 have identical schemas including all the dbda8d6ce9 2007-07-21 drh: ** same indices and constraints dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (2) tab1 and tab2 are different tables dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (3) There must be no triggers on tab1 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (4) The result set of the SELECT statement is "*" dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (5) The SELECT statement has no WHERE, HAVING, ORDER BY, GROUP BY, dbda8d6ce9 2007-07-21 drh: ** or LIMIT clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (6) The SELECT statement is a simple (not a compound) select that dbda8d6ce9 2007-07-21 drh: ** contains only tab2 in its FROM clause dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This method for implementing the INSERT transfers raw records from dbda8d6ce9 2007-07-21 drh: ** tab2 over to tab1. The columns are not decoded. Raw records from dbda8d6ce9 2007-07-21 drh: ** the indices of tab2 are transfered to tab1 as well. In so doing, dbda8d6ce9 2007-07-21 drh: ** the resulting tab1 has much less fragmentation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns TRUE if the optimization is attempted. If any dbda8d6ce9 2007-07-21 drh: ** of the conditions above fail so that the optimization should not dbda8d6ce9 2007-07-21 drh: ** be attempted, then this routine returns FALSE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int xferOptimization( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: Table *pDest, /* The table we are inserting into */ dbda8d6ce9 2007-07-21 drh: Select *pSelect, /* A SELECT statement to use as the data source */ dbda8d6ce9 2007-07-21 drh: int onError, /* How to handle constraint errors */ dbda8d6ce9 2007-07-21 drh: int iDbDest /* The database of pDest */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: ExprList *pEList; /* The result set of the SELECT */ dbda8d6ce9 2007-07-21 drh: Table *pSrc; /* The table in the FROM clause of SELECT */ dbda8d6ce9 2007-07-21 drh: Index *pSrcIdx, *pDestIdx; /* Source and destination indices */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem; /* An element of pSelect->pSrc */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: int iDbSrc; /* The database of pSrc */ dbda8d6ce9 2007-07-21 drh: int iSrc, iDest; /* Cursors from source and destination */ dbda8d6ce9 2007-07-21 drh: int addr1, addr2; /* Loop addresses */ dbda8d6ce9 2007-07-21 drh: int emptyDestTest; /* Address of test for empty pDest */ dbda8d6ce9 2007-07-21 drh: int emptySrcTest; /* Address of test for empty pSrc */ dbda8d6ce9 2007-07-21 drh: Vdbe *v; /* The VDBE we are building */ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKey; /* Key information for an index */ dbda8d6ce9 2007-07-21 drh: int counterMem; /* Memory register used by AUTOINC */ dbda8d6ce9 2007-07-21 drh: int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pSelect==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Must be of the form INSERT INTO ... SELECT ... */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDest->pTrigger ){ dbda8d6ce9 2007-07-21 drh: return 0; /* tab1 must not have triggers */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( pDest->isVirtual ){ dbda8d6ce9 2007-07-21 drh: return 0; /* tab1 must not be a virtual table */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( onError==OE_Default ){ dbda8d6ce9 2007-07-21 drh: onError = OE_Abort; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( onError!=OE_Abort && onError!=OE_Rollback ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Cannot do OR REPLACE or OR IGNORE or OR FAIL */ dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert(pSelect->pSrc); /* allocated even if there is no FROM clause */ dbda8d6ce9 2007-07-21 drh: if( pSelect->pSrc->nSrc!=1 ){ dbda8d6ce9 2007-07-21 drh: return 0; /* FROM clause must have exactly one term */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSelect->pSrc->a[0].pSelect ){ dbda8d6ce9 2007-07-21 drh: return 0; /* FROM clause cannot contain a subquery */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSelect->pWhere ){ dbda8d6ce9 2007-07-21 drh: return 0; /* SELECT may not have a WHERE clause */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSelect->pOrderBy ){ dbda8d6ce9 2007-07-21 drh: return 0; /* SELECT may not have an ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Do not need to test for a HAVING clause. If HAVING is present but dbda8d6ce9 2007-07-21 drh: ** there is no ORDER BY, we will get an error. */ dbda8d6ce9 2007-07-21 drh: if( pSelect->pGroupBy ){ dbda8d6ce9 2007-07-21 drh: return 0; /* SELECT may not have a GROUP BY clause */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSelect->pLimit ){ dbda8d6ce9 2007-07-21 drh: return 0; /* SELECT may not have a LIMIT clause */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */ dbda8d6ce9 2007-07-21 drh: if( pSelect->pPrior ){ dbda8d6ce9 2007-07-21 drh: return 0; /* SELECT may not be a compound query */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSelect->isDistinct ){ dbda8d6ce9 2007-07-21 drh: return 0; /* SELECT may not be DISTINCT */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pEList = pSelect->pEList; dbda8d6ce9 2007-07-21 drh: assert( pEList!=0 ); dbda8d6ce9 2007-07-21 drh: if( pEList->nExpr!=1 ){ dbda8d6ce9 2007-07-21 drh: return 0; /* The result set must have exactly one column */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pEList->a[0].pExpr ); dbda8d6ce9 2007-07-21 drh: if( pEList->a[0].pExpr->op!=TK_ALL ){ dbda8d6ce9 2007-07-21 drh: return 0; /* The result set must be the special operator "*" */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* At this point we have established that the statement is of the dbda8d6ce9 2007-07-21 drh: ** correct syntactic form to participate in this optimization. Now dbda8d6ce9 2007-07-21 drh: ** we have to check the semantics. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pItem = pSelect->pSrc->a; dbda8d6ce9 2007-07-21 drh: pSrc = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase); dbda8d6ce9 2007-07-21 drh: if( pSrc==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; /* FROM clause does not contain a real table */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSrc==pDest ){ dbda8d6ce9 2007-07-21 drh: return 0; /* tab1 and tab2 may not be the same table */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( pSrc->isVirtual ){ dbda8d6ce9 2007-07-21 drh: return 0; /* tab2 must not be a virtual table */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( pSrc->pSelect ){ dbda8d6ce9 2007-07-21 drh: return 0; /* tab2 may not be a view */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDest->nCol!=pSrc->nCol ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Number of columns must be the same in tab1 and tab2 */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDest->iPKey!=pSrc->iPKey ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<pDest->nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Affinity must be the same on all columns */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Collating sequence must be the same on all columns */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){ dbda8d6ce9 2007-07-21 drh: return 0; /* tab2 must be NOT NULL if tab1 is */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ dbda8d6ce9 2007-07-21 drh: if( pDestIdx->onError!=OE_None ){ dbda8d6ce9 2007-07-21 drh: destHasUniqueIdx = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ dbda8d6ce9 2007-07-21 drh: if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSrcIdx==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; /* pDestIdx has no corresponding index in pSrc */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: if( pDest->pCheck && !sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Tables have different CHECK constraints. Ticket #2252 */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we get this far, it means either: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * We can always do the transfer if the table contains an dbda8d6ce9 2007-07-21 drh: ** an integer primary key dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * We can conditionally do the transfer if the destination dbda8d6ce9 2007-07-21 drh: ** table is empty. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST dbda8d6ce9 2007-07-21 drh: sqlite3_xferopt_count++; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema); dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); c287665ba8 2007-09-14 drh: sqlite3CodeVerifySchema(pParse, iDbSrc); dbda8d6ce9 2007-07-21 drh: iSrc = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: iDest = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: counterMem = autoIncBegin(pParse, iDbDest, pDest); dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); dbda8d6ce9 2007-07-21 drh: if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ){ dbda8d6ce9 2007-07-21 drh: /* If tables do not have an INTEGER PRIMARY KEY and there dbda8d6ce9 2007-07-21 drh: ** are indices to be copied and the destination is not empty, dbda8d6ce9 2007-07-21 drh: ** we have to disallow the transfer optimization because the dbda8d6ce9 2007-07-21 drh: ** the rowids might change which will mess up indexing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Or if the destination has a UNIQUE index and is not empty, dbda8d6ce9 2007-07-21 drh: ** we also disallow the transfer optimization because we cannot dbda8d6ce9 2007-07-21 drh: ** insure that all entries in the union of DEST and SRC will be dbda8d6ce9 2007-07-21 drh: ** unique. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iDest, 0); dbda8d6ce9 2007-07-21 drh: emptyDestTest = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: emptyDestTest = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: emptySrcTest = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0); dbda8d6ce9 2007-07-21 drh: if( pDest->iPKey>=0 ){ dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: addr2 = sqlite3VdbeAddOp(v, OP_NotExists, iDest, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, dbda8d6ce9 2007-07-21 drh: "PRIMARY KEY must be unique", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr2); dbda8d6ce9 2007-07-21 drh: autoIncStep(pParse, counterMem); dbda8d6ce9 2007-07-21 drh: }else if( pDest->pIndex==0 ){ dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_NewRowid, iDest, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0); dbda8d6ce9 2007-07-21 drh: assert( pDest->autoInc==0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_RowData, iSrc, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Insert, iDest, dbda8d6ce9 2007-07-21 drh: OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND, dbda8d6ce9 2007-07-21 drh: pDest->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1); dbda8d6ce9 2007-07-21 drh: autoIncEnd(pParse, iDbDest, pDest, counterMem); dbda8d6ce9 2007-07-21 drh: for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ dbda8d6ce9 2007-07-21 drh: for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ dbda8d6ce9 2007-07-21 drh: if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pSrcIdx ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iSrc, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iDest, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDbSrc, 0); dbda8d6ce9 2007-07-21 drh: pKey = sqlite3IndexKeyinfo(pParse, pSrcIdx); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# %s", pSrcIdx->zName)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenRead, iSrc, pSrcIdx->tnum, dbda8d6ce9 2007-07-21 drh: (char*)pKey, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDbDest, 0); dbda8d6ce9 2007-07-21 drh: pKey = sqlite3IndexKeyinfo(pParse, pDestIdx); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# %s", pDestIdx->zName)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, dbda8d6ce9 2007-07-21 drh: (char*)pKey, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_RowKey, iSrc, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, iDest, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1+1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, emptySrcTest); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iSrc, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iDest, 0); dbda8d6ce9 2007-07-21 drh: if( emptyDestTest ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Halt, SQLITE_OK, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, emptyDestTest); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iDest, 0); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_XFER_OPT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of insert.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file legacy.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** Main file for the SQLite library. The routines in this file dbda8d6ce9 2007-07-21 drh: ** implement the programmer interface to the library. Routines in dbda8d6ce9 2007-07-21 drh: ** other files are for internal use by SQLite and should not be dbda8d6ce9 2007-07-21 drh: ** accessed by users of the library. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: legacy.c,v 1.22 2007/08/29 12:31:26 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Execute SQL code. Return one of the SQLITE_ success/failure dbda8d6ce9 2007-07-21 drh: ** codes. Also write an error message into memory obtained from dbda8d6ce9 2007-07-21 drh: ** malloc() and make *pzErrMsg point to that message. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the SQL is a query, then for each row in the query result dbda8d6ce9 2007-07-21 drh: ** the xCallback() function is called. pArg becomes the first dbda8d6ce9 2007-07-21 drh: ** argument to xCallback(). If xCallback=NULL then no callback dbda8d6ce9 2007-07-21 drh: ** is invoked, even for queries. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_exec( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* The database on which the SQL executes */ dbda8d6ce9 2007-07-21 drh: const char *zSql, /* The SQL to be executed */ dbda8d6ce9 2007-07-21 drh: sqlite3_callback xCallback, /* Invoke this callback routine */ dbda8d6ce9 2007-07-21 drh: void *pArg, /* First argument to xCallback() */ dbda8d6ce9 2007-07-21 drh: char **pzErrMsg /* Write error messages here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: const char *zLeftover; dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pStmt = 0; dbda8d6ce9 2007-07-21 drh: char **azCols = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int nRetry = 0; dbda8d6ce9 2007-07-21 drh: int nCallback; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( zSql==0 ) return SQLITE_OK; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){ dbda8d6ce9 2007-07-21 drh: int nCol; dbda8d6ce9 2007-07-21 drh: char **azVals = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pStmt = 0; dbda8d6ce9 2007-07-21 drh: rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover); dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_OK || pStmt==0 ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pStmt ){ dbda8d6ce9 2007-07-21 drh: /* this happens for a comment or white-space */ dbda8d6ce9 2007-07-21 drh: zSql = zLeftover; dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nCallback = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nCol = sqlite3_column_count(pStmt); c287665ba8 2007-09-14 drh: azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char *) + 1); dbda8d6ce9 2007-07-21 drh: if( azCols==0 ){ dbda8d6ce9 2007-07-21 drh: goto exec_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( 1 ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: rc = sqlite3_step(pStmt); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Invoke the callback function if required */ dbda8d6ce9 2007-07-21 drh: if( xCallback && (SQLITE_ROW==rc || dbda8d6ce9 2007-07-21 drh: (SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){ dbda8d6ce9 2007-07-21 drh: if( 0==nCallback ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: azCols[i] = (char *)sqlite3_column_name(pStmt, i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nCallback++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_ROW ){ dbda8d6ce9 2007-07-21 drh: azVals = &azCols[nCol]; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: azVals[i] = (char *)sqlite3_column_text(pStmt, i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( xCallback(pArg, nCol, azVals, azCols) ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ABORT; dbda8d6ce9 2007-07-21 drh: goto exec_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_ROW ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3_finalize(pStmt); dbda8d6ce9 2007-07-21 drh: pStmt = 0; dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_SCHEMA ){ dbda8d6ce9 2007-07-21 drh: nRetry = 0; dbda8d6ce9 2007-07-21 drh: zSql = zLeftover; dbda8d6ce9 2007-07-21 drh: while( isspace((unsigned char)zSql[0]) ) zSql++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3_free(azCols); dbda8d6ce9 2007-07-21 drh: azCols = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: exec_out: dbda8d6ce9 2007-07-21 drh: if( pStmt ) sqlite3_finalize(pStmt); c287665ba8 2007-09-14 drh: if( azCols ) sqlite3_free(azCols); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){ dbda8d6ce9 2007-07-21 drh: int nErrMsg = 1 + strlen(sqlite3_errmsg(db)); dbda8d6ce9 2007-07-21 drh: *pzErrMsg = sqlite3_malloc(nErrMsg); dbda8d6ce9 2007-07-21 drh: if( *pzErrMsg ){ dbda8d6ce9 2007-07-21 drh: memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pzErrMsg ){ dbda8d6ce9 2007-07-21 drh: *pzErrMsg = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( (rc&db->errMask)==rc ); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of legacy.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file loadext.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2006 June 7 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code used to dynamically load extensions into dbda8d6ce9 2007-07-21 drh: ** the SQLite library. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_LOAD_EXTENSION dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ dbda8d6ce9 2007-07-21 drh: /************** Include sqlite3ext.h in the middle of loadext.c **************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file sqlite3ext.h **************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2006 June 7 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This header file defines the SQLite interface for use by dbda8d6ce9 2007-07-21 drh: ** shared libraries that want to be imported as extensions into dbda8d6ce9 2007-07-21 drh: ** an SQLite instance. Shared libraries that intend to be loaded dbda8d6ce9 2007-07-21 drh: ** as extensions by SQLite should #include this file instead of dbda8d6ce9 2007-07-21 drh: ** sqlite3.h. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** @(#) $Id: sqlite3ext.h,v 1.17 2007/08/31 16:11:36 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef _SQLITE3EXT_H_ dbda8d6ce9 2007-07-21 drh: #define _SQLITE3EXT_H_ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: typedef struct sqlite3_api_routines sqlite3_api_routines; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following structure hold pointers to all of the SQLite API dbda8d6ce9 2007-07-21 drh: ** routines. d8590e093f 2007-07-24 drh: ** d8590e093f 2007-07-24 drh: ** WARNING: In order to maintain backwards compatibility, add new d8590e093f 2007-07-24 drh: ** interfaces to the end of this structure only. If you insert new d8590e093f 2007-07-24 drh: ** interfaces in the middle of this structure, then older different d8590e093f 2007-07-24 drh: ** versions of SQLite will not be able to load each others shared d8590e093f 2007-07-24 drh: ** libraries! dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct sqlite3_api_routines { dbda8d6ce9 2007-07-21 drh: void * (*aggregate_context)(sqlite3_context*,int nBytes); dbda8d6ce9 2007-07-21 drh: int (*aggregate_count)(sqlite3_context*); dbda8d6ce9 2007-07-21 drh: int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); dbda8d6ce9 2007-07-21 drh: int (*bind_double)(sqlite3_stmt*,int,double); dbda8d6ce9 2007-07-21 drh: int (*bind_int)(sqlite3_stmt*,int,int); dbda8d6ce9 2007-07-21 drh: int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); dbda8d6ce9 2007-07-21 drh: int (*bind_null)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: int (*bind_parameter_count)(sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); dbda8d6ce9 2007-07-21 drh: const char * (*bind_parameter_name)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); dbda8d6ce9 2007-07-21 drh: int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); dbda8d6ce9 2007-07-21 drh: int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); dbda8d6ce9 2007-07-21 drh: int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); dbda8d6ce9 2007-07-21 drh: int (*busy_timeout)(sqlite3*,int ms); dbda8d6ce9 2007-07-21 drh: int (*changes)(sqlite3*); dbda8d6ce9 2007-07-21 drh: int (*close)(sqlite3*); dbda8d6ce9 2007-07-21 drh: int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*)); dbda8d6ce9 2007-07-21 drh: int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*)); dbda8d6ce9 2007-07-21 drh: const void * (*column_blob)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: int (*column_bytes)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: int (*column_bytes16)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: int (*column_count)(sqlite3_stmt*pStmt); dbda8d6ce9 2007-07-21 drh: const char * (*column_database_name)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: const void * (*column_database_name16)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: const char * (*column_decltype)(sqlite3_stmt*,int i); dbda8d6ce9 2007-07-21 drh: const void * (*column_decltype16)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: double (*column_double)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: int (*column_int)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: const char * (*column_name)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: const void * (*column_name16)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: const char * (*column_origin_name)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: const void * (*column_origin_name16)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: const char * (*column_table_name)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: const void * (*column_table_name16)(sqlite3_stmt*,int); dbda8d6ce9 2007-07-21 drh: const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: const void * (*column_text16)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: int (*column_type)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); dbda8d6ce9 2007-07-21 drh: void * (*commit_hook)(sqlite3*,int(*)(void*),void*); dbda8d6ce9 2007-07-21 drh: int (*complete)(const char*sql); dbda8d6ce9 2007-07-21 drh: int (*complete16)(const void*sql); dbda8d6ce9 2007-07-21 drh: int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*)); dbda8d6ce9 2007-07-21 drh: int (*create_collation16)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*)); dbda8d6ce9 2007-07-21 drh: int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*)); dbda8d6ce9 2007-07-21 drh: int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*)); dbda8d6ce9 2007-07-21 drh: int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); dbda8d6ce9 2007-07-21 drh: int (*data_count)(sqlite3_stmt*pStmt); dbda8d6ce9 2007-07-21 drh: sqlite3 * (*db_handle)(sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: int (*declare_vtab)(sqlite3*,const char*); dbda8d6ce9 2007-07-21 drh: int (*enable_shared_cache)(int); dbda8d6ce9 2007-07-21 drh: int (*errcode)(sqlite3*db); dbda8d6ce9 2007-07-21 drh: const char * (*errmsg)(sqlite3*); dbda8d6ce9 2007-07-21 drh: const void * (*errmsg16)(sqlite3*); dbda8d6ce9 2007-07-21 drh: int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); dbda8d6ce9 2007-07-21 drh: int (*expired)(sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: int (*finalize)(sqlite3_stmt*pStmt); dbda8d6ce9 2007-07-21 drh: void (*free)(void*); dbda8d6ce9 2007-07-21 drh: void (*free_table)(char**result); dbda8d6ce9 2007-07-21 drh: int (*get_autocommit)(sqlite3*); dbda8d6ce9 2007-07-21 drh: void * (*get_auxdata)(sqlite3_context*,int); dbda8d6ce9 2007-07-21 drh: int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); dbda8d6ce9 2007-07-21 drh: int (*global_recover)(void); dbda8d6ce9 2007-07-21 drh: void (*interruptx)(sqlite3*); dbda8d6ce9 2007-07-21 drh: sqlite_int64 (*last_insert_rowid)(sqlite3*); dbda8d6ce9 2007-07-21 drh: const char * (*libversion)(void); dbda8d6ce9 2007-07-21 drh: int (*libversion_number)(void); dbda8d6ce9 2007-07-21 drh: void *(*malloc)(int); dbda8d6ce9 2007-07-21 drh: char * (*mprintf)(const char*,...); dbda8d6ce9 2007-07-21 drh: int (*open)(const char*,sqlite3**); dbda8d6ce9 2007-07-21 drh: int (*open16)(const void*,sqlite3**); dbda8d6ce9 2007-07-21 drh: int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); dbda8d6ce9 2007-07-21 drh: int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); dbda8d6ce9 2007-07-21 drh: void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); dbda8d6ce9 2007-07-21 drh: void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); dbda8d6ce9 2007-07-21 drh: void *(*realloc)(void*,int); dbda8d6ce9 2007-07-21 drh: int (*reset)(sqlite3_stmt*pStmt); dbda8d6ce9 2007-07-21 drh: void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); dbda8d6ce9 2007-07-21 drh: void (*result_double)(sqlite3_context*,double); dbda8d6ce9 2007-07-21 drh: void (*result_error)(sqlite3_context*,const char*,int); dbda8d6ce9 2007-07-21 drh: void (*result_error16)(sqlite3_context*,const void*,int); dbda8d6ce9 2007-07-21 drh: void (*result_int)(sqlite3_context*,int); dbda8d6ce9 2007-07-21 drh: void (*result_int64)(sqlite3_context*,sqlite_int64); dbda8d6ce9 2007-07-21 drh: void (*result_null)(sqlite3_context*); dbda8d6ce9 2007-07-21 drh: void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); dbda8d6ce9 2007-07-21 drh: void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); dbda8d6ce9 2007-07-21 drh: void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); dbda8d6ce9 2007-07-21 drh: void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); dbda8d6ce9 2007-07-21 drh: void (*result_value)(sqlite3_context*,sqlite3_value*); dbda8d6ce9 2007-07-21 drh: void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); dbda8d6ce9 2007-07-21 drh: int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*); dbda8d6ce9 2007-07-21 drh: void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); dbda8d6ce9 2007-07-21 drh: char * (*snprintf)(int,char*,const char*,...); dbda8d6ce9 2007-07-21 drh: int (*step)(sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*); dbda8d6ce9 2007-07-21 drh: void (*thread_cleanup)(void); dbda8d6ce9 2007-07-21 drh: int (*total_changes)(sqlite3*); dbda8d6ce9 2007-07-21 drh: void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); dbda8d6ce9 2007-07-21 drh: int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); dbda8d6ce9 2007-07-21 drh: void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*); dbda8d6ce9 2007-07-21 drh: void * (*user_data)(sqlite3_context*); dbda8d6ce9 2007-07-21 drh: const void * (*value_blob)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: int (*value_bytes)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: int (*value_bytes16)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: double (*value_double)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: int (*value_int)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: sqlite_int64 (*value_int64)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: int (*value_numeric_type)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: const unsigned char * (*value_text)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: const void * (*value_text16)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: const void * (*value_text16be)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: const void * (*value_text16le)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: int (*value_type)(sqlite3_value*); dbda8d6ce9 2007-07-21 drh: char *(*vmprintf)(const char*,va_list); c287665ba8 2007-09-14 drh: /* Added ??? */ dbda8d6ce9 2007-07-21 drh: int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); c287665ba8 2007-09-14 drh: /* Added by 3.3.13 */ dbda8d6ce9 2007-07-21 drh: int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); dbda8d6ce9 2007-07-21 drh: int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); dbda8d6ce9 2007-07-21 drh: int (*clear_bindings)(sqlite3_stmt*); c287665ba8 2007-09-14 drh: /* Added by 3.4.1 */ d8590e093f 2007-07-24 drh: int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *)); c287665ba8 2007-09-14 drh: /* Added by 3.5.0 */ c287665ba8 2007-09-14 drh: int (*bind_zeroblob)(sqlite3_stmt*,int,int); c287665ba8 2007-09-14 drh: int (*blob_bytes)(sqlite3_blob*); c287665ba8 2007-09-14 drh: int (*blob_close)(sqlite3_blob*); c287665ba8 2007-09-14 drh: int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**); c287665ba8 2007-09-14 drh: int (*blob_read)(sqlite3_blob*,void*,int,int); c287665ba8 2007-09-14 drh: int (*blob_write)(sqlite3_blob*,const void*,int,int); c287665ba8 2007-09-14 drh: int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*)); c287665ba8 2007-09-14 drh: int (*file_control)(sqlite3*,const char*,int,void*); c287665ba8 2007-09-14 drh: sqlite3_int64 (*memory_highwater)(int); c287665ba8 2007-09-14 drh: sqlite3_int64 (*memory_used)(void); c287665ba8 2007-09-14 drh: sqlite3_mutex *(*mutex_alloc)(int); c287665ba8 2007-09-14 drh: void (*mutex_enter)(sqlite3_mutex*); c287665ba8 2007-09-14 drh: void (*mutex_free)(sqlite3_mutex*); c287665ba8 2007-09-14 drh: void (*mutex_leave)(sqlite3_mutex*); c287665ba8 2007-09-14 drh: int (*mutex_try)(sqlite3_mutex*); c287665ba8 2007-09-14 drh: int (*open_v2)(const char*,sqlite3**,int,const char*); c287665ba8 2007-09-14 drh: int (*release_memory)(int); c287665ba8 2007-09-14 drh: void (*result_error_nomem)(sqlite3_context*); c287665ba8 2007-09-14 drh: void (*result_error_toobig)(sqlite3_context*); c287665ba8 2007-09-14 drh: int (*sleep)(int); c287665ba8 2007-09-14 drh: void (*soft_heap_limit)(int); c287665ba8 2007-09-14 drh: sqlite3_vfs *(*vfs_find)(const char*); c287665ba8 2007-09-14 drh: int (*vfs_register)(sqlite3_vfs*,int); c287665ba8 2007-09-14 drh: int (*vfs_unregister)(sqlite3_vfs*); dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following macros redefine the API routines so that they are dbda8d6ce9 2007-07-21 drh: ** redirected throught the global sqlite3_api structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This header file is also used by the loadext.c source file dbda8d6ce9 2007-07-21 drh: ** (part of the main SQLite library - not an extension) so that dbda8d6ce9 2007-07-21 drh: ** it can get access to the sqlite3_api_routines structure dbda8d6ce9 2007-07-21 drh: ** definition. But the main library does not want to redefine dbda8d6ce9 2007-07-21 drh: ** the API. So the redefinition macros are only valid if the dbda8d6ce9 2007-07-21 drh: ** SQLITE_CORE macros is undefined. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_CORE dbda8d6ce9 2007-07-21 drh: #define sqlite3_aggregate_context sqlite3_api->aggregate_context dbda8d6ce9 2007-07-21 drh: #define sqlite3_aggregate_count sqlite3_api->aggregate_count dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_blob sqlite3_api->bind_blob dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_double sqlite3_api->bind_double dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_int sqlite3_api->bind_int dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_int64 sqlite3_api->bind_int64 dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_null sqlite3_api->bind_null dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_text sqlite3_api->bind_text dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_text16 sqlite3_api->bind_text16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_bind_value sqlite3_api->bind_value dbda8d6ce9 2007-07-21 drh: #define sqlite3_busy_handler sqlite3_api->busy_handler dbda8d6ce9 2007-07-21 drh: #define sqlite3_busy_timeout sqlite3_api->busy_timeout dbda8d6ce9 2007-07-21 drh: #define sqlite3_changes sqlite3_api->changes dbda8d6ce9 2007-07-21 drh: #define sqlite3_close sqlite3_api->close dbda8d6ce9 2007-07-21 drh: #define sqlite3_collation_needed sqlite3_api->collation_needed dbda8d6ce9 2007-07-21 drh: #define sqlite3_collation_needed16 sqlite3_api->collation_needed16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_blob sqlite3_api->column_blob dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_bytes sqlite3_api->column_bytes dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_bytes16 sqlite3_api->column_bytes16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_count sqlite3_api->column_count dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_database_name sqlite3_api->column_database_name dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_database_name16 sqlite3_api->column_database_name16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_decltype sqlite3_api->column_decltype dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_decltype16 sqlite3_api->column_decltype16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_double sqlite3_api->column_double dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_int sqlite3_api->column_int dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_int64 sqlite3_api->column_int64 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_name sqlite3_api->column_name dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_name16 sqlite3_api->column_name16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_origin_name sqlite3_api->column_origin_name dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_table_name sqlite3_api->column_table_name dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_table_name16 sqlite3_api->column_table_name16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_text sqlite3_api->column_text dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_text16 sqlite3_api->column_text16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_type sqlite3_api->column_type dbda8d6ce9 2007-07-21 drh: #define sqlite3_column_value sqlite3_api->column_value dbda8d6ce9 2007-07-21 drh: #define sqlite3_commit_hook sqlite3_api->commit_hook dbda8d6ce9 2007-07-21 drh: #define sqlite3_complete sqlite3_api->complete dbda8d6ce9 2007-07-21 drh: #define sqlite3_complete16 sqlite3_api->complete16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_create_collation sqlite3_api->create_collation dbda8d6ce9 2007-07-21 drh: #define sqlite3_create_collation16 sqlite3_api->create_collation16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_create_function sqlite3_api->create_function dbda8d6ce9 2007-07-21 drh: #define sqlite3_create_function16 sqlite3_api->create_function16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_create_module sqlite3_api->create_module dbda8d6ce9 2007-07-21 drh: #define sqlite3_create_module_v2 sqlite3_api->create_module_v2 dbda8d6ce9 2007-07-21 drh: #define sqlite3_data_count sqlite3_api->data_count dbda8d6ce9 2007-07-21 drh: #define sqlite3_db_handle sqlite3_api->db_handle dbda8d6ce9 2007-07-21 drh: #define sqlite3_declare_vtab sqlite3_api->declare_vtab dbda8d6ce9 2007-07-21 drh: #define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache dbda8d6ce9 2007-07-21 drh: #define sqlite3_errcode sqlite3_api->errcode dbda8d6ce9 2007-07-21 drh: #define sqlite3_errmsg sqlite3_api->errmsg dbda8d6ce9 2007-07-21 drh: #define sqlite3_errmsg16 sqlite3_api->errmsg16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_exec sqlite3_api->exec dbda8d6ce9 2007-07-21 drh: #define sqlite3_expired sqlite3_api->expired dbda8d6ce9 2007-07-21 drh: #define sqlite3_finalize sqlite3_api->finalize dbda8d6ce9 2007-07-21 drh: #define sqlite3_free sqlite3_api->free dbda8d6ce9 2007-07-21 drh: #define sqlite3_free_table sqlite3_api->free_table dbda8d6ce9 2007-07-21 drh: #define sqlite3_get_autocommit sqlite3_api->get_autocommit dbda8d6ce9 2007-07-21 drh: #define sqlite3_get_auxdata sqlite3_api->get_auxdata dbda8d6ce9 2007-07-21 drh: #define sqlite3_get_table sqlite3_api->get_table dbda8d6ce9 2007-07-21 drh: #define sqlite3_global_recover sqlite3_api->global_recover dbda8d6ce9 2007-07-21 drh: #define sqlite3_interrupt sqlite3_api->interruptx dbda8d6ce9 2007-07-21 drh: #define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid dbda8d6ce9 2007-07-21 drh: #define sqlite3_libversion sqlite3_api->libversion dbda8d6ce9 2007-07-21 drh: #define sqlite3_libversion_number sqlite3_api->libversion_number dbda8d6ce9 2007-07-21 drh: #define sqlite3_malloc sqlite3_api->malloc dbda8d6ce9 2007-07-21 drh: #define sqlite3_mprintf sqlite3_api->mprintf dbda8d6ce9 2007-07-21 drh: #define sqlite3_open sqlite3_api->open dbda8d6ce9 2007-07-21 drh: #define sqlite3_open16 sqlite3_api->open16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_prepare sqlite3_api->prepare dbda8d6ce9 2007-07-21 drh: #define sqlite3_prepare16 sqlite3_api->prepare16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 dbda8d6ce9 2007-07-21 drh: #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 dbda8d6ce9 2007-07-21 drh: #define sqlite3_profile sqlite3_api->profile dbda8d6ce9 2007-07-21 drh: #define sqlite3_progress_handler sqlite3_api->progress_handler dbda8d6ce9 2007-07-21 drh: #define sqlite3_realloc sqlite3_api->realloc dbda8d6ce9 2007-07-21 drh: #define sqlite3_reset sqlite3_api->reset dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_blob sqlite3_api->result_blob dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_double sqlite3_api->result_double dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_error sqlite3_api->result_error dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_error16 sqlite3_api->result_error16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_int sqlite3_api->result_int dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_int64 sqlite3_api->result_int64 dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_null sqlite3_api->result_null dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_text sqlite3_api->result_text dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_text16 sqlite3_api->result_text16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_text16be sqlite3_api->result_text16be dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_text16le sqlite3_api->result_text16le dbda8d6ce9 2007-07-21 drh: #define sqlite3_result_value sqlite3_api->result_value dbda8d6ce9 2007-07-21 drh: #define sqlite3_rollback_hook sqlite3_api->rollback_hook dbda8d6ce9 2007-07-21 drh: #define sqlite3_set_authorizer sqlite3_api->set_authorizer dbda8d6ce9 2007-07-21 drh: #define sqlite3_set_auxdata sqlite3_api->set_auxdata dbda8d6ce9 2007-07-21 drh: #define sqlite3_snprintf sqlite3_api->snprintf dbda8d6ce9 2007-07-21 drh: #define sqlite3_step sqlite3_api->step dbda8d6ce9 2007-07-21 drh: #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata dbda8d6ce9 2007-07-21 drh: #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup dbda8d6ce9 2007-07-21 drh: #define sqlite3_total_changes sqlite3_api->total_changes dbda8d6ce9 2007-07-21 drh: #define sqlite3_trace sqlite3_api->trace dbda8d6ce9 2007-07-21 drh: #define sqlite3_transfer_bindings sqlite3_api->transfer_bindings dbda8d6ce9 2007-07-21 drh: #define sqlite3_update_hook sqlite3_api->update_hook dbda8d6ce9 2007-07-21 drh: #define sqlite3_user_data sqlite3_api->user_data dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_blob sqlite3_api->value_blob dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_bytes sqlite3_api->value_bytes dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_bytes16 sqlite3_api->value_bytes16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_double sqlite3_api->value_double dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_int sqlite3_api->value_int dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_int64 sqlite3_api->value_int64 dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_numeric_type sqlite3_api->value_numeric_type dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_text sqlite3_api->value_text dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_text16 sqlite3_api->value_text16 dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_text16be sqlite3_api->value_text16be dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_text16le sqlite3_api->value_text16le dbda8d6ce9 2007-07-21 drh: #define sqlite3_value_type sqlite3_api->value_type dbda8d6ce9 2007-07-21 drh: #define sqlite3_vmprintf sqlite3_api->vmprintf dbda8d6ce9 2007-07-21 drh: #define sqlite3_overload_function sqlite3_api->overload_function dbda8d6ce9 2007-07-21 drh: #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 dbda8d6ce9 2007-07-21 drh: #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 dbda8d6ce9 2007-07-21 drh: #define sqlite3_clear_bindings sqlite3_api->clear_bindings c287665ba8 2007-09-14 drh: #define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob c287665ba8 2007-09-14 drh: #define sqlite3_blob_bytes sqlite3_api->blob_bytes c287665ba8 2007-09-14 drh: #define sqlite3_blob_close sqlite3_api->blob_close c287665ba8 2007-09-14 drh: #define sqlite3_blob_open sqlite3_api->blob_open c287665ba8 2007-09-14 drh: #define sqlite3_blob_read sqlite3_api->blob_read c287665ba8 2007-09-14 drh: #define sqlite3_blob_write sqlite3_api->blob_write c287665ba8 2007-09-14 drh: #define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 c287665ba8 2007-09-14 drh: #define sqlite3_file_control sqlite3_api->file_control c287665ba8 2007-09-14 drh: #define sqlite3_memory_highwater sqlite3_api->memory_highwater c287665ba8 2007-09-14 drh: #define sqlite3_memory_used sqlite3_api->memory_used c287665ba8 2007-09-14 drh: #define sqlite3_mutex_alloc sqlite3_api->mutex_alloc c287665ba8 2007-09-14 drh: #define sqlite3_mutex_enter sqlite3_api->mutex_enter c287665ba8 2007-09-14 drh: #define sqlite3_mutex_free sqlite3_api->mutex_free c287665ba8 2007-09-14 drh: #define sqlite3_mutex_leave sqlite3_api->mutex_leave c287665ba8 2007-09-14 drh: #define sqlite3_mutex_try sqlite3_api->mutex_try c287665ba8 2007-09-14 drh: #define sqlite3_open_v2 sqlite3_api->open_v2 c287665ba8 2007-09-14 drh: #define sqlite3_release_memory sqlite3_api->release_memory c287665ba8 2007-09-14 drh: #define sqlite3_result_error_nomem sqlite3_api->result_error_nomem c287665ba8 2007-09-14 drh: #define sqlite3_result_error_toobig sqlite3_api->result_error_toobig c287665ba8 2007-09-14 drh: #define sqlite3_sleep sqlite3_api->sleep c287665ba8 2007-09-14 drh: #define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit c287665ba8 2007-09-14 drh: #define sqlite3_vfs_find sqlite3_api->vfs_find c287665ba8 2007-09-14 drh: #define sqlite3_vfs_register sqlite3_api->vfs_register c287665ba8 2007-09-14 drh: #define sqlite3_vfs_unregister sqlite3_api->vfs_unregister dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_CORE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api; dbda8d6ce9 2007-07-21 drh: #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* _SQLITE3EXT_H_ */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of sqlite3ext.h ******************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in loadext.c ********************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Some API routines are omitted when various features are dbda8d6ce9 2007-07-21 drh: ** excluded from a build of SQLite. Substitute a NULL pointer dbda8d6ce9 2007-07-21 drh: ** for any missing APIs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_ENABLE_COLUMN_METADATA dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_database_name 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_database_name16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_table_name 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_table_name16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_origin_name 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_origin_name16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_table_column_metadata 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: # define sqlite3_set_authorizer 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: # define sqlite3_bind_text16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_collation_needed16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_decltype16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_name16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_text16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_complete16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_create_collation16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_create_function16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_errmsg16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_open16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_prepare16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_prepare16_v2 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_result_error16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_result_text16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_result_text16be 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_result_text16le 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_value_text16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_value_text16be 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_value_text16le 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_database_name16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_table_name16 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_column_origin_name16 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_COMPLETE dbda8d6ce9 2007-07-21 drh: # define sqlite3_complete 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_complete16 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_PROGRESS_CALLBACK dbda8d6ce9 2007-07-21 drh: # define sqlite3_progress_handler 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: # define sqlite3_create_module 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_create_module_v2 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_declare_vtab 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: # define sqlite3_enable_shared_cache 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_TRACE dbda8d6ce9 2007-07-21 drh: # define sqlite3_profile 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_trace 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_GET_TABLE dbda8d6ce9 2007-07-21 drh: # define sqlite3_free_table 0 dbda8d6ce9 2007-07-21 drh: # define sqlite3_get_table 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following structure contains pointers to all SQLite API routines. dbda8d6ce9 2007-07-21 drh: ** A pointer to this structure is passed into extensions when they are dbda8d6ce9 2007-07-21 drh: ** loaded so that the extension can make calls back into the SQLite dbda8d6ce9 2007-07-21 drh: ** library. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When adding new APIs, add them to the bottom of this structure dbda8d6ce9 2007-07-21 drh: ** in order to preserve backwards compatibility. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Extensions that use newer APIs should first call the dbda8d6ce9 2007-07-21 drh: ** sqlite3_libversion_number() to make sure that the API they dbda8d6ce9 2007-07-21 drh: ** intend to use is supported by the library. Extensions should dbda8d6ce9 2007-07-21 drh: ** also check to make sure that the pointer to the function is dbda8d6ce9 2007-07-21 drh: ** not NULL before calling it. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const sqlite3_api_routines sqlite3_apis = { dbda8d6ce9 2007-07-21 drh: sqlite3_aggregate_context, dbda8d6ce9 2007-07-21 drh: sqlite3_aggregate_count, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_blob, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_double, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_int, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_int64, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_null, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_parameter_count, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_parameter_index, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_parameter_name, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_text, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_text16, dbda8d6ce9 2007-07-21 drh: sqlite3_bind_value, dbda8d6ce9 2007-07-21 drh: sqlite3_busy_handler, dbda8d6ce9 2007-07-21 drh: sqlite3_busy_timeout, dbda8d6ce9 2007-07-21 drh: sqlite3_changes, dbda8d6ce9 2007-07-21 drh: sqlite3_close, dbda8d6ce9 2007-07-21 drh: sqlite3_collation_needed, dbda8d6ce9 2007-07-21 drh: sqlite3_collation_needed16, dbda8d6ce9 2007-07-21 drh: sqlite3_column_blob, dbda8d6ce9 2007-07-21 drh: sqlite3_column_bytes, dbda8d6ce9 2007-07-21 drh: sqlite3_column_bytes16, dbda8d6ce9 2007-07-21 drh: sqlite3_column_count, dbda8d6ce9 2007-07-21 drh: sqlite3_column_database_name, dbda8d6ce9 2007-07-21 drh: sqlite3_column_database_name16, dbda8d6ce9 2007-07-21 drh: sqlite3_column_decltype, dbda8d6ce9 2007-07-21 drh: sqlite3_column_decltype16, dbda8d6ce9 2007-07-21 drh: sqlite3_column_double, dbda8d6ce9 2007-07-21 drh: sqlite3_column_int, dbda8d6ce9 2007-07-21 drh: sqlite3_column_int64, dbda8d6ce9 2007-07-21 drh: sqlite3_column_name, dbda8d6ce9 2007-07-21 drh: sqlite3_column_name16, dbda8d6ce9 2007-07-21 drh: sqlite3_column_origin_name, dbda8d6ce9 2007-07-21 drh: sqlite3_column_origin_name16, dbda8d6ce9 2007-07-21 drh: sqlite3_column_table_name, dbda8d6ce9 2007-07-21 drh: sqlite3_column_table_name16, dbda8d6ce9 2007-07-21 drh: sqlite3_column_text, dbda8d6ce9 2007-07-21 drh: sqlite3_column_text16, dbda8d6ce9 2007-07-21 drh: sqlite3_column_type, dbda8d6ce9 2007-07-21 drh: sqlite3_column_value, dbda8d6ce9 2007-07-21 drh: sqlite3_commit_hook, dbda8d6ce9 2007-07-21 drh: sqlite3_complete, dbda8d6ce9 2007-07-21 drh: sqlite3_complete16, dbda8d6ce9 2007-07-21 drh: sqlite3_create_collation, dbda8d6ce9 2007-07-21 drh: sqlite3_create_collation16, dbda8d6ce9 2007-07-21 drh: sqlite3_create_function, dbda8d6ce9 2007-07-21 drh: sqlite3_create_function16, dbda8d6ce9 2007-07-21 drh: sqlite3_create_module, dbda8d6ce9 2007-07-21 drh: sqlite3_data_count, dbda8d6ce9 2007-07-21 drh: sqlite3_db_handle, dbda8d6ce9 2007-07-21 drh: sqlite3_declare_vtab, dbda8d6ce9 2007-07-21 drh: sqlite3_enable_shared_cache, dbda8d6ce9 2007-07-21 drh: sqlite3_errcode, dbda8d6ce9 2007-07-21 drh: sqlite3_errmsg, dbda8d6ce9 2007-07-21 drh: sqlite3_errmsg16, dbda8d6ce9 2007-07-21 drh: sqlite3_exec, dbda8d6ce9 2007-07-21 drh: sqlite3_expired, dbda8d6ce9 2007-07-21 drh: sqlite3_finalize, dbda8d6ce9 2007-07-21 drh: sqlite3_free, dbda8d6ce9 2007-07-21 drh: sqlite3_free_table, dbda8d6ce9 2007-07-21 drh: sqlite3_get_autocommit, dbda8d6ce9 2007-07-21 drh: sqlite3_get_auxdata, dbda8d6ce9 2007-07-21 drh: sqlite3_get_table, dbda8d6ce9 2007-07-21 drh: 0, /* Was sqlite3_global_recover(), but that function is deprecated */ dbda8d6ce9 2007-07-21 drh: sqlite3_interrupt, dbda8d6ce9 2007-07-21 drh: sqlite3_last_insert_rowid, dbda8d6ce9 2007-07-21 drh: sqlite3_libversion, dbda8d6ce9 2007-07-21 drh: sqlite3_libversion_number, dbda8d6ce9 2007-07-21 drh: sqlite3_malloc, dbda8d6ce9 2007-07-21 drh: sqlite3_mprintf, dbda8d6ce9 2007-07-21 drh: sqlite3_open, dbda8d6ce9 2007-07-21 drh: sqlite3_open16, dbda8d6ce9 2007-07-21 drh: sqlite3_prepare, dbda8d6ce9 2007-07-21 drh: sqlite3_prepare16, dbda8d6ce9 2007-07-21 drh: sqlite3_profile, dbda8d6ce9 2007-07-21 drh: sqlite3_progress_handler, dbda8d6ce9 2007-07-21 drh: sqlite3_realloc, dbda8d6ce9 2007-07-21 drh: sqlite3_reset, dbda8d6ce9 2007-07-21 drh: sqlite3_result_blob, dbda8d6ce9 2007-07-21 drh: sqlite3_result_double, dbda8d6ce9 2007-07-21 drh: sqlite3_result_error, dbda8d6ce9 2007-07-21 drh: sqlite3_result_error16, dbda8d6ce9 2007-07-21 drh: sqlite3_result_int, dbda8d6ce9 2007-07-21 drh: sqlite3_result_int64, dbda8d6ce9 2007-07-21 drh: sqlite3_result_null, dbda8d6ce9 2007-07-21 drh: sqlite3_result_text, dbda8d6ce9 2007-07-21 drh: sqlite3_result_text16, dbda8d6ce9 2007-07-21 drh: sqlite3_result_text16be, dbda8d6ce9 2007-07-21 drh: sqlite3_result_text16le, dbda8d6ce9 2007-07-21 drh: sqlite3_result_value, dbda8d6ce9 2007-07-21 drh: sqlite3_rollback_hook, dbda8d6ce9 2007-07-21 drh: sqlite3_set_authorizer, dbda8d6ce9 2007-07-21 drh: sqlite3_set_auxdata, dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf, dbda8d6ce9 2007-07-21 drh: sqlite3_step, dbda8d6ce9 2007-07-21 drh: sqlite3_table_column_metadata, dbda8d6ce9 2007-07-21 drh: sqlite3_thread_cleanup, dbda8d6ce9 2007-07-21 drh: sqlite3_total_changes, dbda8d6ce9 2007-07-21 drh: sqlite3_trace, dbda8d6ce9 2007-07-21 drh: sqlite3_transfer_bindings, dbda8d6ce9 2007-07-21 drh: sqlite3_update_hook, dbda8d6ce9 2007-07-21 drh: sqlite3_user_data, dbda8d6ce9 2007-07-21 drh: sqlite3_value_blob, dbda8d6ce9 2007-07-21 drh: sqlite3_value_bytes, dbda8d6ce9 2007-07-21 drh: sqlite3_value_bytes16, dbda8d6ce9 2007-07-21 drh: sqlite3_value_double, dbda8d6ce9 2007-07-21 drh: sqlite3_value_int, dbda8d6ce9 2007-07-21 drh: sqlite3_value_int64, dbda8d6ce9 2007-07-21 drh: sqlite3_value_numeric_type, dbda8d6ce9 2007-07-21 drh: sqlite3_value_text, dbda8d6ce9 2007-07-21 drh: sqlite3_value_text16, dbda8d6ce9 2007-07-21 drh: sqlite3_value_text16be, dbda8d6ce9 2007-07-21 drh: sqlite3_value_text16le, dbda8d6ce9 2007-07-21 drh: sqlite3_value_type, dbda8d6ce9 2007-07-21 drh: sqlite3_vmprintf, dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The original API set ends here. All extensions can call any dbda8d6ce9 2007-07-21 drh: ** of the APIs above provided that the pointer is not NULL. But dbda8d6ce9 2007-07-21 drh: ** before calling APIs that follow, extension should check the dbda8d6ce9 2007-07-21 drh: ** sqlite3_libversion_number() to make sure they are dealing with dbda8d6ce9 2007-07-21 drh: ** a library that is new enough to support that API. dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3_overload_function, dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Added after 3.3.13 dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3_prepare_v2, dbda8d6ce9 2007-07-21 drh: sqlite3_prepare16_v2, dbda8d6ce9 2007-07-21 drh: sqlite3_clear_bindings, d8590e093f 2007-07-24 drh: d8590e093f 2007-07-24 drh: /* d8590e093f 2007-07-24 drh: ** Added for 3.4.1 d8590e093f 2007-07-24 drh: */ d8590e093f 2007-07-24 drh: sqlite3_create_module_v2, d8590e093f 2007-07-24 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Added for 3.5.0 c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: sqlite3_bind_zeroblob, c287665ba8 2007-09-14 drh: sqlite3_blob_bytes, c287665ba8 2007-09-14 drh: sqlite3_blob_close, c287665ba8 2007-09-14 drh: sqlite3_blob_open, c287665ba8 2007-09-14 drh: sqlite3_blob_read, c287665ba8 2007-09-14 drh: sqlite3_blob_write, c287665ba8 2007-09-14 drh: sqlite3_create_collation_v2, c287665ba8 2007-09-14 drh: sqlite3_file_control, c287665ba8 2007-09-14 drh: sqlite3_memory_highwater, c287665ba8 2007-09-14 drh: sqlite3_memory_used, c287665ba8 2007-09-14 drh: #ifdef SQLITE_MUTEX_NOOP c287665ba8 2007-09-14 drh: 0, c287665ba8 2007-09-14 drh: 0, c287665ba8 2007-09-14 drh: 0, c287665ba8 2007-09-14 drh: 0, c287665ba8 2007-09-14 drh: 0, c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: sqlite3_mutex_alloc, c287665ba8 2007-09-14 drh: sqlite3_mutex_enter, c287665ba8 2007-09-14 drh: sqlite3_mutex_free, c287665ba8 2007-09-14 drh: sqlite3_mutex_leave, c287665ba8 2007-09-14 drh: sqlite3_mutex_try, c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: sqlite3_open_v2, c287665ba8 2007-09-14 drh: sqlite3_release_memory, c287665ba8 2007-09-14 drh: sqlite3_result_error_nomem, c287665ba8 2007-09-14 drh: sqlite3_result_error_toobig, c287665ba8 2007-09-14 drh: sqlite3_sleep, c287665ba8 2007-09-14 drh: sqlite3_soft_heap_limit, c287665ba8 2007-09-14 drh: sqlite3_vfs_find, c287665ba8 2007-09-14 drh: sqlite3_vfs_register, c287665ba8 2007-09-14 drh: sqlite3_vfs_unregister, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to load an SQLite extension library contained in the file dbda8d6ce9 2007-07-21 drh: ** zFile. The entry point is zProc. zProc may be 0 in which case a dbda8d6ce9 2007-07-21 drh: ** default entry point name (sqlite3_extension_init) is used. Use dbda8d6ce9 2007-07-21 drh: ** of the default name is recommended. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with dbda8d6ce9 2007-07-21 drh: ** error message text. The calling function should free this memory dbda8d6ce9 2007-07-21 drh: ** by calling sqlite3_free(). dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static int sqlite3LoadExtension( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Load the extension into this database connection */ dbda8d6ce9 2007-07-21 drh: const char *zFile, /* Name of the shared library containing extension */ dbda8d6ce9 2007-07-21 drh: const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ dbda8d6ce9 2007-07-21 drh: char **pzErrMsg /* Put error message here if not 0 */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs = db->pVfs; dbda8d6ce9 2007-07-21 drh: void *handle; dbda8d6ce9 2007-07-21 drh: int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); dbda8d6ce9 2007-07-21 drh: char *zErrmsg = 0; dbda8d6ce9 2007-07-21 drh: void **aHandle; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Ticket #1863. To avoid a creating security problems for older dbda8d6ce9 2007-07-21 drh: ** applications that relink against newer versions of SQLite, the dbda8d6ce9 2007-07-21 drh: ** ability to run load_extension is turned off by default. One dbda8d6ce9 2007-07-21 drh: ** must call sqlite3_enable_load_extension() to turn on extension dbda8d6ce9 2007-07-21 drh: ** loading. Otherwise you get the following error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (db->flags & SQLITE_LoadExtension)==0 ){ dbda8d6ce9 2007-07-21 drh: if( pzErrMsg ){ dbda8d6ce9 2007-07-21 drh: *pzErrMsg = sqlite3_mprintf("not authorized"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( zProc==0 ){ dbda8d6ce9 2007-07-21 drh: zProc = "sqlite3_extension_init"; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: handle = sqlite3OsDlOpen(pVfs, zFile); dbda8d6ce9 2007-07-21 drh: if( handle==0 ){ dbda8d6ce9 2007-07-21 drh: if( pzErrMsg ){ c287665ba8 2007-09-14 drh: char zErr[256]; c287665ba8 2007-09-14 drh: zErr[sizeof(zErr)-1] = '\0'; c287665ba8 2007-09-14 drh: sqlite3_snprintf(sizeof(zErr)-1, zErr, c287665ba8 2007-09-14 drh: "unable to open shared library [%s]", zFile); c287665ba8 2007-09-14 drh: sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr); c287665ba8 2007-09-14 drh: *pzErrMsg = sqlite3DbStrDup(db, zErr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) c287665ba8 2007-09-14 drh: sqlite3OsDlSym(pVfs, handle, zProc); dbda8d6ce9 2007-07-21 drh: if( xInit==0 ){ dbda8d6ce9 2007-07-21 drh: if( pzErrMsg ){ c287665ba8 2007-09-14 drh: char zErr[256]; c287665ba8 2007-09-14 drh: zErr[sizeof(zErr)-1] = '\0'; c287665ba8 2007-09-14 drh: sqlite3_snprintf(sizeof(zErr)-1, zErr, c287665ba8 2007-09-14 drh: "no entry point [%s] in shared library [%s]", zProc,zFile); c287665ba8 2007-09-14 drh: sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr); c287665ba8 2007-09-14 drh: *pzErrMsg = sqlite3DbStrDup(db, zErr); c287665ba8 2007-09-14 drh: sqlite3OsDlClose(pVfs, handle); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: }else if( xInit(db, &zErrmsg, &sqlite3_apis) ){ dbda8d6ce9 2007-07-21 drh: if( pzErrMsg ){ dbda8d6ce9 2007-07-21 drh: *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_free(zErrmsg); c287665ba8 2007-09-14 drh: sqlite3OsDlClose(pVfs, handle); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Append the new shared library handle to the db->aExtension array. */ dbda8d6ce9 2007-07-21 drh: db->nExtension++; c287665ba8 2007-09-14 drh: aHandle = sqlite3DbMallocZero(db, sizeof(handle)*db->nExtension); dbda8d6ce9 2007-07-21 drh: if( aHandle==0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( db->nExtension>0 ){ dbda8d6ce9 2007-07-21 drh: memcpy(aHandle, db->aExtension, sizeof(handle)*(db->nExtension-1)); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(db->aExtension); dbda8d6ce9 2007-07-21 drh: db->aExtension = aHandle; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: db->aExtension[db->nExtension-1] = handle; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_load_extension( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Load the extension into this database connection */ c287665ba8 2007-09-14 drh: const char *zFile, /* Name of the shared library containing extension */ c287665ba8 2007-09-14 drh: const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ c287665ba8 2007-09-14 drh: char **pzErrMsg /* Put error message here if not 0 */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: rc = sqlite3LoadExtension(db, zFile, zProc, pzErrMsg); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Call this routine when the database connection is closing in order dbda8d6ce9 2007-07-21 drh: ** to clean up loaded extensions dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: int i; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nExtension; i++){ c287665ba8 2007-09-14 drh: sqlite3OsDlClose(db->pVfs, db->aExtension[i]); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(db->aExtension); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Enable or disable extension loading. Extension loading is disabled by dbda8d6ce9 2007-07-21 drh: ** default so as not to open security holes in older applications. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: if( onoff ){ dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_LoadExtension; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: db->flags &= ~SQLITE_LoadExtension; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** The following object holds the list of automatically loaded c287665ba8 2007-09-14 drh: ** extensions. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER c287665ba8 2007-09-14 drh: ** mutex must be held while accessing this list. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static struct { c287665ba8 2007-09-14 drh: int nExt; /* Number of entries in aExt[] */ c287665ba8 2007-09-14 drh: void **aExt; /* Pointers to the extension init functions */ c287665ba8 2007-09-14 drh: } autoext = { 0, 0 }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a statically linked extension that is automatically dbda8d6ce9 2007-07-21 drh: ** loaded by every new database connection. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_auto_extension(void *xInit){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: for(i=0; i<autoext.nExt; i++){ c287665ba8 2007-09-14 drh: if( autoext.aExt[i]==xInit ) break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( i==autoext.nExt ){ c287665ba8 2007-09-14 drh: int nByte = (autoext.nExt+1)*sizeof(autoext.aExt[0]); c287665ba8 2007-09-14 drh: void **aNew; c287665ba8 2007-09-14 drh: aNew = sqlite3_realloc(autoext.aExt, nByte); c287665ba8 2007-09-14 drh: if( aNew==0 ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: autoext.aExt = aNew; c287665ba8 2007-09-14 drh: autoext.aExt[autoext.nExt] = xInit; c287665ba8 2007-09-14 drh: autoext.nExt++; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); dbda8d6ce9 2007-07-21 drh: assert( (rc&0xff)==rc ); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Reset the automatic extension loading mechanism. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_reset_auto_extension(void){ c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: sqlite3_free(autoext.aExt); c287665ba8 2007-09-14 drh: autoext.aExt = 0; c287665ba8 2007-09-14 drh: autoext.nExt = 0; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Load all automatic extensions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3AutoLoadExtensions(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int go = 1; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( autoext.nExt==0 ){ dbda8d6ce9 2007-07-21 drh: /* Common case: early out without every having to acquire a mutex */ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; go; i++){ dbda8d6ce9 2007-07-21 drh: char *zErrmsg = 0; c287665ba8 2007-09-14 drh: sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(mutex); c287665ba8 2007-09-14 drh: if( i>=autoext.nExt ){ dbda8d6ce9 2007-07-21 drh: xInit = 0; dbda8d6ce9 2007-07-21 drh: go = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) c287665ba8 2007-09-14 drh: autoext.aExt[i]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(mutex); dbda8d6ce9 2007-07-21 drh: if( xInit && xInit(db, &zErrmsg, &sqlite3_apis) ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_ERROR, dbda8d6ce9 2007-07-21 drh: "automatic extension loading failed: %s", zErrmsg); dbda8d6ce9 2007-07-21 drh: go = 0; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; c287665ba8 2007-09-14 drh: sqlite3_free(zErrmsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_LOAD_EXTENSION */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of loadext.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file pragma.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2003 April 6 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code used to implement the PRAGMA command. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: pragma.c,v 1.149 2007/08/31 18:34:59 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Ignore this whole file if pragmas are disabled dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Interpret the given string as a safety level. Return 0 for OFF, dbda8d6ce9 2007-07-21 drh: ** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or dbda8d6ce9 2007-07-21 drh: ** unrecognized string argument. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that the values returned are one less that the values that dbda8d6ce9 2007-07-21 drh: ** should be passed into sqlite3BtreeSetSafetyLevel(). The is done dbda8d6ce9 2007-07-21 drh: ** to support legacy SQL code. The safety level used to be boolean dbda8d6ce9 2007-07-21 drh: ** and older scripts may have used numbers 0 for OFF and 1 for ON. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getSafetyLevel(const char *z){ dbda8d6ce9 2007-07-21 drh: /* 123456789 123456789 */ dbda8d6ce9 2007-07-21 drh: static const char zText[] = "onoffalseyestruefull"; dbda8d6ce9 2007-07-21 drh: static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16}; dbda8d6ce9 2007-07-21 drh: static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4}; dbda8d6ce9 2007-07-21 drh: static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2}; dbda8d6ce9 2007-07-21 drh: int i, n; dbda8d6ce9 2007-07-21 drh: if( isdigit(*z) ){ dbda8d6ce9 2007-07-21 drh: return atoi(z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: n = strlen(z); dbda8d6ce9 2007-07-21 drh: for(i=0; i<sizeof(iLength); i++){ dbda8d6ce9 2007-07-21 drh: if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){ dbda8d6ce9 2007-07-21 drh: return iValue[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Interpret the given string as a boolean value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getBoolean(const char *z){ dbda8d6ce9 2007-07-21 drh: return getSafetyLevel(z)&1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Interpret the given string as a locking mode value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getLockingMode(const char *z){ dbda8d6ce9 2007-07-21 drh: if( z ){ dbda8d6ce9 2007-07-21 drh: if( 0==sqlite3StrICmp(z, "exclusive") ) return PAGER_LOCKINGMODE_EXCLUSIVE; dbda8d6ce9 2007-07-21 drh: if( 0==sqlite3StrICmp(z, "normal") ) return PAGER_LOCKINGMODE_NORMAL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return PAGER_LOCKINGMODE_QUERY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Interpret the given string as an auto-vacuum mode value. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following strings, "none", "full" and "incremental" are dbda8d6ce9 2007-07-21 drh: ** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getAutoVacuum(const char *z){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE; dbda8d6ce9 2007-07-21 drh: if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL; dbda8d6ce9 2007-07-21 drh: if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR; dbda8d6ce9 2007-07-21 drh: i = atoi(z); dbda8d6ce9 2007-07-21 drh: return ((i>=0&&i<=2)?i:0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* ifndef SQLITE_OMIT_AUTOVACUUM */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Interpret the given string as a temp db location. Return 1 for file dbda8d6ce9 2007-07-21 drh: ** backed temporary databases, 2 for the Red-Black tree in memory database dbda8d6ce9 2007-07-21 drh: ** and 0 to use the compile-time default. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getTempStore(const char *z){ dbda8d6ce9 2007-07-21 drh: if( z[0]>='0' && z[0]<='2' ){ dbda8d6ce9 2007-07-21 drh: return z[0] - '0'; dbda8d6ce9 2007-07-21 drh: }else if( sqlite3StrICmp(z, "file")==0 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: }else if( sqlite3StrICmp(z, "memory")==0 ){ dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_PAGER_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invalidate temp storage, either when the temp storage is changed dbda8d6ce9 2007-07-21 drh: ** from default, or when 'file' and the temp_store_directory has changed dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int invalidateTempStorage(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: if( db->aDb[1].pBt!=0 ){ dbda8d6ce9 2007-07-21 drh: if( !db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "temporary storage cannot be changed " dbda8d6ce9 2007-07-21 drh: "from within a transaction"); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3BtreeClose(db->aDb[1].pBt); dbda8d6ce9 2007-07-21 drh: db->aDb[1].pBt = 0; dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_PAGER_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the TEMP database is open, close it and mark the database schema dbda8d6ce9 2007-07-21 drh: ** as needing reloading. This must be done when using the TEMP_STORE dbda8d6ce9 2007-07-21 drh: ** or DEFAULT_TEMP_STORE pragmas. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int changeTempStorage(Parse *pParse, const char *zStorageType){ dbda8d6ce9 2007-07-21 drh: int ts = getTempStore(zStorageType); dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: if( db->temp_store==ts ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( invalidateTempStorage( pParse ) != SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db->temp_store = ts; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_PAGER_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code to return a single integer value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void returnSingleInt(Parse *pParse, const char *zLabel, int value){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, value, 0); dbda8d6ce9 2007-07-21 drh: if( pParse->explain==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLAG_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if zRight and zLeft refer to a pragma that queries dbda8d6ce9 2007-07-21 drh: ** or changes one of the flags in db->flags. Return 1 if so and 0 if not. dbda8d6ce9 2007-07-21 drh: ** Also, implement the pragma. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){ dbda8d6ce9 2007-07-21 drh: static const struct sPragmaType { dbda8d6ce9 2007-07-21 drh: const char *zName; /* Name of the pragma */ dbda8d6ce9 2007-07-21 drh: int mask; /* Mask for the db->flags value */ dbda8d6ce9 2007-07-21 drh: } aPragma[] = { dbda8d6ce9 2007-07-21 drh: { "full_column_names", SQLITE_FullColNames }, dbda8d6ce9 2007-07-21 drh: { "short_column_names", SQLITE_ShortColNames }, dbda8d6ce9 2007-07-21 drh: { "count_changes", SQLITE_CountRows }, dbda8d6ce9 2007-07-21 drh: { "empty_result_callbacks", SQLITE_NullCallback }, dbda8d6ce9 2007-07-21 drh: { "legacy_file_format", SQLITE_LegacyFileFmt }, dbda8d6ce9 2007-07-21 drh: { "fullfsync", SQLITE_FullFSync }, dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: { "sql_trace", SQLITE_SqlTrace }, dbda8d6ce9 2007-07-21 drh: { "vdbe_listing", SQLITE_VdbeListing }, dbda8d6ce9 2007-07-21 drh: { "vdbe_trace", SQLITE_VdbeTrace }, dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_CHECK dbda8d6ce9 2007-07-21 drh: { "ignore_check_constraints", SQLITE_IgnoreChecks }, dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: /* The following is VERY experimental */ dbda8d6ce9 2007-07-21 drh: { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode }, dbda8d6ce9 2007-07-21 drh: { "omit_readlock", SQLITE_NoReadlock }, dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted dbda8d6ce9 2007-07-21 drh: ** flag if there are any active statements. */ dbda8d6ce9 2007-07-21 drh: { "read_uncommitted", SQLITE_ReadUncommitted }, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: const struct sPragmaType *p; dbda8d6ce9 2007-07-21 drh: for(i=0, p=aPragma; i<sizeof(aPragma)/sizeof(aPragma[0]); i++, p++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, p->zName)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: if( zRight==0 ){ dbda8d6ce9 2007-07-21 drh: returnSingleInt(pParse, p->zName, (db->flags & p->mask)!=0 ); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( getBoolean(zRight) ){ dbda8d6ce9 2007-07-21 drh: db->flags |= p->mask; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: db->flags &= ~p->mask; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_FLAG_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Process a pragma statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Pragmas are of this form: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]id [= value] dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The identifier might also be a string. The value is a string, and dbda8d6ce9 2007-07-21 drh: ** identifier, or a number. If minusFlag is true, then the value is dbda8d6ce9 2007-07-21 drh: ** a number that was preceded by a minus sign. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the left side is "database.id" then pId1 is the database name dbda8d6ce9 2007-07-21 drh: ** and pId2 is the id. If the left side is just "id" then pId1 is the dbda8d6ce9 2007-07-21 drh: ** id and pId2 is any empty string. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Pragma( dbda8d6ce9 2007-07-21 drh: Parse *pParse, dbda8d6ce9 2007-07-21 drh: Token *pId1, /* First part of [database.]id field */ dbda8d6ce9 2007-07-21 drh: Token *pId2, /* Second part of [database.]id field, or NULL */ dbda8d6ce9 2007-07-21 drh: Token *pValue, /* Token for <value>, or NULL */ dbda8d6ce9 2007-07-21 drh: int minusFlag /* True if a '-' sign preceded <value> */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */ dbda8d6ce9 2007-07-21 drh: char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */ dbda8d6ce9 2007-07-21 drh: const char *zDb = 0; /* The database name */ dbda8d6ce9 2007-07-21 drh: Token *pId; /* Pointer to <id> token */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Database index for <database> */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: Db *pDb; dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Interpret the [database.] part of the pragma statement. iDb is the dbda8d6ce9 2007-07-21 drh: ** index of the database this pragma is being applied to in db.aDb[]. */ dbda8d6ce9 2007-07-21 drh: iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId); dbda8d6ce9 2007-07-21 drh: if( iDb<0 ) return; dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the temp database has been explicitly named as part of the dbda8d6ce9 2007-07-21 drh: ** pragma, make sure it is open. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: zLeft = sqlite3NameFromToken(db, pId); dbda8d6ce9 2007-07-21 drh: if( !zLeft ) return; dbda8d6ce9 2007-07-21 drh: if( minusFlag ){ c287665ba8 2007-09-14 drh: zRight = sqlite3MPrintf(db, "-%T", pValue); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: zRight = sqlite3NameFromToken(db, pValue); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zDb = ((iDb>0)?pDb->zName:0); dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ dbda8d6ce9 2007-07-21 drh: goto pragma_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]default_cache_size dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]default_cache_size=N dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first form reports the current persistent setting for the dbda8d6ce9 2007-07-21 drh: ** page cache size. The value returned is the maximum number of dbda8d6ce9 2007-07-21 drh: ** pages in the page cache. The second form sets both the current dbda8d6ce9 2007-07-21 drh: ** page cache size value and the persistent page cache size value dbda8d6ce9 2007-07-21 drh: ** stored in the database file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The default cache size is stored in meta-value 2 of page 1 of the dbda8d6ce9 2007-07-21 drh: ** database file. The cache size is actually the absolute value of dbda8d6ce9 2007-07-21 drh: ** this memory location. The sign of meta-value 2 determines the dbda8d6ce9 2007-07-21 drh: ** synchronous setting. A negative value means synchronous is off dbda8d6ce9 2007-07-21 drh: ** and a positive value means synchronous is on. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ dbda8d6ce9 2007-07-21 drh: static const VdbeOpList getCacheSize[] = { dbda8d6ce9 2007-07-21 drh: { OP_ReadCookie, 0, 2, 0}, /* 0 */ dbda8d6ce9 2007-07-21 drh: { OP_AbsValue, 0, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Dup, 0, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Integer, 0, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Ne, 0, 6, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Integer, 0, 0, 0}, /* 5 */ dbda8d6ce9 2007-07-21 drh: { OP_Callback, 1, 0, 0}, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; c287665ba8 2007-09-14 drh: sqlite3VdbeUsesBtree(v, iDb); dbda8d6ce9 2007-07-21 drh: if( !zRight ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr+5, SQLITE_DEFAULT_CACHE_SIZE); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int size = atoi(zRight); dbda8d6ce9 2007-07-21 drh: if( size<0 ) size = -size; dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, size, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Negative, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2); dbda8d6ce9 2007-07-21 drh: pDb->pSchema->cache_size = size; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]page_size dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]page_size=N dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first form reports the current setting for the dbda8d6ce9 2007-07-21 drh: ** database page size in bytes. The second form sets the dbda8d6ce9 2007-07-21 drh: ** database page size value. The value can only be set if dbda8d6ce9 2007-07-21 drh: ** the database has not yet been created. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft,"page_size")==0 ){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = pDb->pBt; dbda8d6ce9 2007-07-21 drh: if( !zRight ){ dbda8d6ce9 2007-07-21 drh: int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0; dbda8d6ce9 2007-07-21 drh: returnSingleInt(pParse, "page_size", size); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: /* Malloc may fail when setting the page-size, as there is an internal c287665ba8 2007-09-14 drh: ** buffer that the pager module resizes using sqlite3_realloc(). c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1) ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]max_page_count dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]max_page_count=N dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first form reports the current setting for the dbda8d6ce9 2007-07-21 drh: ** maximum number of pages in the database file. The dbda8d6ce9 2007-07-21 drh: ** second form attempts to change this setting. Both dbda8d6ce9 2007-07-21 drh: ** forms return the current setting. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft,"max_page_count")==0 ){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = pDb->pBt; dbda8d6ce9 2007-07-21 drh: int newMax = 0; dbda8d6ce9 2007-07-21 drh: if( zRight ){ dbda8d6ce9 2007-07-21 drh: newMax = atoi(zRight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pBt ){ dbda8d6ce9 2007-07-21 drh: newMax = sqlite3BtreeMaxPageCount(pBt, newMax); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: returnSingleInt(pParse, "max_page_count", newMax); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]locking_mode dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]locking_mode = (normal|exclusive) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){ dbda8d6ce9 2007-07-21 drh: const char *zRet = "normal"; dbda8d6ce9 2007-07-21 drh: int eMode = getLockingMode(zRight); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){ dbda8d6ce9 2007-07-21 drh: /* Simple "PRAGMA locking_mode;" statement. This is a query for dbda8d6ce9 2007-07-21 drh: ** the current default locking mode (which may be different to dbda8d6ce9 2007-07-21 drh: ** the locking-mode of the main database). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: eMode = db->dfltLockMode; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Pager *pPager; dbda8d6ce9 2007-07-21 drh: if( pId2->n==0 ){ dbda8d6ce9 2007-07-21 drh: /* This indicates that no database name was specified as part dbda8d6ce9 2007-07-21 drh: ** of the PRAGMA command. In this case the locking-mode must be dbda8d6ce9 2007-07-21 drh: ** set on all attached databases, as well as the main db file. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Also, the sqlite3.dfltLockMode variable is set so that dbda8d6ce9 2007-07-21 drh: ** any subsequently attached databases also use the specified dbda8d6ce9 2007-07-21 drh: ** locking mode. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int ii; dbda8d6ce9 2007-07-21 drh: assert(pDb==&db->aDb[0]); dbda8d6ce9 2007-07-21 drh: for(ii=2; ii<db->nDb; ii++){ dbda8d6ce9 2007-07-21 drh: pPager = sqlite3BtreePager(db->aDb[ii].pBt); dbda8d6ce9 2007-07-21 drh: sqlite3PagerLockingMode(pPager, eMode); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db->dfltLockMode = eMode; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPager = sqlite3BtreePager(pDb->pBt); dbda8d6ce9 2007-07-21 drh: eMode = sqlite3PagerLockingMode(pPager, eMode); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert(eMode==PAGER_LOCKINGMODE_NORMAL||eMode==PAGER_LOCKINGMODE_EXCLUSIVE); dbda8d6ce9 2007-07-21 drh: if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){ dbda8d6ce9 2007-07-21 drh: zRet = "exclusive"; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, zRet, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]auto_vacuum dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]auto_vacuum=N dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Get or set the (boolean) value of the database 'auto-vacuum' parameter. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft,"auto_vacuum")==0 ){ dbda8d6ce9 2007-07-21 drh: Btree *pBt = pDb->pBt; dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ){ dbda8d6ce9 2007-07-21 drh: goto pragma_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !zRight ){ dbda8d6ce9 2007-07-21 drh: int auto_vacuum = dbda8d6ce9 2007-07-21 drh: pBt ? sqlite3BtreeGetAutoVacuum(pBt) : SQLITE_DEFAULT_AUTOVACUUM; dbda8d6ce9 2007-07-21 drh: returnSingleInt(pParse, "auto_vacuum", auto_vacuum); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int eAuto = getAutoVacuum(zRight); dbda8d6ce9 2007-07-21 drh: if( eAuto>=0 ){ dbda8d6ce9 2007-07-21 drh: /* Call SetAutoVacuum() to set initialize the internal auto and dbda8d6ce9 2007-07-21 drh: ** incr-vacuum flags. This is required in case this connection dbda8d6ce9 2007-07-21 drh: ** creates the database file. It is important that it is created dbda8d6ce9 2007-07-21 drh: ** as an auto-vacuum capable db. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){ dbda8d6ce9 2007-07-21 drh: /* When setting the auto_vacuum mode to either "full" or dbda8d6ce9 2007-07-21 drh: ** "incremental", write the value of meta[6] in the database dbda8d6ce9 2007-07-21 drh: ** file. Before writing to meta[6], check that meta[3] indicates dbda8d6ce9 2007-07-21 drh: ** that this really is an auto-vacuum capable database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const VdbeOpList setMeta6[] = { dbda8d6ce9 2007-07-21 drh: { OP_Transaction, 0, 1, 0}, /* 0 */ dbda8d6ce9 2007-07-21 drh: { OP_ReadCookie, 0, 3, 0}, /* 1 */ dbda8d6ce9 2007-07-21 drh: { OP_If, 0, 0, 0}, /* 2 */ dbda8d6ce9 2007-07-21 drh: { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */ dbda8d6ce9 2007-07-21 drh: { OP_Integer, 0, 0, 0}, /* 4 */ dbda8d6ce9 2007-07-21 drh: { OP_SetCookie, 0, 6, 0}, /* 5 */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int iAddr; dbda8d6ce9 2007-07-21 drh: iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, iAddr, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, iAddr+1, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, iAddr+5, iDb); c287665ba8 2007-09-14 drh: sqlite3VdbeUsesBtree(v, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]incremental_vacuum(N) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Do N steps of incremental vacuuming on a database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft,"incremental_vacuum")==0 ){ dbda8d6ce9 2007-07-21 drh: int iLimit, addr; dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ){ dbda8d6ce9 2007-07-21 drh: goto pragma_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){ dbda8d6ce9 2007-07-21 drh: iLimit = 0x7fffffff; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, iLimit, 0); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IncrVacuum, iDb, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, -1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IfMemPos, 0, addr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]cache_size dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]cache_size=N dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first form reports the current local setting for the dbda8d6ce9 2007-07-21 drh: ** page cache size. The local setting can be different from dbda8d6ce9 2007-07-21 drh: ** the persistent cache size value that is stored in the database dbda8d6ce9 2007-07-21 drh: ** file itself. The value returned is the maximum number of dbda8d6ce9 2007-07-21 drh: ** pages in the page cache. The second form sets the local dbda8d6ce9 2007-07-21 drh: ** page cache size value. It does not change the persistent dbda8d6ce9 2007-07-21 drh: ** cache size stored on the disk so the cache size will revert dbda8d6ce9 2007-07-21 drh: ** to its default value when the database is closed and reopened. dbda8d6ce9 2007-07-21 drh: ** N should be a positive integer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft,"cache_size")==0 ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: if( !zRight ){ dbda8d6ce9 2007-07-21 drh: returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int size = atoi(zRight); dbda8d6ce9 2007-07-21 drh: if( size<0 ) size = -size; dbda8d6ce9 2007-07-21 drh: pDb->pSchema->cache_size = size; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA temp_store dbda8d6ce9 2007-07-21 drh: ** PRAGMA temp_store = "default"|"memory"|"file" dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return or set the local value of the temp_store flag. Changing dbda8d6ce9 2007-07-21 drh: ** the local value does not make changes to the disk file and the default dbda8d6ce9 2007-07-21 drh: ** value will be restored the next time the database is opened. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that it is possible for the library compile-time options to dbda8d6ce9 2007-07-21 drh: ** override this setting dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "temp_store")==0 ){ dbda8d6ce9 2007-07-21 drh: if( !zRight ){ dbda8d6ce9 2007-07-21 drh: returnSingleInt(pParse, "temp_store", db->temp_store); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: changeTempStorage(pParse, zRight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA temp_store_directory dbda8d6ce9 2007-07-21 drh: ** PRAGMA temp_store_directory = ""|"directory_name" dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return or set the local value of the temp_store_directory flag. Changing dbda8d6ce9 2007-07-21 drh: ** the value sets a specific directory to be used for temporary files. dbda8d6ce9 2007-07-21 drh: ** Setting to a null string reverts to the default temporary directory search. dbda8d6ce9 2007-07-21 drh: ** If temporary directory is changed, then invalidateTempStorage. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "temp_store_directory")==0 ){ dbda8d6ce9 2007-07-21 drh: if( !zRight ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3_temp_directory ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, dbda8d6ce9 2007-07-21 drh: "temp_store_directory", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3_temp_directory, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: if( zRight[0] c287665ba8 2007-09-14 drh: && !sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE) c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "not a writable directory"); dbda8d6ce9 2007-07-21 drh: goto pragma_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( TEMP_STORE==0 dbda8d6ce9 2007-07-21 drh: || (TEMP_STORE==1 && db->temp_store<=1) dbda8d6ce9 2007-07-21 drh: || (TEMP_STORE==2 && db->temp_store==1) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: invalidateTempStorage(pParse); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(sqlite3_temp_directory); dbda8d6ce9 2007-07-21 drh: if( zRight[0] ){ dbda8d6ce9 2007-07-21 drh: sqlite3_temp_directory = zRight; dbda8d6ce9 2007-07-21 drh: zRight = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_temp_directory = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]synchronous dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return or set the local value of the synchronous flag. Changing dbda8d6ce9 2007-07-21 drh: ** the local value does not make changes to the disk file and the dbda8d6ce9 2007-07-21 drh: ** default value will be restored the next time the database is dbda8d6ce9 2007-07-21 drh: ** opened. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft,"synchronous")==0 ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: if( !zRight ){ dbda8d6ce9 2007-07-21 drh: returnSingleInt(pParse, "synchronous", pDb->safety_level-1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( !db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "Safety level may not be changed inside a transaction"); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pDb->safety_level = getSafetyLevel(zRight)+1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLAG_PRAGMAS dbda8d6ce9 2007-07-21 drh: if( flagPragma(pParse, zLeft, zRight) ){ dbda8d6ce9 2007-07-21 drh: /* The flagPragma() subroutine also generates any necessary code dbda8d6ce9 2007-07-21 drh: ** there is nothing more to do here */ dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_FLAG_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA table_info(<table>) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return a single row for each column of the named table. The columns of dbda8d6ce9 2007-07-21 drh: ** the returned data set are: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** cid: Column id (numbered from left to right, starting at 0) dbda8d6ce9 2007-07-21 drh: ** name: Column name dbda8d6ce9 2007-07-21 drh: ** type: Column declaration type. dbda8d6ce9 2007-07-21 drh: ** notnull: True if 'NOT NULL' is part of column declaration dbda8d6ce9 2007-07-21 drh: ** dflt_value: The default value for the column, if any. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){ dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: pTab = sqlite3FindTable(db, zRight, zDb); dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int nHidden = 0; dbda8d6ce9 2007-07-21 drh: Column *pCol; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 6); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3ViewGetColumnNames(pParse, pTab); dbda8d6ce9 2007-07-21 drh: for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){ dbda8d6ce9 2007-07-21 drh: const Token *pDflt; dbda8d6ce9 2007-07-21 drh: if( IsHiddenColumn(pCol) ){ dbda8d6ce9 2007-07-21 drh: nHidden++; dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, i-nHidden, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, dbda8d6ce9 2007-07-21 drh: pCol->zType ? pCol->zType : "", 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0); dbda8d6ce9 2007-07-21 drh: if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, (char*)pDflt->z, pDflt->n); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 6, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "index_info")==0 && zRight ){ dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: pIdx = sqlite3FindIndex(db, zRight, zDb); dbda8d6ce9 2007-07-21 drh: if( pIdx ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: pTab = pIdx->pTable; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P3_STATIC); dbda8d6ce9 2007-07-21 drh: for(i=0; i<pIdx->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: int cnum = pIdx->aiColumn[i]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, i, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, cnum, 0); dbda8d6ce9 2007-07-21 drh: assert( pTab->nCol>cnum ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[cnum].zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 3, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "index_list")==0 && zRight ){ dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: pTab = sqlite3FindTable(db, zRight, zDb); dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: pIdx = pTab->pIndex; dbda8d6ce9 2007-07-21 drh: if( pIdx ){ dbda8d6ce9 2007-07-21 drh: int i = 0; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P3_STATIC); dbda8d6ce9 2007-07-21 drh: while(pIdx){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, i, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 3, 0); dbda8d6ce9 2007-07-21 drh: ++i; dbda8d6ce9 2007-07-21 drh: pIdx = pIdx->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "database_list")==0 ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P3_STATIC); dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: if( db->aDb[i].pBt==0 ) continue; dbda8d6ce9 2007-07-21 drh: assert( db->aDb[i].zName!=0 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, i, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, dbda8d6ce9 2007-07-21 drh: sqlite3BtreeGetFilename(db->aDb[i].pBt), 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 3, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "collation_list")==0 ){ dbda8d6ce9 2007-07-21 drh: int i = 0; dbda8d6ce9 2007-07-21 drh: HashElem *p; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC); dbda8d6ce9 2007-07-21 drh: for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = (CollSeq *)sqliteHashData(p); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, i++, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pColl->zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 2, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FOREIGN_KEY dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "foreign_key_list")==0 && zRight ){ dbda8d6ce9 2007-07-21 drh: FKey *pFK; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: pTab = sqlite3FindTable(db, zRight, zDb); dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: pFK = pTab->pFKey; dbda8d6ce9 2007-07-21 drh: if( pFK ){ dbda8d6ce9 2007-07-21 drh: int i = 0; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 5); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P3_STATIC); dbda8d6ce9 2007-07-21 drh: while(pFK){ dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: for(j=0; j<pFK->nCol; j++){ dbda8d6ce9 2007-07-21 drh: char *zCol = pFK->aCol[j].zCol; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, i, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, j, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, dbda8d6ce9 2007-07-21 drh: pTab->aCol[pFK->aCol[j].iFrom].zName, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, zCol ? OP_String8 : OP_Null, 0, 0, zCol, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 5, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: ++i; dbda8d6ce9 2007-07-21 drh: pFK = pFK->pNextFrom; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ dbda8d6ce9 2007-07-21 drh: if( zRight ){ dbda8d6ce9 2007-07-21 drh: if( getBoolean(zRight) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ParserTrace(stderr, "parser: "); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ParserTrace(0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Reinstall the LIKE and GLOB functions. The variant of LIKE dbda8d6ce9 2007-07-21 drh: ** used will be case sensitive or not depending on the RHS. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){ dbda8d6ce9 2007-07-21 drh: if( zRight ){ dbda8d6ce9 2007-07-21 drh: sqlite3RegisterLikeFunctions(db, getBoolean(zRight)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX dbda8d6ce9 2007-07-21 drh: # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_INTEGRITY_CHECK dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){ dbda8d6ce9 2007-07-21 drh: int i, j, addr, mxErr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Code that appears at the end of the integrity check. If no error dbda8d6ce9 2007-07-21 drh: ** messages have been generated, output OK. Otherwise output the dbda8d6ce9 2007-07-21 drh: ** error message dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const VdbeOpList endCode[] = { dbda8d6ce9 2007-07-21 drh: { OP_MemLoad, 0, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Integer, 0, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Ne, 0, 0, 0}, /* 2 */ dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, "ok"}, dbda8d6ce9 2007-07-21 drh: { OP_Callback, 1, 0, 0}, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the VDBE program */ dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the maximum error count */ dbda8d6ce9 2007-07-21 drh: mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; dbda8d6ce9 2007-07-21 drh: if( zRight ){ dbda8d6ce9 2007-07-21 drh: mxErr = atoi(zRight); dbda8d6ce9 2007-07-21 drh: if( mxErr<=0 ){ dbda8d6ce9 2007-07-21 drh: mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, mxErr, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do an integrity check on each database file */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: HashElem *x; dbda8d6ce9 2007-07-21 drh: Hash *pTbls; dbda8d6ce9 2007-07-21 drh: int cnt = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( OMIT_TEMPDB && i==1 ) continue; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3CodeVerifySchema(pParse, i); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Halt, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do an integrity check of the B-Tree dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTbls = &db->aDb[i].pSchema->tblHash; dbda8d6ce9 2007-07-21 drh: for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ dbda8d6ce9 2007-07-21 drh: Table *pTab = sqliteHashData(x); dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0); dbda8d6ce9 2007-07-21 drh: cnt++; dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0); dbda8d6ce9 2007-07-21 drh: cnt++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( cnt==0 ) continue; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, c287665ba8 2007-09-14 drh: sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), dbda8d6ce9 2007-07-21 drh: P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pull, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Concat, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure all the indices are constructed correctly. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ dbda8d6ce9 2007-07-21 drh: Table *pTab = sqliteHashData(x); dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: int loopTop; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pTab->pIndex==0 ) continue; dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Halt, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, 1); dbda8d6ce9 2007-07-21 drh: loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1); dbda8d6ce9 2007-07-21 drh: for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ dbda8d6ce9 2007-07-21 drh: int jmp2; dbda8d6ce9 2007-07-21 drh: static const VdbeOpList idxErr[] = { dbda8d6ce9 2007-07-21 drh: { OP_MemIncr, -1, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, "rowid "}, dbda8d6ce9 2007-07-21 drh: { OP_Rowid, 1, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, " missing from index "}, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, 0}, /* 4 */ dbda8d6ce9 2007-07-21 drh: { OP_Concat, 2, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Callback, 1, 0, 0}, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: sqlite3GenerateIndexKey(v, pIdx, 1); dbda8d6ce9 2007-07-21 drh: jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, jmp2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, loopTop); dbda8d6ce9 2007-07-21 drh: for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ dbda8d6ce9 2007-07-21 drh: static const VdbeOpList cntIdx[] = { dbda8d6ce9 2007-07-21 drh: { OP_MemInt, 0, 2, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Rewind, 0, 0, 0}, /* 1 */ dbda8d6ce9 2007-07-21 drh: { OP_MemIncr, 1, 2, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Next, 0, 0, 0}, /* 3 */ dbda8d6ce9 2007-07-21 drh: { OP_MemLoad, 1, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_MemLoad, 2, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Eq, 0, 0, 0}, /* 6 */ dbda8d6ce9 2007-07-21 drh: { OP_MemIncr, -1, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, "wrong # of entries in index "}, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, 0}, /* 9 */ dbda8d6ce9 2007-07-21 drh: { OP_Concat, 0, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Callback, 1, 0, 0}, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: if( pIdx->tnum==0 ) continue; dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Halt, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr+1, j+2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, addr+1, addr+4); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr+3, j+2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, addr+3, addr+2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr+6); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr+1, mxErr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr+2); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA encoding dbda8d6ce9 2007-07-21 drh: ** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be" dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In it's first form, this pragma returns the encoding of the main dbda8d6ce9 2007-07-21 drh: ** database. If the database is not initialized, it is initialized now. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The second form of this pragma is a no-op if the main database file dbda8d6ce9 2007-07-21 drh: ** has not already been initialized. In this case it sets the default dbda8d6ce9 2007-07-21 drh: ** encoding that will be used for the main database file if a new file dbda8d6ce9 2007-07-21 drh: ** is created. If an existing main database file is opened, then the dbda8d6ce9 2007-07-21 drh: ** default text encoding for the existing database is used. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In all cases new databases created using the ATTACH command are dbda8d6ce9 2007-07-21 drh: ** created to use the same default text encoding as the main database. If dbda8d6ce9 2007-07-21 drh: ** the main database has not been initialized and/or created when ATTACH dbda8d6ce9 2007-07-21 drh: ** is executed, this is done before the ATTACH operation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the second form this pragma sets the text encoding to be used in dbda8d6ce9 2007-07-21 drh: ** new database files created using this database handle. It is only dbda8d6ce9 2007-07-21 drh: ** useful if invoked immediately after the main database i dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "encoding")==0 ){ dbda8d6ce9 2007-07-21 drh: static const struct EncName { dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: u8 enc; dbda8d6ce9 2007-07-21 drh: } encnames[] = { dbda8d6ce9 2007-07-21 drh: { "UTF-8", SQLITE_UTF8 }, dbda8d6ce9 2007-07-21 drh: { "UTF8", SQLITE_UTF8 }, dbda8d6ce9 2007-07-21 drh: { "UTF-16le", SQLITE_UTF16LE }, dbda8d6ce9 2007-07-21 drh: { "UTF16le", SQLITE_UTF16LE }, dbda8d6ce9 2007-07-21 drh: { "UTF-16be", SQLITE_UTF16BE }, dbda8d6ce9 2007-07-21 drh: { "UTF16be", SQLITE_UTF16BE }, dbda8d6ce9 2007-07-21 drh: { "UTF-16", 0 }, /* SQLITE_UTF16NATIVE */ dbda8d6ce9 2007-07-21 drh: { "UTF16", 0 }, /* SQLITE_UTF16NATIVE */ dbda8d6ce9 2007-07-21 drh: { 0, 0 } dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: const struct EncName *pEnc; dbda8d6ce9 2007-07-21 drh: if( !zRight ){ /* "PRAGMA encoding" */ dbda8d6ce9 2007-07-21 drh: if( sqlite3ReadSchema(pParse) ) goto pragma_out; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_String8, 0, 0); dbda8d6ce9 2007-07-21 drh: for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ dbda8d6ce9 2007-07-21 drh: if( pEnc->enc==ENC(pParse->db) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); dbda8d6ce9 2007-07-21 drh: }else{ /* "PRAGMA encoding = XXX" */ dbda8d6ce9 2007-07-21 drh: /* Only change the value of sqlite.enc if the database handle is not dbda8d6ce9 2007-07-21 drh: ** initialized. If the main database exists, the new sqlite.enc value dbda8d6ce9 2007-07-21 drh: ** will be overwritten when the schema is next loaded. If it does not dbda8d6ce9 2007-07-21 drh: ** already exists, it will be created to use the new encoding value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: !(DbHasProperty(db, 0, DB_SchemaLoaded)) || dbda8d6ce9 2007-07-21 drh: DbHasProperty(db, 0, DB_Empty) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ dbda8d6ce9 2007-07-21 drh: if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ dbda8d6ce9 2007-07-21 drh: ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pEnc->zName ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]schema_version dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]schema_version = <integer> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]user_version dbda8d6ce9 2007-07-21 drh: ** PRAGMA [database.]user_version = <integer> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pragma's schema_version and user_version are used to set or get dbda8d6ce9 2007-07-21 drh: ** the value of the schema-version and user-version, respectively. Both dbda8d6ce9 2007-07-21 drh: ** the schema-version and the user-version are 32-bit signed integers dbda8d6ce9 2007-07-21 drh: ** stored in the database header. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The schema-cookie is usually only manipulated internally by SQLite. It dbda8d6ce9 2007-07-21 drh: ** is incremented by SQLite whenever the database schema is modified (by dbda8d6ce9 2007-07-21 drh: ** creating or dropping a table or index). The schema version is used by dbda8d6ce9 2007-07-21 drh: ** SQLite each time a query is executed to ensure that the internal cache dbda8d6ce9 2007-07-21 drh: ** of the schema used when compiling the SQL query matches the schema of dbda8d6ce9 2007-07-21 drh: ** the database against which the compiled query is actually executed. dbda8d6ce9 2007-07-21 drh: ** Subverting this mechanism by using "PRAGMA schema_version" to modify dbda8d6ce9 2007-07-21 drh: ** the schema-version is potentially dangerous and may lead to program dbda8d6ce9 2007-07-21 drh: ** crashes or database corruption. Use with caution! dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The user-version is not used internally by SQLite. It may be used by dbda8d6ce9 2007-07-21 drh: ** applications for any purpose. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "schema_version")==0 dbda8d6ce9 2007-07-21 drh: || sqlite3StrICmp(zLeft, "user_version")==0 dbda8d6ce9 2007-07-21 drh: || sqlite3StrICmp(zLeft, "freelist_count")==0 dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */ c287665ba8 2007-09-14 drh: sqlite3VdbeUsesBtree(v, iDb); dbda8d6ce9 2007-07-21 drh: switch( zLeft[0] ){ dbda8d6ce9 2007-07-21 drh: case 's': case 'S': dbda8d6ce9 2007-07-21 drh: iCookie = 0; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 'f': case 'F': dbda8d6ce9 2007-07-21 drh: iCookie = 1; dbda8d6ce9 2007-07-21 drh: iDb = (-1*(iDb+1)); dbda8d6ce9 2007-07-21 drh: assert(iDb<=0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: default: dbda8d6ce9 2007-07-21 drh: iCookie = 5; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( zRight && iDb>=0 ){ dbda8d6ce9 2007-07-21 drh: /* Write the specified cookie value */ dbda8d6ce9 2007-07-21 drh: static const VdbeOpList setCookie[] = { dbda8d6ce9 2007-07-21 drh: { OP_Transaction, 0, 1, 0}, /* 0 */ dbda8d6ce9 2007-07-21 drh: { OP_Integer, 0, 0, 0}, /* 1 */ dbda8d6ce9 2007-07-21 drh: { OP_SetCookie, 0, 0, 0}, /* 2 */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr+1, atoi(zRight)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr+2, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, addr+2, iCookie); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Read the specified cookie value */ dbda8d6ce9 2007-07-21 drh: static const VdbeOpList readCookie[] = { dbda8d6ce9 2007-07-21 drh: { OP_ReadCookie, 0, 0, 0}, /* 0 */ dbda8d6ce9 2007-07-21 drh: { OP_Callback, 1, 0, 0} dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP1(v, addr, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, addr, iCookie); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, P3_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Report the current state of file logs for all databases dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "lock_status")==0 ){ dbda8d6ce9 2007-07-21 drh: static const char *const azLockName[] = { dbda8d6ce9 2007-07-21 drh: "unlocked", "shared", "reserved", "pending", "exclusive" dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 2); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P3_STATIC); dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: Btree *pBt; dbda8d6ce9 2007-07-21 drh: Pager *pPager; c287665ba8 2007-09-14 drh: const char *zState = "unknown"; c287665ba8 2007-09-14 drh: int j; dbda8d6ce9 2007-07-21 drh: if( db->aDb[i].zName==0 ) continue; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC); dbda8d6ce9 2007-07-21 drh: pBt = db->aDb[i].pBt; dbda8d6ce9 2007-07-21 drh: if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){ c287665ba8 2007-09-14 drh: zState = "closed"; c287665ba8 2007-09-14 drh: }else if( sqlite3_file_control(db, db->aDb[i].zName, c287665ba8 2007-09-14 drh: SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ c287665ba8 2007-09-14 drh: zState = azLockName[j]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3VdbeOp3(v, OP_String8, 0, 0, zState, P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 2, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SSE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if the sqlite_statements table exists. Create it dbda8d6ce9 2007-07-21 drh: ** if it does not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "create_sqlite_statement_table")==0 ){ dbda8d6ce9 2007-07-21 drh: extern int sqlite3CreateStatementsTable(Parse*); dbda8d6ce9 2007-07-21 drh: sqlite3CreateStatementsTable(pParse); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if SQLITE_HAS_CODEC dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "key")==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_key(db, zRight, strlen(zRight)); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #if SQLITE_HAS_CODEC || defined(SQLITE_ENABLE_CEROD) dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){ dbda8d6ce9 2007-07-21 drh: #if SQLITE_HAS_CODEC dbda8d6ce9 2007-07-21 drh: if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){ dbda8d6ce9 2007-07-21 drh: extern void sqlite3_activate_see(const char*); dbda8d6ce9 2007-07-21 drh: sqlite3_activate_see(&zRight[4]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_CEROD dbda8d6ce9 2007-07-21 drh: if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ dbda8d6ce9 2007-07-21 drh: extern void sqlite3_activate_cerod(const char*); dbda8d6ce9 2007-07-21 drh: sqlite3_activate_cerod(&zRight[6]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: {} dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: /* Code an OP_Expire at the end of each PRAGMA program to cause dbda8d6ce9 2007-07-21 drh: ** the VDBE implementing the pragma to expire. Most (all?) pragmas dbda8d6ce9 2007-07-21 drh: ** are only valid for a single execution. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Expire, 1, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Reset the safety level, in case the fullfsync flag or synchronous dbda8d6ce9 2007-07-21 drh: ** setting changed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PAGER_PRAGMAS dbda8d6ce9 2007-07-21 drh: if( db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level, dbda8d6ce9 2007-07-21 drh: (db->flags&SQLITE_FullFSync)!=0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pragma_out: c287665ba8 2007-09-14 drh: sqlite3_free(zLeft); c287665ba8 2007-09-14 drh: sqlite3_free(zRight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_PRAGMA || SQLITE_OMIT_PARSER */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of pragma.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file prepare.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2005 May 25 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains the implementation of the sqlite3_prepare() dbda8d6ce9 2007-07-21 drh: ** interface, and routines that contribute to loading the database schema dbda8d6ce9 2007-07-21 drh: ** from disk. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: prepare.c,v 1.60 2007/08/29 12:31:27 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Fill the InitData structure with an error message that indicates dbda8d6ce9 2007-07-21 drh: ** that the database is corrupt. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void corruptSchema(InitData *pData, const char *zExtra){ c287665ba8 2007-09-14 drh: if( !pData->db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(pData->pzErrMsg, "malformed database schema", dbda8d6ce9 2007-07-21 drh: zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pData->rc = SQLITE_CORRUPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is the callback routine for the code that initializes the dbda8d6ce9 2007-07-21 drh: ** database. See sqlite3Init() below for additional information. dbda8d6ce9 2007-07-21 drh: ** This routine is also called from the OP_ParseSchema opcode of the VDBE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each callback contains the following information: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** argv[0] = name of thing being created dbda8d6ce9 2007-07-21 drh: ** argv[1] = root page number for table or index. 0 for trigger or view. dbda8d6ce9 2007-07-21 drh: ** argv[2] = SQL text for the CREATE statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ dbda8d6ce9 2007-07-21 drh: InitData *pData = (InitData*)pInit; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pData->db; dbda8d6ce9 2007-07-21 drh: int iDb = pData->iDb; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: pData->rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: DbClearProperty(db, iDb, DB_Empty); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: corruptSchema(pData, 0); dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( argc==3 ); dbda8d6ce9 2007-07-21 drh: if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ dbda8d6ce9 2007-07-21 drh: if( argv[1]==0 ){ dbda8d6ce9 2007-07-21 drh: corruptSchema(pData, 0); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: if( argv[2] && argv[2][0] ){ dbda8d6ce9 2007-07-21 drh: /* Call the parser to process a CREATE TABLE, INDEX or VIEW. dbda8d6ce9 2007-07-21 drh: ** But because db->init.busy is set to 1, no VDBE code is generated dbda8d6ce9 2007-07-21 drh: ** or executed. All the parser does is build the internal data dbda8d6ce9 2007-07-21 drh: ** structures that describe the table, index, or view. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: char *zErr; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: assert( db->init.busy ); dbda8d6ce9 2007-07-21 drh: db->init.iDb = iDb; dbda8d6ce9 2007-07-21 drh: db->init.newTnum = atoi(argv[1]); dbda8d6ce9 2007-07-21 drh: rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); dbda8d6ce9 2007-07-21 drh: db->init.iDb = 0; dbda8d6ce9 2007-07-21 drh: assert( rc!=SQLITE_OK || zErr==0 ); dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=rc ){ dbda8d6ce9 2007-07-21 drh: pData->rc = rc; dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_NOMEM ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: }else if( rc!=SQLITE_INTERRUPT ){ dbda8d6ce9 2007-07-21 drh: corruptSchema(pData, zErr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_free(zErr); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* If the SQL column is blank it means this is an index that dbda8d6ce9 2007-07-21 drh: ** was created to be the PRIMARY KEY or to fulfill a UNIQUE dbda8d6ce9 2007-07-21 drh: ** constraint for a CREATE TABLE. The index should have already dbda8d6ce9 2007-07-21 drh: ** been created when we processed the CREATE TABLE. All we have dbda8d6ce9 2007-07-21 drh: ** to do here is record the root page number for that index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: Index *pIndex; dbda8d6ce9 2007-07-21 drh: pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName); dbda8d6ce9 2007-07-21 drh: if( pIndex==0 || pIndex->tnum!=0 ){ dbda8d6ce9 2007-07-21 drh: /* This can occur if there exists an index on a TEMP table which dbda8d6ce9 2007-07-21 drh: ** has the same name as another index on a permanent index. Since dbda8d6ce9 2007-07-21 drh: ** the permanent table is hidden by the TEMP table, we can also dbda8d6ce9 2007-07-21 drh: ** safely ignore the index on the permanent table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Do Nothing */; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pIndex->tnum = atoi(argv[1]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Attempt to read the database schema and initialize internal dbda8d6ce9 2007-07-21 drh: ** data structures for a single database file. The index of the dbda8d6ce9 2007-07-21 drh: ** database file is given by iDb. iDb==0 is used for the main dbda8d6ce9 2007-07-21 drh: ** database. iDb==1 should never be used. iDb>=2 is used for dbda8d6ce9 2007-07-21 drh: ** auxiliary databases. Return one of the SQLITE_ error codes to dbda8d6ce9 2007-07-21 drh: ** indicate success or failure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: BtCursor *curMain; dbda8d6ce9 2007-07-21 drh: int size; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: Db *pDb; dbda8d6ce9 2007-07-21 drh: char const *azArg[4]; dbda8d6ce9 2007-07-21 drh: int meta[10]; dbda8d6ce9 2007-07-21 drh: InitData initData; dbda8d6ce9 2007-07-21 drh: char const *zMasterSchema; dbda8d6ce9 2007-07-21 drh: char const *zMasterName = SCHEMA_TABLE(iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The master database table has a structure like this dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const char master_schema[] = dbda8d6ce9 2007-07-21 drh: "CREATE TABLE sqlite_master(\n" dbda8d6ce9 2007-07-21 drh: " type text,\n" dbda8d6ce9 2007-07-21 drh: " name text,\n" dbda8d6ce9 2007-07-21 drh: " tbl_name text,\n" dbda8d6ce9 2007-07-21 drh: " rootpage integer,\n" dbda8d6ce9 2007-07-21 drh: " sql text\n" dbda8d6ce9 2007-07-21 drh: ")" dbda8d6ce9 2007-07-21 drh: ; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TEMPDB dbda8d6ce9 2007-07-21 drh: static const char temp_master_schema[] = dbda8d6ce9 2007-07-21 drh: "CREATE TEMP TABLE sqlite_temp_master(\n" dbda8d6ce9 2007-07-21 drh: " type text,\n" dbda8d6ce9 2007-07-21 drh: " name text,\n" dbda8d6ce9 2007-07-21 drh: " tbl_name text,\n" dbda8d6ce9 2007-07-21 drh: " rootpage integer,\n" dbda8d6ce9 2007-07-21 drh: " sql text\n" dbda8d6ce9 2007-07-21 drh: ")" dbda8d6ce9 2007-07-21 drh: ; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define temp_master_schema 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: assert( db->aDb[iDb].pSchema ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* zMasterSchema and zInitScript are set to point at the master schema dbda8d6ce9 2007-07-21 drh: ** and initialisation script appropriate for the database being dbda8d6ce9 2007-07-21 drh: ** initialised. zMasterName is the name of the master table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && iDb==1 ){ dbda8d6ce9 2007-07-21 drh: zMasterSchema = temp_master_schema; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zMasterSchema = master_schema; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zMasterName = SCHEMA_TABLE(iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Construct the schema tables. */ dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: azArg[0] = zMasterName; dbda8d6ce9 2007-07-21 drh: azArg[1] = "1"; dbda8d6ce9 2007-07-21 drh: azArg[2] = zMasterSchema; dbda8d6ce9 2007-07-21 drh: azArg[3] = 0; dbda8d6ce9 2007-07-21 drh: initData.db = db; dbda8d6ce9 2007-07-21 drh: initData.iDb = iDb; dbda8d6ce9 2007-07-21 drh: initData.pzErrMsg = pzErrMsg; dbda8d6ce9 2007-07-21 drh: rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); c287665ba8 2007-09-14 drh: rc = initData.rc; c287665ba8 2007-09-14 drh: goto error_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); dbda8d6ce9 2007-07-21 drh: if( pTab ){ dbda8d6ce9 2007-07-21 drh: pTab->readOnly = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create a cursor to hold the database open dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[iDb]; dbda8d6ce9 2007-07-21 drh: if( pDb->pBt==0 ){ dbda8d6ce9 2007-07-21 drh: if( !OMIT_TEMPDB && iDb==1 ){ dbda8d6ce9 2007-07-21 drh: DbSetProperty(db, 1, DB_SchemaLoaded); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(pDb->pBt); dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pDb->pBt); c287665ba8 2007-09-14 drh: goto error_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Get the database meta information. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Meta values are as follows: dbda8d6ce9 2007-07-21 drh: ** meta[0] Schema cookie. Changes with each schema change. dbda8d6ce9 2007-07-21 drh: ** meta[1] File format of schema layer. dbda8d6ce9 2007-07-21 drh: ** meta[2] Size of the page cache. dbda8d6ce9 2007-07-21 drh: ** meta[3] Use freelist if 0. Autovacuum if greater than zero. dbda8d6ce9 2007-07-21 drh: ** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE dbda8d6ce9 2007-07-21 drh: ** meta[5] The user cookie. Used by the application. dbda8d6ce9 2007-07-21 drh: ** meta[6] Incremental-vacuum flag. dbda8d6ce9 2007-07-21 drh: ** meta[7] dbda8d6ce9 2007-07-21 drh: ** meta[8] dbda8d6ce9 2007-07-21 drh: ** meta[9] dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to dbda8d6ce9 2007-07-21 drh: ** the possible values of meta[4]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCloseCursor(curMain); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pDb->pBt); c287665ba8 2007-09-14 drh: goto error_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: memset(meta, 0, sizeof(meta)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pDb->pSchema->schema_cookie = meta[0]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If opening a non-empty database, check the text encoding. For the dbda8d6ce9 2007-07-21 drh: ** main database, set sqlite3.enc to the encoding of the main database. dbda8d6ce9 2007-07-21 drh: ** For an attached db, it is an error if the encoding is not the same dbda8d6ce9 2007-07-21 drh: ** as sqlite3.enc. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( meta[4] ){ /* text encoding */ dbda8d6ce9 2007-07-21 drh: if( iDb==0 ){ dbda8d6ce9 2007-07-21 drh: /* If opening the main database, set ENC(db). */ dbda8d6ce9 2007-07-21 drh: ENC(db) = (u8)meta[4]; dbda8d6ce9 2007-07-21 drh: db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* If opening an attached database, the encoding much match ENC(db) */ dbda8d6ce9 2007-07-21 drh: if( meta[4]!=ENC(db) ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCloseCursor(curMain); dbda8d6ce9 2007-07-21 drh: sqlite3SetString(pzErrMsg, "attached databases must use the same" dbda8d6ce9 2007-07-21 drh: " text encoding as main database", (char*)0); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pDb->pBt); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: DbSetProperty(db, iDb, DB_Empty); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pDb->pSchema->enc = ENC(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: size = meta[2]; dbda8d6ce9 2007-07-21 drh: if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; } dbda8d6ce9 2007-07-21 drh: pDb->pSchema->cache_size = size; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** file_format==1 Version 3.0.0. dbda8d6ce9 2007-07-21 drh: ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN dbda8d6ce9 2007-07-21 drh: ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults dbda8d6ce9 2007-07-21 drh: ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pDb->pSchema->file_format = meta[1]; dbda8d6ce9 2007-07-21 drh: if( pDb->pSchema->file_format==0 ){ dbda8d6ce9 2007-07-21 drh: pDb->pSchema->file_format = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCloseCursor(curMain); dbda8d6ce9 2007-07-21 drh: sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pDb->pBt); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Read the schema information out of the schema tables dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( db->init.busy ); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_EMPTY ){ dbda8d6ce9 2007-07-21 drh: /* For an empty database, there is nothing to read */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: char *zSql; c287665ba8 2007-09-14 drh: zSql = sqlite3MPrintf(db, dbda8d6ce9 2007-07-21 drh: "SELECT name, rootpage, sql FROM '%q'.%s", dbda8d6ce9 2007-07-21 drh: db->aDb[iDb].zName, zMasterName); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_ABORT ) rc = initData.rc; dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); c287665ba8 2007-09-14 drh: sqlite3_free(zSql); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_ANALYZE dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3AnalysisLoad(db, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCloseCursor(curMain); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: /* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ dbda8d6ce9 2007-07-21 drh: /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider dbda8d6ce9 2007-07-21 drh: ** the schema loaded, even if errors occured. In this situation the dbda8d6ce9 2007-07-21 drh: ** current sqlite3_prepare() operation will fail, but the following one dbda8d6ce9 2007-07-21 drh: ** will attempt to compile the supplied statement against whatever subset dbda8d6ce9 2007-07-21 drh: ** of the schema was loaded before the error occured. The primary dbda8d6ce9 2007-07-21 drh: ** purpose of this is to allow access to the sqlite_master table dbda8d6ce9 2007-07-21 drh: ** even when it's contents have been corrupted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: DbSetProperty(db, iDb, DB_SchemaLoaded); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pDb->pBt); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: error_out: c287665ba8 2007-09-14 drh: if( rc==SQLITE_NOMEM ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Initialize all database files - the main database file, the file dbda8d6ce9 2007-07-21 drh: ** used to store temporary tables, and any additional database files dbda8d6ce9 2007-07-21 drh: ** created using ATTACH statements. Return a success code. If an dbda8d6ce9 2007-07-21 drh: ** error occurs, write an error message into *pzErrMsg. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** After a database is initialized, the DB_SchemaLoaded bit is set dbda8d6ce9 2007-07-21 drh: ** bit is set in the flags field of the Db structure. If the database dbda8d6ce9 2007-07-21 drh: ** file was of zero-length, then the DB_Empty flag is also set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ dbda8d6ce9 2007-07-21 drh: int i, rc; c287665ba8 2007-09-14 drh: int commit_internal = !(db->flags&SQLITE_InternChanges); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: if( db->init.busy ) return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: db->init.busy = 1; dbda8d6ce9 2007-07-21 drh: for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; dbda8d6ce9 2007-07-21 drh: rc = sqlite3InitOne(db, i, pzErrMsg); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Once all the other databases have been initialised, load the schema dbda8d6ce9 2007-07-21 drh: ** for the TEMP database. This is loaded last, as the TEMP database dbda8d6ce9 2007-07-21 drh: ** schema may contain references to objects in other databases. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TEMPDB dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3InitOne(db, 1, pzErrMsg); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: db->init.busy = 0; c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK && commit_internal ){ dbda8d6ce9 2007-07-21 drh: sqlite3CommitInternalChanges(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is a no-op if the database schema is already initialised. dbda8d6ce9 2007-07-21 drh: ** Otherwise, the schema is loaded. An error code is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: if( !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3Init(db, &pParse->zErrMsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pParse->rc = rc; dbda8d6ce9 2007-07-21 drh: pParse->nErr++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check schema cookies in all databases. If any cookie is out dbda8d6ce9 2007-07-21 drh: ** of date, return 0. If all schema cookies are current, return 1. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int schemaIsValid(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: BtCursor *curTemp; dbda8d6ce9 2007-07-21 drh: int cookie; dbda8d6ce9 2007-07-21 drh: int allOk = 1; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: for(iDb=0; allOk && iDb<db->nDb; iDb++){ dbda8d6ce9 2007-07-21 drh: Btree *pBt; dbda8d6ce9 2007-07-21 drh: pBt = db->aDb[iDb].pBt; dbda8d6ce9 2007-07-21 drh: if( pBt==0 ) continue; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){ dbda8d6ce9 2007-07-21 drh: allOk = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3BtreeCloseCursor(curTemp); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc==SQLITE_NOMEM ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return allOk; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert a schema pointer into the iDb index that indicates dbda8d6ce9 2007-07-21 drh: ** which database file in db->aDb[] the schema refers to. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the same database is attached more than once, the first dbda8d6ce9 2007-07-21 drh: ** attached database is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ dbda8d6ce9 2007-07-21 drh: int i = -1000000; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If pSchema is NULL, then return -1000000. This happens when code in dbda8d6ce9 2007-07-21 drh: ** expr.c is trying to resolve a reference to a transient table (i.e. one dbda8d6ce9 2007-07-21 drh: ** created by a sub-select). In this case the return value of this dbda8d6ce9 2007-07-21 drh: ** function should never be used. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** We return -1000000 instead of the more usual -1 simply because using dbda8d6ce9 2007-07-21 drh: ** -1000000 as incorrectly using -1000000 index into db->aDb[] is much dbda8d6ce9 2007-07-21 drh: ** more likely to cause a segfault than -1 (of course there are assert() dbda8d6ce9 2007-07-21 drh: ** statements too, but it never hurts to play the odds). dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: if( pSchema ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: if( db->aDb[i].pSchema==pSchema ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( i>=0 &&i>=0 && i<db->nDb ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Prepare( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle. */ dbda8d6ce9 2007-07-21 drh: const char *zSql, /* UTF-8 encoded SQL statement. */ dbda8d6ce9 2007-07-21 drh: int nBytes, /* Length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ dbda8d6ce9 2007-07-21 drh: const char **pzTail /* OUT: End of parsed string */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Parse sParse; dbda8d6ce9 2007-07-21 drh: char *zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( ppStmt ); dbda8d6ce9 2007-07-21 drh: *ppStmt = 0; dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If any attached database schemas are locked, do not proceed with dbda8d6ce9 2007-07-21 drh: ** compilation. Instead return SQLITE_LOCKED immediately. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++) { dbda8d6ce9 2007-07-21 drh: Btree *pBt = db->aDb[i].pBt; c287665ba8 2007-09-14 drh: if( pBt ){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: rc = sqlite3BtreeSchemaLocked(pBt); c287665ba8 2007-09-14 drh: if( rc ){ c287665ba8 2007-09-14 drh: const char *zDb = db->aDb[i].zName; c287665ba8 2007-09-14 drh: sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb); c287665ba8 2007-09-14 drh: sqlite3SafetyOff(db); c287665ba8 2007-09-14 drh: return SQLITE_LOCKED; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memset(&sParse, 0, sizeof(sParse)); dbda8d6ce9 2007-07-21 drh: sParse.db = db; dbda8d6ce9 2007-07-21 drh: if( nBytes>=0 && zSql[nBytes]!=0 ){ dbda8d6ce9 2007-07-21 drh: char *zSqlCopy; dbda8d6ce9 2007-07-21 drh: if( nBytes>SQLITE_MAX_SQL_LENGTH ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_TOOBIG; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); dbda8d6ce9 2007-07-21 drh: if( zSqlCopy ){ dbda8d6ce9 2007-07-21 drh: sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg); c287665ba8 2007-09-14 drh: sqlite3_free(zSqlCopy); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sParse.zTail = &zSql[nBytes]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3RunParser(&sParse, zSql, &zErrMsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: sParse.rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: if( sParse.checkSchema && !schemaIsValid(db) ){ dbda8d6ce9 2007-07-21 drh: sParse.rc = SQLITE_SCHEMA; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sParse.rc==SQLITE_SCHEMA ){ dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: sParse.rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pzTail ){ dbda8d6ce9 2007-07-21 drh: *pzTail = sParse.zTail; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sParse.rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_EXPLAIN dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ dbda8d6ce9 2007-07-21 drh: if( sParse.explain==2 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(sParse.pVdbe, 3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P3_STATIC); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(sParse.pVdbe, 5); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( saveSqlFlag ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); dbda8d6ce9 2007-07-21 drh: assert(!(*ppStmt)); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *ppStmt = (sqlite3_stmt*)sParse.pVdbe; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( zErrMsg ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, rc, "%s", zErrMsg); c287665ba8 2007-09-14 drh: sqlite3_free(zErrMsg); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, rc, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: /* sqlite3ReleaseThreadData(); */ dbda8d6ce9 2007-07-21 drh: assert( (rc&db->errMask)==rc ); c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: static int sqlite3LockAndPrepare( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Database handle. */ c287665ba8 2007-09-14 drh: const char *zSql, /* UTF-8 encoded SQL statement. */ c287665ba8 2007-09-14 drh: int nBytes, /* Length of zSql in bytes. */ c287665ba8 2007-09-14 drh: int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ c287665ba8 2007-09-14 drh: sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ c287665ba8 2007-09-14 drh: const char **pzTail /* OUT: End of parsed string */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: if( sqlite3SafetyCheck(db) ){ c287665ba8 2007-09-14 drh: return SQLITE_MISUSE; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: sqlite3BtreeEnterAll(db); c287665ba8 2007-09-14 drh: rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, ppStmt, pzTail); c287665ba8 2007-09-14 drh: sqlite3BtreeLeaveAll(db); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Rerun the compilation of a statement after a schema change. dbda8d6ce9 2007-07-21 drh: ** Return true if the statement was recompiled successfully. dbda8d6ce9 2007-07-21 drh: ** Return false if there is an error of some kind. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pNew; dbda8d6ce9 2007-07-21 drh: const char *zSql; dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); dbda8d6ce9 2007-07-21 drh: zSql = sqlite3VdbeGetSql(p); dbda8d6ce9 2007-07-21 drh: if( zSql==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db = sqlite3VdbeDb(p); c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); c287665ba8 2007-09-14 drh: rc = sqlite3LockAndPrepare(db, zSql, -1, 0, &pNew, 0); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: assert( pNew==0 ); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pNew!=0 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSwap((Vdbe*)pNew, p); dbda8d6ce9 2007-07-21 drh: sqlite3_transfer_bindings(pNew, (sqlite3_stmt*)p); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResetStepResult((Vdbe*)pNew); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeFinalize((Vdbe*)pNew); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Two versions of the official API. Legacy and new use. In the legacy dbda8d6ce9 2007-07-21 drh: ** version, the original SQL text is not saved in the prepared statement dbda8d6ce9 2007-07-21 drh: ** and so if a schema change occurs, SQLITE_SCHEMA is returned by dbda8d6ce9 2007-07-21 drh: ** sqlite3_step(). In the new version, the original SQL text is retained dbda8d6ce9 2007-07-21 drh: ** and the statement is automatically recompiled if an schema change dbda8d6ce9 2007-07-21 drh: ** occurs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_prepare( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle. */ dbda8d6ce9 2007-07-21 drh: const char *zSql, /* UTF-8 encoded SQL statement. */ dbda8d6ce9 2007-07-21 drh: int nBytes, /* Length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ dbda8d6ce9 2007-07-21 drh: const char **pzTail /* OUT: End of parsed string */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: return sqlite3LockAndPrepare(db,zSql,nBytes,0,ppStmt,pzTail); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_prepare_v2( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle. */ dbda8d6ce9 2007-07-21 drh: const char *zSql, /* UTF-8 encoded SQL statement. */ dbda8d6ce9 2007-07-21 drh: int nBytes, /* Length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ dbda8d6ce9 2007-07-21 drh: const char **pzTail /* OUT: End of parsed string */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: return sqlite3LockAndPrepare(db,zSql,nBytes,1,ppStmt,pzTail); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compile the UTF-16 encoded SQL statement zSql into a statement handle. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int sqlite3Prepare16( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle. */ dbda8d6ce9 2007-07-21 drh: const void *zSql, /* UTF-8 encoded SQL statement. */ dbda8d6ce9 2007-07-21 drh: int nBytes, /* Length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ dbda8d6ce9 2007-07-21 drh: const void **pzTail /* OUT: End of parsed string */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: /* This function currently works by first transforming the UTF-16 dbda8d6ce9 2007-07-21 drh: ** encoded string to UTF-8, then invoking sqlite3_prepare(). The dbda8d6ce9 2007-07-21 drh: ** tricky bit is figuring out the pointer to return in *pzTail. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: char *zSql8; dbda8d6ce9 2007-07-21 drh: const char *zTail8 = 0; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: zSql8 = sqlite3Utf16to8(db, zSql, nBytes); dbda8d6ce9 2007-07-21 drh: if( zSql8 ){ c287665ba8 2007-09-14 drh: rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( zTail8 && pzTail ){ dbda8d6ce9 2007-07-21 drh: /* If sqlite3_prepare returns a tail pointer, we calculate the dbda8d6ce9 2007-07-21 drh: ** equivalent pointer into the UTF-16 string by counting the unicode dbda8d6ce9 2007-07-21 drh: ** characters between zSql8 and zTail8, and then returning a pointer dbda8d6ce9 2007-07-21 drh: ** the same number of characters into the UTF-16 string. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int chars_parsed = sqlite3Utf8CharLen(zSql8, zTail8-zSql8); dbda8d6ce9 2007-07-21 drh: *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(zSql8); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Two versions of the official API. Legacy and new use. In the legacy dbda8d6ce9 2007-07-21 drh: ** version, the original SQL text is not saved in the prepared statement dbda8d6ce9 2007-07-21 drh: ** and so if a schema change occurs, SQLITE_SCHEMA is returned by dbda8d6ce9 2007-07-21 drh: ** sqlite3_step(). In the new version, the original SQL text is retained dbda8d6ce9 2007-07-21 drh: ** and the statement is automatically recompiled if an schema change dbda8d6ce9 2007-07-21 drh: ** occurs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_prepare16( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle. */ dbda8d6ce9 2007-07-21 drh: const void *zSql, /* UTF-8 encoded SQL statement. */ dbda8d6ce9 2007-07-21 drh: int nBytes, /* Length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ dbda8d6ce9 2007-07-21 drh: const void **pzTail /* OUT: End of parsed string */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_prepare16_v2( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database handle. */ dbda8d6ce9 2007-07-21 drh: const void *zSql, /* UTF-8 encoded SQL statement. */ dbda8d6ce9 2007-07-21 drh: int nBytes, /* Length of zSql in bytes. */ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ dbda8d6ce9 2007-07-21 drh: const void **pzTail /* OUT: End of parsed string */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of prepare.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file select.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains C code routines that are called by the parser dbda8d6ce9 2007-07-21 drh: ** to handle SELECT statements in SQLite. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: select.c,v 1.359 2007/08/31 17:42:48 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete all the content of a Select structure but do not deallocate dbda8d6ce9 2007-07-21 drh: ** the select structure itself. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void clearSelect(Select *p){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(p->pEList); dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(p->pSrc); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pWhere); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(p->pGroupBy); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pHaving); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(p->pOrderBy); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(p->pPrior); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pLimit); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pOffset); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate a new Select structure and return a pointer to that dbda8d6ce9 2007-07-21 drh: ** structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Select *sqlite3SelectNew( c287665ba8 2007-09-14 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList, /* which columns to include in the result */ dbda8d6ce9 2007-07-21 drh: SrcList *pSrc, /* the FROM clause -- which tables to scan */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere, /* the WHERE clause */ dbda8d6ce9 2007-07-21 drh: ExprList *pGroupBy, /* the GROUP BY clause */ dbda8d6ce9 2007-07-21 drh: Expr *pHaving, /* the HAVING clause */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* the ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: int isDistinct, /* true if the DISTINCT keyword is present */ dbda8d6ce9 2007-07-21 drh: Expr *pLimit, /* LIMIT value. NULL means not used */ dbda8d6ce9 2007-07-21 drh: Expr *pOffset /* OFFSET value. NULL means no offset */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Select *pNew; dbda8d6ce9 2007-07-21 drh: Select standin; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); dbda8d6ce9 2007-07-21 drh: assert( !pOffset || pLimit ); /* Can't have OFFSET without LIMIT. */ dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: pNew = &standin; dbda8d6ce9 2007-07-21 drh: memset(pNew, 0, sizeof(*pNew)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pEList==0 ){ c287665ba8 2007-09-14 drh: pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0,0,0), 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pNew->pEList = pEList; dbda8d6ce9 2007-07-21 drh: pNew->pSrc = pSrc; dbda8d6ce9 2007-07-21 drh: pNew->pWhere = pWhere; dbda8d6ce9 2007-07-21 drh: pNew->pGroupBy = pGroupBy; dbda8d6ce9 2007-07-21 drh: pNew->pHaving = pHaving; dbda8d6ce9 2007-07-21 drh: pNew->pOrderBy = pOrderBy; dbda8d6ce9 2007-07-21 drh: pNew->isDistinct = isDistinct; dbda8d6ce9 2007-07-21 drh: pNew->op = TK_SELECT; dbda8d6ce9 2007-07-21 drh: assert( pOffset==0 || pLimit!=0 ); dbda8d6ce9 2007-07-21 drh: pNew->pLimit = pLimit; dbda8d6ce9 2007-07-21 drh: pNew->pOffset = pOffset; dbda8d6ce9 2007-07-21 drh: pNew->iLimit = -1; dbda8d6ce9 2007-07-21 drh: pNew->iOffset = -1; dbda8d6ce9 2007-07-21 drh: pNew->addrOpenEphm[0] = -1; dbda8d6ce9 2007-07-21 drh: pNew->addrOpenEphm[1] = -1; dbda8d6ce9 2007-07-21 drh: pNew->addrOpenEphm[2] = -1; dbda8d6ce9 2007-07-21 drh: if( pNew==&standin) { dbda8d6ce9 2007-07-21 drh: clearSelect(pNew); dbda8d6ce9 2007-07-21 drh: pNew = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete the given Select structure and all of its substructures. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3SelectDelete(Select *p){ dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: clearSelect(p); c287665ba8 2007-09-14 drh: sqlite3_free(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the dbda8d6ce9 2007-07-21 drh: ** type of join. Return an integer constant that expresses that type dbda8d6ce9 2007-07-21 drh: ** in terms of the following bit values: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** JT_INNER dbda8d6ce9 2007-07-21 drh: ** JT_CROSS dbda8d6ce9 2007-07-21 drh: ** JT_OUTER dbda8d6ce9 2007-07-21 drh: ** JT_NATURAL dbda8d6ce9 2007-07-21 drh: ** JT_LEFT dbda8d6ce9 2007-07-21 drh: ** JT_RIGHT dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A full outer join is the combination of JT_LEFT and JT_RIGHT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an illegal or unsupported join type is seen, then still return dbda8d6ce9 2007-07-21 drh: ** a join type, but put an error in the pParse structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ dbda8d6ce9 2007-07-21 drh: int jointype = 0; dbda8d6ce9 2007-07-21 drh: Token *apAll[3]; dbda8d6ce9 2007-07-21 drh: Token *p; dbda8d6ce9 2007-07-21 drh: static const struct { dbda8d6ce9 2007-07-21 drh: const char zKeyword[8]; dbda8d6ce9 2007-07-21 drh: u8 nChar; dbda8d6ce9 2007-07-21 drh: u8 code; dbda8d6ce9 2007-07-21 drh: } keywords[] = { dbda8d6ce9 2007-07-21 drh: { "natural", 7, JT_NATURAL }, dbda8d6ce9 2007-07-21 drh: { "left", 4, JT_LEFT|JT_OUTER }, dbda8d6ce9 2007-07-21 drh: { "right", 5, JT_RIGHT|JT_OUTER }, dbda8d6ce9 2007-07-21 drh: { "full", 4, JT_LEFT|JT_RIGHT|JT_OUTER }, dbda8d6ce9 2007-07-21 drh: { "outer", 5, JT_OUTER }, dbda8d6ce9 2007-07-21 drh: { "inner", 5, JT_INNER }, dbda8d6ce9 2007-07-21 drh: { "cross", 5, JT_INNER|JT_CROSS }, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: apAll[0] = pA; dbda8d6ce9 2007-07-21 drh: apAll[1] = pB; dbda8d6ce9 2007-07-21 drh: apAll[2] = pC; dbda8d6ce9 2007-07-21 drh: for(i=0; i<3 && apAll[i]; i++){ dbda8d6ce9 2007-07-21 drh: p = apAll[i]; dbda8d6ce9 2007-07-21 drh: for(j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++){ dbda8d6ce9 2007-07-21 drh: if( p->n==keywords[j].nChar dbda8d6ce9 2007-07-21 drh: && sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){ dbda8d6ce9 2007-07-21 drh: jointype |= keywords[j].code; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( j>=sizeof(keywords)/sizeof(keywords[0]) ){ dbda8d6ce9 2007-07-21 drh: jointype |= JT_ERROR; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) || dbda8d6ce9 2007-07-21 drh: (jointype & JT_ERROR)!=0 dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const char *zSp1 = " "; dbda8d6ce9 2007-07-21 drh: const char *zSp2 = " "; dbda8d6ce9 2007-07-21 drh: if( pB==0 ){ zSp1++; } dbda8d6ce9 2007-07-21 drh: if( pC==0 ){ zSp2++; } dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "unknown or unsupported join type: " dbda8d6ce9 2007-07-21 drh: "%T%s%T%s%T", pA, zSp1, pB, zSp2, pC); dbda8d6ce9 2007-07-21 drh: jointype = JT_INNER; dbda8d6ce9 2007-07-21 drh: }else if( jointype & JT_RIGHT ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "RIGHT and FULL OUTER JOINs are not currently supported"); dbda8d6ce9 2007-07-21 drh: jointype = JT_INNER; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return jointype; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the index of a column in a table. Return -1 if the column dbda8d6ce9 2007-07-21 drh: ** is not contained in the table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int columnIndex(Table *pTab, const char *zCol){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the value of a token to a '\000'-terminated string. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void setToken(Token *p, const char *z){ dbda8d6ce9 2007-07-21 drh: p->z = (u8*)z; dbda8d6ce9 2007-07-21 drh: p->n = z ? strlen(z) : 0; dbda8d6ce9 2007-07-21 drh: p->dyn = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the token to the double-quoted and escaped version of the string pointed dbda8d6ce9 2007-07-21 drh: ** to by z. For example; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** {a"bc} -> {"a""bc"} dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static void setQuotedToken(Parse *pParse, Token *p, const char *z){ c287665ba8 2007-09-14 drh: p->z = (u8 *)sqlite3MPrintf(0, "\"%w\"", z); dbda8d6ce9 2007-07-21 drh: p->dyn = 1; dbda8d6ce9 2007-07-21 drh: if( p->z ){ dbda8d6ce9 2007-07-21 drh: p->n = strlen((char *)p->z); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pParse->db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create an expression node for an identifier with the name of zName dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE Expr *sqlite3CreateIdExpr(Parse *pParse, const char *zName){ dbda8d6ce9 2007-07-21 drh: Token dummy; dbda8d6ce9 2007-07-21 drh: setToken(&dummy, zName); c287665ba8 2007-09-14 drh: return sqlite3PExpr(pParse, TK_ID, 0, 0, &dummy); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a term to the WHERE expression in *ppExpr that requires the dbda8d6ce9 2007-07-21 drh: ** zCol column to be equal in the two tables pTab1 and pTab2. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void addWhereTerm( c287665ba8 2007-09-14 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: const char *zCol, /* Name of the column */ dbda8d6ce9 2007-07-21 drh: const Table *pTab1, /* First table */ dbda8d6ce9 2007-07-21 drh: const char *zAlias1, /* Alias for first table. May be NULL */ dbda8d6ce9 2007-07-21 drh: const Table *pTab2, /* Second table */ dbda8d6ce9 2007-07-21 drh: const char *zAlias2, /* Alias for second table. May be NULL */ dbda8d6ce9 2007-07-21 drh: int iRightJoinTable, /* VDBE cursor for the right table */ dbda8d6ce9 2007-07-21 drh: Expr **ppExpr /* Add the equality term to this expression */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Expr *pE1a, *pE1b, *pE1c; dbda8d6ce9 2007-07-21 drh: Expr *pE2a, *pE2b, *pE2c; dbda8d6ce9 2007-07-21 drh: Expr *pE; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: pE1a = sqlite3CreateIdExpr(pParse, zCol); c287665ba8 2007-09-14 drh: pE2a = sqlite3CreateIdExpr(pParse, zCol); dbda8d6ce9 2007-07-21 drh: if( zAlias1==0 ){ dbda8d6ce9 2007-07-21 drh: zAlias1 = pTab1->zName; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pE1b = sqlite3CreateIdExpr(pParse, zAlias1); dbda8d6ce9 2007-07-21 drh: if( zAlias2==0 ){ dbda8d6ce9 2007-07-21 drh: zAlias2 = pTab2->zName; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pE2b = sqlite3CreateIdExpr(pParse, zAlias2); c287665ba8 2007-09-14 drh: pE1c = sqlite3PExpr(pParse, TK_DOT, pE1b, pE1a, 0); c287665ba8 2007-09-14 drh: pE2c = sqlite3PExpr(pParse, TK_DOT, pE2b, pE2a, 0); c287665ba8 2007-09-14 drh: pE = sqlite3PExpr(pParse, TK_EQ, pE1c, pE2c, 0); dbda8d6ce9 2007-07-21 drh: if( pE ){ dbda8d6ce9 2007-07-21 drh: ExprSetProperty(pE, EP_FromJoin); dbda8d6ce9 2007-07-21 drh: pE->iRightJoinTable = iRightJoinTable; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pE = sqlite3ExprAnd(pParse->db,*ppExpr, pE); dbda8d6ce9 2007-07-21 drh: if( pE ){ dbda8d6ce9 2007-07-21 drh: *ppExpr = pE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Set the EP_FromJoin property on all terms of the given expression. dbda8d6ce9 2007-07-21 drh: ** And set the Expr.iRightJoinTable to iTable for every term in the dbda8d6ce9 2007-07-21 drh: ** expression. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The EP_FromJoin property is used on terms of an expression to tell dbda8d6ce9 2007-07-21 drh: ** the LEFT OUTER JOIN processing logic that this term is part of the dbda8d6ce9 2007-07-21 drh: ** join restriction specified in the ON or USING clause and not a part dbda8d6ce9 2007-07-21 drh: ** of the more general WHERE clause. These terms are moved over to the dbda8d6ce9 2007-07-21 drh: ** WHERE clause during join processing but we need to remember that they dbda8d6ce9 2007-07-21 drh: ** originated in the ON or USING clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The Expr.iRightJoinTable tells the WHERE clause processing that the dbda8d6ce9 2007-07-21 drh: ** expression depends on table iRightJoinTable even if that table is not dbda8d6ce9 2007-07-21 drh: ** explicitly mentioned in the expression. That information is needed dbda8d6ce9 2007-07-21 drh: ** for cases like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The where clause needs to defer the handling of the t1.x=5 dbda8d6ce9 2007-07-21 drh: ** term until after the t2 loop of the join. In that way, a dbda8d6ce9 2007-07-21 drh: ** NULL t2 row will be inserted whenever t1.x!=5. If we do not dbda8d6ce9 2007-07-21 drh: ** defer the handling of t1.x=5, it will be processed immediately dbda8d6ce9 2007-07-21 drh: ** after the t1 loop and rows with t1.x!=5 will never appear in dbda8d6ce9 2007-07-21 drh: ** the output, which is incorrect. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void setJoinExpr(Expr *p, int iTable){ dbda8d6ce9 2007-07-21 drh: while( p ){ dbda8d6ce9 2007-07-21 drh: ExprSetProperty(p, EP_FromJoin); dbda8d6ce9 2007-07-21 drh: p->iRightJoinTable = iTable; dbda8d6ce9 2007-07-21 drh: setJoinExpr(p->pLeft, iTable); dbda8d6ce9 2007-07-21 drh: p = p->pRight; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine processes the join information for a SELECT statement. dbda8d6ce9 2007-07-21 drh: ** ON and USING clauses are converted into extra terms of the WHERE clause. dbda8d6ce9 2007-07-21 drh: ** NATURAL joins also create extra WHERE clause terms. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The terms of a FROM clause are contained in the Select.pSrc structure. dbda8d6ce9 2007-07-21 drh: ** The left most table is the first entry in Select.pSrc. The right-most dbda8d6ce9 2007-07-21 drh: ** table is the last entry. The join operator is held in the entry to dbda8d6ce9 2007-07-21 drh: ** the left. Thus entry 0 contains the join operator for the join between dbda8d6ce9 2007-07-21 drh: ** entries 0 and 1. Any ON or USING clauses associated with the join are dbda8d6ce9 2007-07-21 drh: ** also attached to the left entry. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns the number of errors encountered. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int sqliteProcessJoin(Parse *pParse, Select *p){ dbda8d6ce9 2007-07-21 drh: SrcList *pSrc; /* All tables in the FROM clause */ dbda8d6ce9 2007-07-21 drh: int i, j; /* Loop counters */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pLeft; /* Left table being joined */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pRight; /* Right table being joined */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pSrc = p->pSrc; dbda8d6ce9 2007-07-21 drh: pLeft = &pSrc->a[0]; dbda8d6ce9 2007-07-21 drh: pRight = &pLeft[1]; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){ dbda8d6ce9 2007-07-21 drh: Table *pLeftTab = pLeft->pTab; dbda8d6ce9 2007-07-21 drh: Table *pRightTab = pRight->pTab; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pLeftTab==0 || pRightTab==0 ) continue; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* When the NATURAL keyword is present, add WHERE clause terms for dbda8d6ce9 2007-07-21 drh: ** every column that the two tables have in common. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pRight->jointype & JT_NATURAL ){ dbda8d6ce9 2007-07-21 drh: if( pRight->pOn || pRight->pUsing ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "a NATURAL join may not have " dbda8d6ce9 2007-07-21 drh: "an ON or USING clause", 0); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(j=0; j<pLeftTab->nCol; j++){ dbda8d6ce9 2007-07-21 drh: char *zName = pLeftTab->aCol[j].zName; dbda8d6ce9 2007-07-21 drh: if( columnIndex(pRightTab, zName)>=0 ){ c287665ba8 2007-09-14 drh: addWhereTerm(pParse, zName, pLeftTab, pLeft->zAlias, dbda8d6ce9 2007-07-21 drh: pRightTab, pRight->zAlias, dbda8d6ce9 2007-07-21 drh: pRight->iCursor, &p->pWhere); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Disallow both ON and USING clauses in the same join dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pRight->pOn && pRight->pUsing ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "cannot have both ON and USING " dbda8d6ce9 2007-07-21 drh: "clauses in the same join"); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add the ON clause to the end of the WHERE clause, connected by dbda8d6ce9 2007-07-21 drh: ** an AND operator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pRight->pOn ){ dbda8d6ce9 2007-07-21 drh: setJoinExpr(pRight->pOn, pRight->iCursor); c287665ba8 2007-09-14 drh: p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn); dbda8d6ce9 2007-07-21 drh: pRight->pOn = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create extra terms on the WHERE clause for each column named dbda8d6ce9 2007-07-21 drh: ** in the USING clause. Example: If the two tables to be joined are dbda8d6ce9 2007-07-21 drh: ** A and B and the USING clause names X, Y, and Z, then add this dbda8d6ce9 2007-07-21 drh: ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z dbda8d6ce9 2007-07-21 drh: ** Report an error if any column mentioned in the USING clause is dbda8d6ce9 2007-07-21 drh: ** not contained in both tables to be joined. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pRight->pUsing ){ dbda8d6ce9 2007-07-21 drh: IdList *pList = pRight->pUsing; dbda8d6ce9 2007-07-21 drh: for(j=0; j<pList->nId; j++){ dbda8d6ce9 2007-07-21 drh: char *zName = pList->a[j].zName; dbda8d6ce9 2007-07-21 drh: if( columnIndex(pLeftTab, zName)<0 || columnIndex(pRightTab, zName)<0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "cannot join using column %s - column " dbda8d6ce9 2007-07-21 drh: "not present in both tables", zName); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: addWhereTerm(pParse, zName, pLeftTab, pLeft->zAlias, dbda8d6ce9 2007-07-21 drh: pRightTab, pRight->zAlias, dbda8d6ce9 2007-07-21 drh: pRight->iCursor, &p->pWhere); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Insert code into "v" that will push the record on the top of the dbda8d6ce9 2007-07-21 drh: ** stack into the sorter. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void pushOntoSorter( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* The ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: Select *pSelect /* The whole SELECT statement */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeExprList(pParse, pOrderBy); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Sequence, pOrderBy->iECursor, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr + 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0); dbda8d6ce9 2007-07-21 drh: if( pSelect->iLimit>=0 ){ dbda8d6ce9 2007-07-21 drh: int addr1, addr2; dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_IfMemZero, pSelect->iLimit+1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, -1, pSelect->iLimit+1); dbda8d6ce9 2007-07-21 drh: addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr2); dbda8d6ce9 2007-07-21 drh: pSelect->iLimit = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add code to implement the OFFSET dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void codeOffset( dbda8d6ce9 2007-07-21 drh: Vdbe *v, /* Generate code into this VM */ dbda8d6ce9 2007-07-21 drh: Select *p, /* The SELECT statement being coded */ dbda8d6ce9 2007-07-21 drh: int iContinue, /* Jump here to skip the current record */ dbda8d6ce9 2007-07-21 drh: int nPop /* Number of times to pop stack when jumping */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( p->iOffset>=0 && iContinue!=0 ){ dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, 0); dbda8d6ce9 2007-07-21 drh: if( nPop>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, nPop, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# skip OFFSET records")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add code that will check to make sure the top N elements of the dbda8d6ce9 2007-07-21 drh: ** stack are distinct. iTab is a sorting index that holds previously dbda8d6ce9 2007-07-21 drh: ** seen combinations of the N values. A new entry is made in iTab dbda8d6ce9 2007-07-21 drh: ** if the current N values are new. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A jump to addrRepeat is made and the N+1 values are popped from the dbda8d6ce9 2007-07-21 drh: ** stack if the top N elements are not distinct. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void codeDistinct( dbda8d6ce9 2007-07-21 drh: Vdbe *v, /* Generate code into this VM */ dbda8d6ce9 2007-07-21 drh: int iTab, /* A sorting index used to test for distinctness */ dbda8d6ce9 2007-07-21 drh: int addrRepeat, /* Jump to here if not distinct */ dbda8d6ce9 2007-07-21 drh: int N /* The top N elements of the stack must be distinct */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, N+1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# skip indistinct records")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate an error message when a SELECT is used within a subexpression dbda8d6ce9 2007-07-21 drh: ** (example: "a IN (SELECT * FROM table)") but it has more than 1 result dbda8d6ce9 2007-07-21 drh: ** column. We do this in a subroutine because the error occurs in multiple dbda8d6ce9 2007-07-21 drh: ** places. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int checkForMultiColumnSelectError(Parse *pParse, int eDest, int nExpr){ dbda8d6ce9 2007-07-21 drh: if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "only a single result allowed for " dbda8d6ce9 2007-07-21 drh: "a SELECT that is part of an expression"); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine generates the code for the inside of the inner loop dbda8d6ce9 2007-07-21 drh: ** of a SELECT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If srcTab and nColumn are both zero, then the pEList expressions dbda8d6ce9 2007-07-21 drh: ** are evaluated in order to get the data for this row. If nColumn>0 dbda8d6ce9 2007-07-21 drh: ** then data is pulled from srcTab and pEList is used only to get the dbda8d6ce9 2007-07-21 drh: ** datatypes for each column. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int selectInnerLoop( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: Select *p, /* The complete select statement being coded */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList, /* List of values being extracted */ dbda8d6ce9 2007-07-21 drh: int srcTab, /* Pull data from this table */ dbda8d6ce9 2007-07-21 drh: int nColumn, /* Number of columns in the source table */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* If not NULL, sort results using this key */ dbda8d6ce9 2007-07-21 drh: int distinct, /* If >=0, make sure results are distinct */ dbda8d6ce9 2007-07-21 drh: int eDest, /* How to dispose of the results */ dbda8d6ce9 2007-07-21 drh: int iParm, /* An argument to the disposal method */ dbda8d6ce9 2007-07-21 drh: int iContinue, /* Jump here to continue with next row */ dbda8d6ce9 2007-07-21 drh: int iBreak, /* Jump here to break out of the inner loop */ dbda8d6ce9 2007-07-21 drh: char *aff /* affinity string if eDest is SRT_Union */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int hasDistinct; /* True if the DISTINCT keyword is present */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( v==0 ) return 0; dbda8d6ce9 2007-07-21 drh: assert( pEList!=0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there was a LIMIT clause on the SELECT statement, then do the check dbda8d6ce9 2007-07-21 drh: ** to see if this row should be output. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: hasDistinct = distinct>=0 && pEList->nExpr>0; dbda8d6ce9 2007-07-21 drh: if( pOrderBy==0 && !hasDistinct ){ dbda8d6ce9 2007-07-21 drh: codeOffset(v, p, iContinue, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Pull the requested columns. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( nColumn>0 ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nColumn; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, srcTab, i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nColumn = pEList->nExpr; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeExprList(pParse, pEList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the DISTINCT keyword was present on the SELECT statement dbda8d6ce9 2007-07-21 drh: ** and this row has been seen before, then do not make this row dbda8d6ce9 2007-07-21 drh: ** part of the result. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( hasDistinct ){ dbda8d6ce9 2007-07-21 drh: assert( pEList!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pEList->nExpr==nColumn ); dbda8d6ce9 2007-07-21 drh: codeDistinct(v, distinct, iContinue, nColumn); dbda8d6ce9 2007-07-21 drh: if( pOrderBy==0 ){ dbda8d6ce9 2007-07-21 drh: codeOffset(v, p, iContinue, nColumn); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( checkForMultiColumnSelectError(pParse, eDest, pEList->nExpr) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: switch( eDest ){ dbda8d6ce9 2007-07-21 drh: /* In this mode, write each query result to the key of the temporary dbda8d6ce9 2007-07-21 drh: ** table iParm. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_COMPOUND_SELECT dbda8d6ce9 2007-07-21 drh: case SRT_Union: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); dbda8d6ce9 2007-07-21 drh: if( aff ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, iParm, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Construct a record from the query result, but instead of dbda8d6ce9 2007-07-21 drh: ** saving that record, use it as a key to delete elements from dbda8d6ce9 2007-07-21 drh: ** the temporary table iParm. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case SRT_Except: { dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Delete, iParm, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Store the result as data using a unique key. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case SRT_Table: dbda8d6ce9 2007-07-21 drh: case SRT_EphemTab: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: pushOntoSorter(pParse, pOrderBy, p); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pull, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, iParm, OPFLAG_APPEND); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: /* If we are creating a set for an "expr IN (SELECT ...)" construct, dbda8d6ce9 2007-07-21 drh: ** then there should be a single item on the stack. Write this dbda8d6ce9 2007-07-21 drh: ** item into the set table with bogus data. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case SRT_Set: { dbda8d6ce9 2007-07-21 drh: int addr1 = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: int addr2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( nColumn==1 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); dbda8d6ce9 2007-07-21 drh: p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr,(iParm>>16)&0xff); dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: /* At first glance you would think we could optimize out the dbda8d6ce9 2007-07-21 drh: ** ORDER BY in this case since the order of entries in the set dbda8d6ce9 2007-07-21 drh: ** does not matter. But there might be a LIMIT clause, in which dbda8d6ce9 2007-07-21 drh: ** case the order does matter */ dbda8d6ce9 2007-07-21 drh: pushOntoSorter(pParse, pOrderBy, p); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr2); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If any row exist in the result set, record that fact and abort. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case SRT_Exists: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); dbda8d6ce9 2007-07-21 drh: /* The LIMIT clause will terminate the loop for us */ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is a scalar select that is part of an expression, then dbda8d6ce9 2007-07-21 drh: ** store the results in the appropriate memory cell and break out dbda8d6ce9 2007-07-21 drh: ** of the scan loop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case SRT_Mem: { dbda8d6ce9 2007-07-21 drh: assert( nColumn==1 ); dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: pushOntoSorter(pParse, pOrderBy, p); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); dbda8d6ce9 2007-07-21 drh: /* The LIMIT clause will jump out of the loop for us */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Send the data to the callback function or to a subroutine. In the dbda8d6ce9 2007-07-21 drh: ** case of a subroutine, the subroutine itself is responsible for dbda8d6ce9 2007-07-21 drh: ** popping the data from the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case SRT_Subroutine: dbda8d6ce9 2007-07-21 drh: case SRT_Callback: { dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); dbda8d6ce9 2007-07-21 drh: pushOntoSorter(pParse, pOrderBy, p); dbda8d6ce9 2007-07-21 drh: }else if( eDest==SRT_Subroutine ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_TRIGGER) dbda8d6ce9 2007-07-21 drh: /* Discard the results. This is used for SELECT statements inside dbda8d6ce9 2007-07-21 drh: ** the body of a TRIGGER. The purpose of such selects is to call dbda8d6ce9 2007-07-21 drh: ** user-defined functions that have side effects. We do not care dbda8d6ce9 2007-07-21 drh: ** about the actual results of the select. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: assert( eDest==SRT_Discard ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump to the end of the loop if the LIMIT is reached. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->iLimit>=0 && pOrderBy==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given an expression list, generate a KeyInfo structure that records dbda8d6ce9 2007-07-21 drh: ** the collating sequence for each expression in that expression list. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the ExprList is an ORDER BY or GROUP BY clause then the resulting dbda8d6ce9 2007-07-21 drh: ** KeyInfo structure is appropriate for initializing a virtual index to dbda8d6ce9 2007-07-21 drh: ** implement that clause. If the ExprList is the result set of a SELECT dbda8d6ce9 2007-07-21 drh: ** then the KeyInfo structure is appropriate for initializing a virtual dbda8d6ce9 2007-07-21 drh: ** index to implement a DISTINCT test. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Space to hold the KeyInfo structure is obtain from malloc. The calling dbda8d6ce9 2007-07-21 drh: ** function is responsible for seeing that this structure is eventually dbda8d6ce9 2007-07-21 drh: ** freed. Add the KeyInfo structure to the P3 field of an opcode using dbda8d6ce9 2007-07-21 drh: ** P3_KEYINFO_HANDOFF is the usual way of dealing with this. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int nExpr; dbda8d6ce9 2007-07-21 drh: KeyInfo *pInfo; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: nExpr = pList->nExpr; c287665ba8 2007-09-14 drh: pInfo = sqlite3DbMallocZero(db, sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) ); dbda8d6ce9 2007-07-21 drh: if( pInfo ){ dbda8d6ce9 2007-07-21 drh: pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr]; dbda8d6ce9 2007-07-21 drh: pInfo->nField = nExpr; dbda8d6ce9 2007-07-21 drh: pInfo->enc = ENC(db); dbda8d6ce9 2007-07-21 drh: for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr); dbda8d6ce9 2007-07-21 drh: if( !pColl ){ dbda8d6ce9 2007-07-21 drh: pColl = db->pDfltColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pInfo->aColl[i] = pColl; dbda8d6ce9 2007-07-21 drh: pInfo->aSortOrder[i] = pItem->sortOrder; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pInfo; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the inner loop was generated using a non-null pOrderBy argument, dbda8d6ce9 2007-07-21 drh: ** then the results were placed in a sorter. After the loop is terminated dbda8d6ce9 2007-07-21 drh: ** we need to run the sorter and output the results. The following dbda8d6ce9 2007-07-21 drh: ** routine generates the code needed to do that. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void generateSortTail( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: Select *p, /* The SELECT statement */ dbda8d6ce9 2007-07-21 drh: Vdbe *v, /* Generate code into this VDBE */ dbda8d6ce9 2007-07-21 drh: int nColumn, /* Number of columns of data */ dbda8d6ce9 2007-07-21 drh: int eDest, /* Write the sorted results here */ dbda8d6ce9 2007-07-21 drh: int iParm /* Optional parameter associated with eDest */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int brk = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: int cont = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: int iTab; dbda8d6ce9 2007-07-21 drh: int pseudoTab = 0; dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy = p->pOrderBy; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: iTab = pOrderBy->iECursor; dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ dbda8d6ce9 2007-07-21 drh: pseudoTab = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenPseudo, pseudoTab, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, pseudoTab, nColumn); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk); dbda8d6ce9 2007-07-21 drh: codeOffset(v, p, cont, 0); dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, 1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); dbda8d6ce9 2007-07-21 drh: switch( eDest ){ dbda8d6ce9 2007-07-21 drh: case SRT_Table: dbda8d6ce9 2007-07-21 drh: case SRT_EphemTab: { dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pull, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, iParm, OPFLAG_APPEND); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: case SRT_Set: { dbda8d6ce9 2007-07-21 drh: assert( nColumn==1 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case SRT_Mem: { dbda8d6ce9 2007-07-21 drh: assert( nColumn==1 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); dbda8d6ce9 2007-07-21 drh: /* The LIMIT clause will terminate the loop for us */ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: case SRT_Callback: dbda8d6ce9 2007-07-21 drh: case SRT_Subroutine: { dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, pseudoTab, 0); dbda8d6ce9 2007-07-21 drh: for(i=0; i<nColumn; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, pseudoTab, i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_Callback ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: /* Do nothing */ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump to the end of the loop when the LIMIT is reached dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->iLimit>=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, brk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The bottom of the loop dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, cont); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, iTab, addr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, brk); dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, pseudoTab, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a pointer to a string containing the 'declaration type' of the dbda8d6ce9 2007-07-21 drh: ** expression pExpr. The string may be treated as static by the caller. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The declaration type is the exact datatype definition extracted from the dbda8d6ce9 2007-07-21 drh: ** original CREATE TABLE statement if the expression is a column. The dbda8d6ce9 2007-07-21 drh: ** declaration type for a ROWID field is INTEGER. Exactly when an expression dbda8d6ce9 2007-07-21 drh: ** is considered a column can be complex in the presence of subqueries. The dbda8d6ce9 2007-07-21 drh: ** result-set expression in all of the following SELECT statements is dbda8d6ce9 2007-07-21 drh: ** considered a column by this function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT col FROM tbl; dbda8d6ce9 2007-07-21 drh: ** SELECT (SELECT col FROM tbl; dbda8d6ce9 2007-07-21 drh: ** SELECT (SELECT col FROM tbl); dbda8d6ce9 2007-07-21 drh: ** SELECT abc FROM (SELECT col AS abc FROM tbl); dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The declaration type for any expression other than a column is NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const char *columnType( dbda8d6ce9 2007-07-21 drh: NameContext *pNC, dbda8d6ce9 2007-07-21 drh: Expr *pExpr, dbda8d6ce9 2007-07-21 drh: const char **pzOriginDb, dbda8d6ce9 2007-07-21 drh: const char **pzOriginTab, dbda8d6ce9 2007-07-21 drh: const char **pzOriginCol dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: char const *zType = 0; dbda8d6ce9 2007-07-21 drh: char const *zOriginDb = 0; dbda8d6ce9 2007-07-21 drh: char const *zOriginTab = 0; dbda8d6ce9 2007-07-21 drh: char const *zOriginCol = 0; dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: if( pExpr==0 || pNC->pSrcList==0 ) return 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: switch( pExpr->op ){ dbda8d6ce9 2007-07-21 drh: case TK_AGG_COLUMN: dbda8d6ce9 2007-07-21 drh: case TK_COLUMN: { dbda8d6ce9 2007-07-21 drh: /* The expression is a column. Locate the table the column is being dbda8d6ce9 2007-07-21 drh: ** extracted from in NameContext.pSrcList. This table may be real dbda8d6ce9 2007-07-21 drh: ** database table or a subquery. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: Table *pTab = 0; /* Table structure column is extracted from */ dbda8d6ce9 2007-07-21 drh: Select *pS = 0; /* Select the column is extracted from */ dbda8d6ce9 2007-07-21 drh: int iCol = pExpr->iColumn; /* Index of column in pTab */ dbda8d6ce9 2007-07-21 drh: while( pNC && !pTab ){ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList = pNC->pSrcList; dbda8d6ce9 2007-07-21 drh: for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); dbda8d6ce9 2007-07-21 drh: if( j<pTabList->nSrc ){ dbda8d6ce9 2007-07-21 drh: pTab = pTabList->a[j].pTab; dbda8d6ce9 2007-07-21 drh: pS = pTabList->a[j].pSelect; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pNC = pNC->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pTab==0 ){ dbda8d6ce9 2007-07-21 drh: /* FIX ME: dbda8d6ce9 2007-07-21 drh: ** This can occurs if you have something like "SELECT new.x;" inside dbda8d6ce9 2007-07-21 drh: ** a trigger. In other words, if you reference the special "new" dbda8d6ce9 2007-07-21 drh: ** table in the result set of a select. We do not have a good way dbda8d6ce9 2007-07-21 drh: ** to find the actual table type, so call it "TEXT". This is really dbda8d6ce9 2007-07-21 drh: ** something of a bug, but I do not know how to fix it. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This code does not produce the correct answer - it just prevents dbda8d6ce9 2007-07-21 drh: ** a segfault. See ticket #1229. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: zType = "TEXT"; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTab ); dbda8d6ce9 2007-07-21 drh: if( pS ){ dbda8d6ce9 2007-07-21 drh: /* The "table" is actually a sub-select or a view in the FROM clause dbda8d6ce9 2007-07-21 drh: ** of the SELECT statement. Return the declaration type and origin dbda8d6ce9 2007-07-21 drh: ** data for the result-set column of the sub-select. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( iCol>=0 && iCol<pS->pEList->nExpr ){ dbda8d6ce9 2007-07-21 drh: /* If iCol is less than zero, then the expression requests the dbda8d6ce9 2007-07-21 drh: ** rowid of the sub-select or view. This expression is legal (see dbda8d6ce9 2007-07-21 drh: ** test case misc2.2.2) - it always evaluates to NULL. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: NameContext sNC; dbda8d6ce9 2007-07-21 drh: Expr *p = pS->pEList->a[iCol].pExpr; dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = pS->pSrc; dbda8d6ce9 2007-07-21 drh: sNC.pNext = 0; dbda8d6ce9 2007-07-21 drh: sNC.pParse = pNC->pParse; dbda8d6ce9 2007-07-21 drh: zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pTab->pSchema ){ dbda8d6ce9 2007-07-21 drh: /* A real table */ dbda8d6ce9 2007-07-21 drh: assert( !pS ); dbda8d6ce9 2007-07-21 drh: if( iCol<0 ) iCol = pTab->iPKey; dbda8d6ce9 2007-07-21 drh: assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); dbda8d6ce9 2007-07-21 drh: if( iCol<0 ){ dbda8d6ce9 2007-07-21 drh: zType = "INTEGER"; dbda8d6ce9 2007-07-21 drh: zOriginCol = "rowid"; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zType = pTab->aCol[iCol].zType; dbda8d6ce9 2007-07-21 drh: zOriginCol = pTab->aCol[iCol].zName; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zOriginTab = pTab->zName; dbda8d6ce9 2007-07-21 drh: if( pNC->pParse ){ dbda8d6ce9 2007-07-21 drh: int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: zOriginDb = pNC->pParse->db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: case TK_SELECT: { dbda8d6ce9 2007-07-21 drh: /* The expression is a sub-select. Return the declaration type and dbda8d6ce9 2007-07-21 drh: ** origin info for the single column in the result set of the SELECT dbda8d6ce9 2007-07-21 drh: ** statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: NameContext sNC; dbda8d6ce9 2007-07-21 drh: Select *pS = pExpr->pSelect; dbda8d6ce9 2007-07-21 drh: Expr *p = pS->pEList->a[0].pExpr; dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = pS->pSrc; dbda8d6ce9 2007-07-21 drh: sNC.pNext = pNC; dbda8d6ce9 2007-07-21 drh: sNC.pParse = pNC->pParse; dbda8d6ce9 2007-07-21 drh: zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pzOriginDb ){ dbda8d6ce9 2007-07-21 drh: assert( pzOriginTab && pzOriginCol ); dbda8d6ce9 2007-07-21 drh: *pzOriginDb = zOriginDb; dbda8d6ce9 2007-07-21 drh: *pzOriginTab = zOriginTab; dbda8d6ce9 2007-07-21 drh: *pzOriginCol = zOriginCol; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zType; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will tell the VDBE the declaration types of columns dbda8d6ce9 2007-07-21 drh: ** in the result set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void generateColumnTypes( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList, /* List of tables */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList /* Expressions defining the result set */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: NameContext sNC; dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = pTabList; dbda8d6ce9 2007-07-21 drh: sNC.pParse = pParse; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pEList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: Expr *p = pEList->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: const char *zOrigDb = 0; dbda8d6ce9 2007-07-21 drh: const char *zOrigTab = 0; dbda8d6ce9 2007-07-21 drh: const char *zOrigCol = 0; dbda8d6ce9 2007-07-21 drh: const char *zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The vdbe must make it's own copy of the column-type and other dbda8d6ce9 2007-07-21 drh: ** column specific strings, in case the schema is reset before this dbda8d6ce9 2007-07-21 drh: ** virtual machine is deleted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, P3_TRANSIENT); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, P3_TRANSIENT); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, P3_TRANSIENT); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, P3_TRANSIENT); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will tell the VDBE the names of columns dbda8d6ce9 2007-07-21 drh: ** in the result set. This information is used to provide the dbda8d6ce9 2007-07-21 drh: ** azCol[] values in the callback. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void generateColumnNames( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList, /* List of tables */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList /* Expressions defining the result set */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int fullNames, shortNames; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_EXPLAIN dbda8d6ce9 2007-07-21 drh: /* If this is an EXPLAIN, skip this step */ dbda8d6ce9 2007-07-21 drh: if( pParse->explain ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( v!=0 ); c287665ba8 2007-09-14 drh: if( pParse->colNamesSet || v==0 || db->mallocFailed ) return; dbda8d6ce9 2007-07-21 drh: pParse->colNamesSet = 1; dbda8d6ce9 2007-07-21 drh: fullNames = (db->flags & SQLITE_FullColNames)!=0; dbda8d6ce9 2007-07-21 drh: shortNames = (db->flags & SQLITE_ShortColNames)!=0; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, pEList->nExpr); dbda8d6ce9 2007-07-21 drh: for(i=0; i<pEList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: Expr *p; dbda8d6ce9 2007-07-21 drh: p = pEList->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: if( p==0 ) continue; dbda8d6ce9 2007-07-21 drh: if( pEList->a[i].zName ){ dbda8d6ce9 2007-07-21 drh: char *zName = pEList->a[i].zName; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, strlen(zName)); dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->op==TK_COLUMN && pTabList ){ dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: char *zCol; dbda8d6ce9 2007-07-21 drh: int iCol = p->iColumn; dbda8d6ce9 2007-07-21 drh: for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){} dbda8d6ce9 2007-07-21 drh: assert( j<pTabList->nSrc ); dbda8d6ce9 2007-07-21 drh: pTab = pTabList->a[j].pTab; dbda8d6ce9 2007-07-21 drh: if( iCol<0 ) iCol = pTab->iPKey; dbda8d6ce9 2007-07-21 drh: assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); dbda8d6ce9 2007-07-21 drh: if( iCol<0 ){ dbda8d6ce9 2007-07-21 drh: zCol = "rowid"; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zCol = pTab->aCol[iCol].zName; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n); dbda8d6ce9 2007-07-21 drh: }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ dbda8d6ce9 2007-07-21 drh: char *zName = 0; dbda8d6ce9 2007-07-21 drh: char *zTab; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: zTab = pTabList->a[j].zAlias; dbda8d6ce9 2007-07-21 drh: if( fullNames || zTab==0 ) zTab = pTab->zName; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&zName, zTab, ".", zCol, (char*)0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, strlen(zCol)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( p->span.z && p->span.z[0] ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n); dbda8d6ce9 2007-07-21 drh: /* sqlite3VdbeCompressSpace(v, addr); */ dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: char zName[30]; dbda8d6ce9 2007-07-21 drh: assert( p->op!=TK_COLUMN || pTabList==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3_snprintf(sizeof(zName), zName, "column%d", i+1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: generateColumnTypes(pParse, pTabList, pEList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_COMPOUND_SELECT dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Name of the connection operator, used for error messages. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const char *selectOpName(int id){ dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: switch( id ){ dbda8d6ce9 2007-07-21 drh: case TK_ALL: z = "UNION ALL"; break; dbda8d6ce9 2007-07-21 drh: case TK_INTERSECT: z = "INTERSECT"; break; dbda8d6ce9 2007-07-21 drh: case TK_EXCEPT: z = "EXCEPT"; break; dbda8d6ce9 2007-07-21 drh: default: z = "UNION"; break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_COMPOUND_SELECT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Forward declaration dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int prepSelectStmt(Parse*, Select*); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given a SELECT statement, generate a Table structure that describes dbda8d6ce9 2007-07-21 drh: ** the result set of that SELECT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: ExprList *pEList; dbda8d6ce9 2007-07-21 drh: Column *aCol, *pCol; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( pSelect->pPrior ) pSelect = pSelect->pPrior; dbda8d6ce9 2007-07-21 drh: if( prepSelectStmt(pParse, pSelect) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SelectResolve(pParse, pSelect, 0) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pTab = sqlite3DbMallocZero(db, sizeof(Table) ); dbda8d6ce9 2007-07-21 drh: if( pTab==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab->nRef = 1; c287665ba8 2007-09-14 drh: pTab->zName = zTabName ? sqlite3DbStrDup(db, zTabName) : 0; dbda8d6ce9 2007-07-21 drh: pEList = pSelect->pEList; dbda8d6ce9 2007-07-21 drh: pTab->nCol = pEList->nExpr; dbda8d6ce9 2007-07-21 drh: assert( pTab->nCol>0 ); c287665ba8 2007-09-14 drh: pTab->aCol = aCol = sqlite3DbMallocZero(db, sizeof(pTab->aCol[0])*pTab->nCol); dbda8d6ce9 2007-07-21 drh: for(i=0, pCol=aCol; i<pTab->nCol; i++, pCol++){ dbda8d6ce9 2007-07-21 drh: Expr *p, *pR; dbda8d6ce9 2007-07-21 drh: char *zType; dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: int nName; dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: int cnt; dbda8d6ce9 2007-07-21 drh: NameContext sNC; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Get an appropriate name for the column dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: p = pEList->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: assert( p->pRight==0 || p->pRight->token.z==0 || p->pRight->token.z[0]!=0 ); dbda8d6ce9 2007-07-21 drh: if( (zName = pEList->a[i].zName)!=0 ){ dbda8d6ce9 2007-07-21 drh: /* If the column contains an "AS <name>" phrase, use <name> as the name */ c287665ba8 2007-09-14 drh: zName = sqlite3DbStrDup(db, zName); dbda8d6ce9 2007-07-21 drh: }else if( p->op==TK_DOT dbda8d6ce9 2007-07-21 drh: && (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){ dbda8d6ce9 2007-07-21 drh: /* For columns of the from A.B use B as the name */ c287665ba8 2007-09-14 drh: zName = sqlite3MPrintf(db, "%T", &pR->token); dbda8d6ce9 2007-07-21 drh: }else if( p->span.z && p->span.z[0] ){ dbda8d6ce9 2007-07-21 drh: /* Use the original text of the column expression as its name */ c287665ba8 2007-09-14 drh: zName = sqlite3MPrintf(db, "%T", &p->span); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* If all else fails, make up a name */ c287665ba8 2007-09-14 drh: zName = sqlite3MPrintf(db, "column%d", i+1); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( !zName || db->mallocFailed ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; c287665ba8 2007-09-14 drh: sqlite3_free(zName); dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(pTab); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3Dequote(zName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the column name is unique. If the name is not unique, dbda8d6ce9 2007-07-21 drh: ** append a integer to the name so that it becomes unique. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nName = strlen(zName); dbda8d6ce9 2007-07-21 drh: for(j=cnt=0; j<i; j++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){ dbda8d6ce9 2007-07-21 drh: zName[nName] = 0; c287665ba8 2007-09-14 drh: zName = sqlite3MPrintf(db, "%z:%d", zName, ++cnt); dbda8d6ce9 2007-07-21 drh: j = -1; dbda8d6ce9 2007-07-21 drh: if( zName==0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pCol->zName = zName; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Get the typename, type affinity, and collating sequence for the dbda8d6ce9 2007-07-21 drh: ** column. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: memset(&sNC, 0, sizeof(sNC)); dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = pSelect->pSrc; c287665ba8 2007-09-14 drh: zType = sqlite3DbStrDup(db, columnType(&sNC, p, 0, 0, 0)); dbda8d6ce9 2007-07-21 drh: pCol->zType = zType; dbda8d6ce9 2007-07-21 drh: pCol->affinity = sqlite3ExprAffinity(p); dbda8d6ce9 2007-07-21 drh: pColl = sqlite3ExprCollSeq(pParse, p); dbda8d6ce9 2007-07-21 drh: if( pColl ){ c287665ba8 2007-09-14 drh: pCol->zColl = sqlite3DbStrDup(db, pColl->zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab->iPKey = -1; dbda8d6ce9 2007-07-21 drh: return pTab; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Prepare a SELECT statement for processing by doing the following dbda8d6ce9 2007-07-21 drh: ** things: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) Make sure VDBE cursor numbers have been assigned to every dbda8d6ce9 2007-07-21 drh: ** element of the FROM clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (2) Fill in the pTabList->a[].pTab fields in the SrcList that dbda8d6ce9 2007-07-21 drh: ** defines FROM clause. When views appear in the FROM clause, dbda8d6ce9 2007-07-21 drh: ** fill pTabList->a[].pSelect with a copy of the SELECT statement dbda8d6ce9 2007-07-21 drh: ** that implements the view. A copy is made of the view's SELECT dbda8d6ce9 2007-07-21 drh: ** statement so that we can freely modify or delete that statement dbda8d6ce9 2007-07-21 drh: ** without worrying about messing up the presistent representation dbda8d6ce9 2007-07-21 drh: ** of the view. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (3) Add terms to the WHERE clause to accomodate the NATURAL keyword dbda8d6ce9 2007-07-21 drh: ** on joins and the ON and USING clause of joins. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (4) Scan the list of columns in the result set (pEList) looking dbda8d6ce9 2007-07-21 drh: ** for instances of the "*" operator or the TABLE.* operator. dbda8d6ce9 2007-07-21 drh: ** If found, expand each "*" to be every column in every table dbda8d6ce9 2007-07-21 drh: ** and TABLE.* to be every column in TABLE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return 0 on success. If there are problems, leave an error message dbda8d6ce9 2007-07-21 drh: ** in pParse and return non-zero. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int prepSelectStmt(Parse *pParse, Select *p){ dbda8d6ce9 2007-07-21 drh: int i, j, k, rc; dbda8d6ce9 2007-07-21 drh: SrcList *pTabList; dbda8d6ce9 2007-07-21 drh: ExprList *pEList; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pFrom; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( p==0 || p->pSrc==0 || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTabList = p->pSrc; dbda8d6ce9 2007-07-21 drh: pEList = p->pEList; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure cursor numbers have been assigned to all entries in dbda8d6ce9 2007-07-21 drh: ** the FROM clause of the SELECT statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3SrcListAssignCursors(pParse, p->pSrc); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Look up every table named in the FROM clause of the select. If dbda8d6ce9 2007-07-21 drh: ** an entry of the FROM clause is a subquery instead of a table or view, dbda8d6ce9 2007-07-21 drh: ** then create a transient table structure to describe the subquery. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: if( pFrom->pTab!=0 ){ dbda8d6ce9 2007-07-21 drh: /* This statement has already been prepared. There is no need dbda8d6ce9 2007-07-21 drh: ** to go further. */ dbda8d6ce9 2007-07-21 drh: assert( i==0 ); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pFrom->zName==0 ){ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: /* A sub-query in the FROM clause of a SELECT */ dbda8d6ce9 2007-07-21 drh: assert( pFrom->pSelect!=0 ); dbda8d6ce9 2007-07-21 drh: if( pFrom->zAlias==0 ){ dbda8d6ce9 2007-07-21 drh: pFrom->zAlias = c287665ba8 2007-09-14 drh: sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pFrom->pSelect); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pFrom->pTab==0 ); dbda8d6ce9 2007-07-21 drh: pFrom->pTab = pTab = dbda8d6ce9 2007-07-21 drh: sqlite3ResultSetOfSelect(pParse, pFrom->zAlias, pFrom->pSelect); dbda8d6ce9 2007-07-21 drh: if( pTab==0 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* The isEphem flag indicates that the Table structure has been dbda8d6ce9 2007-07-21 drh: ** dynamically allocated and may be freed at any time. In other words, dbda8d6ce9 2007-07-21 drh: ** pTab is not pointing to a persistent table structure that defines dbda8d6ce9 2007-07-21 drh: ** part of the schema. */ dbda8d6ce9 2007-07-21 drh: pTab->isEphem = 1; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* An ordinary table or view name in the FROM clause */ dbda8d6ce9 2007-07-21 drh: assert( pFrom->pTab==0 ); dbda8d6ce9 2007-07-21 drh: pFrom->pTab = pTab = dbda8d6ce9 2007-07-21 drh: sqlite3LocateTable(pParse,pFrom->zName,pFrom->zDatabase); dbda8d6ce9 2007-07-21 drh: if( pTab==0 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab->nRef++; dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) dbda8d6ce9 2007-07-21 drh: if( pTab->pSelect || IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: /* We reach here if the named table is a really a view */ dbda8d6ce9 2007-07-21 drh: if( sqlite3ViewGetColumnNames(pParse, pTab) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* If pFrom->pSelect!=0 it means we are dealing with a dbda8d6ce9 2007-07-21 drh: ** view within a view. The SELECT structure has already been dbda8d6ce9 2007-07-21 drh: ** copied by the outer view so we can skip the copy step here dbda8d6ce9 2007-07-21 drh: ** in the inner view. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pFrom->pSelect==0 ){ c287665ba8 2007-09-14 drh: pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Process NATURAL keywords, and ON and USING clauses of joins. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqliteProcessJoin(pParse, p) ) return 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* For every "*" that occurs in the column list, insert the names of dbda8d6ce9 2007-07-21 drh: ** all columns in all tables. And for every TABLE.* insert the names dbda8d6ce9 2007-07-21 drh: ** of all columns in TABLE. The parser inserted a special expression dbda8d6ce9 2007-07-21 drh: ** with the TK_ALL operator for each "*" that it found in the column list. dbda8d6ce9 2007-07-21 drh: ** The following code just has to locate the TK_ALL expressions and expand dbda8d6ce9 2007-07-21 drh: ** each one to the list of all columns in all tables. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The first loop just checks to see if there are any "*" operators dbda8d6ce9 2007-07-21 drh: ** that need expanding. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(k=0; k<pEList->nExpr; k++){ dbda8d6ce9 2007-07-21 drh: Expr *pE = pEList->a[k].pExpr; dbda8d6ce9 2007-07-21 drh: if( pE->op==TK_ALL ) break; dbda8d6ce9 2007-07-21 drh: if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL dbda8d6ce9 2007-07-21 drh: && pE->pLeft && pE->pLeft->op==TK_ID ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: if( k<pEList->nExpr ){ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If we get here it means the result set contains one or more "*" dbda8d6ce9 2007-07-21 drh: ** operators that need to be expanded. Loop through each expression dbda8d6ce9 2007-07-21 drh: ** in the result set and expand them one by one. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *a = pEList->a; dbda8d6ce9 2007-07-21 drh: ExprList *pNew = 0; dbda8d6ce9 2007-07-21 drh: int flags = pParse->db->flags; dbda8d6ce9 2007-07-21 drh: int longNames = (flags & SQLITE_FullColNames)!=0 && dbda8d6ce9 2007-07-21 drh: (flags & SQLITE_ShortColNames)==0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(k=0; k<pEList->nExpr; k++){ dbda8d6ce9 2007-07-21 drh: Expr *pE = a[k].pExpr; dbda8d6ce9 2007-07-21 drh: if( pE->op!=TK_ALL && dbda8d6ce9 2007-07-21 drh: (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){ dbda8d6ce9 2007-07-21 drh: /* This particular expression does not need to be expanded. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr, 0); dbda8d6ce9 2007-07-21 drh: if( pNew ){ dbda8d6ce9 2007-07-21 drh: pNew->a[pNew->nExpr-1].zName = a[k].zName; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: a[k].pExpr = 0; dbda8d6ce9 2007-07-21 drh: a[k].zName = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* This expression is a "*" or a "TABLE.*" and needs to be dbda8d6ce9 2007-07-21 drh: ** expanded. */ dbda8d6ce9 2007-07-21 drh: int tableSeen = 0; /* Set to 1 when TABLE matches */ dbda8d6ce9 2007-07-21 drh: char *zTName; /* text of name of TABLE */ dbda8d6ce9 2007-07-21 drh: if( pE->op==TK_DOT && pE->pLeft ){ c287665ba8 2007-09-14 drh: zTName = sqlite3NameFromToken(db, &pE->pLeft->token); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zTName = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ dbda8d6ce9 2007-07-21 drh: Table *pTab = pFrom->pTab; dbda8d6ce9 2007-07-21 drh: char *zTabName = pFrom->zAlias; dbda8d6ce9 2007-07-21 drh: if( zTabName==0 || zTabName[0]==0 ){ dbda8d6ce9 2007-07-21 drh: zTabName = pTab->zName; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zTName && (zTabName==0 || zTabName[0]==0 || dbda8d6ce9 2007-07-21 drh: sqlite3StrICmp(zTName, zTabName)!=0) ){ dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: tableSeen = 1; dbda8d6ce9 2007-07-21 drh: for(j=0; j<pTab->nCol; j++){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr, *pRight; dbda8d6ce9 2007-07-21 drh: char *zName = pTab->aCol[j].zName; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a column is marked as 'hidden' (currently only possible dbda8d6ce9 2007-07-21 drh: ** for virtual tables), do not include it in the expanded dbda8d6ce9 2007-07-21 drh: ** result-set list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( IsHiddenColumn(&pTab->aCol[j]) ){ dbda8d6ce9 2007-07-21 drh: assert(IsVirtual(pTab)); dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( i>0 ){ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pLeft = &pTabList->a[i-1]; dbda8d6ce9 2007-07-21 drh: if( (pLeft[1].jointype & JT_NATURAL)!=0 && dbda8d6ce9 2007-07-21 drh: columnIndex(pLeft->pTab, zName)>=0 ){ dbda8d6ce9 2007-07-21 drh: /* In a NATURAL join, omit the join columns from the dbda8d6ce9 2007-07-21 drh: ** table on the right */ dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3IdListIndex(pLeft[1].pUsing, zName)>=0 ){ dbda8d6ce9 2007-07-21 drh: /* In a join with a USING clause, omit columns in the dbda8d6ce9 2007-07-21 drh: ** using clause from the table on the right. */ dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pRight = sqlite3PExpr(pParse, TK_ID, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: if( pRight==0 ) break; c287665ba8 2007-09-14 drh: setQuotedToken(pParse, &pRight->token, zName); dbda8d6ce9 2007-07-21 drh: if( zTabName && (longNames || pTabList->nSrc>1) ){ c287665ba8 2007-09-14 drh: Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, 0); c287665ba8 2007-09-14 drh: pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) break; c287665ba8 2007-09-14 drh: setQuotedToken(pParse, &pLeft->token, zTabName); c287665ba8 2007-09-14 drh: setToken(&pExpr->span, c287665ba8 2007-09-14 drh: sqlite3MPrintf(db, "%s.%s", zTabName, zName)); dbda8d6ce9 2007-07-21 drh: pExpr->span.dyn = 1; dbda8d6ce9 2007-07-21 drh: pExpr->token.z = 0; dbda8d6ce9 2007-07-21 drh: pExpr->token.n = 0; dbda8d6ce9 2007-07-21 drh: pExpr->token.dyn = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pExpr = pRight; dbda8d6ce9 2007-07-21 drh: pExpr->span = pExpr->token; dbda8d6ce9 2007-07-21 drh: pExpr->span.dyn = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( longNames ){ c287665ba8 2007-09-14 drh: pNew = sqlite3ExprListAppend(pParse, pNew, pExpr, &pExpr->span); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: pNew = sqlite3ExprListAppend(pParse, pNew, pExpr, &pRight->token); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !tableSeen ){ dbda8d6ce9 2007-07-21 drh: if( zTName ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such table: %s", zTName); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no tables specified"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(zTName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pEList); dbda8d6ce9 2007-07-21 drh: p->pEList = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pEList && p->pEList->nExpr>SQLITE_MAX_COLUMN ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "too many columns in result set"); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_COMPOUND_SELECT dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine associates entries in an ORDER BY expression list with dbda8d6ce9 2007-07-21 drh: ** columns in a result. For each ORDER BY expression, the opcode of dbda8d6ce9 2007-07-21 drh: ** the top-level node is changed to TK_COLUMN and the iColumn value of dbda8d6ce9 2007-07-21 drh: ** the top-level node is filled in with column number and the iTable dbda8d6ce9 2007-07-21 drh: ** value of the top-level node is filled with iTable parameter. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If there are prior SELECT clauses, they are processed first. A match dbda8d6ce9 2007-07-21 drh: ** in an earlier SELECT takes precedence over a later SELECT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Any entry that does not match is flagged as an error. The number dbda8d6ce9 2007-07-21 drh: ** of errors is returned. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int matchOrderbyToColumn( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* A place to leave error messages */ dbda8d6ce9 2007-07-21 drh: Select *pSelect, /* Match to result columns of this SELECT */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* The ORDER BY values to match against columns */ dbda8d6ce9 2007-07-21 drh: int iTable, /* Insert this value in iTable */ dbda8d6ce9 2007-07-21 drh: int mustComplete /* If TRUE all ORDER BYs must match */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int nErr = 0; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: ExprList *pEList; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pSelect==0 || pOrderBy==0 ) return 1; dbda8d6ce9 2007-07-21 drh: if( mustComplete ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( prepSelectStmt(pParse, pSelect) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSelect->pPrior ){ dbda8d6ce9 2007-07-21 drh: if( matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pEList = pSelect->pEList; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pOrderBy->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: Expr *pE = pOrderBy->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: int iCol = -1; dbda8d6ce9 2007-07-21 drh: char *zLabel; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pOrderBy->a[i].done ) continue; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprIsInteger(pE, &iCol) ){ dbda8d6ce9 2007-07-21 drh: if( iCol<=0 || iCol>pEList->nExpr ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "ORDER BY position %d should be between 1 and %d", dbda8d6ce9 2007-07-21 drh: iCol, pEList->nExpr); dbda8d6ce9 2007-07-21 drh: nErr++; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !mustComplete ) continue; dbda8d6ce9 2007-07-21 drh: iCol--; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( iCol<0 && (zLabel = sqlite3NameFromToken(db, &pE->token))!=0 ){ dbda8d6ce9 2007-07-21 drh: for(j=0, pItem=pEList->a; j<pEList->nExpr; j++, pItem++){ dbda8d6ce9 2007-07-21 drh: char *zName; dbda8d6ce9 2007-07-21 drh: int isMatch; dbda8d6ce9 2007-07-21 drh: if( pItem->zName ){ c287665ba8 2007-09-14 drh: zName = sqlite3DbStrDup(db, pItem->zName); dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: zName = sqlite3NameFromToken(db, &pItem->pExpr->token); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: isMatch = zName && sqlite3StrICmp(zName, zLabel)==0; c287665ba8 2007-09-14 drh: sqlite3_free(zName); dbda8d6ce9 2007-07-21 drh: if( isMatch ){ dbda8d6ce9 2007-07-21 drh: iCol = j; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(zLabel); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iCol>=0 ){ dbda8d6ce9 2007-07-21 drh: pE->op = TK_COLUMN; dbda8d6ce9 2007-07-21 drh: pE->iColumn = iCol; dbda8d6ce9 2007-07-21 drh: pE->iTable = iTable; dbda8d6ce9 2007-07-21 drh: pE->iAgg = -1; dbda8d6ce9 2007-07-21 drh: pOrderBy->a[i].done = 1; dbda8d6ce9 2007-07-21 drh: }else if( mustComplete ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "ORDER BY term number %d does not match any result column", i+1); dbda8d6ce9 2007-07-21 drh: nErr++; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return nErr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* #ifndef SQLITE_OMIT_COMPOUND_SELECT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Get a VDBE for the given parser context. Create a new one if necessary. dbda8d6ce9 2007-07-21 drh: ** If an error occurs, return NULL and leave a message in pParse. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: if( v==0 ){ dbda8d6ce9 2007-07-21 drh: v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return v; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the iLimit and iOffset fields of the SELECT based on the dbda8d6ce9 2007-07-21 drh: ** pLimit and pOffset expressions. pLimit and pOffset hold the expressions dbda8d6ce9 2007-07-21 drh: ** that appear in the original SQL statement after the LIMIT and OFFSET dbda8d6ce9 2007-07-21 drh: ** keywords. Or NULL if those keywords are omitted. iLimit and iOffset dbda8d6ce9 2007-07-21 drh: ** are the integer memory register numbers for counters used to compute dbda8d6ce9 2007-07-21 drh: ** the limit and offset. If there is no limit and/or offset, then dbda8d6ce9 2007-07-21 drh: ** iLimit and iOffset are negative. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine changes the values of iLimit and iOffset only if dbda8d6ce9 2007-07-21 drh: ** a limit or offset is defined by pLimit and pOffset. iLimit and dbda8d6ce9 2007-07-21 drh: ** iOffset should have been preset to appropriate default values dbda8d6ce9 2007-07-21 drh: ** (usually but not always -1) prior to calling this routine. dbda8d6ce9 2007-07-21 drh: ** Only if pLimit!=0 or pOffset!=0 do the limit registers get dbda8d6ce9 2007-07-21 drh: ** redefined. The UNION ALL operator uses this property to force dbda8d6ce9 2007-07-21 drh: ** the reuse of the same limit and offset registers across multiple dbda8d6ce9 2007-07-21 drh: ** SELECT statements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = 0; dbda8d6ce9 2007-07-21 drh: int iLimit = 0; dbda8d6ce9 2007-07-21 drh: int iOffset; dbda8d6ce9 2007-07-21 drh: int addr1, addr2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** "LIMIT -1" always shows all rows. There is some dbda8d6ce9 2007-07-21 drh: ** contraversy about what the correct behavior should be. dbda8d6ce9 2007-07-21 drh: ** The current implementation interprets "LIMIT 0" to mean dbda8d6ce9 2007-07-21 drh: ** no rows. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pLimit ){ dbda8d6ce9 2007-07-21 drh: p->iLimit = iLimit = pParse->nMem; dbda8d6ce9 2007-07-21 drh: pParse->nMem += 2; dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, p->pLimit); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 1); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# LIMIT counter")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iLimit, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pOffset ){ dbda8d6ce9 2007-07-21 drh: p->iOffset = iOffset = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, p->pOffset); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# OFFSET counter")); dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr1); dbda8d6ce9 2007-07-21 drh: if( p->pLimit ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Add, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pLimit ){ dbda8d6ce9 2007-07-21 drh: addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iLimit, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Pop, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, -1, iLimit+1); dbda8d6ce9 2007-07-21 drh: addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iLimit+1, 1); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# LIMIT+OFFSET")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allocate a virtual index to use for sorting. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){ dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: assert( pOrderBy->iECursor==0 ); dbda8d6ce9 2007-07-21 drh: pOrderBy->iECursor = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenEphemeral, dbda8d6ce9 2007-07-21 drh: pOrderBy->iECursor, pOrderBy->nExpr+1); dbda8d6ce9 2007-07-21 drh: assert( p->addrOpenEphm[2] == -1 ); dbda8d6ce9 2007-07-21 drh: p->addrOpenEphm[2] = addr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_COMPOUND_SELECT dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the appropriate collating sequence for the iCol-th column of dbda8d6ce9 2007-07-21 drh: ** the result set for the compound-select statement "p". Return NULL if dbda8d6ce9 2007-07-21 drh: ** the column has no default collating sequence. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The collating sequence for the compound select is taken from the dbda8d6ce9 2007-07-21 drh: ** left-most term of the select that has a collating sequence. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ dbda8d6ce9 2007-07-21 drh: CollSeq *pRet; dbda8d6ce9 2007-07-21 drh: if( p->pPrior ){ dbda8d6ce9 2007-07-21 drh: pRet = multiSelectCollSeq(pParse, p->pPrior, iCol); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pRet = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pRet==0 ){ dbda8d6ce9 2007-07-21 drh: pRet = sqlite3ExprCollSeq(pParse, p->pEList->a[iCol].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pRet; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_COMPOUND_SELECT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_COMPOUND_SELECT dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called to process a query that is really the union dbda8d6ce9 2007-07-21 drh: ** or intersection of two or more separate queries. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** "p" points to the right-most of the two queries. the query on the dbda8d6ce9 2007-07-21 drh: ** left is p->pPrior. The left query could also be a compound query dbda8d6ce9 2007-07-21 drh: ** in which case this routine will be called recursively. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The results of the total query are to be written into a destination dbda8d6ce9 2007-07-21 drh: ** of type eDest with parameter iParm. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Example 1: Consider a three-way compound SQL statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This statement is parsed up as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT c FROM t3 dbda8d6ce9 2007-07-21 drh: ** | dbda8d6ce9 2007-07-21 drh: ** `-----> SELECT b FROM t2 dbda8d6ce9 2007-07-21 drh: ** | dbda8d6ce9 2007-07-21 drh: ** `------> SELECT a FROM t1 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The arrows in the diagram above represent the Select.pPrior pointer. dbda8d6ce9 2007-07-21 drh: ** So if this routine is called with p equal to the t3 query, then dbda8d6ce9 2007-07-21 drh: ** pPrior will be the t2 query. p->op will be TK_UNION in this case. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Notice that because of the way SQLite parses compound SELECTs, the dbda8d6ce9 2007-07-21 drh: ** individual selects always group from left to right. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int multiSelect( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: Select *p, /* The right-most of SELECTs to be coded */ dbda8d6ce9 2007-07-21 drh: int eDest, /* \___ Store query results as specified */ dbda8d6ce9 2007-07-21 drh: int iParm, /* / by these two parameters. */ dbda8d6ce9 2007-07-21 drh: char *aff /* If eDest is SRT_Union, the affinity string */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; /* Success code from a subroutine */ dbda8d6ce9 2007-07-21 drh: Select *pPrior; /* Another SELECT immediately to our left */ dbda8d6ce9 2007-07-21 drh: Vdbe *v; /* Generate code to this VDBE */ dbda8d6ce9 2007-07-21 drh: int nCol; /* Number of columns in the result set */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy; /* The ORDER BY clause on p */ dbda8d6ce9 2007-07-21 drh: int aSetP2[2]; /* Set P2 value of these op to number of columns */ dbda8d6ce9 2007-07-21 drh: int nSetP2 = 0; /* Number of slots in aSetP2[] used */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only dbda8d6ce9 2007-07-21 drh: ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p==0 || p->pPrior==0 ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pPrior = p->pPrior; dbda8d6ce9 2007-07-21 drh: assert( pPrior->pRightmost!=pPrior ); dbda8d6ce9 2007-07-21 drh: assert( pPrior->pRightmost==p->pRightmost ); dbda8d6ce9 2007-07-21 drh: if( pPrior->pOrderBy ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before", dbda8d6ce9 2007-07-21 drh: selectOpName(p->op)); dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pPrior->pLimit ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before", dbda8d6ce9 2007-07-21 drh: selectOpName(p->op)); dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure we have a valid query engine. If not, create a new one. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create the destination temporary table if necessary dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_EphemTab ){ dbda8d6ce9 2007-07-21 drh: assert( p->pEList ); dbda8d6ce9 2007-07-21 drh: assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) ); dbda8d6ce9 2007-07-21 drh: aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 0); dbda8d6ce9 2007-07-21 drh: eDest = SRT_Table; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code for the left and right SELECT statements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pOrderBy = p->pOrderBy; dbda8d6ce9 2007-07-21 drh: switch( p->op ){ dbda8d6ce9 2007-07-21 drh: case TK_ALL: { dbda8d6ce9 2007-07-21 drh: if( pOrderBy==0 ){ dbda8d6ce9 2007-07-21 drh: int addr = 0; dbda8d6ce9 2007-07-21 drh: assert( !pPrior->pLimit ); dbda8d6ce9 2007-07-21 drh: pPrior->pLimit = p->pLimit; dbda8d6ce9 2007-07-21 drh: pPrior->pOffset = p->pOffset; dbda8d6ce9 2007-07-21 drh: rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff); dbda8d6ce9 2007-07-21 drh: p->pLimit = 0; dbda8d6ce9 2007-07-21 drh: p->pOffset = 0; dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->pPrior = 0; dbda8d6ce9 2007-07-21 drh: p->iLimit = pPrior->iLimit; dbda8d6ce9 2007-07-21 drh: p->iOffset = pPrior->iOffset; dbda8d6ce9 2007-07-21 drh: if( p->iLimit>=0 ){ dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# Jump ahead if LIMIT reached")); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff); dbda8d6ce9 2007-07-21 drh: p->pPrior = pPrior; dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( addr ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* For UNION ALL ... ORDER BY fall through to the next case */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_EXCEPT: dbda8d6ce9 2007-07-21 drh: case TK_UNION: { dbda8d6ce9 2007-07-21 drh: int unionTab; /* Cursor number of the temporary table holding result */ dbda8d6ce9 2007-07-21 drh: int op = 0; /* One of the SRT_ operations to apply to self */ dbda8d6ce9 2007-07-21 drh: int priorOp; /* The SRT_ operation to apply to prior selects */ dbda8d6ce9 2007-07-21 drh: Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */ dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union; dbda8d6ce9 2007-07-21 drh: if( eDest==priorOp && pOrderBy==0 && !p->pLimit && !p->pOffset ){ dbda8d6ce9 2007-07-21 drh: /* We can reuse a temporary table generated by a SELECT to our dbda8d6ce9 2007-07-21 drh: ** right. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: unionTab = iParm; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* We will need to create our own temporary table to hold the dbda8d6ce9 2007-07-21 drh: ** intermediate results. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: unionTab = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: if( pOrderBy && matchOrderbyToColumn(pParse, p, pOrderBy, unionTab,1) ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, unionTab, 0); dbda8d6ce9 2007-07-21 drh: if( priorOp==SRT_Table ){ dbda8d6ce9 2007-07-21 drh: assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) ); dbda8d6ce9 2007-07-21 drh: aSetP2[nSetP2++] = addr; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( p->addrOpenEphm[0] == -1 ); dbda8d6ce9 2007-07-21 drh: p->addrOpenEphm[0] = addr; dbda8d6ce9 2007-07-21 drh: p->pRightmost->usesEphm = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: createSortingIndex(pParse, p, pOrderBy); dbda8d6ce9 2007-07-21 drh: assert( p->pEList ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Code the SELECT statements to our left dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( !pPrior->pOrderBy ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Code the current SELECT statement dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: switch( p->op ){ dbda8d6ce9 2007-07-21 drh: case TK_EXCEPT: op = SRT_Except; break; dbda8d6ce9 2007-07-21 drh: case TK_UNION: op = SRT_Union; break; dbda8d6ce9 2007-07-21 drh: case TK_ALL: op = SRT_Table; break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->pPrior = 0; dbda8d6ce9 2007-07-21 drh: p->pOrderBy = 0; dbda8d6ce9 2007-07-21 drh: p->disallowOrderBy = pOrderBy!=0; dbda8d6ce9 2007-07-21 drh: pLimit = p->pLimit; dbda8d6ce9 2007-07-21 drh: p->pLimit = 0; dbda8d6ce9 2007-07-21 drh: pOffset = p->pOffset; dbda8d6ce9 2007-07-21 drh: p->pOffset = 0; dbda8d6ce9 2007-07-21 drh: rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff); dbda8d6ce9 2007-07-21 drh: /* Query flattening in sqlite3Select() might refill p->pOrderBy. dbda8d6ce9 2007-07-21 drh: ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(p->pOrderBy); dbda8d6ce9 2007-07-21 drh: p->pPrior = pPrior; dbda8d6ce9 2007-07-21 drh: p->pOrderBy = pOrderBy; dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pLimit); dbda8d6ce9 2007-07-21 drh: p->pLimit = pLimit; dbda8d6ce9 2007-07-21 drh: p->pOffset = pOffset; dbda8d6ce9 2007-07-21 drh: p->iLimit = -1; dbda8d6ce9 2007-07-21 drh: p->iOffset = -1; dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Convert the data in the temporary table into whatever form dbda8d6ce9 2007-07-21 drh: ** it is that we currently need. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( eDest!=priorOp || unionTab!=iParm ){ dbda8d6ce9 2007-07-21 drh: int iCont, iBreak, iStart; dbda8d6ce9 2007-07-21 drh: assert( p->pEList ); dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_Callback ){ dbda8d6ce9 2007-07-21 drh: Select *pFirst = p; dbda8d6ce9 2007-07-21 drh: while( pFirst->pPrior ) pFirst = pFirst->pPrior; dbda8d6ce9 2007-07-21 drh: generateColumnNames(pParse, 0, pFirst->pEList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iBreak = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: iCont = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: computeLimitRegisters(pParse, p, iBreak); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak); dbda8d6ce9 2007-07-21 drh: iStart = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, dbda8d6ce9 2007-07-21 drh: pOrderBy, -1, eDest, iParm, dbda8d6ce9 2007-07-21 drh: iCont, iBreak, 0); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iCont); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, unionTab, iStart); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iBreak); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, unionTab, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_INTERSECT: { dbda8d6ce9 2007-07-21 drh: int tab1, tab2; dbda8d6ce9 2007-07-21 drh: int iCont, iBreak, iStart; dbda8d6ce9 2007-07-21 drh: Expr *pLimit, *pOffset; dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* INTERSECT is different from the others since it requires dbda8d6ce9 2007-07-21 drh: ** two temporary tables. Hence it has its own case. Begin dbda8d6ce9 2007-07-21 drh: ** by allocating the tables we will need. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: tab1 = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: tab2 = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: if( pOrderBy && matchOrderbyToColumn(pParse,p,pOrderBy,tab1,1) ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: createSortingIndex(pParse, p, pOrderBy); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab1, 0); dbda8d6ce9 2007-07-21 drh: assert( p->addrOpenEphm[0] == -1 ); dbda8d6ce9 2007-07-21 drh: p->addrOpenEphm[0] = addr; dbda8d6ce9 2007-07-21 drh: p->pRightmost->usesEphm = 1; dbda8d6ce9 2007-07-21 drh: assert( p->pEList ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Code the SELECTs to our left into temporary table "tab1". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Code the current SELECT into temporary table "tab2" dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab2, 0); dbda8d6ce9 2007-07-21 drh: assert( p->addrOpenEphm[1] == -1 ); dbda8d6ce9 2007-07-21 drh: p->addrOpenEphm[1] = addr; dbda8d6ce9 2007-07-21 drh: p->pPrior = 0; dbda8d6ce9 2007-07-21 drh: pLimit = p->pLimit; dbda8d6ce9 2007-07-21 drh: p->pLimit = 0; dbda8d6ce9 2007-07-21 drh: pOffset = p->pOffset; dbda8d6ce9 2007-07-21 drh: p->pOffset = 0; dbda8d6ce9 2007-07-21 drh: rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff); dbda8d6ce9 2007-07-21 drh: p->pPrior = pPrior; dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pLimit); dbda8d6ce9 2007-07-21 drh: p->pLimit = pLimit; dbda8d6ce9 2007-07-21 drh: p->pOffset = pOffset; dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code to take the intersection of the two temporary dbda8d6ce9 2007-07-21 drh: ** tables. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( p->pEList ); dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_Callback ){ dbda8d6ce9 2007-07-21 drh: Select *pFirst = p; dbda8d6ce9 2007-07-21 drh: while( pFirst->pPrior ) pFirst = pFirst->pPrior; dbda8d6ce9 2007-07-21 drh: generateColumnNames(pParse, 0, pFirst->pEList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iBreak = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: iCont = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: computeLimitRegisters(pParse, p, iBreak); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak); dbda8d6ce9 2007-07-21 drh: iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont); dbda8d6ce9 2007-07-21 drh: rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, dbda8d6ce9 2007-07-21 drh: pOrderBy, -1, eDest, iParm, dbda8d6ce9 2007-07-21 drh: iCont, iBreak, 0); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iCont); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, tab1, iStart); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iBreak); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, tab2, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, tab1, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure all SELECTs in the statement have the same number of elements dbda8d6ce9 2007-07-21 drh: ** in their result sets. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( p->pEList && pPrior->pEList ); dbda8d6ce9 2007-07-21 drh: if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" dbda8d6ce9 2007-07-21 drh: " do not have the same number of result columns", selectOpName(p->op)); dbda8d6ce9 2007-07-21 drh: rc = 1; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the number of columns in temporary tables dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nCol = p->pEList->nExpr; dbda8d6ce9 2007-07-21 drh: while( nSetP2 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, aSetP2[--nSetP2], nCol); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Compute collating sequences used by either the ORDER BY clause or dbda8d6ce9 2007-07-21 drh: ** by any temporary tables needed to implement the compound select. dbda8d6ce9 2007-07-21 drh: ** Attach the KeyInfo structure to all temporary tables. Invoke the dbda8d6ce9 2007-07-21 drh: ** ORDER BY processing if there is an ORDER BY clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This section is run by the right-most SELECT statement only. dbda8d6ce9 2007-07-21 drh: ** SELECT statements to the left always skip this part. The right-most dbda8d6ce9 2007-07-21 drh: ** SELECT might also skip this part if it has no ORDER BY clause and dbda8d6ce9 2007-07-21 drh: ** no temp tables are required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pOrderBy || p->usesEphm ){ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo; /* Collating sequence for the result set */ dbda8d6ce9 2007-07-21 drh: Select *pLoop; /* For looping through SELECT statements */ dbda8d6ce9 2007-07-21 drh: int nKeyCol; /* Number of entries in pKeyInfo->aCol[] */ dbda8d6ce9 2007-07-21 drh: CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ dbda8d6ce9 2007-07-21 drh: CollSeq **aCopy; /* A copy of pKeyInfo->aColl[] */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( p->pRightmost==p ); dbda8d6ce9 2007-07-21 drh: nKeyCol = nCol + (pOrderBy ? pOrderBy->nExpr : 0); c287665ba8 2007-09-14 drh: pKeyInfo = sqlite3DbMallocZero(pParse->db, c287665ba8 2007-09-14 drh: sizeof(*pKeyInfo)+nKeyCol*(sizeof(CollSeq*) + 1)); dbda8d6ce9 2007-07-21 drh: if( !pKeyInfo ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto multi_select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pKeyInfo->enc = ENC(pParse->db); dbda8d6ce9 2007-07-21 drh: pKeyInfo->nField = nCol; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){ dbda8d6ce9 2007-07-21 drh: *apColl = multiSelectCollSeq(pParse, p, i); dbda8d6ce9 2007-07-21 drh: if( 0==*apColl ){ dbda8d6ce9 2007-07-21 drh: *apColl = pParse->db->pDfltColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<2; i++){ dbda8d6ce9 2007-07-21 drh: int addr = pLoop->addrOpenEphm[i]; dbda8d6ce9 2007-07-21 drh: if( addr<0 ){ dbda8d6ce9 2007-07-21 drh: /* If [0] is unused then [1] is also unused. So we can dbda8d6ce9 2007-07-21 drh: ** always safely abort as soon as the first unused slot is found */ dbda8d6ce9 2007-07-21 drh: assert( pLoop->addrOpenEphm[1]<0 ); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, addr, nCol); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO); dbda8d6ce9 2007-07-21 drh: pLoop->addrOpenEphm[i] = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pOTerm = pOrderBy->a; dbda8d6ce9 2007-07-21 drh: int nOrderByExpr = pOrderBy->nExpr; dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: u8 *pSortOrder; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Reuse the same pKeyInfo for the ORDER BY as was used above for dbda8d6ce9 2007-07-21 drh: ** the compound select statements. Except we have to change out the dbda8d6ce9 2007-07-21 drh: ** pKeyInfo->aColl[] values. Some of the aColl[] values will be dbda8d6ce9 2007-07-21 drh: ** reused when constructing the pKeyInfo for the ORDER BY, so make dbda8d6ce9 2007-07-21 drh: ** a copy. Sufficient space to hold both the nCol entries for dbda8d6ce9 2007-07-21 drh: ** the compound select and the nOrderbyExpr entries for the ORDER BY dbda8d6ce9 2007-07-21 drh: ** was allocated above. But we need to move the compound select dbda8d6ce9 2007-07-21 drh: ** entries out of the way before constructing the ORDER BY entries. dbda8d6ce9 2007-07-21 drh: ** Move the compound select entries into aCopy[] where they can be dbda8d6ce9 2007-07-21 drh: ** accessed and reused when constructing the ORDER BY entries. dbda8d6ce9 2007-07-21 drh: ** Because nCol might be greater than or less than nOrderByExpr dbda8d6ce9 2007-07-21 drh: ** we have to use memmove() when doing the copy. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: aCopy = &pKeyInfo->aColl[nOrderByExpr]; dbda8d6ce9 2007-07-21 drh: pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol]; dbda8d6ce9 2007-07-21 drh: memmove(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: apColl = pKeyInfo->aColl; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr = pOTerm->pExpr; dbda8d6ce9 2007-07-21 drh: if( (pExpr->flags & EP_ExpCollate) ){ dbda8d6ce9 2007-07-21 drh: assert( pExpr->pColl!=0 ); dbda8d6ce9 2007-07-21 drh: *apColl = pExpr->pColl; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *apColl = aCopy[pExpr->iColumn]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pSortOrder = pOTerm->sortOrder; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( p->pRightmost==p ); dbda8d6ce9 2007-07-21 drh: assert( p->addrOpenEphm[2]>=0 ); dbda8d6ce9 2007-07-21 drh: addr = p->addrOpenEphm[2]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, addr, p->pOrderBy->nExpr+2); dbda8d6ce9 2007-07-21 drh: pKeyInfo->nField = nOrderByExpr; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: pKeyInfo = 0; dbda8d6ce9 2007-07-21 drh: generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3_free(pKeyInfo); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: multi_select_end: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_COMPOUND_SELECT */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW c287665ba8 2007-09-14 drh: /* Forward Declarations */ c287665ba8 2007-09-14 drh: static void substExprList(sqlite3*, ExprList*, int, ExprList*); c287665ba8 2007-09-14 drh: static void substSelect(sqlite3*, Select *, int, ExprList *); c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Scan through the expression pExpr. Replace every reference to dbda8d6ce9 2007-07-21 drh: ** a column in table number iTable with a copy of the iColumn-th dbda8d6ce9 2007-07-21 drh: ** entry in pEList. (But leave references to the ROWID column dbda8d6ce9 2007-07-21 drh: ** unchanged.) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is part of the flattening procedure. A subquery dbda8d6ce9 2007-07-21 drh: ** whose result set is defined by pEList appears as entry in the dbda8d6ce9 2007-07-21 drh: ** FROM clause of a SELECT such that the VDBE cursor assigned to that dbda8d6ce9 2007-07-21 drh: ** FORM clause entry is iTable. This routine make the necessary dbda8d6ce9 2007-07-21 drh: ** changes to pExpr so that it refers directly to the source table dbda8d6ce9 2007-07-21 drh: ** of the subquery rather the result set of the subquery. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static void substExpr( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Report malloc errors to this connection */ c287665ba8 2007-09-14 drh: Expr *pExpr, /* Expr in which substitution occurs */ c287665ba8 2007-09-14 drh: int iTable, /* Table to be substituted */ c287665ba8 2007-09-14 drh: ExprList *pEList /* Substitute expressions */ c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) return; dbda8d6ce9 2007-07-21 drh: if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){ dbda8d6ce9 2007-07-21 drh: if( pExpr->iColumn<0 ){ dbda8d6ce9 2007-07-21 drh: pExpr->op = TK_NULL; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Expr *pNew; dbda8d6ce9 2007-07-21 drh: assert( pEList!=0 && pExpr->iColumn<pEList->nExpr ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 ); dbda8d6ce9 2007-07-21 drh: pNew = pEList->a[pExpr->iColumn].pExpr; dbda8d6ce9 2007-07-21 drh: assert( pNew!=0 ); dbda8d6ce9 2007-07-21 drh: pExpr->op = pNew->op; dbda8d6ce9 2007-07-21 drh: assert( pExpr->pLeft==0 ); c287665ba8 2007-09-14 drh: pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft); dbda8d6ce9 2007-07-21 drh: assert( pExpr->pRight==0 ); c287665ba8 2007-09-14 drh: pExpr->pRight = sqlite3ExprDup(db, pNew->pRight); dbda8d6ce9 2007-07-21 drh: assert( pExpr->pList==0 ); c287665ba8 2007-09-14 drh: pExpr->pList = sqlite3ExprListDup(db, pNew->pList); dbda8d6ce9 2007-07-21 drh: pExpr->iTable = pNew->iTable; dbda8d6ce9 2007-07-21 drh: pExpr->pTab = pNew->pTab; dbda8d6ce9 2007-07-21 drh: pExpr->iColumn = pNew->iColumn; dbda8d6ce9 2007-07-21 drh: pExpr->iAgg = pNew->iAgg; c287665ba8 2007-09-14 drh: sqlite3TokenCopy(db, &pExpr->token, &pNew->token); c287665ba8 2007-09-14 drh: sqlite3TokenCopy(db, &pExpr->span, &pNew->span); c287665ba8 2007-09-14 drh: pExpr->pSelect = sqlite3SelectDup(db, pNew->pSelect); dbda8d6ce9 2007-07-21 drh: pExpr->flags = pNew->flags; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: substExpr(db, pExpr->pLeft, iTable, pEList); c287665ba8 2007-09-14 drh: substExpr(db, pExpr->pRight, iTable, pEList); c287665ba8 2007-09-14 drh: substSelect(db, pExpr->pSelect, iTable, pEList); c287665ba8 2007-09-14 drh: substExprList(db, pExpr->pList, iTable, pEList); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: static void substExprList( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Report malloc errors here */ c287665ba8 2007-09-14 drh: ExprList *pList, /* List to scan and in which to make substitutes */ c287665ba8 2007-09-14 drh: int iTable, /* Table to be substituted */ c287665ba8 2007-09-14 drh: ExprList *pEList /* Substitute values */ c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( pList==0 ) return; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pList->nExpr; i++){ c287665ba8 2007-09-14 drh: substExpr(db, pList->a[i].pExpr, iTable, pEList); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: static void substSelect( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Report malloc errors here */ c287665ba8 2007-09-14 drh: Select *p, /* SELECT statement in which to make substitutions */ c287665ba8 2007-09-14 drh: int iTable, /* Table to be replaced */ c287665ba8 2007-09-14 drh: ExprList *pEList /* Substitute values */ c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: if( !p ) return; c287665ba8 2007-09-14 drh: substExprList(db, p->pEList, iTable, pEList); c287665ba8 2007-09-14 drh: substExprList(db, p->pGroupBy, iTable, pEList); c287665ba8 2007-09-14 drh: substExprList(db, p->pOrderBy, iTable, pEList); c287665ba8 2007-09-14 drh: substExpr(db, p->pHaving, iTable, pEList); c287665ba8 2007-09-14 drh: substExpr(db, p->pWhere, iTable, pEList); c287665ba8 2007-09-14 drh: substSelect(db, p->pPrior, iTable, pEList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_VIEW) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine attempts to flatten subqueries in order to speed dbda8d6ce9 2007-07-21 drh: ** execution. It returns 1 if it makes changes and 0 if no flattening dbda8d6ce9 2007-07-21 drh: ** occurs. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** To understand the concept of flattening, consider the following dbda8d6ce9 2007-07-21 drh: ** query: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The default way of implementing this query is to execute the dbda8d6ce9 2007-07-21 drh: ** subquery first and store the results in a temporary table, then dbda8d6ce9 2007-07-21 drh: ** run the outer query on that temporary table. This requires two dbda8d6ce9 2007-07-21 drh: ** passes over the data. Furthermore, because the temporary table dbda8d6ce9 2007-07-21 drh: ** has no indices, the WHERE clause on the outer query cannot be dbda8d6ce9 2007-07-21 drh: ** optimized. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine attempts to rewrite queries such as the above into dbda8d6ce9 2007-07-21 drh: ** a single flat select, like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code generated for this simpification gives the same result dbda8d6ce9 2007-07-21 drh: ** but only has to scan the data once. And because indices might dbda8d6ce9 2007-07-21 drh: ** exist on the table t1, a complete scan of the data might be dbda8d6ce9 2007-07-21 drh: ** avoided. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Flattening is only attempted if all of the following are true: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) The subquery and the outer query do not both use aggregates. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (2) The subquery is not an aggregate or the outer query is not a join. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (3) The subquery is not the right operand of a left outer join, or dbda8d6ce9 2007-07-21 drh: ** the subquery is not itself a join. (Ticket #306) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (4) The subquery is not DISTINCT or the outer query is not a join. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (5) The subquery is not DISTINCT or the outer query does not use dbda8d6ce9 2007-07-21 drh: ** aggregates. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (6) The subquery does not use aggregates or the outer query is not dbda8d6ce9 2007-07-21 drh: ** DISTINCT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (7) The subquery has a FROM clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (8) The subquery does not use LIMIT or the outer query is not a join. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (9) The subquery does not use LIMIT or the outer query does not use dbda8d6ce9 2007-07-21 drh: ** aggregates. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (10) The subquery does not use aggregates or the outer query does not dbda8d6ce9 2007-07-21 drh: ** use LIMIT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (11) The subquery and the outer query do not both have ORDER BY clauses. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (12) The subquery is not the right term of a LEFT OUTER JOIN or the dbda8d6ce9 2007-07-21 drh: ** subquery has no WHERE clause. (added by ticket #350) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (13) The subquery and outer query do not both use LIMIT dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (14) The subquery does not use OFFSET dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (15) The outer query is not part of a compound select or the dbda8d6ce9 2007-07-21 drh: ** subquery does not have both an ORDER BY and a LIMIT clause. dbda8d6ce9 2007-07-21 drh: ** (See ticket #2339) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In this routine, the "p" parameter is a pointer to the outer query. dbda8d6ce9 2007-07-21 drh: ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query dbda8d6ce9 2007-07-21 drh: ** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If flattening is not attempted, this routine is a no-op and returns 0. dbda8d6ce9 2007-07-21 drh: ** If flattening is attempted this routine returns 1. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All of the expression analysis must occur on both the outer query and dbda8d6ce9 2007-07-21 drh: ** the subquery before this routine runs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int flattenSubquery( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Database connection */ dbda8d6ce9 2007-07-21 drh: Select *p, /* The parent or outer SELECT statement */ dbda8d6ce9 2007-07-21 drh: int iFrom, /* Index in p->pSrc->a[] of the inner subquery */ dbda8d6ce9 2007-07-21 drh: int isAgg, /* True if outer SELECT uses aggregate functions */ dbda8d6ce9 2007-07-21 drh: int subqueryIsAgg /* True if the subquery uses aggregate functions */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Select *pSub; /* The inner query or "subquery" */ dbda8d6ce9 2007-07-21 drh: SrcList *pSrc; /* The FROM clause of the outer query */ dbda8d6ce9 2007-07-21 drh: SrcList *pSubSrc; /* The FROM clause of the subquery */ dbda8d6ce9 2007-07-21 drh: ExprList *pList; /* The result set of the outer query */ dbda8d6ce9 2007-07-21 drh: int iParent; /* VDBE cursor number of the pSub result set temp table */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere; /* The WHERE clause */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pSubitem; /* The subquery */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to see if flattening is permitted. Return 0 if not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p==0 ) return 0; dbda8d6ce9 2007-07-21 drh: pSrc = p->pSrc; dbda8d6ce9 2007-07-21 drh: assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc ); dbda8d6ce9 2007-07-21 drh: pSubitem = &pSrc->a[iFrom]; dbda8d6ce9 2007-07-21 drh: pSub = pSubitem->pSelect; dbda8d6ce9 2007-07-21 drh: assert( pSub!=0 ); dbda8d6ce9 2007-07-21 drh: if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */ dbda8d6ce9 2007-07-21 drh: if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */ dbda8d6ce9 2007-07-21 drh: pSubSrc = pSub->pSrc; dbda8d6ce9 2007-07-21 drh: assert( pSubSrc ); dbda8d6ce9 2007-07-21 drh: /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, dbda8d6ce9 2007-07-21 drh: ** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET dbda8d6ce9 2007-07-21 drh: ** because they could be computed at compile-time. But when LIMIT and OFFSET dbda8d6ce9 2007-07-21 drh: ** became arbitrary expressions, we were forced to add restrictions (13) dbda8d6ce9 2007-07-21 drh: ** and (14). */ dbda8d6ce9 2007-07-21 drh: if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */ dbda8d6ce9 2007-07-21 drh: if( pSub->pOffset ) return 0; /* Restriction (14) */ dbda8d6ce9 2007-07-21 drh: if( p->pRightmost && pSub->pLimit && pSub->pOrderBy ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Restriction (15) */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ dbda8d6ce9 2007-07-21 drh: if( (pSub->isDistinct || pSub->pLimit) dbda8d6ce9 2007-07-21 drh: && (pSrc->nSrc>1 || isAgg) ){ /* Restrictions (4)(5)(8)(9) */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->isDistinct && subqueryIsAgg ) return 0; /* Restriction (6) */ dbda8d6ce9 2007-07-21 drh: if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ){ dbda8d6ce9 2007-07-21 drh: return 0; /* Restriction (11) */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Restriction 3: If the subquery is a join, make sure the subquery is dbda8d6ce9 2007-07-21 drh: ** not used as the right operand of an outer join. Examples of why this dbda8d6ce9 2007-07-21 drh: ** is not allowed: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** t1 LEFT OUTER JOIN (t2 JOIN t3) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If we flatten the above, we would get dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (t1 LEFT OUTER JOIN t2) JOIN t3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** which is not at all the same thing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pSubSrc->nSrc>1 && (pSubitem->jointype & JT_OUTER)!=0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Restriction 12: If the subquery is the right operand of a left outer dbda8d6ce9 2007-07-21 drh: ** join, make sure the subquery has no WHERE clause. dbda8d6ce9 2007-07-21 drh: ** An examples of why this is not allowed: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If we flatten the above, we would get dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** But the t2.x>0 test will always fail on a NULL row of t2, which dbda8d6ce9 2007-07-21 drh: ** effectively converts the OUTER JOIN into an INNER JOIN. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (pSubitem->jointype & JT_OUTER)!=0 && pSub->pWhere!=0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we reach this point, it means flattening is permitted for the dbda8d6ce9 2007-07-21 drh: ** iFrom-th entry of the FROM clause in the outer query. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Move all of the FROM elements of the subquery into the dbda8d6ce9 2007-07-21 drh: ** the FROM clause of the outer query. Before doing this, remember dbda8d6ce9 2007-07-21 drh: ** the cursor number for the original outer query FROM element in dbda8d6ce9 2007-07-21 drh: ** iParent. The iParent cursor will never be used. Subsequent code dbda8d6ce9 2007-07-21 drh: ** will scan expressions looking for iParent references and replace dbda8d6ce9 2007-07-21 drh: ** those references with expressions that resolve to the subquery FROM dbda8d6ce9 2007-07-21 drh: ** elements we are now copying in. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: iParent = pSubitem->iCursor; dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int nSubSrc = pSubSrc->nSrc; dbda8d6ce9 2007-07-21 drh: int jointype = pSubitem->jointype; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(pSubitem->pTab); c287665ba8 2007-09-14 drh: sqlite3_free(pSubitem->zDatabase); c287665ba8 2007-09-14 drh: sqlite3_free(pSubitem->zName); c287665ba8 2007-09-14 drh: sqlite3_free(pSubitem->zAlias); dbda8d6ce9 2007-07-21 drh: if( nSubSrc>1 ){ dbda8d6ce9 2007-07-21 drh: int extra = nSubSrc - 1; dbda8d6ce9 2007-07-21 drh: for(i=1; i<nSubSrc; i++){ c287665ba8 2007-09-14 drh: pSrc = sqlite3SrcListAppend(db, pSrc, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->pSrc = pSrc; dbda8d6ce9 2007-07-21 drh: for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){ dbda8d6ce9 2007-07-21 drh: pSrc->a[i] = pSrc->a[i-extra]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<nSubSrc; i++){ dbda8d6ce9 2007-07-21 drh: pSrc->a[i+iFrom] = pSubSrc->a[i]; dbda8d6ce9 2007-07-21 drh: memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pSrc->a[iFrom].jointype = jointype; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Now begin substituting subquery result set expressions for dbda8d6ce9 2007-07-21 drh: ** references to the iParent in the outer query. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Example: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; dbda8d6ce9 2007-07-21 drh: ** \ \_____________ subquery __________/ / dbda8d6ce9 2007-07-21 drh: ** \_____________________ outer query ______________________________/ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** We look at every expression in the outer query and every place we see dbda8d6ce9 2007-07-21 drh: ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pList = p->pEList; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr; dbda8d6ce9 2007-07-21 drh: if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){ c287665ba8 2007-09-14 drh: pList->a[i].zName = c287665ba8 2007-09-14 drh: sqlite3DbStrNDup(db, (char*)pExpr->span.z, pExpr->span.n); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: substExprList(db, p->pEList, iParent, pSub->pEList); dbda8d6ce9 2007-07-21 drh: if( isAgg ){ c287665ba8 2007-09-14 drh: substExprList(db, p->pGroupBy, iParent, pSub->pEList); c287665ba8 2007-09-14 drh: substExpr(db, p->pHaving, iParent, pSub->pEList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSub->pOrderBy ){ dbda8d6ce9 2007-07-21 drh: assert( p->pOrderBy==0 ); dbda8d6ce9 2007-07-21 drh: p->pOrderBy = pSub->pOrderBy; dbda8d6ce9 2007-07-21 drh: pSub->pOrderBy = 0; dbda8d6ce9 2007-07-21 drh: }else if( p->pOrderBy ){ c287665ba8 2007-09-14 drh: substExprList(db, p->pOrderBy, iParent, pSub->pEList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pSub->pWhere ){ c287665ba8 2007-09-14 drh: pWhere = sqlite3ExprDup(db, pSub->pWhere); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pWhere = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( subqueryIsAgg ){ dbda8d6ce9 2007-07-21 drh: assert( p->pHaving==0 ); dbda8d6ce9 2007-07-21 drh: p->pHaving = p->pWhere; dbda8d6ce9 2007-07-21 drh: p->pWhere = pWhere; c287665ba8 2007-09-14 drh: substExpr(db, p->pHaving, iParent, pSub->pEList); c287665ba8 2007-09-14 drh: p->pHaving = sqlite3ExprAnd(db, p->pHaving, c287665ba8 2007-09-14 drh: sqlite3ExprDup(db, pSub->pHaving)); dbda8d6ce9 2007-07-21 drh: assert( p->pGroupBy==0 ); c287665ba8 2007-09-14 drh: p->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: substExpr(db, p->pWhere, iParent, pSub->pEList); c287665ba8 2007-09-14 drh: p->pWhere = sqlite3ExprAnd(db, p->pWhere, pWhere); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The flattened query is distinct if either the inner or the dbda8d6ce9 2007-07-21 drh: ** outer query is distinct. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: p->isDistinct = p->isDistinct || pSub->isDistinct; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** One is tempted to try to add a and b to combine the limits. But this dbda8d6ce9 2007-07-21 drh: ** does not work if either limit is negative. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pSub->pLimit ){ dbda8d6ce9 2007-07-21 drh: p->pLimit = pSub->pLimit; dbda8d6ce9 2007-07-21 drh: pSub->pLimit = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Finially, delete what is left of the subquery and return dbda8d6ce9 2007-07-21 drh: ** success. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSub); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIEW */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Analyze the SELECT statement passed in as an argument to see if it dbda8d6ce9 2007-07-21 drh: ** is a simple min() or max() query. If it is and this query can be dbda8d6ce9 2007-07-21 drh: ** satisfied using a single seek to the beginning or end of an index, dbda8d6ce9 2007-07-21 drh: ** then generate the code for this SELECT and return 1. If this is not a dbda8d6ce9 2007-07-21 drh: ** simple min() or max() query, then return 0; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A simply min() or max() query looks like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT min(a) FROM table; dbda8d6ce9 2007-07-21 drh: ** SELECT max(a) FROM table; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The query may have only a single table in its FROM argument. There dbda8d6ce9 2007-07-21 drh: ** can be no GROUP BY or HAVING or WHERE clauses. The result set must dbda8d6ce9 2007-07-21 drh: ** be the min() or max() of a single column of the table. The column dbda8d6ce9 2007-07-21 drh: ** in the min() or max() function must be indexed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The parameters to this routine are the same as for sqlite3Select(). dbda8d6ce9 2007-07-21 drh: ** See the header comment on that routine for additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr; dbda8d6ce9 2007-07-21 drh: int iCol; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: Index *pIdx; dbda8d6ce9 2007-07-21 drh: int base; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: int seekOp; dbda8d6ce9 2007-07-21 drh: ExprList *pEList, *pList, eList; dbda8d6ce9 2007-07-21 drh: struct ExprList_item eListItem; dbda8d6ce9 2007-07-21 drh: SrcList *pSrc; dbda8d6ce9 2007-07-21 drh: int brk; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to see if this query is a simple min() or max() query. Return dbda8d6ce9 2007-07-21 drh: ** zero if it is not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pGroupBy || p->pHaving || p->pWhere ) return 0; dbda8d6ce9 2007-07-21 drh: pSrc = p->pSrc; dbda8d6ce9 2007-07-21 drh: if( pSrc->nSrc!=1 ) return 0; dbda8d6ce9 2007-07-21 drh: pEList = p->pEList; dbda8d6ce9 2007-07-21 drh: if( pEList->nExpr!=1 ) return 0; dbda8d6ce9 2007-07-21 drh: pExpr = pEList->a[0].pExpr; dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_AGG_FUNCTION ) return 0; dbda8d6ce9 2007-07-21 drh: pList = pExpr->pList; dbda8d6ce9 2007-07-21 drh: if( pList==0 || pList->nExpr!=1 ) return 0; dbda8d6ce9 2007-07-21 drh: if( pExpr->token.n!=3 ) return 0; dbda8d6ce9 2007-07-21 drh: if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){ dbda8d6ce9 2007-07-21 drh: seekOp = OP_Rewind; dbda8d6ce9 2007-07-21 drh: }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){ dbda8d6ce9 2007-07-21 drh: seekOp = OP_Last; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pExpr = pList->a[0].pExpr; dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_COLUMN ) return 0; dbda8d6ce9 2007-07-21 drh: iCol = pExpr->iColumn; dbda8d6ce9 2007-07-21 drh: pTab = pSrc->a[0].pTab; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This optimization cannot be used with virtual tables. */ dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ) return 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we get to here, it means the query is of the correct form. dbda8d6ce9 2007-07-21 drh: ** Check to make sure we have an index and make pIdx point to the dbda8d6ce9 2007-07-21 drh: ** appropriate index. If the min() or max() is on an INTEGER PRIMARY dbda8d6ce9 2007-07-21 drh: ** key column, no index is necessary so set pIdx to NULL. If no dbda8d6ce9 2007-07-21 drh: ** usable index is found, return 0. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( iCol<0 ){ dbda8d6ce9 2007-07-21 drh: pIdx = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr); dbda8d6ce9 2007-07-21 drh: if( pColl==0 ) return 0; dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: assert( pIdx->nColumn>=1 ); dbda8d6ce9 2007-07-21 drh: if( pIdx->aiColumn[0]==iCol && dbda8d6ce9 2007-07-21 drh: 0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pIdx==0 ) return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Identify column types if we will be using the callback. This dbda8d6ce9 2007-07-21 drh: ** step is skipped if the output is going to a table or a memory cell. dbda8d6ce9 2007-07-21 drh: ** The column names have already been generated in the calling function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) return 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the output is destined for a temporary table, open that table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_EphemTab ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generating code to find the min or the max. Basically all we have dbda8d6ce9 2007-07-21 drh: ** to do is find the first or the last entry in the chosen index. If dbda8d6ce9 2007-07-21 drh: ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first dbda8d6ce9 2007-07-21 drh: ** or last entry in the main table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 || pTab->isEphem ); dbda8d6ce9 2007-07-21 drh: sqlite3CodeVerifySchema(pParse, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); dbda8d6ce9 2007-07-21 drh: base = pSrc->a[0].iCursor; dbda8d6ce9 2007-07-21 drh: brk = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: computeLimitRegisters(pParse, p, brk); dbda8d6ce9 2007-07-21 drh: if( pSrc->a[0].pSelect==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pIdx==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, seekOp, base, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Even though the cursor used to open the index here is closed dbda8d6ce9 2007-07-21 drh: ** as soon as a single value has been read from it, allocate it dbda8d6ce9 2007-07-21 drh: ** using (pParse->nTab++) to prevent the cursor id from being dbda8d6ce9 2007-07-21 drh: ** reused. This is important for statements of the form dbda8d6ce9 2007-07-21 drh: ** "INSERT INTO x SELECT max() FROM x". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int iIdx; dbda8d6ce9 2007-07-21 drh: KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); dbda8d6ce9 2007-07-21 drh: iIdx = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: assert( pIdx->pSchema==pTab->pSchema ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum, dbda8d6ce9 2007-07-21 drh: (char*)pKey, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: if( seekOp==OP_Rewind ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0); dbda8d6ce9 2007-07-21 drh: seekOp = OP_MoveGt; dbda8d6ce9 2007-07-21 drh: } d8590e093f 2007-07-24 drh: if( pIdx->aSortOrder[0]==SQLITE_SO_DESC ){ d8590e093f 2007-07-24 drh: /* Ticket #2514: invert the seek operator if we are using d8590e093f 2007-07-24 drh: ** a descending index. */ d8590e093f 2007-07-24 drh: if( seekOp==OP_Last ){ d8590e093f 2007-07-24 drh: seekOp = OP_Rewind; d8590e093f 2007-07-24 drh: }else{ d8590e093f 2007-07-24 drh: assert( seekOp==OP_MoveGt ); d8590e093f 2007-07-24 drh: seekOp = OP_MoveLt; d8590e093f 2007-07-24 drh: } d8590e093f 2007-07-24 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, seekOp, iIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxRowid, iIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: eList.nExpr = 1; dbda8d6ce9 2007-07-21 drh: memset(&eListItem, 0, sizeof(eListItem)); dbda8d6ce9 2007-07-21 drh: eList.a = &eListItem; dbda8d6ce9 2007-07-21 drh: eList.a[0].pExpr = pExpr; dbda8d6ce9 2007-07-21 drh: selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, brk); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, base, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Analyze and ORDER BY or GROUP BY clause in a SELECT statement. Return dbda8d6ce9 2007-07-21 drh: ** the number of errors seen. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An ORDER BY or GROUP BY is a list of expressions. If any expression dbda8d6ce9 2007-07-21 drh: ** is an integer constant, then that expression is replaced by the dbda8d6ce9 2007-07-21 drh: ** corresponding entry in the result set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int processOrderGroupBy( dbda8d6ce9 2007-07-21 drh: NameContext *pNC, /* Name context of the SELECT statement. */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */ dbda8d6ce9 2007-07-21 drh: const char *zType /* Either "ORDER" or "GROUP", as appropriate */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: ExprList *pEList = pNC->pEList; /* The result set of the SELECT */ dbda8d6ce9 2007-07-21 drh: Parse *pParse = pNC->pParse; /* The result set of the SELECT */ dbda8d6ce9 2007-07-21 drh: assert( pEList ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pOrderBy==0 ) return 0; dbda8d6ce9 2007-07-21 drh: if( pOrderBy->nExpr>SQLITE_MAX_COLUMN ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<pOrderBy->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: int iCol; dbda8d6ce9 2007-07-21 drh: Expr *pE = pOrderBy->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprIsInteger(pE, &iCol) ){ dbda8d6ce9 2007-07-21 drh: if( iCol>0 && iCol<=pEList->nExpr ){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = pE->pColl; dbda8d6ce9 2007-07-21 drh: int flags = pE->flags & EP_ExpCollate; dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pE); c287665ba8 2007-09-14 drh: pE = sqlite3ExprDup(pParse->db, pEList->a[iCol-1].pExpr); c287665ba8 2007-09-14 drh: pOrderBy->a[i].pExpr = pE; dbda8d6ce9 2007-07-21 drh: if( pColl && flags ){ dbda8d6ce9 2007-07-21 drh: pE->pColl = pColl; dbda8d6ce9 2007-07-21 drh: pE->flags |= flags; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, dbda8d6ce9 2007-07-21 drh: "%s BY column number %d out of range - should be " dbda8d6ce9 2007-07-21 drh: "between 1 and %d", zType, iCol, pEList->nExpr); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(pNC, pE) ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine resolves any names used in the result set of the dbda8d6ce9 2007-07-21 drh: ** supplied SELECT statement. If the SELECT statement being resolved dbda8d6ce9 2007-07-21 drh: ** is a sub-select, then pOuterNC is a pointer to the NameContext dbda8d6ce9 2007-07-21 drh: ** of the parent SELECT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3SelectResolve( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: Select *p, /* The SELECT statement being coded. */ dbda8d6ce9 2007-07-21 drh: NameContext *pOuterNC /* The outer name context. May be NULL. */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: ExprList *pEList; /* Result set. */ dbda8d6ce9 2007-07-21 drh: int i; /* For-loop variable used in multiple places */ dbda8d6ce9 2007-07-21 drh: NameContext sNC; /* Local name-context */ dbda8d6ce9 2007-07-21 drh: ExprList *pGroupBy; /* The group by clause */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this routine has run before, return immediately. */ dbda8d6ce9 2007-07-21 drh: if( p->isResolved ){ dbda8d6ce9 2007-07-21 drh: assert( !pOuterNC ); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->isResolved = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there have already been errors, do nothing. */ dbda8d6ce9 2007-07-21 drh: if( pParse->nErr>0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Prepare the select statement. This call will allocate all cursors dbda8d6ce9 2007-07-21 drh: ** required to handle the tables and subqueries in the FROM clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( prepSelectStmt(pParse, p) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Resolve the expressions in the LIMIT and OFFSET clauses. These dbda8d6ce9 2007-07-21 drh: ** are not allowed to refer to any names, so pass an empty NameContext. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: memset(&sNC, 0, sizeof(sNC)); dbda8d6ce9 2007-07-21 drh: sNC.pParse = pParse; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, p->pLimit) || dbda8d6ce9 2007-07-21 drh: sqlite3ExprResolveNames(&sNC, p->pOffset) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set up the local name-context to pass to ExprResolveNames() to dbda8d6ce9 2007-07-21 drh: ** resolve the expression-list. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sNC.allowAgg = 1; dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = p->pSrc; dbda8d6ce9 2007-07-21 drh: sNC.pNext = pOuterNC; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Resolve names in the result set. */ dbda8d6ce9 2007-07-21 drh: pEList = p->pEList; dbda8d6ce9 2007-07-21 drh: if( !pEList ) return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pEList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: Expr *pX = pEList->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, pX) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there are no aggregate functions in the result-set, and no GROUP BY dbda8d6ce9 2007-07-21 drh: ** expression, do not allow aggregates in any of the other expressions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( !p->isAgg ); dbda8d6ce9 2007-07-21 drh: pGroupBy = p->pGroupBy; dbda8d6ce9 2007-07-21 drh: if( pGroupBy || sNC.hasAgg ){ dbda8d6ce9 2007-07-21 drh: p->isAgg = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sNC.allowAgg = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a HAVING clause is present, then there must be a GROUP BY clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pHaving && !pGroupBy ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add the expression list to the name-context before parsing the dbda8d6ce9 2007-07-21 drh: ** other expressions in the SELECT statement. This is so that dbda8d6ce9 2007-07-21 drh: ** expressions in the WHERE clause (etc.) can refer to expressions by dbda8d6ce9 2007-07-21 drh: ** aliases in the result set. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Minor point: If this is the case, then the expression will be dbda8d6ce9 2007-07-21 drh: ** re-evaluated for each reference to it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sNC.pEList = p->pEList; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, p->pWhere) || dbda8d6ce9 2007-07-21 drh: sqlite3ExprResolveNames(&sNC, p->pHaving) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pPrior==0 ){ dbda8d6ce9 2007-07-21 drh: if( processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") || dbda8d6ce9 2007-07-21 drh: processOrderGroupBy(&sNC, pGroupBy, "GROUP") ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( pParse->db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure the GROUP BY clause does not contain aggregate functions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pGroupBy ){ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=0, pItem=pGroupBy->a; i<pGroupBy->nExpr; i++, pItem++){ dbda8d6ce9 2007-07-21 drh: if( ExprHasProperty(pItem->pExpr, EP_Agg) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "aggregate functions are not allowed in " dbda8d6ce9 2007-07-21 drh: "the GROUP BY clause"); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is one SELECT of a compound, be sure to resolve names dbda8d6ce9 2007-07-21 drh: ** in the other SELECTs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pPrior ){ dbda8d6ce9 2007-07-21 drh: return sqlite3SelectResolve(pParse, p->pPrior, pOuterNC); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Reset the aggregate accumulator. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The aggregate accumulator is a set of memory cells that hold dbda8d6ce9 2007-07-21 drh: ** intermediate results while calculating an aggregate. This dbda8d6ce9 2007-07-21 drh: ** routine simply stores NULLs in all of those memory cells. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct AggInfo_func *pFunc; dbda8d6ce9 2007-07-21 drh: if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<pAggInfo->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemNull, pAggInfo->aCol[i].iMem, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemNull, pFunc->iMem, 0); dbda8d6ce9 2007-07-21 drh: if( pFunc->iDistinct>=0 ){ dbda8d6ce9 2007-07-21 drh: Expr *pE = pFunc->pExpr; dbda8d6ce9 2007-07-21 drh: if( pE->pList==0 || pE->pList->nExpr!=1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "DISTINCT in aggregate must be followed " dbda8d6ce9 2007-07-21 drh: "by an expression"); dbda8d6ce9 2007-07-21 drh: pFunc->iDistinct = -1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenEphemeral, pFunc->iDistinct, 0, dbda8d6ce9 2007-07-21 drh: (char*)pKeyInfo, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invoke the OP_AggFinalize opcode for every aggregate function dbda8d6ce9 2007-07-21 drh: ** in the AggInfo structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct AggInfo_func *pF; dbda8d6ce9 2007-07-21 drh: for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){ dbda8d6ce9 2007-07-21 drh: ExprList *pList = pF->pExpr->pList; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, dbda8d6ce9 2007-07-21 drh: (void*)pF->pFunc, P3_FUNCDEF); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Update the accumulator memory cells for an aggregate based on dbda8d6ce9 2007-07-21 drh: ** the current cursor position. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: struct AggInfo_func *pF; dbda8d6ce9 2007-07-21 drh: struct AggInfo_col *pC; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pAggInfo->directMode = 1; dbda8d6ce9 2007-07-21 drh: for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){ dbda8d6ce9 2007-07-21 drh: int nArg; dbda8d6ce9 2007-07-21 drh: int addrNext = 0; dbda8d6ce9 2007-07-21 drh: ExprList *pList = pF->pExpr->pList; dbda8d6ce9 2007-07-21 drh: if( pList ){ dbda8d6ce9 2007-07-21 drh: nArg = pList->nExpr; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeExprList(pParse, pList); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: nArg = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pF->iDistinct>=0 ){ dbda8d6ce9 2007-07-21 drh: addrNext = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: assert( nArg==1 ); dbda8d6ce9 2007-07-21 drh: codeDistinct(v, pF->iDistinct, addrNext, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pF->pFunc->needCollSeq ){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = 0; dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pItem; dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: assert( pList!=0 ); /* pList!=0 if pF->pFunc->needCollSeq is true */ dbda8d6ce9 2007-07-21 drh: for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){ dbda8d6ce9 2007-07-21 drh: pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pColl ){ dbda8d6ce9 2007-07-21 drh: pColl = pParse->db->pDfltColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_AggStep, pF->iMem, nArg, (void*)pF->pFunc, P3_FUNCDEF); dbda8d6ce9 2007-07-21 drh: if( addrNext ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, addrNext); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pC->pExpr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, pC->iMem, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pAggInfo->directMode = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for the given SELECT statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The results are distributed in various ways depending on the dbda8d6ce9 2007-07-21 drh: ** value of eDest and iParm. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** eDest Value Result dbda8d6ce9 2007-07-21 drh: ** ------------ ------------------------------------------- dbda8d6ce9 2007-07-21 drh: ** SRT_Callback Invoke the callback for each row of the result. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SRT_Mem Store first result in memory cell iParm dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SRT_Set Store results as keys of table iParm. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SRT_Union Store results as a key in a temporary table iParm dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SRT_Except Remove results from the temporary table iParm. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SRT_Table Store results in temporary table iParm dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The table above is incomplete. Additional eDist value have be added dbda8d6ce9 2007-07-21 drh: ** since this comment was written. See the selectInnerLoop() function for dbda8d6ce9 2007-07-21 drh: ** a complete listing of the allowed values of eDest and their meanings. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine returns the number of errors. If any errors are dbda8d6ce9 2007-07-21 drh: ** encountered, then an appropriate error message is left in dbda8d6ce9 2007-07-21 drh: ** pParse->zErrMsg. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine does NOT free the Select structure passed in. The dbda8d6ce9 2007-07-21 drh: ** calling function needs to do that. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pParent, parentTab, and *pParentAgg fields are filled in if this dbda8d6ce9 2007-07-21 drh: ** SELECT is a subquery. This routine may try to combine this SELECT dbda8d6ce9 2007-07-21 drh: ** with its parent to form a single flat query. In so doing, it might dbda8d6ce9 2007-07-21 drh: ** change the parent query from a non-aggregate to an aggregate query. dbda8d6ce9 2007-07-21 drh: ** For that reason, the pParentAgg flag is passed as a pointer, so it dbda8d6ce9 2007-07-21 drh: ** can be changed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Example 1: The meaning of the pParent parameter. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT * FROM t1 JOIN (SELECT x, count(*) FROM t2) JOIN t3; dbda8d6ce9 2007-07-21 drh: ** \ \_______ subquery _______/ / dbda8d6ce9 2007-07-21 drh: ** \ / dbda8d6ce9 2007-07-21 drh: ** \____________________ outer query ___________________/ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is called for the outer query first. For that call, dbda8d6ce9 2007-07-21 drh: ** pParent will be NULL. During the processing of the outer query, this dbda8d6ce9 2007-07-21 drh: ** routine is called recursively to handle the subquery. For the recursive dbda8d6ce9 2007-07-21 drh: ** call, pParent will point to the outer query. Because the subquery is dbda8d6ce9 2007-07-21 drh: ** the second element in a three-way join, the parentTab parameter will dbda8d6ce9 2007-07-21 drh: ** be 1 (the 2nd value of a 0-indexed array.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Select( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: Select *p, /* The SELECT statement being coded. */ dbda8d6ce9 2007-07-21 drh: int eDest, /* How to dispose of the results */ dbda8d6ce9 2007-07-21 drh: int iParm, /* A parameter used by the eDest disposal method */ dbda8d6ce9 2007-07-21 drh: Select *pParent, /* Another SELECT for which this is a sub-query */ dbda8d6ce9 2007-07-21 drh: int parentTab, /* Index in pParent->pSrc of this query */ dbda8d6ce9 2007-07-21 drh: int *pParentAgg, /* True if pParent uses aggregate functions */ dbda8d6ce9 2007-07-21 drh: char *aff /* If eDest is SRT_Union, the affinity string */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i, j; /* Loop counters */ dbda8d6ce9 2007-07-21 drh: WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */ dbda8d6ce9 2007-07-21 drh: Vdbe *v; /* The virtual machine under construction */ dbda8d6ce9 2007-07-21 drh: int isAgg; /* True for select lists like "count(*)" */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList; /* List of columns to extract. */ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList; /* List of tables to select from */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere; /* The WHERE clause. May be NULL */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ dbda8d6ce9 2007-07-21 drh: ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ dbda8d6ce9 2007-07-21 drh: Expr *pHaving; /* The HAVING clause. May be NULL */ dbda8d6ce9 2007-07-21 drh: int isDistinct; /* True if the DISTINCT keyword is present */ dbda8d6ce9 2007-07-21 drh: int distinct; /* Table to use for the distinct set */ dbda8d6ce9 2007-07-21 drh: int rc = 1; /* Value to return from this function */ dbda8d6ce9 2007-07-21 drh: int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ dbda8d6ce9 2007-07-21 drh: AggInfo sAggInfo; /* Information used by aggregate queries */ dbda8d6ce9 2007-07-21 drh: int iEnd; /* Address of the end of the query */ c287665ba8 2007-09-14 drh: sqlite3 *db; /* The database connection */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: db = pParse->db; c287665ba8 2007-09-14 drh: if( p==0 || db->mallocFailed || pParse->nErr ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; dbda8d6ce9 2007-07-21 drh: memset(&sAggInfo, 0, sizeof(sAggInfo)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_COMPOUND_SELECT dbda8d6ce9 2007-07-21 drh: /* If there is are a sequence of queries, do the earlier ones first. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->pPrior ){ dbda8d6ce9 2007-07-21 drh: if( p->pRightmost==0 ){ dbda8d6ce9 2007-07-21 drh: Select *pLoop; dbda8d6ce9 2007-07-21 drh: int cnt = 0; dbda8d6ce9 2007-07-21 drh: for(pLoop=p; pLoop; pLoop=pLoop->pPrior, cnt++){ dbda8d6ce9 2007-07-21 drh: pLoop->pRightmost = p; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( SQLITE_MAX_COMPOUND_SELECT>0 && cnt>SQLITE_MAX_COMPOUND_SELECT ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return multiSelect(pParse, p, eDest, iParm, aff); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pOrderBy = p->pOrderBy; dbda8d6ce9 2007-07-21 drh: if( IgnorableOrderby(eDest) ){ dbda8d6ce9 2007-07-21 drh: p->pOrderBy = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SelectResolve(pParse, p, 0) ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->pOrderBy = pOrderBy; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make local copies of the parameters for this query. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTabList = p->pSrc; dbda8d6ce9 2007-07-21 drh: pWhere = p->pWhere; dbda8d6ce9 2007-07-21 drh: pGroupBy = p->pGroupBy; dbda8d6ce9 2007-07-21 drh: pHaving = p->pHaving; dbda8d6ce9 2007-07-21 drh: isAgg = p->isAgg; dbda8d6ce9 2007-07-21 drh: isDistinct = p->isDistinct; dbda8d6ce9 2007-07-21 drh: pEList = p->pEList; dbda8d6ce9 2007-07-21 drh: if( pEList==0 ) goto select_end; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Do not even attempt to generate any code if we have already seen dbda8d6ce9 2007-07-21 drh: ** errors before this routine starts. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pParse->nErr>0 ) goto select_end; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If writing to memory or generating a set dbda8d6ce9 2007-07-21 drh: ** only a single column may be output. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: if( checkForMultiColumnSelectError(pParse, eDest, pEList->nExpr) ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* ORDER BY is ignored for some destinations. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( IgnorableOrderby(eDest) ){ dbda8d6ce9 2007-07-21 drh: pOrderBy = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin generating code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) goto select_end; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code for all sub-queries in the FROM clause dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTabList->nSrc; i++){ dbda8d6ce9 2007-07-21 drh: const char *zSavedAuthContext = 0; dbda8d6ce9 2007-07-21 drh: int needRestoreContext; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem = &pTabList->a[i]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pItem->pSelect==0 || pItem->isPopulated ) continue; dbda8d6ce9 2007-07-21 drh: if( pItem->zName!=0 ){ dbda8d6ce9 2007-07-21 drh: zSavedAuthContext = pParse->zAuthContext; dbda8d6ce9 2007-07-21 drh: pParse->zAuthContext = pItem->zName; dbda8d6ce9 2007-07-21 drh: needRestoreContext = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: needRestoreContext = 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 dbda8d6ce9 2007-07-21 drh: /* Increment Parse.nHeight by the height of the largest expression dbda8d6ce9 2007-07-21 drh: ** tree refered to by this, the parent select. The child select dbda8d6ce9 2007-07-21 drh: ** may contain expression trees of at most dbda8d6ce9 2007-07-21 drh: ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit dbda8d6ce9 2007-07-21 drh: ** more conservative than necessary, but much easier than enforcing dbda8d6ce9 2007-07-21 drh: ** an exact limit. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pParse->nHeight += sqlite3SelectExprHeight(p); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3Select(pParse, pItem->pSelect, SRT_EphemTab, dbda8d6ce9 2007-07-21 drh: pItem->iCursor, p, i, &isAgg, 0); c287665ba8 2007-09-14 drh: #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 dbda8d6ce9 2007-07-21 drh: pParse->nHeight -= sqlite3SelectExprHeight(p); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( needRestoreContext ){ dbda8d6ce9 2007-07-21 drh: pParse->zAuthContext = zSavedAuthContext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTabList = p->pSrc; dbda8d6ce9 2007-07-21 drh: pWhere = p->pWhere; dbda8d6ce9 2007-07-21 drh: if( !IgnorableOrderby(eDest) ){ dbda8d6ce9 2007-07-21 drh: pOrderBy = p->pOrderBy; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pGroupBy = p->pGroupBy; dbda8d6ce9 2007-07-21 drh: pHaving = p->pHaving; dbda8d6ce9 2007-07-21 drh: isDistinct = p->isDistinct; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check for the special case of a min() or max() function by itself dbda8d6ce9 2007-07-21 drh: ** in the result set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){ dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to see if this is a subquery that can be "flattened" into its parent. dbda8d6ce9 2007-07-21 drh: ** If flattening is a possiblity, do so and return immediately. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: if( pParent && pParentAgg && c287665ba8 2007-09-14 drh: flattenSubquery(db, pParent, parentTab, *pParentAgg, isAgg) ){ dbda8d6ce9 2007-07-21 drh: if( isAgg ) *pParentAgg = 1; dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there is an ORDER BY clause, then this sorting dbda8d6ce9 2007-07-21 drh: ** index might end up being unused if the data can be dbda8d6ce9 2007-07-21 drh: ** extracted in pre-sorted order. If that is the case, then the dbda8d6ce9 2007-07-21 drh: ** OP_OpenEphemeral instruction will be changed to an OP_Noop once dbda8d6ce9 2007-07-21 drh: ** we figure out that the sorting index is not needed. The addrSortIndex dbda8d6ce9 2007-07-21 drh: ** variable is used to facilitate that change. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo; dbda8d6ce9 2007-07-21 drh: if( pParse->nErr ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pKeyInfo = keyInfoFromExprList(pParse, pOrderBy); dbda8d6ce9 2007-07-21 drh: pOrderBy->iECursor = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: p->addrOpenEphm[2] = addrSortIndex = dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+2, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: addrSortIndex = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the output is destined for a temporary table, open that table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( eDest==SRT_EphemTab ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, pEList->nExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the limiter. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: iEnd = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: computeLimitRegisters(pParse, p, iEnd); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open a virtual index to use for the distinct set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( isDistinct ){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo; dbda8d6ce9 2007-07-21 drh: distinct = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: pKeyInfo = keyInfoFromExprList(pParse, p->pEList); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenEphemeral, distinct, 0, dbda8d6ce9 2007-07-21 drh: (char*)pKeyInfo, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: distinct = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Aggregate and non-aggregate queries are handled differently */ dbda8d6ce9 2007-07-21 drh: if( !isAgg && pGroupBy==0 ){ dbda8d6ce9 2007-07-21 drh: /* This case is for non-aggregate queries dbda8d6ce9 2007-07-21 drh: ** Begin the database scan dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy); dbda8d6ce9 2007-07-21 drh: if( pWInfo==0 ) goto select_end; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If sorting index that was created by a prior OP_OpenEphemeral dbda8d6ce9 2007-07-21 drh: ** instruction ended up not being needed, then change the OP_OpenEphemeral dbda8d6ce9 2007-07-21 drh: ** into an OP_Noop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( addrSortIndex>=0 && pOrderBy==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); dbda8d6ce9 2007-07-21 drh: p->addrOpenEphm[2] = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Use the standard inner loop dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, dbda8d6ce9 2007-07-21 drh: iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* End the database scan loop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3WhereEnd(pWInfo); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* This is the processing for aggregate queries */ dbda8d6ce9 2007-07-21 drh: NameContext sNC; /* Name context for processing aggregate information */ dbda8d6ce9 2007-07-21 drh: int iAMem; /* First Mem address for storing current GROUP BY */ dbda8d6ce9 2007-07-21 drh: int iBMem; /* First Mem address for previous GROUP BY */ dbda8d6ce9 2007-07-21 drh: int iUseFlag; /* Mem address holding flag indicating that at least dbda8d6ce9 2007-07-21 drh: ** one row of the input to the aggregator has been dbda8d6ce9 2007-07-21 drh: ** processed */ dbda8d6ce9 2007-07-21 drh: int iAbortFlag; /* Mem address which causes query abort if positive */ dbda8d6ce9 2007-07-21 drh: int groupBySort; /* Rows come from source in GROUP BY order */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following variables hold addresses or labels for parts of the dbda8d6ce9 2007-07-21 drh: ** virtual machine program we are putting together */ dbda8d6ce9 2007-07-21 drh: int addrOutputRow; /* Start of subroutine that outputs a result row */ dbda8d6ce9 2007-07-21 drh: int addrSetAbort; /* Set the abort flag and return */ dbda8d6ce9 2007-07-21 drh: int addrInitializeLoop; /* Start of code that initializes the input loop */ dbda8d6ce9 2007-07-21 drh: int addrTopOfLoop; /* Top of the input loop */ dbda8d6ce9 2007-07-21 drh: int addrGroupByChange; /* Code that runs when any GROUP BY term changes */ dbda8d6ce9 2007-07-21 drh: int addrProcessRow; /* Code to process a single input row */ dbda8d6ce9 2007-07-21 drh: int addrEnd; /* End of all processing */ dbda8d6ce9 2007-07-21 drh: int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ dbda8d6ce9 2007-07-21 drh: int addrReset; /* Subroutine for resetting the accumulator */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: addrEnd = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in dbda8d6ce9 2007-07-21 drh: ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the dbda8d6ce9 2007-07-21 drh: ** SELECT statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: memset(&sNC, 0, sizeof(sNC)); dbda8d6ce9 2007-07-21 drh: sNC.pParse = pParse; dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = pTabList; dbda8d6ce9 2007-07-21 drh: sNC.pAggInfo = &sAggInfo; dbda8d6ce9 2007-07-21 drh: sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; dbda8d6ce9 2007-07-21 drh: sAggInfo.pGroupBy = pGroupBy; dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sAggInfo.nAccumulator = sAggInfo.nColumn; dbda8d6ce9 2007-07-21 drh: for(i=0; i<sAggInfo.nFunc; i++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList) ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( db->mallocFailed ) goto select_end; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Processing for aggregates with GROUP BY is very different and dbda8d6ce9 2007-07-21 drh: ** much more complex tha aggregates without a GROUP BY. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pGroupBy ){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKeyInfo; /* Keying information for the group by clause */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create labels that we will be needing dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: addrInitializeLoop = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: addrGroupByChange = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: addrProcessRow = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there is a GROUP BY clause we might need a sorting index to dbda8d6ce9 2007-07-21 drh: ** implement it. Allocate that sorting index now. If it turns out dbda8d6ce9 2007-07-21 drh: ** that we do not need it after all, the OpenEphemeral instruction dbda8d6ce9 2007-07-21 drh: ** will be converted into a Noop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sAggInfo.sortingIdx = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: pKeyInfo = keyInfoFromExprList(pParse, pGroupBy); dbda8d6ce9 2007-07-21 drh: addrSortingIdx = dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenEphemeral, sAggInfo.sortingIdx, dbda8d6ce9 2007-07-21 drh: sAggInfo.nSortingColumn, dbda8d6ce9 2007-07-21 drh: (char*)pKeyInfo, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize memory locations used by GROUP BY aggregate processing dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: iUseFlag = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: iAbortFlag = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: iAMem = pParse->nMem; dbda8d6ce9 2007-07-21 drh: pParse->nMem += pGroupBy->nExpr; dbda8d6ce9 2007-07-21 drh: iBMem = pParse->nMem; dbda8d6ce9 2007-07-21 drh: pParse->nMem += pGroupBy->nExpr; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, iAbortFlag); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# clear abort flag")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, iUseFlag); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# indicate accumulator empty")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, addrInitializeLoop); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate a subroutine that outputs a single row of the result dbda8d6ce9 2007-07-21 drh: ** set. This subroutine first looks at the iUseFlag. If iUseFlag dbda8d6ce9 2007-07-21 drh: ** is less than or equal to zero, the subroutine is a no-op. If dbda8d6ce9 2007-07-21 drh: ** the processing calls for the query to abort, this subroutine dbda8d6ce9 2007-07-21 drh: ** increments the iAbortFlag memory location before returning in dbda8d6ce9 2007-07-21 drh: ** order to signal the caller to abort. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: addrSetAbort = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 1, iAbortFlag); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# set abort flag")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Return, 0, 0); dbda8d6ce9 2007-07-21 drh: addrOutputRow = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IfMemPos, iUseFlag, addrOutputRow+2); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# Groupby result generator entry point")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Return, 0, 0); dbda8d6ce9 2007-07-21 drh: finalizeAggFunctions(pParse, &sAggInfo); dbda8d6ce9 2007-07-21 drh: if( pHaving ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: rc = selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy, dbda8d6ce9 2007-07-21 drh: distinct, eDest, iParm, dbda8d6ce9 2007-07-21 drh: addrOutputRow+1, addrSetAbort, aff); dbda8d6ce9 2007-07-21 drh: if( rc ){ dbda8d6ce9 2007-07-21 drh: goto select_end; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Return, 0, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# end groupby result generator")); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate a subroutine that will reset the group-by accumulator dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: addrReset = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: resetAccumulator(pParse, &sAggInfo); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Return, 0, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin a loop that will extract all source rows in GROUP BY order. dbda8d6ce9 2007-07-21 drh: ** This might involve two separate loops with an OP_Sort in between, or dbda8d6ce9 2007-07-21 drh: ** it might be a single loop that uses an index to extract information dbda8d6ce9 2007-07-21 drh: ** in the right order to begin with. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, addrInitializeLoop); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset); dbda8d6ce9 2007-07-21 drh: pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy); dbda8d6ce9 2007-07-21 drh: if( pWInfo==0 ) goto select_end; dbda8d6ce9 2007-07-21 drh: if( pGroupBy==0 ){ dbda8d6ce9 2007-07-21 drh: /* The optimizer is able to deliver rows in group by order so dbda8d6ce9 2007-07-21 drh: ** we do not have to sort. The OP_OpenEphemeral table will be dbda8d6ce9 2007-07-21 drh: ** cancelled later because we still need to use the pKeyInfo dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pGroupBy = p->pGroupBy; dbda8d6ce9 2007-07-21 drh: groupBySort = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Rows are coming out in undetermined order. We have to push dbda8d6ce9 2007-07-21 drh: ** each row into a sorting index, terminate the first loop, dbda8d6ce9 2007-07-21 drh: ** then loop over the sorting index in order to get the output dbda8d6ce9 2007-07-21 drh: ** in sorted order dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: groupBySort = 1; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeExprList(pParse, pGroupBy); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Sequence, sAggInfo.sortingIdx, 0); dbda8d6ce9 2007-07-21 drh: j = pGroupBy->nExpr+1; dbda8d6ce9 2007-07-21 drh: for(i=0; i<sAggInfo.nColumn; i++){ dbda8d6ce9 2007-07-21 drh: struct AggInfo_col *pCol = &sAggInfo.aCol[i]; dbda8d6ce9 2007-07-21 drh: if( pCol->iSorterColumn<j ) continue; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeGetColumn(v, pCol->pTab, pCol->iColumn, pCol->iTable); dbda8d6ce9 2007-07-21 drh: j++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, j, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxInsert, sAggInfo.sortingIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3WhereEnd(pWInfo); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Sort, sAggInfo.sortingIdx, addrEnd); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# GROUP BY sort")); dbda8d6ce9 2007-07-21 drh: sAggInfo.useSortingIdx = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Evaluate the current GROUP BY terms and store in b0, b1, b2... dbda8d6ce9 2007-07-21 drh: ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) dbda8d6ce9 2007-07-21 drh: ** Then compare the current GROUP BY terms against the GROUP BY terms dbda8d6ce9 2007-07-21 drh: ** from the previous row currently stored in a0, a1, a2... dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: addrTopOfLoop = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: for(j=0; j<pGroupBy->nExpr; j++){ dbda8d6ce9 2007-07-21 drh: if( groupBySort ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, sAggInfo.sortingIdx, j); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sAggInfo.directMode = 1; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, iBMem+j, j<pGroupBy->nExpr-1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(j=pGroupBy->nExpr-1; j>=0; j--){ dbda8d6ce9 2007-07-21 drh: if( j<pGroupBy->nExpr-1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iBMem+j, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, iAMem+j, 0); dbda8d6ce9 2007-07-21 drh: if( j==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Eq, 0x200, addrProcessRow); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Ne, 0x200, addrGroupByChange); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, (void*)pKeyInfo->aColl[j], P3_COLLSEQ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code that runs whenever the GROUP BY changes. dbda8d6ce9 2007-07-21 drh: ** Change in the GROUP BY are detected by the previous code dbda8d6ce9 2007-07-21 drh: ** block. If there were no changes, this block is skipped. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This code copies current group by terms in b0,b1,b2,... dbda8d6ce9 2007-07-21 drh: ** over to a0,a1,a2. It then calls the output subroutine dbda8d6ce9 2007-07-21 drh: ** and resets the aggregate accumulator registers in preparation dbda8d6ce9 2007-07-21 drh: ** for the next GROUP BY batch. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, addrGroupByChange); dbda8d6ce9 2007-07-21 drh: for(j=0; j<pGroupBy->nExpr; j++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemMove, iAMem+j, iBMem+j); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# output one row")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IfMemPos, iAbortFlag, addrEnd); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# check abort flag")); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# reset accumulator")); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update the aggregate accumulators based on the content of dbda8d6ce9 2007-07-21 drh: ** the current row dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, addrProcessRow); dbda8d6ce9 2007-07-21 drh: updateAccumulator(pParse, &sAggInfo); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 1, iUseFlag); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# indicate data in accumulator")); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* End of the loop dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( groupBySort ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3WhereEnd(pWInfo); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Output the final row of result dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# output final row")); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: } /* endif pGroupBy */ dbda8d6ce9 2007-07-21 drh: else { dbda8d6ce9 2007-07-21 drh: /* This case runs if the aggregate has no GROUP BY clause. The dbda8d6ce9 2007-07-21 drh: ** processing is much simpler since there is only a single row dbda8d6ce9 2007-07-21 drh: ** of output. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: resetAccumulator(pParse, &sAggInfo); dbda8d6ce9 2007-07-21 drh: pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); dbda8d6ce9 2007-07-21 drh: if( pWInfo==0 ) goto select_end; dbda8d6ce9 2007-07-21 drh: updateAccumulator(pParse, &sAggInfo); dbda8d6ce9 2007-07-21 drh: sqlite3WhereEnd(pWInfo); dbda8d6ce9 2007-07-21 drh: finalizeAggFunctions(pParse, &sAggInfo); dbda8d6ce9 2007-07-21 drh: pOrderBy = 0; dbda8d6ce9 2007-07-21 drh: if( pHaving ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pHaving, addrEnd, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1, dbda8d6ce9 2007-07-21 drh: eDest, iParm, addrEnd, addrEnd, aff); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, addrEnd); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: } /* endif aggregate query */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there is an ORDER BY clause, then we need to sort the results dbda8d6ce9 2007-07-21 drh: ** and send them to the callback one by one. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: generateSortTail(pParse, p, v, pEList->nExpr, eDest, iParm); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: /* If this was a subquery, we have now converted the subquery into a dbda8d6ce9 2007-07-21 drh: ** temporary table. So set the SrcList_item.isPopulated flag to prevent dbda8d6ce9 2007-07-21 drh: ** this subquery from being evaluated again and to force the use of dbda8d6ce9 2007-07-21 drh: ** the temporary table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pParent ){ dbda8d6ce9 2007-07-21 drh: assert( pParent->pSrc->nSrc>parentTab ); dbda8d6ce9 2007-07-21 drh: assert( pParent->pSrc->a[parentTab].pSelect==p ); dbda8d6ce9 2007-07-21 drh: pParent->pSrc->a[parentTab].isPopulated = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump here to skip this query dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, iEnd); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The SELECT was successfully coded. Set the return code to 0 dbda8d6ce9 2007-07-21 drh: ** to indicate no errors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Control jumps to here if an error is encountered above, or upon dbda8d6ce9 2007-07-21 drh: ** successful coding of the SELECT. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: select_end: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Identify column names if we will be using them in a callback. This dbda8d6ce9 2007-07-21 drh: ** step is skipped if the output is going to some other destination. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && eDest==SRT_Callback ){ dbda8d6ce9 2007-07-21 drh: generateColumnNames(pParse, pTabList, pEList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3_free(sAggInfo.aCol); c287665ba8 2007-09-14 drh: sqlite3_free(sAggInfo.aFunc); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_DEBUG) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ******************************************************************************* dbda8d6ce9 2007-07-21 drh: ** The following code is used for testing and debugging only. The code dbda8d6ce9 2007-07-21 drh: ** that follows does not appear in normal builds. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines are used to print out the content of all or part of a dbda8d6ce9 2007-07-21 drh: ** parse structures such as Select or Expr. Such printouts are useful dbda8d6ce9 2007-07-21 drh: ** for helping to understand what is happening inside the code generator dbda8d6ce9 2007-07-21 drh: ** during the execution of complex SELECT statements. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routine are not called anywhere from within the normal dbda8d6ce9 2007-07-21 drh: ** code base. Then are intended to be called from within the debugger dbda8d6ce9 2007-07-21 drh: ** or from temporary "printf" statements inserted for debugging. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PrintExpr(Expr *p){ dbda8d6ce9 2007-07-21 drh: if( p->token.z && p->token.n>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("(%.*s", p->token.n, p->token.z); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("(%d", p->op); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pLeft ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" "); dbda8d6ce9 2007-07-21 drh: sqlite3PrintExpr(p->pLeft); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pRight ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" "); dbda8d6ce9 2007-07-21 drh: sqlite3PrintExpr(p->pRight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(")"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PrintExprList(ExprList *pList){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3PrintExpr(pList->a[i].pExpr); dbda8d6ce9 2007-07-21 drh: if( i<pList->nExpr-1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(", "); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3PrintSelect(Select *p, int indent){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("%*sSELECT(%p) ", indent, "", p); dbda8d6ce9 2007-07-21 drh: sqlite3PrintExprList(p->pEList); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("\n"); dbda8d6ce9 2007-07-21 drh: if( p->pSrc ){ dbda8d6ce9 2007-07-21 drh: char *zPrefix; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: zPrefix = "FROM"; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->pSrc->nSrc; i++){ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem = &p->pSrc->a[i]; dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("%*s ", indent+6, zPrefix); dbda8d6ce9 2007-07-21 drh: zPrefix = ""; dbda8d6ce9 2007-07-21 drh: if( pItem->pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("(\n"); dbda8d6ce9 2007-07-21 drh: sqlite3PrintSelect(pItem->pSelect, indent+10); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("%*s)", indent+8, ""); dbda8d6ce9 2007-07-21 drh: }else if( pItem->zName ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("%s", pItem->zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pItem->pTab ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("(table: %s)", pItem->pTab->zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pItem->zAlias ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" AS %s", pItem->zAlias); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<p->pSrc->nSrc-1 ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(","); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("\n"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pWhere ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("%*s WHERE ", indent, ""); dbda8d6ce9 2007-07-21 drh: sqlite3PrintExpr(p->pWhere); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("\n"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pGroupBy ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("%*s GROUP BY ", indent, ""); dbda8d6ce9 2007-07-21 drh: sqlite3PrintExprList(p->pGroupBy); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("\n"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pHaving ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("%*s HAVING ", indent, ""); dbda8d6ce9 2007-07-21 drh: sqlite3PrintExpr(p->pHaving); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("\n"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pOrderBy ){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("%*s ORDER BY ", indent, ""); dbda8d6ce9 2007-07-21 drh: sqlite3PrintExprList(p->pOrderBy); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf("\n"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* End of the structure debug printing code dbda8d6ce9 2007-07-21 drh: *****************************************************************************/ dbda8d6ce9 2007-07-21 drh: #endif /* defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of select.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file table.c *******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains the sqlite3_get_table() and sqlite3_free_table() dbda8d6ce9 2007-07-21 drh: ** interface routines. These are just wrappers around the main dbda8d6ce9 2007-07-21 drh: ** interface routine of sqlite3_exec(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** These routines are in a separate files so that they will not be linked dbda8d6ce9 2007-07-21 drh: ** if they are not used. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_GET_TABLE dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This structure is used to pass data from sqlite3_get_table() through dbda8d6ce9 2007-07-21 drh: ** to the callback function is uses to build the result. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct TabResult { dbda8d6ce9 2007-07-21 drh: char **azResult; dbda8d6ce9 2007-07-21 drh: char *zErrMsg; dbda8d6ce9 2007-07-21 drh: int nResult; dbda8d6ce9 2007-07-21 drh: int nAlloc; dbda8d6ce9 2007-07-21 drh: int nRow; dbda8d6ce9 2007-07-21 drh: int nColumn; dbda8d6ce9 2007-07-21 drh: int nData; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: } TabResult; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called once for each row in the result table. Its job dbda8d6ce9 2007-07-21 drh: ** is to fill in the TabResult structure appropriately, allocating new dbda8d6ce9 2007-07-21 drh: ** memory as necessary. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ dbda8d6ce9 2007-07-21 drh: TabResult *p = (TabResult*)pArg; dbda8d6ce9 2007-07-21 drh: int need; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure there is enough space in p->azResult to hold everything dbda8d6ce9 2007-07-21 drh: ** we need to remember from this invocation of the callback. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->nRow==0 && argv!=0 ){ dbda8d6ce9 2007-07-21 drh: need = nCol*2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: need = nCol; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->nData + need >= p->nAlloc ){ dbda8d6ce9 2007-07-21 drh: char **azNew; dbda8d6ce9 2007-07-21 drh: p->nAlloc = p->nAlloc*2 + need + 1; dbda8d6ce9 2007-07-21 drh: azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc ); dbda8d6ce9 2007-07-21 drh: if( azNew==0 ) goto malloc_failed; dbda8d6ce9 2007-07-21 drh: p->azResult = azNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is the first row, then generate an extra row containing dbda8d6ce9 2007-07-21 drh: ** the names of all columns. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( p->nRow==0 ){ dbda8d6ce9 2007-07-21 drh: p->nColumn = nCol; dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( colv[i]==0 ){ dbda8d6ce9 2007-07-21 drh: z = sqlite3_mprintf(""); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: z = sqlite3_mprintf("%s", colv[i]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->azResult[p->nData++] = z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( p->nColumn!=nCol ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&p->zErrMsg, dbda8d6ce9 2007-07-21 drh: "sqlite3_get_table() called with two or more incompatible queries", dbda8d6ce9 2007-07-21 drh: (char*)0); dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Copy over the row data dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( argv!=0 ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( argv[i]==0 ){ dbda8d6ce9 2007-07-21 drh: z = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int n = strlen(argv[i])+1; dbda8d6ce9 2007-07-21 drh: z = sqlite3_malloc( n ); dbda8d6ce9 2007-07-21 drh: if( z==0 ) goto malloc_failed; dbda8d6ce9 2007-07-21 drh: memcpy(z, argv[i], n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->azResult[p->nData++] = z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->nRow++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: malloc_failed: dbda8d6ce9 2007-07-21 drh: p->rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Query the database. But instead of invoking a callback for each row, dbda8d6ce9 2007-07-21 drh: ** malloc() for space to hold the result and return the entire results dbda8d6ce9 2007-07-21 drh: ** at the conclusion of the call. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The result that is written to ***pazResult is held in memory obtained dbda8d6ce9 2007-07-21 drh: ** from malloc(). But the caller cannot free this memory directly. dbda8d6ce9 2007-07-21 drh: ** Instead, the entire table should be passed to sqlite3_free_table() when dbda8d6ce9 2007-07-21 drh: ** the calling procedure is finished using it. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_get_table( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* The database on which the SQL executes */ dbda8d6ce9 2007-07-21 drh: const char *zSql, /* The SQL to be executed */ dbda8d6ce9 2007-07-21 drh: char ***pazResult, /* Write the result table here */ dbda8d6ce9 2007-07-21 drh: int *pnRow, /* Write the number of rows in the result here */ dbda8d6ce9 2007-07-21 drh: int *pnColumn, /* Write the number of columns of result here */ dbda8d6ce9 2007-07-21 drh: char **pzErrMsg /* Write error messages here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: TabResult res; dbda8d6ce9 2007-07-21 drh: if( pazResult==0 ){ return SQLITE_ERROR; } dbda8d6ce9 2007-07-21 drh: *pazResult = 0; dbda8d6ce9 2007-07-21 drh: if( pnColumn ) *pnColumn = 0; dbda8d6ce9 2007-07-21 drh: if( pnRow ) *pnRow = 0; dbda8d6ce9 2007-07-21 drh: res.zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: res.nResult = 0; dbda8d6ce9 2007-07-21 drh: res.nRow = 0; dbda8d6ce9 2007-07-21 drh: res.nColumn = 0; dbda8d6ce9 2007-07-21 drh: res.nData = 1; dbda8d6ce9 2007-07-21 drh: res.nAlloc = 20; dbda8d6ce9 2007-07-21 drh: res.rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: res.azResult = sqlite3_malloc( sizeof(char*)*res.nAlloc ); dbda8d6ce9 2007-07-21 drh: if( res.azResult==0 ) return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: res.azResult[0] = 0; dbda8d6ce9 2007-07-21 drh: rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg); c287665ba8 2007-09-14 drh: #ifndef NDEBUG c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: assert((rc&db->errMask)==rc && (res.rc&db->errMask)==res.rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: #endif dbda8d6ce9 2007-07-21 drh: if( res.azResult ){ dbda8d6ce9 2007-07-21 drh: assert( sizeof(res.azResult[0])>= sizeof(res.nData) ); dbda8d6ce9 2007-07-21 drh: res.azResult[0] = (char*)res.nData; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (rc&0xff)==SQLITE_ABORT ){ dbda8d6ce9 2007-07-21 drh: sqlite3_free_table(&res.azResult[1]); dbda8d6ce9 2007-07-21 drh: if( res.zErrMsg ){ dbda8d6ce9 2007-07-21 drh: if( pzErrMsg ){ dbda8d6ce9 2007-07-21 drh: sqlite3_free(*pzErrMsg); dbda8d6ce9 2007-07-21 drh: *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(res.zErrMsg); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: db->errCode = res.rc; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return res.rc; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(res.zErrMsg); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3_free_table(&res.azResult[1]); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( res.nAlloc>res.nData ){ dbda8d6ce9 2007-07-21 drh: char **azNew; dbda8d6ce9 2007-07-21 drh: azNew = sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) ); dbda8d6ce9 2007-07-21 drh: if( azNew==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_free_table(&res.azResult[1]); dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: res.nAlloc = res.nData+1; dbda8d6ce9 2007-07-21 drh: res.azResult = azNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pazResult = &res.azResult[1]; dbda8d6ce9 2007-07-21 drh: if( pnColumn ) *pnColumn = res.nColumn; dbda8d6ce9 2007-07-21 drh: if( pnRow ) *pnRow = res.nRow; c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine frees the space the sqlite3_get_table() malloced. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_free_table( dbda8d6ce9 2007-07-21 drh: char **azResult /* Result returned from from sqlite3_get_table() */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( azResult ){ dbda8d6ce9 2007-07-21 drh: int i, n; dbda8d6ce9 2007-07-21 drh: azResult--; dbda8d6ce9 2007-07-21 drh: if( azResult==0 ) return; dbda8d6ce9 2007-07-21 drh: n = (int)azResult[0]; dbda8d6ce9 2007-07-21 drh: for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); } dbda8d6ce9 2007-07-21 drh: sqlite3_free(azResult); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_GET_TABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of table.c ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file trigger.c *****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Delete a linked list of TriggerStep structures. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){ dbda8d6ce9 2007-07-21 drh: while( pTriggerStep ){ dbda8d6ce9 2007-07-21 drh: TriggerStep * pTmp = pTriggerStep; dbda8d6ce9 2007-07-21 drh: pTriggerStep = pTriggerStep->pNext; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( pTmp->target.dyn ) sqlite3_free((char*)pTmp->target.z); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pTmp->pWhere); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pTmp->pExprList); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pTmp->pSelect); dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(pTmp->pIdList); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3_free(pTmp); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is called by the parser when it sees a CREATE TRIGGER statement dbda8d6ce9 2007-07-21 drh: ** up to the point of the BEGIN before the trigger actions. A Trigger dbda8d6ce9 2007-07-21 drh: ** structure is generated based on the information available and stored dbda8d6ce9 2007-07-21 drh: ** in pParse->pNewTrigger. After the trigger actions have been parsed, the dbda8d6ce9 2007-07-21 drh: ** sqlite3FinishTrigger() function is called to complete the trigger dbda8d6ce9 2007-07-21 drh: ** construction process. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3BeginTrigger( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parse context of the CREATE TRIGGER statement */ dbda8d6ce9 2007-07-21 drh: Token *pName1, /* The name of the trigger */ dbda8d6ce9 2007-07-21 drh: Token *pName2, /* The name of the trigger */ dbda8d6ce9 2007-07-21 drh: int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */ dbda8d6ce9 2007-07-21 drh: int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */ dbda8d6ce9 2007-07-21 drh: IdList *pColumns, /* column list if this is an UPDATE OF trigger */ dbda8d6ce9 2007-07-21 drh: SrcList *pTableName,/* The name of the table/view the trigger applies to */ dbda8d6ce9 2007-07-21 drh: Expr *pWhen, /* WHEN clause */ dbda8d6ce9 2007-07-21 drh: int isTemp, /* True if the TEMPORARY keyword is present */ dbda8d6ce9 2007-07-21 drh: int noErr /* Suppress errors if the trigger already exists */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Trigger *pTrigger = 0; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: char *zName = 0; /* Name of the trigger */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int iDb; /* The database to store the trigger in */ dbda8d6ce9 2007-07-21 drh: Token *pName; /* The unqualified db name */ dbda8d6ce9 2007-07-21 drh: DbFixer sFix; dbda8d6ce9 2007-07-21 drh: int iTabDb; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ dbda8d6ce9 2007-07-21 drh: assert( pName2!=0 ); dbda8d6ce9 2007-07-21 drh: if( isTemp ){ dbda8d6ce9 2007-07-21 drh: /* If TEMP was specified, then the trigger name may not be qualified. */ dbda8d6ce9 2007-07-21 drh: if( pName2->n>0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name"); dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iDb = 1; dbda8d6ce9 2007-07-21 drh: pName = pName1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Figure out the db that the the trigger will be created in */ dbda8d6ce9 2007-07-21 drh: iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); dbda8d6ce9 2007-07-21 drh: if( iDb<0 ){ dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the trigger name was unqualified, and the table is a temp table, dbda8d6ce9 2007-07-21 drh: ** then set iDb to 1 to create the trigger in the temporary database. dbda8d6ce9 2007-07-21 drh: ** If sqlite3SrcListLookup() returns 0, indicating the table does not dbda8d6ce9 2007-07-21 drh: ** exist, the error is caught by the block below. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: if( !pTableName || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab = sqlite3SrcListLookup(pParse, pTableName); dbda8d6ce9 2007-07-21 drh: if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ dbda8d6ce9 2007-07-21 drh: iDb = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Ensure the table name matches database name and that the table exists */ c287665ba8 2007-09-14 drh: if( db->mallocFailed ) goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: assert( pTableName->nSrc==1 ); dbda8d6ce9 2007-07-21 drh: if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && dbda8d6ce9 2007-07-21 drh: sqlite3FixSrcList(&sFix, pTableName) ){ dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab = sqlite3SrcListLookup(pParse, pTableName); dbda8d6ce9 2007-07-21 drh: if( !pTab ){ dbda8d6ce9 2007-07-21 drh: /* The table does not exist. */ dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check that the trigger name is not reserved and that no trigger of the dbda8d6ce9 2007-07-21 drh: ** specified name exists */ c287665ba8 2007-09-14 drh: zName = sqlite3NameFromToken(db, pName); dbda8d6ce9 2007-07-21 drh: if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){ dbda8d6ce9 2007-07-21 drh: if( !noErr ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do not create a trigger on a system table */ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); dbda8d6ce9 2007-07-21 drh: pParse->nErr++; dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* INSTEAD of triggers are only for views and views only support INSTEAD dbda8d6ce9 2007-07-21 drh: ** of triggers. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", dbda8d6ce9 2007-07-21 drh: (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" dbda8d6ce9 2007-07-21 drh: " trigger on table: %S", pTableName, 0); dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int code = SQLITE_CREATE_TRIGGER; dbda8d6ce9 2007-07-21 drh: const char *zDb = db->aDb[iTabDb].zName; dbda8d6ce9 2007-07-21 drh: const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb; dbda8d6ce9 2007-07-21 drh: if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){ dbda8d6ce9 2007-07-21 drh: goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* INSTEAD OF triggers can only appear on views and BEFORE triggers dbda8d6ce9 2007-07-21 drh: ** cannot appear on views. So we might as well translate every dbda8d6ce9 2007-07-21 drh: ** INSTEAD OF trigger into a BEFORE trigger. It simplifies code dbda8d6ce9 2007-07-21 drh: ** elsewhere. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if (tr_tm == TK_INSTEAD){ dbda8d6ce9 2007-07-21 drh: tr_tm = TK_BEFORE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Build the Trigger object */ c287665ba8 2007-09-14 drh: pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); dbda8d6ce9 2007-07-21 drh: if( pTrigger==0 ) goto trigger_cleanup; dbda8d6ce9 2007-07-21 drh: pTrigger->name = zName; dbda8d6ce9 2007-07-21 drh: zName = 0; c287665ba8 2007-09-14 drh: pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); dbda8d6ce9 2007-07-21 drh: pTrigger->pSchema = db->aDb[iDb].pSchema; dbda8d6ce9 2007-07-21 drh: pTrigger->pTabSchema = pTab->pSchema; dbda8d6ce9 2007-07-21 drh: pTrigger->op = op; dbda8d6ce9 2007-07-21 drh: pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; c287665ba8 2007-09-14 drh: pTrigger->pWhen = sqlite3ExprDup(db, pWhen); c287665ba8 2007-09-14 drh: pTrigger->pColumns = sqlite3IdListDup(db, pColumns); c287665ba8 2007-09-14 drh: sqlite3TokenCopy(db, &pTrigger->nameToken,pName); dbda8d6ce9 2007-07-21 drh: assert( pParse->pNewTrigger==0 ); dbda8d6ce9 2007-07-21 drh: pParse->pNewTrigger = pTrigger; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: trigger_cleanup: c287665ba8 2007-09-14 drh: sqlite3_free(zName); dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pTableName); dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(pColumns); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pWhen); dbda8d6ce9 2007-07-21 drh: if( !pParse->pNewTrigger ){ dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTrigger(pTrigger); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert( pParse->pNewTrigger==pTrigger ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called after all of the trigger actions have been parsed dbda8d6ce9 2007-07-21 drh: ** in order to complete the process of building the trigger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3FinishTrigger( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parser context */ dbda8d6ce9 2007-07-21 drh: TriggerStep *pStepList, /* The triggered program */ dbda8d6ce9 2007-07-21 drh: Token *pAll /* Token that describes the complete CREATE TRIGGER */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Trigger *pTrig = 0; /* The trigger whose construction is finishing up */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; /* The database */ dbda8d6ce9 2007-07-21 drh: DbFixer sFix; dbda8d6ce9 2007-07-21 drh: int iDb; /* Database containing the trigger */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTrig = pParse->pNewTrigger; dbda8d6ce9 2007-07-21 drh: pParse->pNewTrigger = 0; dbda8d6ce9 2007-07-21 drh: if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup; dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); dbda8d6ce9 2007-07-21 drh: pTrig->step_list = pStepList; dbda8d6ce9 2007-07-21 drh: while( pStepList ){ dbda8d6ce9 2007-07-21 drh: pStepList->pTrig = pTrig; dbda8d6ce9 2007-07-21 drh: pStepList = pStepList->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken) dbda8d6ce9 2007-07-21 drh: && sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){ dbda8d6ce9 2007-07-21 drh: goto triggerfinish_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* if we are not initializing, and this trigger is not on a TEMP table, dbda8d6ce9 2007-07-21 drh: ** build the sqlite_master entry dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: static const VdbeOpList insertTrig[] = { dbda8d6ce9 2007-07-21 drh: { OP_NewRowid, 0, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, "trigger" }, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, 0 }, /* 2: trigger name */ dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, 0 }, /* 3: table name */ dbda8d6ce9 2007-07-21 drh: { OP_Integer, 0, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, "CREATE TRIGGER "}, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, 0 }, /* 6: SQL */ dbda8d6ce9 2007-07-21 drh: { OP_Concat, 0, 0, 0 }, dbda8d6ce9 2007-07-21 drh: { OP_MakeRecord, 5, 0, "aaada" }, dbda8d6ce9 2007-07-21 drh: { OP_Insert, 0, 0, 0 }, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make an entry in the sqlite_master table */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) goto triggerfinish_cleanup; dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3OpenMasterTable(pParse, iDb); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, addr+6, (char*)pAll->z, pAll->n); dbda8d6ce9 2007-07-21 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, 0, 0); c287665ba8 2007-09-14 drh: sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, sqlite3MPrintf( c287665ba8 2007-09-14 drh: db, "type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC c287665ba8 2007-09-14 drh: ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( db->init.busy ){ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: Trigger *pDel; dbda8d6ce9 2007-07-21 drh: pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, dbda8d6ce9 2007-07-21 drh: pTrig->name, strlen(pTrig->name), pTrig); dbda8d6ce9 2007-07-21 drh: if( pDel ){ c287665ba8 2007-09-14 drh: assert( pDel==pTrig ); c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: goto triggerfinish_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: n = strlen(pTrig->table) + 1; dbda8d6ce9 2007-07-21 drh: pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n); dbda8d6ce9 2007-07-21 drh: assert( pTab!=0 ); dbda8d6ce9 2007-07-21 drh: pTrig->pNext = pTab->pTrigger; dbda8d6ce9 2007-07-21 drh: pTab->pTrigger = pTrig; dbda8d6ce9 2007-07-21 drh: pTrig = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: triggerfinish_cleanup: dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTrigger(pTrig); dbda8d6ce9 2007-07-21 drh: assert( !pParse->pNewTrigger ); dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTriggerStep(pStepList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Make a copy of all components of the given trigger step. This has dbda8d6ce9 2007-07-21 drh: ** the effect of copying all Expr.token.z values into memory obtained c287665ba8 2007-09-14 drh: ** from sqlite3_malloc(). As initially created, the Expr.token.z values dbda8d6ce9 2007-07-21 drh: ** all point to the input string that was fed to the parser. But that dbda8d6ce9 2007-07-21 drh: ** string is ephemeral - it will go away as soon as the sqlite3_exec() dbda8d6ce9 2007-07-21 drh: ** call that started the parser exits. This routine makes a persistent dbda8d6ce9 2007-07-21 drh: ** copy of all the Expr.token.z strings so that the TriggerStep structure dbda8d6ce9 2007-07-21 drh: ** will be valid even after the sqlite3_exec() call returns. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){ dbda8d6ce9 2007-07-21 drh: if( p->target.z ){ c287665ba8 2007-09-14 drh: p->target.z = (u8*)sqlite3DbStrNDup(db, (char*)p->target.z, p->target.n); dbda8d6ce9 2007-07-21 drh: p->target.dyn = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pSelect ){ c287665ba8 2007-09-14 drh: Select *pNew = sqlite3SelectDup(db, p->pSelect); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(p->pSelect); dbda8d6ce9 2007-07-21 drh: p->pSelect = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pWhere ){ c287665ba8 2007-09-14 drh: Expr *pNew = sqlite3ExprDup(db, p->pWhere); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p->pWhere); dbda8d6ce9 2007-07-21 drh: p->pWhere = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pExprList ){ c287665ba8 2007-09-14 drh: ExprList *pNew = sqlite3ExprListDup(db, p->pExprList); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(p->pExprList); dbda8d6ce9 2007-07-21 drh: p->pExprList = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->pIdList ){ c287665ba8 2007-09-14 drh: IdList *pNew = sqlite3IdListDup(db, p->pIdList); dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(p->pIdList); dbda8d6ce9 2007-07-21 drh: p->pIdList = pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Turn a SELECT statement (that the pSelect parameter points to) into dbda8d6ce9 2007-07-21 drh: ** a trigger step. Return a pointer to a TriggerStep structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The parser calls this routine when it finds a SELECT statement in dbda8d6ce9 2007-07-21 drh: ** body of a TRIGGER. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){ c287665ba8 2007-09-14 drh: TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); dbda8d6ce9 2007-07-21 drh: if( pTriggerStep==0 ) { dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSelect); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTriggerStep->op = TK_SELECT; dbda8d6ce9 2007-07-21 drh: pTriggerStep->pSelect = pSelect; dbda8d6ce9 2007-07-21 drh: pTriggerStep->orconf = OE_Default; c287665ba8 2007-09-14 drh: sqlitePersistTriggerStep(db, pTriggerStep); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return pTriggerStep; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Build a trigger step out of an INSERT statement. Return a pointer dbda8d6ce9 2007-07-21 drh: ** to the new trigger step. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The parser calls this routine when it sees an INSERT inside the dbda8d6ce9 2007-07-21 drh: ** body of a trigger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( c287665ba8 2007-09-14 drh: sqlite3 *db, /* The database connection */ dbda8d6ce9 2007-07-21 drh: Token *pTableName, /* Name of the table into which we insert */ dbda8d6ce9 2007-07-21 drh: IdList *pColumn, /* List of columns in pTableName to insert into */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ dbda8d6ce9 2007-07-21 drh: Select *pSelect, /* A SELECT statement that supplies values */ dbda8d6ce9 2007-07-21 drh: int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: TriggerStep *pTriggerStep; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert(pEList == 0 || pSelect == 0); c287665ba8 2007-09-14 drh: assert(pEList != 0 || pSelect != 0 || db->mallocFailed); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); dbda8d6ce9 2007-07-21 drh: if( pTriggerStep ){ dbda8d6ce9 2007-07-21 drh: pTriggerStep->op = TK_INSERT; dbda8d6ce9 2007-07-21 drh: pTriggerStep->pSelect = pSelect; dbda8d6ce9 2007-07-21 drh: pTriggerStep->target = *pTableName; dbda8d6ce9 2007-07-21 drh: pTriggerStep->pIdList = pColumn; dbda8d6ce9 2007-07-21 drh: pTriggerStep->pExprList = pEList; dbda8d6ce9 2007-07-21 drh: pTriggerStep->orconf = orconf; c287665ba8 2007-09-14 drh: sqlitePersistTriggerStep(db, pTriggerStep); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(pColumn); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pEList); c287665ba8 2007-09-14 drh: sqlite3SelectDelete(pSelect); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return pTriggerStep; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Construct a trigger step that implements an UPDATE statement and return dbda8d6ce9 2007-07-21 drh: ** a pointer to that trigger step. The parser calls this routine when it dbda8d6ce9 2007-07-21 drh: ** sees an UPDATE statement inside the body of a CREATE TRIGGER. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( c287665ba8 2007-09-14 drh: sqlite3 *db, /* The database connection */ dbda8d6ce9 2007-07-21 drh: Token *pTableName, /* Name of the table to be updated */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList, /* The SET clause: list of column and new values */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere, /* The WHERE clause */ dbda8d6ce9 2007-07-21 drh: int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); dbda8d6ce9 2007-07-21 drh: if( pTriggerStep==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pEList); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pWhere); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTriggerStep->op = TK_UPDATE; dbda8d6ce9 2007-07-21 drh: pTriggerStep->target = *pTableName; dbda8d6ce9 2007-07-21 drh: pTriggerStep->pExprList = pEList; dbda8d6ce9 2007-07-21 drh: pTriggerStep->pWhere = pWhere; dbda8d6ce9 2007-07-21 drh: pTriggerStep->orconf = orconf; c287665ba8 2007-09-14 drh: sqlitePersistTriggerStep(db, pTriggerStep); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return pTriggerStep; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Construct a trigger step that implements a DELETE statement and return dbda8d6ce9 2007-07-21 drh: ** a pointer to that trigger step. The parser calls this routine when it dbda8d6ce9 2007-07-21 drh: ** sees a DELETE statement inside the body of a CREATE TRIGGER. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Database connection */ c287665ba8 2007-09-14 drh: Token *pTableName, /* The table from which rows are deleted */ c287665ba8 2007-09-14 drh: Expr *pWhere /* The WHERE clause */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); dbda8d6ce9 2007-07-21 drh: if( pTriggerStep==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pWhere); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTriggerStep->op = TK_DELETE; dbda8d6ce9 2007-07-21 drh: pTriggerStep->target = *pTableName; dbda8d6ce9 2007-07-21 drh: pTriggerStep->pWhere = pWhere; dbda8d6ce9 2007-07-21 drh: pTriggerStep->orconf = OE_Default; c287665ba8 2007-09-14 drh: sqlitePersistTriggerStep(db, pTriggerStep); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return pTriggerStep; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Recursively delete a Trigger structure dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DeleteTrigger(Trigger *pTrigger){ dbda8d6ce9 2007-07-21 drh: if( pTrigger==0 ) return; dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTriggerStep(pTrigger->step_list); c287665ba8 2007-09-14 drh: sqlite3_free(pTrigger->name); c287665ba8 2007-09-14 drh: sqlite3_free(pTrigger->table); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pTrigger->pWhen); dbda8d6ce9 2007-07-21 drh: sqlite3IdListDelete(pTrigger->pColumns); c287665ba8 2007-09-14 drh: if( pTrigger->nameToken.dyn ) sqlite3_free((char*)pTrigger->nameToken.z); c287665ba8 2007-09-14 drh: sqlite3_free(pTrigger); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is called to drop a trigger from the database schema. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This may be called directly from the parser and therefore identifies dbda8d6ce9 2007-07-21 drh: ** the trigger by name. The sqlite3DropTriggerPtr() routine does the dbda8d6ce9 2007-07-21 drh: ** same job as this routine except it takes a pointer to the trigger dbda8d6ce9 2007-07-21 drh: ** instead of the trigger name. dbda8d6ce9 2007-07-21 drh: **/ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){ dbda8d6ce9 2007-07-21 drh: Trigger *pTrigger = 0; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: const char *zDb; dbda8d6ce9 2007-07-21 drh: const char *zName; dbda8d6ce9 2007-07-21 drh: int nName; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( db->mallocFailed ) goto drop_trigger_cleanup; dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ dbda8d6ce9 2007-07-21 drh: goto drop_trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pName->nSrc==1 ); dbda8d6ce9 2007-07-21 drh: zDb = pName->a[0].zDatabase; dbda8d6ce9 2007-07-21 drh: zName = pName->a[0].zName; dbda8d6ce9 2007-07-21 drh: nName = strlen(zName); dbda8d6ce9 2007-07-21 drh: for(i=OMIT_TEMPDB; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ dbda8d6ce9 2007-07-21 drh: if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; dbda8d6ce9 2007-07-21 drh: pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName); dbda8d6ce9 2007-07-21 drh: if( pTrigger ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pTrigger ){ dbda8d6ce9 2007-07-21 drh: if( !noErr ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: goto drop_trigger_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3DropTriggerPtr(pParse, pTrigger); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: drop_trigger_cleanup: dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a pointer to the Table structure for the table that a trigger dbda8d6ce9 2007-07-21 drh: ** is set on. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static Table *tableOfTrigger(Trigger *pTrigger){ dbda8d6ce9 2007-07-21 drh: int n = strlen(pTrigger->table) + 1; dbda8d6ce9 2007-07-21 drh: return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Drop a trigger given a pointer to that trigger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ dbda8d6ce9 2007-07-21 drh: Table *pTable; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 && iDb<db->nDb ); dbda8d6ce9 2007-07-21 drh: pTable = tableOfTrigger(pTrigger); dbda8d6ce9 2007-07-21 drh: assert( pTable ); dbda8d6ce9 2007-07-21 drh: assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int code = SQLITE_DROP_TRIGGER; dbda8d6ce9 2007-07-21 drh: const char *zDb = db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: const char *zTab = SCHEMA_TABLE(iDb); dbda8d6ce9 2007-07-21 drh: if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; dbda8d6ce9 2007-07-21 drh: if( sqlite3AuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) || dbda8d6ce9 2007-07-21 drh: sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code to destroy the database record of the trigger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pTable!=0 ); dbda8d6ce9 2007-07-21 drh: if( (v = sqlite3GetVdbe(pParse))!=0 ){ dbda8d6ce9 2007-07-21 drh: int base; dbda8d6ce9 2007-07-21 drh: static const VdbeOpList dropTrigger[] = { dbda8d6ce9 2007-07-21 drh: { OP_Rewind, 0, ADDR(9), 0}, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, 0}, /* 1 */ dbda8d6ce9 2007-07-21 drh: { OP_Column, 0, 1, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Ne, 0, ADDR(8), 0}, dbda8d6ce9 2007-07-21 drh: { OP_String8, 0, 0, "trigger"}, dbda8d6ce9 2007-07-21 drh: { OP_Column, 0, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Ne, 0, ADDR(8), 0}, dbda8d6ce9 2007-07-21 drh: { OP_Delete, 0, 0, 0}, dbda8d6ce9 2007-07-21 drh: { OP_Next, 0, ADDR(1), 0}, /* 8 */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 0, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3OpenMasterTable(pParse, iDb); dbda8d6ce9 2007-07-21 drh: base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Remove a trigger from the hash tables of the sqlite* pointer. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ dbda8d6ce9 2007-07-21 drh: Trigger *pTrigger; dbda8d6ce9 2007-07-21 drh: int nName = strlen(zName); dbda8d6ce9 2007-07-21 drh: pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash), dbda8d6ce9 2007-07-21 drh: zName, nName, 0); dbda8d6ce9 2007-07-21 drh: if( pTrigger ){ dbda8d6ce9 2007-07-21 drh: Table *pTable = tableOfTrigger(pTrigger); dbda8d6ce9 2007-07-21 drh: assert( pTable!=0 ); dbda8d6ce9 2007-07-21 drh: if( pTable->pTrigger == pTrigger ){ dbda8d6ce9 2007-07-21 drh: pTable->pTrigger = pTrigger->pNext; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: Trigger *cc = pTable->pTrigger; dbda8d6ce9 2007-07-21 drh: while( cc ){ dbda8d6ce9 2007-07-21 drh: if( cc->pNext == pTrigger ){ dbda8d6ce9 2007-07-21 drh: cc->pNext = cc->pNext->pNext; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: cc = cc->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert(cc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTrigger(pTrigger); dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_InternChanges; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** pEList is the SET clause of an UPDATE statement. Each entry dbda8d6ce9 2007-07-21 drh: ** in pEList is of the format <id>=<expr>. If any of the entries dbda8d6ce9 2007-07-21 drh: ** in pEList have an <id> which matches an identifier in pIdList, dbda8d6ce9 2007-07-21 drh: ** then return TRUE. If pIdList==NULL, then it is considered a dbda8d6ce9 2007-07-21 drh: ** wildcard that matches anything. Likewise if pEList==NULL then dbda8d6ce9 2007-07-21 drh: ** it matches anything so always return true. Return false only dbda8d6ce9 2007-07-21 drh: ** if there is no match. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){ dbda8d6ce9 2007-07-21 drh: int e; dbda8d6ce9 2007-07-21 drh: if( !pIdList || !pEList ) return 1; dbda8d6ce9 2007-07-21 drh: for(e=0; e<pEList->nExpr; e++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a bit vector to indicate what kind of triggers exist for operation dbda8d6ce9 2007-07-21 drh: ** "op" on table pTab. If pChanges is not NULL then it is a list of columns dbda8d6ce9 2007-07-21 drh: ** that are being updated. Triggers only match if the ON clause of the dbda8d6ce9 2007-07-21 drh: ** trigger definition overlaps the set of columns being updated. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The returned bit vector is some combination of TRIGGER_BEFORE and dbda8d6ce9 2007-07-21 drh: ** TRIGGER_AFTER. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3TriggersExist( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Used to check for recursive triggers */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* The table the contains the triggers */ dbda8d6ce9 2007-07-21 drh: int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ dbda8d6ce9 2007-07-21 drh: ExprList *pChanges /* Columns that change in an UPDATE statement */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Trigger *pTrigger; dbda8d6ce9 2007-07-21 drh: int mask = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTrigger = IsVirtual(pTab) ? 0 : pTab->pTrigger; dbda8d6ce9 2007-07-21 drh: while( pTrigger ){ dbda8d6ce9 2007-07-21 drh: if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){ dbda8d6ce9 2007-07-21 drh: mask |= pTrigger->tr_tm; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTrigger = pTrigger->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return mask; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert the pStep->target token into a SrcList and return a pointer dbda8d6ce9 2007-07-21 drh: ** to that SrcList. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine adds a specific database name, if needed, to the target when dbda8d6ce9 2007-07-21 drh: ** forming the SrcList. This prevents a trigger in one database from dbda8d6ce9 2007-07-21 drh: ** referring to a target in another database. An exception is when the dbda8d6ce9 2007-07-21 drh: ** trigger is in TEMP in which case it can refer to any other database it dbda8d6ce9 2007-07-21 drh: ** wants. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static SrcList *targetSrcList( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: TriggerStep *pStep /* The trigger containing the target token */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Token sDb; /* Dummy database name token */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Index of the database to use */ dbda8d6ce9 2007-07-21 drh: SrcList *pSrc; /* SrcList to be returned */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema); dbda8d6ce9 2007-07-21 drh: if( iDb==0 || iDb>=2 ){ dbda8d6ce9 2007-07-21 drh: assert( iDb<pParse->db->nDb ); dbda8d6ce9 2007-07-21 drh: sDb.z = (u8*)pParse->db->aDb[iDb].zName; dbda8d6ce9 2007-07-21 drh: sDb.n = strlen((char*)sDb.z); c287665ba8 2007-09-14 drh: pSrc = sqlite3SrcListAppend(pParse->db, 0, &sDb, &pStep->target); dbda8d6ce9 2007-07-21 drh: } else { c287665ba8 2007-09-14 drh: pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pSrc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate VDBE code for zero or more statements inside the body of a dbda8d6ce9 2007-07-21 drh: ** trigger. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int codeTriggerProgram( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: TriggerStep *pStepList, /* List of statements inside the trigger body */ dbda8d6ce9 2007-07-21 drh: int orconfin /* Conflict algorithm. (OE_Abort, etc) */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: TriggerStep * pTriggerStep = pStepList; dbda8d6ce9 2007-07-21 drh: int orconf; dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pTriggerStep!=0 ); dbda8d6ce9 2007-07-21 drh: assert( v!=0 ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name)); dbda8d6ce9 2007-07-21 drh: while( pTriggerStep ){ dbda8d6ce9 2007-07-21 drh: orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; dbda8d6ce9 2007-07-21 drh: pParse->trigStack->orconf = orconf; dbda8d6ce9 2007-07-21 drh: switch( pTriggerStep->op ){ dbda8d6ce9 2007-07-21 drh: case TK_SELECT: { c287665ba8 2007-09-14 drh: Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect); dbda8d6ce9 2007-07-21 drh: if( ss ){ dbda8d6ce9 2007-07-21 drh: sqlite3SelectResolve(pParse, ss, 0); dbda8d6ce9 2007-07-21 drh: sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(ss); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_UPDATE: { dbda8d6ce9 2007-07-21 drh: SrcList *pSrc; dbda8d6ce9 2007-07-21 drh: pSrc = targetSrcList(pParse, pTriggerStep); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3Update(pParse, pSrc, c287665ba8 2007-09-14 drh: sqlite3ExprListDup(db, pTriggerStep->pExprList), c287665ba8 2007-09-14 drh: sqlite3ExprDup(db, pTriggerStep->pWhere), orconf); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_INSERT: { dbda8d6ce9 2007-07-21 drh: SrcList *pSrc; dbda8d6ce9 2007-07-21 drh: pSrc = targetSrcList(pParse, pTriggerStep); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3Insert(pParse, pSrc, c287665ba8 2007-09-14 drh: sqlite3ExprListDup(db, pTriggerStep->pExprList), c287665ba8 2007-09-14 drh: sqlite3SelectDup(db, pTriggerStep->pSelect), c287665ba8 2007-09-14 drh: sqlite3IdListDup(db, pTriggerStep->pIdList), orconf); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_DELETE: { dbda8d6ce9 2007-07-21 drh: SrcList *pSrc; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0); dbda8d6ce9 2007-07-21 drh: pSrc = targetSrcList(pParse, pTriggerStep); c287665ba8 2007-09-14 drh: sqlite3DeleteFrom(pParse, pSrc, c287665ba8 2007-09-14 drh: sqlite3ExprDup(db, pTriggerStep->pWhere)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: dbda8d6ce9 2007-07-21 drh: assert(0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTriggerStep = pTriggerStep->pNext; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# end trigger %s", pStepList->pTrig->name)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is called to code FOR EACH ROW triggers. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When the code that this function generates is executed, the following dbda8d6ce9 2007-07-21 drh: ** must be true: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1. No cursors may be open in the main database. (But newIdx and oldIdx dbda8d6ce9 2007-07-21 drh: ** can be indices of cursors in temporary tables. See below.) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then dbda8d6ce9 2007-07-21 drh: ** a temporary vdbe cursor (index newIdx) must be open and pointing at dbda8d6ce9 2007-07-21 drh: ** a row containing values to be substituted for new.* expressions in the dbda8d6ce9 2007-07-21 drh: ** trigger program(s). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then dbda8d6ce9 2007-07-21 drh: ** a temporary vdbe cursor (index oldIdx) must be open and pointing at dbda8d6ce9 2007-07-21 drh: ** a row containing values to be substituted for old.* expressions in the dbda8d6ce9 2007-07-21 drh: ** trigger program(s). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3CodeRowTrigger( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parse context */ dbda8d6ce9 2007-07-21 drh: int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ dbda8d6ce9 2007-07-21 drh: ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ dbda8d6ce9 2007-07-21 drh: int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* The table to code triggers from */ dbda8d6ce9 2007-07-21 drh: int newIdx, /* The indice of the "new" row to access */ dbda8d6ce9 2007-07-21 drh: int oldIdx, /* The indice of the "old" row to access */ dbda8d6ce9 2007-07-21 drh: int orconf, /* ON CONFLICT policy */ dbda8d6ce9 2007-07-21 drh: int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Trigger *p; dbda8d6ce9 2007-07-21 drh: TriggerStack trigStackEntry; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); dbda8d6ce9 2007-07-21 drh: assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert(newIdx != -1 || oldIdx != -1); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(p=pTab->pTrigger; p; p=p->pNext){ dbda8d6ce9 2007-07-21 drh: int fire_this = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Determine whether we should code this trigger */ dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: p->op==op && dbda8d6ce9 2007-07-21 drh: p->tr_tm==tr_tm && dbda8d6ce9 2007-07-21 drh: (p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) && dbda8d6ce9 2007-07-21 drh: (op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges)) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: TriggerStack *pS; /* Pointer to trigger-stack entry */ dbda8d6ce9 2007-07-21 drh: for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext){} dbda8d6ce9 2007-07-21 drh: if( !pS ){ dbda8d6ce9 2007-07-21 drh: fire_this = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #if 0 /* Give no warning for recursive triggers. Just do not do them */ dbda8d6ce9 2007-07-21 drh: else{ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "recursive triggers not supported (%s)", dbda8d6ce9 2007-07-21 drh: p->name); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( fire_this ){ dbda8d6ce9 2007-07-21 drh: int endTrigger; dbda8d6ce9 2007-07-21 drh: Expr * whenExpr; dbda8d6ce9 2007-07-21 drh: AuthContext sContext; dbda8d6ce9 2007-07-21 drh: NameContext sNC; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memset(&sNC, 0, sizeof(sNC)); dbda8d6ce9 2007-07-21 drh: sNC.pParse = pParse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Push an entry on to the trigger stack */ dbda8d6ce9 2007-07-21 drh: trigStackEntry.pTrigger = p; dbda8d6ce9 2007-07-21 drh: trigStackEntry.newIdx = newIdx; dbda8d6ce9 2007-07-21 drh: trigStackEntry.oldIdx = oldIdx; dbda8d6ce9 2007-07-21 drh: trigStackEntry.pTab = pTab; dbda8d6ce9 2007-07-21 drh: trigStackEntry.pNext = pParse->trigStack; dbda8d6ce9 2007-07-21 drh: trigStackEntry.ignoreJump = ignoreJump; dbda8d6ce9 2007-07-21 drh: pParse->trigStack = &trigStackEntry; dbda8d6ce9 2007-07-21 drh: sqlite3AuthContextPush(pParse, &sContext, p->name); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* code the WHEN clause */ dbda8d6ce9 2007-07-21 drh: endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe); c287665ba8 2007-09-14 drh: whenExpr = sqlite3ExprDup(pParse->db, p->pWhen); dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, whenExpr) ){ dbda8d6ce9 2007-07-21 drh: pParse->trigStack = trigStackEntry.pNext; dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(whenExpr); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(whenExpr); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: codeTriggerProgram(pParse, p->step_list, orconf); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Pop the entry off the trigger stack */ dbda8d6ce9 2007-07-21 drh: pParse->trigStack = trigStackEntry.pNext; dbda8d6ce9 2007-07-21 drh: sqlite3AuthContextPop(&sContext); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !defined(SQLITE_OMIT_TRIGGER) */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of trigger.c *********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file update.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains C code routines that are called by the parser dbda8d6ce9 2007-07-21 drh: ** to handle UPDATE statements. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: update.c,v 1.140 2007/08/16 10:09:03 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Forward declaration */ dbda8d6ce9 2007-07-21 drh: static void updateVirtualTable( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: SrcList *pSrc, /* The virtual table to be modified */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* The virtual table */ dbda8d6ce9 2007-07-21 drh: ExprList *pChanges, /* The columns to change in the UPDATE statement */ dbda8d6ce9 2007-07-21 drh: Expr *pRowidExpr, /* Expression used to recompute the rowid */ dbda8d6ce9 2007-07-21 drh: int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere /* WHERE clause of the UPDATE statement */ dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The most recently coded instruction was an OP_Column to retrieve the dbda8d6ce9 2007-07-21 drh: ** i-th column of table pTab. This routine sets the P3 parameter of the dbda8d6ce9 2007-07-21 drh: ** OP_Column to the default value, if any. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The default value of a column is specified by a DEFAULT clause in the dbda8d6ce9 2007-07-21 drh: ** column definition. This was either supplied by the user when the table dbda8d6ce9 2007-07-21 drh: ** was created, or added later to the table definition by an ALTER TABLE dbda8d6ce9 2007-07-21 drh: ** command. If the latter, then the row-records in the table btree on disk dbda8d6ce9 2007-07-21 drh: ** may not contain a value for the column and the default value, taken dbda8d6ce9 2007-07-21 drh: ** from the P3 parameter of the OP_Column instruction, is returned instead. dbda8d6ce9 2007-07-21 drh: ** If the former, then all row-records are guaranteed to include a value dbda8d6ce9 2007-07-21 drh: ** for the column and the P3 value is not required. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Column definitions created by an ALTER TABLE command may only have dbda8d6ce9 2007-07-21 drh: ** literal default values specified: a number, null or a string. (If a more dbda8d6ce9 2007-07-21 drh: ** complicated default expression value was provided, it is evaluated dbda8d6ce9 2007-07-21 drh: ** when the ALTER TABLE is executed and one of the literal values written dbda8d6ce9 2007-07-21 drh: ** into the sqlite_master table.) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Therefore, the P3 parameter is only required if the default value for dbda8d6ce9 2007-07-21 drh: ** the column is a literal number, string or null. The sqlite3ValueFromExpr() dbda8d6ce9 2007-07-21 drh: ** function is capable of transforming these types of expressions into dbda8d6ce9 2007-07-21 drh: ** sqlite3_value objects. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){ dbda8d6ce9 2007-07-21 drh: if( pTab && !pTab->pSelect ){ dbda8d6ce9 2007-07-21 drh: sqlite3_value *pValue; dbda8d6ce9 2007-07-21 drh: u8 enc = ENC(sqlite3VdbeDb(v)); dbda8d6ce9 2007-07-21 drh: Column *pCol = &pTab->aCol[i]; dbda8d6ce9 2007-07-21 drh: assert( i<pTab->nCol ); c287665ba8 2007-09-14 drh: sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, pCol->affinity, &pValue); dbda8d6ce9 2007-07-21 drh: if( pValue ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# %s.%s", pTab->zName, pCol->zName)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Process an UPDATE statement. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; dbda8d6ce9 2007-07-21 drh: ** \_______/ \________/ \______/ \________________/ dbda8d6ce9 2007-07-21 drh: * onError pTabList pChanges pWhere dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Update( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList, /* The table in which we should change things */ dbda8d6ce9 2007-07-21 drh: ExprList *pChanges, /* Things to be changed */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere, /* The WHERE clause. May be null */ dbda8d6ce9 2007-07-21 drh: int onError /* How to handle constraint errors */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i, j; /* Loop counters */ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* The table to be updated */ dbda8d6ce9 2007-07-21 drh: int addr = 0; /* VDBE instruction address of the start of the loop */ dbda8d6ce9 2007-07-21 drh: WhereInfo *pWInfo; /* Information about the WHERE clause */ dbda8d6ce9 2007-07-21 drh: Vdbe *v; /* The virtual database engine */ dbda8d6ce9 2007-07-21 drh: Index *pIdx; /* For looping over indices */ dbda8d6ce9 2007-07-21 drh: int nIdx; /* Number of indices that need updating */ dbda8d6ce9 2007-07-21 drh: int nIdxTotal; /* Total number of indices */ dbda8d6ce9 2007-07-21 drh: int iCur; /* VDBE Cursor number of pTab */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; /* The database structure */ dbda8d6ce9 2007-07-21 drh: Index **apIdx = 0; /* An array of indices that need updating too */ dbda8d6ce9 2007-07-21 drh: char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */ dbda8d6ce9 2007-07-21 drh: int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the dbda8d6ce9 2007-07-21 drh: ** an expression for the i-th column of the table. dbda8d6ce9 2007-07-21 drh: ** aXRef[i]==-1 if the i-th column is not changed. */ dbda8d6ce9 2007-07-21 drh: int chngRowid; /* True if the record number is being changed */ dbda8d6ce9 2007-07-21 drh: Expr *pRowidExpr = 0; /* Expression defining the new record number */ dbda8d6ce9 2007-07-21 drh: int openAll = 0; /* True if all indices need to be opened */ dbda8d6ce9 2007-07-21 drh: AuthContext sContext; /* The authorization context */ dbda8d6ce9 2007-07-21 drh: NameContext sNC; /* The name-context to resolve expressions in */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Database containing the table being updated */ dbda8d6ce9 2007-07-21 drh: int memCnt = 0; /* Memory cell used for counting rows changed */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: int isView; /* Trying to update a view */ dbda8d6ce9 2007-07-21 drh: int triggers_exist = 0; /* True if any row triggers exist */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int newIdx = -1; /* index of trigger "new" temp table */ dbda8d6ce9 2007-07-21 drh: int oldIdx = -1; /* index of trigger "old" temp table */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sContext.pParse = 0; c287665ba8 2007-09-14 drh: db = pParse->db; c287665ba8 2007-09-14 drh: if( pParse->nErr || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pTabList->nSrc==1 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Locate the table which we want to update. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTab = sqlite3SrcListLookup(pParse, pTabList); dbda8d6ce9 2007-07-21 drh: if( pTab==0 ) goto update_cleanup; dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out if we have any triggers and if the table being dbda8d6ce9 2007-07-21 drh: ** updated is a view dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRIGGER dbda8d6ce9 2007-07-21 drh: triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges); dbda8d6ce9 2007-07-21 drh: isView = pTab->pSelect!=0; dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define triggers_exist 0 dbda8d6ce9 2007-07-21 drh: # define isView 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_OMIT_VIEW dbda8d6ce9 2007-07-21 drh: # undef isView dbda8d6ce9 2007-07-21 drh: # define isView 0 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){ dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3ViewGetColumnNames(pParse, pTab) ){ dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol ); dbda8d6ce9 2007-07-21 drh: if( aXRef==0 ) goto update_cleanup; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++) aXRef[i] = -1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there are FOR EACH ROW triggers, allocate cursors for the dbda8d6ce9 2007-07-21 drh: ** special OLD and NEW tables dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: newIdx = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: oldIdx = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate a cursors for the main database table and for all indices. dbda8d6ce9 2007-07-21 drh: ** The index cursors might not be used, but if they are used they dbda8d6ce9 2007-07-21 drh: ** need to occur right after the database cursor. So go ahead and dbda8d6ce9 2007-07-21 drh: ** allocate enough space, just in case. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTabList->a[0].iCursor = iCur = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: pParse->nTab++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the name-context */ dbda8d6ce9 2007-07-21 drh: memset(&sNC, 0, sizeof(sNC)); dbda8d6ce9 2007-07-21 drh: sNC.pParse = pParse; dbda8d6ce9 2007-07-21 drh: sNC.pSrcList = pTabList; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Resolve the column names in all the expressions of the dbda8d6ce9 2007-07-21 drh: ** of the UPDATE statement. Also find the column index dbda8d6ce9 2007-07-21 drh: ** for each column to be updated in the pChanges array. For each dbda8d6ce9 2007-07-21 drh: ** column to be updated, make sure we have authorization to change dbda8d6ce9 2007-07-21 drh: ** that column. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: chngRowid = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pChanges->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, pChanges->a[i].pExpr) ){ dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(j=0; j<pTab->nCol; j++){ dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ dbda8d6ce9 2007-07-21 drh: if( j==pTab->iPKey ){ dbda8d6ce9 2007-07-21 drh: chngRowid = 1; dbda8d6ce9 2007-07-21 drh: pRowidExpr = pChanges->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: aXRef[j] = i; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( j>=pTab->nCol ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3IsRowid(pChanges->a[i].zName) ){ dbda8d6ce9 2007-07-21 drh: chngRowid = 1; dbda8d6ce9 2007-07-21 drh: pRowidExpr = pChanges->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, dbda8d6ce9 2007-07-21 drh: pTab->aCol[j].zName, db->aDb[iDb].zName); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_DENY ){ dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: }else if( rc==SQLITE_IGNORE ){ dbda8d6ce9 2007-07-21 drh: aXRef[j] = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate memory for the array apIdx[] and fill it with pointers to every dbda8d6ce9 2007-07-21 drh: ** index that needs to be updated. Indices only need updating if their dbda8d6ce9 2007-07-21 drh: ** key includes one of the columns named in pChanges or if the record dbda8d6ce9 2007-07-21 drh: ** number of the original table entry is changing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){ dbda8d6ce9 2007-07-21 drh: if( chngRowid ){ dbda8d6ce9 2007-07-21 drh: i = 0; dbda8d6ce9 2007-07-21 drh: }else { dbda8d6ce9 2007-07-21 drh: for(i=0; i<pIdx->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: if( aXRef[pIdx->aiColumn[i]]>=0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<pIdx->nColumn ) nIdx++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nIdxTotal>0 ){ c287665ba8 2007-09-14 drh: apIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx + nIdxTotal ); dbda8d6ce9 2007-07-21 drh: if( apIdx==0 ) goto update_cleanup; dbda8d6ce9 2007-07-21 drh: aIdxUsed = (char*)&apIdx[nIdx]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ dbda8d6ce9 2007-07-21 drh: if( chngRowid ){ dbda8d6ce9 2007-07-21 drh: i = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pIdx->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: if( aXRef[pIdx->aiColumn[i]]>=0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<pIdx->nColumn ){ dbda8d6ce9 2007-07-21 drh: apIdx[nIdx++] = pIdx; dbda8d6ce9 2007-07-21 drh: aIdxUsed[j] = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: aIdxUsed[j] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin generating code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v==0 ) goto update_cleanup; dbda8d6ce9 2007-07-21 drh: if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); dbda8d6ce9 2007-07-21 drh: sqlite3BeginWriteOperation(pParse, 1, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Virtual tables must be handled separately */ dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, dbda8d6ce9 2007-07-21 drh: pWhere); dbda8d6ce9 2007-07-21 drh: pWhere = 0; dbda8d6ce9 2007-07-21 drh: pTabList = 0; dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Resolve the column names in all the expressions in the dbda8d6ce9 2007-07-21 drh: ** WHERE clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3ExprResolveNames(&sNC, pWhere) ){ dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Start the view context dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3AuthContextPush(pParse, &sContext, pTab->zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we are trying to update a view, realize that view into dbda8d6ce9 2007-07-21 drh: ** a ephemeral table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( isView ){ dbda8d6ce9 2007-07-21 drh: Select *pView; c287665ba8 2007-09-14 drh: pView = sqlite3SelectDup(db, pTab->pSelect); dbda8d6ce9 2007-07-21 drh: sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pView); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin the database scan dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); dbda8d6ce9 2007-07-21 drh: if( pWInfo==0 ) goto update_cleanup; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Remember the rowid of every item to be updated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* End the database scan loop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3WhereEnd(pWInfo); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the count of updated rows dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows && !pParse->trigStack ){ dbda8d6ce9 2007-07-21 drh: memCnt = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: /* Create pseudo-tables for NEW and OLD dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The top of the update loop for when there are triggers. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: /* Open a cursor and make it point to the record that is dbda8d6ce9 2007-07-21 drh: ** being updated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate the OLD table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate the NEW table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( chngRowid ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeAndCache(pParse, pRowidExpr); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( i==pTab->iPKey ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: j = aXRef[i]; dbda8d6ce9 2007-07-21 drh: if( j<0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iCur, i); dbda8d6ce9 2007-07-21 drh: sqlite3ColumnDefault(v, pTab, i); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3TableAffinityStr(v, pTab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pParse->nErr ) goto update_cleanup; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0); dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Fire the BEFORE and INSTEAD OF triggers dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, dbda8d6ce9 2007-07-21 drh: newIdx, oldIdx, onError, addr) ){ dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !isView && !IsVirtual(pTab) ){ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Open every index that needs updating. Note that if any dbda8d6ce9 2007-07-21 drh: ** index could potentially invoke a REPLACE conflict resolution dbda8d6ce9 2007-07-21 drh: ** action, then we need to open all indices because we might need dbda8d6ce9 2007-07-21 drh: ** to be deleting some records. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); dbda8d6ce9 2007-07-21 drh: if( onError==OE_Replace ){ dbda8d6ce9 2007-07-21 drh: openAll = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: openAll = 0; dbda8d6ce9 2007-07-21 drh: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ dbda8d6ce9 2007-07-21 drh: if( pIdx->onError==OE_Replace ){ dbda8d6ce9 2007-07-21 drh: openAll = 1; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ dbda8d6ce9 2007-07-21 drh: if( openAll || aIdxUsed[i] ){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, dbda8d6ce9 2007-07-21 drh: (char*)pKey, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: assert( pParse->nTab>iCur+i+1 ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Loop over every record that needs updating. We have to load dbda8d6ce9 2007-07-21 drh: ** the old data for each record to be updated because some columns dbda8d6ce9 2007-07-21 drh: ** might not change and we will need to copy the old value. dbda8d6ce9 2007-07-21 drh: ** Also, the old data is needed to delete the old index entries. dbda8d6ce9 2007-07-21 drh: ** So make the cursor point at the old record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !triggers_exist ){ dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the record number will change, push the record number as it dbda8d6ce9 2007-07-21 drh: ** will be after the update. (The old record number is currently dbda8d6ce9 2007-07-21 drh: ** on top of the stack.) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( chngRowid ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pRowidExpr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Compute new data for this record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( i==pTab->iPKey ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: j = aXRef[i]; dbda8d6ce9 2007-07-21 drh: if( j<0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iCur, i); dbda8d6ce9 2007-07-21 drh: sqlite3ColumnDefault(v, pTab, i); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pChanges->a[j].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Do constraint checks dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, dbda8d6ce9 2007-07-21 drh: onError, addr); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Delete the old indices for the current record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If changing the record number, delete the old record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( chngRowid ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Delete, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create the new index entries and the new record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Increment the row counter dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows && !pParse->trigStack){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there are triggers, close all the cursors after each iteration dbda8d6ce9 2007-07-21 drh: ** through the loop. The fire the after triggers. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( triggers_exist ){ dbda8d6ce9 2007-07-21 drh: if( !isView ){ dbda8d6ce9 2007-07-21 drh: for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ dbda8d6ce9 2007-07-21 drh: if( openAll || aIdxUsed[i] ) dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab, dbda8d6ce9 2007-07-21 drh: newIdx, oldIdx, onError, addr) ){ dbda8d6ce9 2007-07-21 drh: goto update_cleanup; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Repeat the above with the next record to be updated, until dbda8d6ce9 2007-07-21 drh: ** all record selected by the WHERE clause have been updated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, addr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Close all tables if there were no FOR EACH ROW triggers */ dbda8d6ce9 2007-07-21 drh: if( !triggers_exist ){ dbda8d6ce9 2007-07-21 drh: for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ dbda8d6ce9 2007-07-21 drh: if( openAll || aIdxUsed[i] ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, newIdx, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of rows that were changed. If this routine is dbda8d6ce9 2007-07-21 drh: ** generating code because of a call to sqlite3NestedParse(), do not dbda8d6ce9 2007-07-21 drh: ** invoke the callback function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetNumCols(v, 1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: update_cleanup: dbda8d6ce9 2007-07-21 drh: sqlite3AuthContextPop(&sContext); c287665ba8 2007-09-14 drh: sqlite3_free(apIdx); c287665ba8 2007-09-14 drh: sqlite3_free(aXRef); dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pTabList); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pChanges); dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pWhere); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for an UPDATE of a virtual table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The strategy is that we create an ephemerial table that contains dbda8d6ce9 2007-07-21 drh: ** for each row to be changed: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (A) The original rowid of that row. dbda8d6ce9 2007-07-21 drh: ** (B) The revised rowid for the row. (note1) dbda8d6ce9 2007-07-21 drh: ** (C) The content of every column in the row. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then we loop over this ephemeral table and for each row in dbda8d6ce9 2007-07-21 drh: ** the ephermeral table call VUpdate. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When finished, drop the ephemeral table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (note1) Actually, if we know in advance that (A) is always the same dbda8d6ce9 2007-07-21 drh: ** as (B) we only store (A), then duplicate (A) when pulling dbda8d6ce9 2007-07-21 drh: ** it out of the ephemeral table before calling VUpdate. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void updateVirtualTable( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: SrcList *pSrc, /* The virtual table to be modified */ dbda8d6ce9 2007-07-21 drh: Table *pTab, /* The virtual table */ dbda8d6ce9 2007-07-21 drh: ExprList *pChanges, /* The columns to change in the UPDATE statement */ dbda8d6ce9 2007-07-21 drh: Expr *pRowid, /* Expression used to recompute the rowid */ dbda8d6ce9 2007-07-21 drh: int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere /* WHERE clause of the UPDATE statement */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ dbda8d6ce9 2007-07-21 drh: ExprList *pEList = 0; /* The result set of the SELECT statement */ dbda8d6ce9 2007-07-21 drh: Select *pSelect = 0; /* The SELECT statement */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr; /* Temporary expression */ dbda8d6ce9 2007-07-21 drh: int ephemTab; /* Table holding the result of the SELECT */ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: int addr; /* Address of top of loop */ c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; /* Database connection */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Construct the SELECT statement that will find the new values for dbda8d6ce9 2007-07-21 drh: ** all updated rows. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: pEList = sqlite3ExprListAppend(pParse, 0, c287665ba8 2007-09-14 drh: sqlite3CreateIdExpr(pParse, "_rowid_"), 0); dbda8d6ce9 2007-07-21 drh: if( pRowid ){ c287665ba8 2007-09-14 drh: pEList = sqlite3ExprListAppend(pParse, pEList, c287665ba8 2007-09-14 drh: sqlite3ExprDup(db, pRowid), 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pTab->iPKey<0 ); dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: if( aXRef[i]>=0 ){ c287665ba8 2007-09-14 drh: pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr); c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pEList = sqlite3ExprListAppend(pParse, pEList, pExpr, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create the ephemeral table into which the update results will dbda8d6ce9 2007-07-21 drh: ** be stored. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( v ); dbda8d6ce9 2007-07-21 drh: ephemTab = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* fill the ephemeral table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3Select(pParse, pSelect, SRT_Table, ephemTab, 0, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code to scan the ephemeral table and call VDelete and dbda8d6ce9 2007-07-21 drh: ** VInsert dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, ephemTab, 0); dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, ephemTab, 0); dbda8d6ce9 2007-07-21 drh: if( pRowid ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, ephemTab, 1); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTab->nCol; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->pVirtualLock = pTab; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2, dbda8d6ce9 2007-07-21 drh: (const char*)pTab->pVtab, P3_VTAB); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr-1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Cleanup */ dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(pSelect); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of update.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vacuum.c ******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2003 April 6 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code used to implement the VACUUM command. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Most of the code in this file may be omitted by defining the dbda8d6ce9 2007-07-21 drh: ** SQLITE_OMIT_VACUUM macro. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: vacuum.c,v 1.73 2007/08/29 12:31:28 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Execute zSql on database db. Return an error code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int execSql(sqlite3 *db, const char *zSql){ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pStmt; c287665ba8 2007-09-14 drh: if( !zSql ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){ dbda8d6ce9 2007-07-21 drh: return sqlite3_errcode(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( SQLITE_ROW==sqlite3_step(pStmt) ){} dbda8d6ce9 2007-07-21 drh: return sqlite3_finalize(pStmt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Execute zSql on database db. The statement returns exactly dbda8d6ce9 2007-07-21 drh: ** one column. Execute this as SQL on the same database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int execExecSql(sqlite3 *db, const char *zSql){ dbda8d6ce9 2007-07-21 drh: sqlite3_stmt *pStmt; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) return rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while( SQLITE_ROW==sqlite3_step(pStmt) ){ dbda8d6ce9 2007-07-21 drh: rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0)); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3_finalize(pStmt); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return sqlite3_finalize(pStmt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The non-standard VACUUM command is used to clean up the database, dbda8d6ce9 2007-07-21 drh: ** collapse free space, etc. It is modelled after the VACUUM command dbda8d6ce9 2007-07-21 drh: ** in PostgreSQL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In version 1.0.x of SQLite, the VACUUM command would call dbda8d6ce9 2007-07-21 drh: ** gdbm_reorganize() on all the database tables. But beginning dbda8d6ce9 2007-07-21 drh: ** with 2.0.0, SQLite no longer uses GDBM so this command has dbda8d6ce9 2007-07-21 drh: ** become a no-op. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: if( v ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine implements the OP_Vacuum opcode of the VDBE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; /* Return code from service routines */ dbda8d6ce9 2007-07-21 drh: Btree *pMain; /* The database being vacuumed */ dbda8d6ce9 2007-07-21 drh: Btree *pTemp; /* The temporary database we vacuum into */ dbda8d6ce9 2007-07-21 drh: char *zSql = 0; /* SQL statements */ dbda8d6ce9 2007-07-21 drh: int saved_flags; /* Saved value of the db->flags */ dbda8d6ce9 2007-07-21 drh: Db *pDb = 0; /* Database to detach at end of vacuum */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Save the current value of the write-schema flag before setting it. */ dbda8d6ce9 2007-07-21 drh: saved_flags = db->flags; dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !db->autoCommit ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", dbda8d6ce9 2007-07-21 drh: (char*)0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pMain = db->aDb[0].pBt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Attach the temporary database as 'vacuum_db'. The synchronous pragma dbda8d6ce9 2007-07-21 drh: ** can be set to 'off' for this file, as it is not recovered if a crash dbda8d6ce9 2007-07-21 drh: ** occurs anyway. The integrity of the database is maintained by a dbda8d6ce9 2007-07-21 drh: ** (possibly synchronous) transaction opened on the main database before dbda8d6ce9 2007-07-21 drh: ** sqlite3BtreeCopyFile() is called. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An optimisation would be to use a non-journaled pager. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: zSql = "ATTACH '' AS vacuum_db;"; dbda8d6ce9 2007-07-21 drh: rc = execSql(db, zSql); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: pDb = &db->aDb[db->nDb-1]; dbda8d6ce9 2007-07-21 drh: assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 ); dbda8d6ce9 2007-07-21 drh: pTemp = db->aDb[db->nDb-1].pBt; dbda8d6ce9 2007-07-21 drh: sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), dbda8d6ce9 2007-07-21 drh: sqlite3BtreeGetReserve(pMain)); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) ); dbda8d6ce9 2007-07-21 drh: rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF"); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTOVACUUM dbda8d6ce9 2007-07-21 drh: sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain)); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Begin a transaction */ dbda8d6ce9 2007-07-21 drh: rc = execSql(db, "BEGIN EXCLUSIVE;"); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Query the schema of the main database. Create a mirror schema dbda8d6ce9 2007-07-21 drh: ** in the temporary database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = execExecSql(db, dbda8d6ce9 2007-07-21 drh: "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) " dbda8d6ce9 2007-07-21 drh: " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" dbda8d6ce9 2007-07-21 drh: " AND rootpage>0" dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: rc = execExecSql(db, dbda8d6ce9 2007-07-21 drh: "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)" dbda8d6ce9 2007-07-21 drh: " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: rc = execExecSql(db, dbda8d6ce9 2007-07-21 drh: "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) " dbda8d6ce9 2007-07-21 drh: " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Loop through the tables in the main database. For each, do dbda8d6ce9 2007-07-21 drh: ** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy dbda8d6ce9 2007-07-21 drh: ** the contents to the temporary database. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = execExecSql(db, dbda8d6ce9 2007-07-21 drh: "SELECT 'INSERT INTO vacuum_db.' || quote(name) " dbda8d6ce9 2007-07-21 drh: "|| ' SELECT * FROM ' || quote(name) || ';'" dbda8d6ce9 2007-07-21 drh: "FROM sqlite_master " dbda8d6ce9 2007-07-21 drh: "WHERE type = 'table' AND name!='sqlite_sequence' " dbda8d6ce9 2007-07-21 drh: " AND rootpage>0" dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Copy over the sequence table dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = execExecSql(db, dbda8d6ce9 2007-07-21 drh: "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " dbda8d6ce9 2007-07-21 drh: "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' " dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: rc = execExecSql(db, dbda8d6ce9 2007-07-21 drh: "SELECT 'INSERT INTO vacuum_db.' || quote(name) " dbda8d6ce9 2007-07-21 drh: "|| ' SELECT * FROM ' || quote(name) || ';' " dbda8d6ce9 2007-07-21 drh: "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';" dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Copy the triggers, views, and virtual tables from the main database dbda8d6ce9 2007-07-21 drh: ** over to the temporary database. None of these objects has any dbda8d6ce9 2007-07-21 drh: ** associated storage, so all we have to do is copy their entries dbda8d6ce9 2007-07-21 drh: ** from the SQLITE_MASTER table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: rc = execSql(db, dbda8d6ce9 2007-07-21 drh: "INSERT INTO vacuum_db.sqlite_master " dbda8d6ce9 2007-07-21 drh: " SELECT type, name, tbl_name, rootpage, sql" dbda8d6ce9 2007-07-21 drh: " FROM sqlite_master" dbda8d6ce9 2007-07-21 drh: " WHERE type='view' OR type='trigger'" dbda8d6ce9 2007-07-21 drh: " OR (type='table' AND rootpage=0)" dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( rc ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* At this point, unless the main db was completely empty, there is now a dbda8d6ce9 2007-07-21 drh: ** transaction open on the vacuum database, but not on the main database. dbda8d6ce9 2007-07-21 drh: ** Open a btree level transaction on the main database. This allows a dbda8d6ce9 2007-07-21 drh: ** call to sqlite3BtreeCopyFile(). The main database btree level dbda8d6ce9 2007-07-21 drh: ** transaction is then committed, so the SQL level never knows it was dbda8d6ce9 2007-07-21 drh: ** opened for writing. This way, the SQL transaction used to create the dbda8d6ce9 2007-07-21 drh: ** temporary database never needs to be committed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: u32 meta; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This array determines which meta meta values are preserved in the dbda8d6ce9 2007-07-21 drh: ** vacuum. Even entries are the meta value number and odd entries dbda8d6ce9 2007-07-21 drh: ** are an increment to apply to the meta value after the vacuum. dbda8d6ce9 2007-07-21 drh: ** The increment is used to increase the schema cookie so that other dbda8d6ce9 2007-07-21 drh: ** connections to the same database will know to reread the schema. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const unsigned char aCopy[] = { dbda8d6ce9 2007-07-21 drh: 1, 1, /* Add one to the old schema cookie */ dbda8d6ce9 2007-07-21 drh: 3, 0, /* Preserve the default page cache size */ dbda8d6ce9 2007-07-21 drh: 5, 0, /* Preserve the default text encoding */ dbda8d6ce9 2007-07-21 drh: 6, 0, /* Preserve the user version */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( 1==sqlite3BtreeIsInTrans(pTemp) ); dbda8d6ce9 2007-07-21 drh: assert( 1==sqlite3BtreeIsInTrans(pMain) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Copy Btree meta values */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCopyFile(pMain, pTemp); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCommit(pTemp); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ) goto end_of_vacuum; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeCommit(pMain); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: end_of_vacuum: dbda8d6ce9 2007-07-21 drh: /* Restore the original value of db->flags */ dbda8d6ce9 2007-07-21 drh: db->flags = saved_flags; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Currently there is an SQL level transaction open on the vacuum dbda8d6ce9 2007-07-21 drh: ** database. No locks are held on any other files (since the main file dbda8d6ce9 2007-07-21 drh: ** was committed at the btree level). So it safe to end the transaction dbda8d6ce9 2007-07-21 drh: ** by manually setting the autoCommit flag to true and detaching the dbda8d6ce9 2007-07-21 drh: ** vacuum database. The vacuum_db journal file is deleted when the pager dbda8d6ce9 2007-07-21 drh: ** is closed by the DETACH. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: db->autoCommit = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pDb ){ c287665ba8 2007-09-14 drh: sqlite3BtreeClose(pDb->pBt); dbda8d6ce9 2007-07-21 drh: pDb->pBt = 0; dbda8d6ce9 2007-07-21 drh: pDb->pSchema = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vacuum.c **********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file vtab.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2006 June 10 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This file contains code used to help implement virtual tables. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: vtab.c,v 1.57 2007/09/04 15:38:58 danielk1977 Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: static int createModule( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database in which module is registered */ dbda8d6ce9 2007-07-21 drh: const char *zName, /* Name assigned to this module */ dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule, /* The definition of the module */ dbda8d6ce9 2007-07-21 drh: void *pAux, /* Context pointer for xCreate/xConnect */ dbda8d6ce9 2007-07-21 drh: void (*xDestroy)(void *) /* Module destructor function */ dbda8d6ce9 2007-07-21 drh: ) { c287665ba8 2007-09-14 drh: int rc, nName; c287665ba8 2007-09-14 drh: Module *pMod; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: nName = strlen(zName); c287665ba8 2007-09-14 drh: pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1); dbda8d6ce9 2007-07-21 drh: if( pMod ){ dbda8d6ce9 2007-07-21 drh: char *zCopy = (char *)(&pMod[1]); dbda8d6ce9 2007-07-21 drh: memcpy(zCopy, zName, nName+1); dbda8d6ce9 2007-07-21 drh: pMod->zName = zCopy; dbda8d6ce9 2007-07-21 drh: pMod->pModule = pModule; dbda8d6ce9 2007-07-21 drh: pMod->pAux = pAux; dbda8d6ce9 2007-07-21 drh: pMod->xDestroy = xDestroy; dbda8d6ce9 2007-07-21 drh: pMod = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); dbda8d6ce9 2007-07-21 drh: if( pMod && pMod->xDestroy ){ dbda8d6ce9 2007-07-21 drh: pMod->xDestroy(pMod->pAux); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pMod); dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, SQLITE_OK); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** External API function used to create a new virtual-table module. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_module( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database in which module is registered */ dbda8d6ce9 2007-07-21 drh: const char *zName, /* Name assigned to this module */ dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule, /* The definition of the module */ dbda8d6ce9 2007-07-21 drh: void *pAux /* Context pointer for xCreate/xConnect */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return createModule(db, zName, pModule, pAux, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** External API function used to create a new virtual-table module. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_module_v2( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Database in which module is registered */ dbda8d6ce9 2007-07-21 drh: const char *zName, /* Name assigned to this module */ dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule, /* The definition of the module */ dbda8d6ce9 2007-07-21 drh: void *pAux, /* Context pointer for xCreate/xConnect */ dbda8d6ce9 2007-07-21 drh: void (*xDestroy)(void *) /* Module destructor function */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: return createModule(db, zName, pModule, pAux, xDestroy); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Lock the virtual table so that it cannot be disconnected. dbda8d6ce9 2007-07-21 drh: ** Locks nest. Every lock should have a corresponding unlock. dbda8d6ce9 2007-07-21 drh: ** If an unlock is omitted, resources leaks will occur. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If a disconnect is attempted while a virtual table is locked, dbda8d6ce9 2007-07-21 drh: ** the disconnect is deferred until all locks have been removed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabLock(sqlite3_vtab *pVtab){ dbda8d6ce9 2007-07-21 drh: pVtab->nRef++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Unlock a virtual table. When the last lock is removed, dbda8d6ce9 2007-07-21 drh: ** disconnect the virtual table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){ dbda8d6ce9 2007-07-21 drh: pVtab->nRef--; dbda8d6ce9 2007-07-21 drh: assert(db); dbda8d6ce9 2007-07-21 drh: assert(!sqlite3SafetyCheck(db)); dbda8d6ce9 2007-07-21 drh: if( pVtab->nRef==0 ){ dbda8d6ce9 2007-07-21 drh: if( db->magic==SQLITE_MAGIC_BUSY ){ dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: pVtab->pModule->xDisconnect(pVtab); dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: pVtab->pModule->xDisconnect(pVtab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear any and all virtual-table information from the Table record. dbda8d6ce9 2007-07-21 drh: ** This routine is called, for example, just before deleting the Table dbda8d6ce9 2007-07-21 drh: ** record. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabClear(Table *p){ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab = p->pVtab; dbda8d6ce9 2007-07-21 drh: if( pVtab ){ dbda8d6ce9 2007-07-21 drh: assert( p->pMod && p->pMod->pModule ); dbda8d6ce9 2007-07-21 drh: sqlite3VtabUnlock(p->pSchema->db, pVtab); dbda8d6ce9 2007-07-21 drh: p->pVtab = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->azModuleArg ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nModuleArg; i++){ c287665ba8 2007-09-14 drh: sqlite3_free(p->azModuleArg[i]); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(p->azModuleArg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a new module argument to pTable->azModuleArg[]. dbda8d6ce9 2007-07-21 drh: ** The string is not copied - the pointer is stored. The dbda8d6ce9 2007-07-21 drh: ** string will be freed automatically when the table is dbda8d6ce9 2007-07-21 drh: ** deleted. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){ dbda8d6ce9 2007-07-21 drh: int i = pTable->nModuleArg++; dbda8d6ce9 2007-07-21 drh: int nBytes = sizeof(char *)*(1+pTable->nModuleArg); dbda8d6ce9 2007-07-21 drh: char **azModuleArg; c287665ba8 2007-09-14 drh: azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); dbda8d6ce9 2007-07-21 drh: if( azModuleArg==0 ){ dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: for(j=0; j<i; j++){ c287665ba8 2007-09-14 drh: sqlite3_free(pTable->azModuleArg[j]); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(zArg); c287665ba8 2007-09-14 drh: sqlite3_free(pTable->azModuleArg); dbda8d6ce9 2007-07-21 drh: pTable->nModuleArg = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: azModuleArg[i] = zArg; dbda8d6ce9 2007-07-21 drh: azModuleArg[i+1] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTable->azModuleArg = azModuleArg; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE dbda8d6ce9 2007-07-21 drh: ** statement. The module name has been parsed, but the optional list dbda8d6ce9 2007-07-21 drh: ** of parameters that follow the module name are still pending. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabBeginParse( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: Token *pName1, /* Name of new table, or database name */ dbda8d6ce9 2007-07-21 drh: Token *pName2, /* Name of new table or NULL */ dbda8d6ce9 2007-07-21 drh: Token *pModuleName /* Name of the module for the virtual table */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int iDb; /* The database the table is being created in */ dbda8d6ce9 2007-07-21 drh: Table *pTable; /* The new virtual table */ c287665ba8 2007-09-14 drh: sqlite3 *db; /* Database connection */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( pParse->db->flags & SQLITE_SharedCache ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode"); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); dbda8d6ce9 2007-07-21 drh: pTable = pParse->pNewTable; dbda8d6ce9 2007-07-21 drh: if( pTable==0 || pParse->nErr ) return; dbda8d6ce9 2007-07-21 drh: assert( 0==pTable->pIndex ); dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: db = pParse->db; c287665ba8 2007-09-14 drh: iDb = sqlite3SchemaToIndex(db, pTable->pSchema); dbda8d6ce9 2007-07-21 drh: assert( iDb>=0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTable->isVirtual = 1; dbda8d6ce9 2007-07-21 drh: pTable->nModuleArg = 0; c287665ba8 2007-09-14 drh: addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); c287665ba8 2007-09-14 drh: addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName)); c287665ba8 2007-09-14 drh: addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); dbda8d6ce9 2007-07-21 drh: pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_AUTHORIZATION dbda8d6ce9 2007-07-21 drh: /* Creating a virtual table invokes the authorization callback twice. dbda8d6ce9 2007-07-21 drh: ** The first invocation, to obtain permission to INSERT a row into the dbda8d6ce9 2007-07-21 drh: ** sqlite_master table, has already been made by sqlite3StartTable(). dbda8d6ce9 2007-07-21 drh: ** The second call, to obtain permission to create the table, is made now. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTable->azModuleArg ){ dbda8d6ce9 2007-07-21 drh: sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, dbda8d6ce9 2007-07-21 drh: pTable->azModuleArg[0], pParse->db->aDb[iDb].zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine takes the module argument that has been accumulating dbda8d6ce9 2007-07-21 drh: ** in pParse->zArg[] and appends it to the list of arguments on the dbda8d6ce9 2007-07-21 drh: ** virtual table currently under construction in pParse->pTable. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void addArgumentToVtab(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: if( pParse->sArg.z && pParse->pNewTable ){ dbda8d6ce9 2007-07-21 drh: const char *z = (const char*)pParse->sArg.z; dbda8d6ce9 2007-07-21 drh: int n = pParse->sArg.n; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; c287665ba8 2007-09-14 drh: addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The parser calls this routine after the CREATE VIRTUAL TABLE statement dbda8d6ce9 2007-07-21 drh: ** has been completely parsed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* The table being constructed */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; /* The database connection */ dbda8d6ce9 2007-07-21 drh: char *zModule; /* The module name of the table: USING modulename */ dbda8d6ce9 2007-07-21 drh: Module *pMod = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: addArgumentToVtab(pParse); dbda8d6ce9 2007-07-21 drh: pParse->sArg.z = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Lookup the module name. */ dbda8d6ce9 2007-07-21 drh: pTab = pParse->pNewTable; dbda8d6ce9 2007-07-21 drh: if( pTab==0 ) return; dbda8d6ce9 2007-07-21 drh: db = pParse->db; dbda8d6ce9 2007-07-21 drh: if( pTab->nModuleArg<1 ) return; dbda8d6ce9 2007-07-21 drh: zModule = pTab->azModuleArg[0]; dbda8d6ce9 2007-07-21 drh: pMod = (Module *)sqlite3HashFind(&db->aModule, zModule, strlen(zModule)); dbda8d6ce9 2007-07-21 drh: pTab->pMod = pMod; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the CREATE VIRTUAL TABLE statement is being entered for the dbda8d6ce9 2007-07-21 drh: ** first time (in other words if the virtual table is actually being dbda8d6ce9 2007-07-21 drh: ** created now instead of just being read out of sqlite_master) then dbda8d6ce9 2007-07-21 drh: ** do additional initialization work and store the statement text dbda8d6ce9 2007-07-21 drh: ** in the sqlite_master table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !db->init.busy ){ dbda8d6ce9 2007-07-21 drh: char *zStmt; dbda8d6ce9 2007-07-21 drh: char *zWhere; dbda8d6ce9 2007-07-21 drh: int iDb; dbda8d6ce9 2007-07-21 drh: Vdbe *v; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ dbda8d6ce9 2007-07-21 drh: if( pEnd ){ dbda8d6ce9 2007-07-21 drh: pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* A slot for the record has already been allocated in the dbda8d6ce9 2007-07-21 drh: ** SQLITE_MASTER table. We just need to update that slot with all dbda8d6ce9 2007-07-21 drh: ** the information we've collected. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The top of the stack is the rootpage allocated by sqlite3StartTable(). dbda8d6ce9 2007-07-21 drh: ** This value is always 0 and is ignored, a virtual table does not have a dbda8d6ce9 2007-07-21 drh: ** rootpage. The next entry on the stack is the rowid of the record dbda8d6ce9 2007-07-21 drh: ** in the sqlite_master table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: sqlite3NestedParse(pParse, dbda8d6ce9 2007-07-21 drh: "UPDATE %Q.%s " dbda8d6ce9 2007-07-21 drh: "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " dbda8d6ce9 2007-07-21 drh: "WHERE rowid=#1", dbda8d6ce9 2007-07-21 drh: db->aDb[iDb].zName, SCHEMA_TABLE(iDb), dbda8d6ce9 2007-07-21 drh: pTab->zName, dbda8d6ce9 2007-07-21 drh: pTab->zName, dbda8d6ce9 2007-07-21 drh: zStmt dbda8d6ce9 2007-07-21 drh: ); c287665ba8 2007-09-14 drh: sqlite3_free(zStmt); dbda8d6ce9 2007-07-21 drh: v = sqlite3GetVdbe(pParse); dbda8d6ce9 2007-07-21 drh: sqlite3ChangeCookie(db, v, iDb); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Expire, 0, 0); c287665ba8 2007-09-14 drh: zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If we are rereading the sqlite_master table create the in-memory dbda8d6ce9 2007-07-21 drh: ** record of the table. If the module has already been registered, dbda8d6ce9 2007-07-21 drh: ** also call the xConnect method here. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: else { dbda8d6ce9 2007-07-21 drh: Table *pOld; dbda8d6ce9 2007-07-21 drh: Schema *pSchema = pTab->pSchema; dbda8d6ce9 2007-07-21 drh: const char *zName = pTab->zName; dbda8d6ce9 2007-07-21 drh: int nName = strlen(zName) + 1; dbda8d6ce9 2007-07-21 drh: pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); dbda8d6ce9 2007-07-21 drh: if( pOld ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pSchema->db = pParse->db; dbda8d6ce9 2007-07-21 drh: pParse->pNewTable = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The parser calls this routine when it sees the first token dbda8d6ce9 2007-07-21 drh: ** of an argument to the module name in a CREATE VIRTUAL TABLE statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabArgInit(Parse *pParse){ dbda8d6ce9 2007-07-21 drh: addArgumentToVtab(pParse); dbda8d6ce9 2007-07-21 drh: pParse->sArg.z = 0; dbda8d6ce9 2007-07-21 drh: pParse->sArg.n = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The parser calls this routine for each token after the first token dbda8d6ce9 2007-07-21 drh: ** in an argument to the module name in a CREATE VIRTUAL TABLE statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse *pParse, Token *p){ dbda8d6ce9 2007-07-21 drh: Token *pArg = &pParse->sArg; dbda8d6ce9 2007-07-21 drh: if( pArg->z==0 ){ dbda8d6ce9 2007-07-21 drh: pArg->z = p->z; dbda8d6ce9 2007-07-21 drh: pArg->n = p->n; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: assert(pArg->z < p->z); dbda8d6ce9 2007-07-21 drh: pArg->n = (p->z + p->n - pArg->z); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invoke a virtual table constructor (either xCreate or xConnect). The dbda8d6ce9 2007-07-21 drh: ** pointer to the function to invoke is passed as the fourth parameter dbda8d6ce9 2007-07-21 drh: ** to this procedure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int vtabCallConstructor( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: Table *pTab, dbda8d6ce9 2007-07-21 drh: Module *pMod, dbda8d6ce9 2007-07-21 drh: int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), dbda8d6ce9 2007-07-21 drh: char **pzErr dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: int rc2; c287665ba8 2007-09-14 drh: sqlite3_vtab *pVtab = 0; dbda8d6ce9 2007-07-21 drh: const char *const*azArg = (const char *const*)pTab->azModuleArg; dbda8d6ce9 2007-07-21 drh: int nArg = pTab->nModuleArg; dbda8d6ce9 2007-07-21 drh: char *zErr = 0; c287665ba8 2007-09-14 drh: char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !zModuleName ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( !db->pVTab ); dbda8d6ce9 2007-07-21 drh: assert( xConstruct ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: db->pVTab = pTab; dbda8d6ce9 2007-07-21 drh: rc = sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_OK ); c287665ba8 2007-09-14 drh: rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr); c287665ba8 2007-09-14 drh: rc2 = sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && pVtab ){ dbda8d6ce9 2007-07-21 drh: pVtab->pModule = pMod->pModule; dbda8d6ce9 2007-07-21 drh: pVtab->nRef = 1; c287665ba8 2007-09-14 drh: pTab->pVtab = pVtab; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=rc ){ dbda8d6ce9 2007-07-21 drh: if( zErr==0 ){ c287665ba8 2007-09-14 drh: *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); dbda8d6ce9 2007-07-21 drh: }else { c287665ba8 2007-09-14 drh: *pzErr = sqlite3MPrintf(db, "%s", zErr); dbda8d6ce9 2007-07-21 drh: sqlite3_free(zErr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( db->pVTab ){ dbda8d6ce9 2007-07-21 drh: const char *zFormat = "vtable constructor did not declare schema: %s"; c287665ba8 2007-09-14 drh: *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = rc2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db->pVTab = 0; c287665ba8 2007-09-14 drh: sqlite3_free(zModuleName); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If everything went according to plan, loop through the columns dbda8d6ce9 2007-07-21 drh: ** of the table to see if any of them contain the token "hidden". dbda8d6ce9 2007-07-21 drh: ** If so, set the Column.isHidden flag and remove the token from dbda8d6ce9 2007-07-21 drh: ** the type string. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: int iCol; dbda8d6ce9 2007-07-21 drh: for(iCol=0; iCol<pTab->nCol; iCol++){ dbda8d6ce9 2007-07-21 drh: char *zType = pTab->aCol[iCol].zType; dbda8d6ce9 2007-07-21 drh: int nType; dbda8d6ce9 2007-07-21 drh: int i = 0; dbda8d6ce9 2007-07-21 drh: if( !zType ) continue; dbda8d6ce9 2007-07-21 drh: nType = strlen(zType); dbda8d6ce9 2007-07-21 drh: if( sqlite3StrNICmp("hidden", zType, 6) || (zType[6] && zType[6]!=' ') ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<nType; i++){ dbda8d6ce9 2007-07-21 drh: if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7)) dbda8d6ce9 2007-07-21 drh: && (zType[i+7]=='\0' || zType[i+7]==' ') dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<nType ){ dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: int nDel = 6 + (zType[i+6] ? 1 : 0); dbda8d6ce9 2007-07-21 drh: for(j=i; (j+nDel)<=nType; j++){ dbda8d6ce9 2007-07-21 drh: zType[j] = zType[j+nDel]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zType[i]=='\0' && i>0 ){ dbda8d6ce9 2007-07-21 drh: assert(zType[i-1]==' '); dbda8d6ce9 2007-07-21 drh: zType[i-1] = '\0'; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTab->aCol[iCol].isHidden = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is invoked by the parser to call the xConnect() method dbda8d6ce9 2007-07-21 drh: ** of the virtual table pTab. If an error occurs, an error code is returned dbda8d6ce9 2007-07-21 drh: ** and an error left in pParse. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This call is a no-op if table pTab is not a virtual table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ dbda8d6ce9 2007-07-21 drh: Module *pMod; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pTab || !pTab->isVirtual || pTab->pVtab ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pMod = pTab->pMod; dbda8d6ce9 2007-07-21 drh: if( !pMod ){ dbda8d6ce9 2007-07-21 drh: const char *zModule = pTab->azModuleArg[0]; dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "no such module: %s", zModule); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: char *zErr = 0; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "%s", zErr); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(zErr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add the virtual table pVtab to the array sqlite3.aVTrans[]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){ dbda8d6ce9 2007-07-21 drh: const int ARRAY_INCR = 5; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Grow the sqlite3.aVTrans array if required */ dbda8d6ce9 2007-07-21 drh: if( (db->nVTrans%ARRAY_INCR)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab **aVTrans; dbda8d6ce9 2007-07-21 drh: int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); c287665ba8 2007-09-14 drh: aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); dbda8d6ce9 2007-07-21 drh: if( !aVTrans ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR); dbda8d6ce9 2007-07-21 drh: db->aVTrans = aVTrans; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add pVtab to the end of sqlite3.aVTrans */ dbda8d6ce9 2007-07-21 drh: db->aVTrans[db->nVTrans++] = pVtab; dbda8d6ce9 2007-07-21 drh: sqlite3VtabLock(pVtab); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is invoked by the vdbe to call the xCreate method dbda8d6ce9 2007-07-21 drh: ** of the virtual table named zTab in database iDb. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an error occurs, *pzErr is set to point an an English language dbda8d6ce9 2007-07-21 drh: ** description of the error and an SQLITE_XXX error code is returned. c287665ba8 2007-09-14 drh: ** In this case the caller must call sqlite3_free() on *pzErr. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: Module *pMod; dbda8d6ce9 2007-07-21 drh: const char *zModule; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); dbda8d6ce9 2007-07-21 drh: assert(pTab && pTab->isVirtual && !pTab->pVtab); dbda8d6ce9 2007-07-21 drh: pMod = pTab->pMod; dbda8d6ce9 2007-07-21 drh: zModule = pTab->azModuleArg[0]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the module has been registered and includes a Create method, dbda8d6ce9 2007-07-21 drh: ** invoke it now. If the module has not been registered, return an dbda8d6ce9 2007-07-21 drh: ** error. Otherwise, do nothing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( !pMod ){ c287665ba8 2007-09-14 drh: *pzErr = sqlite3MPrintf(db, "no such module: %s", zModule); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && pTab->pVtab ){ dbda8d6ce9 2007-07-21 drh: rc = addToVTrans(db, pTab->pVtab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is used to set the schema of a virtual table. It is only dbda8d6ce9 2007-07-21 drh: ** valid to call this function from within the xCreate() or xConnect() of a dbda8d6ce9 2007-07-21 drh: ** virtual table module. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ dbda8d6ce9 2007-07-21 drh: Parse sParse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; c287665ba8 2007-09-14 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: char *zErr = 0; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: pTab = db->pVTab; dbda8d6ce9 2007-07-21 drh: if( !pTab ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_MISUSE, 0); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memset(&sParse, 0, sizeof(Parse)); dbda8d6ce9 2007-07-21 drh: sParse.declareVtab = 1; dbda8d6ce9 2007-07-21 drh: sParse.db = db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( dbda8d6ce9 2007-07-21 drh: SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) && dbda8d6ce9 2007-07-21 drh: sParse.pNewTable && dbda8d6ce9 2007-07-21 drh: !sParse.pNewTable->pSelect && dbda8d6ce9 2007-07-21 drh: !sParse.pNewTable->isVirtual dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: pTab->aCol = sParse.pNewTable->aCol; dbda8d6ce9 2007-07-21 drh: pTab->nCol = sParse.pNewTable->nCol; dbda8d6ce9 2007-07-21 drh: sParse.pNewTable->nCol = 0; dbda8d6ce9 2007-07-21 drh: sParse.pNewTable->aCol = 0; dbda8d6ce9 2007-07-21 drh: db->pVTab = 0; dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_ERROR, zErr); c287665ba8 2007-09-14 drh: sqlite3_free(zErr); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sParse.declareVtab = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(sParse.pNewTable); dbda8d6ce9 2007-07-21 drh: sParse.pNewTable = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( (rc&0xff)==rc ); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is invoked by the vdbe to call the xDestroy method dbda8d6ce9 2007-07-21 drh: ** of the virtual table named zTab in database iDb. This occurs dbda8d6ce9 2007-07-21 drh: ** when a DROP TABLE is mentioned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This call is a no-op if zTab is not a virtual table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab) dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); dbda8d6ce9 2007-07-21 drh: assert(pTab); dbda8d6ce9 2007-07-21 drh: if( pTab->pVtab ){ dbda8d6ce9 2007-07-21 drh: int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy; dbda8d6ce9 2007-07-21 drh: rc = sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: assert( rc==SQLITE_OK ); dbda8d6ce9 2007-07-21 drh: if( xDestroy ){ dbda8d6ce9 2007-07-21 drh: rc = xDestroy(pTab->pVtab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: pTab->pVtab = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function invokes either the xRollback or xCommit method dbda8d6ce9 2007-07-21 drh: ** of each of the virtual tables in the sqlite3.aVTrans array. The method dbda8d6ce9 2007-07-21 drh: ** called is identified by the second argument, "offset", which is dbda8d6ce9 2007-07-21 drh: ** the offset of the method to call in the sqlite3_module structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The array is cleared after invoking the callbacks. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void callFinaliser(sqlite3 *db, int offset){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( db->aVTrans ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab = db->aVTrans[i]; dbda8d6ce9 2007-07-21 drh: int (*x)(sqlite3_vtab *); dbda8d6ce9 2007-07-21 drh: x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset); dbda8d6ce9 2007-07-21 drh: if( x ) x(pVtab); dbda8d6ce9 2007-07-21 drh: sqlite3VtabUnlock(db, pVtab); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(db->aVTrans); dbda8d6ce9 2007-07-21 drh: db->nVTrans = 0; dbda8d6ce9 2007-07-21 drh: db->aVTrans = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If argument rc2 is not SQLITE_OK, then return it and do nothing. dbda8d6ce9 2007-07-21 drh: ** Otherwise, invoke the xSync method of all virtual tables in the dbda8d6ce9 2007-07-21 drh: ** sqlite3.aVTrans array. Return the error code for the first error dbda8d6ce9 2007-07-21 drh: ** that occurs, or SQLITE_OK if all xSync operations are successful. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, int rc2){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: int rcsafety; dbda8d6ce9 2007-07-21 drh: sqlite3_vtab **aVTrans = db->aVTrans; dbda8d6ce9 2007-07-21 drh: if( rc2!=SQLITE_OK ) return rc2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = sqlite3SafetyOff(db); dbda8d6ce9 2007-07-21 drh: db->aVTrans = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; rc==SQLITE_OK && i<db->nVTrans && aVTrans[i]; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab = aVTrans[i]; dbda8d6ce9 2007-07-21 drh: int (*x)(sqlite3_vtab *); dbda8d6ce9 2007-07-21 drh: x = pVtab->pModule->xSync; dbda8d6ce9 2007-07-21 drh: if( x ){ dbda8d6ce9 2007-07-21 drh: rc = x(pVtab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db->aVTrans = aVTrans; dbda8d6ce9 2007-07-21 drh: rcsafety = sqlite3SafetyOn(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: rc = rcsafety; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invoke the xRollback method of all virtual tables in the dbda8d6ce9 2007-07-21 drh: ** sqlite3.aVTrans array. Then clear the array itself. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: callFinaliser(db, (int)(&((sqlite3_module *)0)->xRollback)); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invoke the xCommit method of all virtual tables in the dbda8d6ce9 2007-07-21 drh: ** sqlite3.aVTrans array. Then clear the array itself. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: callFinaliser(db, (int)(&((sqlite3_module *)0)->xCommit)); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the virtual table pVtab supports the transaction interface dbda8d6ce9 2007-07-21 drh: ** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is dbda8d6ce9 2007-07-21 drh: ** not currently open, invoke the xBegin method now. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the xBegin call is successful, place the sqlite3_vtab pointer dbda8d6ce9 2007-07-21 drh: ** in the sqlite3.aVTrans array. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: const sqlite3_module *pModule; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Special case: If db->aVTrans is NULL and db->nVTrans is greater dbda8d6ce9 2007-07-21 drh: ** than zero, then this function is being called from within a dbda8d6ce9 2007-07-21 drh: ** virtual module xSync() callback. It is illegal to write to dbda8d6ce9 2007-07-21 drh: ** virtual module tables in this case, so return SQLITE_LOCKED. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( 0==db->aVTrans && db->nVTrans>0 ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_LOCKED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !pVtab ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pModule = pVtab->pModule; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pModule->xBegin ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If pVtab is already in the aVTrans array, return early */ dbda8d6ce9 2007-07-21 drh: for(i=0; (i<db->nVTrans) && 0!=db->aVTrans[i]; i++){ dbda8d6ce9 2007-07-21 drh: if( db->aVTrans[i]==pVtab ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Invoke the xBegin method */ dbda8d6ce9 2007-07-21 drh: rc = pModule->xBegin(pVtab); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: rc = addToVTrans(db, pVtab); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The first parameter (pDef) is a function implementation. The dbda8d6ce9 2007-07-21 drh: ** second parameter (pExpr) is the first argument to this function. dbda8d6ce9 2007-07-21 drh: ** If pExpr is a column in a virtual table, then let the virtual dbda8d6ce9 2007-07-21 drh: ** table implementation have an opportunity to overload the function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is used to allow virtual table implementations to dbda8d6ce9 2007-07-21 drh: ** overload MATCH, LIKE, GLOB, and REGEXP operators. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return either the pDef argument (indicating no change) or a dbda8d6ce9 2007-07-21 drh: ** new FuncDef structure that is marked as ephemeral using the dbda8d6ce9 2007-07-21 drh: ** SQLITE_FUNC_EPHEM flag. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( c287665ba8 2007-09-14 drh: sqlite3 *db, /* Database connection for reporting malloc problems */ dbda8d6ce9 2007-07-21 drh: FuncDef *pDef, /* Function to possibly overload */ dbda8d6ce9 2007-07-21 drh: int nArg, /* Number of arguments to the function */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr /* First argument to the function */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Table *pTab; dbda8d6ce9 2007-07-21 drh: sqlite3_vtab *pVtab; dbda8d6ce9 2007-07-21 drh: sqlite3_module *pMod; dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value**); dbda8d6ce9 2007-07-21 drh: void *pArg; dbda8d6ce9 2007-07-21 drh: FuncDef *pNew; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: char *zLowerName; dbda8d6ce9 2007-07-21 drh: unsigned char *z; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to see the left operand is a column in a virtual table */ dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) return pDef; dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_COLUMN ) return pDef; dbda8d6ce9 2007-07-21 drh: pTab = pExpr->pTab; dbda8d6ce9 2007-07-21 drh: if( pTab==0 ) return pDef; dbda8d6ce9 2007-07-21 drh: if( !pTab->isVirtual ) return pDef; dbda8d6ce9 2007-07-21 drh: pVtab = pTab->pVtab; dbda8d6ce9 2007-07-21 drh: assert( pVtab!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pVtab->pModule!=0 ); dbda8d6ce9 2007-07-21 drh: pMod = (sqlite3_module *)pVtab->pModule; dbda8d6ce9 2007-07-21 drh: if( pMod->xFindFunction==0 ) return pDef; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Call the xFuncFunction method on the virtual table implementation dbda8d6ce9 2007-07-21 drh: ** to see if the implementation wants to overload this function dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: zLowerName = sqlite3DbStrDup(db, pDef->zName); c287665ba8 2007-09-14 drh: if( zLowerName ){ c287665ba8 2007-09-14 drh: for(z=(unsigned char*)zLowerName; *z; z++){ c287665ba8 2007-09-14 drh: *z = sqlite3UpperToLower[*z]; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg); c287665ba8 2007-09-14 drh: sqlite3_free(zLowerName); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( rc==0 ){ dbda8d6ce9 2007-07-21 drh: return pDef; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create a new ephemeral function definition for the overloaded dbda8d6ce9 2007-07-21 drh: ** function */ c287665ba8 2007-09-14 drh: pNew = sqlite3DbMallocZero(db, sizeof(*pNew) + strlen(pDef->zName) ); dbda8d6ce9 2007-07-21 drh: if( pNew==0 ){ dbda8d6ce9 2007-07-21 drh: return pDef; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pNew = *pDef; dbda8d6ce9 2007-07-21 drh: memcpy(pNew->zName, pDef->zName, strlen(pDef->zName)+1); dbda8d6ce9 2007-07-21 drh: pNew->xFunc = xFunc; dbda8d6ce9 2007-07-21 drh: pNew->pUserData = pArg; dbda8d6ce9 2007-07-21 drh: pNew->flags |= SQLITE_FUNC_EPHEM; dbda8d6ce9 2007-07-21 drh: return pNew; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of vtab.c ************************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file where.c *******************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** This module contains C code that generates VDBE code used to process dbda8d6ce9 2007-07-21 drh: ** the WHERE clause of SQL statements. This module is reponsible for dbda8d6ce9 2007-07-21 drh: ** generating the code that loops through a table looking for applicable dbda8d6ce9 2007-07-21 drh: ** rows. Indices are selected and used to speed the search when doing dbda8d6ce9 2007-07-21 drh: ** so is applicable. Because this module is responsible for selecting dbda8d6ce9 2007-07-21 drh: ** indices, you might also think of this module as the "query optimizer". dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: where.c,v 1.261 2007/09/13 17:54:40 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The number of bits in a Bitmask. "BMS" means "BitMask Size". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define BMS (sizeof(Bitmask)*8) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Trace output macros dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_where_trace = 0; dbda8d6ce9 2007-07-21 drh: # define WHERETRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: # define WHERETRACE(X) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward reference dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct WhereClause WhereClause; dbda8d6ce9 2007-07-21 drh: typedef struct ExprMaskSet ExprMaskSet; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The query generator uses an array of instances of this structure to dbda8d6ce9 2007-07-21 drh: ** help it analyze the subexpressions of the WHERE clause. Each WHERE dbda8d6ce9 2007-07-21 drh: ** clause subexpression is separated from the others by an AND operator. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All WhereTerms are collected into a single WhereClause structure. dbda8d6ce9 2007-07-21 drh: ** The following identity holds: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When a term is of the form: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** X <op> <expr> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** where X is a column name and <op> is one of certain operators, dbda8d6ce9 2007-07-21 drh: ** then WhereTerm.leftCursor and WhereTerm.leftColumn record the dbda8d6ce9 2007-07-21 drh: ** cursor number and column number for X. WhereTerm.operator records dbda8d6ce9 2007-07-21 drh: ** the <op> using a bitmask encoding defined by WO_xxx below. The dbda8d6ce9 2007-07-21 drh: ** use of a bitmask encoding for the operator allows us to search dbda8d6ce9 2007-07-21 drh: ** quickly for terms that match any of several different operators. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** prereqRight and prereqAll record sets of cursor numbers, dbda8d6ce9 2007-07-21 drh: ** but they do so indirectly. A single ExprMaskSet structure translates dbda8d6ce9 2007-07-21 drh: ** cursor number into bits and the translated bit is stored in the prereq dbda8d6ce9 2007-07-21 drh: ** fields. The translation is used in order to maximize the number of dbda8d6ce9 2007-07-21 drh: ** bits that will fit in a Bitmask. The VDBE cursor numbers might be dbda8d6ce9 2007-07-21 drh: ** spread out over the non-negative integers. For example, the cursor dbda8d6ce9 2007-07-21 drh: ** numbers might be 3, 8, 9, 10, 20, 23, 41, and 45. The ExprMaskSet dbda8d6ce9 2007-07-21 drh: ** translates these sparse cursor numbers into consecutive integers dbda8d6ce9 2007-07-21 drh: ** beginning with 0 in order to make the best possible use of the available dbda8d6ce9 2007-07-21 drh: ** bits in the Bitmask. So, in the example above, the cursor numbers dbda8d6ce9 2007-07-21 drh: ** would be mapped into integers 0 through 7. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: typedef struct WhereTerm WhereTerm; dbda8d6ce9 2007-07-21 drh: struct WhereTerm { dbda8d6ce9 2007-07-21 drh: Expr *pExpr; /* Pointer to the subexpression */ dbda8d6ce9 2007-07-21 drh: i16 iParent; /* Disable pWC->a[iParent] when this term disabled */ dbda8d6ce9 2007-07-21 drh: i16 leftCursor; /* Cursor number of X in "X <op> <expr>" */ dbda8d6ce9 2007-07-21 drh: i16 leftColumn; /* Column number of X in "X <op> <expr>" */ dbda8d6ce9 2007-07-21 drh: u16 eOperator; /* A WO_xx value describing <op> */ dbda8d6ce9 2007-07-21 drh: u8 flags; /* Bit flags. See below */ dbda8d6ce9 2007-07-21 drh: u8 nChild; /* Number of children that must disable us */ dbda8d6ce9 2007-07-21 drh: WhereClause *pWC; /* The clause this term is part of */ dbda8d6ce9 2007-07-21 drh: Bitmask prereqRight; /* Bitmask of tables used by pRight */ dbda8d6ce9 2007-07-21 drh: Bitmask prereqAll; /* Bitmask of tables referenced by p */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Allowed values of WhereTerm.flags dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define TERM_DYNAMIC 0x01 /* Need to call sqlite3ExprDelete(pExpr) */ dbda8d6ce9 2007-07-21 drh: #define TERM_VIRTUAL 0x02 /* Added by the optimizer. Do not code */ dbda8d6ce9 2007-07-21 drh: #define TERM_CODED 0x04 /* This term is already coded */ dbda8d6ce9 2007-07-21 drh: #define TERM_COPIED 0x08 /* Has a child */ dbda8d6ce9 2007-07-21 drh: #define TERM_OR_OK 0x10 /* Used during OR-clause processing */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure holds all information about a dbda8d6ce9 2007-07-21 drh: ** WHERE clause. Mostly this is a container for one or more WhereTerms. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct WhereClause { dbda8d6ce9 2007-07-21 drh: Parse *pParse; /* The parser context */ dbda8d6ce9 2007-07-21 drh: ExprMaskSet *pMaskSet; /* Mapping of table indices to bitmasks */ dbda8d6ce9 2007-07-21 drh: int nTerm; /* Number of terms */ dbda8d6ce9 2007-07-21 drh: int nSlot; /* Number of entries in a[] */ dbda8d6ce9 2007-07-21 drh: WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ dbda8d6ce9 2007-07-21 drh: WhereTerm aStatic[10]; /* Initial static space for a[] */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure keeps track of a mapping dbda8d6ce9 2007-07-21 drh: ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The VDBE cursor numbers are small integers contained in dbda8d6ce9 2007-07-21 drh: ** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE dbda8d6ce9 2007-07-21 drh: ** clause, the cursor numbers might not begin with 0 and they might dbda8d6ce9 2007-07-21 drh: ** contain gaps in the numbering sequence. But we want to make maximum dbda8d6ce9 2007-07-21 drh: ** use of the bits in our bitmasks. This structure provides a mapping dbda8d6ce9 2007-07-21 drh: ** from the sparse cursor numbers into consecutive integers beginning dbda8d6ce9 2007-07-21 drh: ** with 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If ExprMaskSet.ix[A]==B it means that The A-th bit of a Bitmask dbda8d6ce9 2007-07-21 drh: ** corresponds VDBE cursor number B. The A-th bit of a bitmask is 1<<A. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For example, if the WHERE clause expression used these VDBE dbda8d6ce9 2007-07-21 drh: ** cursors: 4, 5, 8, 29, 57, 73. Then the ExprMaskSet structure dbda8d6ce9 2007-07-21 drh: ** would map those cursor numbers into bits 0 through 5. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that the mapping is not necessarily ordered. In the example dbda8d6ce9 2007-07-21 drh: ** above, the mapping might go like this: 4->3, 5->1, 8->2, 29->0, dbda8d6ce9 2007-07-21 drh: ** 57->5, 73->4. Or one of 719 other combinations might be used. It dbda8d6ce9 2007-07-21 drh: ** does not really matter. What is important is that sparse cursor dbda8d6ce9 2007-07-21 drh: ** numbers all get mapped into bit numbers that begin with 0 and contain dbda8d6ce9 2007-07-21 drh: ** no gaps. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct ExprMaskSet { dbda8d6ce9 2007-07-21 drh: int n; /* Number of assigned cursor values */ dbda8d6ce9 2007-07-21 drh: int ix[sizeof(Bitmask)*8]; /* Cursor assigned to each bit */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Bitmasks for the operators that indices are able to exploit. An dbda8d6ce9 2007-07-21 drh: ** OR-ed combination of these values can be used when searching for dbda8d6ce9 2007-07-21 drh: ** terms in the where clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define WO_IN 1 dbda8d6ce9 2007-07-21 drh: #define WO_EQ 2 dbda8d6ce9 2007-07-21 drh: #define WO_LT (WO_EQ<<(TK_LT-TK_EQ)) dbda8d6ce9 2007-07-21 drh: #define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) dbda8d6ce9 2007-07-21 drh: #define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) dbda8d6ce9 2007-07-21 drh: #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) dbda8d6ce9 2007-07-21 drh: #define WO_MATCH 64 dbda8d6ce9 2007-07-21 drh: #define WO_ISNULL 128 dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Value for flags returned by bestIndex(). dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The least significant byte is reserved as a mask for WO_ values above. dbda8d6ce9 2007-07-21 drh: ** The WhereLevel.flags field is usually set to WO_IN|WO_EQ|WO_ISNULL. dbda8d6ce9 2007-07-21 drh: ** But if the table is the right table of a left join, WhereLevel.flags dbda8d6ce9 2007-07-21 drh: ** is set to WO_IN|WO_EQ. The WhereLevel.flags field can then be used as dbda8d6ce9 2007-07-21 drh: ** the "op" parameter to findTerm when we are resolving equality constraints. dbda8d6ce9 2007-07-21 drh: ** ISNULL constraints will then not be used on the right table of a left dbda8d6ce9 2007-07-21 drh: ** join. Tickets #2177 and #2189. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define WHERE_ROWID_EQ 0x000100 /* rowid=EXPR or rowid IN (...) */ dbda8d6ce9 2007-07-21 drh: #define WHERE_ROWID_RANGE 0x000200 /* rowid<EXPR and/or rowid>EXPR */ dbda8d6ce9 2007-07-21 drh: #define WHERE_COLUMN_EQ 0x001000 /* x=EXPR or x IN (...) */ dbda8d6ce9 2007-07-21 drh: #define WHERE_COLUMN_RANGE 0x002000 /* x<EXPR and/or x>EXPR */ dbda8d6ce9 2007-07-21 drh: #define WHERE_COLUMN_IN 0x004000 /* x IN (...) */ dbda8d6ce9 2007-07-21 drh: #define WHERE_TOP_LIMIT 0x010000 /* x<EXPR or x<=EXPR constraint */ dbda8d6ce9 2007-07-21 drh: #define WHERE_BTM_LIMIT 0x020000 /* x>EXPR or x>=EXPR constraint */ dbda8d6ce9 2007-07-21 drh: #define WHERE_IDX_ONLY 0x080000 /* Use index only - omit table */ dbda8d6ce9 2007-07-21 drh: #define WHERE_ORDERBY 0x100000 /* Output will appear in correct order */ dbda8d6ce9 2007-07-21 drh: #define WHERE_REVERSE 0x200000 /* Scan in reverse order */ dbda8d6ce9 2007-07-21 drh: #define WHERE_UNIQUE 0x400000 /* Selects no more than one row */ dbda8d6ce9 2007-07-21 drh: #define WHERE_VIRTUALTABLE 0x800000 /* Use virtual-table processing */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Initialize a preallocated WhereClause structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void whereClauseInit( dbda8d6ce9 2007-07-21 drh: WhereClause *pWC, /* The WhereClause to be initialized */ dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: ExprMaskSet *pMaskSet /* Mapping from table indices to bitmasks */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: pWC->pParse = pParse; dbda8d6ce9 2007-07-21 drh: pWC->pMaskSet = pMaskSet; dbda8d6ce9 2007-07-21 drh: pWC->nTerm = 0; dbda8d6ce9 2007-07-21 drh: pWC->nSlot = ArraySize(pWC->aStatic); dbda8d6ce9 2007-07-21 drh: pWC->a = pWC->aStatic; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Deallocate a WhereClause structure. The WhereClause structure dbda8d6ce9 2007-07-21 drh: ** itself is not freed. This routine is the inverse of whereClauseInit(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void whereClauseClear(WhereClause *pWC){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: WhereTerm *a; dbda8d6ce9 2007-07-21 drh: for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){ dbda8d6ce9 2007-07-21 drh: if( a->flags & TERM_DYNAMIC ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(a->pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pWC->a!=pWC->aStatic ){ c287665ba8 2007-09-14 drh: sqlite3_free(pWC->a); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a new entries to the WhereClause structure. Increase the allocated dbda8d6ce9 2007-07-21 drh: ** space as necessary. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the flags argument includes TERM_DYNAMIC, then responsibility dbda8d6ce9 2007-07-21 drh: ** for freeing the expression p is assumed by the WhereClause object. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** WARNING: This routine might reallocate the space used to store dbda8d6ce9 2007-07-21 drh: ** WhereTerms. All pointers to WhereTerms should be invalided after dbda8d6ce9 2007-07-21 drh: ** calling this routine. Such pointers may be reinitialized by referencing dbda8d6ce9 2007-07-21 drh: ** the pWC->a[] array. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int whereClauseInsert(WhereClause *pWC, Expr *p, int flags){ dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm; dbda8d6ce9 2007-07-21 drh: int idx; dbda8d6ce9 2007-07-21 drh: if( pWC->nTerm>=pWC->nSlot ){ dbda8d6ce9 2007-07-21 drh: WhereTerm *pOld = pWC->a; c287665ba8 2007-09-14 drh: pWC->a = sqlite3_malloc( sizeof(pWC->a[0])*pWC->nSlot*2 ); dbda8d6ce9 2007-07-21 drh: if( pWC->a==0 ){ c287665ba8 2007-09-14 drh: pWC->pParse->db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: if( flags & TERM_DYNAMIC ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm); dbda8d6ce9 2007-07-21 drh: if( pOld!=pWC->aStatic ){ c287665ba8 2007-09-14 drh: sqlite3_free(pOld); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pWC->nSlot *= 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTerm = &pWC->a[idx = pWC->nTerm]; dbda8d6ce9 2007-07-21 drh: pWC->nTerm++; dbda8d6ce9 2007-07-21 drh: pTerm->pExpr = p; dbda8d6ce9 2007-07-21 drh: pTerm->flags = flags; dbda8d6ce9 2007-07-21 drh: pTerm->pWC = pWC; dbda8d6ce9 2007-07-21 drh: pTerm->iParent = -1; dbda8d6ce9 2007-07-21 drh: return idx; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine identifies subexpressions in the WHERE clause where dbda8d6ce9 2007-07-21 drh: ** each subexpression is separated by the AND operator or some other dbda8d6ce9 2007-07-21 drh: ** operator specified in the op parameter. The WhereClause structure dbda8d6ce9 2007-07-21 drh: ** is filled with pointers to subexpressions. For example: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22) dbda8d6ce9 2007-07-21 drh: ** \________/ \_______________/ \________________/ dbda8d6ce9 2007-07-21 drh: ** slot[0] slot[1] slot[2] dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The original WHERE clause in pExpr is unaltered. All this routine dbda8d6ce9 2007-07-21 drh: ** does is make slot[] entries point to substructure within pExpr. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the previous sentence and in the diagram, "slot[]" refers to dbda8d6ce9 2007-07-21 drh: ** the WhereClause.a[] array. This array grows as needed to contain dbda8d6ce9 2007-07-21 drh: ** all terms of the WHERE clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void whereSplit(WhereClause *pWC, Expr *pExpr, int op){ dbda8d6ce9 2007-07-21 drh: if( pExpr==0 ) return; dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=op ){ dbda8d6ce9 2007-07-21 drh: whereClauseInsert(pWC, pExpr, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: whereSplit(pWC, pExpr->pLeft, op); dbda8d6ce9 2007-07-21 drh: whereSplit(pWC, pExpr->pRight, op); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Initialize an expression mask set dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define initMaskSet(P) memset(P, 0, sizeof(*P)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the bitmask for the given cursor number. Return 0 if dbda8d6ce9 2007-07-21 drh: ** iCursor is not in the set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pMaskSet->n; i++){ dbda8d6ce9 2007-07-21 drh: if( pMaskSet->ix[i]==iCursor ){ dbda8d6ce9 2007-07-21 drh: return ((Bitmask)1)<<i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new mask for cursor iCursor. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There is one cursor per table in the FROM clause. The number of dbda8d6ce9 2007-07-21 drh: ** tables in the FROM clause is limited by a test early in the dbda8d6ce9 2007-07-21 drh: ** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[] dbda8d6ce9 2007-07-21 drh: ** array will never overflow. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void createMask(ExprMaskSet *pMaskSet, int iCursor){ dbda8d6ce9 2007-07-21 drh: assert( pMaskSet->n < ArraySize(pMaskSet->ix) ); dbda8d6ce9 2007-07-21 drh: pMaskSet->ix[pMaskSet->n++] = iCursor; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine walks (recursively) an expression tree and generates dbda8d6ce9 2007-07-21 drh: ** a bitmask indicating which tables are used in that expression dbda8d6ce9 2007-07-21 drh: ** tree. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In order for this routine to work, the calling function must have dbda8d6ce9 2007-07-21 drh: ** previously invoked sqlite3ExprResolveNames() on the expression. See dbda8d6ce9 2007-07-21 drh: ** the header comment on that routine for additional information. dbda8d6ce9 2007-07-21 drh: ** The sqlite3ExprResolveNames() routines looks for column names and dbda8d6ce9 2007-07-21 drh: ** sets their opcodes to TK_COLUMN and their Expr.iTable fields to dbda8d6ce9 2007-07-21 drh: ** the VDBE cursor number of the table. This routine just has to dbda8d6ce9 2007-07-21 drh: ** translate the cursor numbers into bitmask values and OR all dbda8d6ce9 2007-07-21 drh: ** the bitmasks together. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static Bitmask exprListTableUsage(ExprMaskSet*, ExprList*); dbda8d6ce9 2007-07-21 drh: static Bitmask exprSelectTableUsage(ExprMaskSet*, Select*); dbda8d6ce9 2007-07-21 drh: static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){ dbda8d6ce9 2007-07-21 drh: Bitmask mask = 0; dbda8d6ce9 2007-07-21 drh: if( p==0 ) return 0; dbda8d6ce9 2007-07-21 drh: if( p->op==TK_COLUMN ){ dbda8d6ce9 2007-07-21 drh: mask = getMask(pMaskSet, p->iTable); dbda8d6ce9 2007-07-21 drh: return mask; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: mask = exprTableUsage(pMaskSet, p->pRight); dbda8d6ce9 2007-07-21 drh: mask |= exprTableUsage(pMaskSet, p->pLeft); dbda8d6ce9 2007-07-21 drh: mask |= exprListTableUsage(pMaskSet, p->pList); dbda8d6ce9 2007-07-21 drh: mask |= exprSelectTableUsage(pMaskSet, p->pSelect); dbda8d6ce9 2007-07-21 drh: return mask; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Bitmask mask = 0; dbda8d6ce9 2007-07-21 drh: if( pList ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pList->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: mask |= exprTableUsage(pMaskSet, pList->a[i].pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return mask; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static Bitmask exprSelectTableUsage(ExprMaskSet *pMaskSet, Select *pS){ c287665ba8 2007-09-14 drh: Bitmask mask = 0; c287665ba8 2007-09-14 drh: while( pS ){ c287665ba8 2007-09-14 drh: mask |= exprListTableUsage(pMaskSet, pS->pEList); dbda8d6ce9 2007-07-21 drh: mask |= exprListTableUsage(pMaskSet, pS->pGroupBy); dbda8d6ce9 2007-07-21 drh: mask |= exprListTableUsage(pMaskSet, pS->pOrderBy); dbda8d6ce9 2007-07-21 drh: mask |= exprTableUsage(pMaskSet, pS->pWhere); dbda8d6ce9 2007-07-21 drh: mask |= exprTableUsage(pMaskSet, pS->pHaving); c287665ba8 2007-09-14 drh: pS = pS->pPrior; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return mask; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the given operator is one of the operators that is dbda8d6ce9 2007-07-21 drh: ** allowed for an indexable WHERE clause term. The allowed operators are dbda8d6ce9 2007-07-21 drh: ** "=", "<", ">", "<=", ">=", and "IN". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int allowedOp(int op){ dbda8d6ce9 2007-07-21 drh: assert( TK_GT>TK_EQ && TK_GT<TK_GE ); dbda8d6ce9 2007-07-21 drh: assert( TK_LT>TK_EQ && TK_LT<TK_GE ); dbda8d6ce9 2007-07-21 drh: assert( TK_LE>TK_EQ && TK_LE<TK_GE ); dbda8d6ce9 2007-07-21 drh: assert( TK_GE==TK_EQ+4 ); dbda8d6ce9 2007-07-21 drh: return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Swap two objects of type T. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Commute a comparision operator. Expressions of the form "X op Y" dbda8d6ce9 2007-07-21 drh: ** are converted into "Y op X". c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If a collation sequence is associated with either the left or right c287665ba8 2007-09-14 drh: ** side of the comparison, it remains associated with the same side after c287665ba8 2007-09-14 drh: ** the commutation. So "Y collate NOCASE op X" becomes c287665ba8 2007-09-14 drh: ** "X collate NOCASE op Y". This is because any collation sequence on c287665ba8 2007-09-14 drh: ** the left hand side of a comparison overrides any collation sequence c287665ba8 2007-09-14 drh: ** attached to the right. For the same reason the EP_ExpCollate flag c287665ba8 2007-09-14 drh: ** is not commuted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void exprCommute(Expr *pExpr){ c287665ba8 2007-09-14 drh: u16 expRight = (pExpr->pRight->flags & EP_ExpCollate); c287665ba8 2007-09-14 drh: u16 expLeft = (pExpr->pLeft->flags & EP_ExpCollate); dbda8d6ce9 2007-07-21 drh: assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); dbda8d6ce9 2007-07-21 drh: SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl); c287665ba8 2007-09-14 drh: pExpr->pRight->flags = (pExpr->pRight->flags & ~EP_ExpCollate) | expLeft; c287665ba8 2007-09-14 drh: pExpr->pLeft->flags = (pExpr->pLeft->flags & ~EP_ExpCollate) | expRight; dbda8d6ce9 2007-07-21 drh: SWAP(Expr*,pExpr->pRight,pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: if( pExpr->op>=TK_GT ){ dbda8d6ce9 2007-07-21 drh: assert( TK_LT==TK_GT+2 ); dbda8d6ce9 2007-07-21 drh: assert( TK_GE==TK_LE+2 ); dbda8d6ce9 2007-07-21 drh: assert( TK_GT>TK_EQ ); dbda8d6ce9 2007-07-21 drh: assert( TK_GT<TK_LE ); dbda8d6ce9 2007-07-21 drh: assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE ); dbda8d6ce9 2007-07-21 drh: pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Translate from TK_xx operator to WO_xx bitmask. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int operatorMask(int op){ dbda8d6ce9 2007-07-21 drh: int c; dbda8d6ce9 2007-07-21 drh: assert( allowedOp(op) ); dbda8d6ce9 2007-07-21 drh: if( op==TK_IN ){ dbda8d6ce9 2007-07-21 drh: c = WO_IN; dbda8d6ce9 2007-07-21 drh: }else if( op==TK_ISNULL ){ dbda8d6ce9 2007-07-21 drh: c = WO_ISNULL; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: c = WO_EQ<<(op-TK_EQ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( op!=TK_ISNULL || c==WO_ISNULL ); dbda8d6ce9 2007-07-21 drh: assert( op!=TK_IN || c==WO_IN ); dbda8d6ce9 2007-07-21 drh: assert( op!=TK_EQ || c==WO_EQ ); dbda8d6ce9 2007-07-21 drh: assert( op!=TK_LT || c==WO_LT ); dbda8d6ce9 2007-07-21 drh: assert( op!=TK_LE || c==WO_LE ); dbda8d6ce9 2007-07-21 drh: assert( op!=TK_GT || c==WO_GT ); dbda8d6ce9 2007-07-21 drh: assert( op!=TK_GE || c==WO_GE ); dbda8d6ce9 2007-07-21 drh: return c; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Search for a term in the WHERE clause that is of the form "X <op> <expr>" dbda8d6ce9 2007-07-21 drh: ** where X is a reference to the iColumn of table iCur and <op> is one of dbda8d6ce9 2007-07-21 drh: ** the WO_xx operator codes specified by the op parameter. dbda8d6ce9 2007-07-21 drh: ** Return a pointer to the term. Return 0 if not found. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static WhereTerm *findTerm( dbda8d6ce9 2007-07-21 drh: WhereClause *pWC, /* The WHERE clause to be searched */ dbda8d6ce9 2007-07-21 drh: int iCur, /* Cursor number of LHS */ dbda8d6ce9 2007-07-21 drh: int iColumn, /* Column number of LHS */ dbda8d6ce9 2007-07-21 drh: Bitmask notReady, /* RHS must not overlap with this mask */ dbda8d6ce9 2007-07-21 drh: u16 op, /* Mask of WO_xx values describing operator */ dbda8d6ce9 2007-07-21 drh: Index *pIdx /* Must be compatible with this index, if not NULL */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm; dbda8d6ce9 2007-07-21 drh: int k; dbda8d6ce9 2007-07-21 drh: for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ dbda8d6ce9 2007-07-21 drh: if( pTerm->leftCursor==iCur dbda8d6ce9 2007-07-21 drh: && (pTerm->prereqRight & notReady)==0 dbda8d6ce9 2007-07-21 drh: && pTerm->leftColumn==iColumn dbda8d6ce9 2007-07-21 drh: && (pTerm->eOperator & op)!=0 dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( iCur>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){ dbda8d6ce9 2007-07-21 drh: Expr *pX = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: char idxaff; dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: Parse *pParse = pWC->pParse; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: idxaff = pIdx->pTable->aCol[iColumn].affinity; dbda8d6ce9 2007-07-21 drh: if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out the collation sequence required from an index for dbda8d6ce9 2007-07-21 drh: ** it to be useful for optimising expression pX. Store this dbda8d6ce9 2007-07-21 drh: ** value in variable pColl. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert(pX->pLeft); dbda8d6ce9 2007-07-21 drh: pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); dbda8d6ce9 2007-07-21 drh: if( !pColl ){ dbda8d6ce9 2007-07-21 drh: pColl = pParse->db->pDfltColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(j=0; j<pIdx->nColumn && pIdx->aiColumn[j]!=iColumn; j++){} dbda8d6ce9 2007-07-21 drh: assert( j<pIdx->nColumn ); dbda8d6ce9 2007-07-21 drh: if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pTerm; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Forward reference */ dbda8d6ce9 2007-07-21 drh: static void exprAnalyze(SrcList*, WhereClause*, int); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Call exprAnalyze on all terms in a WHERE clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void exprAnalyzeAll( dbda8d6ce9 2007-07-21 drh: SrcList *pTabList, /* the FROM clause */ dbda8d6ce9 2007-07-21 drh: WhereClause *pWC /* the WHERE clause to be analyzed */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=pWC->nTerm-1; i>=0; i--){ dbda8d6ce9 2007-07-21 drh: exprAnalyze(pTabList, pWC, i); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if the given expression is a LIKE or GLOB operator that dbda8d6ce9 2007-07-21 drh: ** can be optimized using inequality constraints. Return TRUE if it is dbda8d6ce9 2007-07-21 drh: ** so and false if not. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In order for the operator to be optimizible, the RHS must be a string dbda8d6ce9 2007-07-21 drh: ** literal that does not begin with a wildcard. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int isLikeOrGlob( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* The database */ dbda8d6ce9 2007-07-21 drh: Expr *pExpr, /* Test this expression */ dbda8d6ce9 2007-07-21 drh: int *pnPattern, /* Number of non-wildcard prefix characters */ dbda8d6ce9 2007-07-21 drh: int *pisComplete /* True if the only wildcard is % in the last character */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: const char *z; dbda8d6ce9 2007-07-21 drh: Expr *pRight, *pLeft; dbda8d6ce9 2007-07-21 drh: ExprList *pList; dbda8d6ce9 2007-07-21 drh: int c, cnt; dbda8d6ce9 2007-07-21 drh: int noCase; dbda8d6ce9 2007-07-21 drh: char wc[3]; dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !sqlite3IsLikeFunction(db, pExpr, &noCase, wc) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pList = pExpr->pList; dbda8d6ce9 2007-07-21 drh: pRight = pList->a[0].pExpr; dbda8d6ce9 2007-07-21 drh: if( pRight->op!=TK_STRING ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pLeft = pList->a[1].pExpr; dbda8d6ce9 2007-07-21 drh: if( pLeft->op!=TK_COLUMN ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pColl = pLeft->pColl; dbda8d6ce9 2007-07-21 drh: if( pColl==0 ){ dbda8d6ce9 2007-07-21 drh: /* TODO: Coverage testing doesn't get this case. Is it actually possible dbda8d6ce9 2007-07-21 drh: ** for an expression of type TK_COLUMN to not have an assigned collation dbda8d6ce9 2007-07-21 drh: ** sequence at this point? dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pColl = db->pDfltColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (pColl->type!=SQLITE_COLL_BINARY || noCase) && dbda8d6ce9 2007-07-21 drh: (pColl->type!=SQLITE_COLL_NOCASE || !noCase) ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3DequoteExpr(db, pRight); dbda8d6ce9 2007-07-21 drh: z = (char *)pRight->token.z; dbda8d6ce9 2007-07-21 drh: for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){} dbda8d6ce9 2007-07-21 drh: if( cnt==0 || 255==(u8)z[cnt] ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pisComplete = z[cnt]==wc[0] && z[cnt+1]==0; dbda8d6ce9 2007-07-21 drh: *pnPattern = cnt; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if the given expression is of the form dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** column MATCH expr dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If it is then return TRUE. If not, return FALSE. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int isMatchOfColumn( dbda8d6ce9 2007-07-21 drh: Expr *pExpr /* Test this expression */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: ExprList *pList; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_FUNCTION ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pExpr->token.n!=5 || dbda8d6ce9 2007-07-21 drh: sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pList = pExpr->pList; dbda8d6ce9 2007-07-21 drh: if( pList->nExpr!=2 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pList->a[1].pExpr->op != TK_COLUMN ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the pBase expression originated in the ON or USING clause of dbda8d6ce9 2007-07-21 drh: ** a join, then transfer the appropriate markings over to derived. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ dbda8d6ce9 2007-07-21 drh: pDerived->flags |= pBase->flags & EP_FromJoin; dbda8d6ce9 2007-07-21 drh: pDerived->iRightJoinTable = pBase->iRightJoinTable; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the given term of an OR clause can be converted dbda8d6ce9 2007-07-21 drh: ** into an IN clause. The iCursor and iColumn define the left-hand dbda8d6ce9 2007-07-21 drh: ** side of the IN clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The context is that we have multiple OR-connected equality terms dbda8d6ce9 2007-07-21 drh: ** like this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** a=<expr1> OR a=<expr2> OR b=<expr3> OR ... dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pOrTerm input to this routine corresponds to a single term of dbda8d6ce9 2007-07-21 drh: ** this OR clause. In order for the term to be a condidate for dbda8d6ce9 2007-07-21 drh: ** conversion to an IN operator, the following must be true: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * The left-hand side of the term must be the column which dbda8d6ce9 2007-07-21 drh: ** is identified by iCursor and iColumn. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * If the right-hand side is also a column, then the affinities dbda8d6ce9 2007-07-21 drh: ** of both right and left sides must be such that no type dbda8d6ce9 2007-07-21 drh: ** conversions are required on the right. (Ticket #2249) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If both of these conditions are true, then return true. Otherwise dbda8d6ce9 2007-07-21 drh: ** return false. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int orTermIsOptCandidate(WhereTerm *pOrTerm, int iCursor, int iColumn){ dbda8d6ce9 2007-07-21 drh: int affLeft, affRight; dbda8d6ce9 2007-07-21 drh: assert( pOrTerm->eOperator==WO_EQ ); dbda8d6ce9 2007-07-21 drh: if( pOrTerm->leftCursor!=iCursor ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pOrTerm->leftColumn!=iColumn ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight); dbda8d6ce9 2007-07-21 drh: if( affRight==0 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: if( affRight!=affLeft ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return true if the given term of an OR clause can be ignored during dbda8d6ce9 2007-07-21 drh: ** a check to make sure all OR terms are candidates for optimization. dbda8d6ce9 2007-07-21 drh: ** In other words, return true if a call to the orTermIsOptCandidate() dbda8d6ce9 2007-07-21 drh: ** above returned false but it is not necessary to disqualify the dbda8d6ce9 2007-07-21 drh: ** optimization. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Suppose the original OR phrase was this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** a=4 OR a=11 OR a=b dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** During analysis, the third term gets flipped around and duplicate dbda8d6ce9 2007-07-21 drh: ** so that we are left with this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** a=4 OR a=11 OR a=b OR b=a dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Since the last two terms are duplicates, only one of them dbda8d6ce9 2007-07-21 drh: ** has to qualify in order for the whole phrase to qualify. When dbda8d6ce9 2007-07-21 drh: ** this routine is called, we know that pOrTerm did not qualify. dbda8d6ce9 2007-07-21 drh: ** This routine merely checks to see if pOrTerm has a duplicate that dbda8d6ce9 2007-07-21 drh: ** might qualify. If there is a duplicate that has not yet been dbda8d6ce9 2007-07-21 drh: ** disqualified, then return true. If there are no duplicates, or dbda8d6ce9 2007-07-21 drh: ** the duplicate has also been disqualifed, return false. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int orTermHasOkDuplicate(WhereClause *pOr, WhereTerm *pOrTerm){ dbda8d6ce9 2007-07-21 drh: if( pOrTerm->flags & TERM_COPIED ){ dbda8d6ce9 2007-07-21 drh: /* This is the original term. The duplicate is to the left had dbda8d6ce9 2007-07-21 drh: ** has not yet been analyzed and thus has not yet been disqualified. */ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (pOrTerm->flags & TERM_VIRTUAL)!=0 dbda8d6ce9 2007-07-21 drh: && (pOr->a[pOrTerm->iParent].flags & TERM_OR_OK)!=0 ){ dbda8d6ce9 2007-07-21 drh: /* This is a duplicate term. The original qualified so this one dbda8d6ce9 2007-07-21 drh: ** does not have to. */ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* This is either a singleton term or else it is a duplicate for dbda8d6ce9 2007-07-21 drh: ** which the original did not qualify. Either way we are done for. */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The input to this routine is an WhereTerm structure with only the dbda8d6ce9 2007-07-21 drh: ** "pExpr" field filled in. The job of this routine is to analyze the dbda8d6ce9 2007-07-21 drh: ** subexpression and populate all the other fields of the WhereTerm dbda8d6ce9 2007-07-21 drh: ** structure. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the expression is of the form "<expr> <op> X" it gets commuted dbda8d6ce9 2007-07-21 drh: ** to the standard form of "X <op> <expr>". If the expression is of dbda8d6ce9 2007-07-21 drh: ** the form "X <op> Y" where both X and Y are columns, then the original dbda8d6ce9 2007-07-21 drh: ** expression is unchanged and a new virtual expression of the form dbda8d6ce9 2007-07-21 drh: ** "Y <op> X" is added to the WHERE clause and analyzed separately. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void exprAnalyze( dbda8d6ce9 2007-07-21 drh: SrcList *pSrc, /* the FROM clause */ dbda8d6ce9 2007-07-21 drh: WhereClause *pWC, /* the WHERE clause */ dbda8d6ce9 2007-07-21 drh: int idxTerm /* Index of the term to be analyzed */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm = &pWC->a[idxTerm]; dbda8d6ce9 2007-07-21 drh: ExprMaskSet *pMaskSet = pWC->pMaskSet; dbda8d6ce9 2007-07-21 drh: Expr *pExpr = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: Bitmask prereqLeft; dbda8d6ce9 2007-07-21 drh: Bitmask prereqAll; dbda8d6ce9 2007-07-21 drh: int nPattern; dbda8d6ce9 2007-07-21 drh: int isComplete; dbda8d6ce9 2007-07-21 drh: int op; c287665ba8 2007-09-14 drh: Parse *pParse = pWC->pParse; c287665ba8 2007-09-14 drh: sqlite3 *db = pParse->db; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: if( db->mallocFailed ) return; dbda8d6ce9 2007-07-21 drh: prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); dbda8d6ce9 2007-07-21 drh: op = pExpr->op; dbda8d6ce9 2007-07-21 drh: if( op==TK_IN ){ dbda8d6ce9 2007-07-21 drh: assert( pExpr->pRight==0 ); dbda8d6ce9 2007-07-21 drh: pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList) dbda8d6ce9 2007-07-21 drh: | exprSelectTableUsage(pMaskSet, pExpr->pSelect); dbda8d6ce9 2007-07-21 drh: }else if( op==TK_ISNULL ){ dbda8d6ce9 2007-07-21 drh: pTerm->prereqRight = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: prereqAll = exprTableUsage(pMaskSet, pExpr); dbda8d6ce9 2007-07-21 drh: if( ExprHasProperty(pExpr, EP_FromJoin) ){ dbda8d6ce9 2007-07-21 drh: prereqAll |= getMask(pMaskSet, pExpr->iRightJoinTable); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTerm->prereqAll = prereqAll; dbda8d6ce9 2007-07-21 drh: pTerm->leftCursor = -1; dbda8d6ce9 2007-07-21 drh: pTerm->iParent = -1; dbda8d6ce9 2007-07-21 drh: pTerm->eOperator = 0; dbda8d6ce9 2007-07-21 drh: if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){ dbda8d6ce9 2007-07-21 drh: Expr *pLeft = pExpr->pLeft; dbda8d6ce9 2007-07-21 drh: Expr *pRight = pExpr->pRight; dbda8d6ce9 2007-07-21 drh: if( pLeft->op==TK_COLUMN ){ dbda8d6ce9 2007-07-21 drh: pTerm->leftCursor = pLeft->iTable; dbda8d6ce9 2007-07-21 drh: pTerm->leftColumn = pLeft->iColumn; dbda8d6ce9 2007-07-21 drh: pTerm->eOperator = operatorMask(op); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pRight && pRight->op==TK_COLUMN ){ dbda8d6ce9 2007-07-21 drh: WhereTerm *pNew; dbda8d6ce9 2007-07-21 drh: Expr *pDup; dbda8d6ce9 2007-07-21 drh: if( pTerm->leftCursor>=0 ){ dbda8d6ce9 2007-07-21 drh: int idxNew; c287665ba8 2007-09-14 drh: pDup = sqlite3ExprDup(db, pExpr); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprDelete(pDup); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); dbda8d6ce9 2007-07-21 drh: if( idxNew==0 ) return; dbda8d6ce9 2007-07-21 drh: pNew = &pWC->a[idxNew]; dbda8d6ce9 2007-07-21 drh: pNew->iParent = idxTerm; dbda8d6ce9 2007-07-21 drh: pTerm = &pWC->a[idxTerm]; dbda8d6ce9 2007-07-21 drh: pTerm->nChild = 1; dbda8d6ce9 2007-07-21 drh: pTerm->flags |= TERM_COPIED; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pDup = pExpr; dbda8d6ce9 2007-07-21 drh: pNew = pTerm; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: exprCommute(pDup); dbda8d6ce9 2007-07-21 drh: pLeft = pDup->pLeft; dbda8d6ce9 2007-07-21 drh: pNew->leftCursor = pLeft->iTable; dbda8d6ce9 2007-07-21 drh: pNew->leftColumn = pLeft->iColumn; dbda8d6ce9 2007-07-21 drh: pNew->prereqRight = prereqLeft; dbda8d6ce9 2007-07-21 drh: pNew->prereqAll = prereqAll; dbda8d6ce9 2007-07-21 drh: pNew->eOperator = operatorMask(pDup->op); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION dbda8d6ce9 2007-07-21 drh: /* If a term is the BETWEEN operator, create two new virtual terms dbda8d6ce9 2007-07-21 drh: ** that define the range that the BETWEEN implements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: else if( pExpr->op==TK_BETWEEN ){ dbda8d6ce9 2007-07-21 drh: ExprList *pList = pExpr->pList; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: static const u8 ops[] = {TK_GE, TK_LE}; dbda8d6ce9 2007-07-21 drh: assert( pList!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pList->nExpr==2 ); dbda8d6ce9 2007-07-21 drh: for(i=0; i<2; i++){ dbda8d6ce9 2007-07-21 drh: Expr *pNewExpr; dbda8d6ce9 2007-07-21 drh: int idxNew; c287665ba8 2007-09-14 drh: pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft), c287665ba8 2007-09-14 drh: sqlite3ExprDup(db, pList->a[i].pExpr), 0); dbda8d6ce9 2007-07-21 drh: idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); dbda8d6ce9 2007-07-21 drh: exprAnalyze(pSrc, pWC, idxNew); dbda8d6ce9 2007-07-21 drh: pTerm = &pWC->a[idxTerm]; dbda8d6ce9 2007-07-21 drh: pWC->a[idxNew].iParent = idxTerm; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pTerm->nChild = 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) dbda8d6ce9 2007-07-21 drh: /* Attempt to convert OR-connected terms into an IN operator so that dbda8d6ce9 2007-07-21 drh: ** they can make use of indices. Example: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** x = expr1 OR expr2 = x OR x = expr3 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** is converted into dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** x IN (expr1,expr2,expr3) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This optimization must be omitted if OMIT_SUBQUERY is defined because dbda8d6ce9 2007-07-21 drh: ** the compiler for the the IN operator is part of sub-queries. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: else if( pExpr->op==TK_OR ){ dbda8d6ce9 2007-07-21 drh: int ok; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: int iColumn, iCursor; dbda8d6ce9 2007-07-21 drh: WhereClause sOr; dbda8d6ce9 2007-07-21 drh: WhereTerm *pOrTerm; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( (pTerm->flags & TERM_DYNAMIC)==0 ); dbda8d6ce9 2007-07-21 drh: whereClauseInit(&sOr, pWC->pParse, pMaskSet); dbda8d6ce9 2007-07-21 drh: whereSplit(&sOr, pExpr, TK_OR); dbda8d6ce9 2007-07-21 drh: exprAnalyzeAll(pSrc, &sOr); dbda8d6ce9 2007-07-21 drh: assert( sOr.nTerm>=2 ); dbda8d6ce9 2007-07-21 drh: j = 0; dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: assert( j<sOr.nTerm ); dbda8d6ce9 2007-07-21 drh: iColumn = sOr.a[j].leftColumn; dbda8d6ce9 2007-07-21 drh: iCursor = sOr.a[j].leftCursor; dbda8d6ce9 2007-07-21 drh: ok = iCursor>=0; dbda8d6ce9 2007-07-21 drh: for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){ dbda8d6ce9 2007-07-21 drh: if( pOrTerm->eOperator!=WO_EQ ){ dbda8d6ce9 2007-07-21 drh: goto or_not_possible; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( orTermIsOptCandidate(pOrTerm, iCursor, iColumn) ){ dbda8d6ce9 2007-07-21 drh: pOrTerm->flags |= TERM_OR_OK; dbda8d6ce9 2007-07-21 drh: }else if( orTermHasOkDuplicate(&sOr, pOrTerm) ){ dbda8d6ce9 2007-07-21 drh: pOrTerm->flags &= ~TERM_OR_OK; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: ok = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<2 ); dbda8d6ce9 2007-07-21 drh: if( ok ){ dbda8d6ce9 2007-07-21 drh: ExprList *pList = 0; dbda8d6ce9 2007-07-21 drh: Expr *pNew, *pDup; dbda8d6ce9 2007-07-21 drh: Expr *pLeft = 0; dbda8d6ce9 2007-07-21 drh: for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){ dbda8d6ce9 2007-07-21 drh: if( (pOrTerm->flags & TERM_OR_OK)==0 ) continue; c287665ba8 2007-09-14 drh: pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight); c287665ba8 2007-09-14 drh: pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0); dbda8d6ce9 2007-07-21 drh: pLeft = pOrTerm->pExpr->pLeft; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pLeft!=0 ); c287665ba8 2007-09-14 drh: pDup = sqlite3ExprDup(db, pLeft); c287665ba8 2007-09-14 drh: pNew = sqlite3Expr(db, TK_IN, pDup, 0, 0); dbda8d6ce9 2007-07-21 drh: if( pNew ){ dbda8d6ce9 2007-07-21 drh: int idxNew; dbda8d6ce9 2007-07-21 drh: transferJoinMarkings(pNew, pExpr); dbda8d6ce9 2007-07-21 drh: pNew->pList = pList; dbda8d6ce9 2007-07-21 drh: idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); dbda8d6ce9 2007-07-21 drh: exprAnalyze(pSrc, pWC, idxNew); dbda8d6ce9 2007-07-21 drh: pTerm = &pWC->a[idxTerm]; dbda8d6ce9 2007-07-21 drh: pWC->a[idxNew].iParent = idxTerm; dbda8d6ce9 2007-07-21 drh: pTerm->nChild = 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pList); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: or_not_possible: dbda8d6ce9 2007-07-21 drh: whereClauseClear(&sOr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION dbda8d6ce9 2007-07-21 drh: /* Add constraints to reduce the search space on a LIKE or GLOB dbda8d6ce9 2007-07-21 drh: ** operator. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: if( isLikeOrGlob(db, pExpr, &nPattern, &isComplete) ){ dbda8d6ce9 2007-07-21 drh: Expr *pLeft, *pRight; dbda8d6ce9 2007-07-21 drh: Expr *pStr1, *pStr2; dbda8d6ce9 2007-07-21 drh: Expr *pNewExpr1, *pNewExpr2; dbda8d6ce9 2007-07-21 drh: int idxNew1, idxNew2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pLeft = pExpr->pList->a[1].pExpr; dbda8d6ce9 2007-07-21 drh: pRight = pExpr->pList->a[0].pExpr; c287665ba8 2007-09-14 drh: pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: if( pStr1 ){ c287665ba8 2007-09-14 drh: sqlite3TokenCopy(db, &pStr1->token, &pRight->token); dbda8d6ce9 2007-07-21 drh: pStr1->token.n = nPattern; dbda8d6ce9 2007-07-21 drh: pStr1->flags = EP_Dequoted; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pStr2 = sqlite3ExprDup(db, pStr1); dbda8d6ce9 2007-07-21 drh: if( pStr2 ){ dbda8d6ce9 2007-07-21 drh: assert( pStr2->token.dyn ); dbda8d6ce9 2007-07-21 drh: ++*(u8*)&pStr2->token.z[nPattern-1]; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft), pStr1, 0); dbda8d6ce9 2007-07-21 drh: idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC); dbda8d6ce9 2007-07-21 drh: exprAnalyze(pSrc, pWC, idxNew1); c287665ba8 2007-09-14 drh: pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft), pStr2, 0); dbda8d6ce9 2007-07-21 drh: idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); dbda8d6ce9 2007-07-21 drh: exprAnalyze(pSrc, pWC, idxNew2); dbda8d6ce9 2007-07-21 drh: pTerm = &pWC->a[idxTerm]; dbda8d6ce9 2007-07-21 drh: if( isComplete ){ dbda8d6ce9 2007-07-21 drh: pWC->a[idxNew1].iParent = idxTerm; dbda8d6ce9 2007-07-21 drh: pWC->a[idxNew2].iParent = idxTerm; dbda8d6ce9 2007-07-21 drh: pTerm->nChild = 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* Add a WO_MATCH auxiliary term to the constraint set if the dbda8d6ce9 2007-07-21 drh: ** current expression is of the form: column MATCH expr. dbda8d6ce9 2007-07-21 drh: ** This information is used by the xBestIndex methods of dbda8d6ce9 2007-07-21 drh: ** virtual tables. The native query optimizer does not attempt dbda8d6ce9 2007-07-21 drh: ** to do anything with MATCH functions. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( isMatchOfColumn(pExpr) ){ dbda8d6ce9 2007-07-21 drh: int idxNew; dbda8d6ce9 2007-07-21 drh: Expr *pRight, *pLeft; dbda8d6ce9 2007-07-21 drh: WhereTerm *pNewTerm; dbda8d6ce9 2007-07-21 drh: Bitmask prereqColumn, prereqExpr; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pRight = pExpr->pList->a[0].pExpr; dbda8d6ce9 2007-07-21 drh: pLeft = pExpr->pList->a[1].pExpr; dbda8d6ce9 2007-07-21 drh: prereqExpr = exprTableUsage(pMaskSet, pRight); dbda8d6ce9 2007-07-21 drh: prereqColumn = exprTableUsage(pMaskSet, pLeft); dbda8d6ce9 2007-07-21 drh: if( (prereqExpr & prereqColumn)==0 ){ dbda8d6ce9 2007-07-21 drh: Expr *pNewExpr; c287665ba8 2007-09-14 drh: pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0); dbda8d6ce9 2007-07-21 drh: idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); dbda8d6ce9 2007-07-21 drh: pNewTerm = &pWC->a[idxNew]; dbda8d6ce9 2007-07-21 drh: pNewTerm->prereqRight = prereqExpr; dbda8d6ce9 2007-07-21 drh: pNewTerm->leftCursor = pLeft->iTable; dbda8d6ce9 2007-07-21 drh: pNewTerm->leftColumn = pLeft->iColumn; dbda8d6ce9 2007-07-21 drh: pNewTerm->eOperator = WO_MATCH; dbda8d6ce9 2007-07-21 drh: pNewTerm->iParent = idxTerm; dbda8d6ce9 2007-07-21 drh: pTerm = &pWC->a[idxTerm]; dbda8d6ce9 2007-07-21 drh: pTerm->nChild = 1; dbda8d6ce9 2007-07-21 drh: pTerm->flags |= TERM_COPIED; dbda8d6ce9 2007-07-21 drh: pNewTerm->prereqAll = pTerm->prereqAll; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return TRUE if any of the expressions in pList->a[iFirst...] contain dbda8d6ce9 2007-07-21 drh: ** a reference to any table other than the iBase table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int referencesOtherTables( dbda8d6ce9 2007-07-21 drh: ExprList *pList, /* Search expressions in ths list */ dbda8d6ce9 2007-07-21 drh: ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */ dbda8d6ce9 2007-07-21 drh: int iFirst, /* Be searching with the iFirst-th expression */ dbda8d6ce9 2007-07-21 drh: int iBase /* Ignore references to this table */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Bitmask allowed = ~getMask(pMaskSet, iBase); dbda8d6ce9 2007-07-21 drh: while( iFirst<pList->nExpr ){ dbda8d6ce9 2007-07-21 drh: if( (exprTableUsage(pMaskSet, pList->a[iFirst++].pExpr)&allowed)!=0 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine decides if pIdx can be used to satisfy the ORDER BY dbda8d6ce9 2007-07-21 drh: ** clause. If it can, it returns 1. If pIdx cannot satisfy the dbda8d6ce9 2007-07-21 drh: ** ORDER BY clause, this routine returns 0. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pOrderBy is an ORDER BY clause from a SELECT statement. pTab is the dbda8d6ce9 2007-07-21 drh: ** left-most table in the FROM clause of that same SELECT statement and dbda8d6ce9 2007-07-21 drh: ** the table has a cursor number of "base". pIdx is an index on pTab. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** nEqCol is the number of columns of pIdx that are used as equality dbda8d6ce9 2007-07-21 drh: ** constraints. Any of these columns may be missing from the ORDER BY dbda8d6ce9 2007-07-21 drh: ** clause and the match can still be a success. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** All terms of the ORDER BY that match against the index must be either dbda8d6ce9 2007-07-21 drh: ** ASC or DESC. (Terms of the ORDER BY clause past the end of a UNIQUE dbda8d6ce9 2007-07-21 drh: ** index do not need to satisfy this constraint.) The *pbRev value is dbda8d6ce9 2007-07-21 drh: ** set to 1 if the ORDER BY clause is all DESC and it is set to 0 if dbda8d6ce9 2007-07-21 drh: ** the ORDER BY clause is all ASC. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int isSortingIndex( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: ExprMaskSet *pMaskSet, /* Mapping from table indices to bitmaps */ dbda8d6ce9 2007-07-21 drh: Index *pIdx, /* The index we are testing */ dbda8d6ce9 2007-07-21 drh: int base, /* Cursor number for the table to be sorted */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* The ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: int nEqCol, /* Number of index columns with == constraints */ dbda8d6ce9 2007-07-21 drh: int *pbRev /* Set to 1 if ORDER BY is DESC */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i, j; /* Loop counters */ dbda8d6ce9 2007-07-21 drh: int sortOrder = 0; /* XOR of index and ORDER BY sort direction */ dbda8d6ce9 2007-07-21 drh: int nTerm; /* Number of ORDER BY terms */ dbda8d6ce9 2007-07-21 drh: struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pOrderBy!=0 ); dbda8d6ce9 2007-07-21 drh: nTerm = pOrderBy->nExpr; dbda8d6ce9 2007-07-21 drh: assert( nTerm>0 ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Match terms of the ORDER BY clause against columns of dbda8d6ce9 2007-07-21 drh: ** the index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that indices have pIdx->nColumn regular columns plus dbda8d6ce9 2007-07-21 drh: ** one additional column containing the rowid. The rowid column dbda8d6ce9 2007-07-21 drh: ** of the index is also allowed to match against the ORDER BY dbda8d6ce9 2007-07-21 drh: ** clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<=pIdx->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr; /* The expression of the ORDER BY pTerm */ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; /* The collating sequence of pExpr */ dbda8d6ce9 2007-07-21 drh: int termSortOrder; /* Sort order for this term */ dbda8d6ce9 2007-07-21 drh: int iColumn; /* The i-th column of the index. -1 for rowid */ dbda8d6ce9 2007-07-21 drh: int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */ dbda8d6ce9 2007-07-21 drh: const char *zColl; /* Name of the collating sequence for i-th index term */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pExpr = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){ dbda8d6ce9 2007-07-21 drh: /* Can not use an index sort on anything that is not a column in the dbda8d6ce9 2007-07-21 drh: ** left-most table of the FROM clause */ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pColl = sqlite3ExprCollSeq(pParse, pExpr); dbda8d6ce9 2007-07-21 drh: if( !pColl ){ dbda8d6ce9 2007-07-21 drh: pColl = db->pDfltColl; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i<pIdx->nColumn ){ dbda8d6ce9 2007-07-21 drh: iColumn = pIdx->aiColumn[i]; dbda8d6ce9 2007-07-21 drh: if( iColumn==pIdx->pTable->iPKey ){ dbda8d6ce9 2007-07-21 drh: iColumn = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: iSortOrder = pIdx->aSortOrder[i]; dbda8d6ce9 2007-07-21 drh: zColl = pIdx->azColl[i]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: iColumn = -1; dbda8d6ce9 2007-07-21 drh: iSortOrder = 0; dbda8d6ce9 2007-07-21 drh: zColl = pColl->zName; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){ dbda8d6ce9 2007-07-21 drh: /* Term j of the ORDER BY clause does not match column i of the index */ dbda8d6ce9 2007-07-21 drh: if( i<nEqCol ){ dbda8d6ce9 2007-07-21 drh: /* If an index column that is constrained by == fails to match an dbda8d6ce9 2007-07-21 drh: ** ORDER BY term, that is OK. Just ignore that column of the index dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* If an index column fails to match and is not constrained by == dbda8d6ce9 2007-07-21 drh: ** then the index cannot satisfy the ORDER BY constraint. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pIdx->aSortOrder!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 ); dbda8d6ce9 2007-07-21 drh: assert( iSortOrder==0 || iSortOrder==1 ); dbda8d6ce9 2007-07-21 drh: termSortOrder = iSortOrder ^ pTerm->sortOrder; dbda8d6ce9 2007-07-21 drh: if( i>nEqCol ){ dbda8d6ce9 2007-07-21 drh: if( termSortOrder!=sortOrder ){ dbda8d6ce9 2007-07-21 drh: /* Indices can only be used if all ORDER BY terms past the dbda8d6ce9 2007-07-21 drh: ** equality constraints are all either DESC or ASC. */ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sortOrder = termSortOrder; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: j++; dbda8d6ce9 2007-07-21 drh: pTerm++; dbda8d6ce9 2007-07-21 drh: if( iColumn<0 && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){ dbda8d6ce9 2007-07-21 drh: /* If the indexed column is the primary key and everything matches dbda8d6ce9 2007-07-21 drh: ** so far and none of the ORDER BY terms to the right reference other dbda8d6ce9 2007-07-21 drh: ** tables in the join, then we are assured that the index can be used dbda8d6ce9 2007-07-21 drh: ** to sort because the primary key is unique and so none of the other dbda8d6ce9 2007-07-21 drh: ** columns will make any difference dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: j = nTerm; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: *pbRev = sortOrder!=0; dbda8d6ce9 2007-07-21 drh: if( j>=nTerm ){ dbda8d6ce9 2007-07-21 drh: /* All terms of the ORDER BY clause are covered by this index so dbda8d6ce9 2007-07-21 drh: ** this index can be used for sorting. */ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pIdx->onError!=OE_None && i==pIdx->nColumn dbda8d6ce9 2007-07-21 drh: && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){ dbda8d6ce9 2007-07-21 drh: /* All terms of this index match some prefix of the ORDER BY clause dbda8d6ce9 2007-07-21 drh: ** and the index is UNIQUE and no terms on the tail of the ORDER BY dbda8d6ce9 2007-07-21 drh: ** clause reference other tables in a join. If this is all true then dbda8d6ce9 2007-07-21 drh: ** the order by clause is superfluous. */ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check table to see if the ORDER BY clause in pOrderBy can be satisfied dbda8d6ce9 2007-07-21 drh: ** by sorting in order of ROWID. Return true if so and set *pbRev to be dbda8d6ce9 2007-07-21 drh: ** true for reverse ROWID and false for forward ROWID order. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int sortableByRowid( dbda8d6ce9 2007-07-21 drh: int base, /* Cursor number for table to be sorted */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* The ORDER BY clause */ dbda8d6ce9 2007-07-21 drh: ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */ dbda8d6ce9 2007-07-21 drh: int *pbRev /* Set to 1 if ORDER BY is DESC */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Expr *p; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pOrderBy!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pOrderBy->nExpr>0 ); dbda8d6ce9 2007-07-21 drh: p = pOrderBy->a[0].pExpr; dbda8d6ce9 2007-07-21 drh: if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1 dbda8d6ce9 2007-07-21 drh: && !referencesOtherTables(pOrderBy, pMaskSet, 1, base) ){ dbda8d6ce9 2007-07-21 drh: *pbRev = pOrderBy->a[0].sortOrder; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Prepare a crude estimate of the logarithm of the input value. dbda8d6ce9 2007-07-21 drh: ** The results need not be exact. This is only used for estimating dbda8d6ce9 2007-07-21 drh: ** the total cost of performing operatings with O(logN) or O(NlogN) dbda8d6ce9 2007-07-21 drh: ** complexity. Because N is just a guess, it is no great tragedy if dbda8d6ce9 2007-07-21 drh: ** logN is a little off. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static double estLog(double N){ dbda8d6ce9 2007-07-21 drh: double logN = 1; dbda8d6ce9 2007-07-21 drh: double x = 10; dbda8d6ce9 2007-07-21 drh: while( N>x ){ dbda8d6ce9 2007-07-21 drh: logN += 1; dbda8d6ce9 2007-07-21 drh: x *= 10; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return logN; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Two routines for printing the content of an sqlite3_index_info dbda8d6ce9 2007-07-21 drh: ** structure. Used for testing and debugging only. If neither dbda8d6ce9 2007-07-21 drh: ** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines dbda8d6ce9 2007-07-21 drh: ** are no-ops. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_DEBUG) dbda8d6ce9 2007-07-21 drh: static void TRACE_IDX_INPUTS(sqlite3_index_info *p){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( !sqlite3_where_trace ) return; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nConstraint; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n", dbda8d6ce9 2007-07-21 drh: i, dbda8d6ce9 2007-07-21 drh: p->aConstraint[i].iColumn, dbda8d6ce9 2007-07-21 drh: p->aConstraint[i].iTermOffset, dbda8d6ce9 2007-07-21 drh: p->aConstraint[i].op, dbda8d6ce9 2007-07-21 drh: p->aConstraint[i].usable); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nOrderBy; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n", dbda8d6ce9 2007-07-21 drh: i, dbda8d6ce9 2007-07-21 drh: p->aOrderBy[i].iColumn, dbda8d6ce9 2007-07-21 drh: p->aOrderBy[i].desc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: if( !sqlite3_where_trace ) return; dbda8d6ce9 2007-07-21 drh: for(i=0; i<p->nConstraint; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n", dbda8d6ce9 2007-07-21 drh: i, dbda8d6ce9 2007-07-21 drh: p->aConstraintUsage[i].argvIndex, dbda8d6ce9 2007-07-21 drh: p->aConstraintUsage[i].omit); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" idxNum=%d\n", p->idxNum); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" idxStr=%s\n", p->idxStr); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" orderByConsumed=%d\n", p->orderByConsumed); dbda8d6ce9 2007-07-21 drh: sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: #define TRACE_IDX_INPUTS(A) dbda8d6ce9 2007-07-21 drh: #define TRACE_IDX_OUTPUTS(A) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the best index for a virtual table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The best index is computed by the xBestIndex method of the virtual dbda8d6ce9 2007-07-21 drh: ** table module. This routine is really just a wrapper that sets up dbda8d6ce9 2007-07-21 drh: ** the sqlite3_index_info structure that is used to communicate with dbda8d6ce9 2007-07-21 drh: ** xBestIndex. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In a join, this routine might be called multiple times for the dbda8d6ce9 2007-07-21 drh: ** same virtual table. The sqlite3_index_info structure is created dbda8d6ce9 2007-07-21 drh: ** and initialized on the first invocation and reused on all subsequent dbda8d6ce9 2007-07-21 drh: ** invocations. The sqlite3_index_info structure is also used when dbda8d6ce9 2007-07-21 drh: ** code is generated to access the virtual table. The whereInfoDelete() dbda8d6ce9 2007-07-21 drh: ** routine takes care of freeing the sqlite3_index_info structure after dbda8d6ce9 2007-07-21 drh: ** everybody has finished with it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static double bestVirtualIndex( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: WhereClause *pWC, /* The WHERE clause */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pSrc, /* The FROM clause term to search */ dbda8d6ce9 2007-07-21 drh: Bitmask notReady, /* Mask of cursors that are not available */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* The order by clause */ dbda8d6ce9 2007-07-21 drh: int orderByUsable, /* True if we can potential sort */ dbda8d6ce9 2007-07-21 drh: sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Table *pTab = pSrc->pTab; dbda8d6ce9 2007-07-21 drh: sqlite3_index_info *pIdxInfo; dbda8d6ce9 2007-07-21 drh: struct sqlite3_index_constraint *pIdxCons; dbda8d6ce9 2007-07-21 drh: struct sqlite3_index_orderby *pIdxOrderBy; dbda8d6ce9 2007-07-21 drh: struct sqlite3_index_constraint_usage *pUsage; dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: int nOrderBy; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the sqlite3_index_info structure has not been previously dbda8d6ce9 2007-07-21 drh: ** allocated and initialized for this virtual table, then allocate dbda8d6ce9 2007-07-21 drh: ** and initialize it now dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pIdxInfo = *ppIdxInfo; dbda8d6ce9 2007-07-21 drh: if( pIdxInfo==0 ){ dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm; dbda8d6ce9 2007-07-21 drh: int nTerm; dbda8d6ce9 2007-07-21 drh: WHERETRACE(("Recomputing index info for %s...\n", pTab->zName)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Count the number of possible WHERE clause constraints referring dbda8d6ce9 2007-07-21 drh: ** to this virtual table */ dbda8d6ce9 2007-07-21 drh: for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ dbda8d6ce9 2007-07-21 drh: if( pTerm->leftCursor != pSrc->iCursor ) continue; dbda8d6ce9 2007-07-21 drh: if( pTerm->eOperator==WO_IN ) continue; dbda8d6ce9 2007-07-21 drh: nTerm++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the ORDER BY clause contains only columns in the current dbda8d6ce9 2007-07-21 drh: ** virtual table then allocate space for the aOrderBy part of dbda8d6ce9 2007-07-21 drh: ** the sqlite3_index_info structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nOrderBy = 0; dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pOrderBy->nExpr; i++){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr = pOrderBy->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( i==pOrderBy->nExpr ){ dbda8d6ce9 2007-07-21 drh: nOrderBy = pOrderBy->nExpr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate the sqlite3_index_info structure dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) dbda8d6ce9 2007-07-21 drh: + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm dbda8d6ce9 2007-07-21 drh: + sizeof(*pIdxOrderBy)*nOrderBy ); dbda8d6ce9 2007-07-21 drh: if( pIdxInfo==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "out of memory"); dbda8d6ce9 2007-07-21 drh: return 0.0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *ppIdxInfo = pIdxInfo; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Initialize the structure. The sqlite3_index_info structure contains dbda8d6ce9 2007-07-21 drh: ** many fields that are declared "const" to prevent xBestIndex from dbda8d6ce9 2007-07-21 drh: ** changing them. We have to do some funky casting in order to dbda8d6ce9 2007-07-21 drh: ** initialize those fields. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1]; dbda8d6ce9 2007-07-21 drh: pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm]; dbda8d6ce9 2007-07-21 drh: pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy]; dbda8d6ce9 2007-07-21 drh: *(int*)&pIdxInfo->nConstraint = nTerm; dbda8d6ce9 2007-07-21 drh: *(int*)&pIdxInfo->nOrderBy = nOrderBy; dbda8d6ce9 2007-07-21 drh: *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons; dbda8d6ce9 2007-07-21 drh: *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy; dbda8d6ce9 2007-07-21 drh: *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage = dbda8d6ce9 2007-07-21 drh: pUsage; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ dbda8d6ce9 2007-07-21 drh: if( pTerm->leftCursor != pSrc->iCursor ) continue; dbda8d6ce9 2007-07-21 drh: if( pTerm->eOperator==WO_IN ) continue; dbda8d6ce9 2007-07-21 drh: pIdxCons[j].iColumn = pTerm->leftColumn; dbda8d6ce9 2007-07-21 drh: pIdxCons[j].iTermOffset = i; dbda8d6ce9 2007-07-21 drh: pIdxCons[j].op = pTerm->eOperator; dbda8d6ce9 2007-07-21 drh: /* The direct assignment in the previous line is possible only because dbda8d6ce9 2007-07-21 drh: ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The dbda8d6ce9 2007-07-21 drh: ** following asserts verify this fact. */ dbda8d6ce9 2007-07-21 drh: assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); dbda8d6ce9 2007-07-21 drh: assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); dbda8d6ce9 2007-07-21 drh: assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); dbda8d6ce9 2007-07-21 drh: assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); dbda8d6ce9 2007-07-21 drh: assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); dbda8d6ce9 2007-07-21 drh: assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); dbda8d6ce9 2007-07-21 drh: assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); dbda8d6ce9 2007-07-21 drh: j++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=0; i<nOrderBy; i++){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr = pOrderBy->a[i].pExpr; dbda8d6ce9 2007-07-21 drh: pIdxOrderBy[i].iColumn = pExpr->iColumn; dbda8d6ce9 2007-07-21 drh: pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* At this point, the sqlite3_index_info structure that pIdxInfo points dbda8d6ce9 2007-07-21 drh: ** to will have been initialized, either during the current invocation or dbda8d6ce9 2007-07-21 drh: ** during some prior invocation. Now we just have to customize the dbda8d6ce9 2007-07-21 drh: ** details of pIdxInfo for the current invocation and pass it to dbda8d6ce9 2007-07-21 drh: ** xBestIndex. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The module name must be defined. Also, by this point there must dbda8d6ce9 2007-07-21 drh: ** be a pointer to an sqlite3_vtab structure. Otherwise dbda8d6ce9 2007-07-21 drh: ** sqlite3ViewGetColumnNames() would have picked up the error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pTab->azModuleArg && pTab->azModuleArg[0] ); dbda8d6ce9 2007-07-21 drh: assert( pTab->pVtab ); dbda8d6ce9 2007-07-21 drh: #if 0 dbda8d6ce9 2007-07-21 drh: if( pTab->pVtab==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "undefined module %s for table %s", dbda8d6ce9 2007-07-21 drh: pTab->azModuleArg[0], pTab->zName); dbda8d6ce9 2007-07-21 drh: return 0.0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the aConstraint[].usable fields and initialize all dbda8d6ce9 2007-07-21 drh: ** output variables to zero. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** aConstraint[].usable is true for constraints where the right-hand dbda8d6ce9 2007-07-21 drh: ** side contains only references to tables to the left of the current dbda8d6ce9 2007-07-21 drh: ** table. In other words, if the constraint is of the form: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** column = expr dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** and we are evaluating a join, then the constraint on column is dbda8d6ce9 2007-07-21 drh: ** only valid if all tables referenced in expr occur to the left dbda8d6ce9 2007-07-21 drh: ** of the table containing column. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The aConstraints[] array contains entries for all constraints dbda8d6ce9 2007-07-21 drh: ** on the current table. That way we only have to compute it once dbda8d6ce9 2007-07-21 drh: ** even though we might try to pick the best index multiple times. dbda8d6ce9 2007-07-21 drh: ** For each attempt at picking an index, the order of tables in the dbda8d6ce9 2007-07-21 drh: ** join might be different so we have to recompute the usable flag dbda8d6ce9 2007-07-21 drh: ** each time. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; dbda8d6ce9 2007-07-21 drh: pUsage = pIdxInfo->aConstraintUsage; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ dbda8d6ce9 2007-07-21 drh: j = pIdxCons->iTermOffset; dbda8d6ce9 2007-07-21 drh: pTerm = &pWC->a[j]; dbda8d6ce9 2007-07-21 drh: pIdxCons->usable = (pTerm->prereqRight & notReady)==0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); dbda8d6ce9 2007-07-21 drh: if( pIdxInfo->needToFreeIdxStr ){ dbda8d6ce9 2007-07-21 drh: sqlite3_free(pIdxInfo->idxStr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIdxInfo->idxStr = 0; dbda8d6ce9 2007-07-21 drh: pIdxInfo->idxNum = 0; dbda8d6ce9 2007-07-21 drh: pIdxInfo->needToFreeIdxStr = 0; dbda8d6ce9 2007-07-21 drh: pIdxInfo->orderByConsumed = 0; dbda8d6ce9 2007-07-21 drh: pIdxInfo->estimatedCost = SQLITE_BIG_DBL / 2.0; dbda8d6ce9 2007-07-21 drh: nOrderBy = pIdxInfo->nOrderBy; dbda8d6ce9 2007-07-21 drh: if( pIdxInfo->nOrderBy && !orderByUsable ){ dbda8d6ce9 2007-07-21 drh: *(int*)&pIdxInfo->nOrderBy = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOff(pParse->db); dbda8d6ce9 2007-07-21 drh: WHERETRACE(("xBestIndex for %s\n", pTab->zName)); dbda8d6ce9 2007-07-21 drh: TRACE_IDX_INPUTS(pIdxInfo); dbda8d6ce9 2007-07-21 drh: rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo); dbda8d6ce9 2007-07-21 drh: TRACE_IDX_OUTPUTS(pIdxInfo); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_NOMEM ){ c287665ba8 2007-09-14 drh: pParse->db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: }else { dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3SafetyOn(pParse->db); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: rc = sqlite3SafetyOn(pParse->db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *(int*)&pIdxInfo->nOrderBy = nOrderBy; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return pIdxInfo->estimatedCost; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the best index for accessing a particular table. Return a pointer dbda8d6ce9 2007-07-21 drh: ** to the index, flags that describe how the index should be used, the dbda8d6ce9 2007-07-21 drh: ** number of equality constraints, and the "cost" for this index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The lowest cost index wins. The cost is an estimate of the amount of dbda8d6ce9 2007-07-21 drh: ** CPU and disk I/O need to process the request using the selected index. dbda8d6ce9 2007-07-21 drh: ** Factors that influence cost include: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * The estimated number of rows that will be retrieved. (The dbda8d6ce9 2007-07-21 drh: ** fewer the better.) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Whether or not sorting must occur. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Whether or not there must be separate lookups in the dbda8d6ce9 2007-07-21 drh: ** index and in the main table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static double bestIndex( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: WhereClause *pWC, /* The WHERE clause */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pSrc, /* The FROM clause term to search */ dbda8d6ce9 2007-07-21 drh: Bitmask notReady, /* Mask of cursors that are not available */ dbda8d6ce9 2007-07-21 drh: ExprList *pOrderBy, /* The order by clause */ dbda8d6ce9 2007-07-21 drh: Index **ppIndex, /* Make *ppIndex point to the best index */ dbda8d6ce9 2007-07-21 drh: int *pFlags, /* Put flags describing this choice in *pFlags */ dbda8d6ce9 2007-07-21 drh: int *pnEq /* Put the number of == or IN constraints here */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm; dbda8d6ce9 2007-07-21 drh: Index *bestIdx = 0; /* Index that gives the lowest cost */ dbda8d6ce9 2007-07-21 drh: double lowestCost; /* The cost of using bestIdx */ dbda8d6ce9 2007-07-21 drh: int bestFlags = 0; /* Flags associated with bestIdx */ dbda8d6ce9 2007-07-21 drh: int bestNEq = 0; /* Best value for nEq */ dbda8d6ce9 2007-07-21 drh: int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ dbda8d6ce9 2007-07-21 drh: Index *pProbe; /* An index we are evaluating */ dbda8d6ce9 2007-07-21 drh: int rev; /* True to scan in reverse order */ dbda8d6ce9 2007-07-21 drh: int flags; /* Flags associated with pProbe */ dbda8d6ce9 2007-07-21 drh: int nEq; /* Number of == or IN constraints */ dbda8d6ce9 2007-07-21 drh: int eqTermMask; /* Mask of valid equality operators */ dbda8d6ce9 2007-07-21 drh: double cost; /* Cost of using pProbe */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: WHERETRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady)); dbda8d6ce9 2007-07-21 drh: lowestCost = SQLITE_BIG_DBL; dbda8d6ce9 2007-07-21 drh: pProbe = pSrc->pTab->pIndex; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the table has no indices and there are no terms in the where dbda8d6ce9 2007-07-21 drh: ** clause that refer to the ROWID, then we will never be able to do dbda8d6ce9 2007-07-21 drh: ** anything other than a full table scan on this table. We might as dbda8d6ce9 2007-07-21 drh: ** well put it first in the join order. That way, perhaps it can be dbda8d6ce9 2007-07-21 drh: ** referenced by other tables in the join. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pProbe==0 && dbda8d6ce9 2007-07-21 drh: findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IN|WO_LT|WO_LE|WO_GT|WO_GE,0)==0 && dbda8d6ce9 2007-07-21 drh: (pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev)) ){ dbda8d6ce9 2007-07-21 drh: *pFlags = 0; dbda8d6ce9 2007-07-21 drh: *ppIndex = 0; dbda8d6ce9 2007-07-21 drh: *pnEq = 0; dbda8d6ce9 2007-07-21 drh: return 0.0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check for a rowid=EXPR or rowid IN (...) constraints dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); dbda8d6ce9 2007-07-21 drh: if( pTerm ){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr; dbda8d6ce9 2007-07-21 drh: *ppIndex = 0; dbda8d6ce9 2007-07-21 drh: bestFlags = WHERE_ROWID_EQ; dbda8d6ce9 2007-07-21 drh: if( pTerm->eOperator & WO_EQ ){ dbda8d6ce9 2007-07-21 drh: /* Rowid== is always the best pick. Look no further. Because only dbda8d6ce9 2007-07-21 drh: ** a single row is generated, output is always in sorted order */ dbda8d6ce9 2007-07-21 drh: *pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE; dbda8d6ce9 2007-07-21 drh: *pnEq = 1; dbda8d6ce9 2007-07-21 drh: WHERETRACE(("... best is rowid\n")); dbda8d6ce9 2007-07-21 drh: return 0.0; dbda8d6ce9 2007-07-21 drh: }else if( (pExpr = pTerm->pExpr)->pList!=0 ){ dbda8d6ce9 2007-07-21 drh: /* Rowid IN (LIST): cost is NlogN where N is the number of list dbda8d6ce9 2007-07-21 drh: ** elements. */ dbda8d6ce9 2007-07-21 drh: lowestCost = pExpr->pList->nExpr; dbda8d6ce9 2007-07-21 drh: lowestCost *= estLog(lowestCost); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Rowid IN (SELECT): cost is NlogN where N is the number of rows dbda8d6ce9 2007-07-21 drh: ** in the result of the inner select. We have no way to estimate dbda8d6ce9 2007-07-21 drh: ** that value so make a wild guess. */ dbda8d6ce9 2007-07-21 drh: lowestCost = 200; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: WHERETRACE(("... rowid IN cost: %.9g\n", lowestCost)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Estimate the cost of a table scan. If we do not know how many dbda8d6ce9 2007-07-21 drh: ** entries are in the table, use 1 million as a guess. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: cost = pProbe ? pProbe->aiRowEst[0] : 1000000; dbda8d6ce9 2007-07-21 drh: WHERETRACE(("... table scan base cost: %.9g\n", cost)); dbda8d6ce9 2007-07-21 drh: flags = WHERE_ROWID_RANGE; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check for constraints on a range of rowids in a table scan. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTerm = findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE|WO_GT|WO_GE, 0); dbda8d6ce9 2007-07-21 drh: if( pTerm ){ dbda8d6ce9 2007-07-21 drh: if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_TOP_LIMIT; dbda8d6ce9 2007-07-21 drh: cost /= 3; /* Guess that rowid<EXPR eliminates two-thirds or rows */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_BTM_LIMIT; dbda8d6ce9 2007-07-21 drh: cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: WHERETRACE(("... rowid range reduces cost to %.9g\n", cost)); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: flags = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the table scan does not satisfy the ORDER BY clause, increase dbda8d6ce9 2007-07-21 drh: ** the cost by NlogN to cover the expense of sorting. */ dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: if( sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev) ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_ORDERBY|WHERE_ROWID_RANGE; dbda8d6ce9 2007-07-21 drh: if( rev ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_REVERSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: cost += cost*estLog(cost); dbda8d6ce9 2007-07-21 drh: WHERETRACE(("... sorting increases cost to %.9g\n", cost)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( cost<lowestCost ){ dbda8d6ce9 2007-07-21 drh: lowestCost = cost; dbda8d6ce9 2007-07-21 drh: bestFlags = flags; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the pSrc table is the right table of a LEFT JOIN then we may not dbda8d6ce9 2007-07-21 drh: ** use an index to satisfy IS NULL constraints on that table. This is dbda8d6ce9 2007-07-21 drh: ** because columns might end up being NULL if the table does not match - dbda8d6ce9 2007-07-21 drh: ** a circumstance which the index cannot help us discover. Ticket #2177. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (pSrc->jointype & JT_LEFT)!=0 ){ dbda8d6ce9 2007-07-21 drh: eqTermMask = WO_EQ|WO_IN; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: eqTermMask = WO_EQ|WO_IN|WO_ISNULL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Look at each index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(; pProbe; pProbe=pProbe->pNext){ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: double inMultiplier = 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: WHERETRACE(("... index %s:\n", pProbe->zName)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Count the number of columns in the index that are satisfied dbda8d6ce9 2007-07-21 drh: ** by x=EXPR constraints or x IN (...) constraints. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: flags = 0; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pProbe->nColumn; i++){ dbda8d6ce9 2007-07-21 drh: int j = pProbe->aiColumn[i]; dbda8d6ce9 2007-07-21 drh: pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pProbe); dbda8d6ce9 2007-07-21 drh: if( pTerm==0 ) break; dbda8d6ce9 2007-07-21 drh: flags |= WHERE_COLUMN_EQ; dbda8d6ce9 2007-07-21 drh: if( pTerm->eOperator & WO_IN ){ dbda8d6ce9 2007-07-21 drh: Expr *pExpr = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: flags |= WHERE_COLUMN_IN; dbda8d6ce9 2007-07-21 drh: if( pExpr->pSelect!=0 ){ dbda8d6ce9 2007-07-21 drh: inMultiplier *= 25; dbda8d6ce9 2007-07-21 drh: }else if( pExpr->pList!=0 ){ dbda8d6ce9 2007-07-21 drh: inMultiplier *= pExpr->pList->nExpr + 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: cost = pProbe->aiRowEst[i] * inMultiplier * estLog(inMultiplier); dbda8d6ce9 2007-07-21 drh: nEq = i; dbda8d6ce9 2007-07-21 drh: if( pProbe->onError!=OE_None && (flags & WHERE_COLUMN_IN)==0 dbda8d6ce9 2007-07-21 drh: && nEq==pProbe->nColumn ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_UNIQUE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: WHERETRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n",nEq,inMultiplier,cost)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Look for range constraints dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( nEq<pProbe->nColumn ){ dbda8d6ce9 2007-07-21 drh: int j = pProbe->aiColumn[nEq]; dbda8d6ce9 2007-07-21 drh: pTerm = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pProbe); dbda8d6ce9 2007-07-21 drh: if( pTerm ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_COLUMN_RANGE; dbda8d6ce9 2007-07-21 drh: if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_TOP_LIMIT; dbda8d6ce9 2007-07-21 drh: cost /= 3; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_BTM_LIMIT; dbda8d6ce9 2007-07-21 drh: cost /= 3; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: WHERETRACE(("...... range reduces cost to %.9g\n", cost)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Add the additional cost of sorting if that is a factor. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pOrderBy ){ dbda8d6ce9 2007-07-21 drh: if( (flags & WHERE_COLUMN_IN)==0 && dbda8d6ce9 2007-07-21 drh: isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev) ){ dbda8d6ce9 2007-07-21 drh: if( flags==0 ){ dbda8d6ce9 2007-07-21 drh: flags = WHERE_COLUMN_RANGE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: flags |= WHERE_ORDERBY; dbda8d6ce9 2007-07-21 drh: if( rev ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_REVERSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: cost += cost*estLog(cost); dbda8d6ce9 2007-07-21 drh: WHERETRACE(("...... orderby increases cost to %.9g\n", cost)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check to see if we can get away with using just the index without dbda8d6ce9 2007-07-21 drh: ** ever reading the table. If that is the case, then halve the dbda8d6ce9 2007-07-21 drh: ** cost of this index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( flags && pSrc->colUsed < (((Bitmask)1)<<(BMS-1)) ){ dbda8d6ce9 2007-07-21 drh: Bitmask m = pSrc->colUsed; dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: for(j=0; j<pProbe->nColumn; j++){ dbda8d6ce9 2007-07-21 drh: int x = pProbe->aiColumn[j]; dbda8d6ce9 2007-07-21 drh: if( x<BMS-1 ){ dbda8d6ce9 2007-07-21 drh: m &= ~(((Bitmask)1)<<x); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( m==0 ){ dbda8d6ce9 2007-07-21 drh: flags |= WHERE_IDX_ONLY; dbda8d6ce9 2007-07-21 drh: cost /= 2; dbda8d6ce9 2007-07-21 drh: WHERETRACE(("...... idx-only reduces cost to %.9g\n", cost)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this index has achieved the lowest cost so far, then use it. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: if( flags && cost < lowestCost ){ dbda8d6ce9 2007-07-21 drh: bestIdx = pProbe; dbda8d6ce9 2007-07-21 drh: lowestCost = cost; dbda8d6ce9 2007-07-21 drh: bestFlags = flags; dbda8d6ce9 2007-07-21 drh: bestNEq = nEq; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Report the best result dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: *ppIndex = bestIdx; dbda8d6ce9 2007-07-21 drh: WHERETRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n", dbda8d6ce9 2007-07-21 drh: bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq)); dbda8d6ce9 2007-07-21 drh: *pFlags = bestFlags | eqTermMask; dbda8d6ce9 2007-07-21 drh: *pnEq = bestNEq; dbda8d6ce9 2007-07-21 drh: return lowestCost; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Disable a term in the WHERE clause. Except, do not disable the term dbda8d6ce9 2007-07-21 drh: ** if it controls a LEFT OUTER JOIN and it did not originate in the ON dbda8d6ce9 2007-07-21 drh: ** or USING clause of that join. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Consider the term t2.z='ok' in the following queries: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok' dbda8d6ce9 2007-07-21 drh: ** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok' dbda8d6ce9 2007-07-21 drh: ** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok' dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The t2.z='ok' is disabled in the in (2) because it originates dbda8d6ce9 2007-07-21 drh: ** in the ON clause. The term is disabled in (3) because it is not part dbda8d6ce9 2007-07-21 drh: ** of a LEFT OUTER JOIN. In (1), the term is not disabled. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Disabling a term causes that term to not be tested in the inner loop dbda8d6ce9 2007-07-21 drh: ** of the join. Disabling is an optimization. When terms are satisfied dbda8d6ce9 2007-07-21 drh: ** by indices, we disable them to prevent redundant tests in the inner dbda8d6ce9 2007-07-21 drh: ** loop. We would get the correct results if nothing were ever disabled, dbda8d6ce9 2007-07-21 drh: ** but joins might run a little slower. The trick is to disable as much dbda8d6ce9 2007-07-21 drh: ** as we can without disabling too much. If we disabled in (1), we'd get dbda8d6ce9 2007-07-21 drh: ** the wrong answer. See ticket #813. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ dbda8d6ce9 2007-07-21 drh: if( pTerm dbda8d6ce9 2007-07-21 drh: && (pTerm->flags & TERM_CODED)==0 dbda8d6ce9 2007-07-21 drh: && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: pTerm->flags |= TERM_CODED; dbda8d6ce9 2007-07-21 drh: if( pTerm->iParent>=0 ){ dbda8d6ce9 2007-07-21 drh: WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent]; dbda8d6ce9 2007-07-21 drh: if( (--pOther->nChild)==0 ){ dbda8d6ce9 2007-07-21 drh: disableTerm(pLevel, pOther); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that builds a probe for an index. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There should be nColumn values on the stack. The index dbda8d6ce9 2007-07-21 drh: ** to be probed is pIdx. Pop the values from the stack and dbda8d6ce9 2007-07-21 drh: ** replace them all with a single record that is the index dbda8d6ce9 2007-07-21 drh: ** problem. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void buildIndexProbe( dbda8d6ce9 2007-07-21 drh: Vdbe *v, /* Generate code into this VM */ dbda8d6ce9 2007-07-21 drh: int nColumn, /* The number of columns to check for NULL */ dbda8d6ce9 2007-07-21 drh: Index *pIdx /* Index that we will be searching */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); dbda8d6ce9 2007-07-21 drh: sqlite3IndexAffinityStr(v, pIdx); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code for a single equality term of the WHERE clause. An equality dbda8d6ce9 2007-07-21 drh: ** term can be either X=expr or X IN (...). pTerm is the term to be dbda8d6ce9 2007-07-21 drh: ** coded. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The current value for the constraint is left on the top of the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For a constraint of the form X=expr, the expression is evaluated and its dbda8d6ce9 2007-07-21 drh: ** result is left on the stack. For constraints of the form X IN (...) dbda8d6ce9 2007-07-21 drh: ** this routine sets up a loop that will iterate over all values of X. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void codeEqualityTerm( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parsing context */ dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ dbda8d6ce9 2007-07-21 drh: WhereLevel *pLevel /* When level of the FROM clause we are working on */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: Expr *pX = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: if( pX->op==TK_EQ ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pX->pRight); dbda8d6ce9 2007-07-21 drh: }else if( pX->op==TK_ISNULL ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Null, 0, 0); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SUBQUERY dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int iTab; dbda8d6ce9 2007-07-21 drh: struct InLoop *pIn; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pX->op==TK_IN ); dbda8d6ce9 2007-07-21 drh: sqlite3CodeSubselect(pParse, pX); dbda8d6ce9 2007-07-21 drh: iTab = pX->iTable; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# %.*s", pX->span.n, pX->span.z)); dbda8d6ce9 2007-07-21 drh: if( pLevel->nIn==0 ){ dbda8d6ce9 2007-07-21 drh: pLevel->nxt = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pLevel->nIn++; c287665ba8 2007-09-14 drh: pLevel->aInLoop = sqlite3DbReallocOrFree(pParse->db, pLevel->aInLoop, dbda8d6ce9 2007-07-21 drh: sizeof(pLevel->aInLoop[0])*pLevel->nIn); dbda8d6ce9 2007-07-21 drh: pIn = pLevel->aInLoop; dbda8d6ce9 2007-07-21 drh: if( pIn ){ dbda8d6ce9 2007-07-21 drh: pIn += pLevel->nIn - 1; dbda8d6ce9 2007-07-21 drh: pIn->iCur = iTab; dbda8d6ce9 2007-07-21 drh: pIn->topAddr = sqlite3VdbeAddOp(v, OP_Column, iTab, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IsNull, -1, 0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pLevel->nIn = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: disableTerm(pLevel, pTerm); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate code that will evaluate all == and IN constraints for an dbda8d6ce9 2007-07-21 drh: ** index. The values for all constraints are left on the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c). dbda8d6ce9 2007-07-21 drh: ** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10 dbda8d6ce9 2007-07-21 drh: ** The index has as many as three equality constraints, but in this dbda8d6ce9 2007-07-21 drh: ** example, the third "c" value is an inequality. So only two dbda8d6ce9 2007-07-21 drh: ** constraints are coded. This routine will generate code to evaluate dbda8d6ce9 2007-07-21 drh: ** a==5 and b IN (1,2,3). The current values for a and b will be left dbda8d6ce9 2007-07-21 drh: ** on the stack - a is the deepest and b the shallowest. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** In the example above nEq==2. But this subroutine works for any value dbda8d6ce9 2007-07-21 drh: ** of nEq including 0. If nEq==0, this routine is nearly a no-op. dbda8d6ce9 2007-07-21 drh: ** The only thing it does is allocate the pLevel->iMem memory cell. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine always allocates at least one memory cell and puts dbda8d6ce9 2007-07-21 drh: ** the address of that memory cell in pLevel->iMem. The code that dbda8d6ce9 2007-07-21 drh: ** calls this routine will use pLevel->iMem to store the termination dbda8d6ce9 2007-07-21 drh: ** key value of the loop. If one or more IN operators appear, then dbda8d6ce9 2007-07-21 drh: ** this routine allocates an additional nEq memory cells for internal dbda8d6ce9 2007-07-21 drh: ** use. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void codeAllEqualityTerms( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* Parsing context */ dbda8d6ce9 2007-07-21 drh: WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ dbda8d6ce9 2007-07-21 drh: WhereClause *pWC, /* The WHERE clause */ dbda8d6ce9 2007-07-21 drh: Bitmask notReady /* Which parts of FROM have not yet been coded */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int nEq = pLevel->nEq; /* The number of == or IN constraints to code */ dbda8d6ce9 2007-07-21 drh: int termsInMem = 0; /* If true, store value in mem[] cells */ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; /* The virtual machine under construction */ dbda8d6ce9 2007-07-21 drh: Index *pIdx = pLevel->pIdx; /* The index being used for this loop */ dbda8d6ce9 2007-07-21 drh: int iCur = pLevel->iTabCur; /* The cursor of the table */ dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm; /* A single constraint term */ dbda8d6ce9 2007-07-21 drh: int j; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out how many memory cells we will need then allocate them. dbda8d6ce9 2007-07-21 drh: ** We always need at least one used to store the loop terminator dbda8d6ce9 2007-07-21 drh: ** value. If there are IN operators we'll need one for each == or dbda8d6ce9 2007-07-21 drh: ** IN constraint. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pLevel->iMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: if( pLevel->flags & WHERE_COLUMN_IN ){ dbda8d6ce9 2007-07-21 drh: pParse->nMem += pLevel->nEq; dbda8d6ce9 2007-07-21 drh: termsInMem = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Evaluate the equality constraints dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( pIdx->nColumn>=nEq ); dbda8d6ce9 2007-07-21 drh: for(j=0; j<nEq; j++){ dbda8d6ce9 2007-07-21 drh: int k = pIdx->aiColumn[j]; dbda8d6ce9 2007-07-21 drh: pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx); dbda8d6ce9 2007-07-21 drh: if( pTerm==0 ) break; dbda8d6ce9 2007-07-21 drh: assert( (pTerm->flags & TERM_CODED)==0 ); dbda8d6ce9 2007-07-21 drh: codeEqualityTerm(pParse, pTerm, pLevel); dbda8d6ce9 2007-07-21 drh: if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IsNull, termsInMem ? -1 : -(j+1), pLevel->brk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( termsInMem ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make sure all the constraint values are on the top of the stack dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( termsInMem ){ dbda8d6ce9 2007-07-21 drh: for(j=0; j<nEq; j++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem+j+1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if defined(SQLITE_TEST) dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following variable holds a text description of query plan generated dbda8d6ce9 2007-07-21 drh: ** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin dbda8d6ce9 2007-07-21 drh: ** overwrites the previous. This information is used for testing and dbda8d6ce9 2007-07-21 drh: ** analysis only. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API char sqlite3_query_plan[BMS*2*40]; /* Text of the join */ dbda8d6ce9 2007-07-21 drh: static int nQPlan = 0; /* Next free slow in _query_plan[] */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_TEST */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Free a WhereInfo structure dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void whereInfoFree(WhereInfo *pWInfo){ dbda8d6ce9 2007-07-21 drh: if( pWInfo ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: for(i=0; i<pWInfo->nLevel; i++){ dbda8d6ce9 2007-07-21 drh: sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo; dbda8d6ce9 2007-07-21 drh: if( pInfo ){ dbda8d6ce9 2007-07-21 drh: if( pInfo->needToFreeIdxStr ){ dbda8d6ce9 2007-07-21 drh: /* Coverage: Don't think this can be reached. By the time this dbda8d6ce9 2007-07-21 drh: ** function is called, the index-strings have been passed dbda8d6ce9 2007-07-21 drh: ** to the vdbe layer for deletion. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3_free(pInfo->idxStr); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pInfo); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pWInfo); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate the beginning of the loop used for WHERE clause processing. dbda8d6ce9 2007-07-21 drh: ** The return value is a pointer to an opaque structure that contains dbda8d6ce9 2007-07-21 drh: ** information needed to terminate the loop. Later, the calling routine dbda8d6ce9 2007-07-21 drh: ** should invoke sqlite3WhereEnd() with the return value of this function dbda8d6ce9 2007-07-21 drh: ** in order to complete the WHERE clause processing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an error occurs, this routine returns NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The basic idea is to do a nested loop, one loop for each table in dbda8d6ce9 2007-07-21 drh: ** the FROM clause of a select. (INSERT and UPDATE statements are the dbda8d6ce9 2007-07-21 drh: ** same as a SELECT with only a single table in the FROM clause.) For dbda8d6ce9 2007-07-21 drh: ** example, if the SQL is this: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** SELECT * FROM t1, t2, t3 WHERE ...; dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then the code generated is conceptually like the following: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** foreach row1 in t1 do \ Code generated dbda8d6ce9 2007-07-21 drh: ** foreach row2 in t2 do |-- by sqlite3WhereBegin() dbda8d6ce9 2007-07-21 drh: ** foreach row3 in t3 do / dbda8d6ce9 2007-07-21 drh: ** ... dbda8d6ce9 2007-07-21 drh: ** end \ Code generated dbda8d6ce9 2007-07-21 drh: ** end |-- by sqlite3WhereEnd() dbda8d6ce9 2007-07-21 drh: ** end / dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note that the loops might not be nested in the order in which they dbda8d6ce9 2007-07-21 drh: ** appear in the FROM clause if a different order is better able to make dbda8d6ce9 2007-07-21 drh: ** use of indices. Note also that when the IN operator appears in dbda8d6ce9 2007-07-21 drh: ** the WHERE clause, it might result in additional nested loops for dbda8d6ce9 2007-07-21 drh: ** scanning through all values on the right-hand side of the IN. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** There are Btree cursors associated with each table. t1 uses cursor dbda8d6ce9 2007-07-21 drh: ** number pTabList->a[0].iCursor. t2 uses the cursor pTabList->a[1].iCursor. dbda8d6ce9 2007-07-21 drh: ** And so forth. This routine generates code to open those VDBE cursors dbda8d6ce9 2007-07-21 drh: ** and sqlite3WhereEnd() generates the code to close them. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code that sqlite3WhereBegin() generates leaves the cursors named dbda8d6ce9 2007-07-21 drh: ** in pTabList pointing at their appropriate entries. The [...] code dbda8d6ce9 2007-07-21 drh: ** can use OP_Column and OP_Rowid opcodes on these cursors to extract dbda8d6ce9 2007-07-21 drh: ** data from the various tables of the loop. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the WHERE clause is empty, the foreach loops must each scan their dbda8d6ce9 2007-07-21 drh: ** entire tables. Thus a three-way join is an O(N^3) operation. But if dbda8d6ce9 2007-07-21 drh: ** the tables have indices and there are terms in the WHERE clause that dbda8d6ce9 2007-07-21 drh: ** refer to those indices, a complete table scan can be avoided and the dbda8d6ce9 2007-07-21 drh: ** code will run much faster. Most of the work of this routine is checking dbda8d6ce9 2007-07-21 drh: ** to see if there are indices that can be used to speed up the loop. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Terms of the WHERE clause are also used to limit which rows actually dbda8d6ce9 2007-07-21 drh: ** make it to the "..." in the middle of the loop. After each "foreach", dbda8d6ce9 2007-07-21 drh: ** terms of the WHERE clause that use only terms in that loop and outer dbda8d6ce9 2007-07-21 drh: ** loops are evaluated and if false a jump is made around all subsequent dbda8d6ce9 2007-07-21 drh: ** inner loops (or around the "..." if the test occurs within the inner- dbda8d6ce9 2007-07-21 drh: ** most loop) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** OUTER JOINS dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** An outer join of tables t1 and t2 is conceptally coded as follows: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** foreach row1 in t1 do dbda8d6ce9 2007-07-21 drh: ** flag = 0 dbda8d6ce9 2007-07-21 drh: ** foreach row2 in t2 do dbda8d6ce9 2007-07-21 drh: ** start: dbda8d6ce9 2007-07-21 drh: ** ... dbda8d6ce9 2007-07-21 drh: ** flag = 1 dbda8d6ce9 2007-07-21 drh: ** end dbda8d6ce9 2007-07-21 drh: ** if flag==0 then dbda8d6ce9 2007-07-21 drh: ** move the row2 cursor to a null row dbda8d6ce9 2007-07-21 drh: ** goto start dbda8d6ce9 2007-07-21 drh: ** fi dbda8d6ce9 2007-07-21 drh: ** end dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** ORDER BY CLAUSE PROCESSING dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement, dbda8d6ce9 2007-07-21 drh: ** if there is one. If there is no ORDER BY clause or if this routine dbda8d6ce9 2007-07-21 drh: ** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If an index can be used so that the natural output order of the table dbda8d6ce9 2007-07-21 drh: ** scan is correct for the ORDER BY clause, then that index is used and dbda8d6ce9 2007-07-21 drh: ** *ppOrderBy is set to NULL. This is an optimization that prevents an dbda8d6ce9 2007-07-21 drh: ** unnecessary sort of the result set if an index appropriate for the dbda8d6ce9 2007-07-21 drh: ** ORDER BY clause already exists. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the where clause loops cannot be arranged to provide the correct dbda8d6ce9 2007-07-21 drh: ** output order, then the *ppOrderBy is unchanged. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( dbda8d6ce9 2007-07-21 drh: Parse *pParse, /* The parser context */ dbda8d6ce9 2007-07-21 drh: SrcList *pTabList, /* A list of all tables to be scanned */ dbda8d6ce9 2007-07-21 drh: Expr *pWhere, /* The WHERE clause */ dbda8d6ce9 2007-07-21 drh: ExprList **ppOrderBy /* An ORDER BY clause, or NULL */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; /* Loop counter */ dbda8d6ce9 2007-07-21 drh: WhereInfo *pWInfo; /* Will become the return value of this function */ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pParse->pVdbe; /* The virtual database engine */ dbda8d6ce9 2007-07-21 drh: int brk, cont = 0; /* Addresses used during code generation */ dbda8d6ce9 2007-07-21 drh: Bitmask notReady; /* Cursors that are not yet positioned */ dbda8d6ce9 2007-07-21 drh: WhereTerm *pTerm; /* A single term in the WHERE clause */ dbda8d6ce9 2007-07-21 drh: ExprMaskSet maskSet; /* The expression mask set */ dbda8d6ce9 2007-07-21 drh: WhereClause wc; /* The WHERE clause is divided into these terms */ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pTabItem; /* A single entry from pTabList */ dbda8d6ce9 2007-07-21 drh: WhereLevel *pLevel; /* A single level in the pWInfo list */ dbda8d6ce9 2007-07-21 drh: int iFrom; /* First unused FROM clause element */ dbda8d6ce9 2007-07-21 drh: int andFlags; /* AND-ed combination of all wc.a[].flags */ c287665ba8 2007-09-14 drh: sqlite3 *db; /* Database connection */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The number of tables in the FROM clause is limited by the number of dbda8d6ce9 2007-07-21 drh: ** bits in a Bitmask dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pTabList->nSrc>BMS ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Split the WHERE clause into separate subexpressions where each dbda8d6ce9 2007-07-21 drh: ** subexpression is separated by an AND operator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: initMaskSet(&maskSet); dbda8d6ce9 2007-07-21 drh: whereClauseInit(&wc, pParse, &maskSet); dbda8d6ce9 2007-07-21 drh: whereSplit(&wc, pWhere, TK_AND); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate and initialize the WhereInfo structure that will become the dbda8d6ce9 2007-07-21 drh: ** return value. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: db = pParse->db; c287665ba8 2007-09-14 drh: pWInfo = sqlite3DbMallocZero(db, c287665ba8 2007-09-14 drh: sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel)); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto whereBeginNoMem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pWInfo->nLevel = pTabList->nSrc; dbda8d6ce9 2007-07-21 drh: pWInfo->pParse = pParse; dbda8d6ce9 2007-07-21 drh: pWInfo->pTabList = pTabList; dbda8d6ce9 2007-07-21 drh: pWInfo->iBreak = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Special case: a WHERE clause that is constant. Evaluate the dbda8d6ce9 2007-07-21 drh: ** expression and either jump over all of the code or fall thru. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){ dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1); dbda8d6ce9 2007-07-21 drh: pWhere = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Analyze all of the subexpressions. Note that exprAnalyze() might dbda8d6ce9 2007-07-21 drh: ** add new virtual terms onto the end of the WHERE clause. We do not dbda8d6ce9 2007-07-21 drh: ** want to analyze these virtual terms, so start analyzing at the end dbda8d6ce9 2007-07-21 drh: ** and work forward so that the added virtual terms are never processed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTabList->nSrc; i++){ dbda8d6ce9 2007-07-21 drh: createMask(&maskSet, pTabList->a[i].iCursor); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: exprAnalyzeAll(pTabList, &wc); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto whereBeginNoMem; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Chose the best index to use for each table in the FROM clause. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This loop fills in the following fields: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** pWInfo->a[].pIdx The index to use for this level of the loop. dbda8d6ce9 2007-07-21 drh: ** pWInfo->a[].flags WHERE_xxx flags associated with pIdx dbda8d6ce9 2007-07-21 drh: ** pWInfo->a[].nEq The number of == and IN constraints dbda8d6ce9 2007-07-21 drh: ** pWInfo->a[].iFrom When term of the FROM clause is being coded dbda8d6ce9 2007-07-21 drh: ** pWInfo->a[].iTabCur The VDBE cursor for the database table dbda8d6ce9 2007-07-21 drh: ** pWInfo->a[].iIdxCur The VDBE cursor for the index dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This loop also figures out the nesting order of tables in the FROM dbda8d6ce9 2007-07-21 drh: ** clause. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: notReady = ~(Bitmask)0; dbda8d6ce9 2007-07-21 drh: pTabItem = pTabList->a; dbda8d6ce9 2007-07-21 drh: pLevel = pWInfo->a; dbda8d6ce9 2007-07-21 drh: andFlags = ~0; dbda8d6ce9 2007-07-21 drh: WHERETRACE(("*** Optimizer Start ***\n")); dbda8d6ce9 2007-07-21 drh: for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ dbda8d6ce9 2007-07-21 drh: Index *pIdx; /* Index for FROM table at pTabItem */ dbda8d6ce9 2007-07-21 drh: int flags; /* Flags asssociated with pIdx */ dbda8d6ce9 2007-07-21 drh: int nEq; /* Number of == or IN constraints */ dbda8d6ce9 2007-07-21 drh: double cost; /* The cost for pIdx */ dbda8d6ce9 2007-07-21 drh: int j; /* For looping over FROM tables */ dbda8d6ce9 2007-07-21 drh: Index *pBest = 0; /* The best index seen so far */ dbda8d6ce9 2007-07-21 drh: int bestFlags = 0; /* Flags associated with pBest */ dbda8d6ce9 2007-07-21 drh: int bestNEq = 0; /* nEq associated with pBest */ dbda8d6ce9 2007-07-21 drh: double lowestCost; /* Cost of the pBest */ dbda8d6ce9 2007-07-21 drh: int bestJ = 0; /* The value of j */ dbda8d6ce9 2007-07-21 drh: Bitmask m; /* Bitmask value for j or bestJ */ dbda8d6ce9 2007-07-21 drh: int once = 0; /* True when first table is seen */ dbda8d6ce9 2007-07-21 drh: sqlite3_index_info *pIndex; /* Current virtual index */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: lowestCost = SQLITE_BIG_DBL; dbda8d6ce9 2007-07-21 drh: for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){ dbda8d6ce9 2007-07-21 drh: int doNotReorder; /* True if this table should not be reordered */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0; dbda8d6ce9 2007-07-21 drh: if( once && doNotReorder ) break; dbda8d6ce9 2007-07-21 drh: m = getMask(&maskSet, pTabItem->iCursor); dbda8d6ce9 2007-07-21 drh: if( (m & notReady)==0 ){ dbda8d6ce9 2007-07-21 drh: if( j==iFrom ) iFrom++; dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pTabItem->pTab ); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( IsVirtual(pTabItem->pTab) ){ dbda8d6ce9 2007-07-21 drh: sqlite3_index_info **ppIdxInfo = &pWInfo->a[j].pIdxInfo; dbda8d6ce9 2007-07-21 drh: cost = bestVirtualIndex(pParse, &wc, pTabItem, notReady, dbda8d6ce9 2007-07-21 drh: ppOrderBy ? *ppOrderBy : 0, i==0, dbda8d6ce9 2007-07-21 drh: ppIdxInfo); dbda8d6ce9 2007-07-21 drh: flags = WHERE_VIRTUALTABLE; dbda8d6ce9 2007-07-21 drh: pIndex = *ppIdxInfo; dbda8d6ce9 2007-07-21 drh: if( pIndex && pIndex->orderByConsumed ){ dbda8d6ce9 2007-07-21 drh: flags = WHERE_VIRTUALTABLE | WHERE_ORDERBY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pIdx = 0; dbda8d6ce9 2007-07-21 drh: nEq = 0; dbda8d6ce9 2007-07-21 drh: if( (SQLITE_BIG_DBL/2.0)<cost ){ dbda8d6ce9 2007-07-21 drh: /* The cost is not allowed to be larger than SQLITE_BIG_DBL (the dbda8d6ce9 2007-07-21 drh: ** inital value of lowestCost in this loop. If it is, then dbda8d6ce9 2007-07-21 drh: ** the (cost<lowestCost) test below will never be true and dbda8d6ce9 2007-07-21 drh: ** pLevel->pBestIdx never set. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: cost = (SQLITE_BIG_DBL/2.0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: cost = bestIndex(pParse, &wc, pTabItem, notReady, dbda8d6ce9 2007-07-21 drh: (i==0 && ppOrderBy) ? *ppOrderBy : 0, dbda8d6ce9 2007-07-21 drh: &pIdx, &flags, &nEq); dbda8d6ce9 2007-07-21 drh: pIndex = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( cost<lowestCost ){ dbda8d6ce9 2007-07-21 drh: once = 1; dbda8d6ce9 2007-07-21 drh: lowestCost = cost; dbda8d6ce9 2007-07-21 drh: pBest = pIdx; dbda8d6ce9 2007-07-21 drh: bestFlags = flags; dbda8d6ce9 2007-07-21 drh: bestNEq = nEq; dbda8d6ce9 2007-07-21 drh: bestJ = j; dbda8d6ce9 2007-07-21 drh: pLevel->pBestIdx = pIndex; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( doNotReorder ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: WHERETRACE(("*** Optimizer choose table %d for loop %d\n", bestJ, dbda8d6ce9 2007-07-21 drh: pLevel-pWInfo->a)); dbda8d6ce9 2007-07-21 drh: if( (bestFlags & WHERE_ORDERBY)!=0 ){ dbda8d6ce9 2007-07-21 drh: *ppOrderBy = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: andFlags &= bestFlags; dbda8d6ce9 2007-07-21 drh: pLevel->flags = bestFlags; dbda8d6ce9 2007-07-21 drh: pLevel->pIdx = pBest; dbda8d6ce9 2007-07-21 drh: pLevel->nEq = bestNEq; dbda8d6ce9 2007-07-21 drh: pLevel->aInLoop = 0; dbda8d6ce9 2007-07-21 drh: pLevel->nIn = 0; dbda8d6ce9 2007-07-21 drh: if( pBest ){ dbda8d6ce9 2007-07-21 drh: pLevel->iIdxCur = pParse->nTab++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pLevel->iIdxCur = -1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor); dbda8d6ce9 2007-07-21 drh: pLevel->iFrom = bestJ; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: WHERETRACE(("*** Optimizer Finished ***\n")); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If the total query only selects a single row, then the ORDER BY dbda8d6ce9 2007-07-21 drh: ** clause is irrelevant. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (andFlags & WHERE_UNIQUE)!=0 && ppOrderBy ){ dbda8d6ce9 2007-07-21 drh: *ppOrderBy = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open all tables in the pTabList and any indices selected for dbda8d6ce9 2007-07-21 drh: ** searching those tables. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ dbda8d6ce9 2007-07-21 drh: for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ dbda8d6ce9 2007-07-21 drh: Table *pTab; /* Table to open */ dbda8d6ce9 2007-07-21 drh: Index *pIx; /* Index used to access pTab (if any) */ dbda8d6ce9 2007-07-21 drh: int iDb; /* Index of database containing table/index */ dbda8d6ce9 2007-07-21 drh: int iIdxCur = pLevel->iIdxCur; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_EXPLAIN dbda8d6ce9 2007-07-21 drh: if( pParse->explain==2 ){ dbda8d6ce9 2007-07-21 drh: char *zMsg; dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; c287665ba8 2007-09-14 drh: zMsg = sqlite3MPrintf(db, "TABLE %s", pItem->zName); dbda8d6ce9 2007-07-21 drh: if( pItem->zAlias ){ c287665ba8 2007-09-14 drh: zMsg = sqlite3MPrintf(db, "%z AS %s", zMsg, pItem->zAlias); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (pIx = pLevel->pIdx)!=0 ){ c287665ba8 2007-09-14 drh: zMsg = sqlite3MPrintf(db, "%z WITH INDEX %s", zMsg, pIx->zName); dbda8d6ce9 2007-07-21 drh: }else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){ c287665ba8 2007-09-14 drh: zMsg = sqlite3MPrintf(db, "%z USING PRIMARY KEY", zMsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: else if( pLevel->pBestIdx ){ dbda8d6ce9 2007-07-21 drh: sqlite3_index_info *pBestIdx = pLevel->pBestIdx; c287665ba8 2007-09-14 drh: zMsg = sqlite3MPrintf(db, "%z VIRTUAL TABLE INDEX %d:%s", zMsg, dbda8d6ce9 2007-07-21 drh: pBestIdx->idxNum, pBestIdx->idxStr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( pLevel->flags & WHERE_ORDERBY ){ c287665ba8 2007-09-14 drh: zMsg = sqlite3MPrintf(db, "%z ORDER BY", zMsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_EXPLAIN */ dbda8d6ce9 2007-07-21 drh: pTabItem = &pTabList->a[pLevel->iFrom]; dbda8d6ce9 2007-07-21 drh: pTab = pTabItem->pTab; dbda8d6ce9 2007-07-21 drh: iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); dbda8d6ce9 2007-07-21 drh: if( pTab->isEphem || pTab->pSelect ) continue; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( pLevel->pBestIdx ){ dbda8d6ce9 2007-07-21 drh: int iCur = pTabItem->iCursor; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VOpen, iCur, 0, (const char*)pTab->pVtab, P3_VTAB); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead); dbda8d6ce9 2007-07-21 drh: if( pTab->nCol<(sizeof(Bitmask)*8) ){ dbda8d6ce9 2007-07-21 drh: Bitmask b = pTabItem->colUsed; dbda8d6ce9 2007-07-21 drh: int n = 0; dbda8d6ce9 2007-07-21 drh: for(; b; b=b>>1, n++){} dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-1, n); dbda8d6ce9 2007-07-21 drh: assert( n<=pTab->nCol ); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pLevel->iTabCur = pTabItem->iCursor; dbda8d6ce9 2007-07-21 drh: if( (pIx = pLevel->pIdx)!=0 ){ dbda8d6ce9 2007-07-21 drh: KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx); dbda8d6ce9 2007-07-21 drh: assert( pIx->pSchema==pTab->pSchema ); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# %s", pIx->zName)); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum, dbda8d6ce9 2007-07-21 drh: (char*)pKey, P3_KEYINFO_HANDOFF); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (pLevel->flags & (WHERE_IDX_ONLY|WHERE_COLUMN_RANGE))!=0 ){ dbda8d6ce9 2007-07-21 drh: /* Only call OP_SetNumColumns on the index if we might later use dbda8d6ce9 2007-07-21 drh: ** OP_Column on the index. */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3CodeVerifySchema(pParse, iDb); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pWInfo->iTop = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate the code to do the search. Each iteration of the for dbda8d6ce9 2007-07-21 drh: ** loop below generates code for a single nested loop of the VM dbda8d6ce9 2007-07-21 drh: ** program. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: notReady = ~(Bitmask)0; dbda8d6ce9 2007-07-21 drh: for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: int iCur = pTabItem->iCursor; /* The VDBE cursor for the table */ dbda8d6ce9 2007-07-21 drh: Index *pIdx; /* The index we will be using */ dbda8d6ce9 2007-07-21 drh: int nxt; /* Where to jump to continue with the next IN case */ dbda8d6ce9 2007-07-21 drh: int iIdxCur; /* The VDBE cursor for the index */ dbda8d6ce9 2007-07-21 drh: int omitTable; /* True if we use the index only */ dbda8d6ce9 2007-07-21 drh: int bRev; /* True if we need to scan in reverse order */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pTabItem = &pTabList->a[pLevel->iFrom]; dbda8d6ce9 2007-07-21 drh: iCur = pTabItem->iCursor; dbda8d6ce9 2007-07-21 drh: pIdx = pLevel->pIdx; dbda8d6ce9 2007-07-21 drh: iIdxCur = pLevel->iIdxCur; dbda8d6ce9 2007-07-21 drh: bRev = (pLevel->flags & WHERE_REVERSE)!=0; dbda8d6ce9 2007-07-21 drh: omitTable = (pLevel->flags & WHERE_IDX_ONLY)!=0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Create labels for the "break" and "continue" instructions dbda8d6ce9 2007-07-21 drh: ** for the current loop. Jump to brk to break out of a loop. dbda8d6ce9 2007-07-21 drh: ** Jump to cont to go immediately to the next iteration of the dbda8d6ce9 2007-07-21 drh: ** loop. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When there is an IN operator, we also have a "nxt" label that dbda8d6ce9 2007-07-21 drh: ** means to continue with the next IN value combination. When dbda8d6ce9 2007-07-21 drh: ** there are no IN operators in the constraints, the "nxt" label dbda8d6ce9 2007-07-21 drh: ** is the same as "brk". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: brk = pLevel->brk = pLevel->nxt = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: cont = pLevel->cont = sqlite3VdbeMakeLabel(v); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If this is the right table of a LEFT OUTER JOIN, allocate and dbda8d6ce9 2007-07-21 drh: ** initialize a memory cell that records if this table matches any dbda8d6ce9 2007-07-21 drh: ** row of the left table of the join. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){ dbda8d6ce9 2007-07-21 drh: if( !pParse->nMem ) pParse->nMem++; dbda8d6ce9 2007-07-21 drh: pLevel->iLeftJoin = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# init LEFT JOIN no-match flag")); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: if( pLevel->pBestIdx ){ dbda8d6ce9 2007-07-21 drh: /* Case 0: The table is a virtual-table. Use the VFilter and VNext dbda8d6ce9 2007-07-21 drh: ** to access the data. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: sqlite3_index_info *pBestIdx = pLevel->pBestIdx; dbda8d6ce9 2007-07-21 drh: int nConstraint = pBestIdx->nConstraint; dbda8d6ce9 2007-07-21 drh: struct sqlite3_index_constraint_usage *aUsage = dbda8d6ce9 2007-07-21 drh: pBestIdx->aConstraintUsage; dbda8d6ce9 2007-07-21 drh: const struct sqlite3_index_constraint *aConstraint = dbda8d6ce9 2007-07-21 drh: pBestIdx->aConstraint; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(j=1; j<=nConstraint; j++){ dbda8d6ce9 2007-07-21 drh: int k; dbda8d6ce9 2007-07-21 drh: for(k=0; k<nConstraint; k++){ dbda8d6ce9 2007-07-21 drh: if( aUsage[k].argvIndex==j ){ dbda8d6ce9 2007-07-21 drh: int iTerm = aConstraint[k].iTermOffset; dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, wc.a[iTerm].pExpr->pRight); dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( k==nConstraint ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, j-1, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Integer, pBestIdx->idxNum, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_VFilter, iCur, brk, pBestIdx->idxStr, dbda8d6ce9 2007-07-21 drh: pBestIdx->needToFreeIdxStr ? P3_MPRINTF : P3_STATIC); dbda8d6ce9 2007-07-21 drh: pBestIdx->needToFreeIdxStr = 0; dbda8d6ce9 2007-07-21 drh: for(j=0; j<pBestIdx->nConstraint; j++){ dbda8d6ce9 2007-07-21 drh: if( aUsage[j].omit ){ dbda8d6ce9 2007-07-21 drh: int iTerm = aConstraint[j].iTermOffset; dbda8d6ce9 2007-07-21 drh: disableTerm(pLevel, &wc.a[iTerm]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pLevel->op = OP_VNext; dbda8d6ce9 2007-07-21 drh: pLevel->p1 = iCur; dbda8d6ce9 2007-07-21 drh: pLevel->p2 = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_VIRTUALTABLE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pLevel->flags & WHERE_ROWID_EQ ){ dbda8d6ce9 2007-07-21 drh: /* Case 1: We can directly reference a single row using an dbda8d6ce9 2007-07-21 drh: ** equality comparison against the ROWID field. Or dbda8d6ce9 2007-07-21 drh: ** we reference multiple rows using a "rowid IN (...)" dbda8d6ce9 2007-07-21 drh: ** construct. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pTerm = findTerm(&wc, iCur, -1, notReady, WO_EQ|WO_IN, 0); dbda8d6ce9 2007-07-21 drh: assert( pTerm!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pTerm->pExpr!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pTerm->leftCursor==iCur ); dbda8d6ce9 2007-07-21 drh: assert( omitTable==0 ); dbda8d6ce9 2007-07-21 drh: codeEqualityTerm(pParse, pTerm, pLevel); dbda8d6ce9 2007-07-21 drh: nxt = pLevel->nxt; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MustBeInt, 1, nxt); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NotExists, iCur, nxt); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "pk")); dbda8d6ce9 2007-07-21 drh: pLevel->op = OP_Noop; dbda8d6ce9 2007-07-21 drh: }else if( pLevel->flags & WHERE_ROWID_RANGE ){ dbda8d6ce9 2007-07-21 drh: /* Case 2: We have an inequality comparison against the ROWID field. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int testOp = OP_Noop; dbda8d6ce9 2007-07-21 drh: int start; dbda8d6ce9 2007-07-21 drh: WhereTerm *pStart, *pEnd; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( omitTable==0 ); dbda8d6ce9 2007-07-21 drh: pStart = findTerm(&wc, iCur, -1, notReady, WO_GT|WO_GE, 0); dbda8d6ce9 2007-07-21 drh: pEnd = findTerm(&wc, iCur, -1, notReady, WO_LT|WO_LE, 0); dbda8d6ce9 2007-07-21 drh: if( bRev ){ dbda8d6ce9 2007-07-21 drh: pTerm = pStart; dbda8d6ce9 2007-07-21 drh: pStart = pEnd; dbda8d6ce9 2007-07-21 drh: pEnd = pTerm; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pStart ){ dbda8d6ce9 2007-07-21 drh: Expr *pX; dbda8d6ce9 2007-07-21 drh: pX = pStart->pExpr; dbda8d6ce9 2007-07-21 drh: assert( pX!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pStart->leftCursor==iCur ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pX->pRight); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_ForceInt, pX->op==TK_LE || pX->op==TK_GT, brk); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "pk")); dbda8d6ce9 2007-07-21 drh: disableTerm(pLevel, pStart); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, bRev ? OP_Last : OP_Rewind, iCur, brk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pEnd ){ dbda8d6ce9 2007-07-21 drh: Expr *pX; dbda8d6ce9 2007-07-21 drh: pX = pEnd->pExpr; dbda8d6ce9 2007-07-21 drh: assert( pX!=0 ); dbda8d6ce9 2007-07-21 drh: assert( pEnd->leftCursor==iCur ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pX->pRight); dbda8d6ce9 2007-07-21 drh: pLevel->iMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); dbda8d6ce9 2007-07-21 drh: if( pX->op==TK_LT || pX->op==TK_GT ){ dbda8d6ce9 2007-07-21 drh: testOp = bRev ? OP_Le : OP_Ge; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: testOp = bRev ? OP_Lt : OP_Gt; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: disableTerm(pLevel, pEnd); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: start = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: pLevel->op = bRev ? OP_Prev : OP_Next; dbda8d6ce9 2007-07-21 drh: pLevel->p1 = iCur; dbda8d6ce9 2007-07-21 drh: pLevel->p2 = start; dbda8d6ce9 2007-07-21 drh: if( testOp!=OP_Noop ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, testOp, SQLITE_AFF_NUMERIC|0x100, brk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pLevel->flags & WHERE_COLUMN_RANGE ){ dbda8d6ce9 2007-07-21 drh: /* Case 3: The WHERE clause term that refers to the right-most dbda8d6ce9 2007-07-21 drh: ** column of the index is an inequality. For example, if dbda8d6ce9 2007-07-21 drh: ** the index is on (x,y,z) and the WHERE clause is of the dbda8d6ce9 2007-07-21 drh: ** form "x=5 AND y<10" then this case is used. Only the dbda8d6ce9 2007-07-21 drh: ** right-most column can be an inequality - the rest must dbda8d6ce9 2007-07-21 drh: ** use the "==" and "IN" operators. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This case is also used when there are no WHERE clause dbda8d6ce9 2007-07-21 drh: ** constraints but an index is selected anyway, in order dbda8d6ce9 2007-07-21 drh: ** to force the output order to conform to an ORDER BY. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int start; dbda8d6ce9 2007-07-21 drh: int nEq = pLevel->nEq; dbda8d6ce9 2007-07-21 drh: int topEq=0; /* True if top limit uses ==. False is strictly < */ dbda8d6ce9 2007-07-21 drh: int btmEq=0; /* True if btm limit uses ==. False if strictly > */ dbda8d6ce9 2007-07-21 drh: int topOp, btmOp; /* Operators for the top and bottom search bounds */ dbda8d6ce9 2007-07-21 drh: int testOp; dbda8d6ce9 2007-07-21 drh: int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0; dbda8d6ce9 2007-07-21 drh: int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code to evaluate all constraint terms using == or IN dbda8d6ce9 2007-07-21 drh: ** and level the values of those terms on the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: codeAllEqualityTerms(pParse, pLevel, &wc, notReady); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Duplicate the equality term values because they will all be dbda8d6ce9 2007-07-21 drh: ** used twice: once to make the termination key and once to make the dbda8d6ce9 2007-07-21 drh: ** start key. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(j=0; j<nEq; j++){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Dup, nEq-1, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Figure out what comparison operators to use for top and bottom dbda8d6ce9 2007-07-21 drh: ** search bounds. For an ascending index, the bottom bound is a > or >= dbda8d6ce9 2007-07-21 drh: ** operator and the top bound is a < or <= operator. For a descending dbda8d6ce9 2007-07-21 drh: ** index the operators are reversed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){ dbda8d6ce9 2007-07-21 drh: topOp = WO_LT|WO_LE; dbda8d6ce9 2007-07-21 drh: btmOp = WO_GT|WO_GE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: topOp = WO_GT|WO_GE; dbda8d6ce9 2007-07-21 drh: btmOp = WO_LT|WO_LE; dbda8d6ce9 2007-07-21 drh: SWAP(int, topLimit, btmLimit); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate the termination key. This is the key value that dbda8d6ce9 2007-07-21 drh: ** will end the search. There is no termination key if there dbda8d6ce9 2007-07-21 drh: ** are no equality terms and no "X<..." term. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2002-Dec-04: On a reverse-order scan, the so-called "termination" dbda8d6ce9 2007-07-21 drh: ** key computed here really ends up being the start key. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: nxt = pLevel->nxt; dbda8d6ce9 2007-07-21 drh: if( topLimit ){ dbda8d6ce9 2007-07-21 drh: Expr *pX; dbda8d6ce9 2007-07-21 drh: int k = pIdx->aiColumn[j]; dbda8d6ce9 2007-07-21 drh: pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx); dbda8d6ce9 2007-07-21 drh: assert( pTerm!=0 ); dbda8d6ce9 2007-07-21 drh: pX = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: assert( (pTerm->flags & TERM_CODED)==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pX->pRight); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IsNull, -(nEq*2+1), nxt); dbda8d6ce9 2007-07-21 drh: topEq = pTerm->eOperator & (WO_LE|WO_GE); dbda8d6ce9 2007-07-21 drh: disableTerm(pLevel, pTerm); dbda8d6ce9 2007-07-21 drh: testOp = OP_IdxGE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: testOp = nEq>0 ? OP_IdxGE : OP_Noop; dbda8d6ce9 2007-07-21 drh: topEq = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( testOp!=OP_Noop ){ dbda8d6ce9 2007-07-21 drh: int nCol = nEq + topLimit; dbda8d6ce9 2007-07-21 drh: pLevel->iMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: buildIndexProbe(v, nCol, pIdx); dbda8d6ce9 2007-07-21 drh: if( bRev ){ dbda8d6ce9 2007-07-21 drh: int op = topEq ? OP_MoveLe : OP_MoveLt; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, iIdxCur, nxt); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( bRev ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Last, iIdxCur, brk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate the start key. This is the key that defines the lower dbda8d6ce9 2007-07-21 drh: ** bound on the search. There is no start key if there are no dbda8d6ce9 2007-07-21 drh: ** equality terms and if there is no "X>..." term. In dbda8d6ce9 2007-07-21 drh: ** that case, generate a "Rewind" instruction in place of the dbda8d6ce9 2007-07-21 drh: ** start key search. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2002-Dec-04: In the case of a reverse-order search, the so-called dbda8d6ce9 2007-07-21 drh: ** "start" key really ends up being used as the termination key. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( btmLimit ){ dbda8d6ce9 2007-07-21 drh: Expr *pX; dbda8d6ce9 2007-07-21 drh: int k = pIdx->aiColumn[j]; dbda8d6ce9 2007-07-21 drh: pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx); dbda8d6ce9 2007-07-21 drh: assert( pTerm!=0 ); dbda8d6ce9 2007-07-21 drh: pX = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: assert( (pTerm->flags & TERM_CODED)==0 ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprCode(pParse, pX->pRight); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), nxt); dbda8d6ce9 2007-07-21 drh: btmEq = pTerm->eOperator & (WO_LE|WO_GE); dbda8d6ce9 2007-07-21 drh: disableTerm(pLevel, pTerm); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: btmEq = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nEq>0 || btmLimit ){ dbda8d6ce9 2007-07-21 drh: int nCol = nEq + btmLimit; dbda8d6ce9 2007-07-21 drh: buildIndexProbe(v, nCol, pIdx); dbda8d6ce9 2007-07-21 drh: if( bRev ){ dbda8d6ce9 2007-07-21 drh: pLevel->iMem = pParse->nMem++; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); dbda8d6ce9 2007-07-21 drh: testOp = OP_IdxLT; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: int op = btmEq ? OP_MoveGe : OP_MoveGt; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, op, iIdxCur, nxt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( bRev ){ dbda8d6ce9 2007-07-21 drh: testOp = OP_Noop; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, brk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate the the top of the loop. If there is a termination dbda8d6ce9 2007-07-21 drh: ** key we have to test for that key and abort at the top of the dbda8d6ce9 2007-07-21 drh: ** loop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: start = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: if( testOp!=OP_Noop ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, testOp, iIdxCur, nxt); dbda8d6ce9 2007-07-21 drh: if( (topEq && !bRev) || (!btmEq && bRev) ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( topLimit | btmLimit ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Column, iIdxCur, nEq); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IsNull, 1, cont); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !omitTable ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Record the instruction used to terminate the loop. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pLevel->op = bRev ? OP_Prev : OP_Next; dbda8d6ce9 2007-07-21 drh: pLevel->p1 = iIdxCur; dbda8d6ce9 2007-07-21 drh: pLevel->p2 = start; dbda8d6ce9 2007-07-21 drh: }else if( pLevel->flags & WHERE_COLUMN_EQ ){ dbda8d6ce9 2007-07-21 drh: /* Case 4: There is an index and all terms of the WHERE clause that dbda8d6ce9 2007-07-21 drh: ** refer to the index using the "==" or "IN" operators. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int start; dbda8d6ce9 2007-07-21 drh: int nEq = pLevel->nEq; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code to evaluate all constraint terms using == or IN dbda8d6ce9 2007-07-21 drh: ** and leave the values of those terms on the stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: codeAllEqualityTerms(pParse, pLevel, &wc, notReady); dbda8d6ce9 2007-07-21 drh: nxt = pLevel->nxt; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate a single key that will be used to both start and terminate dbda8d6ce9 2007-07-21 drh: ** the search dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: buildIndexProbe(v, nEq, pIdx); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate code (1) to move to the first matching element of the table. dbda8d6ce9 2007-07-21 drh: ** Then generate code (2) that jumps to "nxt" after the cursor is past dbda8d6ce9 2007-07-21 drh: ** the last matching element of the table. The code (1) is executed dbda8d6ce9 2007-07-21 drh: ** once to initialize the search, the code (2) is executed before each dbda8d6ce9 2007-07-21 drh: ** iteration of the scan to see if the scan has finished. */ dbda8d6ce9 2007-07-21 drh: if( bRev ){ dbda8d6ce9 2007-07-21 drh: /* Scan in reverse order */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, nxt); dbda8d6ce9 2007-07-21 drh: start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, nxt); dbda8d6ce9 2007-07-21 drh: pLevel->op = OP_Prev; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Scan in the forward order */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, nxt); dbda8d6ce9 2007-07-21 drh: start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, nxt, "+", P3_STATIC); dbda8d6ce9 2007-07-21 drh: pLevel->op = OP_Next; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !omitTable ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pLevel->p1 = iIdxCur; dbda8d6ce9 2007-07-21 drh: pLevel->p2 = start; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: /* Case 5: There is no usable index. We must do a complete dbda8d6ce9 2007-07-21 drh: ** scan of the entire table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: assert( omitTable==0 ); dbda8d6ce9 2007-07-21 drh: assert( bRev==0 ); dbda8d6ce9 2007-07-21 drh: pLevel->op = OP_Next; dbda8d6ce9 2007-07-21 drh: pLevel->p1 = iCur; dbda8d6ce9 2007-07-21 drh: pLevel->p2 = 1 + sqlite3VdbeAddOp(v, OP_Rewind, iCur, brk); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: notReady &= ~getMask(&maskSet, iCur); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Insert code to test every subexpression that can be completely dbda8d6ce9 2007-07-21 drh: ** computed using the current set of tables. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(pTerm=wc.a, j=wc.nTerm; j>0; j--, pTerm++){ dbda8d6ce9 2007-07-21 drh: Expr *pE; dbda8d6ce9 2007-07-21 drh: if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue; dbda8d6ce9 2007-07-21 drh: if( (pTerm->prereqAll & notReady)!=0 ) continue; dbda8d6ce9 2007-07-21 drh: pE = pTerm->pExpr; dbda8d6ce9 2007-07-21 drh: assert( pE!=0 ); dbda8d6ce9 2007-07-21 drh: if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ dbda8d6ce9 2007-07-21 drh: continue; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pE, cont, 1); dbda8d6ce9 2007-07-21 drh: pTerm->flags |= TERM_CODED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* For a LEFT OUTER JOIN, generate code that will record the fact that dbda8d6ce9 2007-07-21 drh: ** at least one row of the right table has matched the left table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pLevel->iLeftJoin ){ dbda8d6ce9 2007-07-21 drh: pLevel->top = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_MemInt, 1, pLevel->iLeftJoin); dbda8d6ce9 2007-07-21 drh: VdbeComment((v, "# record LEFT JOIN hit")); dbda8d6ce9 2007-07-21 drh: for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){ dbda8d6ce9 2007-07-21 drh: if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue; dbda8d6ce9 2007-07-21 drh: if( (pTerm->prereqAll & notReady)!=0 ) continue; dbda8d6ce9 2007-07-21 drh: assert( pTerm->pExpr ); dbda8d6ce9 2007-07-21 drh: sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, 1); dbda8d6ce9 2007-07-21 drh: pTerm->flags |= TERM_CODED; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_TEST /* For testing and debugging use only */ dbda8d6ce9 2007-07-21 drh: /* Record in the query plan information about the current table dbda8d6ce9 2007-07-21 drh: ** and the index used to access it (if any). If the table itself dbda8d6ce9 2007-07-21 drh: ** is not used, its name is just '{}'. If no index is used dbda8d6ce9 2007-07-21 drh: ** the index is listed as "{}". If the primary key is used the dbda8d6ce9 2007-07-21 drh: ** index name is '*'. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0; i<pTabList->nSrc; i++){ dbda8d6ce9 2007-07-21 drh: char *z; dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: pLevel = &pWInfo->a[i]; dbda8d6ce9 2007-07-21 drh: pTabItem = &pTabList->a[pLevel->iFrom]; dbda8d6ce9 2007-07-21 drh: z = pTabItem->zAlias; dbda8d6ce9 2007-07-21 drh: if( z==0 ) z = pTabItem->pTab->zName; dbda8d6ce9 2007-07-21 drh: n = strlen(z); dbda8d6ce9 2007-07-21 drh: if( n+nQPlan < sizeof(sqlite3_query_plan)-10 ){ dbda8d6ce9 2007-07-21 drh: if( pLevel->flags & WHERE_IDX_ONLY ){ dbda8d6ce9 2007-07-21 drh: memcpy(&sqlite3_query_plan[nQPlan], "{}", 2); dbda8d6ce9 2007-07-21 drh: nQPlan += 2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: memcpy(&sqlite3_query_plan[nQPlan], z, n); dbda8d6ce9 2007-07-21 drh: nQPlan += n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_query_plan[nQPlan++] = ' '; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){ dbda8d6ce9 2007-07-21 drh: memcpy(&sqlite3_query_plan[nQPlan], "* ", 2); dbda8d6ce9 2007-07-21 drh: nQPlan += 2; dbda8d6ce9 2007-07-21 drh: }else if( pLevel->pIdx==0 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&sqlite3_query_plan[nQPlan], "{} ", 3); dbda8d6ce9 2007-07-21 drh: nQPlan += 3; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: n = strlen(pLevel->pIdx->zName); dbda8d6ce9 2007-07-21 drh: if( n+nQPlan < sizeof(sqlite3_query_plan)-2 ){ dbda8d6ce9 2007-07-21 drh: memcpy(&sqlite3_query_plan[nQPlan], pLevel->pIdx->zName, n); dbda8d6ce9 2007-07-21 drh: nQPlan += n; dbda8d6ce9 2007-07-21 drh: sqlite3_query_plan[nQPlan++] = ' '; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( nQPlan>0 && sqlite3_query_plan[nQPlan-1]==' ' ){ dbda8d6ce9 2007-07-21 drh: sqlite3_query_plan[--nQPlan] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3_query_plan[nQPlan] = 0; dbda8d6ce9 2007-07-21 drh: nQPlan = 0; dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_TEST // Testing and debugging use only */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Record the continuation address in the WhereInfo structure. Then dbda8d6ce9 2007-07-21 drh: ** clean up and return. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pWInfo->iContinue = cont; dbda8d6ce9 2007-07-21 drh: whereClauseClear(&wc); dbda8d6ce9 2007-07-21 drh: return pWInfo; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Jump here if malloc fails */ dbda8d6ce9 2007-07-21 drh: whereBeginNoMem: dbda8d6ce9 2007-07-21 drh: whereClauseClear(&wc); dbda8d6ce9 2007-07-21 drh: whereInfoFree(pWInfo); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Generate the end of the WHERE loop. See comments on dbda8d6ce9 2007-07-21 drh: ** sqlite3WhereBegin() for additional information. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ dbda8d6ce9 2007-07-21 drh: Vdbe *v = pWInfo->pParse->pVdbe; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: WhereLevel *pLevel; dbda8d6ce9 2007-07-21 drh: SrcList *pTabList = pWInfo->pTabList; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Generate loop termination code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=pTabList->nSrc-1; i>=0; i--){ dbda8d6ce9 2007-07-21 drh: pLevel = &pWInfo->a[i]; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, pLevel->cont); dbda8d6ce9 2007-07-21 drh: if( pLevel->op!=OP_Noop ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pLevel->nIn ){ dbda8d6ce9 2007-07-21 drh: struct InLoop *pIn; dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, pLevel->nxt); dbda8d6ce9 2007-07-21 drh: for(j=pLevel->nIn, pIn=&pLevel->aInLoop[j-1]; j>0; j--, pIn--){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, pIn->topAddr+1); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Next, pIn->iCur, pIn->topAddr); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, pIn->topAddr-1); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pLevel->aInLoop); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, pLevel->brk); dbda8d6ce9 2007-07-21 drh: if( pLevel->iLeftJoin ){ dbda8d6ce9 2007-07-21 drh: int addr; dbda8d6ce9 2007-07-21 drh: addr = sqlite3VdbeAddOp(v, OP_IfMemPos, pLevel->iLeftJoin, 0); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0); dbda8d6ce9 2007-07-21 drh: if( pLevel->iIdxCur>=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top); dbda8d6ce9 2007-07-21 drh: sqlite3VdbeJumpHere(v, addr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The "break" point is here, just past the end of the outer loop. dbda8d6ce9 2007-07-21 drh: ** Set it. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeResolveLabel(v, pWInfo->iBreak); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Close all of the cursors that were opened by sqlite3WhereBegin. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ dbda8d6ce9 2007-07-21 drh: struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; dbda8d6ce9 2007-07-21 drh: Table *pTab = pTabItem->pTab; dbda8d6ce9 2007-07-21 drh: assert( pTab!=0 ); dbda8d6ce9 2007-07-21 drh: if( pTab->isEphem || pTab->pSelect ) continue; dbda8d6ce9 2007-07-21 drh: if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, pTabItem->iCursor, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pLevel->pIdx!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeAddOp(v, OP_Close, pLevel->iIdxCur, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Make cursor substitutions for cases where we want to use dbda8d6ce9 2007-07-21 drh: ** just the index and never reference the table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Calls to the code generator in between sqlite3WhereBegin and dbda8d6ce9 2007-07-21 drh: ** sqlite3WhereEnd will have created code that references the table dbda8d6ce9 2007-07-21 drh: ** directly. This loop scans all that code looking for opcodes dbda8d6ce9 2007-07-21 drh: ** that reference the table and converts them into opcodes that dbda8d6ce9 2007-07-21 drh: ** reference the index. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pLevel->flags & WHERE_IDX_ONLY ){ dbda8d6ce9 2007-07-21 drh: int k, j, last; dbda8d6ce9 2007-07-21 drh: VdbeOp *pOp; dbda8d6ce9 2007-07-21 drh: Index *pIdx = pLevel->pIdx; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( pIdx!=0 ); dbda8d6ce9 2007-07-21 drh: pOp = sqlite3VdbeGetOp(v, pWInfo->iTop); dbda8d6ce9 2007-07-21 drh: last = sqlite3VdbeCurrentAddr(v); dbda8d6ce9 2007-07-21 drh: for(k=pWInfo->iTop; k<last; k++, pOp++){ dbda8d6ce9 2007-07-21 drh: if( pOp->p1!=pLevel->iTabCur ) continue; dbda8d6ce9 2007-07-21 drh: if( pOp->opcode==OP_Column ){ dbda8d6ce9 2007-07-21 drh: pOp->p1 = pLevel->iIdxCur; dbda8d6ce9 2007-07-21 drh: for(j=0; j<pIdx->nColumn; j++){ dbda8d6ce9 2007-07-21 drh: if( pOp->p2==pIdx->aiColumn[j] ){ dbda8d6ce9 2007-07-21 drh: pOp->p2 = j; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( pOp->opcode==OP_Rowid ){ dbda8d6ce9 2007-07-21 drh: pOp->p1 = pLevel->iIdxCur; dbda8d6ce9 2007-07-21 drh: pOp->opcode = OP_IdxRowid; dbda8d6ce9 2007-07-21 drh: }else if( pOp->opcode==OP_NullRow ){ dbda8d6ce9 2007-07-21 drh: pOp->opcode = OP_Noop; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Final cleanup dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: whereInfoFree(pWInfo); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of where.c ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file parse.c *******************************************/ dbda8d6ce9 2007-07-21 drh: /* Driver template for the LEMON parser generator. dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* First off, code is include which follows the "include" declaration dbda8d6ce9 2007-07-21 drh: ** in the input file. */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of this structure holds information about the dbda8d6ce9 2007-07-21 drh: ** LIMIT clause of a SELECT statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct LimitVal { dbda8d6ce9 2007-07-21 drh: Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */ dbda8d6ce9 2007-07-21 drh: Expr *pOffset; /* The OFFSET expression. NULL if there is none */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of this structure is used to store the LIKE, dbda8d6ce9 2007-07-21 drh: ** GLOB, NOT LIKE, and NOT GLOB operators. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct LikeOp { dbda8d6ce9 2007-07-21 drh: Token eOperator; /* "like" or "glob" or "regexp" */ dbda8d6ce9 2007-07-21 drh: int not; /* True if the NOT keyword is present */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of the following structure describes the event of a dbda8d6ce9 2007-07-21 drh: ** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, dbda8d6ce9 2007-07-21 drh: ** TK_DELETE, or TK_INSTEAD. If the event is of the form dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** UPDATE ON (a,b,c) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Then the "b" IdList records the list "a,b,c". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct TrigEvent { int a; IdList * b; }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** An instance of this structure holds the ATTACH key and the key type. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct AttachKey { int type; Token key; }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Next is all token values, in a form suitable for use by makeheaders. dbda8d6ce9 2007-07-21 drh: ** This section will be null unless lemon is run with the -m switch. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** These constants (all generated automatically by the parser generator) dbda8d6ce9 2007-07-21 drh: ** specify the various kinds of tokens (terminals) that the parser dbda8d6ce9 2007-07-21 drh: ** understands. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Each symbol here is a terminal symbol in the grammar. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Make sure the INTERFACE macro is defined. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef INTERFACE dbda8d6ce9 2007-07-21 drh: # define INTERFACE 1 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: /* The next thing included is series of defines which control dbda8d6ce9 2007-07-21 drh: ** various aspects of the generated parser. dbda8d6ce9 2007-07-21 drh: ** YYCODETYPE is the data type used for storing terminal dbda8d6ce9 2007-07-21 drh: ** and nonterminal numbers. "unsigned char" is dbda8d6ce9 2007-07-21 drh: ** used if there are fewer than 250 terminals dbda8d6ce9 2007-07-21 drh: ** and nonterminals. "int" is used otherwise. dbda8d6ce9 2007-07-21 drh: ** YYNOCODE is a number of type YYCODETYPE which corresponds dbda8d6ce9 2007-07-21 drh: ** to no legal terminal or nonterminal number. This dbda8d6ce9 2007-07-21 drh: ** number is used to fill in empty slots of the hash dbda8d6ce9 2007-07-21 drh: ** table. dbda8d6ce9 2007-07-21 drh: ** YYFALLBACK If defined, this indicates that one or more tokens dbda8d6ce9 2007-07-21 drh: ** have fall-back values which should be used if the dbda8d6ce9 2007-07-21 drh: ** original value of the token will not parse. dbda8d6ce9 2007-07-21 drh: ** YYACTIONTYPE is the data type used for storing terminal dbda8d6ce9 2007-07-21 drh: ** and nonterminal numbers. "unsigned char" is dbda8d6ce9 2007-07-21 drh: ** used if there are fewer than 250 rules and dbda8d6ce9 2007-07-21 drh: ** states combined. "int" is used otherwise. dbda8d6ce9 2007-07-21 drh: ** sqlite3ParserTOKENTYPE is the data type used for minor tokens given dbda8d6ce9 2007-07-21 drh: ** directly to the parser from the tokenizer. dbda8d6ce9 2007-07-21 drh: ** YYMINORTYPE is the data type used for all minor tokens. dbda8d6ce9 2007-07-21 drh: ** This is typically a union of many types, one of dbda8d6ce9 2007-07-21 drh: ** which is sqlite3ParserTOKENTYPE. The entry in the union dbda8d6ce9 2007-07-21 drh: ** for base tokens is called "yy0". dbda8d6ce9 2007-07-21 drh: ** YYSTACKDEPTH is the maximum depth of the parser's stack. If dbda8d6ce9 2007-07-21 drh: ** zero the stack is dynamically sized using realloc() dbda8d6ce9 2007-07-21 drh: ** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument dbda8d6ce9 2007-07-21 drh: ** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument dbda8d6ce9 2007-07-21 drh: ** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser dbda8d6ce9 2007-07-21 drh: ** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser dbda8d6ce9 2007-07-21 drh: ** YYNSTATE the combined number of states. dbda8d6ce9 2007-07-21 drh: ** YYNRULE the number of rules in the grammar dbda8d6ce9 2007-07-21 drh: ** YYERRORSYMBOL is the code number of the error symbol. If not dbda8d6ce9 2007-07-21 drh: ** defined, then do no error processing. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #define YYCODETYPE unsigned char dbda8d6ce9 2007-07-21 drh: #define YYNOCODE 248 dbda8d6ce9 2007-07-21 drh: #define YYACTIONTYPE unsigned short int dbda8d6ce9 2007-07-21 drh: #define YYWILDCARD 59 dbda8d6ce9 2007-07-21 drh: #define sqlite3ParserTOKENTYPE Token dbda8d6ce9 2007-07-21 drh: typedef union { dbda8d6ce9 2007-07-21 drh: sqlite3ParserTOKENTYPE yy0; dbda8d6ce9 2007-07-21 drh: int yy46; dbda8d6ce9 2007-07-21 drh: struct LikeOp yy72; dbda8d6ce9 2007-07-21 drh: Expr* yy172; dbda8d6ce9 2007-07-21 drh: ExprList* yy174; dbda8d6ce9 2007-07-21 drh: Select* yy219; dbda8d6ce9 2007-07-21 drh: struct LimitVal yy234; dbda8d6ce9 2007-07-21 drh: TriggerStep* yy243; dbda8d6ce9 2007-07-21 drh: struct TrigEvent yy370; dbda8d6ce9 2007-07-21 drh: SrcList* yy373; dbda8d6ce9 2007-07-21 drh: Expr * yy386; dbda8d6ce9 2007-07-21 drh: struct {int value; int mask;} yy405; dbda8d6ce9 2007-07-21 drh: Token yy410; dbda8d6ce9 2007-07-21 drh: IdList* yy432; dbda8d6ce9 2007-07-21 drh: int yy495; dbda8d6ce9 2007-07-21 drh: } YYMINORTYPE; dbda8d6ce9 2007-07-21 drh: #ifndef YYSTACKDEPTH dbda8d6ce9 2007-07-21 drh: #define YYSTACKDEPTH 100 dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #define sqlite3ParserARG_SDECL Parse *pParse; dbda8d6ce9 2007-07-21 drh: #define sqlite3ParserARG_PDECL ,Parse *pParse dbda8d6ce9 2007-07-21 drh: #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse dbda8d6ce9 2007-07-21 drh: #define sqlite3ParserARG_STORE yypParser->pParse = pParse dbda8d6ce9 2007-07-21 drh: #define YYNSTATE 586 dbda8d6ce9 2007-07-21 drh: #define YYNRULE 311 dbda8d6ce9 2007-07-21 drh: #define YYERRORSYMBOL 138 dbda8d6ce9 2007-07-21 drh: #define YYERRSYMDT yy495 dbda8d6ce9 2007-07-21 drh: #define YYFALLBACK 1 dbda8d6ce9 2007-07-21 drh: #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) dbda8d6ce9 2007-07-21 drh: #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) dbda8d6ce9 2007-07-21 drh: #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Next are that tables used to determine what action to take based on the dbda8d6ce9 2007-07-21 drh: ** current state and lookahead token. These tables are used to implement dbda8d6ce9 2007-07-21 drh: ** functions that take a state number and lookahead value and return an dbda8d6ce9 2007-07-21 drh: ** action integer. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Suppose the action integer is N. Then the action is determined as dbda8d6ce9 2007-07-21 drh: ** follows dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 0 <= N < YYNSTATE Shift N. That is, push the lookahead dbda8d6ce9 2007-07-21 drh: ** token onto the stack and goto state N. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** N == YYNSTATE+YYNRULE A syntax error has occurred. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** N == YYNSTATE+YYNRULE+1 The parser accepts its input. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused dbda8d6ce9 2007-07-21 drh: ** slots in the yy_action[] table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The action table is constructed as a single large table named yy_action[]. dbda8d6ce9 2007-07-21 drh: ** Given state S and lookahead X, the action is computed as dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** yy_action[ yy_shift_ofst[S] + X ] dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the index value yy_shift_ofst[S]+X is out of range or if the value dbda8d6ce9 2007-07-21 drh: ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] dbda8d6ce9 2007-07-21 drh: ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table dbda8d6ce9 2007-07-21 drh: ** and that yy_default[S] should be used instead. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The formula above is for computing the action when the lookahead is dbda8d6ce9 2007-07-21 drh: ** a terminal symbol. If the lookahead is a non-terminal (as occurs after dbda8d6ce9 2007-07-21 drh: ** a reduce action) then the yy_reduce_ofst[] array is used in place of dbda8d6ce9 2007-07-21 drh: ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of dbda8d6ce9 2007-07-21 drh: ** YY_SHIFT_USE_DFLT. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The following are the tables generated in this section: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** yy_action[] A single table containing all actions. dbda8d6ce9 2007-07-21 drh: ** yy_lookahead[] A table containing the lookahead for each entry in dbda8d6ce9 2007-07-21 drh: ** yy_action. Used to detect hash collisions. dbda8d6ce9 2007-07-21 drh: ** yy_shift_ofst[] For each state, the offset into yy_action for dbda8d6ce9 2007-07-21 drh: ** shifting terminals. dbda8d6ce9 2007-07-21 drh: ** yy_reduce_ofst[] For each state, the offset into yy_action for dbda8d6ce9 2007-07-21 drh: ** shifting non-terminals after a reduce. dbda8d6ce9 2007-07-21 drh: ** yy_default[] Default action for each state. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const YYACTIONTYPE yy_action[] = { dbda8d6ce9 2007-07-21 drh: /* 0 */ 290, 898, 122, 585, 407, 170, 2, 437, 61, 61, dbda8d6ce9 2007-07-21 drh: /* 10 */ 61, 61, 517, 63, 63, 63, 63, 64, 64, 65, dbda8d6ce9 2007-07-21 drh: /* 20 */ 65, 65, 66, 231, 445, 209, 422, 428, 68, 63, dbda8d6ce9 2007-07-21 drh: /* 30 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 231, dbda8d6ce9 2007-07-21 drh: /* 40 */ 389, 386, 394, 449, 60, 59, 295, 432, 433, 429, dbda8d6ce9 2007-07-21 drh: /* 50 */ 429, 62, 62, 61, 61, 61, 61, 261, 63, 63, dbda8d6ce9 2007-07-21 drh: /* 60 */ 63, 63, 64, 64, 65, 65, 65, 66, 231, 290, dbda8d6ce9 2007-07-21 drh: /* 70 */ 491, 492, 437, 487, 206, 81, 67, 417, 69, 152, dbda8d6ce9 2007-07-21 drh: /* 80 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66, dbda8d6ce9 2007-07-21 drh: /* 90 */ 231, 67, 460, 69, 152, 422, 428, 571, 262, 58, dbda8d6ce9 2007-07-21 drh: /* 100 */ 64, 64, 65, 65, 65, 66, 231, 395, 396, 419, dbda8d6ce9 2007-07-21 drh: /* 110 */ 419, 419, 290, 60, 59, 295, 432, 433, 429, 429, dbda8d6ce9 2007-07-21 drh: /* 120 */ 62, 62, 61, 61, 61, 61, 315, 63, 63, 63, dbda8d6ce9 2007-07-21 drh: /* 130 */ 63, 64, 64, 65, 65, 65, 66, 231, 422, 428, dbda8d6ce9 2007-07-21 drh: /* 140 */ 93, 65, 65, 65, 66, 231, 394, 231, 412, 34, dbda8d6ce9 2007-07-21 drh: /* 150 */ 56, 296, 440, 441, 408, 486, 60, 59, 295, 432, dbda8d6ce9 2007-07-21 drh: /* 160 */ 433, 429, 429, 62, 62, 61, 61, 61, 61, 488, dbda8d6ce9 2007-07-21 drh: /* 170 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66, dbda8d6ce9 2007-07-21 drh: /* 180 */ 231, 290, 255, 522, 293, 569, 112, 406, 520, 449, dbda8d6ce9 2007-07-21 drh: /* 190 */ 329, 315, 405, 20, 437, 338, 517, 394, 530, 529, dbda8d6ce9 2007-07-21 drh: /* 200 */ 503, 445, 209, 568, 567, 206, 528, 422, 428, 147, dbda8d6ce9 2007-07-21 drh: /* 210 */ 148, 395, 396, 412, 41, 208, 149, 531, 370, 487, dbda8d6ce9 2007-07-21 drh: /* 220 */ 259, 566, 257, 417, 290, 60, 59, 295, 432, 433, dbda8d6ce9 2007-07-21 drh: /* 230 */ 429, 429, 62, 62, 61, 61, 61, 61, 315, 63, dbda8d6ce9 2007-07-21 drh: /* 240 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 231, dbda8d6ce9 2007-07-21 drh: /* 250 */ 422, 428, 445, 331, 212, 419, 419, 419, 361, 437, dbda8d6ce9 2007-07-21 drh: /* 260 */ 412, 41, 395, 396, 364, 565, 208, 290, 60, 59, dbda8d6ce9 2007-07-21 drh: /* 270 */ 295, 432, 433, 429, 429, 62, 62, 61, 61, 61, dbda8d6ce9 2007-07-21 drh: /* 280 */ 61, 394, 63, 63, 63, 63, 64, 64, 65, 65, dbda8d6ce9 2007-07-21 drh: /* 290 */ 65, 66, 231, 422, 428, 489, 298, 522, 472, 66, dbda8d6ce9 2007-07-21 drh: /* 300 */ 231, 211, 472, 224, 409, 284, 532, 20, 447, 521, dbda8d6ce9 2007-07-21 drh: /* 310 */ 166, 60, 59, 295, 432, 433, 429, 429, 62, 62, dbda8d6ce9 2007-07-21 drh: /* 320 */ 61, 61, 61, 61, 472, 63, 63, 63, 63, 64, dbda8d6ce9 2007-07-21 drh: /* 330 */ 64, 65, 65, 65, 66, 231, 207, 478, 315, 76, dbda8d6ce9 2007-07-21 drh: /* 340 */ 290, 235, 298, 55, 482, 225, 395, 396, 179, 545, dbda8d6ce9 2007-07-21 drh: /* 350 */ 492, 343, 346, 347, 67, 150, 69, 152, 337, 522, dbda8d6ce9 2007-07-21 drh: /* 360 */ 412, 35, 348, 237, 249, 368, 422, 428, 576, 20, dbda8d6ce9 2007-07-21 drh: /* 370 */ 162, 116, 239, 341, 244, 342, 174, 320, 440, 441, dbda8d6ce9 2007-07-21 drh: /* 380 */ 412, 3, 79, 250, 60, 59, 295, 432, 433, 429, dbda8d6ce9 2007-07-21 drh: /* 390 */ 429, 62, 62, 61, 61, 61, 61, 172, 63, 63, dbda8d6ce9 2007-07-21 drh: /* 400 */ 63, 63, 64, 64, 65, 65, 65, 66, 231, 290, dbda8d6ce9 2007-07-21 drh: /* 410 */ 249, 548, 232, 485, 508, 351, 315, 116, 239, 341, dbda8d6ce9 2007-07-21 drh: /* 420 */ 244, 342, 174, 179, 315, 523, 343, 346, 347, 250, dbda8d6ce9 2007-07-21 drh: /* 430 */ 218, 413, 153, 462, 509, 422, 428, 348, 412, 34, dbda8d6ce9 2007-07-21 drh: /* 440 */ 463, 208, 175, 173, 158, 233, 412, 34, 336, 547, dbda8d6ce9 2007-07-21 drh: /* 450 */ 447, 321, 166, 60, 59, 295, 432, 433, 429, 429, dbda8d6ce9 2007-07-21 drh: /* 460 */ 62, 62, 61, 61, 61, 61, 413, 63, 63, 63, dbda8d6ce9 2007-07-21 drh: /* 470 */ 63, 64, 64, 65, 65, 65, 66, 231, 290, 540, dbda8d6ce9 2007-07-21 drh: /* 480 */ 333, 515, 502, 539, 454, 569, 300, 19, 329, 142, dbda8d6ce9 2007-07-21 drh: /* 490 */ 315, 388, 315, 328, 2, 360, 455, 292, 481, 371, dbda8d6ce9 2007-07-21 drh: /* 500 */ 267, 266, 250, 568, 422, 428, 586, 389, 386, 456, dbda8d6ce9 2007-07-21 drh: /* 510 */ 206, 493, 412, 49, 412, 49, 301, 583, 889, 157, dbda8d6ce9 2007-07-21 drh: /* 520 */ 889, 494, 60, 59, 295, 432, 433, 429, 429, 62, dbda8d6ce9 2007-07-21 drh: /* 530 */ 62, 61, 61, 61, 61, 199, 63, 63, 63, 63, dbda8d6ce9 2007-07-21 drh: /* 540 */ 64, 64, 65, 65, 65, 66, 231, 290, 315, 179, dbda8d6ce9 2007-07-21 drh: /* 550 */ 436, 253, 343, 346, 347, 368, 151, 580, 306, 248, dbda8d6ce9 2007-07-21 drh: /* 560 */ 307, 450, 75, 348, 77, 380, 208, 423, 424, 413, dbda8d6ce9 2007-07-21 drh: /* 570 */ 412, 27, 317, 422, 428, 438, 1, 22, 583, 888, dbda8d6ce9 2007-07-21 drh: /* 580 */ 394, 888, 542, 476, 318, 261, 435, 435, 426, 427, dbda8d6ce9 2007-07-21 drh: /* 590 */ 413, 60, 59, 295, 432, 433, 429, 429, 62, 62, dbda8d6ce9 2007-07-21 drh: /* 600 */ 61, 61, 61, 61, 326, 63, 63, 63, 63, 64, dbda8d6ce9 2007-07-21 drh: /* 610 */ 64, 65, 65, 65, 66, 231, 290, 425, 580, 372, dbda8d6ce9 2007-07-21 drh: /* 620 */ 219, 92, 515, 9, 334, 394, 555, 394, 454, 67, dbda8d6ce9 2007-07-21 drh: /* 630 */ 394, 69, 152, 397, 398, 399, 318, 234, 435, 435, dbda8d6ce9 2007-07-21 drh: /* 640 */ 455, 316, 422, 428, 297, 395, 396, 318, 430, 435, dbda8d6ce9 2007-07-21 drh: /* 650 */ 435, 579, 289, 456, 220, 325, 5, 217, 544, 290, dbda8d6ce9 2007-07-21 drh: /* 660 */ 60, 59, 295, 432, 433, 429, 429, 62, 62, 61, dbda8d6ce9 2007-07-21 drh: /* 670 */ 61, 61, 61, 393, 63, 63, 63, 63, 64, 64, dbda8d6ce9 2007-07-21 drh: /* 680 */ 65, 65, 65, 66, 231, 422, 428, 480, 311, 390, dbda8d6ce9 2007-07-21 drh: /* 690 */ 395, 396, 395, 396, 205, 395, 396, 821, 271, 515, dbda8d6ce9 2007-07-21 drh: /* 700 */ 248, 198, 290, 60, 59, 295, 432, 433, 429, 429, dbda8d6ce9 2007-07-21 drh: /* 710 */ 62, 62, 61, 61, 61, 61, 468, 63, 63, 63, dbda8d6ce9 2007-07-21 drh: /* 720 */ 63, 64, 64, 65, 65, 65, 66, 231, 422, 428, dbda8d6ce9 2007-07-21 drh: /* 730 */ 169, 158, 261, 261, 302, 413, 274, 117, 272, 261, dbda8d6ce9 2007-07-21 drh: /* 740 */ 515, 515, 261, 515, 190, 290, 60, 70, 295, 432, dbda8d6ce9 2007-07-21 drh: /* 750 */ 433, 429, 429, 62, 62, 61, 61, 61, 61, 377, dbda8d6ce9 2007-07-21 drh: /* 760 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66, dbda8d6ce9 2007-07-21 drh: /* 770 */ 231, 422, 428, 382, 557, 303, 304, 248, 413, 318, dbda8d6ce9 2007-07-21 drh: /* 780 */ 558, 435, 435, 559, 538, 358, 538, 385, 290, 194, dbda8d6ce9 2007-07-21 drh: /* 790 */ 59, 295, 432, 433, 429, 429, 62, 62, 61, 61, dbda8d6ce9 2007-07-21 drh: /* 800 */ 61, 61, 369, 63, 63, 63, 63, 64, 64, 65, dbda8d6ce9 2007-07-21 drh: /* 810 */ 65, 65, 66, 231, 422, 428, 394, 273, 248, 248, dbda8d6ce9 2007-07-21 drh: /* 820 */ 170, 246, 437, 413, 384, 365, 176, 177, 178, 467, dbda8d6ce9 2007-07-21 drh: /* 830 */ 309, 121, 154, 126, 295, 432, 433, 429, 429, 62, dbda8d6ce9 2007-07-21 drh: /* 840 */ 62, 61, 61, 61, 61, 315, 63, 63, 63, 63, dbda8d6ce9 2007-07-21 drh: /* 850 */ 64, 64, 65, 65, 65, 66, 231, 72, 322, 175, dbda8d6ce9 2007-07-21 drh: /* 860 */ 4, 315, 261, 315, 294, 261, 413, 412, 28, 315, dbda8d6ce9 2007-07-21 drh: /* 870 */ 261, 315, 319, 72, 322, 315, 4, 418, 443, 443, dbda8d6ce9 2007-07-21 drh: /* 880 */ 294, 395, 396, 412, 23, 412, 32, 437, 319, 324, dbda8d6ce9 2007-07-21 drh: /* 890 */ 327, 412, 53, 412, 52, 315, 156, 412, 97, 449, dbda8d6ce9 2007-07-21 drh: /* 900 */ 315, 192, 315, 275, 315, 324, 376, 469, 500, 315, dbda8d6ce9 2007-07-21 drh: /* 910 */ 476, 277, 476, 163, 292, 449, 315, 412, 95, 74, dbda8d6ce9 2007-07-21 drh: /* 920 */ 73, 467, 412, 100, 412, 101, 412, 111, 72, 313, dbda8d6ce9 2007-07-21 drh: /* 930 */ 314, 412, 113, 417, 446, 74, 73, 479, 412, 16, dbda8d6ce9 2007-07-21 drh: /* 940 */ 379, 315, 181, 465, 72, 313, 314, 72, 322, 417, dbda8d6ce9 2007-07-21 drh: /* 950 */ 4, 206, 315, 184, 294, 315, 497, 498, 474, 206, dbda8d6ce9 2007-07-21 drh: /* 960 */ 171, 339, 319, 412, 98, 419, 419, 419, 420, 421, dbda8d6ce9 2007-07-21 drh: /* 970 */ 11, 359, 378, 305, 412, 33, 413, 412, 96, 324, dbda8d6ce9 2007-07-21 drh: /* 980 */ 458, 419, 419, 419, 420, 421, 11, 413, 411, 449, dbda8d6ce9 2007-07-21 drh: /* 990 */ 411, 160, 410, 315, 410, 466, 221, 222, 223, 103, dbda8d6ce9 2007-07-21 drh: /* 1000 */ 83, 471, 315, 507, 506, 315, 620, 475, 315, 74, dbda8d6ce9 2007-07-21 drh: /* 1010 */ 73, 245, 203, 21, 279, 412, 24, 437, 72, 313, dbda8d6ce9 2007-07-21 drh: /* 1020 */ 314, 280, 315, 417, 412, 54, 505, 412, 114, 315, dbda8d6ce9 2007-07-21 drh: /* 1030 */ 412, 115, 504, 201, 145, 547, 240, 510, 524, 200, dbda8d6ce9 2007-07-21 drh: /* 1040 */ 315, 511, 202, 315, 412, 25, 315, 241, 315, 18, dbda8d6ce9 2007-07-21 drh: /* 1050 */ 315, 412, 36, 315, 254, 419, 419, 419, 420, 421, dbda8d6ce9 2007-07-21 drh: /* 1060 */ 11, 256, 412, 37, 258, 412, 26, 315, 412, 38, dbda8d6ce9 2007-07-21 drh: /* 1070 */ 412, 39, 412, 40, 260, 412, 42, 315, 512, 315, dbda8d6ce9 2007-07-21 drh: /* 1080 */ 126, 315, 437, 315, 187, 375, 276, 266, 265, 412, dbda8d6ce9 2007-07-21 drh: /* 1090 */ 43, 291, 315, 252, 315, 126, 206, 581, 8, 412, dbda8d6ce9 2007-07-21 drh: /* 1100 */ 44, 412, 29, 412, 30, 412, 45, 350, 363, 126, dbda8d6ce9 2007-07-21 drh: /* 1110 */ 315, 543, 315, 126, 412, 46, 412, 47, 315, 355, dbda8d6ce9 2007-07-21 drh: /* 1120 */ 381, 551, 315, 171, 552, 315, 90, 562, 578, 90, dbda8d6ce9 2007-07-21 drh: /* 1130 */ 288, 366, 412, 48, 412, 31, 582, 367, 268, 269, dbda8d6ce9 2007-07-21 drh: /* 1140 */ 412, 10, 270, 554, 412, 50, 564, 412, 51, 278, dbda8d6ce9 2007-07-21 drh: /* 1150 */ 281, 282, 575, 144, 442, 403, 323, 226, 444, 461, dbda8d6ce9 2007-07-21 drh: /* 1160 */ 464, 242, 503, 550, 561, 513, 161, 392, 400, 516, dbda8d6ce9 2007-07-21 drh: /* 1170 */ 401, 345, 402, 7, 312, 83, 227, 332, 228, 82, dbda8d6ce9 2007-07-21 drh: /* 1180 */ 330, 57, 408, 416, 168, 78, 459, 123, 210, 414, dbda8d6ce9 2007-07-21 drh: /* 1190 */ 84, 335, 340, 299, 496, 500, 490, 229, 495, 243, dbda8d6ce9 2007-07-21 drh: /* 1200 */ 104, 247, 499, 501, 230, 285, 415, 215, 514, 518, dbda8d6ce9 2007-07-21 drh: /* 1210 */ 525, 526, 519, 236, 527, 473, 238, 352, 477, 286, dbda8d6ce9 2007-07-21 drh: /* 1220 */ 182, 356, 533, 354, 119, 183, 185, 87, 546, 130, dbda8d6ce9 2007-07-21 drh: /* 1230 */ 186, 535, 188, 140, 362, 191, 553, 216, 373, 374, dbda8d6ce9 2007-07-21 drh: /* 1240 */ 131, 560, 308, 132, 133, 572, 577, 136, 263, 134, dbda8d6ce9 2007-07-21 drh: /* 1250 */ 139, 536, 573, 391, 91, 94, 404, 574, 99, 214, dbda8d6ce9 2007-07-21 drh: /* 1260 */ 102, 621, 622, 431, 164, 434, 165, 71, 141, 17, dbda8d6ce9 2007-07-21 drh: /* 1270 */ 439, 448, 451, 155, 6, 452, 470, 110, 167, 453, dbda8d6ce9 2007-07-21 drh: /* 1280 */ 457, 124, 13, 213, 120, 80, 12, 125, 159, 483, dbda8d6ce9 2007-07-21 drh: /* 1290 */ 484, 85, 310, 105, 180, 251, 106, 118, 86, 107, dbda8d6ce9 2007-07-21 drh: /* 1300 */ 241, 344, 349, 353, 143, 534, 127, 357, 171, 189, dbda8d6ce9 2007-07-21 drh: /* 1310 */ 264, 108, 287, 128, 549, 129, 193, 537, 541, 14, dbda8d6ce9 2007-07-21 drh: /* 1320 */ 195, 88, 196, 556, 197, 137, 138, 135, 15, 563, dbda8d6ce9 2007-07-21 drh: /* 1330 */ 570, 109, 283, 146, 204, 383, 387, 899, 584, 899, dbda8d6ce9 2007-07-21 drh: /* 1340 */ 899, 899, 899, 899, 89, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: static const YYCODETYPE yy_lookahead[] = { dbda8d6ce9 2007-07-21 drh: /* 0 */ 16, 139, 140, 141, 168, 21, 144, 23, 69, 70, dbda8d6ce9 2007-07-21 drh: /* 10 */ 71, 72, 176, 74, 75, 76, 77, 78, 79, 80, dbda8d6ce9 2007-07-21 drh: /* 20 */ 81, 82, 83, 84, 78, 79, 42, 43, 73, 74, dbda8d6ce9 2007-07-21 drh: /* 30 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, dbda8d6ce9 2007-07-21 drh: /* 40 */ 1, 2, 23, 58, 60, 61, 62, 63, 64, 65, dbda8d6ce9 2007-07-21 drh: /* 50 */ 66, 67, 68, 69, 70, 71, 72, 147, 74, 75, dbda8d6ce9 2007-07-21 drh: /* 60 */ 76, 77, 78, 79, 80, 81, 82, 83, 84, 16, dbda8d6ce9 2007-07-21 drh: /* 70 */ 185, 186, 88, 88, 110, 22, 217, 92, 219, 220, dbda8d6ce9 2007-07-21 drh: /* 80 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, dbda8d6ce9 2007-07-21 drh: /* 90 */ 84, 217, 218, 219, 220, 42, 43, 238, 188, 46, dbda8d6ce9 2007-07-21 drh: /* 100 */ 78, 79, 80, 81, 82, 83, 84, 88, 89, 124, dbda8d6ce9 2007-07-21 drh: /* 110 */ 125, 126, 16, 60, 61, 62, 63, 64, 65, 66, dbda8d6ce9 2007-07-21 drh: /* 120 */ 67, 68, 69, 70, 71, 72, 147, 74, 75, 76, dbda8d6ce9 2007-07-21 drh: /* 130 */ 77, 78, 79, 80, 81, 82, 83, 84, 42, 43, dbda8d6ce9 2007-07-21 drh: /* 140 */ 44, 80, 81, 82, 83, 84, 23, 84, 169, 170, dbda8d6ce9 2007-07-21 drh: /* 150 */ 19, 164, 165, 166, 23, 169, 60, 61, 62, 63, dbda8d6ce9 2007-07-21 drh: /* 160 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 169, dbda8d6ce9 2007-07-21 drh: /* 170 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, dbda8d6ce9 2007-07-21 drh: /* 180 */ 84, 16, 14, 147, 150, 147, 21, 167, 168, 58, dbda8d6ce9 2007-07-21 drh: /* 190 */ 211, 147, 156, 157, 23, 216, 176, 23, 181, 176, dbda8d6ce9 2007-07-21 drh: /* 200 */ 177, 78, 79, 165, 166, 110, 183, 42, 43, 78, dbda8d6ce9 2007-07-21 drh: /* 210 */ 79, 88, 89, 169, 170, 228, 180, 181, 123, 88, dbda8d6ce9 2007-07-21 drh: /* 220 */ 52, 98, 54, 92, 16, 60, 61, 62, 63, 64, dbda8d6ce9 2007-07-21 drh: /* 230 */ 65, 66, 67, 68, 69, 70, 71, 72, 147, 74, dbda8d6ce9 2007-07-21 drh: /* 240 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, dbda8d6ce9 2007-07-21 drh: /* 250 */ 42, 43, 78, 209, 210, 124, 125, 126, 224, 88, dbda8d6ce9 2007-07-21 drh: /* 260 */ 169, 170, 88, 89, 230, 227, 228, 16, 60, 61, dbda8d6ce9 2007-07-21 drh: /* 270 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, dbda8d6ce9 2007-07-21 drh: /* 280 */ 72, 23, 74, 75, 76, 77, 78, 79, 80, 81, dbda8d6ce9 2007-07-21 drh: /* 290 */ 82, 83, 84, 42, 43, 160, 16, 147, 161, 83, dbda8d6ce9 2007-07-21 drh: /* 300 */ 84, 210, 161, 153, 169, 158, 156, 157, 161, 162, dbda8d6ce9 2007-07-21 drh: /* 310 */ 163, 60, 61, 62, 63, 64, 65, 66, 67, 68, dbda8d6ce9 2007-07-21 drh: /* 320 */ 69, 70, 71, 72, 161, 74, 75, 76, 77, 78, dbda8d6ce9 2007-07-21 drh: /* 330 */ 79, 80, 81, 82, 83, 84, 192, 200, 147, 131, dbda8d6ce9 2007-07-21 drh: /* 340 */ 16, 200, 16, 199, 20, 190, 88, 89, 90, 185, dbda8d6ce9 2007-07-21 drh: /* 350 */ 186, 93, 94, 95, 217, 22, 219, 220, 147, 147, dbda8d6ce9 2007-07-21 drh: /* 360 */ 169, 170, 104, 200, 84, 147, 42, 43, 156, 157, dbda8d6ce9 2007-07-21 drh: /* 370 */ 90, 91, 92, 93, 94, 95, 96, 164, 165, 166, dbda8d6ce9 2007-07-21 drh: /* 380 */ 169, 170, 131, 103, 60, 61, 62, 63, 64, 65, dbda8d6ce9 2007-07-21 drh: /* 390 */ 66, 67, 68, 69, 70, 71, 72, 155, 74, 75, dbda8d6ce9 2007-07-21 drh: /* 400 */ 76, 77, 78, 79, 80, 81, 82, 83, 84, 16, dbda8d6ce9 2007-07-21 drh: /* 410 */ 84, 11, 221, 20, 30, 16, 147, 91, 92, 93, dbda8d6ce9 2007-07-21 drh: /* 420 */ 94, 95, 96, 90, 147, 181, 93, 94, 95, 103, dbda8d6ce9 2007-07-21 drh: /* 430 */ 212, 189, 155, 27, 50, 42, 43, 104, 169, 170, dbda8d6ce9 2007-07-21 drh: /* 440 */ 34, 228, 43, 201, 202, 147, 169, 170, 206, 49, dbda8d6ce9 2007-07-21 drh: /* 450 */ 161, 162, 163, 60, 61, 62, 63, 64, 65, 66, dbda8d6ce9 2007-07-21 drh: /* 460 */ 67, 68, 69, 70, 71, 72, 189, 74, 75, 76, dbda8d6ce9 2007-07-21 drh: /* 470 */ 77, 78, 79, 80, 81, 82, 83, 84, 16, 25, dbda8d6ce9 2007-07-21 drh: /* 480 */ 211, 147, 20, 29, 12, 147, 102, 19, 211, 21, dbda8d6ce9 2007-07-21 drh: /* 490 */ 147, 141, 147, 216, 144, 41, 24, 98, 20, 99, dbda8d6ce9 2007-07-21 drh: /* 500 */ 100, 101, 103, 165, 42, 43, 0, 1, 2, 37, dbda8d6ce9 2007-07-21 drh: /* 510 */ 110, 39, 169, 170, 169, 170, 182, 19, 20, 147, dbda8d6ce9 2007-07-21 drh: /* 520 */ 22, 49, 60, 61, 62, 63, 64, 65, 66, 67, dbda8d6ce9 2007-07-21 drh: /* 530 */ 68, 69, 70, 71, 72, 155, 74, 75, 76, 77, dbda8d6ce9 2007-07-21 drh: /* 540 */ 78, 79, 80, 81, 82, 83, 84, 16, 147, 90, dbda8d6ce9 2007-07-21 drh: /* 550 */ 20, 20, 93, 94, 95, 147, 155, 59, 215, 225, dbda8d6ce9 2007-07-21 drh: /* 560 */ 215, 20, 130, 104, 132, 227, 228, 42, 43, 189, dbda8d6ce9 2007-07-21 drh: /* 570 */ 169, 170, 16, 42, 43, 20, 19, 22, 19, 20, dbda8d6ce9 2007-07-21 drh: /* 580 */ 23, 22, 18, 147, 106, 147, 108, 109, 63, 64, dbda8d6ce9 2007-07-21 drh: /* 590 */ 189, 60, 61, 62, 63, 64, 65, 66, 67, 68, dbda8d6ce9 2007-07-21 drh: /* 600 */ 69, 70, 71, 72, 186, 74, 75, 76, 77, 78, dbda8d6ce9 2007-07-21 drh: /* 610 */ 79, 80, 81, 82, 83, 84, 16, 92, 59, 55, dbda8d6ce9 2007-07-21 drh: /* 620 */ 212, 21, 147, 19, 147, 23, 188, 23, 12, 217, dbda8d6ce9 2007-07-21 drh: /* 630 */ 23, 219, 220, 7, 8, 9, 106, 147, 108, 109, dbda8d6ce9 2007-07-21 drh: /* 640 */ 24, 147, 42, 43, 208, 88, 89, 106, 92, 108, dbda8d6ce9 2007-07-21 drh: /* 650 */ 109, 244, 245, 37, 145, 39, 191, 182, 94, 16, dbda8d6ce9 2007-07-21 drh: /* 660 */ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, dbda8d6ce9 2007-07-21 drh: /* 670 */ 70, 71, 72, 147, 74, 75, 76, 77, 78, 79, dbda8d6ce9 2007-07-21 drh: /* 680 */ 80, 81, 82, 83, 84, 42, 43, 80, 142, 143, dbda8d6ce9 2007-07-21 drh: /* 690 */ 88, 89, 88, 89, 148, 88, 89, 133, 14, 147, dbda8d6ce9 2007-07-21 drh: /* 700 */ 225, 155, 16, 60, 61, 62, 63, 64, 65, 66, dbda8d6ce9 2007-07-21 drh: /* 710 */ 67, 68, 69, 70, 71, 72, 114, 74, 75, 76, dbda8d6ce9 2007-07-21 drh: /* 720 */ 77, 78, 79, 80, 81, 82, 83, 84, 42, 43, dbda8d6ce9 2007-07-21 drh: /* 730 */ 201, 202, 147, 147, 182, 189, 52, 147, 54, 147, dbda8d6ce9 2007-07-21 drh: /* 740 */ 147, 147, 147, 147, 155, 16, 60, 61, 62, 63, dbda8d6ce9 2007-07-21 drh: /* 750 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 213, dbda8d6ce9 2007-07-21 drh: /* 760 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, dbda8d6ce9 2007-07-21 drh: /* 770 */ 84, 42, 43, 188, 188, 182, 182, 225, 189, 106, dbda8d6ce9 2007-07-21 drh: /* 780 */ 188, 108, 109, 188, 99, 100, 101, 241, 16, 155, dbda8d6ce9 2007-07-21 drh: /* 790 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, dbda8d6ce9 2007-07-21 drh: /* 800 */ 71, 72, 213, 74, 75, 76, 77, 78, 79, 80, dbda8d6ce9 2007-07-21 drh: /* 810 */ 81, 82, 83, 84, 42, 43, 23, 133, 225, 225, dbda8d6ce9 2007-07-21 drh: /* 820 */ 21, 225, 23, 189, 239, 236, 99, 100, 101, 22, dbda8d6ce9 2007-07-21 drh: /* 830 */ 242, 243, 155, 22, 62, 63, 64, 65, 66, 67, dbda8d6ce9 2007-07-21 drh: /* 840 */ 68, 69, 70, 71, 72, 147, 74, 75, 76, 77, dbda8d6ce9 2007-07-21 drh: /* 850 */ 78, 79, 80, 81, 82, 83, 84, 16, 17, 43, dbda8d6ce9 2007-07-21 drh: /* 860 */ 19, 147, 147, 147, 23, 147, 189, 169, 170, 147, dbda8d6ce9 2007-07-21 drh: /* 870 */ 147, 147, 31, 16, 17, 147, 19, 147, 124, 125, dbda8d6ce9 2007-07-21 drh: /* 880 */ 23, 88, 89, 169, 170, 169, 170, 88, 31, 48, dbda8d6ce9 2007-07-21 drh: /* 890 */ 147, 169, 170, 169, 170, 147, 89, 169, 170, 58, dbda8d6ce9 2007-07-21 drh: /* 900 */ 147, 22, 147, 188, 147, 48, 188, 114, 97, 147, dbda8d6ce9 2007-07-21 drh: /* 910 */ 147, 188, 147, 19, 98, 58, 147, 169, 170, 78, dbda8d6ce9 2007-07-21 drh: /* 920 */ 79, 114, 169, 170, 169, 170, 169, 170, 87, 88, dbda8d6ce9 2007-07-21 drh: /* 930 */ 89, 169, 170, 92, 161, 78, 79, 80, 169, 170, dbda8d6ce9 2007-07-21 drh: /* 940 */ 91, 147, 155, 22, 87, 88, 89, 16, 17, 92, dbda8d6ce9 2007-07-21 drh: /* 950 */ 19, 110, 147, 155, 23, 147, 7, 8, 20, 110, dbda8d6ce9 2007-07-21 drh: /* 960 */ 22, 80, 31, 169, 170, 124, 125, 126, 127, 128, dbda8d6ce9 2007-07-21 drh: /* 970 */ 129, 208, 123, 208, 169, 170, 189, 169, 170, 48, dbda8d6ce9 2007-07-21 drh: /* 980 */ 147, 124, 125, 126, 127, 128, 129, 189, 107, 58, dbda8d6ce9 2007-07-21 drh: /* 990 */ 107, 5, 111, 147, 111, 203, 10, 11, 12, 13, dbda8d6ce9 2007-07-21 drh: /* 1000 */ 121, 147, 147, 91, 92, 147, 112, 147, 147, 78, dbda8d6ce9 2007-07-21 drh: /* 1010 */ 79, 147, 26, 19, 28, 169, 170, 23, 87, 88, dbda8d6ce9 2007-07-21 drh: /* 1020 */ 89, 35, 147, 92, 169, 170, 178, 169, 170, 147, dbda8d6ce9 2007-07-21 drh: /* 1030 */ 169, 170, 147, 47, 113, 49, 92, 178, 147, 53, dbda8d6ce9 2007-07-21 drh: /* 1040 */ 147, 178, 56, 147, 169, 170, 147, 103, 147, 19, dbda8d6ce9 2007-07-21 drh: /* 1050 */ 147, 169, 170, 147, 147, 124, 125, 126, 127, 128, dbda8d6ce9 2007-07-21 drh: /* 1060 */ 129, 147, 169, 170, 147, 169, 170, 147, 169, 170, dbda8d6ce9 2007-07-21 drh: /* 1070 */ 169, 170, 169, 170, 147, 169, 170, 147, 20, 147, dbda8d6ce9 2007-07-21 drh: /* 1080 */ 22, 147, 88, 147, 232, 99, 100, 101, 147, 169, dbda8d6ce9 2007-07-21 drh: /* 1090 */ 170, 105, 147, 20, 147, 22, 110, 20, 68, 169, dbda8d6ce9 2007-07-21 drh: /* 1100 */ 170, 169, 170, 169, 170, 169, 170, 20, 147, 22, dbda8d6ce9 2007-07-21 drh: /* 1110 */ 147, 20, 147, 22, 169, 170, 169, 170, 147, 233, dbda8d6ce9 2007-07-21 drh: /* 1120 */ 134, 20, 147, 22, 20, 147, 22, 20, 20, 22, dbda8d6ce9 2007-07-21 drh: /* 1130 */ 22, 147, 169, 170, 169, 170, 59, 147, 147, 147, dbda8d6ce9 2007-07-21 drh: /* 1140 */ 169, 170, 147, 147, 169, 170, 147, 169, 170, 147, dbda8d6ce9 2007-07-21 drh: /* 1150 */ 147, 147, 147, 191, 229, 149, 223, 193, 229, 172, dbda8d6ce9 2007-07-21 drh: /* 1160 */ 172, 172, 177, 194, 194, 172, 6, 146, 146, 172, dbda8d6ce9 2007-07-21 drh: /* 1170 */ 146, 173, 146, 22, 154, 121, 194, 118, 195, 119, dbda8d6ce9 2007-07-21 drh: /* 1180 */ 116, 120, 23, 160, 112, 130, 152, 152, 222, 189, dbda8d6ce9 2007-07-21 drh: /* 1190 */ 98, 115, 98, 40, 179, 97, 171, 196, 171, 171, dbda8d6ce9 2007-07-21 drh: /* 1200 */ 19, 84, 173, 171, 197, 174, 198, 226, 160, 160, dbda8d6ce9 2007-07-21 drh: /* 1210 */ 171, 171, 179, 204, 171, 205, 204, 15, 205, 174, dbda8d6ce9 2007-07-21 drh: /* 1220 */ 151, 38, 152, 152, 60, 151, 151, 130, 184, 19, dbda8d6ce9 2007-07-21 drh: /* 1230 */ 152, 152, 151, 214, 152, 184, 194, 226, 152, 15, dbda8d6ce9 2007-07-21 drh: /* 1240 */ 187, 194, 152, 187, 187, 33, 137, 184, 234, 187, dbda8d6ce9 2007-07-21 drh: /* 1250 */ 214, 235, 152, 1, 237, 237, 20, 152, 159, 175, dbda8d6ce9 2007-07-21 drh: /* 1260 */ 175, 112, 112, 92, 112, 107, 112, 19, 19, 231, dbda8d6ce9 2007-07-21 drh: /* 1270 */ 20, 20, 11, 19, 117, 20, 114, 240, 22, 20, dbda8d6ce9 2007-07-21 drh: /* 1280 */ 20, 19, 117, 44, 243, 22, 22, 20, 112, 20, dbda8d6ce9 2007-07-21 drh: /* 1290 */ 20, 19, 246, 19, 96, 20, 19, 32, 19, 19, dbda8d6ce9 2007-07-21 drh: /* 1300 */ 103, 44, 44, 16, 21, 17, 98, 36, 22, 98, dbda8d6ce9 2007-07-21 drh: /* 1310 */ 133, 19, 5, 45, 1, 102, 122, 51, 45, 19, dbda8d6ce9 2007-07-21 drh: /* 1320 */ 113, 68, 14, 17, 115, 102, 122, 113, 19, 123, dbda8d6ce9 2007-07-21 drh: /* 1330 */ 20, 14, 136, 19, 135, 57, 3, 247, 4, 247, dbda8d6ce9 2007-07-21 drh: /* 1340 */ 247, 247, 247, 247, 68, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #define YY_SHIFT_USE_DFLT (-62) dbda8d6ce9 2007-07-21 drh: #define YY_SHIFT_MAX 387 dbda8d6ce9 2007-07-21 drh: static const short yy_shift_ofst[] = { dbda8d6ce9 2007-07-21 drh: /* 0 */ 39, 841, 986, -16, 841, 931, 931, 258, 123, -36, dbda8d6ce9 2007-07-21 drh: /* 10 */ 96, 931, 931, 931, 931, 931, -45, 400, 174, 19, dbda8d6ce9 2007-07-21 drh: /* 20 */ 171, -54, -54, 53, 165, 208, 251, 324, 393, 462, dbda8d6ce9 2007-07-21 drh: /* 30 */ 531, 600, 643, 686, 643, 643, 643, 643, 643, 643, dbda8d6ce9 2007-07-21 drh: /* 40 */ 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, dbda8d6ce9 2007-07-21 drh: /* 50 */ 643, 643, 729, 772, 772, 857, 931, 931, 931, 931, dbda8d6ce9 2007-07-21 drh: /* 60 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, dbda8d6ce9 2007-07-21 drh: /* 70 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, dbda8d6ce9 2007-07-21 drh: /* 80 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, dbda8d6ce9 2007-07-21 drh: /* 90 */ 931, 931, 931, 931, 931, -61, -61, 6, 6, 280, dbda8d6ce9 2007-07-21 drh: /* 100 */ 22, 61, 399, 564, 19, 19, 19, 19, 19, 19, dbda8d6ce9 2007-07-21 drh: /* 110 */ 19, 216, 171, 63, -62, -62, 131, 326, 472, 472, dbda8d6ce9 2007-07-21 drh: /* 120 */ 498, 559, 506, 799, 19, 799, 19, 19, 19, 19, dbda8d6ce9 2007-07-21 drh: /* 130 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 849, dbda8d6ce9 2007-07-21 drh: /* 140 */ 95, -36, -36, -36, -62, -62, -62, -15, -15, 333, dbda8d6ce9 2007-07-21 drh: /* 150 */ 459, 478, 557, 530, 541, 616, 602, 793, 604, 607, dbda8d6ce9 2007-07-21 drh: /* 160 */ 626, 19, 19, 881, 19, 19, 994, 19, 19, 807, dbda8d6ce9 2007-07-21 drh: /* 170 */ 19, 19, 673, 807, 19, 19, 384, 384, 384, 19, dbda8d6ce9 2007-07-21 drh: /* 180 */ 19, 673, 19, 19, 673, 19, 454, 685, 19, 19, dbda8d6ce9 2007-07-21 drh: /* 190 */ 673, 19, 19, 19, 673, 19, 19, 19, 673, 673, dbda8d6ce9 2007-07-21 drh: /* 200 */ 19, 19, 19, 19, 19, 468, 883, 921, 754, 754, dbda8d6ce9 2007-07-21 drh: /* 210 */ 432, 406, 406, 406, 816, 406, 406, 811, 879, 879, dbda8d6ce9 2007-07-21 drh: /* 220 */ 1160, 1160, 1160, 1160, 1151, -36, 1054, 1059, 1060, 1064, dbda8d6ce9 2007-07-21 drh: /* 230 */ 1061, 1159, 1055, 1072, 1072, 1092, 1076, 1092, 1076, 1094, dbda8d6ce9 2007-07-21 drh: /* 240 */ 1094, 1153, 1094, 1098, 1094, 1181, 1117, 1159, 1117, 1159, dbda8d6ce9 2007-07-21 drh: /* 250 */ 1153, 1094, 1094, 1094, 1181, 1202, 1072, 1202, 1072, 1202, dbda8d6ce9 2007-07-21 drh: /* 260 */ 1072, 1072, 1183, 1097, 1202, 1072, 1164, 1164, 1210, 1054, dbda8d6ce9 2007-07-21 drh: /* 270 */ 1072, 1224, 1224, 1224, 1224, 1054, 1164, 1210, 1072, 1212, dbda8d6ce9 2007-07-21 drh: /* 280 */ 1212, 1072, 1072, 1109, -62, -62, -62, -62, -62, -62, dbda8d6ce9 2007-07-21 drh: /* 290 */ 525, 684, 727, 168, 894, 556, 555, 938, 944, 949, dbda8d6ce9 2007-07-21 drh: /* 300 */ 912, 1058, 1073, 1087, 1091, 1101, 1104, 1107, 1030, 1108, dbda8d6ce9 2007-07-21 drh: /* 310 */ 1077, 1252, 1236, 1149, 1150, 1152, 1154, 1171, 1158, 1248, dbda8d6ce9 2007-07-21 drh: /* 320 */ 1250, 1251, 1249, 1261, 1254, 1255, 1256, 1259, 1260, 1263, dbda8d6ce9 2007-07-21 drh: /* 330 */ 1157, 1264, 1165, 1263, 1162, 1262, 1267, 1176, 1269, 1270, dbda8d6ce9 2007-07-21 drh: /* 340 */ 1265, 1239, 1272, 1257, 1274, 1275, 1277, 1279, 1258, 1280, dbda8d6ce9 2007-07-21 drh: /* 350 */ 1198, 1197, 1287, 1288, 1283, 1208, 1271, 1266, 1268, 1286, dbda8d6ce9 2007-07-21 drh: /* 360 */ 1273, 1177, 1211, 1292, 1307, 1313, 1213, 1253, 1276, 1194, dbda8d6ce9 2007-07-21 drh: /* 370 */ 1300, 1207, 1308, 1209, 1306, 1214, 1223, 1204, 1309, 1206, dbda8d6ce9 2007-07-21 drh: /* 380 */ 1310, 1317, 1278, 1199, 1196, 1314, 1333, 1334, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #define YY_REDUCE_USE_DFLT (-165) dbda8d6ce9 2007-07-21 drh: #define YY_REDUCE_MAX 289 dbda8d6ce9 2007-07-21 drh: static const short yy_reduce_ofst[] = { dbda8d6ce9 2007-07-21 drh: /* 0 */ -138, 277, 546, 137, 401, -21, 44, 36, 38, 242, dbda8d6ce9 2007-07-21 drh: /* 10 */ -141, 191, 91, 269, 343, 345, -126, 589, 338, 150, dbda8d6ce9 2007-07-21 drh: /* 20 */ 147, -13, 213, 412, 412, 412, 412, 412, 412, 412, dbda8d6ce9 2007-07-21 drh: /* 30 */ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, dbda8d6ce9 2007-07-21 drh: /* 40 */ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, dbda8d6ce9 2007-07-21 drh: /* 50 */ 412, 412, 412, 412, 412, 211, 698, 714, 716, 722, dbda8d6ce9 2007-07-21 drh: /* 60 */ 724, 728, 748, 753, 755, 757, 762, 769, 794, 805, dbda8d6ce9 2007-07-21 drh: /* 70 */ 808, 846, 855, 858, 861, 875, 882, 893, 896, 899, dbda8d6ce9 2007-07-21 drh: /* 80 */ 901, 903, 906, 920, 930, 932, 934, 936, 945, 947, dbda8d6ce9 2007-07-21 drh: /* 90 */ 963, 965, 971, 975, 978, 412, 412, 412, 412, 20, dbda8d6ce9 2007-07-21 drh: /* 100 */ 412, 412, 23, 34, 334, 475, 552, 593, 594, 585, dbda8d6ce9 2007-07-21 drh: /* 110 */ 212, 412, 289, 412, 412, 412, 135, -164, -115, 164, dbda8d6ce9 2007-07-21 drh: /* 120 */ 407, 407, 350, 141, 436, 163, 596, -90, 763, 218, dbda8d6ce9 2007-07-21 drh: /* 130 */ 765, 438, 586, 592, 595, 715, 718, 408, 723, 380, dbda8d6ce9 2007-07-21 drh: /* 140 */ 634, 677, 787, 798, 144, 529, 588, -14, 0, 17, dbda8d6ce9 2007-07-21 drh: /* 150 */ 244, 155, 298, 155, 155, 418, 372, 477, 490, 494, dbda8d6ce9 2007-07-21 drh: /* 160 */ 509, 526, 590, 465, 494, 730, 773, 743, 833, 792, dbda8d6ce9 2007-07-21 drh: /* 170 */ 854, 860, 155, 792, 864, 885, 848, 859, 863, 891, dbda8d6ce9 2007-07-21 drh: /* 180 */ 907, 155, 914, 917, 155, 927, 852, 886, 941, 961, dbda8d6ce9 2007-07-21 drh: /* 190 */ 155, 984, 990, 991, 155, 992, 995, 996, 155, 155, dbda8d6ce9 2007-07-21 drh: /* 200 */ 999, 1002, 1003, 1004, 1005, 1006, 962, 964, 925, 929, dbda8d6ce9 2007-07-21 drh: /* 210 */ 933, 987, 988, 989, 985, 993, 997, 998, 969, 970, dbda8d6ce9 2007-07-21 drh: /* 220 */ 1021, 1022, 1024, 1026, 1020, 1000, 982, 983, 1001, 1007, dbda8d6ce9 2007-07-21 drh: /* 230 */ 1008, 1023, 966, 1034, 1035, 1009, 1010, 1012, 1013, 1025, dbda8d6ce9 2007-07-21 drh: /* 240 */ 1027, 1015, 1028, 1029, 1032, 1031, 981, 1048, 1011, 1049, dbda8d6ce9 2007-07-21 drh: /* 250 */ 1033, 1039, 1040, 1043, 1045, 1069, 1070, 1074, 1071, 1075, dbda8d6ce9 2007-07-21 drh: /* 260 */ 1078, 1079, 1014, 1016, 1081, 1082, 1044, 1051, 1019, 1042, dbda8d6ce9 2007-07-21 drh: /* 270 */ 1086, 1053, 1056, 1057, 1062, 1047, 1063, 1036, 1090, 1017, dbda8d6ce9 2007-07-21 drh: /* 280 */ 1018, 1100, 1105, 1037, 1099, 1084, 1085, 1038, 1041, 1046, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: static const YYACTIONTYPE yy_default[] = { dbda8d6ce9 2007-07-21 drh: /* 0 */ 592, 816, 897, 707, 897, 816, 897, 897, 843, 711, dbda8d6ce9 2007-07-21 drh: /* 10 */ 872, 814, 897, 897, 897, 897, 789, 897, 843, 897, dbda8d6ce9 2007-07-21 drh: /* 20 */ 623, 843, 843, 740, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 30 */ 897, 897, 741, 897, 818, 813, 809, 811, 810, 817, dbda8d6ce9 2007-07-21 drh: /* 40 */ 742, 731, 738, 745, 723, 856, 747, 748, 754, 755, dbda8d6ce9 2007-07-21 drh: /* 50 */ 873, 871, 777, 776, 795, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 60 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 70 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 80 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 90 */ 897, 897, 897, 897, 897, 779, 800, 778, 788, 616, dbda8d6ce9 2007-07-21 drh: /* 100 */ 780, 781, 676, 611, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 110 */ 897, 782, 897, 783, 796, 797, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 120 */ 897, 897, 592, 707, 897, 707, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 130 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 140 */ 897, 897, 897, 897, 701, 711, 890, 897, 897, 667, dbda8d6ce9 2007-07-21 drh: /* 150 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 160 */ 599, 597, 897, 699, 897, 897, 625, 897, 897, 709, dbda8d6ce9 2007-07-21 drh: /* 170 */ 897, 897, 714, 715, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 180 */ 897, 613, 897, 897, 688, 897, 849, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 190 */ 863, 897, 897, 897, 861, 897, 897, 897, 690, 750, dbda8d6ce9 2007-07-21 drh: /* 200 */ 830, 897, 876, 878, 897, 897, 699, 708, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 210 */ 812, 734, 734, 734, 646, 734, 734, 649, 744, 744, dbda8d6ce9 2007-07-21 drh: /* 220 */ 596, 596, 596, 596, 666, 897, 744, 735, 737, 727, dbda8d6ce9 2007-07-21 drh: /* 230 */ 739, 897, 897, 716, 716, 724, 726, 724, 726, 678, dbda8d6ce9 2007-07-21 drh: /* 240 */ 678, 663, 678, 649, 678, 822, 827, 897, 827, 897, dbda8d6ce9 2007-07-21 drh: /* 250 */ 663, 678, 678, 678, 822, 608, 716, 608, 716, 608, dbda8d6ce9 2007-07-21 drh: /* 260 */ 716, 716, 853, 855, 608, 716, 680, 680, 756, 744, dbda8d6ce9 2007-07-21 drh: /* 270 */ 716, 687, 687, 687, 687, 744, 680, 756, 716, 875, dbda8d6ce9 2007-07-21 drh: /* 280 */ 875, 716, 716, 883, 633, 651, 651, 858, 890, 895, dbda8d6ce9 2007-07-21 drh: /* 290 */ 897, 897, 897, 897, 763, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 300 */ 897, 897, 897, 897, 897, 897, 897, 897, 836, 897, dbda8d6ce9 2007-07-21 drh: /* 310 */ 897, 897, 897, 768, 764, 897, 765, 897, 693, 897, dbda8d6ce9 2007-07-21 drh: /* 320 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 815, dbda8d6ce9 2007-07-21 drh: /* 330 */ 897, 728, 897, 736, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 340 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 350 */ 897, 897, 897, 897, 897, 897, 897, 897, 851, 852, dbda8d6ce9 2007-07-21 drh: /* 360 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 370 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, dbda8d6ce9 2007-07-21 drh: /* 380 */ 897, 897, 882, 897, 897, 885, 593, 897, 587, 590, dbda8d6ce9 2007-07-21 drh: /* 390 */ 589, 591, 595, 598, 620, 621, 622, 600, 601, 602, dbda8d6ce9 2007-07-21 drh: /* 400 */ 603, 604, 605, 606, 612, 614, 632, 634, 618, 636, dbda8d6ce9 2007-07-21 drh: /* 410 */ 697, 698, 760, 691, 692, 696, 771, 762, 766, 767, dbda8d6ce9 2007-07-21 drh: /* 420 */ 769, 770, 784, 785, 787, 793, 799, 802, 786, 791, dbda8d6ce9 2007-07-21 drh: /* 430 */ 792, 794, 798, 801, 694, 695, 805, 619, 626, 627, dbda8d6ce9 2007-07-21 drh: /* 440 */ 630, 631, 839, 841, 840, 842, 629, 628, 772, 775, dbda8d6ce9 2007-07-21 drh: /* 450 */ 807, 808, 864, 865, 866, 867, 868, 803, 717, 806, dbda8d6ce9 2007-07-21 drh: /* 460 */ 790, 729, 732, 733, 730, 700, 710, 719, 720, 721, dbda8d6ce9 2007-07-21 drh: /* 470 */ 722, 705, 706, 712, 725, 758, 759, 713, 702, 703, dbda8d6ce9 2007-07-21 drh: /* 480 */ 704, 804, 761, 773, 774, 637, 638, 768, 639, 640, dbda8d6ce9 2007-07-21 drh: /* 490 */ 641, 679, 682, 683, 684, 642, 661, 664, 665, 643, dbda8d6ce9 2007-07-21 drh: /* 500 */ 650, 644, 645, 652, 653, 654, 657, 658, 659, 660, dbda8d6ce9 2007-07-21 drh: /* 510 */ 655, 656, 823, 824, 828, 826, 825, 647, 648, 662, dbda8d6ce9 2007-07-21 drh: /* 520 */ 635, 624, 617, 668, 671, 672, 673, 674, 675, 677, dbda8d6ce9 2007-07-21 drh: /* 530 */ 669, 670, 615, 607, 609, 718, 845, 854, 850, 846, dbda8d6ce9 2007-07-21 drh: /* 540 */ 847, 848, 610, 819, 820, 681, 752, 753, 844, 857, dbda8d6ce9 2007-07-21 drh: /* 550 */ 859, 757, 860, 862, 887, 685, 686, 689, 829, 869, dbda8d6ce9 2007-07-21 drh: /* 560 */ 743, 746, 749, 751, 831, 832, 833, 834, 837, 838, dbda8d6ce9 2007-07-21 drh: /* 570 */ 835, 870, 874, 877, 879, 880, 881, 884, 886, 891, dbda8d6ce9 2007-07-21 drh: /* 580 */ 892, 893, 896, 894, 594, 588, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0])) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The next table maps tokens into fallback tokens. If a construct dbda8d6ce9 2007-07-21 drh: ** like the following: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** %fallback ID X Y Z. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** appears in the grammer, then ID becomes a fallback token for X, Y, dbda8d6ce9 2007-07-21 drh: ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser dbda8d6ce9 2007-07-21 drh: ** but it does not parse, the type of the token is changed to ID and dbda8d6ce9 2007-07-21 drh: ** the parse is retried before an error is thrown. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef YYFALLBACK dbda8d6ce9 2007-07-21 drh: static const YYCODETYPE yyFallback[] = { dbda8d6ce9 2007-07-21 drh: 0, /* $ => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* SEMI => nothing */ dbda8d6ce9 2007-07-21 drh: 23, /* EXPLAIN => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* QUERY => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* PLAN => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* BEGIN => ID */ dbda8d6ce9 2007-07-21 drh: 0, /* TRANSACTION => nothing */ dbda8d6ce9 2007-07-21 drh: 23, /* DEFERRED => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* IMMEDIATE => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* EXCLUSIVE => ID */ dbda8d6ce9 2007-07-21 drh: 0, /* COMMIT => nothing */ dbda8d6ce9 2007-07-21 drh: 23, /* END => ID */ dbda8d6ce9 2007-07-21 drh: 0, /* ROLLBACK => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* CREATE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* TABLE => nothing */ dbda8d6ce9 2007-07-21 drh: 23, /* IF => ID */ dbda8d6ce9 2007-07-21 drh: 0, /* NOT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* EXISTS => nothing */ dbda8d6ce9 2007-07-21 drh: 23, /* TEMP => ID */ dbda8d6ce9 2007-07-21 drh: 0, /* LP => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* RP => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* AS => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* COMMA => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ID => nothing */ dbda8d6ce9 2007-07-21 drh: 23, /* ABORT => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* AFTER => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* ANALYZE => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* ASC => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* ATTACH => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* BEFORE => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* CASCADE => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* CAST => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* CONFLICT => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* DATABASE => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* DESC => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* DETACH => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* EACH => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* FAIL => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* FOR => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* IGNORE => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* INITIALLY => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* INSTEAD => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* LIKE_KW => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* MATCH => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* KEY => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* OF => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* OFFSET => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* PRAGMA => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* RAISE => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* REPLACE => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* RESTRICT => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* ROW => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* TRIGGER => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* VACUUM => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* VIEW => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* VIRTUAL => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* REINDEX => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* RENAME => ID */ dbda8d6ce9 2007-07-21 drh: 23, /* CTIME_KW => ID */ dbda8d6ce9 2007-07-21 drh: 0, /* ANY => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* OR => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* AND => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* IS => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* BETWEEN => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* IN => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ISNULL => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* NOTNULL => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* NE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* EQ => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* GT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* LE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* LT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* GE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ESCAPE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* BITAND => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* BITOR => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* LSHIFT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* RSHIFT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* PLUS => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* MINUS => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* STAR => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* SLASH => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* REM => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* CONCAT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* COLLATE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* UMINUS => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* UPLUS => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* BITNOT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* STRING => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* JOIN_KW => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* CONSTRAINT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* DEFAULT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* NULL => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* PRIMARY => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* UNIQUE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* CHECK => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* REFERENCES => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* AUTOINCR => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ON => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* DELETE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* UPDATE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* INSERT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* SET => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* DEFERRABLE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* FOREIGN => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* DROP => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* UNION => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ALL => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* EXCEPT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* INTERSECT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* SELECT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* DISTINCT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* DOT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* FROM => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* JOIN => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* USING => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ORDER => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* BY => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* GROUP => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* HAVING => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* LIMIT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* WHERE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* INTO => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* VALUES => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* INTEGER => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* FLOAT => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* BLOB => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* REGISTER => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* VARIABLE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* CASE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* WHEN => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* THEN => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ELSE => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* INDEX => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ALTER => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* TO => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* ADD => nothing */ dbda8d6ce9 2007-07-21 drh: 0, /* COLUMNKW => nothing */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #endif /* YYFALLBACK */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following structure represents a single element of the dbda8d6ce9 2007-07-21 drh: ** parser's stack. Information stored includes: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** + The state number for the parser at this level of the stack. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** + The value of the token stored at this level of the stack. dbda8d6ce9 2007-07-21 drh: ** (In other words, the "major" token.) dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** + The semantic value stored at this level of the stack. This is dbda8d6ce9 2007-07-21 drh: ** the information used by the action routines in the grammar. dbda8d6ce9 2007-07-21 drh: ** It is sometimes called the "minor" token. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct yyStackEntry { dbda8d6ce9 2007-07-21 drh: int stateno; /* The state-number */ dbda8d6ce9 2007-07-21 drh: int major; /* The major token value. This is the code dbda8d6ce9 2007-07-21 drh: ** number for the token at this stack level */ dbda8d6ce9 2007-07-21 drh: YYMINORTYPE minor; /* The user-supplied minor token value. This dbda8d6ce9 2007-07-21 drh: ** is the value of the token */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: typedef struct yyStackEntry yyStackEntry; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The state of the parser is completely contained in an instance of dbda8d6ce9 2007-07-21 drh: ** the following structure */ dbda8d6ce9 2007-07-21 drh: struct yyParser { dbda8d6ce9 2007-07-21 drh: int yyidx; /* Index of top element in stack */ dbda8d6ce9 2007-07-21 drh: int yyerrcnt; /* Shifts left before out of the error */ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ dbda8d6ce9 2007-07-21 drh: #if YYSTACKDEPTH<=0 dbda8d6ce9 2007-07-21 drh: int yystksz; /* Current side of the stack */ dbda8d6ce9 2007-07-21 drh: yyStackEntry *yystack; /* The parser's stack */ dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: typedef struct yyParser yyParser; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: static FILE *yyTraceFILE = 0; dbda8d6ce9 2007-07-21 drh: static char *yyTracePrompt = 0; dbda8d6ce9 2007-07-21 drh: #endif /* NDEBUG */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Turn parser tracing on by giving a stream to which to write the trace dbda8d6ce9 2007-07-21 drh: ** and a prompt to preface each trace message. Tracing is turned off dbda8d6ce9 2007-07-21 drh: ** by making either argument NULL dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Inputs: dbda8d6ce9 2007-07-21 drh: ** <ul> dbda8d6ce9 2007-07-21 drh: ** <li> A FILE* to which trace output should be written. dbda8d6ce9 2007-07-21 drh: ** If NULL, then tracing is turned off. dbda8d6ce9 2007-07-21 drh: ** <li> A prefix string written at the beginning of every dbda8d6ce9 2007-07-21 drh: ** line of trace output. If NULL, then tracing is dbda8d6ce9 2007-07-21 drh: ** turned off. dbda8d6ce9 2007-07-21 drh: ** </ul> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Outputs: dbda8d6ce9 2007-07-21 drh: ** None. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){ dbda8d6ce9 2007-07-21 drh: yyTraceFILE = TraceFILE; dbda8d6ce9 2007-07-21 drh: yyTracePrompt = zTracePrompt; dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE==0 ) yyTracePrompt = 0; dbda8d6ce9 2007-07-21 drh: else if( yyTracePrompt==0 ) yyTraceFILE = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* NDEBUG */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* For tracing shifts, the names of all terminals and nonterminals dbda8d6ce9 2007-07-21 drh: ** are required. The following table supplies these names */ dbda8d6ce9 2007-07-21 drh: static const char *const yyTokenName[] = { dbda8d6ce9 2007-07-21 drh: "$", "SEMI", "EXPLAIN", "QUERY", dbda8d6ce9 2007-07-21 drh: "PLAN", "BEGIN", "TRANSACTION", "DEFERRED", dbda8d6ce9 2007-07-21 drh: "IMMEDIATE", "EXCLUSIVE", "COMMIT", "END", dbda8d6ce9 2007-07-21 drh: "ROLLBACK", "CREATE", "TABLE", "IF", dbda8d6ce9 2007-07-21 drh: "NOT", "EXISTS", "TEMP", "LP", dbda8d6ce9 2007-07-21 drh: "RP", "AS", "COMMA", "ID", dbda8d6ce9 2007-07-21 drh: "ABORT", "AFTER", "ANALYZE", "ASC", dbda8d6ce9 2007-07-21 drh: "ATTACH", "BEFORE", "CASCADE", "CAST", dbda8d6ce9 2007-07-21 drh: "CONFLICT", "DATABASE", "DESC", "DETACH", dbda8d6ce9 2007-07-21 drh: "EACH", "FAIL", "FOR", "IGNORE", dbda8d6ce9 2007-07-21 drh: "INITIALLY", "INSTEAD", "LIKE_KW", "MATCH", dbda8d6ce9 2007-07-21 drh: "KEY", "OF", "OFFSET", "PRAGMA", dbda8d6ce9 2007-07-21 drh: "RAISE", "REPLACE", "RESTRICT", "ROW", dbda8d6ce9 2007-07-21 drh: "TRIGGER", "VACUUM", "VIEW", "VIRTUAL", dbda8d6ce9 2007-07-21 drh: "REINDEX", "RENAME", "CTIME_KW", "ANY", dbda8d6ce9 2007-07-21 drh: "OR", "AND", "IS", "BETWEEN", dbda8d6ce9 2007-07-21 drh: "IN", "ISNULL", "NOTNULL", "NE", dbda8d6ce9 2007-07-21 drh: "EQ", "GT", "LE", "LT", dbda8d6ce9 2007-07-21 drh: "GE", "ESCAPE", "BITAND", "BITOR", dbda8d6ce9 2007-07-21 drh: "LSHIFT", "RSHIFT", "PLUS", "MINUS", dbda8d6ce9 2007-07-21 drh: "STAR", "SLASH", "REM", "CONCAT", dbda8d6ce9 2007-07-21 drh: "COLLATE", "UMINUS", "UPLUS", "BITNOT", dbda8d6ce9 2007-07-21 drh: "STRING", "JOIN_KW", "CONSTRAINT", "DEFAULT", dbda8d6ce9 2007-07-21 drh: "NULL", "PRIMARY", "UNIQUE", "CHECK", dbda8d6ce9 2007-07-21 drh: "REFERENCES", "AUTOINCR", "ON", "DELETE", dbda8d6ce9 2007-07-21 drh: "UPDATE", "INSERT", "SET", "DEFERRABLE", dbda8d6ce9 2007-07-21 drh: "FOREIGN", "DROP", "UNION", "ALL", dbda8d6ce9 2007-07-21 drh: "EXCEPT", "INTERSECT", "SELECT", "DISTINCT", dbda8d6ce9 2007-07-21 drh: "DOT", "FROM", "JOIN", "USING", dbda8d6ce9 2007-07-21 drh: "ORDER", "BY", "GROUP", "HAVING", dbda8d6ce9 2007-07-21 drh: "LIMIT", "WHERE", "INTO", "VALUES", dbda8d6ce9 2007-07-21 drh: "INTEGER", "FLOAT", "BLOB", "REGISTER", dbda8d6ce9 2007-07-21 drh: "VARIABLE", "CASE", "WHEN", "THEN", dbda8d6ce9 2007-07-21 drh: "ELSE", "INDEX", "ALTER", "TO", dbda8d6ce9 2007-07-21 drh: "ADD", "COLUMNKW", "error", "input", dbda8d6ce9 2007-07-21 drh: "cmdlist", "ecmd", "cmdx", "cmd", dbda8d6ce9 2007-07-21 drh: "explain", "transtype", "trans_opt", "nm", dbda8d6ce9 2007-07-21 drh: "create_table", "create_table_args", "temp", "ifnotexists", dbda8d6ce9 2007-07-21 drh: "dbnm", "columnlist", "conslist_opt", "select", dbda8d6ce9 2007-07-21 drh: "column", "columnid", "type", "carglist", dbda8d6ce9 2007-07-21 drh: "id", "ids", "typetoken", "typename", dbda8d6ce9 2007-07-21 drh: "signed", "plus_num", "minus_num", "carg", dbda8d6ce9 2007-07-21 drh: "ccons", "term", "expr", "onconf", dbda8d6ce9 2007-07-21 drh: "sortorder", "autoinc", "idxlist_opt", "refargs", dbda8d6ce9 2007-07-21 drh: "defer_subclause", "refarg", "refact", "init_deferred_pred_opt", dbda8d6ce9 2007-07-21 drh: "conslist", "tcons", "idxlist", "defer_subclause_opt", dbda8d6ce9 2007-07-21 drh: "orconf", "resolvetype", "raisetype", "ifexists", dbda8d6ce9 2007-07-21 drh: "fullname", "oneselect", "multiselect_op", "distinct", dbda8d6ce9 2007-07-21 drh: "selcollist", "from", "where_opt", "groupby_opt", dbda8d6ce9 2007-07-21 drh: "having_opt", "orderby_opt", "limit_opt", "sclp", dbda8d6ce9 2007-07-21 drh: "as", "seltablist", "stl_prefix", "joinop", dbda8d6ce9 2007-07-21 drh: "on_opt", "using_opt", "seltablist_paren", "joinop2", dbda8d6ce9 2007-07-21 drh: "inscollist", "sortlist", "sortitem", "nexprlist", dbda8d6ce9 2007-07-21 drh: "setlist", "insert_cmd", "inscollist_opt", "itemlist", dbda8d6ce9 2007-07-21 drh: "exprlist", "likeop", "escape", "between_op", dbda8d6ce9 2007-07-21 drh: "in_op", "case_operand", "case_exprlist", "case_else", dbda8d6ce9 2007-07-21 drh: "uniqueflag", "idxitem", "collate", "nmnum", dbda8d6ce9 2007-07-21 drh: "plus_opt", "number", "trigger_decl", "trigger_cmd_list", dbda8d6ce9 2007-07-21 drh: "trigger_time", "trigger_event", "foreach_clause", "when_clause", dbda8d6ce9 2007-07-21 drh: "trigger_cmd", "database_kw_opt", "key_opt", "add_column_fullname", dbda8d6ce9 2007-07-21 drh: "kwcolumn_opt", "create_vtab", "vtabarglist", "vtabarg", dbda8d6ce9 2007-07-21 drh: "vtabargtoken", "lp", "anylist", dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #endif /* NDEBUG */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: /* For tracing reduce actions, the names of all rules are required. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const char *const yyRuleName[] = { dbda8d6ce9 2007-07-21 drh: /* 0 */ "input ::= cmdlist", dbda8d6ce9 2007-07-21 drh: /* 1 */ "cmdlist ::= cmdlist ecmd", dbda8d6ce9 2007-07-21 drh: /* 2 */ "cmdlist ::= ecmd", dbda8d6ce9 2007-07-21 drh: /* 3 */ "cmdx ::= cmd", dbda8d6ce9 2007-07-21 drh: /* 4 */ "ecmd ::= SEMI", dbda8d6ce9 2007-07-21 drh: /* 5 */ "ecmd ::= explain cmdx SEMI", dbda8d6ce9 2007-07-21 drh: /* 6 */ "explain ::=", dbda8d6ce9 2007-07-21 drh: /* 7 */ "explain ::= EXPLAIN", dbda8d6ce9 2007-07-21 drh: /* 8 */ "explain ::= EXPLAIN QUERY PLAN", dbda8d6ce9 2007-07-21 drh: /* 9 */ "cmd ::= BEGIN transtype trans_opt", dbda8d6ce9 2007-07-21 drh: /* 10 */ "trans_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 11 */ "trans_opt ::= TRANSACTION", dbda8d6ce9 2007-07-21 drh: /* 12 */ "trans_opt ::= TRANSACTION nm", dbda8d6ce9 2007-07-21 drh: /* 13 */ "transtype ::=", dbda8d6ce9 2007-07-21 drh: /* 14 */ "transtype ::= DEFERRED", dbda8d6ce9 2007-07-21 drh: /* 15 */ "transtype ::= IMMEDIATE", dbda8d6ce9 2007-07-21 drh: /* 16 */ "transtype ::= EXCLUSIVE", dbda8d6ce9 2007-07-21 drh: /* 17 */ "cmd ::= COMMIT trans_opt", dbda8d6ce9 2007-07-21 drh: /* 18 */ "cmd ::= END trans_opt", dbda8d6ce9 2007-07-21 drh: /* 19 */ "cmd ::= ROLLBACK trans_opt", dbda8d6ce9 2007-07-21 drh: /* 20 */ "cmd ::= create_table create_table_args", dbda8d6ce9 2007-07-21 drh: /* 21 */ "create_table ::= CREATE temp TABLE ifnotexists nm dbnm", dbda8d6ce9 2007-07-21 drh: /* 22 */ "ifnotexists ::=", dbda8d6ce9 2007-07-21 drh: /* 23 */ "ifnotexists ::= IF NOT EXISTS", dbda8d6ce9 2007-07-21 drh: /* 24 */ "temp ::= TEMP", dbda8d6ce9 2007-07-21 drh: /* 25 */ "temp ::=", dbda8d6ce9 2007-07-21 drh: /* 26 */ "create_table_args ::= LP columnlist conslist_opt RP", dbda8d6ce9 2007-07-21 drh: /* 27 */ "create_table_args ::= AS select", dbda8d6ce9 2007-07-21 drh: /* 28 */ "columnlist ::= columnlist COMMA column", dbda8d6ce9 2007-07-21 drh: /* 29 */ "columnlist ::= column", dbda8d6ce9 2007-07-21 drh: /* 30 */ "column ::= columnid type carglist", dbda8d6ce9 2007-07-21 drh: /* 31 */ "columnid ::= nm", dbda8d6ce9 2007-07-21 drh: /* 32 */ "id ::= ID", dbda8d6ce9 2007-07-21 drh: /* 33 */ "ids ::= ID|STRING", dbda8d6ce9 2007-07-21 drh: /* 34 */ "nm ::= ID", dbda8d6ce9 2007-07-21 drh: /* 35 */ "nm ::= STRING", dbda8d6ce9 2007-07-21 drh: /* 36 */ "nm ::= JOIN_KW", dbda8d6ce9 2007-07-21 drh: /* 37 */ "type ::=", dbda8d6ce9 2007-07-21 drh: /* 38 */ "type ::= typetoken", dbda8d6ce9 2007-07-21 drh: /* 39 */ "typetoken ::= typename", dbda8d6ce9 2007-07-21 drh: /* 40 */ "typetoken ::= typename LP signed RP", dbda8d6ce9 2007-07-21 drh: /* 41 */ "typetoken ::= typename LP signed COMMA signed RP", dbda8d6ce9 2007-07-21 drh: /* 42 */ "typename ::= ids", dbda8d6ce9 2007-07-21 drh: /* 43 */ "typename ::= typename ids", dbda8d6ce9 2007-07-21 drh: /* 44 */ "signed ::= plus_num", dbda8d6ce9 2007-07-21 drh: /* 45 */ "signed ::= minus_num", dbda8d6ce9 2007-07-21 drh: /* 46 */ "carglist ::= carglist carg", dbda8d6ce9 2007-07-21 drh: /* 47 */ "carglist ::=", dbda8d6ce9 2007-07-21 drh: /* 48 */ "carg ::= CONSTRAINT nm ccons", dbda8d6ce9 2007-07-21 drh: /* 49 */ "carg ::= ccons", dbda8d6ce9 2007-07-21 drh: /* 50 */ "ccons ::= DEFAULT term", dbda8d6ce9 2007-07-21 drh: /* 51 */ "ccons ::= DEFAULT LP expr RP", dbda8d6ce9 2007-07-21 drh: /* 52 */ "ccons ::= DEFAULT PLUS term", dbda8d6ce9 2007-07-21 drh: /* 53 */ "ccons ::= DEFAULT MINUS term", dbda8d6ce9 2007-07-21 drh: /* 54 */ "ccons ::= DEFAULT id", dbda8d6ce9 2007-07-21 drh: /* 55 */ "ccons ::= NULL onconf", dbda8d6ce9 2007-07-21 drh: /* 56 */ "ccons ::= NOT NULL onconf", dbda8d6ce9 2007-07-21 drh: /* 57 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", dbda8d6ce9 2007-07-21 drh: /* 58 */ "ccons ::= UNIQUE onconf", dbda8d6ce9 2007-07-21 drh: /* 59 */ "ccons ::= CHECK LP expr RP", dbda8d6ce9 2007-07-21 drh: /* 60 */ "ccons ::= REFERENCES nm idxlist_opt refargs", dbda8d6ce9 2007-07-21 drh: /* 61 */ "ccons ::= defer_subclause", dbda8d6ce9 2007-07-21 drh: /* 62 */ "ccons ::= COLLATE id", dbda8d6ce9 2007-07-21 drh: /* 63 */ "autoinc ::=", dbda8d6ce9 2007-07-21 drh: /* 64 */ "autoinc ::= AUTOINCR", dbda8d6ce9 2007-07-21 drh: /* 65 */ "refargs ::=", dbda8d6ce9 2007-07-21 drh: /* 66 */ "refargs ::= refargs refarg", dbda8d6ce9 2007-07-21 drh: /* 67 */ "refarg ::= MATCH nm", dbda8d6ce9 2007-07-21 drh: /* 68 */ "refarg ::= ON DELETE refact", dbda8d6ce9 2007-07-21 drh: /* 69 */ "refarg ::= ON UPDATE refact", dbda8d6ce9 2007-07-21 drh: /* 70 */ "refarg ::= ON INSERT refact", dbda8d6ce9 2007-07-21 drh: /* 71 */ "refact ::= SET NULL", dbda8d6ce9 2007-07-21 drh: /* 72 */ "refact ::= SET DEFAULT", dbda8d6ce9 2007-07-21 drh: /* 73 */ "refact ::= CASCADE", dbda8d6ce9 2007-07-21 drh: /* 74 */ "refact ::= RESTRICT", dbda8d6ce9 2007-07-21 drh: /* 75 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", dbda8d6ce9 2007-07-21 drh: /* 76 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", dbda8d6ce9 2007-07-21 drh: /* 77 */ "init_deferred_pred_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 78 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", dbda8d6ce9 2007-07-21 drh: /* 79 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", dbda8d6ce9 2007-07-21 drh: /* 80 */ "conslist_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 81 */ "conslist_opt ::= COMMA conslist", dbda8d6ce9 2007-07-21 drh: /* 82 */ "conslist ::= conslist COMMA tcons", dbda8d6ce9 2007-07-21 drh: /* 83 */ "conslist ::= conslist tcons", dbda8d6ce9 2007-07-21 drh: /* 84 */ "conslist ::= tcons", dbda8d6ce9 2007-07-21 drh: /* 85 */ "tcons ::= CONSTRAINT nm", dbda8d6ce9 2007-07-21 drh: /* 86 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf", dbda8d6ce9 2007-07-21 drh: /* 87 */ "tcons ::= UNIQUE LP idxlist RP onconf", dbda8d6ce9 2007-07-21 drh: /* 88 */ "tcons ::= CHECK LP expr RP onconf", dbda8d6ce9 2007-07-21 drh: /* 89 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt", dbda8d6ce9 2007-07-21 drh: /* 90 */ "defer_subclause_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 91 */ "defer_subclause_opt ::= defer_subclause", dbda8d6ce9 2007-07-21 drh: /* 92 */ "onconf ::=", dbda8d6ce9 2007-07-21 drh: /* 93 */ "onconf ::= ON CONFLICT resolvetype", dbda8d6ce9 2007-07-21 drh: /* 94 */ "orconf ::=", dbda8d6ce9 2007-07-21 drh: /* 95 */ "orconf ::= OR resolvetype", dbda8d6ce9 2007-07-21 drh: /* 96 */ "resolvetype ::= raisetype", dbda8d6ce9 2007-07-21 drh: /* 97 */ "resolvetype ::= IGNORE", dbda8d6ce9 2007-07-21 drh: /* 98 */ "resolvetype ::= REPLACE", dbda8d6ce9 2007-07-21 drh: /* 99 */ "cmd ::= DROP TABLE ifexists fullname", dbda8d6ce9 2007-07-21 drh: /* 100 */ "ifexists ::= IF EXISTS", dbda8d6ce9 2007-07-21 drh: /* 101 */ "ifexists ::=", dbda8d6ce9 2007-07-21 drh: /* 102 */ "cmd ::= CREATE temp VIEW ifnotexists nm dbnm AS select", dbda8d6ce9 2007-07-21 drh: /* 103 */ "cmd ::= DROP VIEW ifexists fullname", dbda8d6ce9 2007-07-21 drh: /* 104 */ "cmd ::= select", dbda8d6ce9 2007-07-21 drh: /* 105 */ "select ::= oneselect", dbda8d6ce9 2007-07-21 drh: /* 106 */ "select ::= select multiselect_op oneselect", dbda8d6ce9 2007-07-21 drh: /* 107 */ "multiselect_op ::= UNION", dbda8d6ce9 2007-07-21 drh: /* 108 */ "multiselect_op ::= UNION ALL", dbda8d6ce9 2007-07-21 drh: /* 109 */ "multiselect_op ::= EXCEPT|INTERSECT", dbda8d6ce9 2007-07-21 drh: /* 110 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", dbda8d6ce9 2007-07-21 drh: /* 111 */ "distinct ::= DISTINCT", dbda8d6ce9 2007-07-21 drh: /* 112 */ "distinct ::= ALL", dbda8d6ce9 2007-07-21 drh: /* 113 */ "distinct ::=", dbda8d6ce9 2007-07-21 drh: /* 114 */ "sclp ::= selcollist COMMA", dbda8d6ce9 2007-07-21 drh: /* 115 */ "sclp ::=", dbda8d6ce9 2007-07-21 drh: /* 116 */ "selcollist ::= sclp expr as", dbda8d6ce9 2007-07-21 drh: /* 117 */ "selcollist ::= sclp STAR", dbda8d6ce9 2007-07-21 drh: /* 118 */ "selcollist ::= sclp nm DOT STAR", dbda8d6ce9 2007-07-21 drh: /* 119 */ "as ::= AS nm", dbda8d6ce9 2007-07-21 drh: /* 120 */ "as ::= ids", dbda8d6ce9 2007-07-21 drh: /* 121 */ "as ::=", dbda8d6ce9 2007-07-21 drh: /* 122 */ "from ::=", dbda8d6ce9 2007-07-21 drh: /* 123 */ "from ::= FROM seltablist", dbda8d6ce9 2007-07-21 drh: /* 124 */ "stl_prefix ::= seltablist joinop", dbda8d6ce9 2007-07-21 drh: /* 125 */ "stl_prefix ::=", dbda8d6ce9 2007-07-21 drh: /* 126 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt", dbda8d6ce9 2007-07-21 drh: /* 127 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt", dbda8d6ce9 2007-07-21 drh: /* 128 */ "seltablist_paren ::= select", dbda8d6ce9 2007-07-21 drh: /* 129 */ "seltablist_paren ::= seltablist", dbda8d6ce9 2007-07-21 drh: /* 130 */ "dbnm ::=", dbda8d6ce9 2007-07-21 drh: /* 131 */ "dbnm ::= DOT nm", dbda8d6ce9 2007-07-21 drh: /* 132 */ "fullname ::= nm dbnm", dbda8d6ce9 2007-07-21 drh: /* 133 */ "joinop ::= COMMA|JOIN", dbda8d6ce9 2007-07-21 drh: /* 134 */ "joinop ::= JOIN_KW JOIN", dbda8d6ce9 2007-07-21 drh: /* 135 */ "joinop ::= JOIN_KW nm JOIN", dbda8d6ce9 2007-07-21 drh: /* 136 */ "joinop ::= JOIN_KW nm nm JOIN", dbda8d6ce9 2007-07-21 drh: /* 137 */ "on_opt ::= ON expr", dbda8d6ce9 2007-07-21 drh: /* 138 */ "on_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 139 */ "using_opt ::= USING LP inscollist RP", dbda8d6ce9 2007-07-21 drh: /* 140 */ "using_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 141 */ "orderby_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 142 */ "orderby_opt ::= ORDER BY sortlist", dbda8d6ce9 2007-07-21 drh: /* 143 */ "sortlist ::= sortlist COMMA sortitem sortorder", dbda8d6ce9 2007-07-21 drh: /* 144 */ "sortlist ::= sortitem sortorder", dbda8d6ce9 2007-07-21 drh: /* 145 */ "sortitem ::= expr", dbda8d6ce9 2007-07-21 drh: /* 146 */ "sortorder ::= ASC", dbda8d6ce9 2007-07-21 drh: /* 147 */ "sortorder ::= DESC", dbda8d6ce9 2007-07-21 drh: /* 148 */ "sortorder ::=", dbda8d6ce9 2007-07-21 drh: /* 149 */ "groupby_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 150 */ "groupby_opt ::= GROUP BY nexprlist", dbda8d6ce9 2007-07-21 drh: /* 151 */ "having_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 152 */ "having_opt ::= HAVING expr", dbda8d6ce9 2007-07-21 drh: /* 153 */ "limit_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 154 */ "limit_opt ::= LIMIT expr", dbda8d6ce9 2007-07-21 drh: /* 155 */ "limit_opt ::= LIMIT expr OFFSET expr", dbda8d6ce9 2007-07-21 drh: /* 156 */ "limit_opt ::= LIMIT expr COMMA expr", dbda8d6ce9 2007-07-21 drh: /* 157 */ "cmd ::= DELETE FROM fullname where_opt", dbda8d6ce9 2007-07-21 drh: /* 158 */ "where_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 159 */ "where_opt ::= WHERE expr", dbda8d6ce9 2007-07-21 drh: /* 160 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt", dbda8d6ce9 2007-07-21 drh: /* 161 */ "setlist ::= setlist COMMA nm EQ expr", dbda8d6ce9 2007-07-21 drh: /* 162 */ "setlist ::= nm EQ expr", dbda8d6ce9 2007-07-21 drh: /* 163 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP", dbda8d6ce9 2007-07-21 drh: /* 164 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select", dbda8d6ce9 2007-07-21 drh: /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES", dbda8d6ce9 2007-07-21 drh: /* 166 */ "insert_cmd ::= INSERT orconf", dbda8d6ce9 2007-07-21 drh: /* 167 */ "insert_cmd ::= REPLACE", dbda8d6ce9 2007-07-21 drh: /* 168 */ "itemlist ::= itemlist COMMA expr", dbda8d6ce9 2007-07-21 drh: /* 169 */ "itemlist ::= expr", dbda8d6ce9 2007-07-21 drh: /* 170 */ "inscollist_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 171 */ "inscollist_opt ::= LP inscollist RP", dbda8d6ce9 2007-07-21 drh: /* 172 */ "inscollist ::= inscollist COMMA nm", dbda8d6ce9 2007-07-21 drh: /* 173 */ "inscollist ::= nm", dbda8d6ce9 2007-07-21 drh: /* 174 */ "expr ::= term", dbda8d6ce9 2007-07-21 drh: /* 175 */ "expr ::= LP expr RP", dbda8d6ce9 2007-07-21 drh: /* 176 */ "term ::= NULL", dbda8d6ce9 2007-07-21 drh: /* 177 */ "expr ::= ID", dbda8d6ce9 2007-07-21 drh: /* 178 */ "expr ::= JOIN_KW", dbda8d6ce9 2007-07-21 drh: /* 179 */ "expr ::= nm DOT nm", dbda8d6ce9 2007-07-21 drh: /* 180 */ "expr ::= nm DOT nm DOT nm", dbda8d6ce9 2007-07-21 drh: /* 181 */ "term ::= INTEGER|FLOAT|BLOB", dbda8d6ce9 2007-07-21 drh: /* 182 */ "term ::= STRING", dbda8d6ce9 2007-07-21 drh: /* 183 */ "expr ::= REGISTER", dbda8d6ce9 2007-07-21 drh: /* 184 */ "expr ::= VARIABLE", dbda8d6ce9 2007-07-21 drh: /* 185 */ "expr ::= expr COLLATE id", dbda8d6ce9 2007-07-21 drh: /* 186 */ "expr ::= CAST LP expr AS typetoken RP", dbda8d6ce9 2007-07-21 drh: /* 187 */ "expr ::= ID LP distinct exprlist RP", dbda8d6ce9 2007-07-21 drh: /* 188 */ "expr ::= ID LP STAR RP", dbda8d6ce9 2007-07-21 drh: /* 189 */ "term ::= CTIME_KW", dbda8d6ce9 2007-07-21 drh: /* 190 */ "expr ::= expr AND expr", dbda8d6ce9 2007-07-21 drh: /* 191 */ "expr ::= expr OR expr", dbda8d6ce9 2007-07-21 drh: /* 192 */ "expr ::= expr LT|GT|GE|LE expr", dbda8d6ce9 2007-07-21 drh: /* 193 */ "expr ::= expr EQ|NE expr", dbda8d6ce9 2007-07-21 drh: /* 194 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", dbda8d6ce9 2007-07-21 drh: /* 195 */ "expr ::= expr PLUS|MINUS expr", dbda8d6ce9 2007-07-21 drh: /* 196 */ "expr ::= expr STAR|SLASH|REM expr", dbda8d6ce9 2007-07-21 drh: /* 197 */ "expr ::= expr CONCAT expr", dbda8d6ce9 2007-07-21 drh: /* 198 */ "likeop ::= LIKE_KW", dbda8d6ce9 2007-07-21 drh: /* 199 */ "likeop ::= NOT LIKE_KW", dbda8d6ce9 2007-07-21 drh: /* 200 */ "likeop ::= MATCH", dbda8d6ce9 2007-07-21 drh: /* 201 */ "likeop ::= NOT MATCH", dbda8d6ce9 2007-07-21 drh: /* 202 */ "escape ::= ESCAPE expr", dbda8d6ce9 2007-07-21 drh: /* 203 */ "escape ::=", dbda8d6ce9 2007-07-21 drh: /* 204 */ "expr ::= expr likeop expr escape", dbda8d6ce9 2007-07-21 drh: /* 205 */ "expr ::= expr ISNULL|NOTNULL", dbda8d6ce9 2007-07-21 drh: /* 206 */ "expr ::= expr IS NULL", dbda8d6ce9 2007-07-21 drh: /* 207 */ "expr ::= expr NOT NULL", dbda8d6ce9 2007-07-21 drh: /* 208 */ "expr ::= expr IS NOT NULL", dbda8d6ce9 2007-07-21 drh: /* 209 */ "expr ::= NOT|BITNOT expr", dbda8d6ce9 2007-07-21 drh: /* 210 */ "expr ::= MINUS expr", dbda8d6ce9 2007-07-21 drh: /* 211 */ "expr ::= PLUS expr", dbda8d6ce9 2007-07-21 drh: /* 212 */ "between_op ::= BETWEEN", dbda8d6ce9 2007-07-21 drh: /* 213 */ "between_op ::= NOT BETWEEN", dbda8d6ce9 2007-07-21 drh: /* 214 */ "expr ::= expr between_op expr AND expr", dbda8d6ce9 2007-07-21 drh: /* 215 */ "in_op ::= IN", dbda8d6ce9 2007-07-21 drh: /* 216 */ "in_op ::= NOT IN", dbda8d6ce9 2007-07-21 drh: /* 217 */ "expr ::= expr in_op LP exprlist RP", dbda8d6ce9 2007-07-21 drh: /* 218 */ "expr ::= LP select RP", dbda8d6ce9 2007-07-21 drh: /* 219 */ "expr ::= expr in_op LP select RP", dbda8d6ce9 2007-07-21 drh: /* 220 */ "expr ::= expr in_op nm dbnm", dbda8d6ce9 2007-07-21 drh: /* 221 */ "expr ::= EXISTS LP select RP", dbda8d6ce9 2007-07-21 drh: /* 222 */ "expr ::= CASE case_operand case_exprlist case_else END", dbda8d6ce9 2007-07-21 drh: /* 223 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", dbda8d6ce9 2007-07-21 drh: /* 224 */ "case_exprlist ::= WHEN expr THEN expr", dbda8d6ce9 2007-07-21 drh: /* 225 */ "case_else ::= ELSE expr", dbda8d6ce9 2007-07-21 drh: /* 226 */ "case_else ::=", dbda8d6ce9 2007-07-21 drh: /* 227 */ "case_operand ::= expr", dbda8d6ce9 2007-07-21 drh: /* 228 */ "case_operand ::=", dbda8d6ce9 2007-07-21 drh: /* 229 */ "exprlist ::= nexprlist", dbda8d6ce9 2007-07-21 drh: /* 230 */ "exprlist ::=", dbda8d6ce9 2007-07-21 drh: /* 231 */ "nexprlist ::= nexprlist COMMA expr", dbda8d6ce9 2007-07-21 drh: /* 232 */ "nexprlist ::= expr", dbda8d6ce9 2007-07-21 drh: /* 233 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP", dbda8d6ce9 2007-07-21 drh: /* 234 */ "uniqueflag ::= UNIQUE", dbda8d6ce9 2007-07-21 drh: /* 235 */ "uniqueflag ::=", dbda8d6ce9 2007-07-21 drh: /* 236 */ "idxlist_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 237 */ "idxlist_opt ::= LP idxlist RP", dbda8d6ce9 2007-07-21 drh: /* 238 */ "idxlist ::= idxlist COMMA idxitem collate sortorder", dbda8d6ce9 2007-07-21 drh: /* 239 */ "idxlist ::= idxitem collate sortorder", dbda8d6ce9 2007-07-21 drh: /* 240 */ "idxitem ::= nm", dbda8d6ce9 2007-07-21 drh: /* 241 */ "collate ::=", dbda8d6ce9 2007-07-21 drh: /* 242 */ "collate ::= COLLATE id", dbda8d6ce9 2007-07-21 drh: /* 243 */ "cmd ::= DROP INDEX ifexists fullname", dbda8d6ce9 2007-07-21 drh: /* 244 */ "cmd ::= VACUUM", dbda8d6ce9 2007-07-21 drh: /* 245 */ "cmd ::= VACUUM nm", dbda8d6ce9 2007-07-21 drh: /* 246 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", dbda8d6ce9 2007-07-21 drh: /* 247 */ "cmd ::= PRAGMA nm dbnm EQ ON", dbda8d6ce9 2007-07-21 drh: /* 248 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", dbda8d6ce9 2007-07-21 drh: /* 249 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", dbda8d6ce9 2007-07-21 drh: /* 250 */ "cmd ::= PRAGMA nm dbnm", dbda8d6ce9 2007-07-21 drh: /* 251 */ "nmnum ::= plus_num", dbda8d6ce9 2007-07-21 drh: /* 252 */ "nmnum ::= nm", dbda8d6ce9 2007-07-21 drh: /* 253 */ "plus_num ::= plus_opt number", dbda8d6ce9 2007-07-21 drh: /* 254 */ "minus_num ::= MINUS number", dbda8d6ce9 2007-07-21 drh: /* 255 */ "number ::= INTEGER|FLOAT", dbda8d6ce9 2007-07-21 drh: /* 256 */ "plus_opt ::= PLUS", dbda8d6ce9 2007-07-21 drh: /* 257 */ "plus_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 258 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END", dbda8d6ce9 2007-07-21 drh: /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", dbda8d6ce9 2007-07-21 drh: /* 260 */ "trigger_time ::= BEFORE", dbda8d6ce9 2007-07-21 drh: /* 261 */ "trigger_time ::= AFTER", dbda8d6ce9 2007-07-21 drh: /* 262 */ "trigger_time ::= INSTEAD OF", dbda8d6ce9 2007-07-21 drh: /* 263 */ "trigger_time ::=", dbda8d6ce9 2007-07-21 drh: /* 264 */ "trigger_event ::= DELETE|INSERT", dbda8d6ce9 2007-07-21 drh: /* 265 */ "trigger_event ::= UPDATE", dbda8d6ce9 2007-07-21 drh: /* 266 */ "trigger_event ::= UPDATE OF inscollist", dbda8d6ce9 2007-07-21 drh: /* 267 */ "foreach_clause ::=", dbda8d6ce9 2007-07-21 drh: /* 268 */ "foreach_clause ::= FOR EACH ROW", dbda8d6ce9 2007-07-21 drh: /* 269 */ "when_clause ::=", dbda8d6ce9 2007-07-21 drh: /* 270 */ "when_clause ::= WHEN expr", dbda8d6ce9 2007-07-21 drh: /* 271 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", dbda8d6ce9 2007-07-21 drh: /* 272 */ "trigger_cmd_list ::=", dbda8d6ce9 2007-07-21 drh: /* 273 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt", dbda8d6ce9 2007-07-21 drh: /* 274 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP", dbda8d6ce9 2007-07-21 drh: /* 275 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select", dbda8d6ce9 2007-07-21 drh: /* 276 */ "trigger_cmd ::= DELETE FROM nm where_opt", dbda8d6ce9 2007-07-21 drh: /* 277 */ "trigger_cmd ::= select", dbda8d6ce9 2007-07-21 drh: /* 278 */ "expr ::= RAISE LP IGNORE RP", dbda8d6ce9 2007-07-21 drh: /* 279 */ "expr ::= RAISE LP raisetype COMMA nm RP", dbda8d6ce9 2007-07-21 drh: /* 280 */ "raisetype ::= ROLLBACK", dbda8d6ce9 2007-07-21 drh: /* 281 */ "raisetype ::= ABORT", dbda8d6ce9 2007-07-21 drh: /* 282 */ "raisetype ::= FAIL", dbda8d6ce9 2007-07-21 drh: /* 283 */ "cmd ::= DROP TRIGGER ifexists fullname", dbda8d6ce9 2007-07-21 drh: /* 284 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", dbda8d6ce9 2007-07-21 drh: /* 285 */ "cmd ::= DETACH database_kw_opt expr", dbda8d6ce9 2007-07-21 drh: /* 286 */ "key_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 287 */ "key_opt ::= KEY expr", dbda8d6ce9 2007-07-21 drh: /* 288 */ "database_kw_opt ::= DATABASE", dbda8d6ce9 2007-07-21 drh: /* 289 */ "database_kw_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 290 */ "cmd ::= REINDEX", dbda8d6ce9 2007-07-21 drh: /* 291 */ "cmd ::= REINDEX nm dbnm", dbda8d6ce9 2007-07-21 drh: /* 292 */ "cmd ::= ANALYZE", dbda8d6ce9 2007-07-21 drh: /* 293 */ "cmd ::= ANALYZE nm dbnm", dbda8d6ce9 2007-07-21 drh: /* 294 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", dbda8d6ce9 2007-07-21 drh: /* 295 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column", dbda8d6ce9 2007-07-21 drh: /* 296 */ "add_column_fullname ::= fullname", dbda8d6ce9 2007-07-21 drh: /* 297 */ "kwcolumn_opt ::=", dbda8d6ce9 2007-07-21 drh: /* 298 */ "kwcolumn_opt ::= COLUMNKW", dbda8d6ce9 2007-07-21 drh: /* 299 */ "cmd ::= create_vtab", dbda8d6ce9 2007-07-21 drh: /* 300 */ "cmd ::= create_vtab LP vtabarglist RP", dbda8d6ce9 2007-07-21 drh: /* 301 */ "create_vtab ::= CREATE VIRTUAL TABLE nm dbnm USING nm", dbda8d6ce9 2007-07-21 drh: /* 302 */ "vtabarglist ::= vtabarg", dbda8d6ce9 2007-07-21 drh: /* 303 */ "vtabarglist ::= vtabarglist COMMA vtabarg", dbda8d6ce9 2007-07-21 drh: /* 304 */ "vtabarg ::=", dbda8d6ce9 2007-07-21 drh: /* 305 */ "vtabarg ::= vtabarg vtabargtoken", dbda8d6ce9 2007-07-21 drh: /* 306 */ "vtabargtoken ::= ANY", dbda8d6ce9 2007-07-21 drh: /* 307 */ "vtabargtoken ::= lp anylist RP", dbda8d6ce9 2007-07-21 drh: /* 308 */ "lp ::= LP", dbda8d6ce9 2007-07-21 drh: /* 309 */ "anylist ::=", dbda8d6ce9 2007-07-21 drh: /* 310 */ "anylist ::= anylist ANY", dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #endif /* NDEBUG */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if YYSTACKDEPTH<=0 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Try to increase the size of the parser stack. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void yyGrowStack(yyParser *p){ dbda8d6ce9 2007-07-21 drh: int newSize; dbda8d6ce9 2007-07-21 drh: yyStackEntry *pNew; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: newSize = p->yystksz*2 + 100; dbda8d6ce9 2007-07-21 drh: pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); dbda8d6ce9 2007-07-21 drh: if( pNew ){ dbda8d6ce9 2007-07-21 drh: p->yystack = pNew; dbda8d6ce9 2007-07-21 drh: p->yystksz = newSize; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", dbda8d6ce9 2007-07-21 drh: yyTracePrompt, p->yystksz); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function allocates a new parser. dbda8d6ce9 2007-07-21 drh: ** The only argument is a pointer to a function which works like dbda8d6ce9 2007-07-21 drh: ** malloc. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Inputs: dbda8d6ce9 2007-07-21 drh: ** A pointer to the function used to allocate memory. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Outputs: dbda8d6ce9 2007-07-21 drh: ** A pointer to a parser. This pointer is used in subsequent calls dbda8d6ce9 2007-07-21 drh: ** to sqlite3Parser and sqlite3ParserFree. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(size_t)){ dbda8d6ce9 2007-07-21 drh: yyParser *pParser; dbda8d6ce9 2007-07-21 drh: pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); dbda8d6ce9 2007-07-21 drh: if( pParser ){ dbda8d6ce9 2007-07-21 drh: pParser->yyidx = -1; dbda8d6ce9 2007-07-21 drh: #if YYSTACKDEPTH<=0 dbda8d6ce9 2007-07-21 drh: yyGrowStack(pParser); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return pParser; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following function deletes the value associated with a dbda8d6ce9 2007-07-21 drh: ** symbol. The symbol can be either a terminal or nonterminal. dbda8d6ce9 2007-07-21 drh: ** "yymajor" is the symbol code, and "yypminor" is a pointer to dbda8d6ce9 2007-07-21 drh: ** the value. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ dbda8d6ce9 2007-07-21 drh: switch( yymajor ){ dbda8d6ce9 2007-07-21 drh: /* Here is inserted the actions which take place when a dbda8d6ce9 2007-07-21 drh: ** terminal or non-terminal is destroyed. This can happen dbda8d6ce9 2007-07-21 drh: ** when the symbol is popped from the stack during a dbda8d6ce9 2007-07-21 drh: ** reduce or during error processing or when a parser is dbda8d6ce9 2007-07-21 drh: ** being destroyed before it is finished parsing. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Note: during a reduce, the only symbols destroyed are those dbda8d6ce9 2007-07-21 drh: ** which appear on the RHS of the rule, but which are not used dbda8d6ce9 2007-07-21 drh: ** inside the C code. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case 155: dbda8d6ce9 2007-07-21 drh: case 189: dbda8d6ce9 2007-07-21 drh: case 206: dbda8d6ce9 2007-07-21 drh: {sqlite3SelectDelete((yypminor->yy219));} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 169: dbda8d6ce9 2007-07-21 drh: case 170: dbda8d6ce9 2007-07-21 drh: case 194: dbda8d6ce9 2007-07-21 drh: case 196: dbda8d6ce9 2007-07-21 drh: case 204: dbda8d6ce9 2007-07-21 drh: case 210: dbda8d6ce9 2007-07-21 drh: case 218: dbda8d6ce9 2007-07-21 drh: case 221: dbda8d6ce9 2007-07-21 drh: case 223: dbda8d6ce9 2007-07-21 drh: case 235: dbda8d6ce9 2007-07-21 drh: {sqlite3ExprDelete((yypminor->yy172));} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 174: dbda8d6ce9 2007-07-21 drh: case 182: dbda8d6ce9 2007-07-21 drh: case 192: dbda8d6ce9 2007-07-21 drh: case 195: dbda8d6ce9 2007-07-21 drh: case 197: dbda8d6ce9 2007-07-21 drh: case 199: dbda8d6ce9 2007-07-21 drh: case 209: dbda8d6ce9 2007-07-21 drh: case 211: dbda8d6ce9 2007-07-21 drh: case 212: dbda8d6ce9 2007-07-21 drh: case 215: dbda8d6ce9 2007-07-21 drh: case 216: dbda8d6ce9 2007-07-21 drh: case 222: dbda8d6ce9 2007-07-21 drh: {sqlite3ExprListDelete((yypminor->yy174));} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 188: dbda8d6ce9 2007-07-21 drh: case 193: dbda8d6ce9 2007-07-21 drh: case 201: dbda8d6ce9 2007-07-21 drh: case 202: dbda8d6ce9 2007-07-21 drh: {sqlite3SrcListDelete((yypminor->yy373));} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 205: dbda8d6ce9 2007-07-21 drh: case 208: dbda8d6ce9 2007-07-21 drh: case 214: dbda8d6ce9 2007-07-21 drh: {sqlite3IdListDelete((yypminor->yy432));} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 231: dbda8d6ce9 2007-07-21 drh: case 236: dbda8d6ce9 2007-07-21 drh: {sqlite3DeleteTriggerStep((yypminor->yy243));} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 233: dbda8d6ce9 2007-07-21 drh: {sqlite3IdListDelete((yypminor->yy370).b);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 238: dbda8d6ce9 2007-07-21 drh: {sqlite3ExprDelete((yypminor->yy386));} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: default: break; /* If no destructor action specified: do nothing */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Pop the parser's stack once. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If there is a destructor routine associated with the token which dbda8d6ce9 2007-07-21 drh: ** is popped from the stack, then call it. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the major token number for the symbol popped. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int yy_pop_parser_stack(yyParser *pParser){ dbda8d6ce9 2007-07-21 drh: YYCODETYPE yymajor; dbda8d6ce9 2007-07-21 drh: yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( pParser->yyidx<0 ) return 0; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE && pParser->yyidx>=0 ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sPopping %s\n", dbda8d6ce9 2007-07-21 drh: yyTracePrompt, dbda8d6ce9 2007-07-21 drh: yyTokenName[yytos->major]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: yymajor = yytos->major; dbda8d6ce9 2007-07-21 drh: yy_destructor( yymajor, &yytos->minor); dbda8d6ce9 2007-07-21 drh: pParser->yyidx--; dbda8d6ce9 2007-07-21 drh: return yymajor; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Deallocate and destroy a parser. Destructors are all called for dbda8d6ce9 2007-07-21 drh: ** all stack elements before shutting the parser down. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Inputs: dbda8d6ce9 2007-07-21 drh: ** <ul> dbda8d6ce9 2007-07-21 drh: ** <li> A pointer to the parser. This should be a pointer dbda8d6ce9 2007-07-21 drh: ** obtained from sqlite3ParserAlloc. dbda8d6ce9 2007-07-21 drh: ** <li> A pointer to a function used to reclaim memory obtained dbda8d6ce9 2007-07-21 drh: ** from malloc. dbda8d6ce9 2007-07-21 drh: ** </ul> dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3ParserFree( dbda8d6ce9 2007-07-21 drh: void *p, /* The parser to be deleted */ dbda8d6ce9 2007-07-21 drh: void (*freeProc)(void*) /* Function used to reclaim memory */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: yyParser *pParser = (yyParser*)p; dbda8d6ce9 2007-07-21 drh: if( pParser==0 ) return; dbda8d6ce9 2007-07-21 drh: while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); dbda8d6ce9 2007-07-21 drh: #if YYSTACKDEPTH<=0 dbda8d6ce9 2007-07-21 drh: free(pParser->yystack); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: (*freeProc)((void*)pParser); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the appropriate action for a parser given the terminal dbda8d6ce9 2007-07-21 drh: ** look-ahead token iLookAhead. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the look-ahead token is YYNOCODE, then check to see if the action is dbda8d6ce9 2007-07-21 drh: ** independent of the look-ahead. If it is, return the action, otherwise dbda8d6ce9 2007-07-21 drh: ** return YY_NO_ACTION. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int yy_find_shift_action( dbda8d6ce9 2007-07-21 drh: yyParser *pParser, /* The parser */ dbda8d6ce9 2007-07-21 drh: YYCODETYPE iLookAhead /* The look-ahead token */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int stateno = pParser->yystack[pParser->yyidx].stateno; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ dbda8d6ce9 2007-07-21 drh: return yy_default[stateno]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iLookAhead==YYNOCODE ){ dbda8d6ce9 2007-07-21 drh: return YY_NO_ACTION; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i += iLookAhead; dbda8d6ce9 2007-07-21 drh: if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ dbda8d6ce9 2007-07-21 drh: if( iLookAhead>0 ){ dbda8d6ce9 2007-07-21 drh: #ifdef YYFALLBACK dbda8d6ce9 2007-07-21 drh: int iFallback; /* Fallback token */ dbda8d6ce9 2007-07-21 drh: if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) dbda8d6ce9 2007-07-21 drh: && (iFallback = yyFallback[iLookAhead])!=0 ){ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", dbda8d6ce9 2007-07-21 drh: yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: return yy_find_shift_action(pParser, iFallback); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef YYWILDCARD dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: int j = i - iLookAhead + YYWILDCARD; dbda8d6ce9 2007-07-21 drh: if( j>=0 && j<YY_SZ_ACTTAB && yy_lookahead[j]==YYWILDCARD ){ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", dbda8d6ce9 2007-07-21 drh: yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* NDEBUG */ dbda8d6ce9 2007-07-21 drh: return yy_action[j]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* YYWILDCARD */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return yy_default[stateno]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return yy_action[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Find the appropriate action for a parser given the non-terminal dbda8d6ce9 2007-07-21 drh: ** look-ahead token iLookAhead. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the look-ahead token is YYNOCODE, then check to see if the action is dbda8d6ce9 2007-07-21 drh: ** independent of the look-ahead. If it is, return the action, otherwise dbda8d6ce9 2007-07-21 drh: ** return YY_NO_ACTION. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int yy_find_reduce_action( dbda8d6ce9 2007-07-21 drh: int stateno, /* Current state number */ dbda8d6ce9 2007-07-21 drh: YYCODETYPE iLookAhead /* The look-ahead token */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: /* int stateno = pParser->yystack[pParser->yyidx].stateno; */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( stateno>YY_REDUCE_MAX || dbda8d6ce9 2007-07-21 drh: (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){ dbda8d6ce9 2007-07-21 drh: return yy_default[stateno]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iLookAhead==YYNOCODE ){ dbda8d6ce9 2007-07-21 drh: return YY_NO_ACTION; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i += iLookAhead; dbda8d6ce9 2007-07-21 drh: if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ dbda8d6ce9 2007-07-21 drh: return yy_default[stateno]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: return yy_action[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following routine is called if the stack overflows. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_FETCH; dbda8d6ce9 2007-07-21 drh: yypParser->yyidx--; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); dbda8d6ce9 2007-07-21 drh: /* Here code is inserted which will execute if the parser dbda8d6ce9 2007-07-21 drh: ** stack every overflows */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "parser stack overflow"); dbda8d6ce9 2007-07-21 drh: pParse->parseError = 1; dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Perform a shift action. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void yy_shift( dbda8d6ce9 2007-07-21 drh: yyParser *yypParser, /* The parser to be shifted */ dbda8d6ce9 2007-07-21 drh: int yyNewState, /* The new state to shift in */ dbda8d6ce9 2007-07-21 drh: int yyMajor, /* The major token to shift in */ dbda8d6ce9 2007-07-21 drh: YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: yyStackEntry *yytos; dbda8d6ce9 2007-07-21 drh: yypParser->yyidx++; dbda8d6ce9 2007-07-21 drh: #if YYSTACKDEPTH>0 dbda8d6ce9 2007-07-21 drh: if( yypParser->yyidx>=YYSTACKDEPTH ){ dbda8d6ce9 2007-07-21 drh: yyStackOverflow(yypParser, yypMinor); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: if( yypParser->yyidx>=yypParser->yystksz ){ dbda8d6ce9 2007-07-21 drh: yyGrowStack(yypParser); dbda8d6ce9 2007-07-21 drh: if( yypParser->yyidx>=yypParser->yystksz ){ dbda8d6ce9 2007-07-21 drh: yyStackOverflow(yypParser, yypMinor); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: yytos = &yypParser->yystack[yypParser->yyidx]; dbda8d6ce9 2007-07-21 drh: yytos->stateno = yyNewState; dbda8d6ce9 2007-07-21 drh: yytos->major = yyMajor; dbda8d6ce9 2007-07-21 drh: yytos->minor = *yypMinor; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE && yypParser->yyidx>0 ){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); dbda8d6ce9 2007-07-21 drh: for(i=1; i<=yypParser->yyidx; i++) dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"\n"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following table contains information about every rule that dbda8d6ce9 2007-07-21 drh: ** is used during the reduce. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const struct { dbda8d6ce9 2007-07-21 drh: YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ dbda8d6ce9 2007-07-21 drh: unsigned char nrhs; /* Number of right-hand side symbols in the rule */ dbda8d6ce9 2007-07-21 drh: } yyRuleInfo[] = { dbda8d6ce9 2007-07-21 drh: { 139, 1 }, dbda8d6ce9 2007-07-21 drh: { 140, 2 }, dbda8d6ce9 2007-07-21 drh: { 140, 1 }, dbda8d6ce9 2007-07-21 drh: { 142, 1 }, dbda8d6ce9 2007-07-21 drh: { 141, 1 }, dbda8d6ce9 2007-07-21 drh: { 141, 3 }, dbda8d6ce9 2007-07-21 drh: { 144, 0 }, dbda8d6ce9 2007-07-21 drh: { 144, 1 }, dbda8d6ce9 2007-07-21 drh: { 144, 3 }, dbda8d6ce9 2007-07-21 drh: { 143, 3 }, dbda8d6ce9 2007-07-21 drh: { 146, 0 }, dbda8d6ce9 2007-07-21 drh: { 146, 1 }, dbda8d6ce9 2007-07-21 drh: { 146, 2 }, dbda8d6ce9 2007-07-21 drh: { 145, 0 }, dbda8d6ce9 2007-07-21 drh: { 145, 1 }, dbda8d6ce9 2007-07-21 drh: { 145, 1 }, dbda8d6ce9 2007-07-21 drh: { 145, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 2 }, dbda8d6ce9 2007-07-21 drh: { 143, 2 }, dbda8d6ce9 2007-07-21 drh: { 143, 2 }, dbda8d6ce9 2007-07-21 drh: { 143, 2 }, dbda8d6ce9 2007-07-21 drh: { 148, 6 }, dbda8d6ce9 2007-07-21 drh: { 151, 0 }, dbda8d6ce9 2007-07-21 drh: { 151, 3 }, dbda8d6ce9 2007-07-21 drh: { 150, 1 }, dbda8d6ce9 2007-07-21 drh: { 150, 0 }, dbda8d6ce9 2007-07-21 drh: { 149, 4 }, dbda8d6ce9 2007-07-21 drh: { 149, 2 }, dbda8d6ce9 2007-07-21 drh: { 153, 3 }, dbda8d6ce9 2007-07-21 drh: { 153, 1 }, dbda8d6ce9 2007-07-21 drh: { 156, 3 }, dbda8d6ce9 2007-07-21 drh: { 157, 1 }, dbda8d6ce9 2007-07-21 drh: { 160, 1 }, dbda8d6ce9 2007-07-21 drh: { 161, 1 }, dbda8d6ce9 2007-07-21 drh: { 147, 1 }, dbda8d6ce9 2007-07-21 drh: { 147, 1 }, dbda8d6ce9 2007-07-21 drh: { 147, 1 }, dbda8d6ce9 2007-07-21 drh: { 158, 0 }, dbda8d6ce9 2007-07-21 drh: { 158, 1 }, dbda8d6ce9 2007-07-21 drh: { 162, 1 }, dbda8d6ce9 2007-07-21 drh: { 162, 4 }, dbda8d6ce9 2007-07-21 drh: { 162, 6 }, dbda8d6ce9 2007-07-21 drh: { 163, 1 }, dbda8d6ce9 2007-07-21 drh: { 163, 2 }, dbda8d6ce9 2007-07-21 drh: { 164, 1 }, dbda8d6ce9 2007-07-21 drh: { 164, 1 }, dbda8d6ce9 2007-07-21 drh: { 159, 2 }, dbda8d6ce9 2007-07-21 drh: { 159, 0 }, dbda8d6ce9 2007-07-21 drh: { 167, 3 }, dbda8d6ce9 2007-07-21 drh: { 167, 1 }, dbda8d6ce9 2007-07-21 drh: { 168, 2 }, dbda8d6ce9 2007-07-21 drh: { 168, 4 }, dbda8d6ce9 2007-07-21 drh: { 168, 3 }, dbda8d6ce9 2007-07-21 drh: { 168, 3 }, dbda8d6ce9 2007-07-21 drh: { 168, 2 }, dbda8d6ce9 2007-07-21 drh: { 168, 2 }, dbda8d6ce9 2007-07-21 drh: { 168, 3 }, dbda8d6ce9 2007-07-21 drh: { 168, 5 }, dbda8d6ce9 2007-07-21 drh: { 168, 2 }, dbda8d6ce9 2007-07-21 drh: { 168, 4 }, dbda8d6ce9 2007-07-21 drh: { 168, 4 }, dbda8d6ce9 2007-07-21 drh: { 168, 1 }, dbda8d6ce9 2007-07-21 drh: { 168, 2 }, dbda8d6ce9 2007-07-21 drh: { 173, 0 }, dbda8d6ce9 2007-07-21 drh: { 173, 1 }, dbda8d6ce9 2007-07-21 drh: { 175, 0 }, dbda8d6ce9 2007-07-21 drh: { 175, 2 }, dbda8d6ce9 2007-07-21 drh: { 177, 2 }, dbda8d6ce9 2007-07-21 drh: { 177, 3 }, dbda8d6ce9 2007-07-21 drh: { 177, 3 }, dbda8d6ce9 2007-07-21 drh: { 177, 3 }, dbda8d6ce9 2007-07-21 drh: { 178, 2 }, dbda8d6ce9 2007-07-21 drh: { 178, 2 }, dbda8d6ce9 2007-07-21 drh: { 178, 1 }, dbda8d6ce9 2007-07-21 drh: { 178, 1 }, dbda8d6ce9 2007-07-21 drh: { 176, 3 }, dbda8d6ce9 2007-07-21 drh: { 176, 2 }, dbda8d6ce9 2007-07-21 drh: { 179, 0 }, dbda8d6ce9 2007-07-21 drh: { 179, 2 }, dbda8d6ce9 2007-07-21 drh: { 179, 2 }, dbda8d6ce9 2007-07-21 drh: { 154, 0 }, dbda8d6ce9 2007-07-21 drh: { 154, 2 }, dbda8d6ce9 2007-07-21 drh: { 180, 3 }, dbda8d6ce9 2007-07-21 drh: { 180, 2 }, dbda8d6ce9 2007-07-21 drh: { 180, 1 }, dbda8d6ce9 2007-07-21 drh: { 181, 2 }, dbda8d6ce9 2007-07-21 drh: { 181, 7 }, dbda8d6ce9 2007-07-21 drh: { 181, 5 }, dbda8d6ce9 2007-07-21 drh: { 181, 5 }, dbda8d6ce9 2007-07-21 drh: { 181, 10 }, dbda8d6ce9 2007-07-21 drh: { 183, 0 }, dbda8d6ce9 2007-07-21 drh: { 183, 1 }, dbda8d6ce9 2007-07-21 drh: { 171, 0 }, dbda8d6ce9 2007-07-21 drh: { 171, 3 }, dbda8d6ce9 2007-07-21 drh: { 184, 0 }, dbda8d6ce9 2007-07-21 drh: { 184, 2 }, dbda8d6ce9 2007-07-21 drh: { 185, 1 }, dbda8d6ce9 2007-07-21 drh: { 185, 1 }, dbda8d6ce9 2007-07-21 drh: { 185, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 4 }, dbda8d6ce9 2007-07-21 drh: { 187, 2 }, dbda8d6ce9 2007-07-21 drh: { 187, 0 }, dbda8d6ce9 2007-07-21 drh: { 143, 8 }, dbda8d6ce9 2007-07-21 drh: { 143, 4 }, dbda8d6ce9 2007-07-21 drh: { 143, 1 }, dbda8d6ce9 2007-07-21 drh: { 155, 1 }, dbda8d6ce9 2007-07-21 drh: { 155, 3 }, dbda8d6ce9 2007-07-21 drh: { 190, 1 }, dbda8d6ce9 2007-07-21 drh: { 190, 2 }, dbda8d6ce9 2007-07-21 drh: { 190, 1 }, dbda8d6ce9 2007-07-21 drh: { 189, 9 }, dbda8d6ce9 2007-07-21 drh: { 191, 1 }, dbda8d6ce9 2007-07-21 drh: { 191, 1 }, dbda8d6ce9 2007-07-21 drh: { 191, 0 }, dbda8d6ce9 2007-07-21 drh: { 199, 2 }, dbda8d6ce9 2007-07-21 drh: { 199, 0 }, dbda8d6ce9 2007-07-21 drh: { 192, 3 }, dbda8d6ce9 2007-07-21 drh: { 192, 2 }, dbda8d6ce9 2007-07-21 drh: { 192, 4 }, dbda8d6ce9 2007-07-21 drh: { 200, 2 }, dbda8d6ce9 2007-07-21 drh: { 200, 1 }, dbda8d6ce9 2007-07-21 drh: { 200, 0 }, dbda8d6ce9 2007-07-21 drh: { 193, 0 }, dbda8d6ce9 2007-07-21 drh: { 193, 2 }, dbda8d6ce9 2007-07-21 drh: { 202, 2 }, dbda8d6ce9 2007-07-21 drh: { 202, 0 }, dbda8d6ce9 2007-07-21 drh: { 201, 6 }, dbda8d6ce9 2007-07-21 drh: { 201, 7 }, dbda8d6ce9 2007-07-21 drh: { 206, 1 }, dbda8d6ce9 2007-07-21 drh: { 206, 1 }, dbda8d6ce9 2007-07-21 drh: { 152, 0 }, dbda8d6ce9 2007-07-21 drh: { 152, 2 }, dbda8d6ce9 2007-07-21 drh: { 188, 2 }, dbda8d6ce9 2007-07-21 drh: { 203, 1 }, dbda8d6ce9 2007-07-21 drh: { 203, 2 }, dbda8d6ce9 2007-07-21 drh: { 203, 3 }, dbda8d6ce9 2007-07-21 drh: { 203, 4 }, dbda8d6ce9 2007-07-21 drh: { 204, 2 }, dbda8d6ce9 2007-07-21 drh: { 204, 0 }, dbda8d6ce9 2007-07-21 drh: { 205, 4 }, dbda8d6ce9 2007-07-21 drh: { 205, 0 }, dbda8d6ce9 2007-07-21 drh: { 197, 0 }, dbda8d6ce9 2007-07-21 drh: { 197, 3 }, dbda8d6ce9 2007-07-21 drh: { 209, 4 }, dbda8d6ce9 2007-07-21 drh: { 209, 2 }, dbda8d6ce9 2007-07-21 drh: { 210, 1 }, dbda8d6ce9 2007-07-21 drh: { 172, 1 }, dbda8d6ce9 2007-07-21 drh: { 172, 1 }, dbda8d6ce9 2007-07-21 drh: { 172, 0 }, dbda8d6ce9 2007-07-21 drh: { 195, 0 }, dbda8d6ce9 2007-07-21 drh: { 195, 3 }, dbda8d6ce9 2007-07-21 drh: { 196, 0 }, dbda8d6ce9 2007-07-21 drh: { 196, 2 }, dbda8d6ce9 2007-07-21 drh: { 198, 0 }, dbda8d6ce9 2007-07-21 drh: { 198, 2 }, dbda8d6ce9 2007-07-21 drh: { 198, 4 }, dbda8d6ce9 2007-07-21 drh: { 198, 4 }, dbda8d6ce9 2007-07-21 drh: { 143, 4 }, dbda8d6ce9 2007-07-21 drh: { 194, 0 }, dbda8d6ce9 2007-07-21 drh: { 194, 2 }, dbda8d6ce9 2007-07-21 drh: { 143, 6 }, dbda8d6ce9 2007-07-21 drh: { 212, 5 }, dbda8d6ce9 2007-07-21 drh: { 212, 3 }, dbda8d6ce9 2007-07-21 drh: { 143, 8 }, dbda8d6ce9 2007-07-21 drh: { 143, 5 }, dbda8d6ce9 2007-07-21 drh: { 143, 6 }, dbda8d6ce9 2007-07-21 drh: { 213, 2 }, dbda8d6ce9 2007-07-21 drh: { 213, 1 }, dbda8d6ce9 2007-07-21 drh: { 215, 3 }, dbda8d6ce9 2007-07-21 drh: { 215, 1 }, dbda8d6ce9 2007-07-21 drh: { 214, 0 }, dbda8d6ce9 2007-07-21 drh: { 214, 3 }, dbda8d6ce9 2007-07-21 drh: { 208, 3 }, dbda8d6ce9 2007-07-21 drh: { 208, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 169, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 5 }, dbda8d6ce9 2007-07-21 drh: { 169, 1 }, dbda8d6ce9 2007-07-21 drh: { 169, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 6 }, dbda8d6ce9 2007-07-21 drh: { 170, 5 }, dbda8d6ce9 2007-07-21 drh: { 170, 4 }, dbda8d6ce9 2007-07-21 drh: { 169, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 217, 1 }, dbda8d6ce9 2007-07-21 drh: { 217, 2 }, dbda8d6ce9 2007-07-21 drh: { 217, 1 }, dbda8d6ce9 2007-07-21 drh: { 217, 2 }, dbda8d6ce9 2007-07-21 drh: { 218, 2 }, dbda8d6ce9 2007-07-21 drh: { 218, 0 }, dbda8d6ce9 2007-07-21 drh: { 170, 4 }, dbda8d6ce9 2007-07-21 drh: { 170, 2 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 4 }, dbda8d6ce9 2007-07-21 drh: { 170, 2 }, dbda8d6ce9 2007-07-21 drh: { 170, 2 }, dbda8d6ce9 2007-07-21 drh: { 170, 2 }, dbda8d6ce9 2007-07-21 drh: { 219, 1 }, dbda8d6ce9 2007-07-21 drh: { 219, 2 }, dbda8d6ce9 2007-07-21 drh: { 170, 5 }, dbda8d6ce9 2007-07-21 drh: { 220, 1 }, dbda8d6ce9 2007-07-21 drh: { 220, 2 }, dbda8d6ce9 2007-07-21 drh: { 170, 5 }, dbda8d6ce9 2007-07-21 drh: { 170, 3 }, dbda8d6ce9 2007-07-21 drh: { 170, 5 }, dbda8d6ce9 2007-07-21 drh: { 170, 4 }, dbda8d6ce9 2007-07-21 drh: { 170, 4 }, dbda8d6ce9 2007-07-21 drh: { 170, 5 }, dbda8d6ce9 2007-07-21 drh: { 222, 5 }, dbda8d6ce9 2007-07-21 drh: { 222, 4 }, dbda8d6ce9 2007-07-21 drh: { 223, 2 }, dbda8d6ce9 2007-07-21 drh: { 223, 0 }, dbda8d6ce9 2007-07-21 drh: { 221, 1 }, dbda8d6ce9 2007-07-21 drh: { 221, 0 }, dbda8d6ce9 2007-07-21 drh: { 216, 1 }, dbda8d6ce9 2007-07-21 drh: { 216, 0 }, dbda8d6ce9 2007-07-21 drh: { 211, 3 }, dbda8d6ce9 2007-07-21 drh: { 211, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 11 }, dbda8d6ce9 2007-07-21 drh: { 224, 1 }, dbda8d6ce9 2007-07-21 drh: { 224, 0 }, dbda8d6ce9 2007-07-21 drh: { 174, 0 }, dbda8d6ce9 2007-07-21 drh: { 174, 3 }, dbda8d6ce9 2007-07-21 drh: { 182, 5 }, dbda8d6ce9 2007-07-21 drh: { 182, 3 }, dbda8d6ce9 2007-07-21 drh: { 225, 1 }, dbda8d6ce9 2007-07-21 drh: { 226, 0 }, dbda8d6ce9 2007-07-21 drh: { 226, 2 }, dbda8d6ce9 2007-07-21 drh: { 143, 4 }, dbda8d6ce9 2007-07-21 drh: { 143, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 2 }, dbda8d6ce9 2007-07-21 drh: { 143, 5 }, dbda8d6ce9 2007-07-21 drh: { 143, 5 }, dbda8d6ce9 2007-07-21 drh: { 143, 5 }, dbda8d6ce9 2007-07-21 drh: { 143, 6 }, dbda8d6ce9 2007-07-21 drh: { 143, 3 }, dbda8d6ce9 2007-07-21 drh: { 227, 1 }, dbda8d6ce9 2007-07-21 drh: { 227, 1 }, dbda8d6ce9 2007-07-21 drh: { 165, 2 }, dbda8d6ce9 2007-07-21 drh: { 166, 2 }, dbda8d6ce9 2007-07-21 drh: { 229, 1 }, dbda8d6ce9 2007-07-21 drh: { 228, 1 }, dbda8d6ce9 2007-07-21 drh: { 228, 0 }, dbda8d6ce9 2007-07-21 drh: { 143, 5 }, dbda8d6ce9 2007-07-21 drh: { 230, 11 }, dbda8d6ce9 2007-07-21 drh: { 232, 1 }, dbda8d6ce9 2007-07-21 drh: { 232, 1 }, dbda8d6ce9 2007-07-21 drh: { 232, 2 }, dbda8d6ce9 2007-07-21 drh: { 232, 0 }, dbda8d6ce9 2007-07-21 drh: { 233, 1 }, dbda8d6ce9 2007-07-21 drh: { 233, 1 }, dbda8d6ce9 2007-07-21 drh: { 233, 3 }, dbda8d6ce9 2007-07-21 drh: { 234, 0 }, dbda8d6ce9 2007-07-21 drh: { 234, 3 }, dbda8d6ce9 2007-07-21 drh: { 235, 0 }, dbda8d6ce9 2007-07-21 drh: { 235, 2 }, dbda8d6ce9 2007-07-21 drh: { 231, 3 }, dbda8d6ce9 2007-07-21 drh: { 231, 0 }, dbda8d6ce9 2007-07-21 drh: { 236, 6 }, dbda8d6ce9 2007-07-21 drh: { 236, 8 }, dbda8d6ce9 2007-07-21 drh: { 236, 5 }, dbda8d6ce9 2007-07-21 drh: { 236, 4 }, dbda8d6ce9 2007-07-21 drh: { 236, 1 }, dbda8d6ce9 2007-07-21 drh: { 170, 4 }, dbda8d6ce9 2007-07-21 drh: { 170, 6 }, dbda8d6ce9 2007-07-21 drh: { 186, 1 }, dbda8d6ce9 2007-07-21 drh: { 186, 1 }, dbda8d6ce9 2007-07-21 drh: { 186, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 4 }, dbda8d6ce9 2007-07-21 drh: { 143, 6 }, dbda8d6ce9 2007-07-21 drh: { 143, 3 }, dbda8d6ce9 2007-07-21 drh: { 238, 0 }, dbda8d6ce9 2007-07-21 drh: { 238, 2 }, dbda8d6ce9 2007-07-21 drh: { 237, 1 }, dbda8d6ce9 2007-07-21 drh: { 237, 0 }, dbda8d6ce9 2007-07-21 drh: { 143, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 3 }, dbda8d6ce9 2007-07-21 drh: { 143, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 3 }, dbda8d6ce9 2007-07-21 drh: { 143, 6 }, dbda8d6ce9 2007-07-21 drh: { 143, 6 }, dbda8d6ce9 2007-07-21 drh: { 239, 1 }, dbda8d6ce9 2007-07-21 drh: { 240, 0 }, dbda8d6ce9 2007-07-21 drh: { 240, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 1 }, dbda8d6ce9 2007-07-21 drh: { 143, 4 }, dbda8d6ce9 2007-07-21 drh: { 241, 7 }, dbda8d6ce9 2007-07-21 drh: { 242, 1 }, dbda8d6ce9 2007-07-21 drh: { 242, 3 }, dbda8d6ce9 2007-07-21 drh: { 243, 0 }, dbda8d6ce9 2007-07-21 drh: { 243, 2 }, dbda8d6ce9 2007-07-21 drh: { 244, 1 }, dbda8d6ce9 2007-07-21 drh: { 244, 3 }, dbda8d6ce9 2007-07-21 drh: { 245, 1 }, dbda8d6ce9 2007-07-21 drh: { 246, 0 }, dbda8d6ce9 2007-07-21 drh: { 246, 2 }, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: static void yy_accept(yyParser*); /* Forward Declaration */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Perform a reduce action and the shift that must immediately dbda8d6ce9 2007-07-21 drh: ** follow the reduce. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void yy_reduce( dbda8d6ce9 2007-07-21 drh: yyParser *yypParser, /* The parser */ dbda8d6ce9 2007-07-21 drh: int yyruleno /* Number of the rule by which to reduce */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int yygoto; /* The next state */ dbda8d6ce9 2007-07-21 drh: int yyact; /* The next action */ dbda8d6ce9 2007-07-21 drh: YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ dbda8d6ce9 2007-07-21 drh: yyStackEntry *yymsp; /* The top of the parser's stack */ dbda8d6ce9 2007-07-21 drh: int yysize; /* Amount to pop the stack */ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_FETCH; dbda8d6ce9 2007-07-21 drh: yymsp = &yypParser->yystack[yypParser->yyidx]; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE && yyruleno>=0 dbda8d6ce9 2007-07-21 drh: && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, dbda8d6ce9 2007-07-21 drh: yyRuleName[yyruleno]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* NDEBUG */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Silence complaints from purify about yygotominor being uninitialized dbda8d6ce9 2007-07-21 drh: ** in some cases when it is copied into the stack after the following dbda8d6ce9 2007-07-21 drh: ** switch. yygotominor is uninitialized when a rule reduces that does dbda8d6ce9 2007-07-21 drh: ** not set the value of its left-hand side nonterminal. Leaving the dbda8d6ce9 2007-07-21 drh: ** value of the nonterminal uninitialized is utterly harmless as long dbda8d6ce9 2007-07-21 drh: ** as the value is never used. So really the only thing this code dbda8d6ce9 2007-07-21 drh: ** accomplishes is to quieten purify. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2007-01-16: The wireshark project (www.wireshark.org) reports that dbda8d6ce9 2007-07-21 drh: ** without this code, their parser segfaults. I'm not sure what there dbda8d6ce9 2007-07-21 drh: ** parser is doing to make this happen. This is the second bug report dbda8d6ce9 2007-07-21 drh: ** from wireshark this week. Clearly they are stressing Lemon in ways dbda8d6ce9 2007-07-21 drh: ** that it has not been previously stressed... (SQLite ticket #2172) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: memset(&yygotominor, 0, sizeof(yygotominor)); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: switch( yyruleno ){ dbda8d6ce9 2007-07-21 drh: /* Beginning here are the reduction cases. A typical example dbda8d6ce9 2007-07-21 drh: ** follows: dbda8d6ce9 2007-07-21 drh: ** case 0: dbda8d6ce9 2007-07-21 drh: ** #line <lineno> <grammarfile> dbda8d6ce9 2007-07-21 drh: ** { ... } // User supplied code dbda8d6ce9 2007-07-21 drh: ** #line <lineno> <thisfile> dbda8d6ce9 2007-07-21 drh: ** break; dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: case 0: dbda8d6ce9 2007-07-21 drh: case 1: dbda8d6ce9 2007-07-21 drh: case 2: dbda8d6ce9 2007-07-21 drh: case 4: dbda8d6ce9 2007-07-21 drh: case 5: dbda8d6ce9 2007-07-21 drh: case 10: dbda8d6ce9 2007-07-21 drh: case 11: dbda8d6ce9 2007-07-21 drh: case 12: dbda8d6ce9 2007-07-21 drh: case 20: dbda8d6ce9 2007-07-21 drh: case 28: dbda8d6ce9 2007-07-21 drh: case 29: dbda8d6ce9 2007-07-21 drh: case 37: dbda8d6ce9 2007-07-21 drh: case 44: dbda8d6ce9 2007-07-21 drh: case 45: dbda8d6ce9 2007-07-21 drh: case 46: dbda8d6ce9 2007-07-21 drh: case 47: dbda8d6ce9 2007-07-21 drh: case 48: dbda8d6ce9 2007-07-21 drh: case 49: dbda8d6ce9 2007-07-21 drh: case 55: dbda8d6ce9 2007-07-21 drh: case 82: dbda8d6ce9 2007-07-21 drh: case 83: dbda8d6ce9 2007-07-21 drh: case 84: dbda8d6ce9 2007-07-21 drh: case 85: dbda8d6ce9 2007-07-21 drh: case 256: dbda8d6ce9 2007-07-21 drh: case 257: dbda8d6ce9 2007-07-21 drh: case 267: dbda8d6ce9 2007-07-21 drh: case 268: dbda8d6ce9 2007-07-21 drh: case 288: dbda8d6ce9 2007-07-21 drh: case 289: dbda8d6ce9 2007-07-21 drh: case 297: dbda8d6ce9 2007-07-21 drh: case 298: dbda8d6ce9 2007-07-21 drh: case 302: dbda8d6ce9 2007-07-21 drh: case 303: dbda8d6ce9 2007-07-21 drh: case 305: dbda8d6ce9 2007-07-21 drh: case 309: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 3: dbda8d6ce9 2007-07-21 drh: { sqlite3FinishCoding(pParse); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 6: dbda8d6ce9 2007-07-21 drh: { sqlite3BeginParse(pParse, 0); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 7: dbda8d6ce9 2007-07-21 drh: { sqlite3BeginParse(pParse, 1); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 8: dbda8d6ce9 2007-07-21 drh: { sqlite3BeginParse(pParse, 2); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 9: dbda8d6ce9 2007-07-21 drh: {sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 13: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = TK_DEFERRED;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 14: dbda8d6ce9 2007-07-21 drh: case 15: dbda8d6ce9 2007-07-21 drh: case 16: dbda8d6ce9 2007-07-21 drh: case 107: dbda8d6ce9 2007-07-21 drh: case 109: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = yymsp[0].major;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 17: dbda8d6ce9 2007-07-21 drh: case 18: dbda8d6ce9 2007-07-21 drh: {sqlite3CommitTransaction(pParse);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 19: dbda8d6ce9 2007-07-21 drh: {sqlite3RollbackTransaction(pParse);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 21: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3StartTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,yymsp[-4].minor.yy46,0,0,yymsp[-2].minor.yy46); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 22: dbda8d6ce9 2007-07-21 drh: case 25: dbda8d6ce9 2007-07-21 drh: case 63: dbda8d6ce9 2007-07-21 drh: case 77: dbda8d6ce9 2007-07-21 drh: case 79: dbda8d6ce9 2007-07-21 drh: case 90: dbda8d6ce9 2007-07-21 drh: case 101: dbda8d6ce9 2007-07-21 drh: case 112: dbda8d6ce9 2007-07-21 drh: case 113: dbda8d6ce9 2007-07-21 drh: case 212: dbda8d6ce9 2007-07-21 drh: case 215: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 23: dbda8d6ce9 2007-07-21 drh: case 24: dbda8d6ce9 2007-07-21 drh: case 64: dbda8d6ce9 2007-07-21 drh: case 78: dbda8d6ce9 2007-07-21 drh: case 100: dbda8d6ce9 2007-07-21 drh: case 111: dbda8d6ce9 2007-07-21 drh: case 213: dbda8d6ce9 2007-07-21 drh: case 216: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = 1;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 26: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3EndTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy0,0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 27: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy219); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(yymsp[0].minor.yy219); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 30: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: yygotominor.yy410.z = yymsp[-2].minor.yy410.z; dbda8d6ce9 2007-07-21 drh: yygotominor.yy410.n = (pParse->sLastToken.z-yymsp[-2].minor.yy410.z) + pParse->sLastToken.n; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 31: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3AddColumn(pParse,&yymsp[0].minor.yy410); dbda8d6ce9 2007-07-21 drh: yygotominor.yy410 = yymsp[0].minor.yy410; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 32: dbda8d6ce9 2007-07-21 drh: case 33: dbda8d6ce9 2007-07-21 drh: case 34: dbda8d6ce9 2007-07-21 drh: case 35: dbda8d6ce9 2007-07-21 drh: case 36: dbda8d6ce9 2007-07-21 drh: case 255: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy410 = yymsp[0].minor.yy0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 38: dbda8d6ce9 2007-07-21 drh: {sqlite3AddColumnType(pParse,&yymsp[0].minor.yy410);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 39: dbda8d6ce9 2007-07-21 drh: case 42: dbda8d6ce9 2007-07-21 drh: case 119: dbda8d6ce9 2007-07-21 drh: case 120: dbda8d6ce9 2007-07-21 drh: case 131: dbda8d6ce9 2007-07-21 drh: case 240: dbda8d6ce9 2007-07-21 drh: case 242: dbda8d6ce9 2007-07-21 drh: case 251: dbda8d6ce9 2007-07-21 drh: case 252: dbda8d6ce9 2007-07-21 drh: case 253: dbda8d6ce9 2007-07-21 drh: case 254: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy410 = yymsp[0].minor.yy410;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 40: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: yygotominor.yy410.z = yymsp[-3].minor.yy410.z; dbda8d6ce9 2007-07-21 drh: yygotominor.yy410.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy410.z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 41: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: yygotominor.yy410.z = yymsp[-5].minor.yy410.z; dbda8d6ce9 2007-07-21 drh: yygotominor.yy410.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy410.z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 43: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy410.z=yymsp[-1].minor.yy410.z; yygotominor.yy410.n=yymsp[0].minor.yy410.n+(yymsp[0].minor.yy410.z-yymsp[-1].minor.yy410.z);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 50: dbda8d6ce9 2007-07-21 drh: case 52: dbda8d6ce9 2007-07-21 drh: {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy172);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 51: dbda8d6ce9 2007-07-21 drh: {sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy172);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 53: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3AddDefaultValue(pParse,p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 54: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: Expr *p = sqlite3PExpr(pParse, TK_STRING, 0, 0, &yymsp[0].minor.yy410); dbda8d6ce9 2007-07-21 drh: sqlite3AddDefaultValue(pParse,p); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 56: dbda8d6ce9 2007-07-21 drh: {sqlite3AddNotNull(pParse, yymsp[0].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 57: dbda8d6ce9 2007-07-21 drh: {sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy46,yymsp[0].minor.yy46,yymsp[-2].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 58: dbda8d6ce9 2007-07-21 drh: {sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy46,0,0,0,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 59: dbda8d6ce9 2007-07-21 drh: {sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy172);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 60: dbda8d6ce9 2007-07-21 drh: {sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy410,yymsp[-1].minor.yy174,yymsp[0].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 61: dbda8d6ce9 2007-07-21 drh: {sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 62: dbda8d6ce9 2007-07-21 drh: {sqlite3AddCollateType(pParse, (char*)yymsp[0].minor.yy410.z, yymsp[0].minor.yy410.n);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 65: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = OE_Restrict * 0x010101; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 66: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = (yymsp[-1].minor.yy46 & yymsp[0].minor.yy405.mask) | yymsp[0].minor.yy405.value; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 67: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy405.value = 0; yygotominor.yy405.mask = 0x000000; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 68: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy405.value = yymsp[0].minor.yy46; yygotominor.yy405.mask = 0x0000ff; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 69: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy405.value = yymsp[0].minor.yy46<<8; yygotominor.yy405.mask = 0x00ff00; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 70: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy405.value = yymsp[0].minor.yy46<<16; yygotominor.yy405.mask = 0xff0000; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 71: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = OE_SetNull; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 72: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = OE_SetDflt; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 73: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = OE_Cascade; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 74: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = OE_Restrict; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 75: dbda8d6ce9 2007-07-21 drh: case 76: dbda8d6ce9 2007-07-21 drh: case 91: dbda8d6ce9 2007-07-21 drh: case 93: dbda8d6ce9 2007-07-21 drh: case 95: dbda8d6ce9 2007-07-21 drh: case 96: dbda8d6ce9 2007-07-21 drh: case 166: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = yymsp[0].minor.yy46;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 80: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy410.n = 0; yygotominor.yy410.z = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 81: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy410 = yymsp[-1].minor.yy0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 86: dbda8d6ce9 2007-07-21 drh: {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy174,yymsp[0].minor.yy46,yymsp[-2].minor.yy46,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 87: dbda8d6ce9 2007-07-21 drh: {sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy174,yymsp[0].minor.yy46,0,0,0,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 88: dbda8d6ce9 2007-07-21 drh: {sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy172);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 89: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy174, &yymsp[-3].minor.yy410, yymsp[-2].minor.yy174, yymsp[-1].minor.yy46); dbda8d6ce9 2007-07-21 drh: sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy46); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 92: dbda8d6ce9 2007-07-21 drh: case 94: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = OE_Default;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 97: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = OE_Ignore;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 98: dbda8d6ce9 2007-07-21 drh: case 167: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = OE_Replace;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 99: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3DropTable(pParse, yymsp[0].minor.yy373, 0, yymsp[-1].minor.yy46); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 102: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, yymsp[0].minor.yy219, yymsp[-6].minor.yy46, yymsp[-4].minor.yy46); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 103: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3DropTable(pParse, yymsp[0].minor.yy373, 1, yymsp[-1].minor.yy46); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 104: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3Select(pParse, yymsp[0].minor.yy219, SRT_Callback, 0, 0, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(yymsp[0].minor.yy219); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 105: dbda8d6ce9 2007-07-21 drh: case 128: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy219 = yymsp[0].minor.yy219;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 106: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: if( yymsp[0].minor.yy219 ){ dbda8d6ce9 2007-07-21 drh: yymsp[0].minor.yy219->op = yymsp[-1].minor.yy46; dbda8d6ce9 2007-07-21 drh: yymsp[0].minor.yy219->pPrior = yymsp[-2].minor.yy219; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(yymsp[-2].minor.yy219); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: yygotominor.yy219 = yymsp[0].minor.yy219; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 108: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = TK_ALL;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 110: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy219 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy174,yymsp[-5].minor.yy373,yymsp[-4].minor.yy172,yymsp[-3].minor.yy174,yymsp[-2].minor.yy172,yymsp[-1].minor.yy174,yymsp[-7].minor.yy46,yymsp[0].minor.yy234.pLimit,yymsp[0].minor.yy234.pOffset); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 114: dbda8d6ce9 2007-07-21 drh: case 237: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy174 = yymsp[-1].minor.yy174;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 115: dbda8d6ce9 2007-07-21 drh: case 141: dbda8d6ce9 2007-07-21 drh: case 149: dbda8d6ce9 2007-07-21 drh: case 230: dbda8d6ce9 2007-07-21 drh: case 236: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy174 = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 116: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy174,yymsp[-1].minor.yy172,yymsp[0].minor.yy410.n?&yymsp[0].minor.yy410:0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 117: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: Expr *p = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0); c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy174, p, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 118: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0); c287665ba8 2007-09-14 drh: Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410); c287665ba8 2007-09-14 drh: Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy174, pDot, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 121: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy410.n = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 122: c287665ba8 2007-09-14 drh: {yygotominor.yy373 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy373));} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 123: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: yygotominor.yy373 = yymsp[0].minor.yy373; dbda8d6ce9 2007-07-21 drh: sqlite3SrcListShiftJoinType(yygotominor.yy373); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 124: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: yygotominor.yy373 = yymsp[-1].minor.yy373; dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy373 && yygotominor.yy373->nSrc>0 ) yygotominor.yy373->a[yygotominor.yy373->nSrc-1].jointype = yymsp[0].minor.yy46; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 125: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy373 = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 126: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy373 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy373,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,0,yymsp[-1].minor.yy172,yymsp[0].minor.yy432); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 127: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy373 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy373,0,0,&yymsp[-2].minor.yy410,yymsp[-4].minor.yy219,yymsp[-1].minor.yy172,yymsp[0].minor.yy432); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 129: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3SrcListShiftJoinType(yymsp[0].minor.yy373); c287665ba8 2007-09-14 drh: yygotominor.yy219 = sqlite3SelectNew(pParse,0,yymsp[0].minor.yy373,0,0,0,0,0,0,0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 130: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy410.z=0; yygotominor.yy410.n=0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 132: c287665ba8 2007-09-14 drh: {yygotominor.yy373 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 133: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = JT_INNER; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 134: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 135: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy410,0); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 136: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy410,&yymsp[-1].minor.yy410); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 137: dbda8d6ce9 2007-07-21 drh: case 145: dbda8d6ce9 2007-07-21 drh: case 152: dbda8d6ce9 2007-07-21 drh: case 159: dbda8d6ce9 2007-07-21 drh: case 174: dbda8d6ce9 2007-07-21 drh: case 202: dbda8d6ce9 2007-07-21 drh: case 225: dbda8d6ce9 2007-07-21 drh: case 227: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy172 = yymsp[0].minor.yy172;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 138: dbda8d6ce9 2007-07-21 drh: case 151: dbda8d6ce9 2007-07-21 drh: case 158: dbda8d6ce9 2007-07-21 drh: case 203: dbda8d6ce9 2007-07-21 drh: case 226: dbda8d6ce9 2007-07-21 drh: case 228: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy172 = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 139: dbda8d6ce9 2007-07-21 drh: case 171: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy432 = yymsp[-1].minor.yy432;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 140: dbda8d6ce9 2007-07-21 drh: case 170: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy432 = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 142: dbda8d6ce9 2007-07-21 drh: case 150: dbda8d6ce9 2007-07-21 drh: case 229: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy174 = yymsp[0].minor.yy174;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 143: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy174,yymsp[-1].minor.yy172,0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 144: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy172,0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy174 && yygotominor.yy174->a ) yygotominor.yy174->a[0].sortOrder = yymsp[0].minor.yy46; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 146: dbda8d6ce9 2007-07-21 drh: case 148: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = SQLITE_SO_ASC;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 147: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = SQLITE_SO_DESC;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 153: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy234.pLimit = 0; yygotominor.yy234.pOffset = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 154: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy234.pLimit = yymsp[0].minor.yy172; yygotominor.yy234.pOffset = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 155: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy234.pLimit = yymsp[-2].minor.yy172; yygotominor.yy234.pOffset = yymsp[0].minor.yy172;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 156: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy234.pOffset = yymsp[-2].minor.yy172; yygotominor.yy234.pLimit = yymsp[0].minor.yy172;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 157: dbda8d6ce9 2007-07-21 drh: {sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy373,yymsp[0].minor.yy172);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 160: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy174,SQLITE_MAX_COLUMN,"set list"); dbda8d6ce9 2007-07-21 drh: sqlite3Update(pParse,yymsp[-3].minor.yy373,yymsp[-1].minor.yy174,yymsp[0].minor.yy172,yymsp[-4].minor.yy46); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 161: c287665ba8 2007-09-14 drh: {yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 162: c287665ba8 2007-09-14 drh: {yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 163: dbda8d6ce9 2007-07-21 drh: {sqlite3Insert(pParse, yymsp[-5].minor.yy373, yymsp[-1].minor.yy174, 0, yymsp[-4].minor.yy432, yymsp[-7].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 164: dbda8d6ce9 2007-07-21 drh: {sqlite3Insert(pParse, yymsp[-2].minor.yy373, 0, yymsp[0].minor.yy219, yymsp[-1].minor.yy432, yymsp[-4].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 165: dbda8d6ce9 2007-07-21 drh: {sqlite3Insert(pParse, yymsp[-3].minor.yy373, 0, 0, yymsp[-2].minor.yy432, yymsp[-5].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 168: dbda8d6ce9 2007-07-21 drh: case 231: c287665ba8 2007-09-14 drh: {yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy174,yymsp[0].minor.yy172,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 169: dbda8d6ce9 2007-07-21 drh: case 232: c287665ba8 2007-09-14 drh: {yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy172,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 172: c287665ba8 2007-09-14 drh: {yygotominor.yy432 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy432,&yymsp[0].minor.yy410);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 173: c287665ba8 2007-09-14 drh: {yygotominor.yy432 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy410);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 175: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy172 = yymsp[-1].minor.yy172; sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 176: dbda8d6ce9 2007-07-21 drh: case 181: dbda8d6ce9 2007-07-21 drh: case 182: c287665ba8 2007-09-14 drh: {yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 177: dbda8d6ce9 2007-07-21 drh: case 178: c287665ba8 2007-09-14 drh: {yygotominor.yy172 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 179: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410); c287665ba8 2007-09-14 drh: Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy410); c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 180: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy410); c287665ba8 2007-09-14 drh: Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410); c287665ba8 2007-09-14 drh: Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy410); c287665ba8 2007-09-14 drh: Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0); c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 183: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy172 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 184: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: Token *pToken = &yymsp[0].minor.yy0; c287665ba8 2007-09-14 drh: Expr *pExpr = yygotominor.yy172 = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken); dbda8d6ce9 2007-07-21 drh: sqlite3ExprAssignVarNumber(pParse, pExpr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 185: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: yygotominor.yy172 = sqlite3ExprSetColl(pParse, yymsp[-2].minor.yy172, &yymsp[0].minor.yy410); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 186: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy172, 0, &yymsp[-1].minor.yy410); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 187: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: if( yymsp[-1].minor.yy174 && yymsp[-1].minor.yy174->nExpr>SQLITE_MAX_FUNCTION_ARG ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy174, &yymsp[-4].minor.yy0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: if( yymsp[-2].minor.yy46 && yygotominor.yy172 ){ dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->flags |= EP_Distinct; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 188: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 189: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are dbda8d6ce9 2007-07-21 drh: ** treated as functions that return constants */ c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3ExprFunction(pParse, 0,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ){ dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->op = TK_CONST_FUNC; dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->span = yymsp[0].minor.yy0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 190: dbda8d6ce9 2007-07-21 drh: case 191: dbda8d6ce9 2007-07-21 drh: case 192: dbda8d6ce9 2007-07-21 drh: case 193: dbda8d6ce9 2007-07-21 drh: case 194: dbda8d6ce9 2007-07-21 drh: case 195: dbda8d6ce9 2007-07-21 drh: case 196: dbda8d6ce9 2007-07-21 drh: case 197: c287665ba8 2007-09-14 drh: {yygotominor.yy172 = sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy172,yymsp[0].minor.yy172,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 198: dbda8d6ce9 2007-07-21 drh: case 200: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 199: dbda8d6ce9 2007-07-21 drh: case 201: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 1;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 204: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: ExprList *pList; c287665ba8 2007-09-14 drh: pList = sqlite3ExprListAppend(pParse,0, yymsp[-1].minor.yy172, 0); c287665ba8 2007-09-14 drh: pList = sqlite3ExprListAppend(pParse,pList, yymsp[-3].minor.yy172, 0); dbda8d6ce9 2007-07-21 drh: if( yymsp[0].minor.yy172 ){ c287665ba8 2007-09-14 drh: pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy172, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3ExprFunction(pParse, pList, &yymsp[-2].minor.yy72.eOperator); c287665ba8 2007-09-14 drh: if( yymsp[-2].minor.yy72.not ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172, &yymsp[-3].minor.yy172->span, &yymsp[-1].minor.yy172->span); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ) yygotominor.yy172->flags |= EP_InfixFunc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 205: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[0].major, yymsp[-1].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy172->span,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 206: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_ISNULL, yymsp[-2].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 207: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOTNULL, yymsp[-2].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 208: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOTNULL, yymsp[-3].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 209: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 210: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 211: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_UPLUS, yymsp[0].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 214: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy172, 0); c287665ba8 2007-09-14 drh: pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy172, 0); c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ){ dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->pList = pList; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(pList); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy172->span); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 217: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ){ dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->pList = yymsp[-1].minor.yy174; dbda8d6ce9 2007-07-21 drh: sqlite3ExprSetHeight(yygotominor.yy172); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(yymsp[-1].minor.yy174); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 218: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ){ dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->pSelect = yymsp[-1].minor.yy219; dbda8d6ce9 2007-07-21 drh: sqlite3ExprSetHeight(yygotominor.yy172); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(yymsp[-1].minor.yy219); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 219: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ){ dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->pSelect = yymsp[-1].minor.yy219; dbda8d6ce9 2007-07-21 drh: sqlite3ExprSetHeight(yygotominor.yy172); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(yymsp[-1].minor.yy219); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 220: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410); c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ){ c287665ba8 2007-09-14 drh: yygotominor.yy172->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSetHeight(yygotominor.yy172); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3SrcListDelete(pSrc); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: if( yymsp[-2].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,yymsp[0].minor.yy410.z?&yymsp[0].minor.yy410:&yymsp[-1].minor.yy410); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 221: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: Expr *p = yygotominor.yy172 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: if( p ){ dbda8d6ce9 2007-07-21 drh: p->pSelect = yymsp[-1].minor.yy219; dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: sqlite3ExprSetHeight(yygotominor.yy172); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3SelectDelete(yymsp[-1].minor.yy219); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 222: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, 0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ){ dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->pList = yymsp[-2].minor.yy174; dbda8d6ce9 2007-07-21 drh: sqlite3ExprSetHeight(yygotominor.yy172); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExprListDelete(yymsp[-2].minor.yy174); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 223: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174, yymsp[-2].minor.yy172, 0); c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,yygotominor.yy174, yymsp[0].minor.yy172, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 224: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy172, 0); c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,yygotominor.yy174, yymsp[0].minor.yy172, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 233: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy410, &yymsp[-5].minor.yy410, c287665ba8 2007-09-14 drh: sqlite3SrcListAppend(pParse->db,0,&yymsp[-3].minor.yy410,0), yymsp[-1].minor.yy174, yymsp[-9].minor.yy46, dbda8d6ce9 2007-07-21 drh: &yymsp[-10].minor.yy0, &yymsp[0].minor.yy0, SQLITE_SO_ASC, yymsp[-7].minor.yy46); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 234: dbda8d6ce9 2007-07-21 drh: case 281: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = OE_Abort;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 235: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = OE_None;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 238: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: Expr *p = 0; dbda8d6ce9 2007-07-21 drh: if( yymsp[-1].minor.yy410.n>0 ){ c287665ba8 2007-09-14 drh: p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy410.z, yymsp[-1].minor.yy410.n); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174, p, &yymsp[-2].minor.yy410); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListCheckLength(pParse, yygotominor.yy174, SQLITE_MAX_COLUMN, "index"); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 239: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: Expr *p = 0; dbda8d6ce9 2007-07-21 drh: if( yymsp[-1].minor.yy410.n>0 ){ c287665ba8 2007-09-14 drh: p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy410.z, yymsp[-1].minor.yy410.n); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: yygotominor.yy174 = sqlite3ExprListAppend(pParse,0, p, &yymsp[-2].minor.yy410); dbda8d6ce9 2007-07-21 drh: sqlite3ExprListCheckLength(pParse, yygotominor.yy174, SQLITE_MAX_COLUMN, "index"); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 241: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy410.z = 0; yygotominor.yy410.n = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 243: dbda8d6ce9 2007-07-21 drh: {sqlite3DropIndex(pParse, yymsp[0].minor.yy373, yymsp[-1].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 244: dbda8d6ce9 2007-07-21 drh: case 245: dbda8d6ce9 2007-07-21 drh: {sqlite3Vacuum(pParse);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 246: dbda8d6ce9 2007-07-21 drh: {sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 247: dbda8d6ce9 2007-07-21 drh: {sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy0,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 248: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 249: dbda8d6ce9 2007-07-21 drh: {sqlite3Pragma(pParse,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-1].minor.yy410,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 250: dbda8d6ce9 2007-07-21 drh: {sqlite3Pragma(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,0,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 258: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: Token all; dbda8d6ce9 2007-07-21 drh: all.z = yymsp[-3].minor.yy410.z; dbda8d6ce9 2007-07-21 drh: all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy410.z) + yymsp[0].minor.yy0.n; dbda8d6ce9 2007-07-21 drh: sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy243, &all); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 259: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy410, &yymsp[-6].minor.yy410, yymsp[-5].minor.yy46, yymsp[-4].minor.yy370.a, yymsp[-4].minor.yy370.b, yymsp[-2].minor.yy373, yymsp[0].minor.yy172, yymsp[-10].minor.yy46, yymsp[-8].minor.yy46); dbda8d6ce9 2007-07-21 drh: yygotominor.yy410 = (yymsp[-6].minor.yy410.n==0?yymsp[-7].minor.yy410:yymsp[-6].minor.yy410); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 260: dbda8d6ce9 2007-07-21 drh: case 263: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = TK_BEFORE; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 261: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = TK_AFTER; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 262: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy46 = TK_INSTEAD;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 264: dbda8d6ce9 2007-07-21 drh: case 265: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy370.a = yymsp[0].major; yygotominor.yy370.b = 0;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 266: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy370.a = TK_UPDATE; yygotominor.yy370.b = yymsp[0].minor.yy432;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 269: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy172 = 0; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 270: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy172 = yymsp[0].minor.yy172; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 271: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: if( yymsp[-2].minor.yy243 ){ dbda8d6ce9 2007-07-21 drh: yymsp[-2].minor.yy243->pLast->pNext = yymsp[-1].minor.yy243; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: yymsp[-2].minor.yy243 = yymsp[-1].minor.yy243; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: yymsp[-2].minor.yy243->pLast = yymsp[-1].minor.yy243; dbda8d6ce9 2007-07-21 drh: yygotominor.yy243 = yymsp[-2].minor.yy243; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 272: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy243 = 0; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 273: c287665ba8 2007-09-14 drh: { yygotominor.yy243 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-3].minor.yy410, yymsp[-1].minor.yy174, yymsp[0].minor.yy172, yymsp[-4].minor.yy46); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 274: c287665ba8 2007-09-14 drh: {yygotominor.yy243 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-5].minor.yy410, yymsp[-4].minor.yy432, yymsp[-1].minor.yy174, 0, yymsp[-7].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 275: c287665ba8 2007-09-14 drh: {yygotominor.yy243 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy410, yymsp[-1].minor.yy432, 0, yymsp[0].minor.yy219, yymsp[-4].minor.yy46);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 276: c287665ba8 2007-09-14 drh: {yygotominor.yy243 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-1].minor.yy410, yymsp[0].minor.yy172);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 277: c287665ba8 2007-09-14 drh: {yygotominor.yy243 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy219); } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 278: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ){ dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->iColumn = OE_Ignore; dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 279: dbda8d6ce9 2007-07-21 drh: { c287665ba8 2007-09-14 drh: yygotominor.yy172 = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy410); dbda8d6ce9 2007-07-21 drh: if( yygotominor.yy172 ) { dbda8d6ce9 2007-07-21 drh: yygotominor.yy172->iColumn = yymsp[-3].minor.yy46; dbda8d6ce9 2007-07-21 drh: sqlite3ExprSpan(yygotominor.yy172, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 280: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = OE_Rollback;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 282: dbda8d6ce9 2007-07-21 drh: {yygotominor.yy46 = OE_Fail;} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 283: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3DropTrigger(pParse,yymsp[0].minor.yy373,yymsp[-1].minor.yy46); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 284: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3Attach(pParse, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, yymsp[0].minor.yy386); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 285: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3Detach(pParse, yymsp[0].minor.yy172); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 286: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy386 = 0; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 287: dbda8d6ce9 2007-07-21 drh: { yygotominor.yy386 = yymsp[0].minor.yy172; } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 290: dbda8d6ce9 2007-07-21 drh: {sqlite3Reindex(pParse, 0, 0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 291: dbda8d6ce9 2007-07-21 drh: {sqlite3Reindex(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 292: dbda8d6ce9 2007-07-21 drh: {sqlite3Analyze(pParse, 0, 0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 293: dbda8d6ce9 2007-07-21 drh: {sqlite3Analyze(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 294: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy373,&yymsp[0].minor.yy410); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 295: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy410); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 296: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy373); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 299: dbda8d6ce9 2007-07-21 drh: {sqlite3VtabFinishParse(pParse,0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 300: dbda8d6ce9 2007-07-21 drh: {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 301: dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, &yymsp[0].minor.yy410); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 304: dbda8d6ce9 2007-07-21 drh: {sqlite3VtabArgInit(pParse);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: case 306: dbda8d6ce9 2007-07-21 drh: case 307: dbda8d6ce9 2007-07-21 drh: case 308: dbda8d6ce9 2007-07-21 drh: case 310: dbda8d6ce9 2007-07-21 drh: {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: yygoto = yyRuleInfo[yyruleno].lhs; dbda8d6ce9 2007-07-21 drh: yysize = yyRuleInfo[yyruleno].nrhs; dbda8d6ce9 2007-07-21 drh: yypParser->yyidx -= yysize; dbda8d6ce9 2007-07-21 drh: yyact = yy_find_reduce_action(yymsp[-yysize].stateno,yygoto); dbda8d6ce9 2007-07-21 drh: if( yyact < YYNSTATE ){ dbda8d6ce9 2007-07-21 drh: #ifdef NDEBUG dbda8d6ce9 2007-07-21 drh: /* If we are not debugging and the reduce action popped at least dbda8d6ce9 2007-07-21 drh: ** one element off the stack, then we can push the new element back dbda8d6ce9 2007-07-21 drh: ** onto the stack here, and skip the stack overflow test in yy_shift(). dbda8d6ce9 2007-07-21 drh: ** That gives a significant speed improvement. */ dbda8d6ce9 2007-07-21 drh: if( yysize ){ dbda8d6ce9 2007-07-21 drh: yypParser->yyidx++; dbda8d6ce9 2007-07-21 drh: yymsp -= yysize-1; dbda8d6ce9 2007-07-21 drh: yymsp->stateno = yyact; dbda8d6ce9 2007-07-21 drh: yymsp->major = yygoto; dbda8d6ce9 2007-07-21 drh: yymsp->minor = yygotominor; dbda8d6ce9 2007-07-21 drh: }else dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: yy_shift(yypParser,yyact,yygoto,&yygotominor); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( yyact == YYNSTATE + YYNRULE + 1 ){ dbda8d6ce9 2007-07-21 drh: yy_accept(yypParser); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following code executes when the parse fails dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void yy_parse_failed( dbda8d6ce9 2007-07-21 drh: yyParser *yypParser /* The parser */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_FETCH; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); dbda8d6ce9 2007-07-21 drh: /* Here code is inserted which will be executed whenever the dbda8d6ce9 2007-07-21 drh: ** parser fails */ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following code executes when a syntax error first occurs. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void yy_syntax_error( dbda8d6ce9 2007-07-21 drh: yyParser *yypParser, /* The parser */ dbda8d6ce9 2007-07-21 drh: int yymajor, /* The major type of the error token */ dbda8d6ce9 2007-07-21 drh: YYMINORTYPE yyminor /* The minor type of the error token */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_FETCH; dbda8d6ce9 2007-07-21 drh: #define TOKEN (yyminor.yy0) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !pParse->parseError ){ dbda8d6ce9 2007-07-21 drh: if( TOKEN.z[0] ){ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ErrorMsg(pParse, "incomplete SQL statement"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->parseError = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following is executed when the parser accepts dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void yy_accept( dbda8d6ce9 2007-07-21 drh: yyParser *yypParser /* The parser */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_FETCH; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); dbda8d6ce9 2007-07-21 drh: /* Here code is inserted which will be executed whenever the dbda8d6ce9 2007-07-21 drh: ** parser accepts */ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The main parser program. dbda8d6ce9 2007-07-21 drh: ** The first argument is a pointer to a structure obtained from dbda8d6ce9 2007-07-21 drh: ** "sqlite3ParserAlloc" which describes the current state of the parser. dbda8d6ce9 2007-07-21 drh: ** The second argument is the major token number. The third is dbda8d6ce9 2007-07-21 drh: ** the minor token. The fourth optional argument is whatever the dbda8d6ce9 2007-07-21 drh: ** user wants (and specified in the grammar) and is available for dbda8d6ce9 2007-07-21 drh: ** use by the action routines. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Inputs: dbda8d6ce9 2007-07-21 drh: ** <ul> dbda8d6ce9 2007-07-21 drh: ** <li> A pointer to the parser (an opaque structure.) dbda8d6ce9 2007-07-21 drh: ** <li> The major token number. dbda8d6ce9 2007-07-21 drh: ** <li> The minor token number. dbda8d6ce9 2007-07-21 drh: ** <li> An option argument of a grammar-specified type. dbda8d6ce9 2007-07-21 drh: ** </ul> dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Outputs: dbda8d6ce9 2007-07-21 drh: ** None. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3Parser( dbda8d6ce9 2007-07-21 drh: void *yyp, /* The parser */ dbda8d6ce9 2007-07-21 drh: int yymajor, /* The major token code number */ dbda8d6ce9 2007-07-21 drh: sqlite3ParserTOKENTYPE yyminor /* The value for the token */ dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: YYMINORTYPE yyminorunion; dbda8d6ce9 2007-07-21 drh: int yyact; /* The parser action. */ dbda8d6ce9 2007-07-21 drh: int yyendofinput; /* True if we are at the end of input */ dbda8d6ce9 2007-07-21 drh: int yyerrorhit = 0; /* True if yymajor has invoked an error */ dbda8d6ce9 2007-07-21 drh: yyParser *yypParser; /* The parser */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* (re)initialize the parser, if necessary */ dbda8d6ce9 2007-07-21 drh: yypParser = (yyParser*)yyp; dbda8d6ce9 2007-07-21 drh: if( yypParser->yyidx<0 ){ dbda8d6ce9 2007-07-21 drh: #if YYSTACKDEPTH<=0 dbda8d6ce9 2007-07-21 drh: if( yypParser->yystksz <=0 ){ dbda8d6ce9 2007-07-21 drh: memset(&yyminorunion, 0, sizeof(yyminorunion)); dbda8d6ce9 2007-07-21 drh: yyStackOverflow(yypParser, &yyminorunion); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: yypParser->yyidx = 0; dbda8d6ce9 2007-07-21 drh: yypParser->yyerrcnt = -1; dbda8d6ce9 2007-07-21 drh: yypParser->yystack[0].stateno = 0; dbda8d6ce9 2007-07-21 drh: yypParser->yystack[0].major = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: yyminorunion.yy0 = yyminor; dbda8d6ce9 2007-07-21 drh: yyendofinput = (yymajor==0); dbda8d6ce9 2007-07-21 drh: sqlite3ParserARG_STORE; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: yyact = yy_find_shift_action(yypParser,yymajor); dbda8d6ce9 2007-07-21 drh: if( yyact<YYNSTATE ){ dbda8d6ce9 2007-07-21 drh: yy_shift(yypParser,yyact,yymajor,&yyminorunion); dbda8d6ce9 2007-07-21 drh: yypParser->yyerrcnt--; dbda8d6ce9 2007-07-21 drh: if( yyendofinput && yypParser->yyidx>=0 ){ dbda8d6ce9 2007-07-21 drh: yymajor = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: yymajor = YYNOCODE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( yyact < YYNSTATE + YYNRULE ){ dbda8d6ce9 2007-07-21 drh: yy_reduce(yypParser,yyact-YYNSTATE); dbda8d6ce9 2007-07-21 drh: }else if( yyact == YY_ERROR_ACTION ){ dbda8d6ce9 2007-07-21 drh: int yymx; dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef YYERRORSYMBOL dbda8d6ce9 2007-07-21 drh: /* A syntax error has occurred. dbda8d6ce9 2007-07-21 drh: ** The response to an error depends upon whether or not the dbda8d6ce9 2007-07-21 drh: ** grammar defines an error token "ERROR". dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This is what we do if the grammar does define ERROR: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Call the %syntax_error function. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Begin popping the stack until we enter a state where dbda8d6ce9 2007-07-21 drh: ** it is legal to shift the error symbol, then shift dbda8d6ce9 2007-07-21 drh: ** the error symbol. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Set the error count to three. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Begin accepting and shifting new tokens. No new error dbda8d6ce9 2007-07-21 drh: ** processing will occur until three tokens have been dbda8d6ce9 2007-07-21 drh: ** shifted successfully. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( yypParser->yyerrcnt<0 ){ dbda8d6ce9 2007-07-21 drh: yy_syntax_error(yypParser,yymajor,yyminorunion); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: yymx = yypParser->yystack[yypParser->yyidx].major; dbda8d6ce9 2007-07-21 drh: if( yymx==YYERRORSYMBOL || yyerrorhit ){ dbda8d6ce9 2007-07-21 drh: #ifndef NDEBUG dbda8d6ce9 2007-07-21 drh: if( yyTraceFILE ){ dbda8d6ce9 2007-07-21 drh: fprintf(yyTraceFILE,"%sDiscard input token %s\n", dbda8d6ce9 2007-07-21 drh: yyTracePrompt,yyTokenName[yymajor]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: yy_destructor(yymajor,&yyminorunion); dbda8d6ce9 2007-07-21 drh: yymajor = YYNOCODE; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: while( dbda8d6ce9 2007-07-21 drh: yypParser->yyidx >= 0 && dbda8d6ce9 2007-07-21 drh: yymx != YYERRORSYMBOL && dbda8d6ce9 2007-07-21 drh: (yyact = yy_find_reduce_action( dbda8d6ce9 2007-07-21 drh: yypParser->yystack[yypParser->yyidx].stateno, dbda8d6ce9 2007-07-21 drh: YYERRORSYMBOL)) >= YYNSTATE dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: yy_pop_parser_stack(yypParser); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( yypParser->yyidx < 0 || yymajor==0 ){ dbda8d6ce9 2007-07-21 drh: yy_destructor(yymajor,&yyminorunion); dbda8d6ce9 2007-07-21 drh: yy_parse_failed(yypParser); dbda8d6ce9 2007-07-21 drh: yymajor = YYNOCODE; dbda8d6ce9 2007-07-21 drh: }else if( yymx!=YYERRORSYMBOL ){ dbda8d6ce9 2007-07-21 drh: YYMINORTYPE u2; dbda8d6ce9 2007-07-21 drh: u2.YYERRSYMDT = 0; dbda8d6ce9 2007-07-21 drh: yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: yypParser->yyerrcnt = 3; dbda8d6ce9 2007-07-21 drh: yyerrorhit = 1; dbda8d6ce9 2007-07-21 drh: #else /* YYERRORSYMBOL is not defined */ dbda8d6ce9 2007-07-21 drh: /* This is what we do if the grammar does not define ERROR: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * Report an error message, and throw away the input token. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** * If the input token is $, then fail the parse. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** As before, subsequent error messages are suppressed until dbda8d6ce9 2007-07-21 drh: ** three input tokens have been successfully shifted. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( yypParser->yyerrcnt<=0 ){ dbda8d6ce9 2007-07-21 drh: yy_syntax_error(yypParser,yymajor,yyminorunion); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: yypParser->yyerrcnt = 3; dbda8d6ce9 2007-07-21 drh: yy_destructor(yymajor,&yyminorunion); dbda8d6ce9 2007-07-21 drh: if( yyendofinput ){ dbda8d6ce9 2007-07-21 drh: yy_parse_failed(yypParser); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: yymajor = YYNOCODE; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: yy_accept(yypParser); dbda8d6ce9 2007-07-21 drh: yymajor = YYNOCODE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of parse.c ***********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file tokenize.c ****************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** An tokenizer for SQL dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains C code that splits an SQL input string up into dbda8d6ce9 2007-07-21 drh: ** individual tokens and sends those tokens one-by-one over to the dbda8d6ce9 2007-07-21 drh: ** parser for analysis. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: tokenize.c,v 1.136 2007/08/27 23:26:59 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The charMap() macro maps alphabetic characters into their dbda8d6ce9 2007-07-21 drh: ** lower-case ASCII equivalent. On ASCII machines, this is just dbda8d6ce9 2007-07-21 drh: ** an upper-to-lower case map. On EBCDIC machines we also need dbda8d6ce9 2007-07-21 drh: ** to adjust the encoding. Only alphabetic characters and underscores dbda8d6ce9 2007-07-21 drh: ** need to be translated. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ASCII dbda8d6ce9 2007-07-21 drh: # define charMap(X) sqlite3UpperToLower[(unsigned char)X] dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_EBCDIC dbda8d6ce9 2007-07-21 drh: # define charMap(X) ebcdicToAscii[(unsigned char)X] dbda8d6ce9 2007-07-21 drh: const unsigned char ebcdicToAscii[] = { dbda8d6ce9 2007-07-21 drh: /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ dbda8d6ce9 2007-07-21 drh: 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */ dbda8d6ce9 2007-07-21 drh: 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */ dbda8d6ce9 2007-07-21 drh: 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ dbda8d6ce9 2007-07-21 drh: 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */ dbda8d6ce9 2007-07-21 drh: 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */ dbda8d6ce9 2007-07-21 drh: 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */ dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The sqlite3KeywordCode function looks up an identifier to determine if dbda8d6ce9 2007-07-21 drh: ** it is a keyword. If it is a keyword, the token code of that keyword is dbda8d6ce9 2007-07-21 drh: ** returned. If the input is not a keyword, TK_ID is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The implementation of this routine was generated by a program, dbda8d6ce9 2007-07-21 drh: ** mkkeywordhash.h, located in the tool subdirectory of the distribution. dbda8d6ce9 2007-07-21 drh: ** The output of the mkkeywordhash.c program is written into a file dbda8d6ce9 2007-07-21 drh: ** named keywordhash.h and then included into this source file by dbda8d6ce9 2007-07-21 drh: ** the #include below. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /************** Include keywordhash.h in the middle of tokenize.c ************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file keywordhash.h *************************************/ dbda8d6ce9 2007-07-21 drh: /***** This file contains automatically generated code ****** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code in this file has been automatically generated by dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Header: /sqlite/sqlite/tool/mkkeywordhash.c,v 1.31 2007/07/30 18:26:20 rse Exp $ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The code in this file implements a function that determines whether dbda8d6ce9 2007-07-21 drh: ** or not a given identifier is really an SQL keyword. The same thing dbda8d6ce9 2007-07-21 drh: ** might be implemented more directly using a hand-written hash table. dbda8d6ce9 2007-07-21 drh: ** But by using this automatically generated code, the size of the code dbda8d6ce9 2007-07-21 drh: ** is substantially reduced. This is important for embedded applications dbda8d6ce9 2007-07-21 drh: ** on platforms with limited memory. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* Hash score: 165 */ dbda8d6ce9 2007-07-21 drh: static int keywordCode(const char *z, int n){ dbda8d6ce9 2007-07-21 drh: /* zText[] encodes 775 bytes of keywords in 526 bytes */ dbda8d6ce9 2007-07-21 drh: static const char zText[526] = dbda8d6ce9 2007-07-21 drh: "BEFOREIGNOREGEXPLAINSTEADDESCAPEACHECKEYCONSTRAINTERSECTABLEFT" dbda8d6ce9 2007-07-21 drh: "HENDATABASELECTRANSACTIONATURALTERAISELSEXCEPTRIGGEREFERENCES" dbda8d6ce9 2007-07-21 drh: "UNIQUERYATTACHAVINGROUPDATEMPORARYBEGINNEREINDEXCLUSIVEXISTSBETWEEN" dbda8d6ce9 2007-07-21 drh: "OTNULLIKECASCADEFERRABLECASECOLLATECREATECURRENT_DATEDELETEDETACH" dbda8d6ce9 2007-07-21 drh: "IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN" dbda8d6ce9 2007-07-21 drh: "WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMITCONFLICT" dbda8d6ce9 2007-07-21 drh: "CROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAILFROMFULLGLOB" dbda8d6ce9 2007-07-21 drh: "YIFINTOFFSETISNULLORDERESTRICTOUTERIGHTROLLBACKROWUNIONUSINGVACUUM" dbda8d6ce9 2007-07-21 drh: "VIEWINITIALLY"; dbda8d6ce9 2007-07-21 drh: static const unsigned char aHash[127] = { dbda8d6ce9 2007-07-21 drh: 63, 92, 109, 61, 0, 38, 0, 0, 69, 0, 64, 0, 0, dbda8d6ce9 2007-07-21 drh: 102, 4, 65, 7, 0, 108, 72, 103, 99, 0, 22, 0, 0, dbda8d6ce9 2007-07-21 drh: 113, 0, 111, 106, 0, 18, 80, 0, 1, 0, 0, 56, 57, dbda8d6ce9 2007-07-21 drh: 0, 55, 11, 0, 33, 77, 89, 0, 110, 88, 0, 0, 45, dbda8d6ce9 2007-07-21 drh: 0, 90, 54, 0, 20, 0, 114, 34, 19, 0, 10, 97, 28, dbda8d6ce9 2007-07-21 drh: 83, 0, 0, 116, 93, 47, 115, 41, 12, 44, 0, 78, 0, dbda8d6ce9 2007-07-21 drh: 87, 29, 0, 86, 0, 0, 0, 82, 79, 84, 75, 96, 6, dbda8d6ce9 2007-07-21 drh: 14, 95, 0, 68, 0, 21, 76, 98, 27, 0, 112, 67, 104, dbda8d6ce9 2007-07-21 drh: 49, 40, 71, 0, 0, 81, 100, 0, 107, 0, 15, 0, 0, dbda8d6ce9 2007-07-21 drh: 24, 0, 73, 42, 50, 0, 16, 48, 0, 37, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: static const unsigned char aNext[116] = { dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, dbda8d6ce9 2007-07-21 drh: 17, 0, 0, 0, 36, 39, 0, 0, 25, 0, 0, 31, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 43, 52, 0, 0, 0, 53, 0, 0, 0, 0, 0, dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 51, 0, 0, 0, 0, 26, 0, 8, 46, dbda8d6ce9 2007-07-21 drh: 2, 0, 0, 0, 0, 0, 0, 0, 3, 58, 66, 0, 13, dbda8d6ce9 2007-07-21 drh: 0, 91, 85, 0, 94, 0, 74, 0, 0, 62, 0, 35, 101, dbda8d6ce9 2007-07-21 drh: 0, 0, 105, 23, 30, 60, 70, 0, 0, 59, 0, 0, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: static const unsigned char aLen[116] = { dbda8d6ce9 2007-07-21 drh: 6, 7, 3, 6, 6, 7, 7, 3, 4, 6, 4, 5, 3, dbda8d6ce9 2007-07-21 drh: 10, 9, 5, 4, 4, 3, 8, 2, 6, 11, 2, 7, 5, dbda8d6ce9 2007-07-21 drh: 5, 4, 6, 7, 10, 6, 5, 6, 6, 5, 6, 4, 9, dbda8d6ce9 2007-07-21 drh: 2, 5, 5, 7, 5, 9, 6, 7, 7, 3, 4, 4, 7, dbda8d6ce9 2007-07-21 drh: 3, 10, 4, 7, 6, 12, 6, 6, 9, 4, 6, 5, 4, dbda8d6ce9 2007-07-21 drh: 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, dbda8d6ce9 2007-07-21 drh: 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, dbda8d6ce9 2007-07-21 drh: 2, 4, 4, 4, 4, 4, 2, 2, 4, 6, 2, 3, 6, dbda8d6ce9 2007-07-21 drh: 5, 8, 5, 5, 8, 3, 5, 5, 6, 4, 9, 3, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: static const unsigned short int aOffset[116] = { dbda8d6ce9 2007-07-21 drh: 0, 2, 2, 6, 10, 13, 18, 23, 25, 26, 31, 33, 37, dbda8d6ce9 2007-07-21 drh: 40, 47, 55, 58, 61, 63, 65, 70, 71, 76, 85, 86, 91, dbda8d6ce9 2007-07-21 drh: 95, 99, 102, 107, 113, 123, 126, 131, 136, 141, 144, 148, 148, dbda8d6ce9 2007-07-21 drh: 152, 157, 160, 164, 166, 169, 177, 183, 189, 189, 192, 195, 199, dbda8d6ce9 2007-07-21 drh: 200, 204, 214, 218, 225, 231, 243, 249, 255, 264, 266, 272, 277, dbda8d6ce9 2007-07-21 drh: 279, 286, 291, 296, 302, 308, 313, 317, 320, 326, 330, 337, 339, dbda8d6ce9 2007-07-21 drh: 346, 348, 350, 359, 363, 369, 375, 383, 388, 388, 404, 411, 418, dbda8d6ce9 2007-07-21 drh: 419, 426, 430, 434, 438, 442, 445, 447, 449, 452, 452, 455, 458, dbda8d6ce9 2007-07-21 drh: 464, 468, 476, 480, 485, 493, 496, 501, 506, 512, 516, 521, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: static const unsigned char aCode[116] = { dbda8d6ce9 2007-07-21 drh: TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW, dbda8d6ce9 2007-07-21 drh: TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DESC, TK_ESCAPE, dbda8d6ce9 2007-07-21 drh: TK_EACH, TK_CHECK, TK_KEY, TK_CONSTRAINT, TK_INTERSECT, dbda8d6ce9 2007-07-21 drh: TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DATABASE, dbda8d6ce9 2007-07-21 drh: TK_AS, TK_SELECT, TK_TRANSACTION,TK_ON, TK_JOIN_KW, dbda8d6ce9 2007-07-21 drh: TK_ALTER, TK_RAISE, TK_ELSE, TK_EXCEPT, TK_TRIGGER, dbda8d6ce9 2007-07-21 drh: TK_REFERENCES, TK_UNIQUE, TK_QUERY, TK_ATTACH, TK_HAVING, dbda8d6ce9 2007-07-21 drh: TK_GROUP, TK_UPDATE, TK_TEMP, TK_TEMP, TK_OR, dbda8d6ce9 2007-07-21 drh: TK_BEGIN, TK_JOIN_KW, TK_REINDEX, TK_INDEX, TK_EXCLUSIVE, dbda8d6ce9 2007-07-21 drh: TK_EXISTS, TK_BETWEEN, TK_NOTNULL, TK_NOT, TK_NULL, dbda8d6ce9 2007-07-21 drh: TK_LIKE_KW, TK_CASCADE, TK_ASC, TK_DEFERRABLE, TK_CASE, dbda8d6ce9 2007-07-21 drh: TK_COLLATE, TK_CREATE, TK_CTIME_KW, TK_DELETE, TK_DETACH, dbda8d6ce9 2007-07-21 drh: TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH, TK_PLAN, dbda8d6ce9 2007-07-21 drh: TK_ANALYZE, TK_PRAGMA, TK_ABORT, TK_VALUES, TK_VIRTUAL, dbda8d6ce9 2007-07-21 drh: TK_LIMIT, TK_WHEN, TK_WHERE, TK_RENAME, TK_AFTER, dbda8d6ce9 2007-07-21 drh: TK_REPLACE, TK_AND, TK_DEFAULT, TK_AUTOINCR, TK_TO, dbda8d6ce9 2007-07-21 drh: TK_IN, TK_CAST, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, dbda8d6ce9 2007-07-21 drh: TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, dbda8d6ce9 2007-07-21 drh: TK_DISTINCT, TK_IS, TK_DROP, TK_FAIL, TK_FROM, dbda8d6ce9 2007-07-21 drh: TK_JOIN_KW, TK_LIKE_KW, TK_BY, TK_IF, TK_INTO, dbda8d6ce9 2007-07-21 drh: TK_OFFSET, TK_OF, TK_SET, TK_ISNULL, TK_ORDER, dbda8d6ce9 2007-07-21 drh: TK_RESTRICT, TK_JOIN_KW, TK_JOIN_KW, TK_ROLLBACK, TK_ROW, dbda8d6ce9 2007-07-21 drh: TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_INITIALLY, dbda8d6ce9 2007-07-21 drh: TK_ALL, dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: int h, i; dbda8d6ce9 2007-07-21 drh: if( n<2 ) return TK_ID; dbda8d6ce9 2007-07-21 drh: h = ((charMap(z[0])*4) ^ dbda8d6ce9 2007-07-21 drh: (charMap(z[n-1])*3) ^ dbda8d6ce9 2007-07-21 drh: n) % 127; dbda8d6ce9 2007-07-21 drh: for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){ dbda8d6ce9 2007-07-21 drh: if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){ dbda8d6ce9 2007-07-21 drh: return aCode[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return TK_ID; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){ dbda8d6ce9 2007-07-21 drh: return keywordCode((char*)z, n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of keywordhash.h *****************************************/ dbda8d6ce9 2007-07-21 drh: /************** Continuing where we left off in tokenize.c *******************/ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If X is a character that can be used in an identifier then dbda8d6ce9 2007-07-21 drh: ** IdChar(X) will be true. Otherwise it is false. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For ASCII, any character with the high-order bit set is dbda8d6ce9 2007-07-21 drh: ** allowed in an identifier. For 7-bit characters, dbda8d6ce9 2007-07-21 drh: ** sqlite3IsIdChar[X] must be 1. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** For EBCDIC, the rules are more complex but have the same dbda8d6ce9 2007-07-21 drh: ** end result. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Ticket #1066. the SQL standard does not allow '$' in the dbda8d6ce9 2007-07-21 drh: ** middle of identfiers. But many SQL implementations do. dbda8d6ce9 2007-07-21 drh: ** SQLite will allow '$' in identifiers for compatibility. dbda8d6ce9 2007-07-21 drh: ** But the feature is undocumented. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ASCII c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char sqlite3IsAsciiIdChar[] = { dbda8d6ce9 2007-07-21 drh: /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ dbda8d6ce9 2007-07-21 drh: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ dbda8d6ce9 2007-07-21 drh: 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ dbda8d6ce9 2007-07-21 drh: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ dbda8d6ce9 2007-07-21 drh: 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ dbda8d6ce9 2007-07-21 drh: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ dbda8d6ce9 2007-07-21 drh: }; c287665ba8 2007-09-14 drh: #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20])) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_EBCDIC c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = { dbda8d6ce9 2007-07-21 drh: /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ dbda8d6ce9 2007-07-21 drh: 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */ dbda8d6ce9 2007-07-21 drh: 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */ dbda8d6ce9 2007-07-21 drh: 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 6x */ dbda8d6ce9 2007-07-21 drh: 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* 7x */ dbda8d6ce9 2007-07-21 drh: 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* 8x */ dbda8d6ce9 2007-07-21 drh: 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, /* 9x */ dbda8d6ce9 2007-07-21 drh: 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, /* Ax */ dbda8d6ce9 2007-07-21 drh: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ dbda8d6ce9 2007-07-21 drh: 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Cx */ dbda8d6ce9 2007-07-21 drh: 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */ dbda8d6ce9 2007-07-21 drh: 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */ dbda8d6ce9 2007-07-21 drh: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */ dbda8d6ce9 2007-07-21 drh: }; c287665ba8 2007-09-14 drh: #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the length of the token that begins at z[0]. dbda8d6ce9 2007-07-21 drh: ** Store the token type in *tokenType before returning. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int getToken(const unsigned char *z, int *tokenType){ dbda8d6ce9 2007-07-21 drh: int i, c; dbda8d6ce9 2007-07-21 drh: switch( *z ){ dbda8d6ce9 2007-07-21 drh: case ' ': case '\t': case '\n': case '\f': case '\r': { dbda8d6ce9 2007-07-21 drh: for(i=1; isspace(z[i]); i++){} dbda8d6ce9 2007-07-21 drh: *tokenType = TK_SPACE; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '-': { dbda8d6ce9 2007-07-21 drh: if( z[1]=='-' ){ dbda8d6ce9 2007-07-21 drh: for(i=2; (c=z[i])!=0 && c!='\n'; i++){} dbda8d6ce9 2007-07-21 drh: *tokenType = TK_COMMENT; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *tokenType = TK_MINUS; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '(': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_LP; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case ')': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_RP; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case ';': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_SEMI; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '+': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_PLUS; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '*': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_STAR; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '/': { dbda8d6ce9 2007-07-21 drh: if( z[1]!='*' || z[2]==0 ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_SLASH; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} dbda8d6ce9 2007-07-21 drh: if( c ) i++; dbda8d6ce9 2007-07-21 drh: *tokenType = TK_COMMENT; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '%': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_REM; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '=': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_EQ; dbda8d6ce9 2007-07-21 drh: return 1 + (z[1]=='='); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '<': { dbda8d6ce9 2007-07-21 drh: if( (c=z[1])=='=' ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_LE; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: }else if( c=='>' ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_NE; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: }else if( c=='<' ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_LSHIFT; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_LT; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '>': { dbda8d6ce9 2007-07-21 drh: if( (c=z[1])=='=' ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_GE; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: }else if( c=='>' ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_RSHIFT; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_GT; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '!': { dbda8d6ce9 2007-07-21 drh: if( z[1]!='=' ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_ILLEGAL; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_NE; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '|': { dbda8d6ce9 2007-07-21 drh: if( z[1]!='|' ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_BITOR; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_CONCAT; dbda8d6ce9 2007-07-21 drh: return 2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case ',': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_COMMA; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '&': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_BITAND; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '~': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_BITNOT; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '`': dbda8d6ce9 2007-07-21 drh: case '\'': dbda8d6ce9 2007-07-21 drh: case '"': { dbda8d6ce9 2007-07-21 drh: int delim = z[0]; dbda8d6ce9 2007-07-21 drh: for(i=1; (c=z[i])!=0; i++){ dbda8d6ce9 2007-07-21 drh: if( c==delim ){ dbda8d6ce9 2007-07-21 drh: if( z[i+1]==delim ){ dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( c ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_STRING; dbda8d6ce9 2007-07-21 drh: return i+1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_ILLEGAL; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '.': { dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: if( !isdigit(z[1]) ) dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_DOT; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* If the next character is a digit, this is a floating point dbda8d6ce9 2007-07-21 drh: ** number that begins with ".". Fall thru into the next case */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '0': case '1': case '2': case '3': case '4': dbda8d6ce9 2007-07-21 drh: case '5': case '6': case '7': case '8': case '9': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_INTEGER; dbda8d6ce9 2007-07-21 drh: for(i=0; isdigit(z[i]); i++){} dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_FLOATING_POINT dbda8d6ce9 2007-07-21 drh: if( z[i]=='.' ){ dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: while( isdigit(z[i]) ){ i++; } dbda8d6ce9 2007-07-21 drh: *tokenType = TK_FLOAT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( (z[i]=='e' || z[i]=='E') && dbda8d6ce9 2007-07-21 drh: ( isdigit(z[i+1]) dbda8d6ce9 2007-07-21 drh: || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2])) dbda8d6ce9 2007-07-21 drh: ) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: i += 2; dbda8d6ce9 2007-07-21 drh: while( isdigit(z[i]) ){ i++; } dbda8d6ce9 2007-07-21 drh: *tokenType = TK_FLOAT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: while( IdChar(z[i]) ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_ILLEGAL; dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '[': { dbda8d6ce9 2007-07-21 drh: for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} dbda8d6ce9 2007-07-21 drh: *tokenType = TK_ID; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '?': { dbda8d6ce9 2007-07-21 drh: *tokenType = TK_VARIABLE; dbda8d6ce9 2007-07-21 drh: for(i=1; isdigit(z[i]); i++){} dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case '#': { dbda8d6ce9 2007-07-21 drh: for(i=1; isdigit(z[i]); i++){} dbda8d6ce9 2007-07-21 drh: if( i>1 ){ dbda8d6ce9 2007-07-21 drh: /* Parameters of the form #NNN (where NNN is a number) are used dbda8d6ce9 2007-07-21 drh: ** internally by sqlite3NestedParse. */ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_REGISTER; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Fall through into the next case if the '#' is not followed by dbda8d6ce9 2007-07-21 drh: ** a digit. Try to match #AAAA where AAAA is a parameter name. */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TCL_VARIABLE dbda8d6ce9 2007-07-21 drh: case '$': dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: case '@': /* For compatibility with MS SQL Server */ dbda8d6ce9 2007-07-21 drh: case ':': { dbda8d6ce9 2007-07-21 drh: int n = 0; dbda8d6ce9 2007-07-21 drh: *tokenType = TK_VARIABLE; dbda8d6ce9 2007-07-21 drh: for(i=1; (c=z[i])!=0; i++){ dbda8d6ce9 2007-07-21 drh: if( IdChar(c) ){ dbda8d6ce9 2007-07-21 drh: n++; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TCL_VARIABLE dbda8d6ce9 2007-07-21 drh: }else if( c=='(' && n>0 ){ dbda8d6ce9 2007-07-21 drh: do{ dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: }while( (c=z[i])!=0 && !isspace(c) && c!=')' ); dbda8d6ce9 2007-07-21 drh: if( c==')' ){ dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_ILLEGAL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: }else if( c==':' && z[i+1]==':' ){ dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( n==0 ) *tokenType = TK_ILLEGAL; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_BLOB_LITERAL dbda8d6ce9 2007-07-21 drh: case 'x': case 'X': { dbda8d6ce9 2007-07-21 drh: if( (c=z[1])=='\'' || c=='"' ){ dbda8d6ce9 2007-07-21 drh: int delim = c; dbda8d6ce9 2007-07-21 drh: *tokenType = TK_BLOB; dbda8d6ce9 2007-07-21 drh: for(i=2; (c=z[i])!=0; i++){ dbda8d6ce9 2007-07-21 drh: if( c==delim ){ dbda8d6ce9 2007-07-21 drh: if( i%2 ) *tokenType = TK_ILLEGAL; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !isxdigit(c) ){ dbda8d6ce9 2007-07-21 drh: *tokenType = TK_ILLEGAL; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( c ) i++; dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* Otherwise fall through to the next case */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: if( !IdChar(*z) ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: for(i=1; IdChar(z[i]); i++){} dbda8d6ce9 2007-07-21 drh: *tokenType = keywordCode((char*)z, i); dbda8d6ce9 2007-07-21 drh: return i; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *tokenType = TK_ILLEGAL; dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ dbda8d6ce9 2007-07-21 drh: return getToken(z, tokenType); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Run the parser on the given SQL string. The parser structure is dbda8d6ce9 2007-07-21 drh: ** passed in. An SQLITE_ status code is returned. If an error occurs dbda8d6ce9 2007-07-21 drh: ** and pzErrMsg!=NULL then an error message might be written into c287665ba8 2007-09-14 drh: ** memory obtained from sqlite3_malloc() and *pzErrMsg made to point to that dbda8d6ce9 2007-07-21 drh: ** error message. Or maybe not. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ dbda8d6ce9 2007-07-21 drh: int nErr = 0; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: void *pEngine; dbda8d6ce9 2007-07-21 drh: int tokenType; dbda8d6ce9 2007-07-21 drh: int lastTokenParsed = -1; dbda8d6ce9 2007-07-21 drh: sqlite3 *db = pParse->db; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( db->activeVdbeCnt==0 ){ dbda8d6ce9 2007-07-21 drh: db->u1.isInterrupted = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: i = 0; c287665ba8 2007-09-14 drh: pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3_malloc); dbda8d6ce9 2007-07-21 drh: if( pEngine==0 ){ c287665ba8 2007-09-14 drh: db->mallocFailed = 1; dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pParse->sLastToken.dyn==0 ); dbda8d6ce9 2007-07-21 drh: assert( pParse->pNewTable==0 ); dbda8d6ce9 2007-07-21 drh: assert( pParse->pNewTrigger==0 ); dbda8d6ce9 2007-07-21 drh: assert( pParse->nVar==0 ); dbda8d6ce9 2007-07-21 drh: assert( pParse->nVarExpr==0 ); dbda8d6ce9 2007-07-21 drh: assert( pParse->nVarExprAlloc==0 ); dbda8d6ce9 2007-07-21 drh: assert( pParse->apVarExpr==0 ); dbda8d6ce9 2007-07-21 drh: pParse->zTail = pParse->zSql = zSql; c287665ba8 2007-09-14 drh: while( !db->mallocFailed && zSql[i]!=0 ){ dbda8d6ce9 2007-07-21 drh: assert( i>=0 ); dbda8d6ce9 2007-07-21 drh: pParse->sLastToken.z = (u8*)&zSql[i]; dbda8d6ce9 2007-07-21 drh: assert( pParse->sLastToken.dyn==0 ); dbda8d6ce9 2007-07-21 drh: pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType); dbda8d6ce9 2007-07-21 drh: i += pParse->sLastToken.n; dbda8d6ce9 2007-07-21 drh: if( i>SQLITE_MAX_SQL_LENGTH ){ dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_TOOBIG; dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: switch( tokenType ){ dbda8d6ce9 2007-07-21 drh: case TK_SPACE: dbda8d6ce9 2007-07-21 drh: case TK_COMMENT: { dbda8d6ce9 2007-07-21 drh: if( db->u1.isInterrupted ){ dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_INTERRUPT; dbda8d6ce9 2007-07-21 drh: sqlite3SetString(pzErrMsg, "interrupt", (char*)0); dbda8d6ce9 2007-07-21 drh: goto abort_parse; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_ILLEGAL: { dbda8d6ce9 2007-07-21 drh: if( pzErrMsg ){ c287665ba8 2007-09-14 drh: sqlite3_free(*pzErrMsg); c287665ba8 2007-09-14 drh: *pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"", dbda8d6ce9 2007-07-21 drh: &pParse->sLastToken); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: nErr++; dbda8d6ce9 2007-07-21 drh: goto abort_parse; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: case TK_SEMI: { dbda8d6ce9 2007-07-21 drh: pParse->zTail = &zSql[i]; dbda8d6ce9 2007-07-21 drh: /* Fall thru into the default case */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: default: { dbda8d6ce9 2007-07-21 drh: sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse); dbda8d6ce9 2007-07-21 drh: lastTokenParsed = tokenType; dbda8d6ce9 2007-07-21 drh: if( pParse->rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto abort_parse; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: abort_parse: dbda8d6ce9 2007-07-21 drh: if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: if( lastTokenParsed!=TK_SEMI ){ dbda8d6ce9 2007-07-21 drh: sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse); dbda8d6ce9 2007-07-21 drh: pParse->zTail = &zSql[i]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3ParserFree(pEngine, sqlite3_free); c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc), (char*)0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pParse->zErrMsg ){ dbda8d6ce9 2007-07-21 drh: if( pzErrMsg && *pzErrMsg==0 ){ dbda8d6ce9 2007-07-21 drh: *pzErrMsg = pParse->zErrMsg; dbda8d6ce9 2007-07-21 drh: }else{ c287665ba8 2007-09-14 drh: sqlite3_free(pParse->zErrMsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: pParse->zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: if( !nErr ) nErr++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3VdbeDelete(pParse->pVdbe); dbda8d6ce9 2007-07-21 drh: pParse->pVdbe = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_SHARED_CACHE dbda8d6ce9 2007-07-21 drh: if( pParse->nested==0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(pParse->aTableLock); dbda8d6ce9 2007-07-21 drh: pParse->aTableLock = 0; dbda8d6ce9 2007-07-21 drh: pParse->nTableLock = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !IN_DECLARE_VTAB ){ dbda8d6ce9 2007-07-21 drh: /* If the pParse->declareVtab flag is set, do not delete any table dbda8d6ce9 2007-07-21 drh: ** structure built up in pParse->pNewTable. The calling code (see vtab.c) dbda8d6ce9 2007-07-21 drh: ** will take responsibility for freeing the Table structure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTable(pParse->pNewTable); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3DeleteTrigger(pParse->pNewTrigger); c287665ba8 2007-09-14 drh: sqlite3_free(pParse->apVarExpr); dbda8d6ce9 2007-07-21 drh: if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){ dbda8d6ce9 2007-07-21 drh: pParse->rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return nErr; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of tokenize.c ********************************************/ c287665ba8 2007-09-14 drh: /************** Begin file complete.c ****************************************/ c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** 2001 September 15 c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** The author disclaims copyright to this source code. In place of c287665ba8 2007-09-14 drh: ** a legal notice, here is a blessing: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** May you do good and not evil. c287665ba8 2007-09-14 drh: ** May you find forgiveness for yourself and forgive others. c287665ba8 2007-09-14 drh: ** May you share freely, never taking more than you give. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ************************************************************************* c287665ba8 2007-09-14 drh: ** An tokenizer for SQL c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This file contains C code that implements the sqlite3_complete() API. c287665ba8 2007-09-14 drh: ** This code used to be part of the tokenizer.c source file. But by c287665ba8 2007-09-14 drh: ** separating it out, the code will be automatically omitted from c287665ba8 2007-09-14 drh: ** static links that do not use it. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** $Id: complete.c,v 1.6 2007/08/27 23:26:59 drh Exp $ c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_COMPLETE c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This is defined in tokenize.c. We just have to import the definition. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #ifndef SQLITE_AMALGAMATION c287665ba8 2007-09-14 drh: #ifdef SQLITE_ASCII c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char sqlite3IsAsciiIdChar[]; c287665ba8 2007-09-14 drh: #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20])) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: #ifdef SQLITE_EBCDIC c287665ba8 2007-09-14 drh: SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; c287665ba8 2007-09-14 drh: #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: #endif /* SQLITE_AMALGAMATION */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Token types used by the sqlite3_complete() routine. See the header c287665ba8 2007-09-14 drh: ** comments on that procedure for additional information. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: #define tkSEMI 0 c287665ba8 2007-09-14 drh: #define tkWS 1 c287665ba8 2007-09-14 drh: #define tkOTHER 2 c287665ba8 2007-09-14 drh: #define tkEXPLAIN 3 c287665ba8 2007-09-14 drh: #define tkCREATE 4 c287665ba8 2007-09-14 drh: #define tkTEMP 5 c287665ba8 2007-09-14 drh: #define tkTRIGGER 6 c287665ba8 2007-09-14 drh: #define tkEND 7 c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Return TRUE if the given SQL string ends in a semicolon. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Special handling is require for CREATE TRIGGER statements. c287665ba8 2007-09-14 drh: ** Whenever the CREATE TRIGGER keywords are seen, the statement c287665ba8 2007-09-14 drh: ** must end with ";END;". c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** This implementation uses a state machine with 7 states: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (0) START At the beginning or end of an SQL statement. This routine c287665ba8 2007-09-14 drh: ** returns 1 if it ends in the START state and 0 if it ends c287665ba8 2007-09-14 drh: ** in any other state. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (1) NORMAL We are in the middle of statement which ends with a single c287665ba8 2007-09-14 drh: ** semicolon. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (2) EXPLAIN The keyword EXPLAIN has been seen at the beginning of c287665ba8 2007-09-14 drh: ** a statement. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (3) CREATE The keyword CREATE has been seen at the beginning of a c287665ba8 2007-09-14 drh: ** statement, possibly preceeded by EXPLAIN and/or followed by c287665ba8 2007-09-14 drh: ** TEMP or TEMPORARY c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (4) TRIGGER We are in the middle of a trigger definition that must be c287665ba8 2007-09-14 drh: ** ended by a semicolon, the keyword END, and another semicolon. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at c287665ba8 2007-09-14 drh: ** the end of a trigger definition. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (6) END We've seen the ";END" of the ";END;" that occurs at the end c287665ba8 2007-09-14 drh: ** of a trigger difinition. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Transitions between states above are determined by tokens extracted c287665ba8 2007-09-14 drh: ** from the input. The following tokens are significant: c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** (0) tkSEMI A semicolon. c287665ba8 2007-09-14 drh: ** (1) tkWS Whitespace c287665ba8 2007-09-14 drh: ** (2) tkOTHER Any other SQL token. c287665ba8 2007-09-14 drh: ** (3) tkEXPLAIN The "explain" keyword. c287665ba8 2007-09-14 drh: ** (4) tkCREATE The "create" keyword. c287665ba8 2007-09-14 drh: ** (5) tkTEMP The "temp" or "temporary" keyword. c287665ba8 2007-09-14 drh: ** (6) tkTRIGGER The "trigger" keyword. c287665ba8 2007-09-14 drh: ** (7) tkEND The "end" keyword. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** Whitespace never causes a state transition and is always ignored. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed c287665ba8 2007-09-14 drh: ** to recognize the end of a trigger can be omitted. All we have to do c287665ba8 2007-09-14 drh: ** is look for a semicolon that is not part of an string or comment. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_complete(const char *zSql){ c287665ba8 2007-09-14 drh: u8 state = 0; /* Current state, using numbers defined in header comment */ c287665ba8 2007-09-14 drh: u8 token; /* Value of the next token */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_TRIGGER c287665ba8 2007-09-14 drh: /* A complex statement machine used to detect the end of a CREATE TRIGGER c287665ba8 2007-09-14 drh: ** statement. This is the normal case. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static const u8 trans[7][8] = { c287665ba8 2007-09-14 drh: /* Token: */ c287665ba8 2007-09-14 drh: /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ c287665ba8 2007-09-14 drh: /* 0 START: */ { 0, 0, 1, 2, 3, 1, 1, 1, }, c287665ba8 2007-09-14 drh: /* 1 NORMAL: */ { 0, 1, 1, 1, 1, 1, 1, 1, }, c287665ba8 2007-09-14 drh: /* 2 EXPLAIN: */ { 0, 2, 1, 1, 3, 1, 1, 1, }, c287665ba8 2007-09-14 drh: /* 3 CREATE: */ { 0, 3, 1, 1, 1, 3, 4, 1, }, c287665ba8 2007-09-14 drh: /* 4 TRIGGER: */ { 5, 4, 4, 4, 4, 4, 4, 4, }, c287665ba8 2007-09-14 drh: /* 5 SEMI: */ { 5, 5, 4, 4, 4, 4, 4, 6, }, c287665ba8 2007-09-14 drh: /* 6 END: */ { 0, 6, 4, 4, 4, 4, 4, 4, }, c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: /* If triggers are not suppored by this compile then the statement machine c287665ba8 2007-09-14 drh: ** used to detect the end of a statement is much simplier c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: static const u8 trans[2][3] = { c287665ba8 2007-09-14 drh: /* Token: */ c287665ba8 2007-09-14 drh: /* State: ** SEMI WS OTHER */ c287665ba8 2007-09-14 drh: /* 0 START: */ { 0, 0, 1, }, c287665ba8 2007-09-14 drh: /* 1 NORMAL: */ { 0, 1, 1, }, c287665ba8 2007-09-14 drh: }; c287665ba8 2007-09-14 drh: #endif /* SQLITE_OMIT_TRIGGER */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: while( *zSql ){ c287665ba8 2007-09-14 drh: switch( *zSql ){ c287665ba8 2007-09-14 drh: case ';': { /* A semicolon */ c287665ba8 2007-09-14 drh: token = tkSEMI; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: case ' ': c287665ba8 2007-09-14 drh: case '\r': c287665ba8 2007-09-14 drh: case '\t': c287665ba8 2007-09-14 drh: case '\n': c287665ba8 2007-09-14 drh: case '\f': { /* White space is ignored */ c287665ba8 2007-09-14 drh: token = tkWS; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: case '/': { /* C-style comments */ c287665ba8 2007-09-14 drh: if( zSql[1]!='*' ){ c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: zSql += 2; c287665ba8 2007-09-14 drh: while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } c287665ba8 2007-09-14 drh: if( zSql[0]==0 ) return 0; c287665ba8 2007-09-14 drh: zSql++; c287665ba8 2007-09-14 drh: token = tkWS; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: case '-': { /* SQL-style comments from "--" to end of line */ c287665ba8 2007-09-14 drh: if( zSql[1]!='-' ){ c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: while( *zSql && *zSql!='\n' ){ zSql++; } c287665ba8 2007-09-14 drh: if( *zSql==0 ) return state==0; c287665ba8 2007-09-14 drh: token = tkWS; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: case '[': { /* Microsoft-style identifiers in [...] */ c287665ba8 2007-09-14 drh: zSql++; c287665ba8 2007-09-14 drh: while( *zSql && *zSql!=']' ){ zSql++; } c287665ba8 2007-09-14 drh: if( *zSql==0 ) return 0; c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: case '`': /* Grave-accent quoted symbols used by MySQL */ c287665ba8 2007-09-14 drh: case '"': /* single- and double-quoted strings */ c287665ba8 2007-09-14 drh: case '\'': { c287665ba8 2007-09-14 drh: int c = *zSql; c287665ba8 2007-09-14 drh: zSql++; c287665ba8 2007-09-14 drh: while( *zSql && *zSql!=c ){ zSql++; } c287665ba8 2007-09-14 drh: if( *zSql==0 ) return 0; c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: default: { c287665ba8 2007-09-14 drh: int c; c287665ba8 2007-09-14 drh: if( IdChar((u8)*zSql) ){ c287665ba8 2007-09-14 drh: /* Keywords and unquoted identifiers */ c287665ba8 2007-09-14 drh: int nId; c287665ba8 2007-09-14 drh: for(nId=1; IdChar(zSql[nId]); nId++){} c287665ba8 2007-09-14 drh: #ifdef SQLITE_OMIT_TRIGGER c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: #else c287665ba8 2007-09-14 drh: switch( *zSql ){ c287665ba8 2007-09-14 drh: case 'c': case 'C': { c287665ba8 2007-09-14 drh: if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){ c287665ba8 2007-09-14 drh: token = tkCREATE; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: case 't': case 'T': { c287665ba8 2007-09-14 drh: if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){ c287665ba8 2007-09-14 drh: token = tkTRIGGER; c287665ba8 2007-09-14 drh: }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){ c287665ba8 2007-09-14 drh: token = tkTEMP; c287665ba8 2007-09-14 drh: }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){ c287665ba8 2007-09-14 drh: token = tkTEMP; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: case 'e': case 'E': { c287665ba8 2007-09-14 drh: if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){ c287665ba8 2007-09-14 drh: token = tkEND; c287665ba8 2007-09-14 drh: }else c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_EXPLAIN c287665ba8 2007-09-14 drh: if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){ c287665ba8 2007-09-14 drh: token = tkEXPLAIN; c287665ba8 2007-09-14 drh: }else c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: { c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: default: { c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif /* SQLITE_OMIT_TRIGGER */ c287665ba8 2007-09-14 drh: zSql += nId-1; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: /* Operators and special symbols */ c287665ba8 2007-09-14 drh: token = tkOTHER; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: state = trans[state][token]; c287665ba8 2007-09-14 drh: zSql++; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: return state==0; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** This routine is the same as the sqlite3_complete() routine described c287665ba8 2007-09-14 drh: ** above, except that the parameter is required to be UTF-16 encoded, not c287665ba8 2007-09-14 drh: ** UTF-8. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_complete16(const void *zSql){ c287665ba8 2007-09-14 drh: sqlite3_value *pVal; c287665ba8 2007-09-14 drh: char const *zSql8; c287665ba8 2007-09-14 drh: int rc = SQLITE_NOMEM; c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: pVal = sqlite3ValueNew(0); c287665ba8 2007-09-14 drh: sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); c287665ba8 2007-09-14 drh: zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); c287665ba8 2007-09-14 drh: if( zSql8 ){ c287665ba8 2007-09-14 drh: rc = sqlite3_complete(zSql8); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3ValueFree(pVal); c287665ba8 2007-09-14 drh: return sqlite3ApiExit(0, rc); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif /* SQLITE_OMIT_UTF16 */ c287665ba8 2007-09-14 drh: #endif /* SQLITE_OMIT_COMPLETE */ c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /************** End of complete.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /************** Begin file main.c ********************************************/ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** 2001 September 15 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The author disclaims copyright to this source code. In place of dbda8d6ce9 2007-07-21 drh: ** a legal notice, here is a blessing: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** May you do good and not evil. dbda8d6ce9 2007-07-21 drh: ** May you find forgiveness for yourself and forgive others. dbda8d6ce9 2007-07-21 drh: ** May you share freely, never taking more than you give. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ************************************************************************* dbda8d6ce9 2007-07-21 drh: ** Main file for the SQLite library. The routines in this file dbda8d6ce9 2007-07-21 drh: ** implement the programmer interface to the library. Routines in dbda8d6ce9 2007-07-21 drh: ** other files are for internal use by SQLite and should not be dbda8d6ce9 2007-07-21 drh: ** accessed by users of the library. dbda8d6ce9 2007-07-21 drh: ** c287665ba8 2007-09-14 drh: ** $Id: main.c,v 1.404 2007/09/03 15:19:35 drh Exp $ dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The version of the library dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; dbda8d6ce9 2007-07-21 drh: SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the following function pointer is not NULL and if dbda8d6ce9 2007-07-21 drh: ** SQLITE_ENABLE_IOTRACE is enabled, then messages describing dbda8d6ce9 2007-07-21 drh: ** I/O active are written using this function. These messages dbda8d6ce9 2007-07-21 drh: ** are intended for debugging activity only. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void (*sqlite3_io_trace)(const char*, ...) = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** If the following global variable points to a string which is the dbda8d6ce9 2007-07-21 drh: ** name of a directory, then that directory will be used to store dbda8d6ce9 2007-07-21 drh: ** temporary files. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** See also the "PRAGMA temp_store_directory" SQL command. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API char *sqlite3_temp_directory = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is the default collating function named "BINARY" which is always dbda8d6ce9 2007-07-21 drh: ** available. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int binCollFunc( dbda8d6ce9 2007-07-21 drh: void *NotUsed, dbda8d6ce9 2007-07-21 drh: int nKey1, const void *pKey1, dbda8d6ce9 2007-07-21 drh: int nKey2, const void *pKey2 dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc, n; dbda8d6ce9 2007-07-21 drh: n = nKey1<nKey2 ? nKey1 : nKey2; dbda8d6ce9 2007-07-21 drh: rc = memcmp(pKey1, pKey2, n); dbda8d6ce9 2007-07-21 drh: if( rc==0 ){ dbda8d6ce9 2007-07-21 drh: rc = nKey1 - nKey2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Another built-in collating sequence: NOCASE. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This collating sequence is intended to be used for "case independant dbda8d6ce9 2007-07-21 drh: ** comparison". SQLite's knowledge of upper and lower case equivalents dbda8d6ce9 2007-07-21 drh: ** extends only to the 26 characters used in the English language. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** At the moment there is only a UTF-8 implementation. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int nocaseCollatingFunc( dbda8d6ce9 2007-07-21 drh: void *NotUsed, dbda8d6ce9 2007-07-21 drh: int nKey1, const void *pKey1, dbda8d6ce9 2007-07-21 drh: int nKey2, const void *pKey2 dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int r = sqlite3StrNICmp( dbda8d6ce9 2007-07-21 drh: (const char *)pKey1, (const char *)pKey2, (nKey1<nKey2)?nKey1:nKey2); dbda8d6ce9 2007-07-21 drh: if( 0==r ){ dbda8d6ce9 2007-07-21 drh: r = nKey1-nKey2; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return r; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the ROWID of the most recent insert dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: return db->lastRowid; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of changes in the most recent call to sqlite3_exec(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_changes(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: return db->nChange; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the number of changes since the database handle was opened. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_total_changes(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: return db->nTotalChange; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Close an existing SQLite database dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_close(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: HashElem *i; dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( !db ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_SSE dbda8d6ce9 2007-07-21 drh: { dbda8d6ce9 2007-07-21 drh: extern void sqlite3SseCleanup(sqlite3*); dbda8d6ce9 2007-07-21 drh: sqlite3SseCleanup(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If a transaction is open, the ResetInternalSchema() call above dbda8d6ce9 2007-07-21 drh: ** will not have called the xDisconnect() method on any virtual dbda8d6ce9 2007-07-21 drh: ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback() dbda8d6ce9 2007-07-21 drh: ** call will do so. We need to do this before the check for active dbda8d6ce9 2007-07-21 drh: ** SQL statements below, as the v-table implementation may be storing dbda8d6ce9 2007-07-21 drh: ** some prepared statements internally. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3VtabRollback(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If there are any outstanding VMs, return SQLITE_BUSY. */ dbda8d6ce9 2007-07-21 drh: if( db->pVdbe ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_BUSY, dbda8d6ce9 2007-07-21 drh: "Unable to close due to unfinalised statements"); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( !sqlite3SafetyCheck(db) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* FIX ME: db->magic may be set to SQLITE_MAGIC_CLOSED if the database dbda8d6ce9 2007-07-21 drh: ** cannot be opened for some reason. So this routine needs to run in dbda8d6ce9 2007-07-21 drh: ** that case. But maybe there should be an extra magic value for the dbda8d6ce9 2007-07-21 drh: ** "failed to open" state. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** TODO: Coverage tests do not test the case where this condition is dbda8d6ce9 2007-07-21 drh: ** true. It's hard to see how to cause it without messing with threads. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){ dbda8d6ce9 2007-07-21 drh: /* printf("DID NOT CLOSE\n"); fflush(stdout); */ c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(j=0; j<db->nDb; j++){ dbda8d6ce9 2007-07-21 drh: struct Db *pDb = &db->aDb[j]; dbda8d6ce9 2007-07-21 drh: if( pDb->pBt ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeClose(pDb->pBt); dbda8d6ce9 2007-07-21 drh: pDb->pBt = 0; dbda8d6ce9 2007-07-21 drh: if( j!=1 ){ dbda8d6ce9 2007-07-21 drh: pDb->pSchema = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: assert( db->nDb<=2 ); dbda8d6ce9 2007-07-21 drh: assert( db->aDb==db->aDbStatic ); dbda8d6ce9 2007-07-21 drh: for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ dbda8d6ce9 2007-07-21 drh: FuncDef *pFunc, *pNext; dbda8d6ce9 2007-07-21 drh: for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){ dbda8d6ce9 2007-07-21 drh: pNext = pFunc->pNext; c287665ba8 2007-09-14 drh: sqlite3_free(pFunc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl = (CollSeq *)sqliteHashData(i); dbda8d6ce9 2007-07-21 drh: /* Invoke any destructors registered for collation sequence user data. */ dbda8d6ce9 2007-07-21 drh: for(j=0; j<3; j++){ dbda8d6ce9 2007-07-21 drh: if( pColl[j].xDel ){ dbda8d6ce9 2007-07-21 drh: pColl[j].xDel(pColl[j].pUser); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pColl); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3HashClear(&db->aCollSeq); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ dbda8d6ce9 2007-07-21 drh: Module *pMod = (Module *)sqliteHashData(i); dbda8d6ce9 2007-07-21 drh: if( pMod->xDestroy ){ dbda8d6ce9 2007-07-21 drh: pMod->xDestroy(pMod->pAux); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_free(pMod); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3HashClear(&db->aModule); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: sqlite3HashClear(&db->aFunc); dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ dbda8d6ce9 2007-07-21 drh: if( db->pErr ){ dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree(db->pErr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3CloseExtensions(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: db->magic = SQLITE_MAGIC_ERROR; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The temp-database schema is allocated differently from the other schema dbda8d6ce9 2007-07-21 drh: ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). dbda8d6ce9 2007-07-21 drh: ** So it needs to be freed here. Todo: Why not roll the temp schema into dbda8d6ce9 2007-07-21 drh: ** the same sqliteMalloc() as the one that allocates the database dbda8d6ce9 2007-07-21 drh: ** structure? dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: sqlite3_free(db->aDb[1].pSchema); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: sqlite3_mutex_free(db->mutex); c287665ba8 2007-09-14 drh: sqlite3_free(db); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Rollback all database files. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: int inTrans = 0; c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: for(i=0; i<db->nDb; i++){ dbda8d6ce9 2007-07-21 drh: if( db->aDb[i].pBt ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){ dbda8d6ce9 2007-07-21 drh: inTrans = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3BtreeRollback(db->aDb[i].pBt); dbda8d6ce9 2007-07-21 drh: db->aDb[i].inTrans = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3VtabRollback(db); dbda8d6ce9 2007-07-21 drh: if( db->flags&SQLITE_InternChanges ){ c287665ba8 2007-09-14 drh: sqlite3ExpirePreparedStatements(db); dbda8d6ce9 2007-07-21 drh: sqlite3ResetInternalSchema(db, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If one has been configured, invoke the rollback-hook callback */ dbda8d6ce9 2007-07-21 drh: if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ dbda8d6ce9 2007-07-21 drh: db->xRollbackCallback(db->pRollbackArg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return a static string that describes the kind of error specified in the dbda8d6ce9 2007-07-21 drh: ** argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ dbda8d6ce9 2007-07-21 drh: const char *z; dbda8d6ce9 2007-07-21 drh: switch( rc & 0xff ){ dbda8d6ce9 2007-07-21 drh: case SQLITE_ROW: dbda8d6ce9 2007-07-21 drh: case SQLITE_DONE: dbda8d6ce9 2007-07-21 drh: case SQLITE_OK: z = "not an error"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_ERROR: z = "SQL logic error or missing database"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_PERM: z = "access permission denied"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_ABORT: z = "callback requested query abort"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_BUSY: z = "database is locked"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_LOCKED: z = "database table is locked"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_NOMEM: z = "out of memory"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_READONLY: z = "attempt to write a readonly database"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_INTERRUPT: z = "interrupted"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_IOERR: z = "disk I/O error"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_CORRUPT: z = "database disk image is malformed"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_FULL: z = "database or disk is full"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_CANTOPEN: z = "unable to open database file"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_EMPTY: z = "table contains no data"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_SCHEMA: z = "database schema has changed"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_TOOBIG: z = "String or BLOB exceeded size limit"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_CONSTRAINT: z = "constraint failed"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_MISMATCH: z = "datatype mismatch"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_MISUSE: z = "library routine called out of sequence";break; dbda8d6ce9 2007-07-21 drh: case SQLITE_NOLFS: z = "kernel lacks large file support"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_AUTH: z = "authorization denied"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_FORMAT: z = "auxiliary database format error"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_RANGE: z = "bind or column index out of range"; break; dbda8d6ce9 2007-07-21 drh: case SQLITE_NOTADB: z = "file is encrypted or is not a database";break; dbda8d6ce9 2007-07-21 drh: default: z = "unknown error"; break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine implements a busy callback that sleeps and tries dbda8d6ce9 2007-07-21 drh: ** again until a timeout value is reached. The timeout value is dbda8d6ce9 2007-07-21 drh: ** an integer number of milliseconds passed in as the first dbda8d6ce9 2007-07-21 drh: ** argument. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int sqliteDefaultBusyCallback( dbda8d6ce9 2007-07-21 drh: void *ptr, /* Database connection */ dbda8d6ce9 2007-07-21 drh: int count /* Number of times table has been busy */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: #if OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP) dbda8d6ce9 2007-07-21 drh: static const u8 delays[] = dbda8d6ce9 2007-07-21 drh: { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 }; dbda8d6ce9 2007-07-21 drh: static const u8 totals[] = dbda8d6ce9 2007-07-21 drh: { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 }; dbda8d6ce9 2007-07-21 drh: # define NDELAY (sizeof(delays)/sizeof(delays[0])) c287665ba8 2007-09-14 drh: sqlite3 *db = (sqlite3 *)ptr; c287665ba8 2007-09-14 drh: int timeout = db->busyTimeout; dbda8d6ce9 2007-07-21 drh: int delay, prior; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( count>=0 ); dbda8d6ce9 2007-07-21 drh: if( count < NDELAY ){ dbda8d6ce9 2007-07-21 drh: delay = delays[count]; dbda8d6ce9 2007-07-21 drh: prior = totals[count]; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: delay = delays[NDELAY-1]; dbda8d6ce9 2007-07-21 drh: prior = totals[NDELAY-1] + delay*(count-(NDELAY-1)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( prior + delay > timeout ){ dbda8d6ce9 2007-07-21 drh: delay = timeout - prior; dbda8d6ce9 2007-07-21 drh: if( delay<=0 ) return 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3OsSleep(db->pVfs, delay*1000); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: #else c287665ba8 2007-09-14 drh: sqlite3 *db = (sqlite3 *)ptr; dbda8d6ce9 2007-07-21 drh: int timeout = ((sqlite3 *)ptr)->busyTimeout; dbda8d6ce9 2007-07-21 drh: if( (count+1)*1000 > timeout ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3OsSleep(db->pVfs, 1000000); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Invoke the given busy handler. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This routine is called when an operation failed with a lock. dbda8d6ce9 2007-07-21 drh: ** If this routine returns non-zero, the lock is retried. If it dbda8d6ce9 2007-07-21 drh: ** returns 0, the operation aborts with an SQLITE_BUSY error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: if( p==0 || p->xFunc==0 || p->nBusy<0 ) return 0; dbda8d6ce9 2007-07-21 drh: rc = p->xFunc(p->pArg, p->nBusy); dbda8d6ce9 2007-07-21 drh: if( rc==0 ){ dbda8d6ce9 2007-07-21 drh: p->nBusy = -1; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: p->nBusy++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine sets the busy callback for an Sqlite database to the dbda8d6ce9 2007-07-21 drh: ** given callback function with the given argument. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_busy_handler( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: int (*xBusy)(void*,int), dbda8d6ce9 2007-07-21 drh: void *pArg dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: db->busyHandler.xFunc = xBusy; dbda8d6ce9 2007-07-21 drh: db->busyHandler.pArg = pArg; dbda8d6ce9 2007-07-21 drh: db->busyHandler.nBusy = 0; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_PROGRESS_CALLBACK dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine sets the progress callback for an Sqlite database to the dbda8d6ce9 2007-07-21 drh: ** given callback function with the given argument. The progress callback will dbda8d6ce9 2007-07-21 drh: ** be invoked every nOps opcodes. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_progress_handler( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: int nOps, dbda8d6ce9 2007-07-21 drh: int (*xProgress)(void*), dbda8d6ce9 2007-07-21 drh: void *pArg dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( !sqlite3SafetyCheck(db) ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: if( nOps>0 ){ dbda8d6ce9 2007-07-21 drh: db->xProgress = xProgress; dbda8d6ce9 2007-07-21 drh: db->nProgressOps = nOps; dbda8d6ce9 2007-07-21 drh: db->pProgressArg = pArg; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: db->xProgress = 0; dbda8d6ce9 2007-07-21 drh: db->nProgressOps = 0; dbda8d6ce9 2007-07-21 drh: db->pProgressArg = 0; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine installs a default busy handler that waits for the dbda8d6ce9 2007-07-21 drh: ** specified number of milliseconds before returning 0. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( ms>0 ){ dbda8d6ce9 2007-07-21 drh: db->busyTimeout = ms; dbda8d6ce9 2007-07-21 drh: sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3_busy_handler(db, 0, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Cause any pending operation to stop at its earliest opportunity. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API void sqlite3_interrupt(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: if( db && (db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_BUSY) ){ dbda8d6ce9 2007-07-21 drh: db->u1.isInterrupted = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is exactly the same as sqlite3_create_function(), except dbda8d6ce9 2007-07-21 drh: ** that it is designed to be called by internal code. The difference is dbda8d6ce9 2007-07-21 drh: ** that if a malloc() fails in sqlite3_create_function(), an error code dbda8d6ce9 2007-07-21 drh: ** is returned and the mallocFailed flag cleared. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3CreateFunc( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: const char *zFunctionName, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: int enc, dbda8d6ce9 2007-07-21 drh: void *pUserData, dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value **), dbda8d6ce9 2007-07-21 drh: void (*xStep)(sqlite3_context*,int,sqlite3_value **), dbda8d6ce9 2007-07-21 drh: void (*xFinal)(sqlite3_context*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: FuncDef *p; dbda8d6ce9 2007-07-21 drh: int nName; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zFunctionName==0 || dbda8d6ce9 2007-07-21 drh: (xFunc && (xFinal || xStep)) || dbda8d6ce9 2007-07-21 drh: (!xFunc && (xFinal && !xStep)) || dbda8d6ce9 2007-07-21 drh: (!xFunc && (!xFinal && xStep)) || dbda8d6ce9 2007-07-21 drh: (nArg<-1 || nArg>127) || dbda8d6ce9 2007-07-21 drh: (255<(nName = strlen(zFunctionName))) ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_ERROR, "bad parameters"); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* If SQLITE_UTF16 is specified as the encoding type, transform this dbda8d6ce9 2007-07-21 drh: ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the dbda8d6ce9 2007-07-21 drh: ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If SQLITE_ANY is specified, add three versions of the function dbda8d6ce9 2007-07-21 drh: ** to the hash table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( enc==SQLITE_UTF16 ){ dbda8d6ce9 2007-07-21 drh: enc = SQLITE_UTF16NATIVE; dbda8d6ce9 2007-07-21 drh: }else if( enc==SQLITE_ANY ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8, dbda8d6ce9 2007-07-21 drh: pUserData, xFunc, xStep, xFinal); c287665ba8 2007-09-14 drh: if( rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE, c287665ba8 2007-09-14 drh: pUserData, xFunc, xStep, xFinal); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( rc!=SQLITE_OK ){ c287665ba8 2007-09-14 drh: return rc; c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: enc = SQLITE_UTF16BE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #else dbda8d6ce9 2007-07-21 drh: enc = SQLITE_UTF8; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check if an existing function is being overridden or deleted. If so, dbda8d6ce9 2007-07-21 drh: ** and there are active VMs, then return SQLITE_BUSY. If a function dbda8d6ce9 2007-07-21 drh: ** is being overridden/deleted but there are no active VMs, allow the dbda8d6ce9 2007-07-21 drh: ** operation to continue but invalidate all precompiled statements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 0); dbda8d6ce9 2007-07-21 drh: if( p && p->iPrefEnc==enc && p->nArg==nArg ){ dbda8d6ce9 2007-07-21 drh: if( db->activeVdbeCnt ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_BUSY, dbda8d6ce9 2007-07-21 drh: "Unable to delete/modify user-function due to active statements"); c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: return SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: sqlite3ExpirePreparedStatements(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1); c287665ba8 2007-09-14 drh: assert(p || db->mallocFailed); c287665ba8 2007-09-14 drh: if( !p ){ c287665ba8 2007-09-14 drh: return SQLITE_NOMEM; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: p->flags = 0; c287665ba8 2007-09-14 drh: p->xFunc = xFunc; c287665ba8 2007-09-14 drh: p->xStep = xStep; c287665ba8 2007-09-14 drh: p->xFinalize = xFinal; c287665ba8 2007-09-14 drh: p->pUserData = pUserData; c287665ba8 2007-09-14 drh: p->nArg = nArg; dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create new user functions. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_function( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: const char *zFunctionName, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: int enc, dbda8d6ce9 2007-07-21 drh: void *p, dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value **), dbda8d6ce9 2007-07-21 drh: void (*xStep)(sqlite3_context*,int,sqlite3_value **), dbda8d6ce9 2007-07-21 drh: void (*xFinal)(sqlite3_context*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_function16( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: const void *zFunctionName, dbda8d6ce9 2007-07-21 drh: int nArg, dbda8d6ce9 2007-07-21 drh: int eTextRep, dbda8d6ce9 2007-07-21 drh: void *p, dbda8d6ce9 2007-07-21 drh: void (*xFunc)(sqlite3_context*,int,sqlite3_value**), dbda8d6ce9 2007-07-21 drh: void (*xStep)(sqlite3_context*,int,sqlite3_value**), dbda8d6ce9 2007-07-21 drh: void (*xFinal)(sqlite3_context*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: char *zFunc8; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); c287665ba8 2007-09-14 drh: zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1); dbda8d6ce9 2007-07-21 drh: rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal); c287665ba8 2007-09-14 drh: sqlite3_free(zFunc8); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Declare that a function has been overloaded by a virtual table. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If the function already exists as a regular global function, then dbda8d6ce9 2007-07-21 drh: ** this routine is a no-op. If the function does not exist, then create dbda8d6ce9 2007-07-21 drh: ** a new one that always throws a run-time error. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** When virtual tables intend to provide an overloaded function, they dbda8d6ce9 2007-07-21 drh: ** should call this routine to make sure the global function exists. dbda8d6ce9 2007-07-21 drh: ** A global function must exist in order for name resolution to work dbda8d6ce9 2007-07-21 drh: ** properly. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_overload_function( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int nArg dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int nName = strlen(zName); c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, dbda8d6ce9 2007-07-21 drh: 0, sqlite3InvalidFunction, 0, 0); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, SQLITE_OK); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TRACE dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a trace function. The pArg from the previously registered trace dbda8d6ce9 2007-07-21 drh: ** is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A NULL trace function means that no tracing is executes. A non-NULL dbda8d6ce9 2007-07-21 drh: ** trace is a pointer to a function that is invoked at the start of each dbda8d6ce9 2007-07-21 drh: ** SQL statement. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ c287665ba8 2007-09-14 drh: void *pOld; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: pOld = db->pTraceArg; dbda8d6ce9 2007-07-21 drh: db->xTrace = xTrace; dbda8d6ce9 2007-07-21 drh: db->pTraceArg = pArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return pOld; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a profile function. The pArg from the previously registered dbda8d6ce9 2007-07-21 drh: ** profile function is returned. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A NULL profile function means that no profiling is executes. A non-NULL dbda8d6ce9 2007-07-21 drh: ** profile is a pointer to a function that is invoked at the conclusion of dbda8d6ce9 2007-07-21 drh: ** each SQL statement that is run. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API void *sqlite3_profile( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: void (*xProfile)(void*,const char*,sqlite_uint64), dbda8d6ce9 2007-07-21 drh: void *pArg dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: void *pOld; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: pOld = db->pProfileArg; dbda8d6ce9 2007-07-21 drh: db->xProfile = xProfile; dbda8d6ce9 2007-07-21 drh: db->pProfileArg = pArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return pOld; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_TRACE */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /*** EXPERIMENTAL *** dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Register a function to be invoked when a transaction comments. dbda8d6ce9 2007-07-21 drh: ** If the invoked function returns non-zero, then the commit becomes a dbda8d6ce9 2007-07-21 drh: ** rollback. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_commit_hook( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Attach the hook to this database */ dbda8d6ce9 2007-07-21 drh: int (*xCallback)(void*), /* Function to invoke on each commit */ dbda8d6ce9 2007-07-21 drh: void *pArg /* Argument to the function */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: void *pOld; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: pOld = db->pCommitArg; dbda8d6ce9 2007-07-21 drh: db->xCommitCallback = xCallback; dbda8d6ce9 2007-07-21 drh: db->pCommitArg = pArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return pOld; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a callback to be invoked each time a row is updated, dbda8d6ce9 2007-07-21 drh: ** inserted or deleted using this database connection. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_update_hook( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Attach the hook to this database */ dbda8d6ce9 2007-07-21 drh: void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), dbda8d6ce9 2007-07-21 drh: void *pArg /* Argument to the function */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: void *pRet; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: pRet = db->pUpdateArg; dbda8d6ce9 2007-07-21 drh: db->xUpdateCallback = xCallback; dbda8d6ce9 2007-07-21 drh: db->pUpdateArg = pArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return pRet; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a callback to be invoked each time a transaction is rolled dbda8d6ce9 2007-07-21 drh: ** back by this database connection. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void *sqlite3_rollback_hook( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Attach the hook to this database */ dbda8d6ce9 2007-07-21 drh: void (*xCallback)(void*), /* Callback function */ dbda8d6ce9 2007-07-21 drh: void *pArg /* Argument to the function */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: void *pRet; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: pRet = db->pRollbackArg; dbda8d6ce9 2007-07-21 drh: db->xRollbackCallback = xCallback; dbda8d6ce9 2007-07-21 drh: db->pRollbackArg = pArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return pRet; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine is called to create a connection to a database BTree dbda8d6ce9 2007-07-21 drh: ** driver. If zFilename is the name of a file, then that file is dbda8d6ce9 2007-07-21 drh: ** opened and used. If zFilename is the magic name ":memory:" then dbda8d6ce9 2007-07-21 drh: ** the database is stored in memory (and is thus forgotten as soon as dbda8d6ce9 2007-07-21 drh: ** the connection is closed.) If zFilename is NULL then the database dbda8d6ce9 2007-07-21 drh: ** is a "virtual" database for transient use only and is deleted as dbda8d6ce9 2007-07-21 drh: ** soon as the connection is closed. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** A virtual database can be either a disk file (that is automatically dbda8d6ce9 2007-07-21 drh: ** deleted when the file is closed) or it an be held entirely in memory, dbda8d6ce9 2007-07-21 drh: ** depending on the values of the TEMP_STORE compile-time macro and the dbda8d6ce9 2007-07-21 drh: ** db->temp_store variable, according to the following chart: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** TEMP_STORE db->temp_store Location of temporary database dbda8d6ce9 2007-07-21 drh: ** ---------- -------------- ------------------------------ dbda8d6ce9 2007-07-21 drh: ** 0 any file dbda8d6ce9 2007-07-21 drh: ** 1 1 file dbda8d6ce9 2007-07-21 drh: ** 1 2 memory dbda8d6ce9 2007-07-21 drh: ** 1 0 file dbda8d6ce9 2007-07-21 drh: ** 2 1 file dbda8d6ce9 2007-07-21 drh: ** 2 2 memory dbda8d6ce9 2007-07-21 drh: ** 2 0 memory dbda8d6ce9 2007-07-21 drh: ** 3 any memory dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3BtreeFactory( dbda8d6ce9 2007-07-21 drh: const sqlite3 *db, /* Main database when opening aux otherwise 0 */ dbda8d6ce9 2007-07-21 drh: const char *zFilename, /* Name of the file containing the BTree database */ dbda8d6ce9 2007-07-21 drh: int omitJournal, /* if TRUE then do not journal this file */ dbda8d6ce9 2007-07-21 drh: int nCache, /* How many pages in the page cache */ c287665ba8 2007-09-14 drh: int vfsFlags, /* Flags passed through to vfsOpen */ dbda8d6ce9 2007-07-21 drh: Btree **ppBtree /* Pointer to new Btree object written here */ dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: int btFlags = 0; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: assert( ppBtree != 0); dbda8d6ce9 2007-07-21 drh: if( omitJournal ){ c287665ba8 2007-09-14 drh: btFlags |= BTREE_OMIT_JOURNAL; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( db->flags & SQLITE_NoReadlock ){ c287665ba8 2007-09-14 drh: btFlags |= BTREE_NO_READLOCK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zFilename==0 ){ dbda8d6ce9 2007-07-21 drh: #if TEMP_STORE==0 dbda8d6ce9 2007-07-21 drh: /* Do nothing */ dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_MEMORYDB dbda8d6ce9 2007-07-21 drh: #if TEMP_STORE==1 dbda8d6ce9 2007-07-21 drh: if( db->temp_store==2 ) zFilename = ":memory:"; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #if TEMP_STORE==2 dbda8d6ce9 2007-07-21 drh: if( db->temp_store!=1 ) zFilename = ":memory:"; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #if TEMP_STORE==3 dbda8d6ce9 2007-07-21 drh: zFilename = ":memory:"; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_MEMORYDB */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (zFilename==0 || *zFilename==0) ){ c287665ba8 2007-09-14 drh: vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btFlags, vfsFlags); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler); dbda8d6ce9 2007-07-21 drh: sqlite3BtreeSetCacheSize(*ppBtree, nCache); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return UTF-8 encoded English language explanation of the most recent dbda8d6ce9 2007-07-21 drh: ** error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: const char *z; dbda8d6ce9 2007-07-21 drh: if( !db ){ dbda8d6ce9 2007-07-21 drh: return sqlite3ErrStr(SQLITE_NOMEM); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ dbda8d6ce9 2007-07-21 drh: return sqlite3ErrStr(SQLITE_MISUSE); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: z = (char*)sqlite3_value_text(db->pErr); dbda8d6ce9 2007-07-21 drh: if( z==0 ){ dbda8d6ce9 2007-07-21 drh: z = sqlite3ErrStr(db->errCode); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return UTF-16 encoded English language explanation of the most recent dbda8d6ce9 2007-07-21 drh: ** error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: /* Because all the characters in the string are in the unicode dbda8d6ce9 2007-07-21 drh: ** range 0x00-0xFF, if we pad the big-endian string with a dbda8d6ce9 2007-07-21 drh: ** zero byte, we can obtain the little-endian string with dbda8d6ce9 2007-07-21 drh: ** &big_endian[1]. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static const char outOfMemBe[] = { dbda8d6ce9 2007-07-21 drh: 0, 'o', 0, 'u', 0, 't', 0, ' ', dbda8d6ce9 2007-07-21 drh: 0, 'o', 0, 'f', 0, ' ', dbda8d6ce9 2007-07-21 drh: 0, 'm', 0, 'e', 0, 'm', 0, 'o', 0, 'r', 0, 'y', 0, 0, 0 dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: static const char misuseBe [] = { dbda8d6ce9 2007-07-21 drh: 0, 'l', 0, 'i', 0, 'b', 0, 'r', 0, 'a', 0, 'r', 0, 'y', 0, ' ', dbda8d6ce9 2007-07-21 drh: 0, 'r', 0, 'o', 0, 'u', 0, 't', 0, 'i', 0, 'n', 0, 'e', 0, ' ', dbda8d6ce9 2007-07-21 drh: 0, 'c', 0, 'a', 0, 'l', 0, 'l', 0, 'e', 0, 'd', 0, ' ', dbda8d6ce9 2007-07-21 drh: 0, 'o', 0, 'u', 0, 't', 0, ' ', dbda8d6ce9 2007-07-21 drh: 0, 'o', 0, 'f', 0, ' ', dbda8d6ce9 2007-07-21 drh: 0, 's', 0, 'e', 0, 'q', 0, 'u', 0, 'e', 0, 'n', 0, 'c', 0, 'e', 0, 0, 0 dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: const void *z; dbda8d6ce9 2007-07-21 drh: if( !db ){ dbda8d6ce9 2007-07-21 drh: return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ dbda8d6ce9 2007-07-21 drh: return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: z = sqlite3_value_text16(db->pErr); dbda8d6ce9 2007-07-21 drh: if( z==0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode), dbda8d6ce9 2007-07-21 drh: SQLITE_UTF8, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: z = sqlite3_value_text16(db->pErr); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ApiExit(0, 0); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return z; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return the most recent error code generated by an SQLite routine. If NULL is dbda8d6ce9 2007-07-21 drh: ** passed to this function, we assume a malloc() failed during sqlite3_open(). dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_errcode(sqlite3 *db){ c287665ba8 2007-09-14 drh: if( !db || db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return db->errCode & db->errMask; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a new collating function for database "db". The name is zName dbda8d6ce9 2007-07-21 drh: ** and the encoding is enc. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int createCollation( dbda8d6ce9 2007-07-21 drh: sqlite3* db, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int enc, dbda8d6ce9 2007-07-21 drh: void* pCtx, dbda8d6ce9 2007-07-21 drh: int(*xCompare)(void*,int,const void*,int,const void*), dbda8d6ce9 2007-07-21 drh: void(*xDel)(void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: int enc2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: assert( sqlite3_mutex_held(db->mutex) ); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If SQLITE_UTF16 is specified as the encoding type, transform this dbda8d6ce9 2007-07-21 drh: ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the dbda8d6ce9 2007-07-21 drh: ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: enc2 = enc & ~SQLITE_UTF16_ALIGNED; dbda8d6ce9 2007-07-21 drh: if( enc2==SQLITE_UTF16 ){ dbda8d6ce9 2007-07-21 drh: enc2 = SQLITE_UTF16NATIVE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( (enc2&~3)!=0 ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_ERROR, "unknown encoding"); dbda8d6ce9 2007-07-21 drh: return SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Check if this call is removing or replacing an existing collation dbda8d6ce9 2007-07-21 drh: ** sequence. If so, and there are active VMs, return busy. If there dbda8d6ce9 2007-07-21 drh: ** are no active VMs, invalidate any pre-compiled statements. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 0); dbda8d6ce9 2007-07-21 drh: if( pColl && pColl->xCmp ){ dbda8d6ce9 2007-07-21 drh: if( db->activeVdbeCnt ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_BUSY, dbda8d6ce9 2007-07-21 drh: "Unable to delete/modify collation sequence due to active statements"); dbda8d6ce9 2007-07-21 drh: return SQLITE_BUSY; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ExpirePreparedStatements(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* If collation sequence pColl was created directly by a call to dbda8d6ce9 2007-07-21 drh: ** sqlite3_create_collation, and not generated by synthCollSeq(), dbda8d6ce9 2007-07-21 drh: ** then any copies made by synthCollSeq() need to be invalidated. dbda8d6ce9 2007-07-21 drh: ** Also, collation destructor - CollSeq.xDel() - function may need dbda8d6ce9 2007-07-21 drh: ** to be called. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){ dbda8d6ce9 2007-07-21 drh: CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName, strlen(zName)); dbda8d6ce9 2007-07-21 drh: int j; dbda8d6ce9 2007-07-21 drh: for(j=0; j<3; j++){ dbda8d6ce9 2007-07-21 drh: CollSeq *p = &aColl[j]; dbda8d6ce9 2007-07-21 drh: if( p->enc==pColl->enc ){ dbda8d6ce9 2007-07-21 drh: if( p->xDel ){ dbda8d6ce9 2007-07-21 drh: p->xDel(p->pUser); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: p->xCmp = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 1); dbda8d6ce9 2007-07-21 drh: if( pColl ){ dbda8d6ce9 2007-07-21 drh: pColl->xCmp = xCompare; dbda8d6ce9 2007-07-21 drh: pColl->pUser = pCtx; dbda8d6ce9 2007-07-21 drh: pColl->xDel = xDel; dbda8d6ce9 2007-07-21 drh: pColl->enc = enc2 | (enc & SQLITE_UTF16_ALIGNED); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_OK, 0); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This routine does the work of opening a database on behalf of dbda8d6ce9 2007-07-21 drh: ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" dbda8d6ce9 2007-07-21 drh: ** is UTF-8 encoded. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static int openDatabase( dbda8d6ce9 2007-07-21 drh: const char *zFilename, /* Database filename UTF-8 encoded */ c287665ba8 2007-09-14 drh: sqlite3 **ppDb, /* OUT: Returned database handle */ c287665ba8 2007-09-14 drh: unsigned flags, /* Operational flags */ c287665ba8 2007-09-14 drh: const char *zVfs /* Name of the VFS to use */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: sqlite3 *db; dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: CollSeq *pColl; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Allocate the sqlite data structure */ c287665ba8 2007-09-14 drh: db = sqlite3MallocZero( sizeof(sqlite3) ); dbda8d6ce9 2007-07-21 drh: if( db==0 ) goto opendb_out; c287665ba8 2007-09-14 drh: db->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); c287665ba8 2007-09-14 drh: if( db->mutex==0 ){ c287665ba8 2007-09-14 drh: sqlite3_free(db); c287665ba8 2007-09-14 drh: db = 0; c287665ba8 2007-09-14 drh: goto opendb_out; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: db->errMask = 0xff; dbda8d6ce9 2007-07-21 drh: db->priorNewRowid = 0; dbda8d6ce9 2007-07-21 drh: db->nDb = 2; c287665ba8 2007-09-14 drh: db->magic = SQLITE_MAGIC_BUSY; dbda8d6ce9 2007-07-21 drh: db->aDb = db->aDbStatic; dbda8d6ce9 2007-07-21 drh: db->autoCommit = 1; dbda8d6ce9 2007-07-21 drh: db->flags |= SQLITE_ShortColNames dbda8d6ce9 2007-07-21 drh: #if SQLITE_DEFAULT_FILE_FORMAT<4 dbda8d6ce9 2007-07-21 drh: | SQLITE_LegacyFileFmt dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_LOAD_EXTENSION dbda8d6ce9 2007-07-21 drh: | SQLITE_LoadExtension dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: ; dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_VIRTUALTABLE dbda8d6ce9 2007-07-21 drh: sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: db->pVfs = sqlite3_vfs_find(zVfs); c287665ba8 2007-09-14 drh: if( !db->pVfs ){ c287665ba8 2007-09-14 drh: rc = SQLITE_ERROR; c287665ba8 2007-09-14 drh: db->magic = SQLITE_MAGIC_CLOSED; c287665ba8 2007-09-14 drh: sqlite3Error(db, rc, "no such vfs: %s", (zVfs?zVfs:"(null)")); c287665ba8 2007-09-14 drh: goto opendb_out; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: /* Add the default collation sequence BINARY. BINARY works for both UTF-8 dbda8d6ce9 2007-07-21 drh: ** and UTF-16, so add a version for each to avoid any unnecessary dbda8d6ce9 2007-07-21 drh: ** conversions. The only error that can occur here is a malloc() failure. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0) || dbda8d6ce9 2007-07-21 drh: createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0) || dbda8d6ce9 2007-07-21 drh: createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0) || dbda8d6ce9 2007-07-21 drh: (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0 dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: assert( db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: db->magic = SQLITE_MAGIC_CLOSED; dbda8d6ce9 2007-07-21 drh: goto opendb_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Also add a UTF-8 case-insensitive collation sequence. */ dbda8d6ce9 2007-07-21 drh: createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set flags on the built-in collating sequences */ dbda8d6ce9 2007-07-21 drh: db->pDfltColl->type = SQLITE_COLL_BINARY; dbda8d6ce9 2007-07-21 drh: pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 6, 0); dbda8d6ce9 2007-07-21 drh: if( pColl ){ dbda8d6ce9 2007-07-21 drh: pColl->type = SQLITE_COLL_NOCASE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Open the backend database driver */ c287665ba8 2007-09-14 drh: db->openFlags = flags; dbda8d6ce9 2007-07-21 drh: rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE, c287665ba8 2007-09-14 drh: flags | SQLITE_OPEN_MAIN_DB, dbda8d6ce9 2007-07-21 drh: &db->aDb[0].pBt); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, rc, 0); dbda8d6ce9 2007-07-21 drh: db->magic = SQLITE_MAGIC_CLOSED; dbda8d6ce9 2007-07-21 drh: goto opendb_out; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); c287665ba8 2007-09-14 drh: db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The default safety_level for the main database is 'full'; for the temp dbda8d6ce9 2007-07-21 drh: ** database it is 'NONE'. This matches the pager layer defaults. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: db->aDb[0].zName = "main"; dbda8d6ce9 2007-07-21 drh: db->aDb[0].safety_level = 3; dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_TEMPDB dbda8d6ce9 2007-07-21 drh: db->aDb[1].zName = "temp"; dbda8d6ce9 2007-07-21 drh: db->aDb[1].safety_level = 1; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: db->magic = SQLITE_MAGIC_OPEN; c287665ba8 2007-09-14 drh: if( db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: goto opendb_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Register all built-in functions, but do not attempt to read the dbda8d6ce9 2007-07-21 drh: ** database schema yet. This is delayed until the first time the database dbda8d6ce9 2007-07-21 drh: ** is accessed. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, SQLITE_OK, 0); dbda8d6ce9 2007-07-21 drh: sqlite3RegisterBuiltinFunctions(db); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Load automatic extensions - extensions that have been registered dbda8d6ce9 2007-07-21 drh: ** using the sqlite3_automatic_extension() API. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: (void)sqlite3AutoLoadExtensions(db); dbda8d6ce9 2007-07-21 drh: if( sqlite3_errcode(db)!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: goto opendb_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_FTS1 c287665ba8 2007-09-14 drh: if( !db->mallocFailed ){ dbda8d6ce9 2007-07-21 drh: extern int sqlite3Fts1Init(sqlite3*); dbda8d6ce9 2007-07-21 drh: rc = sqlite3Fts1Init(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_FTS2 c287665ba8 2007-09-14 drh: if( !db->mallocFailed && rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: extern int sqlite3Fts2Init(sqlite3*); dbda8d6ce9 2007-07-21 drh: rc = sqlite3Fts2Init(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: c287665ba8 2007-09-14 drh: #ifdef SQLITE_ENABLE_FTS3 c287665ba8 2007-09-14 drh: if( !db->mallocFailed && rc==SQLITE_OK ){ c287665ba8 2007-09-14 drh: extern int sqlite3Fts3Init(sqlite3*); c287665ba8 2007-09-14 drh: rc = sqlite3Fts3Init(db); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: #endif c287665ba8 2007-09-14 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_ICU c287665ba8 2007-09-14 drh: if( !db->mallocFailed && rc==SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: extern int sqlite3IcuInit(sqlite3*); dbda8d6ce9 2007-07-21 drh: rc = sqlite3IcuInit(db); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, rc, 0); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking dbda8d6ce9 2007-07-21 drh: ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking dbda8d6ce9 2007-07-21 drh: ** mode. Doing nothing at all also makes NORMAL the default. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEFAULT_LOCKING_MODE dbda8d6ce9 2007-07-21 drh: db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE; dbda8d6ce9 2007-07-21 drh: sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt), dbda8d6ce9 2007-07-21 drh: SQLITE_DEFAULT_LOCKING_MODE); dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: opendb_out: c287665ba8 2007-09-14 drh: if( db && db->mutex ){ c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: } dbda8d6ce9 2007-07-21 drh: if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){ dbda8d6ce9 2007-07-21 drh: sqlite3_close(db); dbda8d6ce9 2007-07-21 drh: db = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *ppDb = db; dbda8d6ce9 2007-07-21 drh: return sqlite3ApiExit(0, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Open a new database handle. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_open( dbda8d6ce9 2007-07-21 drh: const char *zFilename, dbda8d6ce9 2007-07-21 drh: sqlite3 **ppDb dbda8d6ce9 2007-07-21 drh: ){ c287665ba8 2007-09-14 drh: return openDatabase(zFilename, ppDb, c287665ba8 2007-09-14 drh: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_open_v2( c287665ba8 2007-09-14 drh: const char *filename, /* Database filename (UTF-8) */ c287665ba8 2007-09-14 drh: sqlite3 **ppDb, /* OUT: SQLite db handle */ c287665ba8 2007-09-14 drh: int flags, /* Flags */ c287665ba8 2007-09-14 drh: const char *zVfs /* Name of VFS module to use */ c287665ba8 2007-09-14 drh: ){ c287665ba8 2007-09-14 drh: return openDatabase(filename, ppDb, flags, zVfs); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Open a new database handle. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_open16( dbda8d6ce9 2007-07-21 drh: const void *zFilename, dbda8d6ce9 2007-07-21 drh: sqlite3 **ppDb dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ dbda8d6ce9 2007-07-21 drh: sqlite3_value *pVal; c287665ba8 2007-09-14 drh: int rc = SQLITE_NOMEM; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: assert( zFilename ); dbda8d6ce9 2007-07-21 drh: assert( ppDb ); dbda8d6ce9 2007-07-21 drh: *ppDb = 0; c287665ba8 2007-09-14 drh: pVal = sqlite3ValueNew(0); dbda8d6ce9 2007-07-21 drh: sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); dbda8d6ce9 2007-07-21 drh: zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); dbda8d6ce9 2007-07-21 drh: if( zFilename8 ){ c287665ba8 2007-09-14 drh: rc = openDatabase(zFilename8, ppDb, c287665ba8 2007-09-14 drh: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); dbda8d6ce9 2007-07-21 drh: if( rc==SQLITE_OK && *ppDb ){ dbda8d6ce9 2007-07-21 drh: rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); dbda8d6ce9 2007-07-21 drh: if( rc!=SQLITE_OK ){ dbda8d6ce9 2007-07-21 drh: sqlite3_close(*ppDb); dbda8d6ce9 2007-07-21 drh: *ppDb = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3ValueFree(pVal); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: return sqlite3ApiExit(0, rc); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* c287665ba8 2007-09-14 drh: ** Register a new collation sequence with the database handle db. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_collation( c287665ba8 2007-09-14 drh: sqlite3* db, c287665ba8 2007-09-14 drh: const char *zName, c287665ba8 2007-09-14 drh: int enc, c287665ba8 2007-09-14 drh: void* pCtx, c287665ba8 2007-09-14 drh: int(*xCompare)(void*,int,const void*,int,const void*) c287665ba8 2007-09-14 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); c287665ba8 2007-09-14 drh: rc = createCollation(db, zName, enc, pCtx, xCompare, 0); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a new collation sequence with the database handle db. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_collation_v2( dbda8d6ce9 2007-07-21 drh: sqlite3* db, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int enc, dbda8d6ce9 2007-07-21 drh: void* pCtx, dbda8d6ce9 2007-07-21 drh: int(*xCompare)(void*,int,const void*,int,const void*), dbda8d6ce9 2007-07-21 drh: void(*xDel)(void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); dbda8d6ce9 2007-07-21 drh: rc = createCollation(db, zName, enc, pCtx, xCompare, xDel); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a new collation sequence with the database handle db. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_create_collation16( dbda8d6ce9 2007-07-21 drh: sqlite3* db, dbda8d6ce9 2007-07-21 drh: const char *zName, dbda8d6ce9 2007-07-21 drh: int enc, dbda8d6ce9 2007-07-21 drh: void* pCtx, dbda8d6ce9 2007-07-21 drh: int(*xCompare)(void*,int,const void*,int,const void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc = SQLITE_OK; dbda8d6ce9 2007-07-21 drh: char *zName8; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: assert( !db->mallocFailed ); c287665ba8 2007-09-14 drh: zName8 = sqlite3Utf16to8(db, zName, -1); dbda8d6ce9 2007-07-21 drh: if( zName8 ){ dbda8d6ce9 2007-07-21 drh: rc = createCollation(db, zName8, enc, pCtx, xCompare, 0); c287665ba8 2007-09-14 drh: sqlite3_free(zName8); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a collation sequence factory callback with the database handle dbda8d6ce9 2007-07-21 drh: ** db. Replace any previously installed collation sequence factory. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_collation_needed( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: void *pCollNeededArg, dbda8d6ce9 2007-07-21 drh: void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: db->xCollNeeded = xCollNeeded; dbda8d6ce9 2007-07-21 drh: db->xCollNeeded16 = 0; dbda8d6ce9 2007-07-21 drh: db->pCollNeededArg = pCollNeededArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_UTF16 dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Register a collation sequence factory callback with the database handle dbda8d6ce9 2007-07-21 drh: ** db. Replace any previously installed collation sequence factory. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_collation_needed16( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, dbda8d6ce9 2007-07-21 drh: void *pCollNeededArg, dbda8d6ce9 2007-07-21 drh: void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*) dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyCheck(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: db->xCollNeeded = 0; dbda8d6ce9 2007-07-21 drh: db->xCollNeeded16 = xCollNeeded16; dbda8d6ce9 2007-07-21 drh: db->pCollNeededArg = pCollNeededArg; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif /* SQLITE_OMIT_UTF16 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifndef SQLITE_OMIT_GLOBALRECOVER dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This function is now an anachronism. It used to be used to recover from a dbda8d6ce9 2007-07-21 drh: ** malloc() failure, but SQLite now does this automatically. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_global_recover(){ dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Test to see whether or not the database connection is in autocommit dbda8d6ce9 2007-07-21 drh: ** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on dbda8d6ce9 2007-07-21 drh: ** by default. Autocommit is disabled by a BEGIN statement and reenabled dbda8d6ce9 2007-07-21 drh: ** by the next COMMIT or ROLLBACK. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){ dbda8d6ce9 2007-07-21 drh: return db->autoCommit; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_DEBUG dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The following routine is subtituted for constant SQLITE_CORRUPT in dbda8d6ce9 2007-07-21 drh: ** debugging builds. This provides a way to set a breakpoint for when dbda8d6ce9 2007-07-21 drh: ** corruption is first detected. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_PRIVATE int sqlite3Corrupt(void){ dbda8d6ce9 2007-07-21 drh: return SQLITE_CORRUPT; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** This is a convenience routine that makes sure that all thread-specific dbda8d6ce9 2007-07-21 drh: ** data for this thread has been deallocated. c287665ba8 2007-09-14 drh: ** c287665ba8 2007-09-14 drh: ** SQLite no longer uses thread-specific data so this routine is now a c287665ba8 2007-09-14 drh: ** no-op. It is retained for historical compatibility. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API void sqlite3_thread_cleanup(void){ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Return meta information about a specific column of a database table. dbda8d6ce9 2007-07-21 drh: ** See comment in sqlite3.h (sqlite.h.in) for details. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifdef SQLITE_ENABLE_COLUMN_METADATA c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_table_column_metadata( dbda8d6ce9 2007-07-21 drh: sqlite3 *db, /* Connection handle */ dbda8d6ce9 2007-07-21 drh: const char *zDbName, /* Database name or NULL */ dbda8d6ce9 2007-07-21 drh: const char *zTableName, /* Table name */ dbda8d6ce9 2007-07-21 drh: const char *zColumnName, /* Column name */ dbda8d6ce9 2007-07-21 drh: char const **pzDataType, /* OUTPUT: Declared data type */ dbda8d6ce9 2007-07-21 drh: char const **pzCollSeq, /* OUTPUT: Collation sequence name */ dbda8d6ce9 2007-07-21 drh: int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ dbda8d6ce9 2007-07-21 drh: int *pPrimaryKey, /* OUTPUT: True if column part of PK */ dbda8d6ce9 2007-07-21 drh: int *pAutoinc /* OUTPUT: True if colums is auto-increment */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: char *zErrMsg = 0; dbda8d6ce9 2007-07-21 drh: Table *pTab = 0; dbda8d6ce9 2007-07-21 drh: Column *pCol = 0; dbda8d6ce9 2007-07-21 drh: int iCol; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: char const *zDataType = 0; dbda8d6ce9 2007-07-21 drh: char const *zCollSeq = 0; dbda8d6ce9 2007-07-21 drh: int notnull = 0; dbda8d6ce9 2007-07-21 drh: int primarykey = 0; dbda8d6ce9 2007-07-21 drh: int autoinc = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Ensure the database schema has been loaded */ dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOn(db) ){ dbda8d6ce9 2007-07-21 drh: return SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: rc = sqlite3Init(db, &zErrMsg); dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK!=rc ){ dbda8d6ce9 2007-07-21 drh: goto error_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Locate the table in question */ dbda8d6ce9 2007-07-21 drh: pTab = sqlite3FindTable(db, zTableName, zDbName); dbda8d6ce9 2007-07-21 drh: if( !pTab || pTab->pSelect ){ dbda8d6ce9 2007-07-21 drh: pTab = 0; dbda8d6ce9 2007-07-21 drh: goto error_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Find the column for which info is requested */ dbda8d6ce9 2007-07-21 drh: if( sqlite3IsRowid(zColumnName) ){ dbda8d6ce9 2007-07-21 drh: iCol = pTab->iPKey; dbda8d6ce9 2007-07-21 drh: if( iCol>=0 ){ dbda8d6ce9 2007-07-21 drh: pCol = &pTab->aCol[iCol]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: for(iCol=0; iCol<pTab->nCol; iCol++){ dbda8d6ce9 2007-07-21 drh: pCol = &pTab->aCol[iCol]; dbda8d6ce9 2007-07-21 drh: if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( iCol==pTab->nCol ){ dbda8d6ce9 2007-07-21 drh: pTab = 0; dbda8d6ce9 2007-07-21 drh: goto error_out; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* The following block stores the meta information that will be returned dbda8d6ce9 2007-07-21 drh: ** to the caller in local variables zDataType, zCollSeq, notnull, primarykey dbda8d6ce9 2007-07-21 drh: ** and autoinc. At this point there are two possibilities: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 1. The specified column name was rowid", "oid" or "_rowid_" dbda8d6ce9 2007-07-21 drh: ** and there is no explicitly declared IPK column. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 2. The table is not a view and the column name identified an dbda8d6ce9 2007-07-21 drh: ** explicitly declared column. Copy meta information from *pCol. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pCol ){ dbda8d6ce9 2007-07-21 drh: zDataType = pCol->zType; dbda8d6ce9 2007-07-21 drh: zCollSeq = pCol->zColl; dbda8d6ce9 2007-07-21 drh: notnull = (pCol->notNull?1:0); dbda8d6ce9 2007-07-21 drh: primarykey = (pCol->isPrimKey?1:0); dbda8d6ce9 2007-07-21 drh: autoinc = ((pTab->iPKey==iCol && pTab->autoInc)?1:0); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: zDataType = "INTEGER"; dbda8d6ce9 2007-07-21 drh: primarykey = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !zCollSeq ){ dbda8d6ce9 2007-07-21 drh: zCollSeq = "BINARY"; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: error_out: dbda8d6ce9 2007-07-21 drh: if( sqlite3SafetyOff(db) ){ dbda8d6ce9 2007-07-21 drh: rc = SQLITE_MISUSE; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Whether the function call succeeded or failed, set the output parameters dbda8d6ce9 2007-07-21 drh: ** to whatever their local counterparts contain. If an error did occur, dbda8d6ce9 2007-07-21 drh: ** this has the effect of zeroing all output parameters. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: if( pzDataType ) *pzDataType = zDataType; dbda8d6ce9 2007-07-21 drh: if( pzCollSeq ) *pzCollSeq = zCollSeq; dbda8d6ce9 2007-07-21 drh: if( pNotNull ) *pNotNull = notnull; dbda8d6ce9 2007-07-21 drh: if( pPrimaryKey ) *pPrimaryKey = primarykey; dbda8d6ce9 2007-07-21 drh: if( pAutoinc ) *pAutoinc = autoinc; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( SQLITE_OK==rc && !pTab ){ dbda8d6ce9 2007-07-21 drh: sqlite3SetString(&zErrMsg, "no such table column: ", zTableName, ".", dbda8d6ce9 2007-07-21 drh: zColumnName, 0); dbda8d6ce9 2007-07-21 drh: rc = SQLITE_ERROR; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg); c287665ba8 2007-09-14 drh: sqlite3_free(zErrMsg); c287665ba8 2007-09-14 drh: rc = sqlite3ApiExit(db, rc); c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Sleep for a little while. Return the amount of time slept. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: SQLITE_API int sqlite3_sleep(int ms){ c287665ba8 2007-09-14 drh: sqlite3_vfs *pVfs; c287665ba8 2007-09-14 drh: int rc; c287665ba8 2007-09-14 drh: pVfs = sqlite3_vfs_find(0); c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* This function works in milliseconds, but the underlying OsSleep() c287665ba8 2007-09-14 drh: ** API uses microseconds. Hence the 1000's. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Enable or disable the extended result codes. dbda8d6ce9 2007-07-21 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); dbda8d6ce9 2007-07-21 drh: db->errMask = onoff ? 0xffffffff : 0xff; c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); dbda8d6ce9 2007-07-21 drh: return SQLITE_OK; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: c287665ba8 2007-09-14 drh: /* c287665ba8 2007-09-14 drh: ** Invoke the xFileControl method on a particular database. c287665ba8 2007-09-14 drh: */ c287665ba8 2007-09-14 drh: SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ c287665ba8 2007-09-14 drh: int rc = SQLITE_ERROR; c287665ba8 2007-09-14 drh: int iDb; c287665ba8 2007-09-14 drh: sqlite3_mutex_enter(db->mutex); c287665ba8 2007-09-14 drh: if( zDbName==0 ){ c287665ba8 2007-09-14 drh: iDb = 0; c287665ba8 2007-09-14 drh: }else{ c287665ba8 2007-09-14 drh: for(iDb=0; iDb<db->nDb; iDb++){ c287665ba8 2007-09-14 drh: if( strcmp(db->aDb[iDb].zName, zDbName)==0 ) break; c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: if( iDb<db->nDb ){ c287665ba8 2007-09-14 drh: Btree *pBtree = db->aDb[iDb].pBt; c287665ba8 2007-09-14 drh: if( pBtree ){ c287665ba8 2007-09-14 drh: Pager *pPager; c287665ba8 2007-09-14 drh: sqlite3BtreeEnter(pBtree); c287665ba8 2007-09-14 drh: pPager = sqlite3BtreePager(pBtree); c287665ba8 2007-09-14 drh: if( pPager ){ c287665ba8 2007-09-14 drh: sqlite3_file *fd = sqlite3PagerFile(pPager); c287665ba8 2007-09-14 drh: if( fd ){ c287665ba8 2007-09-14 drh: rc = sqlite3OsFileControl(fd, op, pArg); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3BtreeLeave(pBtree); c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: } c287665ba8 2007-09-14 drh: sqlite3_mutex_leave(db->mutex); c287665ba8 2007-09-14 drh: return rc; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /************** End of main.c ************************************************/