DELETED Doc/SQLite.NET.Internal.chm Index: Doc/SQLite.NET.Internal.chm ================================================================== --- Doc/SQLite.NET.Internal.chm +++ /dev/null cannot compute difference between binary files DELETED Doc/SQLite.NET.Internal.ndoc Index: Doc/SQLite.NET.Internal.ndoc ================================================================== --- Doc/SQLite.NET.Internal.ndoc +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Index: Doc/SQLite.NET.chm ================================================================== --- Doc/SQLite.NET.chm +++ Doc/SQLite.NET.chm cannot compute difference between binary files Index: Doc/SQLite.NET.ndoc ================================================================== --- Doc/SQLite.NET.ndoc +++ Doc/SQLite.NET.ndoc @@ -1,8 +1,8 @@ - + DELETED Doc/System.Data.SQLite.XML Index: Doc/System.Data.SQLite.XML ================================================================== --- Doc/System.Data.SQLite.XML +++ /dev/null @@ -1,2935 +0,0 @@ - - - - System.Data.SQLite - - - - - SQLite implementation of DbProviderFactory. - - - - - Static instance member which returns an instanced SQLiteFactory class. - - - - - Returns a new SQLiteCommand object. - - A SQLiteCommand object. - - - - Returns a new SQLiteCommandBuilder object. - - A SQLiteCommandBuilder object. - - - - Creates a new SQLiteConnection. - - A SQLiteConnection object. - - - - Creates a new SQLiteConnectionStringBuilder. - - A SQLiteConnectionStringBuilder object. - - - - Creates a new SQLiteDataAdapter. - - A SQLiteDataAdapter object. - - - - Creates a new SQLiteParameter. - - A SQLiteParameter object. - - - - SQLite implementation of DbDataReader. - - - - - Underlying command this reader is attached to - - - - - Index of the current statement in the command being processed - - - - - Current statement being Read() - - - - - State of the current statement being processed. - -1 = First Step() executed, so the first Read() will be ignored - 0 = Actively reading - 1 = Finished reading - 2 = Non-row-returning statement, no records - - - - - Number of records affected by the insert/update statements executed on the command - - - - - Count of fields (columns) in the row-returning statement currently being processed - - - - - Datatypes of active fields (columns) in the current statement, used for type-restricting data - - - - - The behavior of the datareader - - - - - Internal constructor, initializes the datareader and sets up to begin executing statements - - The SQLiteCommand this data reader is for - The expected behavior of the data reader - - - - Initializes and resets the datareader's member variables - - - - - Closes the datareader, potentially closing the connection as well if CommandBehavior.CloseConnection was specified. - - - - - Disposes the datareader. Calls Close() to ensure everything is cleaned up. - - - - - Throw an error if the datareader is closed - - - - - Throw an error if a row is not loaded - - - - - Enumerator support - - Returns a DbEnumerator object. - - - - SQLite is inherently un-typed. All datatypes in SQLite are natively strings. The definition of the columns of a table - and the affinity of returned types are all we have to go on to type-restrict data in the reader. - - This function attempts to verify that the type of data being requested of a column matches the datatype of the column. In - the case of columns that are not backed into a table definition, we attempt to match up the affinity of a column (int, double, string or blob) - to a set of known types that closely match that affinity. It's not an exact science, but its the best we can do. - - - This function throws an InvalidTypeCast() exception if the requested type doesn't match the column's definition or affinity. - - The index of the column to type-check - The type we want to get out of the column - - - - Retrieves the column as a boolean value - - The index of the column to retrieve - bool - - - - Retrieves the column as a single byte value - - The index of the column to retrieve - byte - - - - Retrieves a column as an array of bytes (blob) - - The index of the column to retrieve - The zero-based index of where to begin reading the data - The buffer to write the bytes into - The zero-based index of where to begin writing into the array - The number of bytes to retrieve - The actual number of bytes written into the array - - To determine the number of bytes in the column, pass a null value for the buffer. The total length will be returned. - - - - - Returns the column as a single character - - The index of the column to retrieve - char - - - - Retrieves a column as an array of chars (blob) - - The index of the column to retrieve - The zero-based index of where to begin reading the data - The buffer to write the characters into - The zero-based index of where to begin writing into the array - The number of bytes to retrieve - The actual number of characters written into the array - - To determine the number of characters in the column, pass a null value for the buffer. The total length will be returned. - - - - - Retrieves the name of the back-end datatype of the column - - The index of the column to retrieve - string - - - - Retrieve the column as a date/time value - - The index of the column to retrieve - DateTime - - - - Retrieve the column as a decimal value - - The index of the column to retrieve - decimal - - - - Returns the column as a double - - The index of the column to retrieve - double - - - - Returns the .NET type of a given column - - The index of the column to retrieve - Type - - - - Returns a column as a float value - - The index of the column to retrieve - float - - - - Returns the column as a Guid - - The index of the column to retrieve - Guid - - - - Returns the column as a short - - The index of the column to retrieve - Int16 - - - - Retrieves the column as an int - - The index of the column to retrieve - Int32 - - - - Retrieves the column as a long - - The index of the column to retrieve - Int64 - - - - Retrieves the name of the column - - The index of the column to retrieve - string - - - - Retrieves the i of a column, given its name - - The name of the column to retrieve - The int i of the column - - - - Schema information in SQLite is an iffy-business. We've extended the native SQLite3.DLL to include a special pragma called - PRAGMA real_column_names - When enabled, the pragma causes all column aliases to be ignored, and the full Database.Table.ColumnName to be returned for - each column of a SELECT statement. Using this information it is then possible to query each database and table for the - matching column, and associate it with the active statement. - - - The current connection is cloned for the sake of executing this statement, so as to avoid any possibility of corrupting the - original connection's existing statements or state. Any attached databases are re-attached to the new connection. - - Returns a DataTable containing the schema information for the active SELECT statement being processed. - - - - Retrieves the column as a string - - The index of the column to retrieve - string - - - - Retrieves the column as an object corresponding to the underlying datatype of the column - - The index of the column to retrieve - object - - - - Retreives the values of multiple columns, up to the size of the supplied array - - The array to fill with values from the columns in the current resultset - The number of columns retrieved - - - - Returns True if the specified column is null - - The index of the column to retrieve - True or False - - - - Moves to the next resultset in multiple row-returning SQL command. - - True if the command was successful and a new resultset is available, False otherwise. - - - - Retrieves the SQLiteType for a given column, and caches it to avoid repetetive interop calls. - - The index of the column to retrieve - A SQLiteType structure - - - - Reads the next row from the resultset - - True if a new row was successfully loaded and is ready for processing - - - - Not implemented. Returns 0 - - - - - Returns the number of columns in the current resultset - - - - - Returns True if the resultset has rows that can be fetched - - - - - Returns True if the data reader is closed - - - - - Retrieve the count of records affected by an update/insert command. Only valid once the data reader is closed! - - - - - Indexer to retrieve data from a column given its name - - The name of the column to retrieve data for - The value contained in the column - - - - Indexer to retrieve data from a column given its i - - The index of the column to retrieve - The value contained in the column - - - - The type of user-defined function to declare - - - - - Scalar functions are designed to be called and return a result immediately. Examples include ABS(), Upper(), Lower(), etc. - - - - - Aggregate functions are designed to accumulate data until the end of a call and then return a result gleaned from the accumulated data. - Examples include SUM(), COUNT(), AVG(), etc. - - - - - Collation sequences are used to sort textual data in a custom manner, and appear in an ORDER BY clause. Typically text in an ORDER BY is - sorted using a straight case-insensitive comparison function. Custom collating sequences can be used to alter the behavior of text sorting - in a user-defined manner. - - - - - An internal callback delegate declaration. - - Raw context pointer for the user function - Count of arguments to the function - A pointer to the array of argument pointers - - - - Internal callback delegate for implementing collation sequences - - Length of the string pv1 - Pointer to the first string to compare - Length of the string pv2 - Pointer to the second string to compare - Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater - than the second. - - - - This abstract class is designed to handle user-defined functions easily. An instance of the derived class is made for each - connection to the database. - - - Although there is one instance of a class derived from SQLiteFunction per database connection, the derived class has no access - to the underlying connection. This is necessary to deter implementers from thinking it would be a good idea to make database - calls during processing. - - It is important to distinguish between a per-connection instance, and a per-SQL statement context. One instance of this class - services all SQL statements being stepped through on that connection, and there can be many. One should never store per-statement - information in member variables of user-defined function classes. - - For aggregate functions, always create and store your per-statement data in the contextData object on the 1st step. This data will - be automatically freed for you (and Dispose() called if the item supports IDisposable) when the statement completes. - - - - - The base connection this function is attached to - - - - - Used internally to keep track of memory allocated for aggregate functions - - - - - Internal array used to keep track of aggregate function context data - - - - - Holds a reference to the callback function for user functions - - - - - Holds a reference to the callbakc function for stepping in an aggregate function - - - - - Holds a reference to the callback function for finalizing an aggregate function - - - - - Holds a reference to the callback function for collation sequences - - - - - This static list contains all the user-defined functions declared using the proper attributes. - - - - - Internal constructor, initializes the function's internal variables. - - - - - Scalar functions override this method to do their magic. - - - Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available - to force them into a certain type. Therefore the only types you will ever see as parameters are - DBNull.Value, Int64, Double, String or byte[] array. - - The arguments for the command to process - You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or - you may return an Exception-derived class if you wish to return an error to SQLite. Do not actually throw the error, - just return it! - - - - Aggregate functions override this method to do their magic. - - - Typically you'll be updating whatever you've placed in the contextData field and returning as quickly as possible. - - The arguments for the command to process - The 1-based step number. This is incrememted each time the step method is called. - A placeholder for implementers to store contextual data pertaining to the current context. - - - - Aggregate functions override this method to finish their aggregate processing. - - - If you implemented your aggregate function properly, - you've been recording and keeping track of your data in the contextData object provided, and now at this stage you should have - all the information you need in there to figure out what to return. - - Your own assigned contextData, provided for you so you can return your final results. - You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or - you may return an Exception-derived class if you wish to return an error to SQLite. Do not actually throw the error, - just return it! - - - - - User-defined collation sequences override this method to provide a custom string sorting algorithm. - - The first string to compare - The second strnig to compare - 1 if param1 is greater than param2, 0 if they are equal, or -1 if param1 is less than param2 - - - - Converts an IntPtr array of context arguments to an object array containing the resolved parameters the pointers point to. - - - Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available - to force them into a certain type. Therefore the only types you will ever see as parameters are - DBNull.Value, Int64, Double, String or byte[] array. - - The number of arguments - A pointer to the array of arguments - An object array of the arguments once they've been converted to .NET values - - - - Takes the return value from Invoke() and Final() and figures out how to return it to SQLite's context. - - The context the return value applies to - The parameter to return to SQLite - - - - Internal scalar callback function, which wraps the raw context pointer and calls the virtual Invoke() method. - - A raw context pointer - Number of arguments passed in - A pointer to the array of arguments - - - - Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function. - - Length of the string pv1 - Pointer to the first string to compare - Length of the string pv2 - Pointer to the second string to compare - Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater - than the second. - - - - The internal aggregate Step function callback, which wraps the raw context pointer and calls the virtual Step() method. - - - This function takes care of doing the lookups and getting the important information put together to call the Step() function. - That includes pulling out the user's contextData and updating it after the call is made. We use a sorted list for this so - binary searches can be done to find the data. - - A raw context pointer - Number of arguments passed in - A pointer to the array of arguments - - - - An internal aggregate Final function callback, which wraps the context pointer and calls the virtual Final() method. - - A raw context pointer - Not used, always zero - Not used, always zero - - - - Placeholder for a user-defined disposal routine - - True if the object is being disposed explicitly - - - - Disposes of any active contextData variables that were not automatically cleaned up. Sometimes this can happen if - someone closes the connection while a DataReader is open. - - - - - Using reflection, enumerate all assemblies in the current appdomain looking for classes that - have a SQLiteFunctionAttribute attribute, and registering them accordingly. - - - - - Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection. - It is done this way so that all user-defined functions will access the database using the same encoding scheme - as the connection (UTF-8 or UTF-16). - - - The wrapper functions that interop with SQLite will create a unique cooke value, which internally is a pointer to - all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. - - The base object on which the functions are to bind - Returns an array of functions which the connection object should retain until the connection is closed. - - - - Issued after the base connection is closed, this function cleans up all user-defined functions and disposes of them. - - - Cleaning up here is done mainly because of the interop wrapper. It allocated memory to hold a reference to all the - delegates, and now must free that memory. - Freeing is done after the connection is closed to ensure no callbacks get hit after we've freed the cookie. - - The base SQLite connection object - An array of user-defined functions for this object - - - - Returns a reference to the underlying connection's SQLiteConvert class, which can be used to convert - strings and DateTime's into the current connection's encoding schema. - - - - - SQLite has very limited types, and is inherently text-based. The first 5 types below represent the sum of all types SQLite - understands. The DateTime extension to the spec is for internal use only. - - - - - Not used - - - - - All integers in SQLite default to Int64 - - - - - All floating point numbers in SQLite default to double - - - - - The default data type of SQLite is text - - - - - Typically blob types are only seen when returned from a function - - - - - Null types can be returned from functions - - - - - Used internally by this provider - - - - - Used internally - - - - - This implementation of SQLite for ADO.NET can process date/time fields in databases in only one of two formats. Ticks and ISO8601. - Ticks is inherently more accurate, but less compatible with 3rd party tools that query the database, and renders the DateTime field - unreadable without post-processing. - ISO8601 is more compatible, readable, fully-processable, but less accurate as it doesn't provide time down to fractions of a second. - - - - - Using ticks is more accurate but less compatible with other viewers and utilities that access your database. - - - - - The default format for this provider. More compatible with SQLite's intended usage of datetimes, but overall less accurate than Ticks as it doesn't - natively support times down to fractions of a second. - - - - - Struct used internally to determine the datatype of a column in a resultset - - - - - The DbType of the column, or DbType.Object if it cannot be determined - - - - - The affinity of a column, used for expressions or when Type is DbType.Object - - - - - This base class provides datatype conversion services for the SQLite provider. - - - - - An array of ISO8601 datetime formats we support conversion from - - - - - An UTF-8 Encoding instance, so we can convert strings to and from UTF-8 - - - - - The default DateTime format for this instance - - - - - Initializes the conversion class - - The default date/time format to use for this instance - - - - Converts a string to a UTF-8 encoded byte array sized to include a null-terminating character. - - The string to convert to UTF-8 - A byte array containing the converted string plus an extra 0 terminating byte at the end of the array. - - - - Convert a DateTime to a UTF-8 encoded, zero-terminated byte array. - - - This function is a convenience function, which first calls ToString() on the DateTime, and then calls ToUTF8() with the - string result. - - The DateTime to convert. - The UTF-8 encoded string, including a 0 terminating byte at the end of the array. - - - - Converts a UTF-8 encoded IntPtr of the specified length into a .NET string - - The pointer to the memory where the UTF-8 string is encoded - The number of bytes to decode - A string containing the translated character(s) - - - - Converts a string into a DateTime, using the current DateTimeFormat specified for the connection when it was opened. - - - Acceptable ISO8601 DateTime formats are: - yyyy-MM-dd HH:mm:ss - yyyyMMddHHmmss - yyyyMMddTHHmmssfffffff - yyyy-MM-dd - yy-MM-dd - yyyyMMdd - HH:mm:ss - THHmmss - - The string containing either a Tick value or an ISO8601-format string - A DateTime value - - - - Converts a DateTime to a string value, using the current DateTimeFormat specified for the connection when it was opened. - - The DateTime value to convert - Either a string consisting of the tick count for DateTimeFormat.Ticks, or a date/time in ISO8601 format. - - - - Internal function to convert a UTF-8 encoded IntPtr of the specified length to a DateTime. - - - This is a convenience function, which first calls ToString() on the IntPtr to convert it to a string, then calls - ToDateTime() on the string to return a DateTime. - - A pointer to the UTF-8 encoded string - The length in bytes of the string - The parsed DateTime value - - - - Smart method of splitting a string. Skips quoted elements, removes the quotes. - - - This split function works somewhat like the String.Split() function in that it breaks apart a string into - pieces and returns the pieces as an array. The primary differences are: - - Only one character can be provided as a separator character - Quoted text inside the string is skipped over when searching for the separator, and the quotes are removed. - - Thus, if splitting the following string looking for a comma:
- One,Two, "Three, Four", Five
-
- The resulting array would contain
- [0] One
- [1] Two
- [2] Three, Four
- [3] Five
-
- Note that the leading and trailing spaces were removed from each item during the split. -
- Source string to split apart - Separator character - A string array of the split up elements -
- - - Determines the data type of a column in a statement - - The statement to retrieve information for - The column to retrieve type information on - Returns a SQLiteType struct - - - - Converts a SQLiteType to a .NET Type object - - The SQLiteType to convert - Returns a .NET Type object - - - - For a given intrinsic type, return a DbType - - The native type to convert - The corresponding (closest match) DbType - - - - Convert a DbType to a Type - - The DbType to convert from - The closest-match .NET type - - - - For a given type, return the closest-match SQLite TypeAffinity, which only understands a very limited subset of types. - - The type to evaluate - The SQLite type affinity for that type. - - - - For a given type name, return a closest-match .NET type - - The name of the type to match - The .NET DBType the text evaluates to. - - - - A strongly-typed resource class, for looking up localized strings, etc. - - - - - Returns the cached ResourceManager instance used by this class. - - - - - Overrides the current thread's CurrentUICulture property for all - resource lookups using this strongly typed resource class. - - - - - Looks up a localized string similar to <?xml version="1.0" standalone="yes"?> - <DocumentElement> - <DataTypes> - <TypeName>System.Int16</TypeName> - <ProviderDbType>10</ProviderDbType> - <ColumnSize>5</ColumnSize> - <DataType>System.Int16</DataType> - <IsAutoIncrementable>false</IsAutoIncrementable> - <IsCaseSensitive>false</IsCaseSensitive> - <IsFixedLength>true</IsFixedLength> - <IsFixedPrecisionScale>true</IsFixedPrecisionScale> - <IsLong>false</IsLong> - <IsNullable>true</IsNullable> - <IsSearchable>true</Is [rest of string was truncated]";. - - - - - Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> - <DocumentElement> - <MetaDataCollections> - <CollectionName>MetaDataCollections</CollectionName> - <NumberOfRestrictions>0</NumberOfRestrictions> - <NumberOfIdentifierParts>0</NumberOfIdentifierParts> - </MetaDataCollections> - <MetaDataCollections> - <CollectionName>DataSourceInformation</CollectionName> - <NumberOfRestrictions>0</NumberOfRestrictions> - <NumberOfIdentifierParts>0</NumberOfIdentifierParts> - </MetaDataCollections> - <MetaDataC [rest of string was truncated]";. - - - - - A simple custom attribute to enable us to easily find user-defined functions in - the loaded assemblies and initialize them in SQLite as connections are made. - - - - - Default constructor, initializes the internal variables for the function. - - - - - The function's name as it will be used in SQLite command text. - - - - - The number of arguments this function expects. -1 if the number of arguments is variable. - - - - - The type of function this implementation will be. - - - - - SQLite error codes - - - - - Success - - - - - SQL error or missing database - - - - - Internal logic error in SQLite - - - - - Access permission denied - - - - - Callback routine requested an abort - - - - - The database file is locked - - - - - A table in the database is locked - - - - - malloc() failed - - - - - Attempt to write a read-only database - - - - - Operation terminated by sqlite3_interrupt() - - - - - Some kind of disk I/O error occurred - - - - - The database disk image is malformed - - - - - Table or record not found - - - - - Insertion failed because database is full - - - - - Unable to open the database file - - - - - Database lock protocol error - - - - - Database is empty - - - - - The database schema changed - - - - - Too much data for one row of a table - - - - - Abort due to constraint violation - - - - - Data type mismatch - - - - - Library used incorrectly - - - - - Uses OS features not supported on host - - - - - Authorization denied - - - - - Auxiliary database format error - - - - - 2nd parameter to sqlite3_bind out of range - - - - - File opened that is not a database file - - - - - sqlite3_step() has another row ready - - - - - sqlite3_step() has finished executing - - - - - SQLite exception class. - - - - - Public constructor for generating a SQLite error given the base error code - - The SQLite error code to report - Extra text to go along with the error message text - - - - Various public constructors that just pass along to the base Exception - - Passed verbatim to Exception - - - - Various public constructors that just pass along to the base Exception - - - - - Various public constructors that just pass along to the base Exception - Passed to Exception - Passed to Exception - - - - - Initializes the exception class with the SQLite error code. - - The SQLite error code - A detailed error message - An error message string - - - - Retrieves the underlying SQLite error code for this exception - - - - - This class implements SQLiteBase completely, and is the guts of the code that interop's SQLite with .NET - - - - - This internal class provides the foundation of SQLite support. It defines all the abstract members needed to implement - a SQLite data provider, and inherits from SQLiteConvert which allows for simple translations of string to and from SQLite. - - - - - Opens a database. - - - Implementers should call SQLiteFunction.BindFunctions() and save the array after opening a connection - to bind all attributed user-defined functions and collating sequences to the new connection. - - The filename of the database to open. SQLite automatically creates it if it doesn't exist. - - - - Closes the currently-open database. - - - After the database has been closed implemeters should call SQLiteFunction.UnbindFunctions() to deallocate all interop allocated - memory associated with the user-defined functions and collating sequences tied to the closed connection. - - - - - Sets the busy timeout on the connection. SQLiteCommand will call this before executing any command. - - The number of milliseconds to wait before returning SQLITE_BUSY - - - - Quick execute of a SQL command. This is only executed internally, usually by SQLiteConnection when the connection - is first opened to set the necessary startup pragmas. - - The SQL command text to execute - - - - Returns the text of the last error issued by SQLite - - - - - - Prepares a SQL statement for execution. - - The SQL command text to prepare - The previous statement in a multi-statement command, or null if no previous statement exists - The remainder of the statement that was not processed. Each call to prepare parses the - SQL up to to either the end of the text or to the first semi-colon delimiter. The remaining text is returned - here for a subsequent call to Prepare() until all the text has been processed. - Returns an initialized SQLiteStatement. - - - - Steps through a prepared statement. - - The SQLiteStatement to step through - True if a row was returned, False if not. - - - - Finalizes a prepared statement. - - The statement to finalize - - - - Resets a prepared statement so it can be executed again. If the error returned is SQLITE_SCHEMA, - transparently attempt to rebuild the SQL statement and throw an error if that was not possible. - - The statement to reset - Returns -1 if the schema changed while resetting, 0 if the reset was sucessful or 6 (SQLITE_LOCKED) if the reset failed due to a lock - - - - An interop-specific function, this call sets an internal flag in the sqlite.interop.dll which causes all column names - of subsequently-prepared statements to return in Database.Table.Column format, ignoring all aliases that may have been applied - to tables or columns in a resultset. - - - All statements prepared on this connection after this flag is changed are affected. Existing statements are not. - - Set to True to enable real column names, false to disable them. - - - - Helper function to retrieve a column of data from an active statement. - - The statement being step()'d through - The column index to retrieve - The type of data contained in the column. If Uninitialized, this function will retrieve the datatype information. - Returns the data in the column - - - - Returns a string representing the active version of SQLite - - - - - Returns the number of changes the last executing insert/update caused. - - - - - The opaque pointer returned to us by the sqlite provider - - - - - The user-defined functions registered on this connection - - - - - Represents a single SQL statement in SQLite. - - - - - The underlying SQLite object this statement is bound to - - - - - The command text of this SQL statement - - - - - The actual statement pointer - - - - - An index from which unnamed parameters begin - - - - - Names of the parameters as SQLite understands them to be - - - - - Parameters for this statement - - - - - Command this statement belongs to (if any) - - - - - Initializes the statement and attempts to get all information about parameters in the statement - - The base SQLite object - The statement - The command text for this statement - The previous command in a multi-statement command - - - - Called by SQLiteParameterCollection, this function determines if the specified parameter name belongs to - this statement, and if so, keeps a reference to the parameter so it can be bound later. - - The parameter name to map - The parameter to assign it - - - - Disposes and finalizes the statement - - - - - Bind all parameters, making sure the caller didn't miss any - - - - - Perform the bind operation for an individual parameter - - The index of the parameter to bind - The parameter we're binding - - - - SQLite implementation of DbDataAdapter. - - - - - This class is just a shell around the DbDataAdapter. Nothing from DbDataAdapter is overridden here, just a few constructors are defined. - - - Default constructor. - - - - - Constructs a data adapter using the specified select command. - - The select command to associate with the adapter. - - - - Constructs a data adapter with the supplied select command text and associated with the specified connection. - - The select command text to associate with the data adapter. - The connection to associate with the select command. - - - - Constructs a data adapter with the specified select command text, and using the specified database connection string. - - The select command text to use to construct a select command. - A connection string suitable for passing to a new SQLiteConnection, which is associated with the select command. - - - - Raised by the underlying DbDataAdapter when a row is being updated - - The event's specifics - - - - Raised by DbDataAdapter after a row is updated - - The event's specifics - - - - Row updating event handler - - - - - Row updated event handler - - - - - Gets/sets the select command for this DataAdapter - - - - - Gets/sets the insert command for this DataAdapter - - - - - Gets/sets the update command for this DataAdapter - - - - - Gets/sets the delete command for this DataAdapter - - - - - SQLite implementation of DbCommand. - - - - - The command text this command is based on - - - - - The connection the command is associated with - - - - - Indicates whether or not a DataReader is active on the command. - - - - - The timeout for the command, kludged because SQLite doesn't support per-command timeout values - - - - - Designer support - - - - - Used by DbDataAdapter to determine updating behavior - - - - - The collection of parameters for the command - - - - - The SQL command text, broken into individual SQL statements as they are executed - - - - - Unprocessed SQL text that has not been executed - - - - - Constructs a new SQLiteCommand - - - Default constructor - - - - - Initializes the command with the given command text - - The SQL command text - - - - Initializes the command with the given SQL command text and attach the command to the specified - connection. - - The SQL command text - The connection to associate with the command - - - - Initializes the command and associates it with the specified connection. - - The connection to associate with the command - - - - Initializes a command with the given SQL, connection and transaction - - The SQL command text - The connection to associate with the command - The transaction the command should be associated with - - - - Initializes the command class - - The SQL command text - A connection to associate with the command - - - - Disposes of the command and clears all member variables - - Whether or not the class is being explicitly or implicitly disposed - - - - Clears and destroys all statements currently prepared - - - - - Builds an array of prepared statements for each complete SQL statement in the command text - - - - - Not implemented - - - - - Forwards to the local CreateParameter() function - - - - - - Create a new parameter - - - - - - This function ensures there are no active readers, that we have a valid connection, - that the connection is open, that all statements are prepared and all parameters are assigned - in preparation for allocating a data reader. - - - - - Creates a new SQLiteDataReader to execute/iterate the array of SQLite prepared statements - - The behavior the data reader should adopt - Returns a SQLiteDataReader object - - - - Overrides the default behavior to return a SQLiteDataReader specialization class - - The flags to be associated with the reader - A SQLiteDataReader - - - - Overrides the default behavior of DbDataReader to return a specialized SQLiteDataReader class - - A SQLiteDataReader - - - - Called by the SQLiteDataReader when the data reader is closed. - - - - - Execute the command and return the number of rows inserted/updated affected by it. - - - - - - Execute the command and return the first column of the first row of the resultset - (if present), or null if no resultset was returned. - - The first column of the first row of the first resultset from the query - - - - Does nothing. Commands are prepared as they are executed the first time, and kept in prepared state afterwards. - - - - - Clones a command, including all its parameters - - A new SQLiteCommand with the same commandtext, connection and parameters - - - - The SQL command text associated with the command - - - - - The amount of time to wait for the connection to become available before erroring out - - - - - The type of the command. SQLite only supports CommandType.Text - - - - - The connection associated with this command - - - - - Forwards to the local Connection property - - - - - Returns the SQLiteParameterCollection for the given command - - - - - Forwards to the local Parameters property - - - - - The transaction associated with this command. SQLite only supports one transaction per connection, so this property forwards to the - command's underlying connection. - - - - - Forwards to the local Transaction property - - - - - Sets the method the SQLiteCommandBuilder uses to determine how to update inserted or updated rows in a DataTable. - - - - - Determines if the command is visible at design time. Defaults to True. - - - - - SQLite implementation of DbTransaction. - - - - - The connection to which this transaction is bound - - - - - Constructs the transaction object, binding it to the supplied connection - - The connection to open a transaction on - TRUE to defer the writelock, or FALSE to lock immediately - - - - Commits the current transaction. - - - - - Disposes the transaction. If it is currently active, any changes are rolled back. - - - - - Rolls back the active transaction. - - - - - Returns the underlying connection to which this transaction applies. - - - - - Forwards to the local Connection property - - - - - Gets the isolation level of the transaction. SQLite does not support isolation levels, so this always returns Unspecified. - - - - - The I/O file cache flushing behavior for the connection - - - - - Normal file flushing at critical sections of the code - - - - - Full file flushing after every write operation - - - - - Use the default operating system's file flushing, SQLite does not explicitly flush the file buffers after writing - - - - - SQLite implentation of DbConnection. - - - The ConnectionString property of the SQLiteConnection class can contain the following parameter(s), delimited with a semi-colon: - - - Parameter - Values - Required - Default - - - Data Source - {filename} - Y - - - - Version - 3 - N - 3 - - - UseUTF16Encoding - True
False
- N - False -
- - DateTimeFormat - Ticks - Use DateTime.Ticks
ISO8601 - Use ISO8601 DateTime format
- N - ISO8601 -
- - Cache Size - {size in bytes} - N - 2000 - - - Synchronous - Normal - Normal file flushing behavior
Full - Full flushing after all writes
Off - Underlying OS flushes I/O's
- N - Normal -
- - Page Size - {size in bytes} - N - 1024 - - - Password - {password} - N - - -
-
-
- - - State of the current connection - - - - - The connection string - - - - - One transaction allowed per connection please! - - - - - The base SQLite object to interop with - - - - - Commands associated with this connection - - - - - The database filename minus path and extension - - - - - Constructs a new SQLiteConnection object - - - Default constructor - - - - - Initializes the connection with the specified connection string - - The connection string to use on the connection - - - - Clones the settings and connection string from an existing connection. If the existing connection is already open, this - function will open its own connection, enumerate any attached databases of the original connection, and automatically - attach to them. - - - - - - Creates a clone of the connection. All attached databases and user-defined functions are cloned. If the existing connection is open, the cloned connection - will also be opened. - - - - - - Disposes of the SQLiteConnection, closing it if it is active. - - True if the connection is being explicitly closed. - - - - Creates a database file. This just creates a zero-byte file which SQLite - will turn into a database when the file is opened properly. - - The file to create - - - - On NTFS volumes, this function turns on the compression attribute for the given file. - It must not be open or referenced at the time of the function call. - - The file to compress - - - - On NTFS volumes, this function removes the compression attribute for the given file. - It must not be open or referenced at the time of the function call. - - The file to decompress - - - - On NTFS volumes, this function turns on the EFS (Encrypted File System) attribute - for the given file, which causes the file to be encrypted. - For a full description of EFS, see the MSDN documentation. - - - Requires Win2K and above, plus a valid EFS certificate (which is beyond the scope - of this function description). - - The file to encrypt - - - - On NTFS volumes, this function removes the encryption attribute from the file, - causing the file to be decrypted. See the MSDN documentation for full details on - EFS (Encrypted File System). - - - Requires Win2K and above, plus a valid EFS certificate (which is beyond the scope - of this function description). - - The file to decrypt - - - - Returns true if the file is encrypted, or false otherwise. - - - Requires Win2K and above, plus a valid EFS certificate (which is beyond the scope - of this function description). - - The file to check - true if the file is encrypted - - - - Raises the state change event when the state of the connection changes - - The new state. If it is different from the previous state, an event is raised. - - - - Creates a new SQLiteTransaction if one isn't already active on the connection. - - SQLite doesn't support varying isolation levels, so this parameter is ignored. - When TRUE, SQLite defers obtaining a write lock until a write operation is requested. - When FALSE, a writelock is obtained immediately. The default is TRUE, but in a multi-threaded multi-writer - environment, one may instead choose to lock the database immediately to avoid any possible writer deadlock. - Returns a SQLiteTransaction object. - - - - Creates a new SQLiteTransaction if one isn't already active on the connection. - - When TRUE, SQLite defers obtaining a write lock until a write operation is requested. - When FALSE, a writelock is obtained immediately. The default is TRUE, but in a multi-threaded multi-writer - environment, one may instead choose to lock the database immediately to avoid any possible writer deadlock. - Returns a SQLiteTransaction object. - - - - Creates a new SQLiteTransaction if one isn't already active on the connection. - - SQLite doesn't support varying isolation levels, so this parameter is ignored. - Returns a SQLiteTransaction object. - - - - Creates a new SQLiteTransaction if one isn't already active on the connection. - - Returns a SQLiteTransaction object. - - - - Forwards to the local BeginTransaction() function - - - - - - - Not implemented - - - - - - When the database connection is closed, all commands linked to this connection are automatically reset. - - - - - Create a new SQLiteCommand and associate it with this connection. - - Returns an instantiated SQLiteCommand object already assigned to this connection. - - - - Forwards to the local CreateCommand() function - - - - - - Parses the connection string into component parts - - An array of key-value pairs representing each parameter of the connection string - - - - Looks for a key in the array of key/values of the parameter string. If not found, return the specified default value - - The Key/Value pair array to look in - The key to find - The default value to return if the key is not found - The value corresponding to the specified key, or the default value if not found. - - - - Opens the connection using the parameters found in the ConnectionString - - - - - Change the password (or assign a password) to an open database. - - - No readers or writers may be active for this process. The database must already be open - and if it already was password protected, the existing password must already have been supplied. - - The new password to assign to the database - - - - Change the password (or assign a password) to an open database. - - - No readers or writers may be active for this process. The database must already be open - and if it already was password protected, the existing password must already have been supplied. - - The new password to assign to the database - - - - Sets the password for a password-protected database. A password-protected database is - unusable for any operation until the password has been set. - - The password for the database - - - - Sets the password for a password-protected database. A password-protected database is - unusable for any operation until the password has been set. - - The password for the database - - - - The following commands are used to extract schema information out of the database. Valid schema types are: - - - MetaDataCollections - - - DataSourceInformation - - - Columns - - - Indexes - - - Tables - - - Views - - - Catalogs - - - - - Returns the MetaDataCollections schema - - A DataTable of the MetaDataCollections schema - - - - Returns schema information of the specified collection - - The schema collection to retrieve - A DataTable of the specified collection - - - - Retrieves schema information using the specified constraint(s) for the specified collection - - The collection to retrieve - The restrictions to impose - A DataTable of the specified collection - - - - Builds a MetaDataCollections schema datatable - - DataTable - - - - Builds a DataSourceInformation datatable - - DataTable - - - - Build a Columns schema - - The catalog (attached database) to query, can be null - The table to retrieve schema information for, must not be null - The column to retrieve schema information for, can be null - DataTable - - - - Returns index information for the given database and catalog - - The catalog (attached database) to query, can be null - The name of the index to retrieve information for, can be null - The table to retrieve index information for, can be null - DataTable - - - - Retrieves table schema information for the database and catalog - - The catalog (attached database) to retrieve tables on - The table to retrieve, can be null - The table type, can be null - DataTable - - - - Retrieves view schema information for the database - - The catalog (attached database) to retrieve views on - The view name, can be null - DataTable - - - - Retrieves catalog (attached databases) schema information for the database - - The catalog to retrieve, can be null - DataTable - - - - Returns the base column information for indexes in a database - - The catalog to retrieve indexes for (can be null) - The table to restrict index information by (can be null) - The index to restrict index information by (can be null) - The source column to restrict index information by (can be null) - A DataTable containing the results - - - - Returns detailed column information for a specified view - - The catalog to retrieve columns for (can be null) - The view to restrict column information by (can be null) - The source column to restrict column information by (can be null) - A DataTable containing the results - - - - Retrieves foreign key information from the specified set of filters - - An optional catalog to restrict results on - An optional table to restrict results on - An optional foreign key name to restrict results on - A DataTable with the results of the query - - - - - This event is raised whenever the database is opened or closed. - - - - - The connection string containing the parameters for the connection - - - - - Parameter - Values - Required - Default - - - Data Source - {filename} - Y - - - - Version - 3 - N - 3 - - - UseUTF16Encoding - True
False
- N - False -
- - DateTimeFormat - Ticks - Use DateTime.Ticks
ISO8601 - Use ISO8601 DateTime format
- N - ISO8601 -
- - Cache Size - {size in bytes} - N - 2000 - - - Synchronous - Normal - Normal file flushing behavior
Full - Full flushing after all writes
Off - Underlying OS flushes I/O's
- N - Normal -
- - Page Size - {size in bytes} - N - 1024 - - - Password - {password} - N - - -
-
-
- - - Returns the filename without extension or path - - - - - Returns an empty string - - - - - Returns the version of the underlying SQLite database engine - - - - - Returns the state of the connection. - - - - - SQLite implementation of DbCommandBuilder. - - - - - Default constructor - - - - - Initializes the command builder and associates it with the specified data adapter. - - - - - - Not implemented, this function does nothing. - - The parameter to use in applying custom behaviors to a row - The row to apply the parameter to - The type of statement - Whether the application of the parameter is part of a WHERE clause - - - - Not implemented. Throws a NotImplementedException() if called. - - - Not implemented. - - The name of the parameter - Error - - - - Not implemented. - - The i of the parameter - Error - - - - Returns a placeholder character for the specified parameter i. - - The index of the parameter to provide a placeholder for - Returns a "?" character, used for all placeholders. - - - - Sets the handler for receiving row updating events. Used by the DbCommandBuilder to autogenerate SQL - statements that may not have previously been generated. - - A data adapter to receive events on. - - - - Returns the automatically-generated SQLite command to delete rows from the database - - - - - - Returns the automatically-generated SQLite command to delete rows from the database - - - - - - - Returns the automatically-generated SQLite command to update rows in the database - - - - - - Returns the automatically-generated SQLite command to update rows in the database - - - - - - - Returns the automatically-generated SQLite command to insert rows into the database - - - - - - Returns the automatically-generated SQLite command to insert rows into the database - - - - - - - Gets/sets the DataAdapter for this CommandBuilder - - - - - Overridden to hide its property from the designer - - - - - Overridden to hide its property from the designer - - - - - Overridden to hide its property from the designer - - - - - Overridden to hide its property from the designer - - - - - Overridden to hide its property from the designer - - - - - Alternate SQLite3 object, overriding many text behaviors to support UTF-16 (Unicode) - - - - - Overrides SQLiteConvert.ToString() to marshal UTF-16 strings instead of UTF-8 - - A pointer to a UTF-16 string - The length (IN BYTES) of the string - A .NET string - - - - SQLite implementation of DbParameterCollection. - - - - - The underlying command to which this collection belongs - - - - - The internal array of parameters in this collection - - - - - Determines whether or not all parameters have been bound to their statement(s) - - - - - Initializes the collection - - The command to which the collection belongs - - - - Retrieves an enumerator for the collection - - An enumerator for the underlying array - - - - Adds a parameter to the collection - - The parameter name - The data type - The size of the value - The source column - A SQLiteParameter object - - - - Adds a parameter to the collection - - The parameter name - The data type - The size of the value - A SQLiteParameter object - - - - Adds a parameter to the collection - - The parameter name - The data type - A SQLiteParameter object - - - - Adds a parameter to the collection - - The parameter to add - A zero-based index of where the parameter is located in the array - - - - Adds a parameter to the collection - - The parameter to add - A zero-based index of where the parameter is located in the array - - - - Adds a named/unnamed parameter and its value to the parameter collection. - - Name of the parameter, or null to indicate an unnamed parameter - The initial value of the parameter - Returns the SQLiteParameter object created during the call. - - - - Adds an array of parameters to the collection - - The array of parameters to add - - - - Adds an array of parameters to the collection - - The array of parameters to add - - - - Clears the array and resets the collection - - - - - Determines if the named parameter exists in the collection - - The name of the parameter to check - True if the parameter is in the collection - - - - Determines if the parameter exists in the collection - - The SQLiteParameter to check - True if the parameter is in the collection - - - - Not implemented - - - - - - - Retrieve a parameter by name from the collection - - The name of the parameter to fetch - A DbParameter object - - - - Retrieves a parameter by its index in the collection - - The index of the parameter to retrieve - A DbParameter object - - - - Returns the index of a parameter given its name - - The name of the parameter to find - -1 if not found, otherwise a zero-based index of the parameter - - - - Returns the index of a parameter - - The parameter to find - -1 if not found, otherwise a zero-based index of the parameter - - - - Inserts a parameter into the array at the specified location - - The zero-based index to insert the parameter at - The parameter to insert - - - - Removes a parameter from the collection - - The parameter to remove - - - - Removes a parameter from the collection given its name - - The name of the parameter to remove - - - - Removes a parameter from the collection given its index - - The zero-based parameter index to remove - - - - Re-assign the named parameter to a new parameter object - - The name of the parameter to replace - The new parameter - - - - Re-assign a parameter at the specified index - - The zero-based index of the parameter to replace - The new parameter - - - - Un-binds all parameters from their statements - - - - - This function attempts to map all parameters in the collection to all statements in a Command. - Since named parameters may span multiple statements, this function makes sure all statements are bound - to the same named parameter. Unnamed parameters are bound in sequence. - - - - - Returns true - - - - - Returns false - - - - - Returns false - - - - - Returns null - - - - - Returns a count of parameters in the collection - - - - - SQLite implementation of DbParameter. - - - - - The data type of the parameter - - - - - The version information for mapping the parameter - - - - - The value of the data in the parameter - - - - - The source column for the parameter - - - - - The column name - - - - - The data size, unused by SQLite - - - - - Default constructor - - - - - Constructs a named parameter given the specified parameter name - - The parameter name - - - - Constructs a named parameter given the specified parameter name and initial value - - The parameter name - The initial value of the parameter - - - - Constructs a named parameter of the specified type - - The parameter name - The datatype of the parameter - - - - Constructs a named parameter of the specified type and source column reference - - The parameter name - The data type - The source column - - - - Constructs a named parameter of the specified type, source column and row version - - The parameter name - The data type - The source column - The row version information - - - - Constructs an unnamed parameter of the specified data type - - The datatype of the parameter - - - - Constructs an unnamed parameter of the specified data type and sets the initial value - - The datatype of the parameter - The initial value of the parameter - - - - Constructs an unnamed parameter of the specified data type and source column - - The datatype of the parameter - The source column - - - - Constructs an unnamed parameter of the specified data type, source column and row version - - The data type - The source column - The row version information - - - - Constructs a named parameter of the specified type and size - - The parameter name - The data type - The size of the parameter - - - - Constructs a named parameter of the specified type, size and source column - - The name of the parameter - The data type - The size of the parameter - The source column - - - - Constructs a named parameter of the specified type, size, source column and row version - - The name of the parameter - The data type - The size of the parameter - The source column - The row version information - - - - Constructs a named parameter of the specified type, size, source column and row version - - The name of the parameter - The data type - The size of the parameter - Only input parameters are supported in SQLite - Ignored - Ignored - Ignored - The source column - The row version information - The initial value to assign the parameter - - - - Constructs an unnamed parameter of the specified type and size - - The data type - The size of the parameter - - - - Constructs an unnamed parameter of the specified type, size, and source column - - The data type - The size of the parameter - The source column - - - - Constructs an unnamed parameter of the specified type, size, source column and row version - - The data type - The size of the parameter - The source column - The row version information - - - - Initializes the parameter member variables - - The parameter name - The data type - The size - The source column - The row version - - - - Not implemented - - - - - Clones a parameter - - A new, unassociated SQLiteParameter - - - - Returns True. - - - - - Returns the datatype of the parameter - - - - - Supports only input parameters - - - - - Returns the parameter name - - - - - Returns the size of the parameter - - - - - Gets/sets the source column - - - - - Returns false, ignores any set value - - - - - Gets and sets the row version - - - - - Gets and sets the parameter value. If no datatype was specified, the datatype will assume the type from the value given. - - - - - SQLite implementation of DbConnectionStringBuilder. - - - - - Properties of this class - - - - - Constructs a new instance of the class - - - Default constructor - - - - - Constructs a new instance of the class using the specified connection string. - - The connection string to parse - - - - Private initializer, which assigns the connection string and resets the builder - - The connection string to assign - - - - Helper function for retrieving values from the connectionstring - - The keyword to retrieve settings for - The resulting parameter value - Returns true if the value was found and returned - - - - Gets/Sets the default version of the SQLite engine to instantiate. Currently the only valid value is 3, indicating version 3 of the sqlite library. - - - - - Gets/Sets the synchronous mode of the connection string. Default is "Normal". - - - - - Gets/Sets the encoding for the connection string. The default is "False" which indicates UTF-8 encoding. - - - - - Gets/Sets the filename to open on the connection string. - - - - - Gets/sets the database encryption password - - - - - Gets/Sets the page size for the connection. - - - - - Gets/Sets the cache size for the connection. - - - - - Gets/Sets the datetime format for the connection. - - -
-
Index: Doc/ndoc.log ================================================================== --- Doc/ndoc.log +++ Doc/ndoc.log @@ -25,11 +25,10 @@ System.Data.SQLite.SQLiteCommandConstructor.html System.Data.SQLite.SQLiteCommandConstructor1.html System.Data.SQLite.SQLiteCommandConstructor2.html System.Data.SQLite.SQLiteCommandConstructor3.html System.Data.SQLite.SQLiteCommandConstructor4.html -System.Data.SQLite.SQLiteCommandConstructor5.html System.Data.SQLite.SQLiteCommandProperties.html System.Data.SQLite.SQLiteCommand.CommandText.html System.Data.SQLite.SQLiteCommand.CommandTimeout.html System.Data.SQLite.SQLiteCommand.CommandType.html System.Data.SQLite.SQLiteCommand.DesignTimeVisible.html @@ -89,10 +88,11 @@ System.Data.SQLite.SQLiteConvert.ToString_overload_2.html System.Data.SQLite.SQLiteConvert.ToString_overload_1.html System.Data.SQLite.SQLiteConvert.ToUTF8_overloads.html System.Data.SQLite.SQLiteConvert.ToUTF8_overload_2.html System.Data.SQLite.SQLiteConvert.ToUTF8_overload_1.html +System.Data.SQLite.SQLiteConvert.TryToDateTime.html System.Data.SQLite.SQLiteDataAdapter.html System.Data.SQLite.SQLiteDataAdapterMembers.html System.Data.SQLite.SQLiteDataAdapterConstructor.html System.Data.SQLite.SQLiteDataAdapterConstructor1.html System.Data.SQLite.SQLiteDataAdapterConstructor2.html @@ -142,10 +142,12 @@ System.Data.SQLite.SQLiteFactory.html System.Data.SQLite.SQLiteFactoryMembers.html System.Data.SQLite.SQLiteFactoryConstructor.html System.Data.SQLite.SQLiteFactoryFields.html System.Data.SQLite.SQLiteFactory.Instance.html +System.Data.SQLite.SQLiteFactoryProperties.html +System.Data.SQLite.SQLiteFactory.SupportedClasses.html System.Data.SQLite.SQLiteFactoryMethods.html System.Data.SQLite.SQLiteFactory.CreateCommand.html System.Data.SQLite.SQLiteFactory.CreateCommandBuilder.html System.Data.SQLite.SQLiteFactory.CreateConnection.html System.Data.SQLite.SQLiteFactory.CreateConnectionStringBuilder.html @@ -161,10 +163,11 @@ System.Data.SQLite.SQLiteFunction.Dispose_overloads.html System.Data.SQLite.SQLiteFunction.Dispose_overload_2.html System.Data.SQLite.SQLiteFunction.Dispose_overload_1.html System.Data.SQLite.SQLiteFunction.Final.html System.Data.SQLite.SQLiteFunction.Invoke.html +System.Data.SQLite.SQLiteFunction.RegisterFunction.html System.Data.SQLite.SQLiteFunction.Step.html System.Data.SQLite.SQLiteFunctionAttribute.html System.Data.SQLite.SQLiteFunctionAttributeMembers.html System.Data.SQLite.SQLiteFunctionAttributeConstructor.html System.Data.SQLite.SQLiteFunctionAttributeFields.html @@ -186,13 +189,10 @@ System.Data.SQLite.SQLiteParameterConstructor10.html System.Data.SQLite.SQLiteParameterConstructor11.html System.Data.SQLite.SQLiteParameterConstructor12.html System.Data.SQLite.SQLiteParameterConstructor13.html System.Data.SQLite.SQLiteParameterConstructor14.html -System.Data.SQLite.SQLiteParameterConstructor15.html -System.Data.SQLite.SQLiteParameterConstructor16.html -System.Data.SQLite.SQLiteParameterConstructor17.html System.Data.SQLite.SQLiteParameterProperties.html System.Data.SQLite.SQLiteParameter.DbType.html System.Data.SQLite.SQLiteParameter.Direction.html System.Data.SQLite.SQLiteParameter.IsNullable.html System.Data.SQLite.SQLiteParameter.Offset.html @@ -201,10 +201,11 @@ System.Data.SQLite.SQLiteParameter.SourceColumn.html System.Data.SQLite.SQLiteParameter.SourceColumnNullMapping.html System.Data.SQLite.SQLiteParameter.SourceVersion.html System.Data.SQLite.SQLiteParameter.Value.html System.Data.SQLite.SQLiteParameterMethods.html +System.Data.SQLite.SQLiteParameter.CopyTo.html System.Data.SQLite.SQLiteParameter.ResetDbType.html System.Data.SQLite.SQLiteParameterCollection.html System.Data.SQLite.SQLiteParameterCollectionMembers.html System.Data.SQLite.SQLiteParameterCollectionProperties.html System.Data.SQLite.SQLiteParameterCollection.Count.html @@ -252,16 +253,16 @@ Compiling c:\src\SQLite.NET\Doc\ndoc_msdn_temp\SQLite.NET.chm Compile time: 0 minutes, 3 seconds -232 Topics -1,341 Local links +233 Topics +1,346 Local links 0 Internet links 8 Graphics -Created c:\src\SQLite.NET\Doc\ndoc_msdn_temp\SQLite.NET.chm, 142,903 bytes -Compression decreased file by 746,084 bytes. +Created c:\src\SQLite.NET\Doc\ndoc_msdn_temp\SQLite.NET.chm, 135,017 bytes +Compression decreased file by 734,402 bytes. Html Help compile complete Done. DELETED SQLite.Designer/AssemblyInfo.cs Index: SQLite.Designer/AssemblyInfo.cs ================================================================== --- SQLite.Designer/AssemblyInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.ConstrainedExecution; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SQLite.Designer")] -[assembly: AssemblyDescription("ADO.NET 2.0 Data Designer for SQLite")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://sourceforge.net/projects/sqlite-dotnet2")] -[assembly: AssemblyProduct("SQLite.Designer")] -[assembly: AssemblyCopyright("Public Domain")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM componenets. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] -[assembly: CLSCompliant(true)] -[assembly: ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.24.5")] -[assembly: AssemblyFileVersion("1.0.24.5")] -[assembly:AssemblyDelaySignAttribute(false)] -[assembly:AssemblyKeyFileAttribute("..\\System.Data.SQLite\\System.Data.SQLite.snk")] -[assembly:AssemblyKeyNameAttribute("")] DELETED SQLite.Designer/SQLite.Designer.csproj Index: SQLite.Designer/SQLite.Designer.csproj ================================================================== --- SQLite.Designer/SQLite.Designer.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {9B4A5CF6-5BE5-4926-ACC7-B729A8C05198} - Library - Properties - SQLite.Designer - SQLite.Designer - false - - - - - true - full - false - ..\bin\Designer\ - DEBUG;TRACE - prompt - 4 - 1701;1702;1699 - - - none - true - ..\bin\Designer\ - - - prompt - 4 - 1701;1702;1699 - - - - False - C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\Microsoft.VisualStudio.Data.dll - False - - - False - - - - - - - - - - - True - True - SR.resx - - - - - ResXFileCodeGenerator - SR.Designer.cs - - - - - - - DELETED SQLite.Designer/SQLiteDataObjectIdentifierResolver.cs Index: SQLite.Designer/SQLiteDataObjectIdentifierResolver.cs ================================================================== --- SQLite.Designer/SQLiteDataObjectIdentifierResolver.cs +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************** - * ADO.NET 2.0 Data Provider for SQLite Version 3.X - * Written by Robert Simpson (robert@blackcastlesoft.com) - * - * Released to the public domain, use at your own risk! - ********************************************************/ - -namespace SQLite.Designer -{ - using System; - using System.Collections.Generic; - using System.Text; - using Microsoft.VisualStudio.Data; - using Microsoft.VisualStudio.OLE.Interop; - - internal class SQLiteDataObjectIdentifierResolver : DataObjectIdentifierResolver, IObjectWithSite - { - private DataConnection _connection; - - public SQLiteDataObjectIdentifierResolver() - { - } - - protected override object[] QuickExpandIdentifier(string typeName, object[] partialIdentifier) - { - if (typeName == null) - { - throw new ArgumentNullException("typeName"); - } - - // Create an identifier array of the correct full length based on - // the object type - object[] identifier = null; - int length = 0; - - switch (typeName.ToLowerInvariant()) - { - case "": - length = 0; - break; - case "table": - case "view": - length = 3; - break; - case "column": - case "index": - case "foreignkey": - case "viewcolumn": - length = 4; - break; - case "indexcolumn": - case "foreignkeycolumn": - length = 5; - break; - default: - throw new NotSupportedException(); - } - identifier = new object[length]; - - // If the input identifier is not null, copy it to the full - // identifier array. If the input identifier's length is less - // than the full length we assume the more specific parts are - // specified and thus copy into the rightmost portion of the - // full identifier array. - if (partialIdentifier != null) - { - if (partialIdentifier.Length > length) - { - throw new InvalidOperationException(); - } - partialIdentifier.CopyTo(identifier, length - partialIdentifier.Length); - } - - if (length > 0) - { - // Fill in the current database if not specified - if (!(identifier[0] is string)) - { - identifier[0] = _connection.SourceInformation[DataSourceInformation.DefaultCatalog] as string; - } - } - - if (length > 1) - { - identifier[1] = null; - } - - return identifier; - } - - protected override object[] QuickContractIdentifier(string typeName, object[] fullIdentifier) - { - int length = fullIdentifier.Length; - object[] identifier = new object[length]; - - fullIdentifier.CopyTo(identifier, 0); - - if (length > 0) - { - if (!(identifier[0] is string)) - identifier[0] = null; - } - - if (length > 1) - { - identifier[1] = null; - } - - return identifier; - } - - /// - /// GetSite does not need to be implemented since - /// DDEX only calls SetSite to site the object. - /// - void IObjectWithSite.GetSite(ref Guid riid, out IntPtr ppvSite) - { - ppvSite = IntPtr.Zero; - throw new NotImplementedException(); - } - - void IObjectWithSite.SetSite(object pUnkSite) - { - _connection = (DataConnection)pUnkSite; - } - } -} DELETED SQLite.Designer/SQLiteDataSourceInformation.cs Index: SQLite.Designer/SQLiteDataSourceInformation.cs ================================================================== --- SQLite.Designer/SQLiteDataSourceInformation.cs +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************** - * ADO.NET 2.0 Data Provider for SQLite Version 3.X - * Written by Robert Simpson (robert@blackcastlesoft.com) - * - * Released to the public domain, use at your own risk! - ********************************************************/ - -namespace SQLite.Designer -{ - using System; - using System.Collections.Generic; - using System.Text; - using Microsoft.VisualStudio.Data; - - internal class SQLiteDataSourceInformation : DataSourceInformation - { - public SQLiteDataSourceInformation() - { - Initialize(); - } - - public SQLiteDataSourceInformation(DataConnection connection) : base(connection) - { - Initialize(); - } - - private void Initialize() - { - AddProperty(DefaultSchema); - AddProperty(DefaultCatalog, "main"); - AddProperty(SupportsAnsi92Sql, true); - AddProperty(SupportsQuotedIdentifierParts, true); - AddProperty(IdentifierOpenQuote, "["); - AddProperty(IdentifierCloseQuote, "]"); - AddProperty(CatalogSeparator, "."); - AddProperty(CatalogSupported, true); - AddProperty(CatalogSupportedInDml, true); - AddProperty(SchemaSupported, false); - AddProperty(SchemaSupportedInDml, false); - AddProperty(SchemaSeparator, ""); - AddProperty(ParameterPrefix, "$"); - AddProperty(ParameterPrefixInName, true); - } - } -} DELETED SQLite.Designer/SR.Designer.cs Index: SQLite.Designer/SR.Designer.cs ================================================================== --- SQLite.Designer/SR.Designer.cs +++ /dev/null @@ -1,101 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50215.44 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -[assembly: global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Scope="member", Target="SQLite.Designer.SR.get_ResourceManager():System.Resources.ResourceManager")] -[assembly: global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Scope="member", Target="SQLite.Designer.SR.get_Culture():System.Globalization.CultureInfo")] -[assembly: global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Scope="member", Target="SQLite.Designer.SR.set_Culture(System.Globalization.CultureInfo):Void")] - -namespace SQLite.Designer { - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class SR { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal SR() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if ((resourceMan == null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SQLite.Designer.SR", typeof(SR).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to .NET Data Provider for SQLite. - /// - internal static string DataProvider_SQLite { - get { - return ResourceManager.GetString("DataProvider_SQLite", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Description of the SQLite Data Provider goes here. - /// - internal static string DataProvider_SQLite_Description { - get { - return ResourceManager.GetString("DataProvider_SQLite_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Service Provider string. - /// - internal static string DataProvider_SQLite_ServiceProvider { - get { - return ResourceManager.GetString("DataProvider_SQLite_ServiceProvider", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SQLite Database File. - /// - internal static string DataProvider_SQLite_Short { - get { - return ResourceManager.GetString("DataProvider_SQLite_Short", resourceCulture); - } - } - } -} DELETED SQLite.Designer/SR.resx Index: SQLite.Designer/SR.resx ================================================================== --- SQLite.Designer/SR.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - .NET Data Provider for SQLite - - - Description of the SQLite Data Provider goes here - - - Service Provider string - - - SQLite Database File - - DELETED SQLite.Interop/AssemblyInfo.cpp Index: SQLite.Interop/AssemblyInfo.cpp ================================================================== --- SQLite.Interop/AssemblyInfo.cpp +++ /dev/null @@ -1,71 +0,0 @@ -using namespace System::Reflection; -using namespace System::Runtime::CompilerServices; -using namespace System::Runtime::InteropServices; - -// -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -// -[assembly:AssemblyTitleAttribute("System.Data.SQLite")]; -[assembly:AssemblyDescriptionAttribute("http://sourceforge.net/projects/sqlite-dotnet2")]; -[assembly:AssemblyConfigurationAttribute("")]; -[assembly:AssemblyCompanyAttribute("")]; -[assembly:AssemblyProductAttribute("System.Data.SQLite")]; -[assembly:AssemblyCopyrightAttribute("Released to the public domain")]; -[assembly:AssemblyTrademarkAttribute("")]; -[assembly:AssemblyCultureAttribute("")]; - -// -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the value or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly:AssemblyVersionAttribute("1.0.17.0")]; -[assembly:AssemblyFileVersionAttribute("1.0.17.0")]; - -// -// In order to sign your assembly you must specify a key to use. Refer to the -// Microsoft CLR Framework documentation for more information on assembly signing. -// -// You can use the attributes below to control which key is used for signing. -// You can also use the project property page for signing under Common Properties -// to set the same information. -// -// Notes: -// (*) If no key is specified, the assembly is not signed. -// (*) KeyName refers to a key that has been installed in the Crypto Service -// Provider (CSP) on your machine. KeyFile refers to a file which contains -// a key. -// (*) If the KeyFile and the KeyName values are both specified, the -// following processing occurs: -// (1) If the KeyName can be found in the CSP, that key is used. -// (2) If the KeyName does not exist and the KeyFile does exist, the key -// in the KeyFile is installed into the CSP and used. -// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. -// When specifying the KeyFile, the location of the KeyFile should be -// relative to the project directory. -// (*) Delay Signing is an advanced option - see the Microsoft CLR Framework -// documentation for more information on this. -// -[assembly:AssemblyDelaySignAttribute(false)]; - -#ifdef _WIN64 -#ifdef _M_IA64 // Itanium -[assembly:AssemblyKeyFileAttribute("..\\System.Data.SQLite\\System.Data.SQLite.IA64.snk")]; -#else // AMD64 -[assembly:AssemblyKeyFileAttribute("..\\System.Data.SQLite\\System.Data.SQLite.X64.snk")]; -#endif -#else -[assembly:AssemblyKeyFileAttribute("..\\System.Data.SQLite\\System.Data.SQLite.snk")]; -#endif -[assembly:AssemblyKeyNameAttribute("")]; - -[assembly:ComVisible(false)]; - DELETED SQLite.Interop/SQLite.Interop.rc Index: SQLite.Interop/SQLite.Interop.rc ================================================================== --- SQLite.Interop/SQLite.Interop.rc +++ /dev/null @@ -1,102 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,24,5 - PRODUCTVERSION 1,0,0,0 - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "http://sourceforge.net/projects/sqlite-dotnet2" - VALUE "FileDescription", "SQLite.NET Interop Library" - VALUE "FileVersion", "1.0.24.5" - VALUE "InternalName", "SQLite.Interop.DLL" - VALUE "LegalCopyright", "Released to the public domain" - VALUE "OriginalFilename", "SQLite3.DLL 3.3.1 alpha" - VALUE "ProductName", "SQLite.NET" - VALUE "ProductVersion", "1.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - Index: SQLite.Interop/SQLite.Interop.vcproj ================================================================== --- SQLite.Interop/SQLite.Interop.vcproj +++ SQLite.Interop/SQLite.Interop.vcproj @@ -9,36 +9,23 @@ > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -735,18 +203,10 @@ > - - - - @@ -781,96 +241,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -879,78 +271,18 @@ > - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -983,14 +315,10 @@ > - - @@ -1003,33 +331,18 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > - - - - - - - - DELETED SQLite.Interop/crypt.c Index: SQLite.Interop/crypt.c ================================================================== --- SQLite.Interop/crypt.c +++ /dev/null @@ -1,396 +0,0 @@ -#ifdef SQLITE_HAS_CODEC - void sqlite3pager_free_codecarg(void *pArg); -#endif - -#include "src/pager.c" - -#ifndef SQLITE_OMIT_DISKIO -#ifdef SQLITE_HAS_CODEC - -#include -#include - -typedef struct _CRYPTBLOCK -{ - HCRYPTKEY hReadKey; // Key used to read from the database and write to the journal - HCRYPTKEY hWriteKey; // Key used to write to the database - DWORD dwPageSize; // Size of pages - LPVOID pvCrypt; // A buffer for encrypting/decrypting (if necessary) - DWORD dwCryptSize; // Equal to or greater than dwPageSize. If larger, pvCrypt is valid and this is its size -} CRYPTBLOCK, *LPCRYPTBLOCK; - -HCRYPTPROV g_hProvider = 0; // Global instance of the cryptographic provider - -#define SQLITECRYPTERROR_PROVIDER "Cryptographic provider not available" - -// Needed for re-keying -static void * sqlite3pager_get_codecarg(Pager *pPager) -{ - return (pPager->xCodec) ? pPager->pCodecArg: NULL; -} - -// Create a cryptographic context. Use the enhanced provider because it is available on -// most platforms -static BOOL InitializeProvider() -{ - if (g_hProvider) return TRUE; - - if (!CryptAcquireContext(&g_hProvider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0)) - { - if(!CryptAcquireContext(&g_hProvider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) - { - return FALSE; - } - } - return TRUE; -} - -// Create or update a cryptographic context for a pager. -// This function will automatically determine if the encryption algorithm requires -// extra padding, and if it does, will create a temp buffer big enough to provide -// space to hold it. -static LPCRYPTBLOCK CreateCryptBlock(HCRYPTKEY hKey, Pager *pager, LPCRYPTBLOCK pExisting) -{ - LPCRYPTBLOCK pBlock; - - if (!pExisting) // Creating a new cryptblock - { - pBlock = malloc(sizeof(CRYPTBLOCK)); - ZeroMemory(pBlock, sizeof(CRYPTBLOCK)); - pBlock->hReadKey = hKey; - pBlock->hWriteKey = hKey; - } - else // Updating an existing cryptblock - { - pBlock = pExisting; - } - - pBlock->dwPageSize = (DWORD)pager->pageSize; - pBlock->dwCryptSize = pBlock->dwPageSize; - - // Existing cryptblocks may have a buffer, if so, delete it - if (pBlock->pvCrypt) - { - free(pBlock->pvCrypt); - pBlock->pvCrypt = NULL; - } - - // Figure out if this cryptographic key requires extra buffer space, and if so, allocate - // enough room for it - if (CryptEncrypt(hKey, 0, TRUE, 0, NULL, &pBlock->dwCryptSize, pBlock->dwCryptSize * 2)) - { - if (pBlock->dwCryptSize > pBlock->dwPageSize) - { - pBlock->pvCrypt = malloc(pBlock->dwCryptSize); - } - } - return pBlock; -} - -// Destroy a cryptographic context and any buffers and keys allocated therein -static void DestroyCryptBlock(LPCRYPTBLOCK pBlock) -{ - // Destroy the read key if there is one - if (pBlock->hReadKey) - { - CryptDestroyKey(pBlock->hReadKey); - } - - // If there's a writekey and its not equal to the readkey, destroy it - if (pBlock->hWriteKey && pBlock->hWriteKey != pBlock->hReadKey) - { - CryptDestroyKey(pBlock->hWriteKey); - } - - // If there's extra buffer space allocated, free it as well - if (pBlock->pvCrypt) - { - free(pBlock->pvCrypt); - } - - // All done with this cryptblock - free(pBlock); -} - -// Encrypt/Decrypt functionality, called by pager.c -void sqlite3Codec(void *pArg, void *data, Pgno nPageNum, int nMode) -{ - LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)pArg; - DWORD dwPageSize; - LPVOID pvTemp; - - if (!pBlock) return; - - // Make sure the page size for the pager is still the same as the page size - // for the cryptblock. If the user changed it, we need to adjust! - if (nMode != 2) - { - PgHdr *pageHeader; - pageHeader = DATA_TO_PGHDR(data); - if (pageHeader->pPager->pageSize != pBlock->dwPageSize) - { - // Update the cryptblock to reflect the new page size - CreateCryptBlock(0, pageHeader->pPager, pBlock); - } - } - - /* Block ciphers often need to write extra padding beyond the - data block. We don't have that luxury for a given page of data so - we must copy the page data to a buffer that IS large enough to hold - the padding. We then encrypt the block and write the buffer back to - the page without the unnecessary padding. - We only use the special block of memory if its absolutely necessary. */ - if (pBlock->pvCrypt) - { - CopyMemory(pBlock->pvCrypt, data, pBlock->dwPageSize); - pvTemp = data; - data = pBlock->pvCrypt; - } - - switch(nMode) - { - case 0: // Undo a "case 7" journal file encryption - case 2: // Reload a page - case 3: // Load a page - if (!pBlock->hReadKey) break; - dwPageSize = pBlock->dwCryptSize; - CryptDecrypt(pBlock->hReadKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize); - break; - case 6: // Encrypt a page for the main database file - if (!pBlock->hWriteKey) break; - dwPageSize = pBlock->dwPageSize; - CryptEncrypt(pBlock->hWriteKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize, pBlock->dwCryptSize); - break; - case 7: // Encrypt a page for the journal file - /* Under normal circumstances, the readkey is the same as the writekey. However, - when the database is being rekeyed, the readkey is not the same as the writekey. - The rollback journal must be written using the original key for the - database file because it is, by nature, a rollback journal. - Therefore, for case 7, when the rollback is being written, always encrypt using - the database's readkey, which is guaranteed to be the same key that was used to - read the original data. - */ - if (!pBlock->hReadKey) break; - dwPageSize = pBlock->dwPageSize; - CryptEncrypt(pBlock->hReadKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize, pBlock->dwCryptSize); - break; - } - - // If the encryption algorithm required extra padding and we were forced to encrypt or - // decrypt a copy of the page data to a temp buffer, then write the contents of the temp - // buffer back to the page data minus any padding applied. - if (pBlock->pvCrypt) - { - CopyMemory(pvTemp, data, pBlock->dwPageSize); - } -} - -// Derive an encryption key from a user-supplied buffer -static HCRYPTKEY DeriveKey(const void *pKey, int nKeyLen) -{ - HCRYPTHASH hHash = 0; - HCRYPTKEY hKey; - - if (!pKey || !nKeyLen) return 0; - - if (!InitializeProvider()) - { - return MAXDWORD; - } - - if (CryptCreateHash(g_hProvider, CALG_SHA1, 0, 0, &hHash)) - { - if (CryptHashData(hHash, (LPBYTE)pKey, nKeyLen, 0)) - { - CryptDeriveKey(g_hProvider, CALG_RC4, hHash, 0, &hKey); - } - CryptDestroyHash(hHash); - } - return hKey; -} - -// Called by sqlite and sqlite3_key_interop to attach a key to a database. -int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen) -{ - int rc = SQLITE_ERROR; - HCRYPTKEY hKey = 0; - - // No key specified, could mean either use the main db's encryption or no encryption - if (!pKey || !nKeyLen) - { - if (!nDb) - { - return SQLITE_OK; // Main database, no key specified so not encrypted - } - else // Attached database, use the main database's key - { - // Get the encryption block for the main database and attempt to duplicate the key - // for use by the attached database - LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)sqlite3pager_get_codecarg(sqlite3BtreePager(db->aDb[0].pBt)); - - if (!pBlock) return SQLITE_OK; // Main database is not encrypted so neither will be any attached database - if (!pBlock->hReadKey) return SQLITE_OK; // Not encrypted - - if (!CryptDuplicateKey(pBlock->hReadKey, NULL, 0, &hKey)) - return rc; // Unable to duplicate the key - } - } - else // User-supplied passphrase, so create a cryptographic key out of it - { - hKey = DeriveKey(pKey, nKeyLen); - if (hKey == MAXDWORD) - { - sqlite3Error(db, rc, SQLITECRYPTERROR_PROVIDER); - return rc; - } - } - - // Create a new encryption block and assign the codec to the new attached database - if (hKey) - { - LPCRYPTBLOCK pBlock = CreateCryptBlock(hKey, sqlite3BtreePager(db->aDb[nDb].pBt), NULL); - sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, pBlock); - rc = SQLITE_OK; - } - return rc; -} - -void sqlite3pager_free_codecarg(void *pArg) -{ - LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)pArg; - - if (pBlock) - { - if (pBlock->hReadKey) - CryptDestroyKey(pBlock->hReadKey); - if (pBlock->hWriteKey) - CryptDestroyKey(pBlock->hWriteKey); - - if (pBlock->pvCrypt) - free(pBlock->pvCrypt); - } - free(pBlock); -} - -// Once a password has been supplied and a key created, we don't keep the -// original password for security purposes. Therefore return NULL. -void sqlite3CodecGetKey(sqlite3 *db, int nDb, void **ppKey, int *pnKeyLen) -{ - *ppKey = NULL; - *pnKeyLen = 0; -} - -// We do not attach this key to the temp store, only the main database. -__declspec(dllexport) int __stdcall sqlite3_key_interop(sqlite3 *db, const void *pKey, int nKeySize) -{ - return sqlite3CodecAttach(db, 0, pKey, nKeySize); -} - -// Changes the encryption key for an existing database. -__declspec(dllexport) int __stdcall sqlite3_rekey_interop(sqlite3 *db, const void *pKey, int nKeySize) -{ - Btree *pbt = db->aDb[0].pBt; - Pager *p = sqlite3BtreePager(pbt); - LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)sqlite3pager_get_codecarg(p); - HCRYPTKEY hKey = DeriveKey(pKey, nKeySize); - int rc = SQLITE_ERROR; - - if (hKey == MAXDWORD) - { - sqlite3Error(db, rc, SQLITECRYPTERROR_PROVIDER); - return rc; - } - - if (!pBlock && !hKey) return SQLITE_OK; // Wasn't encrypted to begin with - - // To rekey a database, we change the writekey for the pager. The readkey remains - // the same - if (!pBlock) // Encrypt an unencrypted database - { - pBlock = CreateCryptBlock(hKey, p, NULL); - pBlock->hReadKey = 0; // Original database is not encrypted - sqlite3pager_set_codec(sqlite3BtreePager(pbt), sqlite3Codec, pBlock); - } - else // Change the writekey for an already-encrypted database - { - pBlock->hWriteKey = hKey; - } - - // Start a transaction - rc = sqlite3BtreeBeginTrans(pbt, 1); - - if (!rc) - { - // Rewrite all the pages in the database using the new encryption key - int nPage = sqlite3pager_pagecount(p); - void *pPage; - int n; - - for(n = 1; rc == SQLITE_OK && n <= nPage; n ++) - { - rc = sqlite3pager_get(p, n, &pPage); - if(!rc) - { - rc = sqlite3pager_write(pPage); - sqlite3pager_unref(pPage); - } - } - } - - // If we succeeded, try and commit the transaction - if (!rc) - { - rc = sqlite3BtreeCommit(pbt); - } - - // If we failed, rollback - if (rc) - { - sqlite3BtreeRollback(pbt); - } - - // If we succeeded, destroy any previous read key this database used - // and make the readkey equal to the writekey - if (!rc) - { - if (pBlock->hReadKey) - { - CryptDestroyKey(pBlock->hReadKey); - } - pBlock->hReadKey = pBlock->hWriteKey; - } - // We failed. Destroy the new writekey (if there was one) and revert it back to - // the original readkey - else - { - if (pBlock->hWriteKey) - { - CryptDestroyKey(pBlock->hWriteKey); - } - pBlock->hWriteKey = pBlock->hReadKey; - } - - // If the readkey and writekey are both empty, there's no need for a codec on this - // pager anymore. Destroy the crypt block and remove the codec from the pager. - if (!pBlock->hReadKey && !pBlock->hWriteKey) - { - sqlite3pager_set_codec(p, NULL, NULL); - DestroyCryptBlock(pBlock); - } - - return rc; -} - -int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) -{ - return sqlite3_key_interop(db, pKey, nKey); -} - -int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) -{ - return sqlite3_rekey_interop(db, pKey, nKey); -} - -#endif // SQLITE_HAS_CODEC - -#endif // SQLITE_OMIT_DISKIO DELETED SQLite.Interop/fixsource.vbs Index: SQLite.Interop/fixsource.vbs ================================================================== --- SQLite.Interop/fixsource.vbs +++ /dev/null @@ -1,60 +0,0 @@ -' VBScript source code -Main - -Sub Main() - Dim WshShell - Set WshShell = WScript.CreateObject("WScript.Shell") - - Dim fso - Set fso = WScript.CreateObject("Scripting.FileSystemObject") - - Dim srcFile - Dim srcFileContents - dim newFileContents - - ' Changes the name of the function so we can get first crack at it in interop.h to provide GetSchemaTable() support - ' - Set srcFile = fso.OpenTextFile("src\select.c", 1) - srcFileContents = srcFile.ReadAll() - srcFile.Close() - newFileContents = Replace(srcFileContents, "static void generateColumnNames(", "static void _generateColumnNames(") - If (newFileContents <> srcFileContents) Then - WScript.StdOut.WriteLine "Updating select.c" - Set srcFile = fso.CreateTextFile("src\select.c", true) - srcFile.Write(newFileContents) - srcFile.Close() - End If - - ' SQLite supports : and $ for named parameters, but we add support for @ as well here - ' - Set srcFile = fso.OpenTextFile("src\tokenize.c", 1) - srcFileContents = srcFile.ReadAll() - srcFile.Close() - If InStr(1, srcFileContents, " case '@':", 1) = 0 Then - newFileContents = Replace(srcFileContents, " case ':': {", " case '@':" & Chr(10) & " case ':': {") - If (newFileContents <> srcFileContents) Then - WScript.StdOut.WriteLine "Updating tokenize.c" - Set srcFile = fso.CreateTextFile("src\tokenize.c", true) - srcFile.Write(newFileContents) - srcFile.Close() - End If - End If - - ' In order to support encryption, we need to know when the pager is being destroyed so we can destroy our encryption - ' objects. This modification adds code to support that. - ' - Set srcFile = fso.OpenTextFile("src\pager.c", 1) - srcFileContents = srcFile.ReadAll() - srcFile.Close() - If InStr(1, srcFileContents, "sqlite3pager_free_codecarg", 1) = 0 Then - newFileContents = Replace(srcFileContents, Chr(10) & " sqliteFree(pPager);", Chr(10) & "#ifdef SQLITE_HAS_CODEC" & Chr(10) & " sqlite3pager_free_codecarg(pPager->pCodecArg);" & Chr(10) & "#endif" & Chr(10) & " sqliteFree(pPager);") - If (newFileContents <> srcFileContents) Then - WScript.StdOut.WriteLine "Updating pager.c" - Set srcFile = fso.CreateTextFile("src\pager.c", true) - srcFile.Write(newFileContents) - srcFile.Close() - End If - End If - -End Sub - DELETED SQLite.Interop/interop.c Index: SQLite.Interop/interop.c ================================================================== --- SQLite.Interop/interop.c +++ /dev/null @@ -1,768 +0,0 @@ -/* - This interop file must be included at or near the top of the select.c file of the SQLite3 source distribution. - - generateColumnNames() in the select.c must be renamed to _generateColumnNames - -*/ - -#include "src/sqliteint.h" -#include "src\os.h" - -#if _WIN32_WCE && NDEBUG -#include "merge.h" -#endif - -// Forward declare this function, we're implementing it later -static void generateColumnNames( - Parse *pParse, /* Parser context */ - SrcList *pTabList, /* List of tables */ - ExprList *pEList /* Expressions defining the result set */ -); - -#include "src\select.c" - -/* -** Generate code that will tell the VDBE the names of columns -** in the result set. This information is used to provide the -** azCol[] values in the callback. -*/ -static void generateColumnNames( - Parse *pParse, /* Parser context */ - SrcList *pTabList, /* List of tables */ - ExprList *pEList /* Expressions defining the result set */ -){ - Vdbe *v = pParse->pVdbe; - int i, j; - sqlite3 *db = pParse->db; - int fullNames, shortNames; - int realNames; /*** ADDED - SQLite.Interop ***/ - - realNames = (db->flags & 0x01000000)!=0; /*** ADDED - SQLite.Interop ***/ - if (!realNames) // Default to normal Sqlite3 /*** ADDED - SQLite.Interop ***/ - { /*** ADDED - SQLite.Interop ***/ - _generateColumnNames(pParse, pTabList, pEList); /*** ADDED - SQLite.Interop ***/ - return; /*** ADDED - SQLite.Interop ***/ - } /*** ADDED - SQLite.Interop ***/ - -#ifndef SQLITE_OMIT_EXPLAIN - /* If this is an EXPLAIN, skip this step */ - if( pParse->explain ){ - return; - } -#endif - - assert( v!=0 ); - if( pParse->colNamesSet || v==0 || sqlite3ThreadData()->mallocFailed ) return; - pParse->colNamesSet = 1; - fullNames = (db->flags & SQLITE_FullColNames)!=0; - shortNames = (db->flags & SQLITE_ShortColNames)!=0; - if (realNames) fullNames = 1; /*** ADDED - SQLite.Interop ***/ - - sqlite3VdbeSetNumCols(v, pEList->nExpr); - for(i=0; inExpr; i++){ - Expr *p; - p = pEList->a[i].pExpr; - if( p==0 ) continue; - if( pEList->a[i].zName && (realNames == 0 || p->op != TK_COLUMN)){ /*** CHANGED - SQLite.Interop ***/ - char *zName = pEList->a[i].zName; - sqlite3VdbeSetColName(v, i, zName, strlen(zName)); - continue; - } - if( p->op==TK_COLUMN && pTabList ){ - Table *pTab; - char *zCol; - int iCol = p->iColumn; - for(j=0; jnSrc && pTabList->a[j].iCursor!=p->iTable; j++){} - assert( jnSrc ); - pTab = pTabList->a[j].pTab; - if( iCol<0 ) iCol = pTab->iPKey; - assert( iCol==-1 || (iCol>=0 && iColnCol) ); - if( iCol<0 ){ - zCol = "rowid"; - }else{ - zCol = pTab->aCol[iCol].zName; - } - if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); - }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ - char *zName = 0; - char *zTab; - char *zDb = 0; /*** ADDED - SQLite.Interop ***/ - int iDb; - - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - - zTab = pTabList->a[j].zAlias; - if( fullNames || zTab==0 ){ - if (iDb > 1) zDb = db->aDb[iDb].zName; /*** ADDED - SQLite.Interop ***/ - zTab = pTab->zName; - } - if (!zDb || !realNames) sqlite3SetString(&zName, zTab, "\x01", zCol, 0); /*** CHANGED - SQLite.Interop ***/ - else sqlite3SetString(&zName, zDb, "\x01", zTab, "\x01", zCol, 0); /*** ADDED - SQLite.Interop ***/ - sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC); - }else{ - sqlite3VdbeSetColName(v, i, zCol, strlen(zCol)); - } - }else if( p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); - /* sqlite3VdbeCompressSpace(v, addr); */ - }else{ - char zName[30]; - assert( p->op!=TK_COLUMN || pTabList==0 ); - sprintf(zName, "column%d", i+1); - sqlite3VdbeSetColName(v, i, zName, 0); - } - } - generateColumnTypes(pParse, pTabList, pEList); -} - -#ifdef OS_WIN - -#include - -typedef void (__stdcall *SQLITEUSERFUNC)(void *, int, void **); -typedef int (__stdcall *SQLITECOLLATION)(int, const void *, int, const void*); - -typedef int (__stdcall *ENCRYPTFILEW)(const wchar_t *); -typedef int (__stdcall *ENCRYPTEDSTATUSW)(const wchar_t *, unsigned long *); -typedef int (__stdcall *DECRYPTFILEW)(const wchar_t *, unsigned long); - -typedef HANDLE (__stdcall *CREATEFILEW)( - LPCWSTR, - DWORD, - DWORD, - LPSECURITY_ATTRIBUTES, - DWORD, - DWORD, - HANDLE); - -// Callback wrappers -int sqlite3_interop_collationfunc(void *pv, int len1, const void *pv1, int len2, const void *pv2) -{ - SQLITECOLLATION *p = (SQLITECOLLATION *)pv; - return p[0](len1, pv1, len2, pv2); -} - -void sqlite3_interop_func(sqlite3_context *pctx, int n, sqlite3_value **pv) -{ - SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); - pf[0](pctx, n, (void **)pv); -} - -void sqlite3_interop_step(sqlite3_context *pctx, int n, sqlite3_value **pv) -{ - SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); - pf[1](pctx, n, (void **)pv); -} - -void sqlite3_interop_final(sqlite3_context *pctx) -{ - SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); - pf[2](pctx, 0, 0); -} - -__declspec(dllexport) void __stdcall sqlite3_sleep_interop(int milliseconds) -{ - Sleep(milliseconds); -} - -__declspec(dllexport) int sqlite3_encryptfile(const wchar_t *pwszFilename) -{ - HMODULE hMod = LoadLibrary(_T("ADVAPI32")); - ENCRYPTFILEW pfunc; - int n; - - if (hMod == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - pfunc = (ENCRYPTFILEW)GetProcAddress(hMod, _T("EncryptFileW")); - if (pfunc == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - n = pfunc(pwszFilename); - - FreeLibrary(hMod); - - return n; -} - -__declspec(dllexport) int sqlite3_decryptfile(const wchar_t *pwszFilename) -{ - HMODULE hMod = LoadLibrary(_T("ADVAPI32")); - DECRYPTFILEW pfunc; - int n; - - if (hMod == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - pfunc = (DECRYPTFILEW)GetProcAddress(hMod, _T("DecryptFileW")); - if (pfunc == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - n = pfunc(pwszFilename, 0); - - FreeLibrary(hMod); - - return n; -} - -__declspec(dllexport) unsigned long sqlite3_encryptedstatus(const wchar_t *pwszFilename, unsigned long *pdwStatus) -{ - HMODULE hMod = LoadLibrary(_T("ADVAPI32")); - ENCRYPTEDSTATUSW pfunc; - int n; - - if (hMod == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - pfunc = (ENCRYPTEDSTATUSW)GetProcAddress(hMod, _T("FileEncryptionStatusW")); - if (pfunc == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - n = pfunc(pwszFilename, pdwStatus); - - FreeLibrary(hMod); - - return n; -} - -int SetCompression(const wchar_t *pwszFilename, unsigned short ufLevel) -{ -#ifdef FSCTL_SET_COMPRESSION - HMODULE hMod = GetModuleHandle(_T("KERNEL32")); - CREATEFILEW pfunc; - HANDLE hFile; - unsigned long dw = 0; - int n; - - if (hMod == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - pfunc = (CREATEFILEW)GetProcAddress(hMod, _T("CreateFileW")); - if (pfunc == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - hFile = pfunc(pwszFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == NULL) - return 0; - - n = DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, &ufLevel, sizeof(ufLevel), NULL, 0, &dw, NULL); - - CloseHandle(hFile); - - return n; -#else - SetLastError(ERROR_NOT_SUPPORTED); - return 0; -#endif -} - -__declspec(dllexport) int __stdcall sqlite3_compressfile(const wchar_t *pwszFilename) -{ - return SetCompression(pwszFilename, COMPRESSION_FORMAT_DEFAULT); -} - -__declspec(dllexport) int __stdcall sqlite3_decompressfile(const wchar_t *pwszFilename) -{ - return SetCompression(pwszFilename, COMPRESSION_FORMAT_NONE); -} - -__declspec(dllexport) void __stdcall sqlite3_function_free_callbackcookie(void *pCookie) -{ - if (pCookie) - free(pCookie); -} - -// sqlite3 wrappers -__declspec(dllexport) const char * __stdcall sqlite3_libversion_interop(int *plen) -{ - const char *val = sqlite3_libversion(); - *plen = (val != 0) ? strlen(val) : 0; - - return val; -} - -__declspec(dllexport) int __stdcall sqlite3_libversion_number_interop(void) -{ - return sqlite3_libversion_number(); -} - -__declspec(dllexport) int __stdcall sqlite3_close_interop(sqlite3 *db) -{ - return sqlite3_close(db); -} - -__declspec(dllexport) int __stdcall sqlite3_exec_interop(sqlite3 *db, const char *sql, sqlite3_callback cb, void *pv, char **errmsg, int *plen) -{ - int n = sqlite3_exec(db, sql, cb, pv, errmsg); - *plen = (*errmsg != 0) ? strlen(*errmsg) : 0; - return n; -} - -__declspec(dllexport) sqlite_int64 __stdcall sqlite3_last_insert_rowid_interop(sqlite3 *db) -{ - return sqlite3_last_insert_rowid(db); -} - -__declspec(dllexport) int __stdcall sqlite3_changes_interop(sqlite3 *db) -{ - return sqlite3_changes(db); -} - -__declspec(dllexport) int __stdcall sqlite3_total_changes_interop(sqlite3 *db) -{ - return sqlite3_total_changes(db); -} - -__declspec(dllexport) void __stdcall sqlite3_interrupt_interop(sqlite3 *db) -{ - sqlite3_interrupt(db); -} - -__declspec(dllexport) int __stdcall sqlite3_complete_interop(const char *sql) -{ - return sqlite3_complete(sql); -} - -__declspec(dllexport) int __stdcall sqlite3_complete16_interop(const void *sql) -{ - return sqlite3_complete16(sql); -} - -__declspec(dllexport) int __stdcall sqlite3_busy_handler_interop(sqlite3 *db, int(*cb)(void *, int), void *pv) -{ - return sqlite3_busy_handler(db, cb, pv); -} - -__declspec(dllexport) int __stdcall sqlite3_busy_timeout_interop(sqlite3 *db, int ms) -{ - return sqlite3_busy_timeout(db, ms); -} - -__declspec(dllexport) int __stdcall sqlite3_get_table_interop(sqlite3 *db, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg, int *plen) -{ - int n = sqlite3_get_table(db, sql, resultp, nrow, ncolumn, errmsg); - *plen = (*errmsg != 0) ? strlen((char *)*errmsg) : 0; - return n; -} - -__declspec(dllexport) void __stdcall sqlite3_free_table_interop(char **result) -{ - sqlite3_free_table(result); -} - -__declspec(dllexport) void __stdcall sqlite3_free_interop(char *z) -{ - sqlite3_free(z); -} - -__declspec(dllexport) int __stdcall sqlite3_open_interop(const char*filename, sqlite3 **ppdb) -{ - return sqlite3_open(filename, ppdb); -} - -__declspec(dllexport) int __stdcall sqlite3_open16_interop(const void *filename, sqlite3 **ppdb) -{ - return sqlite3_open16(filename, ppdb); -} - -__declspec(dllexport) int __stdcall sqlite3_errcode_interop(sqlite3 *db) -{ - return sqlite3_errcode(db); -} - -__declspec(dllexport) const char * __stdcall sqlite3_errmsg_interop(sqlite3 *db, int *plen) -{ - const char *pval = sqlite3_errmsg(db); - *plen = (pval != 0) ? strlen(pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_errmsg16_interop(sqlite3 *db, int *plen) -{ - const void *pval = sqlite3_errmsg16(db); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_prepare_interop(sqlite3 *db, const char *sql, int nbytes, sqlite3_stmt **ppstmt, const char **pztail, int *plen) -{ - int n = sqlite3_prepare(db, sql, nbytes, ppstmt, pztail); - *plen = (*pztail != 0) ? strlen(*pztail) : 0; - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_prepare16_interop(sqlite3 *db, const void *sql, int nchars, sqlite3_stmt **ppstmt, const void **pztail, int *plen) -{ - int n = sqlite3_prepare16(db, sql, nchars * sizeof(wchar_t), ppstmt, pztail); - *plen = (*pztail != 0) ? wcslen((wchar_t *)*pztail) * sizeof(wchar_t) : 0; - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_bind_blob_interop(sqlite3_stmt *stmt, int iCol, const void *pv, int n, void(*cb)(void*)) -{ - return sqlite3_bind_blob(stmt, iCol, pv, n, cb); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_double_interop(sqlite3_stmt *stmt, int iCol, double *val) -{ - return sqlite3_bind_double(stmt,iCol,*val); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_int_interop(sqlite3_stmt *stmt, int iCol, int val) -{ - return sqlite3_bind_int(stmt, iCol, val); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val) -{ - return sqlite3_bind_int64(stmt,iCol,*val); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_null_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_bind_null(stmt, iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_text_interop(sqlite3_stmt *stmt, int iCol, const char *val, int n, void(*cb)(void *)) -{ - return sqlite3_bind_text(stmt, iCol, val, n, cb); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_text16_interop(sqlite3_stmt *stmt, int iCol, const void *val, int n, void(*cb)(void *)) -{ - return sqlite3_bind_text16(stmt, iCol, val, n, cb); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_parameter_count_interop(sqlite3_stmt *stmt) -{ - return sqlite3_bind_parameter_count(stmt); -} - -__declspec(dllexport) const char * __stdcall sqlite3_bind_parameter_name_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const char *pval = sqlite3_bind_parameter_name(stmt, iCol); - *plen = (pval != 0) ? strlen(pval) : 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_bind_parameter_index_interop(sqlite3_stmt *stmt, const char *zName) -{ - return sqlite3_bind_parameter_index(stmt, zName); -} - -__declspec(dllexport) int __stdcall sqlite3_column_count_interop(sqlite3_stmt *stmt) -{ - return sqlite3_column_count(stmt); -} - -__declspec(dllexport) const char * __stdcall sqlite3_column_name_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const char *pval = sqlite3_column_name(stmt, iCol); - *plen = (pval != 0) ? strlen(pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_column_name16_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const void *pval = sqlite3_column_name16(stmt, iCol); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; - return pval; -} - -__declspec(dllexport) const char * __stdcall sqlite3_column_decltype_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const char *pval = sqlite3_column_decltype(stmt, iCol); - *plen = (pval != 0) ? strlen(pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_column_decltype16_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const void *pval = sqlite3_column_decltype16(stmt, iCol); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_step_interop(sqlite3_stmt *stmt) -{ - return sqlite3_step(stmt); -} - -__declspec(dllexport) int __stdcall sqlite3_data_count_interop(sqlite3_stmt *stmt) -{ - return sqlite3_data_count(stmt); -} - -__declspec(dllexport) const void * __stdcall sqlite3_column_blob_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_blob(stmt, iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_column_bytes_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_bytes(stmt, iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_column_bytes16_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_bytes16(stmt, iCol); -} - -__declspec(dllexport) void __stdcall sqlite3_column_double_interop(sqlite3_stmt *stmt, int iCol, double *val) -{ - *val = sqlite3_column_double(stmt,iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_column_int_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_int(stmt, iCol); -} - -__declspec(dllexport) void __stdcall sqlite3_column_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val) -{ - *val = sqlite3_column_int64(stmt,iCol); -} - -__declspec(dllexport) const unsigned char * __stdcall sqlite3_column_text_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const unsigned char *pval = sqlite3_column_text(stmt, iCol); - *plen = (pval != 0) ? strlen((char *)pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_column_text16_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const void *pval = sqlite3_column_text16(stmt, iCol); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_column_type_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_type(stmt, iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_finalize_interop(sqlite3_stmt *stmt) -{ - return sqlite3_finalize(stmt); -} - -__declspec(dllexport) int __stdcall sqlite3_reset_interop(sqlite3_stmt *stmt) -{ - return sqlite3_reset(stmt); -} - -__declspec(dllexport) int __stdcall sqlite3_create_function_interop(sqlite3 *psql, const char *zFunctionName, int nArg, int eTextRep, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEUSERFUNC funcfinal, void **ppCookie) -{ - int n; - SQLITEUSERFUNC *p = (SQLITEUSERFUNC *)malloc(sizeof(SQLITEUSERFUNC) * 3); - - p[0] = func; - p[1] = funcstep; - p[2] = funcfinal; - - *ppCookie = 0; - - n = sqlite3_create_function(psql, zFunctionName, nArg, eTextRep, p, (func != 0) ? sqlite3_interop_func : 0, (funcstep != 0) ? sqlite3_interop_step : 0, (funcfinal != 0) ? sqlite3_interop_final : 0); - if (n != 0) - free(p); - else - *ppCookie = p; - - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_create_function16_interop(sqlite3 *psql, void *zFunctionName, int nArg, int eTextRep, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEUSERFUNC funcfinal, void **ppCookie) -{ - int n; - SQLITEUSERFUNC *p = (SQLITEUSERFUNC *)malloc(sizeof(SQLITEUSERFUNC) * 3); - - p[0] = func; - p[1] = funcstep; - p[2] = funcfinal; - - *ppCookie = 0; - - n = sqlite3_create_function16(psql, zFunctionName, nArg, eTextRep, p, (func != 0) ? sqlite3_interop_func : 0, (funcstep != 0) ? sqlite3_interop_step : 0, (funcfinal != 0) ? sqlite3_interop_final : 0); - if (n != 0) - free(p); - else - *ppCookie = p; - - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_create_collation_interop(sqlite3* db, const char *zName, int eTextRep, void* pvUser, SQLITECOLLATION func, void **ppCookie) -{ - int n; - SQLITECOLLATION *p = (SQLITECOLLATION *)malloc(sizeof(SQLITECOLLATION)); - - p[0] = func; - - *ppCookie = 0; - - n = sqlite3_create_collation(db, zName, eTextRep, p, sqlite3_interop_collationfunc); - if (n != 0) - free(p); - else - *ppCookie = p; - - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_create_collation16_interop(sqlite3* db, const void *zName, int eTextRep, void* pvUser, SQLITECOLLATION func, void **ppCookie) -{ - int n; - SQLITECOLLATION *p = (SQLITECOLLATION *)malloc(sizeof(SQLITECOLLATION)); - - p[0] = func; - - *ppCookie = 0; - - n = sqlite3_create_collation16(db, (const char *)zName, eTextRep, p, sqlite3_interop_collationfunc); - if (n != 0) - free(p); - else - *ppCookie = p; - - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_aggregate_count_interop(sqlite3_context *pctx) -{ - return sqlite3_aggregate_count(pctx); -} - -__declspec(dllexport) const void * __stdcall sqlite3_value_blob_interop(sqlite3_value *val) -{ - return sqlite3_value_blob(val); -} - -__declspec(dllexport) int __stdcall sqlite3_value_bytes_interop(sqlite3_value *val) -{ - return sqlite3_value_bytes(val); -} - -__declspec(dllexport) int __stdcall sqlite3_value_bytes16_interop(sqlite3_value *val) -{ - return sqlite3_value_bytes16(val); -} - -__declspec(dllexport) void __stdcall sqlite3_value_double_interop(sqlite3_value *pval, double *val) -{ - *val = sqlite3_value_double(pval); -} - -__declspec(dllexport) int __stdcall sqlite3_value_int_interop(sqlite3_value *val) -{ - return sqlite3_value_int(val); -} - -__declspec(dllexport) void __stdcall sqlite3_value_int64_interop(sqlite3_value *pval, sqlite_int64 *val) -{ - *val = sqlite3_value_int64(pval); -} - -__declspec(dllexport) const unsigned char * __stdcall sqlite3_value_text_interop(sqlite3_value *val, int *plen) -{ - const unsigned char *pval = sqlite3_value_text(val); - *plen = (pval != 0) ? strlen((char *)pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_value_text16_interop(sqlite3_value *val, int *plen) -{ - const void *pval = sqlite3_value_text16(val); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_value_type_interop(sqlite3_value *val) -{ - return sqlite3_value_type(val); -} - -__declspec(dllexport) void * __stdcall sqlite3_aggregate_context_interop(sqlite3_context *pctx, int n) -{ - return sqlite3_aggregate_context(pctx, n); -} - -__declspec(dllexport) void __stdcall sqlite3_result_blob_interop(sqlite3_context *ctx, const void *pv, int n, void(*cb)(void *)) -{ - sqlite3_result_blob(ctx, pv, n, cb); -} - -__declspec(dllexport) void __stdcall sqlite3_result_double_interop(sqlite3_context *pctx, double *val) -{ - sqlite3_result_double(pctx, *val); -} - -__declspec(dllexport) void __stdcall sqlite3_result_int_interop(sqlite3_context *pctx, int val) -{ - sqlite3_result_int(pctx, val); -} - -__declspec(dllexport) void __stdcall sqlite3_result_int64_interop(sqlite3_context *pctx, sqlite_int64 *val) -{ - sqlite3_result_int64(pctx, *val); -} - -__declspec(dllexport) void __stdcall sqlite3_result_null_interop(sqlite3_context *pctx) -{ - sqlite3_result_null(pctx); -} - -__declspec(dllexport) void __stdcall sqlite3_result_error_interop(sqlite3_context *ctx, const char *pv, int n) -{ - sqlite3_result_error(ctx, pv, n); -} - -__declspec(dllexport) void __stdcall sqlite3_result_error16_interop(sqlite3_context *ctx, const void *pv, int n) -{ - sqlite3_result_error16(ctx, pv, n); -} - -__declspec(dllexport) void __stdcall sqlite3_result_text_interop(sqlite3_context *ctx, const char *pv, int n, void(*cb)(void *)) -{ - sqlite3_result_text(ctx, pv, n, cb); -} - -__declspec(dllexport) void __stdcall sqlite3_result_text16_interop(sqlite3_context *ctx, const void *pv, int n, void(*cb)(void *)) -{ - sqlite3_result_text16(ctx, pv, n, cb); -} - -__declspec(dllexport) void __stdcall sqlite3_realcolnames(sqlite3 *db, int bOn) -{ - if (bOn) - db->flags |= 0x01000000; - else - db->flags &= (~0x01000000); -} - -#endif // OS_WIN ADDED SQLite.Interop/interop.h Index: SQLite.Interop/interop.h ================================================================== --- /dev/null +++ SQLite.Interop/interop.h @@ -0,0 +1,606 @@ +/* + This interop file must be included at or near the top of the select.c file of the SQLite3 source distribution. + + generateColumnNames() in the select.c must be renamed to _generateColumnNames + +*/ +#include "os.h" +#include "sqliteint.h" + +static void generateColumnTypes( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* List of tables */ + ExprList *pEList /* Expressions defining the result set */ +); + +static void _generateColumnNames( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* List of tables */ + ExprList *pEList /* Expressions defining the result set */ +); + +/* +** Generate code that will tell the VDBE the names of columns +** in the result set. This information is used to provide the +** azCol[] values in the callback. +*/ +static void generateColumnNames( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* List of tables */ + ExprList *pEList /* Expressions defining the result set */ +){ + Vdbe *v = pParse->pVdbe; + int i, j; + sqlite3 *db = pParse->db; + int fullNames, shortNames; + int realNames; /*** ADDED - SQLite.Interop ***/ + + realNames = (db->flags & 0x01000000)!=0; /*** ADDED - SQLite.Interop ***/ + if (!realNames) // Default to normal Sqlite3 /*** ADDED - SQLite.Interop ***/ + { /*** ADDED - SQLite.Interop ***/ + _generateColumnNames(pParse, pTabList, pEList); /*** ADDED - SQLite.Interop ***/ + return; /*** ADDED - SQLite.Interop ***/ + } /*** ADDED - SQLite.Interop ***/ + +#ifndef SQLITE_OMIT_EXPLAIN + /* If this is an EXPLAIN, skip this step */ + if( pParse->explain ){ + return; + } +#endif + + assert( v!=0 ); + if( pParse->colNamesSet || v==0 || sqlite3_malloc_failed ) return; + pParse->colNamesSet = 1; + fullNames = (db->flags & SQLITE_FullColNames)!=0; + shortNames = (db->flags & SQLITE_ShortColNames)!=0; + if (realNames) fullNames = 1; /*** ADDED - SQLite.Interop ***/ + + sqlite3VdbeSetNumCols(v, pEList->nExpr); + for(i=0; inExpr; i++){ + Expr *p; + p = pEList->a[i].pExpr; + if( p==0 ) continue; + if( pEList->a[i].zName && (realNames == 0 || p->op != TK_COLUMN)){ /*** CHANGED - SQLite.Interop ***/ + char *zName = pEList->a[i].zName; + sqlite3VdbeSetColName(v, i, zName, strlen(zName)); + continue; + } + if( p->op==TK_COLUMN && pTabList ){ + Table *pTab; + char *zCol; + int iCol = p->iColumn; + for(j=0; jnSrc && pTabList->a[j].iCursor!=p->iTable; j++){} + assert( jnSrc ); + pTab = pTabList->a[j].pTab; + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==-1 || (iCol>=0 && iColnCol) ); + if( iCol<0 ){ + zCol = "rowid"; + }else{ + zCol = pTab->aCol[iCol].zName; + } + if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ + sqlite3VdbeSetColName(v, i, p->span.z, p->span.n); + }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ + char *zName = 0; + char *zTab; + char *zDb = 0; /*** ADDED - SQLite.Interop ***/ + + zTab = pTabList->a[j].zAlias; + if( fullNames || zTab==0 ){ + if (pTab->iDb > 1) zDb = db->aDb[pTab->iDb].zName; /*** ADDED - SQLite.Interop ***/ + zTab = pTab->zName; + } + if (!zDb || !realNames) sqlite3SetString(&zName, zTab, ".", zCol, 0); /*** CHANGED - SQLite.Interop ***/ + else sqlite3SetString(&zName, zDb, ".", zTab, ".", zCol, 0); /*** ADDED - SQLite.Interop ***/ + sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC); + }else{ + sqlite3VdbeSetColName(v, i, zCol, strlen(zCol)); + } + }else if( p->span.z && p->span.z[0] ){ + sqlite3VdbeSetColName(v, i, p->span.z, p->span.n); + /* sqlite3VdbeCompressSpace(v, addr); */ + }else{ + char zName[30]; + assert( p->op!=TK_COLUMN || pTabList==0 ); + sprintf(zName, "column%d", i+1); + sqlite3VdbeSetColName(v, i, zName, 0); + } + } + generateColumnTypes(pParse, pTabList, pEList); +} + +#ifdef OS_WIN + +typedef void (__stdcall *SQLITEUSERFUNC)(void *, int, void **); +typedef int (__stdcall *SQLITECOLLATION)(int, const void *, int, const void*); + +// Callback wrappers +int sqlite3_interop_collationfunc(void *pv, int len1, const void *pv1, int len2, const void *pv2) +{ + SQLITECOLLATION *p = (SQLITECOLLATION *)pv; + return p[0](len1, pv1, len2, pv2); +} + +void sqlite3_interop_func(sqlite3_context *pctx, int n, sqlite3_value **pv) +{ + SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); + pf[0](pctx, n, pv); +} + +void sqlite3_interop_step(sqlite3_context *pctx, int n, sqlite3_value **pv) +{ + SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); + pf[1](pctx, n, pv); +} + +void sqlite3_interop_final(sqlite3_context *pctx) +{ + SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); + pf[2](pctx, 0, 0); +} + +__declspec(dllexport) void __stdcall sqlite3_function_free_callbackcookie(void *pCookie) +{ + if (pCookie) + free(pCookie); +} + +// sqlite3 wrappers +__declspec(dllexport) const char * __stdcall sqlite3_libversion_interop(int *plen) +{ + const char *val = sqlite3_libversion(); + *plen = (val != 0) ? strlen(val) : 0; + + return val; +} + +__declspec(dllexport) int __stdcall sqlite3_libversion_number_interop(void) +{ + return sqlite3_libversion_number(); +} + +__declspec(dllexport) int __stdcall sqlite3_close_interop(sqlite3 *db) +{ + return sqlite3_close(db); +} + +__declspec(dllexport) int __stdcall sqlite3_exec_interop(sqlite3 *db, const char *sql, sqlite3_callback cb, void *pv, char **errmsg, int *plen) +{ + int n = sqlite3_exec(db, sql, cb, pv, errmsg); + *plen = (*errmsg != 0) ? strlen(*errmsg) : 0; + return n; +} + +__declspec(dllexport) sqlite_int64 __stdcall sqlite3_last_insert_rowid_interop(sqlite3 *db) +{ + return sqlite3_last_insert_rowid(db); +} + +__declspec(dllexport) int __stdcall sqlite3_changes_interop(sqlite3 *db) +{ + return sqlite3_changes(db); +} + +__declspec(dllexport) int __stdcall sqlite3_total_changes_interop(sqlite3 *db) +{ + return sqlite3_total_changes(db); +} + +__declspec(dllexport) void __stdcall sqlite3_interrupt_interop(sqlite3 *db) +{ + sqlite3_interrupt(db); +} + +__declspec(dllexport) int __stdcall sqlite3_complete_interop(const char *sql) +{ + return sqlite3_complete(sql); +} + +__declspec(dllexport) int __stdcall sqlite3_complete16_interop(const void *sql) +{ + return sqlite3_complete16(sql); +} + +__declspec(dllexport) int __stdcall sqlite3_busy_handler_interop(sqlite3 *db, int(*cb)(void *, int), void *pv) +{ + return sqlite3_busy_handler(db, cb, pv); +} + +__declspec(dllexport) int __stdcall sqlite3_busy_timeout_interop(sqlite3 *db, int ms) +{ + return sqlite3_busy_timeout(db, ms); +} + +__declspec(dllexport) int __stdcall sqlite3_get_table_interop(sqlite3 *db, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg, int *plen) +{ + int n = sqlite3_get_table(db, sql, resultp, nrow, ncolumn, errmsg); + *plen = (*errmsg != 0) ? strlen((char *)*errmsg) : 0; + return n; +} + +__declspec(dllexport) void __stdcall sqlite3_free_table_interop(char **result) +{ + sqlite3_free_table(result); +} + +__declspec(dllexport) void __stdcall sqlite3_free_interop(char *z) +{ + sqlite3_free(z); +} + +__declspec(dllexport) int __stdcall sqlite3_open_interop(const char*filename, sqlite3 **ppdb) +{ + return sqlite3_open(filename, ppdb); +} + +__declspec(dllexport) int __stdcall sqlite3_open16_interop(const void *filename, sqlite3 **ppdb) +{ + return sqlite3_open16(filename, ppdb); +} + +__declspec(dllexport) int __stdcall sqlite3_errcode_interop(sqlite3 *db) +{ + return sqlite3_errcode(db); +} + +__declspec(dllexport) const char * __stdcall sqlite3_errmsg_interop(sqlite3 *db, int *plen) +{ + const char *pval = sqlite3_errmsg(db); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_errmsg16_interop(sqlite3 *db) +{ + return sqlite3_errmsg16(db); +} + +__declspec(dllexport) int __stdcall sqlite3_prepare_interop(sqlite3 *db, const char *sql, int nbytes, sqlite3_stmt **ppstmt, const char **pztail, int *plen) +{ + int n = sqlite3_prepare(db, sql, nbytes, ppstmt, pztail); + *plen = (*pztail != 0) ? strlen(*pztail) : 0; + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_prepare16_interop(sqlite3 *db, const void *sql, int nbytes, sqlite3_stmt **ppstmt, const void **pztail) +{ + return sqlite3_prepare16(db, sql, nbytes, ppstmt, pztail); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_blob_interop(sqlite3_stmt *stmt, int iCol, const void *pv, int n, void(*cb)(void*)) +{ + return sqlite3_bind_blob(stmt, iCol, pv, n, cb); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_double_interop(sqlite3_stmt *stmt, int iCol, double *val) +{ + return sqlite3_bind_double(stmt,iCol,*val); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_int_interop(sqlite3_stmt *stmt, int iCol, int val) +{ + return sqlite3_bind_int(stmt, iCol, val); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val) +{ + return sqlite3_bind_int64(stmt,iCol,*val); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_null_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_bind_null(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_text_interop(sqlite3_stmt *stmt, int iCol, const char *val, int n, void(*cb)(void *)) +{ + return sqlite3_bind_text(stmt, iCol, val, n, cb); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_text16_interop(sqlite3_stmt *stmt, int iCol, const void *val, int n, void(*cb)(void *)) +{ + return sqlite3_bind_text16(stmt, iCol, val, n, cb); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_parameter_count_interop(sqlite3_stmt *stmt) +{ + return sqlite3_bind_parameter_count(stmt); +} + +__declspec(dllexport) const char * __stdcall sqlite3_bind_parameter_name_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const char *pval = sqlite3_bind_parameter_name(stmt, iCol); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) int __stdcall sqlite3_bind_parameter_index_interop(sqlite3_stmt *stmt, const char *zName) +{ + return sqlite3_bind_parameter_index(stmt, zName); +} + +__declspec(dllexport) int __stdcall sqlite3_column_count_interop(sqlite3_stmt *stmt) +{ + return sqlite3_column_count(stmt); +} + +__declspec(dllexport) const char * __stdcall sqlite3_column_name_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const char *pval = sqlite3_column_name(stmt, iCol); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_column_name16_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_name16(stmt, iCol); +} + +__declspec(dllexport) const char * __stdcall sqlite3_column_decltype_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const char *pval = sqlite3_column_decltype(stmt, iCol); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_column_decltype16_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_decltype16(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_step_interop(sqlite3_stmt *stmt) +{ + return sqlite3_step(stmt); +} + +__declspec(dllexport) int __stdcall sqlite3_data_count_interop(sqlite3_stmt *stmt) +{ + return sqlite3_data_count(stmt); +} + +__declspec(dllexport) const void * __stdcall sqlite3_column_blob_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_blob(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_column_bytes_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_bytes(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_column_bytes16_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_bytes16(stmt, iCol); +} + +__declspec(dllexport) void __stdcall sqlite3_column_double_interop(sqlite3_stmt *stmt, int iCol, double *val) +{ + *val = sqlite3_column_double(stmt,iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_column_int_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_int(stmt, iCol); +} + +__declspec(dllexport) void __stdcall sqlite3_column_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val) +{ + *val = sqlite3_column_int64(stmt,iCol); +} + +__declspec(dllexport) const unsigned char * __stdcall sqlite3_column_text_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const unsigned char *pval = sqlite3_column_text(stmt, iCol); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_column_text16_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_text16(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_column_type_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_type(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_finalize_interop(sqlite3_stmt *stmt) +{ + return sqlite3_finalize(stmt); +} + +__declspec(dllexport) int __stdcall sqlite3_reset_interop(sqlite3_stmt *stmt) +{ + return sqlite3_reset(stmt); +} + +__declspec(dllexport) int __stdcall sqlite3_create_function_interop(sqlite3 *psql, const char *zFunctionName, int nArg, int eTextRep, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEUSERFUNC funcfinal, void **ppCookie) +{ + int n; + SQLITEUSERFUNC *p = malloc(sizeof(SQLITEUSERFUNC) * 3); + + p[0] = func; + p[1] = funcstep; + p[2] = funcfinal; + + *ppCookie = 0; + + n = sqlite3_create_function(psql, zFunctionName, nArg, eTextRep, p, (func != 0) ? sqlite3_interop_func : 0, (funcstep != 0) ? sqlite3_interop_step : 0, (funcfinal != 0) ? sqlite3_interop_final : 0); + if (n != 0) + free(p); + else + *ppCookie = p; + + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_create_function16_interop(sqlite3 *psql, void *zFunctionName, int nArg, int eTextRep, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEUSERFUNC funcfinal, void **ppCookie) +{ + int n; + SQLITEUSERFUNC *p = malloc(sizeof(SQLITEUSERFUNC) * 3); + + p[0] = func; + p[1] = funcstep; + p[2] = funcfinal; + + *ppCookie = 0; + + n = sqlite3_create_function16(psql, zFunctionName, nArg, eTextRep, p, (func != 0) ? sqlite3_interop_func : 0, (funcstep != 0) ? sqlite3_interop_step : 0, (funcfinal != 0) ? sqlite3_interop_final : 0); + if (n != 0) + free(p); + else + *ppCookie = p; + + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_create_collation_interop(sqlite3* db, const char *zName, int eTextRep, void* pvUser, SQLITECOLLATION func, void **ppCookie) +{ + int n; + SQLITECOLLATION *p = malloc(sizeof(SQLITECOLLATION)); + + p[0] = func; + + *ppCookie = 0; + + n = sqlite3_create_collation(db, zName, eTextRep, p, sqlite3_interop_collationfunc); + if (n != 0) + free(p); + else + *ppCookie = p; + + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_create_collation16_interop(sqlite3* db, const void *zName, int eTextRep, void* pvUser, SQLITECOLLATION func, void **ppCookie) +{ + int n; + SQLITECOLLATION *p = malloc(sizeof(SQLITECOLLATION)); + + p[0] = func; + + *ppCookie = 0; + + n = sqlite3_create_collation16(db, (const char *)zName, eTextRep, p, sqlite3_interop_collationfunc); + if (n != 0) + free(p); + else + *ppCookie = p; + + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_aggregate_count_interop(sqlite3_context *pctx) +{ + return sqlite3_aggregate_count(pctx); +} + +__declspec(dllexport) const void * __stdcall sqlite3_value_blob_interop(sqlite3_value *val) +{ + return sqlite3_value_blob(val); +} + +__declspec(dllexport) int __stdcall sqlite3_value_bytes_interop(sqlite3_value *val) +{ + return sqlite3_value_bytes(val); +} + +__declspec(dllexport) int __stdcall sqlite3_value_bytes16_interop(sqlite3_value *val) +{ + return sqlite3_value_bytes16(val); +} + +__declspec(dllexport) void __stdcall sqlite3_value_double_interop(sqlite3_value *pval, double *val) +{ + *val = sqlite3_value_double(pval); +} + +__declspec(dllexport) int __stdcall sqlite3_value_int_interop(sqlite3_value *val) +{ + return sqlite3_value_int(val); +} + +__declspec(dllexport) void __stdcall sqlite3_value_int64_interop(sqlite3_value *pval, sqlite_int64 *val) +{ + *val = sqlite3_value_int64(pval); +} + +__declspec(dllexport) const unsigned char * __stdcall sqlite3_value_text_interop(sqlite3_value *val, int *plen) +{ + const unsigned char *pval = sqlite3_value_text(val); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_value_text16_interop(sqlite3_value *val) +{ + return sqlite3_value_text16(val); +} + +__declspec(dllexport) int __stdcall sqlite3_value_type_interop(sqlite3_value *val) +{ + return sqlite3_value_type(val); +} + +__declspec(dllexport) void * __stdcall sqlite3_aggregate_context_interop(sqlite3_context *pctx, int n) +{ + return sqlite3_aggregate_context(pctx, n); +} + +__declspec(dllexport) void __stdcall sqlite3_result_blob_interop(sqlite3_context *ctx, const void *pv, int n, void(*cb)(void *)) +{ + sqlite3_result_blob(ctx, pv, n, cb); +} + +__declspec(dllexport) void __stdcall sqlite3_result_double_interop(sqlite3_context *pctx, double *val) +{ + sqlite3_result_double(pctx, *val); +} + +__declspec(dllexport) void __stdcall sqlite3_result_int_interop(sqlite3_context *pctx, int val) +{ + sqlite3_result_int(pctx, val); +} + +__declspec(dllexport) void __stdcall sqlite3_result_int64_interop(sqlite3_context *pctx, sqlite_int64 *val) +{ + sqlite3_result_int64(pctx, *val); +} + +__declspec(dllexport) void __stdcall sqlite3_result_null_interop(sqlite3_context *pctx) +{ + sqlite3_result_null(pctx); +} + +__declspec(dllexport) void __stdcall sqlite3_result_error_interop(sqlite3_context *ctx, const char *pv, int n) +{ + sqlite3_result_error(ctx, pv, n); +} + +__declspec(dllexport) void __stdcall sqlite3_result_error16_interop(sqlite3_context *ctx, const void *pv, int n) +{ + sqlite3_result_error16(ctx, pv, n); +} + +__declspec(dllexport) void __stdcall sqlite3_result_text_interop(sqlite3_context *ctx, const char *pv, int n, void(*cb)(void *)) +{ + sqlite3_result_text(ctx, pv, n, cb); +} + +__declspec(dllexport) void __stdcall sqlite3_result_text16_interop(sqlite3_context *ctx, const void *pv, int n, void(*cb)(void *)) +{ + sqlite3_result_text16(ctx, pv, n, cb); +} + +__declspec(dllexport) void __stdcall sqlite3_realcolnames(sqlite3 *db, int bOn) +{ + if (bOn) + db->flags |= 0x01000000; + else + db->flags &= (~0x01000000); +} + +#endif // OS_WIN DELETED SQLite.Interop/merge.h Index: SQLite.Interop/merge.h ================================================================== --- SQLite.Interop/merge.h +++ /dev/null @@ -1,17 +0,0 @@ -// This code was automatically generated from assembly -// C:\src\SQLite.NET\System.Data.SQLite\bin\System.Data.SQLite.dll - -#include - -#pragma data_seg(".clr") -#pragma comment(linker, "/SECTION:.clr,ER") - char __ph[85184] = {0}; // The number of bytes to reserve -#pragma data_seg() - -#pragma comment(lib, "mscoree") - -extern BOOL WINAPI _CorDllMain(HANDLE, DWORD, LPVOID); -__declspec(dllexport) BOOL WINAPI _CorDllMainStub(HANDLE hModule, DWORD dwReason, LPVOID pvReserved) -{ - return _CorDllMain(hModule, dwReason, pvReserved); -} DELETED SQLite.Interop/resource.h Index: SQLite.Interop/resource.h ================================================================== --- SQLite.Interop/resource.h +++ /dev/null @@ -1,14 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by SQLite.Interop.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif Index: SQLite.Interop/src/alter.c ================================================================== --- SQLite.Interop/src/alter.c +++ SQLite.Interop/src/alter.c @@ -10,14 +10,13 @@ ** ************************************************************************* ** This file contains C code routines that used to generate VDBE code ** that implements the ALTER TABLE command. ** -** $Id: alter.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: alter.c,v 1.1 2005/03/01 16:04:26 rmsimpson Exp $ */ #include "sqliteInt.h" -#include /* ** The code in this file only exists if we are not omitting the ** ALTER TABLE logic from the build. */ @@ -45,11 +44,11 @@ unsigned char const *zSql = sqlite3_value_text(argv[0]); unsigned char const *zTableName = sqlite3_value_text(argv[1]); int token; Token tname; - unsigned char const *zCsr = zSql; + char const *zCsr = zSql; int len = 0; char *zRet; /* The principle used to locate the table name in the CREATE TABLE ** statement is that the table name is the first token that is immediatedly @@ -94,11 +93,11 @@ unsigned char const *zTableName = sqlite3_value_text(argv[1]); int token; Token tname; int dist = 3; - unsigned char const *zCsr = zSql; + char const *zCsr = zSql; int len = 0; char *zRet; /* The principle used to locate the table name in the CREATE TRIGGER ** statement is that the table name is the first token that is immediatedly @@ -165,91 +164,10 @@ sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0); } } -/* -** Generate the text of a WHERE expression which can be used to select all -** temporary triggers on table pTab from the sqlite_temp_master table. If -** table pTab has no temporary triggers, or is itself stored in the -** temporary database, NULL is returned. -*/ -static char *whereTempTriggers(Parse *pParse, Table *pTab){ - Trigger *pTrig; - char *zWhere = 0; - char *tmp = 0; - const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */ - - /* If the table is not located in the temp-db (in which case NULL is - ** returned, loop through the tables list of triggers. For each trigger - ** that is not part of the temp-db schema, add a clause to the WHERE - ** expression being built up in zWhere. - */ - if( pTab->pSchema!=pTempSchema ){ - for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ - if( pTrig->pSchema==pTempSchema ){ - if( !zWhere ){ - zWhere = sqlite3MPrintf("name=%Q", pTrig->name); - }else{ - tmp = zWhere; - zWhere = sqlite3MPrintf("%s OR name=%Q", zWhere, pTrig->name); - sqliteFree(tmp); - } - } - } - } - return zWhere; -} - -/* -** Generate code to drop and reload the internal representation of table -** pTab from the database, including triggers and temporary triggers. -** Argument zName is the name of the table in the database schema at -** the time the generated code is executed. This can be different from -** pTab->zName if this function is being called to code part of an -** "ALTER TABLE RENAME TO" statement. -*/ -static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ - Vdbe *v; - char *zWhere; - int iDb; /* Index of database containing pTab */ -#ifndef SQLITE_OMIT_TRIGGER - Trigger *pTrig; -#endif - - v = sqlite3GetVdbe(pParse); - if( !v ) return; - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - assert( iDb>=0 ); - -#ifndef SQLITE_OMIT_TRIGGER - /* Drop any table triggers from the internal schema. */ - for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){ - int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); - assert( iTrigDb==iDb || iTrigDb==1 ); - sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0); - } -#endif - - /* Drop the table and index from the internal schema */ - sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); - - /* Reload the table, index and permanent trigger schemas. */ - zWhere = sqlite3MPrintf("tbl_name=%Q", zName); - if( !zWhere ) return; - sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); - -#ifndef SQLITE_OMIT_TRIGGER - /* Now, if the table is not stored in the temp database, reload any temp - ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. - */ - if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ - sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC); - } -#endif -} - /* ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" ** command. */ void sqlite3AlterRenameTable( @@ -259,22 +177,22 @@ ){ int iDb; /* Database that contains the table */ char *zDb; /* Name of database iDb */ Table *pTab; /* Table being renamed */ char *zName = 0; /* NULL-terminated version of pName */ + char *zWhere = 0; /* Where clause of schema elements to reparse */ sqlite3 *db = pParse->db; /* Database connection */ Vdbe *v; #ifndef SQLITE_OMIT_TRIGGER - char *zWhere = 0; /* Where clause to locate temp triggers */ + char *zTempTrig = 0; /* Where clause to locate temp triggers */ #endif - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_rename_table; assert( pSrc->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_rename_table; - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + iDb = pTab->iDb; zDb = db->aDb[iDb].zName; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(pName); if( !zName ) goto exit_rename_table; @@ -335,11 +253,11 @@ "ELSE name END " "WHERE tbl_name=%Q AND " "(type='table' OR type='index' OR type='trigger');", zDb, SCHEMA_TABLE(iDb), zName, zName, zName, #ifndef SQLITE_OMIT_TRIGGER - zName, +zName, #endif zName, strlen(pTab->zName), pTab->zName ); #ifndef SQLITE_OMIT_AUTOINCREMENT @@ -356,199 +274,61 @@ #ifndef SQLITE_OMIT_TRIGGER /* If there are TEMP triggers on this table, modify the sqlite_temp_master ** table. Don't do this if the table being ALTERed is itself located in ** the temp database. */ - if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ - sqlite3NestedParse(pParse, - "UPDATE sqlite_temp_master SET " - "sql = sqlite_rename_trigger(sql, %Q), " - "tbl_name = %Q " - "WHERE %s;", zName, zName, zWhere); - sqliteFree(zWhere); + if( iDb!=1 ){ + Trigger *pTrig; + char *tmp = 0; + for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ + if( pTrig->iDb==1 ){ + if( !zTempTrig ){ + zTempTrig = + sqlite3MPrintf("type = 'trigger' AND (name=%Q", pTrig->name); + }else{ + tmp = zTempTrig; + zTempTrig = sqlite3MPrintf("%s OR name=%Q", zTempTrig, pTrig->name); + sqliteFree(tmp); + } + } + } + if( zTempTrig ){ + tmp = zTempTrig; + zTempTrig = sqlite3MPrintf("%s)", zTempTrig); + sqliteFree(tmp); + sqlite3NestedParse(pParse, + "UPDATE sqlite_temp_master SET " + "sql = sqlite_rename_trigger(sql, %Q), " + "tbl_name = %Q " + "WHERE %s;", zName, zName, zTempTrig); + } } #endif - /* Drop and reload the internal table schema. */ - reloadTableSchema(pParse, pTab, zName); + /* Drop the elements of the in-memory schema that refered to the table + ** renamed and load the new versions from the database. + */ + if( pParse->nErr==0 ){ +#ifndef SQLITE_OMIT_TRIGGER + Trigger *pTrig; + for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ + assert( pTrig->iDb==iDb || pTrig->iDb==1 ); + sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0); + } +#endif + sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); + zWhere = sqlite3MPrintf("tbl_name=%Q", zName); + sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); +#ifndef SQLITE_OMIT_TRIGGER + if( zTempTrig ){ + sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zTempTrig, P3_DYNAMIC); + } + }else{ + sqliteFree(zTempTrig); +#endif + } exit_rename_table: sqlite3SrcListDelete(pSrc); sqliteFree(zName); } - - -/* -** This function is called after an "ALTER TABLE ... ADD" statement -** has been parsed. Argument pColDef contains the text of the new -** column definition. -** -** The Table structure pParse->pNewTable was extended to include -** the new column during parsing. -*/ -void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ - Table *pNew; /* Copy of pParse->pNewTable */ - Table *pTab; /* Table being altered */ - int iDb; /* Database number */ - const char *zDb; /* Database name */ - const char *zTab; /* Table name */ - char *zCol; /* Null-terminated column definition */ - Column *pCol; /* The new column */ - Expr *pDflt; /* Default value for the new column */ - - if( pParse->nErr ) return; - pNew = pParse->pNewTable; - assert( pNew ); - - iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema); - zDb = pParse->db->aDb[iDb].zName; - zTab = pNew->zName; - pCol = &pNew->aCol[pNew->nCol-1]; - pDflt = pCol->pDflt; - pTab = sqlite3FindTable(pParse->db, zTab, zDb); - assert( pTab ); - - /* If the default value for the new column was specified with a - ** literal NULL, then set pDflt to 0. This simplifies checking - ** for an SQL NULL default below. - */ - if( pDflt && pDflt->op==TK_NULL ){ - pDflt = 0; - } - - /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. - ** If there is a NOT NULL constraint, then the default value for the - ** column must not be NULL. - */ - if( pCol->isPrimKey ){ - sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); - return; - } - if( pNew->pIndex ){ - sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); - return; - } - if( pCol->notNull && !pDflt ){ - sqlite3ErrorMsg(pParse, - "Cannot add a NOT NULL column with default value NULL"); - return; - } - - /* Ensure the default expression is something that sqlite3ValueFromExpr() - ** can handle (i.e. not CURRENT_TIME etc.) - */ - if( pDflt ){ - sqlite3_value *pVal; - if( sqlite3ValueFromExpr(pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ - /* malloc() has failed */ - return; - } - if( !pVal ){ - sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); - return; - } - sqlite3ValueFree(pVal); - } - - /* Modify the CREATE TABLE statement. */ - zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n); - if( zCol ){ - char *zEnd = &zCol[pColDef->n-1]; - while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){ - *zEnd-- = '\0'; - } - sqlite3NestedParse(pParse, - "UPDATE %Q.%s SET " - "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d,length(sql)) " - "WHERE type = 'table' AND name = %Q", - zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, - zTab - ); - sqliteFree(zCol); - } - - /* If the default value of the new column is NULL, then set the file - ** format to 2. If the default value of the new column is not NULL, - ** the file format becomes 3. - */ - sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2); - - /* Reload the schema of the modified table. */ - reloadTableSchema(pParse, pTab, pTab->zName); -} - -/* -** This function is called by the parser after the table-name in -** an "ALTER TABLE ADD" statement is parsed. Argument -** pSrc is the full-name of the table being altered. -** -** This routine makes a (partial) copy of the Table structure -** for the table being altered and sets Parse.pNewTable to point -** to it. Routines called by the parser as the column definition -** is parsed (i.e. sqlite3AddColumn()) add the new Column data to -** the copy. The copy of the Table structure is deleted by tokenize.c -** after parsing is finished. -** -** Routine sqlite3AlterFinishAddColumn() will be called to complete -** coding the "ALTER TABLE ... ADD" statement. -*/ -void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ - Table *pNew; - Table *pTab; - Vdbe *v; - int iDb; - int i; - int nAlloc; - - /* Look up the table being altered. */ - assert( pParse->pNewTable==0 ); - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_begin_add_column; - pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); - if( !pTab ) goto exit_begin_add_column; - - /* Make sure this is not an attempt to ALTER a view. */ - if( pTab->pSelect ){ - sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); - goto exit_begin_add_column; - } - - assert( pTab->addColOffset>0 ); - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - - /* Put a copy of the Table struct in Parse.pNewTable for the - ** sqlite3AddColumn() function and friends to modify. - */ - pNew = (Table *)sqliteMalloc(sizeof(Table)); - if( !pNew ) goto exit_begin_add_column; - pParse->pNewTable = pNew; - pNew->nRef = 1; - pNew->nCol = pTab->nCol; - assert( pNew->nCol>0 ); - nAlloc = (((pNew->nCol-1)/8)*8)+8; - assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); - pNew->aCol = (Column *)sqliteMalloc(sizeof(Column)*nAlloc); - pNew->zName = sqliteStrDup(pTab->zName); - if( !pNew->aCol || !pNew->zName ){ - goto exit_begin_add_column; - } - memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); - for(i=0; inCol; i++){ - Column *pCol = &pNew->aCol[i]; - pCol->zName = sqliteStrDup(pCol->zName); - pCol->zType = 0; - pCol->pDflt = 0; - } - pNew->pSchema = pParse->db->aDb[iDb].pSchema; - pNew->addColOffset = pTab->addColOffset; - pNew->nRef = 1; - - /* Begin a transaction and increment the schema cookie. */ - sqlite3BeginWriteOperation(pParse, 0, iDb); - v = sqlite3GetVdbe(pParse); - if( !v ) goto exit_begin_add_column; - sqlite3ChangeCookie(pParse->db, v, iDb); - -exit_begin_add_column: - sqlite3SrcListDelete(pSrc); - return; -} #endif /* SQLITE_ALTER_TABLE */ DELETED SQLite.Interop/src/analyze.c Index: SQLite.Interop/src/analyze.c ================================================================== --- SQLite.Interop/src/analyze.c +++ /dev/null @@ -1,403 +0,0 @@ -/* -** 2005 July 8 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains code associated with the ANALYZE command. -** -** @(#) $Id: analyze.c,v 1.9 2006/01/16 15:51:47 rmsimpson Exp $ -*/ -#ifndef SQLITE_OMIT_ANALYZE -#include "sqliteInt.h" - -/* -** This routine generates code that opens the sqlite_stat1 table on cursor -** iStatCur. -** -** If the sqlite_stat1 tables does not previously exist, it is created. -** If it does previously exist, all entires associated with table zWhere -** are removed. If zWhere==0 then all entries are removed. -*/ -static void openStatTable( - Parse *pParse, /* Parsing context */ - int iDb, /* The database we are looking in */ - int iStatCur, /* Open the sqlite_stat1 table on this cursor */ - const char *zWhere /* Delete entries associated with this table */ -){ - sqlite3 *db = pParse->db; - Db *pDb; - int iRootPage; - Table *pStat; - Vdbe *v = sqlite3GetVdbe(pParse); - - pDb = &db->aDb[iDb]; - if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){ - /* The sqlite_stat1 tables does not exist. Create it. - ** Note that a side-effect of the CREATE TABLE statement is to leave - ** the rootpage of the new table on the top of the stack. This is - ** important because the OpenWrite opcode below will be needing it. */ - sqlite3NestedParse(pParse, - "CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)", - pDb->zName - ); - iRootPage = 0; /* Cause rootpage to be taken from top of stack */ - }else if( zWhere ){ - /* The sqlite_stat1 table exists. Delete all entries associated with - ** the table zWhere. */ - sqlite3NestedParse(pParse, - "DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q", - pDb->zName, zWhere - ); - iRootPage = pStat->tnum; - }else{ - /* The sqlite_stat1 table already exists. Delete all rows. */ - iRootPage = pStat->tnum; - sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb); - } - - /* Open the sqlite_stat1 table for writing. Unless it was created - ** by this vdbe program, lock it for writing at the shared-cache level. - ** If this vdbe did create the sqlite_stat1 table, then it must have - ** already obtained a schema-lock, making the write-lock redundant. - */ - if( iRootPage>0 ){ - sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1"); - } - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage); - sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3); -} - -/* -** Generate code to do an analysis of all indices associated with -** a single table. -*/ -static void analyzeOneTable( - Parse *pParse, /* Parser context */ - Table *pTab, /* Table whose indices are to be analyzed */ - int iStatCur, /* Cursor that writes to the sqlite_stat1 table */ - int iMem /* Available memory locations begin here */ -){ - Index *pIdx; /* An index to being analyzed */ - int iIdxCur; /* Cursor number for index being analyzed */ - int nCol; /* Number of columns in the index */ - Vdbe *v; /* The virtual machine being built up */ - int i; /* Loop counter */ - int topOfLoop; /* The top of the loop */ - int endOfLoop; /* The end of the loop */ - int addr; /* The address of an instruction */ - int iDb; /* Index of database containing pTab */ - - v = sqlite3GetVdbe(pParse); - if( pTab==0 || pTab->pIndex==0 ){ - /* Do no analysis for tables that have no indices */ - return; - } - - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - assert( iDb>=0 ); -#ifndef SQLITE_OMIT_AUTHORIZATION - if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, - pParse->db->aDb[iDb].zName ) ){ - return; - } -#endif - - /* Establish a read-lock on the table at the shared-cache level. */ - sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); - - iIdxCur = pParse->nTab; - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); - - /* Open a cursor to the index to be analyzed - */ - assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) ); - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - VdbeComment((v, "# %s", pIdx->zName)); - sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, - (char *)pKey, P3_KEYINFO_HANDOFF); - nCol = pIdx->nColumn; - if( iMem+nCol*2>=pParse->nMem ){ - pParse->nMem = iMem+nCol*2+1; - } - sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, nCol+1); - - /* Memory cells are used as follows: - ** - ** mem[iMem]: The total number of rows in the table. - ** mem[iMem+1]: Number of distinct values in column 1 - ** ... - ** mem[iMem+nCol]: Number of distinct values in column N - ** mem[iMem+nCol+1] Last observed value of column 1 - ** ... - ** mem[iMem+nCol+nCol]: Last observed value of column N - ** - ** Cells iMem through iMem+nCol are initialized to 0. The others - ** are initialized to NULL. - */ - for(i=0; i<=nCol; i++){ - sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i); - } - for(i=0; i0 then it is always the case the D>0 so division by zero - ** is never possible. - */ - sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0); - addr = sqlite3VdbeAddOp(v, OP_IfNot, 0, 0); - sqlite3VdbeAddOp(v, OP_NewRowid, iStatCur, 0); - sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); - sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0); - sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0); - sqlite3VdbeOp3(v, OP_String8, 0, 0, " ", 0); - for(i=0; idb; - Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ - HashElem *k; - int iStatCur; - int iMem; - - sqlite3BeginWriteOperation(pParse, 0, iDb); - iStatCur = pParse->nTab++; - openStatTable(pParse, iDb, iStatCur, 0); - iMem = pParse->nMem; - for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ - Table *pTab = (Table*)sqliteHashData(k); - analyzeOneTable(pParse, pTab, iStatCur, iMem); - } - loadAnalysis(pParse, iDb); -} - -/* -** Generate code that will do an analysis of a single table in -** a database. -*/ -static void analyzeTable(Parse *pParse, Table *pTab){ - int iDb; - int iStatCur; - - assert( pTab!=0 ); - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - sqlite3BeginWriteOperation(pParse, 0, iDb); - iStatCur = pParse->nTab++; - openStatTable(pParse, iDb, iStatCur, pTab->zName); - analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem); - loadAnalysis(pParse, iDb); -} - -/* -** Generate code for the ANALYZE command. The parser calls this routine -** when it recognizes an ANALYZE command. -** -** ANALYZE -- 1 -** ANALYZE -- 2 -** ANALYZE ?.? -- 3 -** -** Form 1 causes all indices in all attached databases to be analyzed. -** Form 2 analyzes all indices the single database named. -** Form 3 analyzes all indices associated with the named table. -*/ -void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ - sqlite3 *db = pParse->db; - int iDb; - int i; - char *z, *zDb; - Table *pTab; - Token *pTableName; - - /* Read the database schema. If an error occurs, leave an error message - ** and code in pParse and return NULL. */ - if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ - return; - } - - if( pName1==0 ){ - /* Form 1: Analyze everything */ - for(i=0; inDb; i++){ - if( i==1 ) continue; /* Do not analyze the TEMP database */ - analyzeDatabase(pParse, i); - } - }else if( pName2==0 || pName2->n==0 ){ - /* Form 2: Analyze the database or table named */ - iDb = sqlite3FindDb(db, pName1); - if( iDb>=0 ){ - analyzeDatabase(pParse, iDb); - }else{ - z = sqlite3NameFromToken(pName1); - pTab = sqlite3LocateTable(pParse, z, 0); - sqliteFree(z); - if( pTab ){ - analyzeTable(pParse, pTab); - } - } - }else{ - /* Form 3: Analyze the fully qualified table name */ - iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); - if( iDb>=0 ){ - zDb = db->aDb[iDb].zName; - z = sqlite3NameFromToken(pTableName); - pTab = sqlite3LocateTable(pParse, z, zDb); - sqliteFree(z); - if( pTab ){ - analyzeTable(pParse, pTab); - } - } - } -} - -/* -** Used to pass information from the analyzer reader through to the -** callback routine. -*/ -typedef struct analysisInfo analysisInfo; -struct analysisInfo { - sqlite3 *db; - const char *zDatabase; -}; - -/* -** This callback is invoked once for each index when reading the -** sqlite_stat1 table. -** -** argv[0] = name of the index -** argv[1] = results of analysis - on integer for each column -*/ -static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){ - analysisInfo *pInfo = (analysisInfo*)pData; - Index *pIndex; - int i, c; - unsigned int v; - const char *z; - - assert( argc==2 ); - if( argv==0 || argv[0]==0 || argv[1]==0 ){ - return 0; - } - pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase); - if( pIndex==0 ){ - return 0; - } - z = argv[1]; - for(i=0; *z && i<=pIndex->nColumn; i++){ - v = 0; - while( (c=z[0])>='0' && c<='9' ){ - v = v*10 + c - '0'; - z++; - } - pIndex->aiRowEst[i] = v; - if( *z==' ' ) z++; - } - return 0; -} - -/* -** Load the content of the sqlite_stat1 table into the index hash tables. -*/ -void sqlite3AnalysisLoad(sqlite3 *db, int iDb){ - analysisInfo sInfo; - HashElem *i; - char *zSql; - - /* Clear any prior statistics */ - for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ - Index *pIdx = sqliteHashData(i); - sqlite3DefaultRowEst(pIdx); - } - - /* Check to make sure the sqlite_stat1 table existss */ - sInfo.db = db; - sInfo.zDatabase = db->aDb[iDb].zName; - if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){ - return; - } - - - /* Load new statistics out of the sqlite_stat1 table */ - zSql = sqlite3MPrintf("SELECT idx, stat FROM %Q.sqlite_stat1", - sInfo.zDatabase); - sqlite3SafetyOff(db); - sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); - sqlite3SafetyOn(db); - sqliteFree(zSql); -} - - -#endif /* SQLITE_OMIT_ANALYZE */ Index: SQLite.Interop/src/attach.c ================================================================== --- SQLite.Interop/src/attach.c +++ SQLite.Interop/src/attach.c @@ -9,346 +9,191 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** -** $Id: attach.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: attach.c,v 1.1 2005/03/01 16:04:26 rmsimpson Exp $ */ #include "sqliteInt.h" /* -** Resolve an expression that was part of an ATTACH or DETACH statement. This -** is slightly different from resolving a normal SQL expression, because simple -** identifiers are treated as strings, not possible column names or aliases. -** -** i.e. if the parser sees: -** -** ATTACH DATABASE abc AS def -** -** it treats the two expressions as literal strings 'abc' and 'def' instead of -** looking for columns of the same name. -** -** This only applies to the root node of pExpr, so the statement: -** -** ATTACH DATABASE abc||def AS 'db2' -** -** will fail because neither abc or def can be resolved. -*/ -int resolveAttachExpr(NameContext *pName, Expr *pExpr) -{ - int rc = SQLITE_OK; - if( pExpr ){ - if( pExpr->op!=TK_ID ){ - rc = sqlite3ExprResolveNames(pName, pExpr); - }else{ - pExpr->op = TK_STRING; - } - } - return rc; -} - -/* -** An SQL user-function registered to do the work of an ATTACH statement. The -** three arguments to the function come directly from an attach statement: -** -** ATTACH DATABASE x AS y KEY z -** -** SELECT sqlite_attach(x, y, z) -** -** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the -** third argument. -*/ -static void attachFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - int i; - int rc = 0; - sqlite3 *db = sqlite3_user_data(context); - const char *zName; - const char *zFile; - Db *aNew; - char zErr[128]; - char *zErrDyn = 0; - - zFile = (const char *)sqlite3_value_text(argv[0]); - zName = (const char *)sqlite3_value_text(argv[1]); - - /* Check for the following errors: - ** - ** * Too many attached databases, - ** * Transaction currently open - ** * Specified database name already being used. - */ - if( db->nDb>=MAX_ATTACHED+2 ){ - sqlite3_snprintf( - 127, zErr, "too many attached databases - max %d", MAX_ATTACHED - ); - goto attach_error; - } - if( !db->autoCommit ){ - strcpy(zErr, "cannot ATTACH database within transaction"); - goto attach_error; - } +** This routine is called by the parser to process an ATTACH statement: +** +** ATTACH DATABASE filename AS dbname +** +** The pFilename and pDbname arguments are the tokens that define the +** filename and dbname in the ATTACH statement. +*/ +void sqlite3Attach( + Parse *pParse, /* The parser context */ + Token *pFilename, /* Name of database file */ + Token *pDbname, /* Name of the database to use internally */ + int keyType, /* 0: no key. 1: TEXT, 2: BLOB */ + Token *pKey /* Text of the key for keytype 1 and 2 */ +){ + Db *aNew; + int rc, i; + char *zFile, *zName; + sqlite3 *db; + Vdbe *v; + + v = sqlite3GetVdbe(pParse); + if( !v ) return; + sqlite3VdbeAddOp(v, OP_Expire, 1, 0); + sqlite3VdbeAddOp(v, OP_Halt, 0, 0); + if( pParse->explain ) return; + db = pParse->db; + if( db->nDb>=MAX_ATTACHED+2 ){ + sqlite3ErrorMsg(pParse, "too many attached databases - max %d", + MAX_ATTACHED); + pParse->rc = SQLITE_ERROR; + return; + } + + if( !db->autoCommit ){ + sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction"); + pParse->rc = SQLITE_ERROR; + return; + } + + zFile = sqlite3NameFromToken(pFilename);; + if( zFile==0 ) return; +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){ + sqliteFree(zFile); + return; + } +#endif /* SQLITE_OMIT_AUTHORIZATION */ + + zName = sqlite3NameFromToken(pDbname); + if( zName==0 ) return; for(i=0; inDb; i++){ char *z = db->aDb[i].zName; if( z && sqlite3StrICmp(z, zName)==0 ){ - sqlite3_snprintf(127, zErr, "database %s is already in use", zName); - goto attach_error; + sqlite3ErrorMsg(pParse, "database %z is already in use", zName); + pParse->rc = SQLITE_ERROR; + sqliteFree(zFile); + return; } } - /* Allocate the new entry in the db->aDb[] array and initialise the schema - ** hash tables. - */ if( db->aDb==db->aDbStatic ){ aNew = sqliteMalloc( sizeof(db->aDb[0])*3 ); - if( aNew==0 ){ - return; - } + if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); - if( aNew==0 ){ - return; - } + if( aNew==0 ) return; } db->aDb = aNew; aNew = &db->aDb[db->nDb++]; memset(aNew, 0, sizeof(*aNew)); - - /* Open the database file. If the btree is successfully opened, use - ** it to obtain the database schema. At this point the schema may - ** or may not be initialised. - */ + sqlite3HashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0); + sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0); + sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0); + sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1); + aNew->zName = zName; + aNew->safety_level = 3; rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt); - if( rc==SQLITE_OK ){ - aNew->pSchema = sqlite3SchemaGet(aNew->pBt); - if( !aNew->pSchema ){ - rc = SQLITE_NOMEM; - }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ - strcpy(zErr, - "attached databases must use the same text encoding as main database"); - goto attach_error; - } - } - aNew->zName = sqliteStrDup(zName); - aNew->safety_level = 3; - + if( rc ){ + sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile); + } #if SQLITE_HAS_CODEC { extern int sqlite3CodecAttach(sqlite3*, int, void*, int); - extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); + char *zKey; int nKey; - char *zKey; - int t = sqlite3_value_type(argv[2]); - switch( t ){ - case SQLITE_INTEGER: - case SQLITE_FLOAT: - zErrDyn = sqliteStrDup("Invalid key value"); - rc = SQLITE_ERROR; - break; - - case SQLITE_TEXT: - case SQLITE_BLOB: - nKey = sqlite3_value_bytes(argv[2]); - zKey = (char *)sqlite3_value_blob(argv[2]); - sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); - break; - - case SQLITE_NULL: - /* No key specified. Use the key from the main database */ - sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); - break; + if( keyType==0 ){ + /* No key specified. Use the key from the main database */ + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); + sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); + }else if( keyType==1 ){ + /* Key specified as text */ + zKey = sqlite3NameFromToken(pKey); + nKey = strlen(zKey); + }else{ + /* Key specified as a BLOB */ + char *zTemp; + assert( keyType==2 ); + pKey->z++; + pKey->n--; + zTemp = sqlite3NameFromToken(pKey); + zKey = sqlite3HexToBlob(zTemp); + sqliteFree(zTemp); + } + sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + if( keyType ){ + sqliteFree(zKey); } } #endif - - /* If the file was opened successfully, read the schema for the new database. - ** If this fails, or if opening the file failed, then close the file and - ** remove the entry from the db->aDb[] array. i.e. put everything back the way - ** we found it. - */ - if( rc==SQLITE_OK ){ - sqlite3SafetyOn(db); - rc = sqlite3Init(db, &zErrDyn); - sqlite3SafetyOff(db); + sqliteFree(zFile); + db->flags &= ~SQLITE_Initialized; + if( pParse->nErr==0 && rc==SQLITE_OK ){ + rc = sqlite3ReadSchema(pParse); } if( rc ){ int i = db->nDb - 1; assert( i>=2 ); if( db->aDb[i].pBt ){ sqlite3BtreeClose(db->aDb[i].pBt); db->aDb[i].pBt = 0; - db->aDb[i].pSchema = 0; - } - sqlite3ResetInternalSchema(db, 0); - db->nDb = i; - sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile); - goto attach_error; - } - - return; - -attach_error: - /* Return an error if we get here */ - if( zErrDyn ){ - sqlite3_result_error(context, zErrDyn, -1); - sqliteFree(zErrDyn); - }else{ - zErr[sizeof(zErr)-1] = 0; - sqlite3_result_error(context, zErr, -1); - } -} - -/* -** An SQL user-function registered to do the work of an DETACH statement. The -** three arguments to the function come directly from a detach statement: -** -** DETACH DATABASE x -** -** SELECT sqlite_detach(x) -*/ -static void detachFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const char *zName = (const char *)sqlite3_value_text(argv[0]); - sqlite3 *db = sqlite3_user_data(context); - int i; - Db *pDb = 0; - char zErr[128]; - - assert(zName); - for(i=0; inDb; i++){ - pDb = &db->aDb[i]; - if( pDb->pBt==0 ) continue; - if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; - } - - if( i>=db->nDb ){ - sqlite3_snprintf(sizeof(zErr), zErr, "no such database: %s", zName); - goto detach_error; - } - if( i<2 ){ - sqlite3_snprintf(sizeof(zErr), zErr, "cannot detach database %s", zName); - goto detach_error; - } - if( !db->autoCommit ){ - strcpy(zErr, "cannot DETACH database within transaction"); - goto detach_error; - } - - sqlite3BtreeClose(pDb->pBt); - pDb->pBt = 0; - pDb->pSchema = 0; - sqlite3ResetInternalSchema(db, 0); - return; - -detach_error: - sqlite3_result_error(context, zErr, -1); -} - -/* -** This procedure generates VDBE code for a single invocation of either the -** sqlite_detach() or sqlite_attach() SQL user functions. -*/ -static void codeAttach( - Parse *pParse, /* The parser context */ - int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ - const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */ - int nFunc, /* Number of args to pass to zFunc */ - Expr *pAuthArg, /* Expression to pass to authorization callback */ - Expr *pFilename, /* Name of database file */ - Expr *pDbname, /* Name of the database to use internally */ - Expr *pKey /* Database key for encryption extension */ -){ - int rc; - NameContext sName; - Vdbe *v; - FuncDef *pFunc; - sqlite3* db = pParse->db; - -#ifndef SQLITE_OMIT_AUTHORIZATION - assert( sqlite3ThreadDataReadOnly()->mallocFailed || pAuthArg ); - if( pAuthArg ){ - char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span); - if( !zAuthArg ){ - goto attach_end; - } - rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); - sqliteFree(zAuthArg); - if(rc!=SQLITE_OK ){ - goto attach_end; - } - } -#endif /* SQLITE_OMIT_AUTHORIZATION */ - - memset(&sName, 0, sizeof(NameContext)); - sName.pParse = pParse; - - if( - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) - ){ - pParse->nErr++; - goto attach_end; - } - - v = sqlite3GetVdbe(pParse); - sqlite3ExprCode(pParse, pFilename); - sqlite3ExprCode(pParse, pDbname); - sqlite3ExprCode(pParse, pKey); - - assert(v || sqlite3ThreadDataReadOnly()->mallocFailed); - if( v ){ - sqlite3VdbeAddOp(v, OP_Function, 0, nFunc); - pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); - sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF); - - /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this - ** statement only). For DETACH, set it to false (expire all existing - ** statements). - */ - sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0); - } - -attach_end: - sqlite3ExprDelete(pFilename); - sqlite3ExprDelete(pDbname); - sqlite3ExprDelete(pKey); -} - -/* -** Called by the parser to compile a DETACH statement. -** -** DETACH pDbname -*/ -void sqlite3Detach(Parse *pParse, Expr *pDbname){ - codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname); -} - -/* -** Called by the parser to compile an ATTACH statement. -** -** ATTACH p AS pDbname KEY pKey -*/ -void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ - codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey); -} - -/* -** Register the functions sqlite_attach and sqlite_detach. -*/ -void sqlite3AttachFunctions(sqlite3 *db){ - static const int enc = SQLITE_UTF8; - sqlite3_create_function(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0); - sqlite3_create_function(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0); + } + sqlite3ResetInternalSchema(db, 0); + if( 0==pParse->nErr ){ + pParse->nErr++; + pParse->rc = SQLITE_ERROR; + } + } +} + +/* +** This routine is called by the parser to process a DETACH statement: +** +** DETACH DATABASE dbname +** +** The pDbname argument is the name of the database in the DETACH statement. +*/ +void sqlite3Detach(Parse *pParse, Token *pDbname){ + int i; + sqlite3 *db; + Vdbe *v; + Db *pDb = 0; + + v = sqlite3GetVdbe(pParse); + if( !v ) return; + sqlite3VdbeAddOp(v, OP_Expire, 0, 0); + sqlite3VdbeAddOp(v, OP_Halt, 0, 0); + if( pParse->explain ) return; + db = pParse->db; + for(i=0; inDb; i++){ + pDb = &db->aDb[i]; + if( pDb->pBt==0 || pDb->zName==0 ) continue; + if( strlen(pDb->zName)!=pDbname->n ) continue; + if( sqlite3StrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break; + } + if( i>=db->nDb ){ + sqlite3ErrorMsg(pParse, "no such database: %T", pDbname); + return; + } + if( i<2 ){ + sqlite3ErrorMsg(pParse, "cannot detach database %T", pDbname); + return; + } + if( !db->autoCommit ){ + sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction"); + pParse->rc = SQLITE_ERROR; + return; + } +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){ + return; + } +#endif /* SQLITE_OMIT_AUTHORIZATION */ + sqlite3BtreeClose(pDb->pBt); + pDb->pBt = 0; + sqlite3ResetInternalSchema(db, 0); } /* ** Initialize a DbFixer structure. This routine must be called prior ** to passing the structure to one of the sqliteFixAAAA() routines below. Index: SQLite.Interop/src/auth.c ================================================================== --- SQLite.Interop/src/auth.c +++ SQLite.Interop/src/auth.c @@ -12,11 +12,11 @@ ** This file contains code used to implement the sqlite3_set_authorizer() ** API. This facility is an optional feature of the library. Embedded ** systems that do not need this facility may omit it by recompiling ** the library with -DSQLITE_OMIT_AUTHORIZATION=1 ** -** $Id: auth.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: auth.c,v 1.1 2005/03/01 16:04:26 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** All of the code in this file may be omitted by defining a single @@ -110,21 +110,13 @@ Table *pTab; /* The table being read */ const char *zCol; /* Name of the column of the table */ int iSrc; /* Index in pTabList->a[] of table being read */ const char *zDBase; /* Name of database being accessed */ TriggerStack *pStack; /* The stack of current triggers */ - int iDb; /* The index of the database the expression refers to */ if( db->xAuth==0 ) return; - if( pExpr->op==TK_AS ) return; assert( pExpr->op==TK_COLUMN ); - iDb = sqlite3SchemaToIndex(pParse->db, pExpr->pSchema); - if( iDb<0 ){ - /* An attempt to read a column out of a subquery or other - ** temporary table. */ - return; - } for(iSrc=0; pTabList && iSrcnSrc; iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break; } if( iSrc>=0 && pTabList && iSrcnSrc ){ pTab = pTabList->a[iSrc].pTab; @@ -145,18 +137,18 @@ assert( pTab->iPKeynCol ); zCol = pTab->aCol[pTab->iPKey].zName; }else{ zCol = "ROWID"; } - assert( iDb>=0 && iDbnDb ); - zDBase = db->aDb[iDb].zName; + assert( pExpr->iDbnDb ); + zDBase = db->aDb[pExpr->iDb].zName; rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase, pParse->zAuthContext); if( rc==SQLITE_IGNORE ){ pExpr->op = TK_NULL; }else if( rc==SQLITE_DENY ){ - if( db->nDb>2 || iDb!=0 ){ + if( db->nDb>2 || pExpr->iDb!=0 ){ sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited", zDBase, pTab->zName, zCol); }else{ sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited",pTab->zName,zCol); } Index: SQLite.Interop/src/btree.c ================================================================== --- SQLite.Interop/src/btree.c +++ SQLite.Interop/src/btree.c @@ -7,11 +7,11 @@ ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.17 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: btree.c,v 1.1 2005/03/01 16:04:27 rmsimpson Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: @@ -209,15 +209,15 @@ #include "pager.h" #include "btree.h" #include "os.h" #include -/* Round up a number to the next larger multiple of 8. This is used -** to force 8-byte alignment on 64-bit architectures. +/* +** This macro rounds values up so that if the value is an address it +** is guaranteed to be an address that is aligned to an 8-byte boundary. */ -#define ROUND8(x) ((x+7)&~7) - +#define FORCE_ALIGNMENT(X) (((X)+7)&~7) /* The following value is the maximum cell size assuming a maximum page ** size give above. */ #define MX_CELL_SIZE(pBt) (pBt->pageSize-8) @@ -228,28 +228,16 @@ */ #define MX_CELL(pBt) ((pBt->pageSize-8)/3) /* Forward declarations */ typedef struct MemPage MemPage; -typedef struct BtLock BtLock; /* ** This is a magic string that appears at the beginning of every ** SQLite database in order to identify the file as a real database. -** -** You can change this value at compile-time by specifying a -** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The -** header must be exactly 16 bytes including the zero-terminator so -** the string itself should be 15 characters long. If you change -** the header, then your custom library will not be able to read -** databases generated by the standard tools and the standard tools -** will not be able to read databases created by your custom library. -*/ -#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */ -# define SQLITE_FILE_HEADER "SQLite format 3" -#endif -static const char zMagicHeader[] = SQLITE_FILE_HEADER; +** 123456789 123456 */ +static const char zMagicHeader[] = "SQLite format 3"; /* ** Page type flags. An ORed combination of these flags appear as the ** first byte of every BTree page. */ @@ -284,14 +272,14 @@ u16 cellOffset; /* Index in aData of first cell pointer */ u16 idxParent; /* Index in parent of this node */ u16 nFree; /* Number of free bytes on the page */ u16 nCell; /* Number of cells on this page, local and ovfl */ struct _OvflCell { /* Cells that will not fit on aData[] */ - u8 *pCell; /* Pointers to the body of the overflow cell */ - u16 idx; /* Insert this cell before idx-th non-overflow cell */ + u8 *pCell; /* Pointers to the body of the overflow cell */ + u16 idx; /* Insert this cell before idx-th non-overflow cell */ } aOvfl[5]; - BtShared *pBt; /* Pointer back to BTree structure */ + struct Btree *pBt; /* Pointer back to BTree structure */ u8 *aData; /* Pointer back to the start of the page */ Pgno pgno; /* Page number for this page */ MemPage *pParent; /* The parent of this page. NULL for root */ }; @@ -300,36 +288,18 @@ ** to the end. EXTRA_SIZE is the number of bytes of space needed to hold ** that extra information. */ #define EXTRA_SIZE sizeof(MemPage) -/* Btree handle */ -struct Btree { - sqlite3 *pSqlite; - BtShared *pBt; - u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ -}; - -/* -** Btree.inTrans may take one of the following values. -** -** If the shared-data extension is enabled, there may be multiple users -** of the Btree structure. At most one of these may open a write transaction, -** but any number may have active read transactions. Variable Btree.pDb -** points to the handle that owns any current write-transaction. -*/ -#define TRANS_NONE 0 -#define TRANS_READ 1 -#define TRANS_WRITE 2 - /* ** Everything we need to know about an open database */ -struct BtShared { +struct Btree { Pager *pPager; /* The page cache */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ + u8 inTrans; /* True if a transaction is in progress */ u8 inStmt; /* True if we are in a statement subtransaction */ u8 readOnly; /* True if the underlying file is readonly */ u8 maxEmbedFrac; /* Maximum payload as % of total page size */ u8 minEmbedFrac; /* Minimum payload as % of total page size */ u8 minLeafFrac; /* Minimum leaf payload as % of total page size */ @@ -336,26 +306,25 @@ u8 pageSizeFixed; /* True if the page size can no longer be changed */ #ifndef SQLITE_OMIT_AUTOVACUUM u8 autoVacuum; /* True if database supports auto-vacuum */ #endif u16 pageSize; /* Total number of bytes on a page */ + u16 psAligned; /* pageSize rounded up to a multiple of 8 */ u16 usableSize; /* Number of usable bytes on each page */ int maxLocal; /* Maximum local payload in non-LEAFDATA tables */ int minLocal; /* Minimum local payload in non-LEAFDATA tables */ int maxLeaf; /* Maximum local payload in a LEAFDATA table */ int minLeaf; /* Minimum local payload in a LEAFDATA table */ - BusyHandler *pBusyHandler; /* Callback for when there is lock contention */ - u8 inTransaction; /* Transaction state */ - int nRef; /* Number of references to this structure */ - int nTransaction; /* Number of open transactions (read + write) */ - void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ - void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ -#ifndef SQLITE_OMIT_SHARED_CACHE - BtLock *pLock; /* List of locks held on this shared-btree struct */ - BtShared *pNext; /* Next in ThreadData.pBtree linked list */ -#endif }; +typedef Btree Bt; + +/* +** Btree.inTrans may take one of the following values. +*/ +#define TRANS_NONE 0 +#define TRANS_READ 1 +#define TRANS_WRITE 2 /* ** An instance of the following structure is used to hold information ** about a cell. The parseCellPtr() function fills in this structure ** based on information extract from the raw disk page. @@ -375,51 +344,22 @@ ** A cursor is a pointer to a particular entry in the BTree. ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. */ struct BtCursor { - Btree *pBtree; /* The Btree to which this cursor belongs */ + Btree *pBt; /* The Btree to which this cursor belongs */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */ void *pArg; /* First arg to xCompare() */ Pgno pgnoRoot; /* The root page of this tree */ MemPage *pPage; /* Page that contains the entry */ int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ - u8 eState; /* One of the CURSOR_XXX constants (see below) */ -#ifndef SQLITE_OMIT_SHARED_CACHE - void *pKey; - i64 nKey; - int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */ -#endif + u8 isValid; /* TRUE if points to a valid entry */ }; -/* -** Potential values for BtCursor.eState. The first two values (VALID and -** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur -** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined. -** -** CURSOR_VALID: -** Cursor points to a valid entry. getPayload() etc. may be called. -** -** CURSOR_INVALID: -** Cursor does not point to a valid entry. This can happen (for example) -** because the table is empty or because BtreeCursorFirst() has not been -** called. -** -** CURSOR_REQUIRESEEK: -** The table that this cursor was opened on still exists, but has been -** modified since the cursor was last used. The cursor position is saved -** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in -** this state, restoreOrClearCursorPosition() can be called to attempt to seek -** the cursor to the saved position. -*/ -#define CURSOR_INVALID 0 -#define CURSOR_VALID 1 -#define CURSOR_REQUIRESEEK 2 - /* ** The TRACE macro will print high-level status information about the ** btree operation when the global variable sqlite3_btree_trace is ** enabled. */ @@ -432,11 +372,11 @@ int sqlite3_btree_trace=0; /* True to enable tracing */ /* ** Forward declaration */ -static int checkReadLocks(BtShared*,Pgno,BtCursor*); +static int checkReadLocks(Btree*,Pgno,BtCursor*); /* ** Read or write a two- and four-byte big-endian integer values. */ static u32 get2byte(unsigned char *p){ @@ -469,278 +409,10 @@ ** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They ** should possibly be consolidated (presumably in pager.h). */ #define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1) -/* -** A linked list of the following structures is stored at BtShared.pLock. -** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor -** is opened on the table with root page BtShared.iTable. Locks are removed -** from this list when a transaction is committed or rolled back, or when -** a btree handle is closed. -*/ -struct BtLock { - Btree *pBtree; /* Btree handle holding this lock */ - Pgno iTable; /* Root page of table */ - u8 eLock; /* READ_LOCK or WRITE_LOCK */ - BtLock *pNext; /* Next in BtShared.pLock list */ -}; - -/* Candidate values for BtLock.eLock */ -#define READ_LOCK 1 -#define WRITE_LOCK 2 - -#ifdef SQLITE_OMIT_SHARED_CACHE - /* - ** The functions queryTableLock(), lockTable() and unlockAllTables() - ** manipulate entries in the BtShared.pLock linked list used to store - ** shared-cache table level locks. If the library is compiled with the - ** shared-cache feature disabled, then there is only ever one user - ** of each BtShared structure and so this locking is not necessary. - ** So define the lock related functions as no-ops. - */ - #define queryTableLock(a,b,c) SQLITE_OK - #define lockTable(a,b,c) SQLITE_OK - #define unlockAllTables(a) - #define restoreOrClearCursorPosition(a,b) SQLITE_OK - #define saveAllCursors(a,b,c) SQLITE_OK - -#else - -/* -** Save the current cursor position in the variables BtCursor.nKey -** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. -*/ -static int saveCursorPosition(BtCursor *pCur){ - int rc = SQLITE_OK; - - assert( CURSOR_VALID==pCur->eState|| CURSOR_INVALID==pCur->eState ); - assert( 0==pCur->pKey ); - - if( pCur->eState==CURSOR_VALID ){ - rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); - - /* If this is an intKey table, then the above call to BtreeKeySize() - ** stores the integer key in pCur->nKey. In this case this value is - ** all that is required. Otherwise, if pCur is not open on an intKey - ** table, then malloc space for and store the pCur->nKey bytes of key - ** data. - */ - if( rc==SQLITE_OK && 0==pCur->pPage->intKey){ - void *pKey = sqliteMalloc(pCur->nKey); - if( pKey ){ - rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey); - if( rc==SQLITE_OK ){ - pCur->pKey = pKey; - }else{ - sqliteFree(pKey); - } - }else{ - rc = SQLITE_NOMEM; - } - } - assert( !pCur->pPage->intKey || !pCur->pKey ); - - /* Todo: Should we drop the reference to pCur->pPage here? */ - - if( rc==SQLITE_OK ){ - pCur->eState = CURSOR_REQUIRESEEK; - } - } - - return rc; -} - -/* -** Save the positions of all cursors except pExcept open on the table -** with root-page iRoot. Usually, this is called just before cursor -** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). -*/ -static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ - BtCursor *p; - if( sqlite3ThreadDataReadOnly()->useSharedData ){ - for(p=pBt->pCursor; p; p=p->pNext){ - if( p!=pExcept && p->pgnoRoot==iRoot && p->eState==CURSOR_VALID ){ - int rc = saveCursorPosition(p); - if( SQLITE_OK!=rc ){ - return rc; - } - } - } - } - return SQLITE_OK; -} - -/* -** Restore the cursor to the position it was in (or as close to as possible) -** when saveCursorPosition() was called. Note that this call deletes the -** saved position info stored by saveCursorPosition(), so there can be -** at most one effective restoreOrClearCursorPosition() call after each -** saveCursorPosition(). -** -** If the second argument argument - doSeek - is false, then instead of -** returning the cursor to it's saved position, any saved position is deleted -** and the cursor state set to CURSOR_INVALID. -*/ -static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){ - int rc = SQLITE_OK; - assert( sqlite3ThreadDataReadOnly()->useSharedData ); - assert( pCur->eState==CURSOR_REQUIRESEEK ); - if( doSeek ){ - rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip); - }else{ - pCur->eState = CURSOR_INVALID; - } - if( rc==SQLITE_OK ){ - sqliteFree(pCur->pKey); - pCur->pKey = 0; - assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState ); - } - return rc; -} - -#define restoreOrClearCursorPosition(p,x) \ - (p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK) - -/* -** Query to see if btree handle p may obtain a lock of type eLock -** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return -** SQLITE_OK if the lock may be obtained (by calling lockTable()), or -** SQLITE_LOCKED if not. -*/ -static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ - BtShared *pBt = p->pBt; - BtLock *pIter; - - /* This is a no-op if the shared-cache is not enabled */ - if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){ - return SQLITE_OK; - } - - /* This (along with lockTable()) is where the ReadUncommitted flag is - ** dealt with. If the caller is querying for a read-lock and the flag is - ** set, it is unconditionally granted - even if there are write-locks - ** on the table. If a write-lock is requested, the ReadUncommitted flag - ** is not considered. - ** - ** In function lockTable(), if a read-lock is demanded and the - ** ReadUncommitted flag is set, no entry is added to the locks list - ** (BtShared.pLock). - ** - ** To summarize: If the ReadUncommitted flag is set, then read cursors do - ** not create or respect table locks. The locking procedure for a - ** write-cursor does not change. - */ - if( - !p->pSqlite || - 0==(p->pSqlite->flags&SQLITE_ReadUncommitted) || - eLock==WRITE_LOCK || - iTab==MASTER_ROOT - ){ - for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ - if( pIter->pBtree!=p && pIter->iTable==iTab && - (pIter->eLock!=eLock || eLock!=READ_LOCK) ){ - return SQLITE_LOCKED; - } - } - } - return SQLITE_OK; -} - -/* -** Add a lock on the table with root-page iTable to the shared-btree used -** by Btree handle p. Parameter eLock must be either READ_LOCK or -** WRITE_LOCK. -** -** SQLITE_OK is returned if the lock is added successfully. SQLITE_BUSY and -** SQLITE_NOMEM may also be returned. -*/ -static int lockTable(Btree *p, Pgno iTable, u8 eLock){ - BtShared *pBt = p->pBt; - BtLock *pLock = 0; - BtLock *pIter; - - /* This is a no-op if the shared-cache is not enabled */ - if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){ - return SQLITE_OK; - } - - assert( SQLITE_OK==queryTableLock(p, iTable, eLock) ); - - /* If the read-uncommitted flag is set and a read-lock is requested, - ** return early without adding an entry to the BtShared.pLock list. See - ** comment in function queryTableLock() for more info on handling - ** the ReadUncommitted flag. - */ - if( - (p->pSqlite) && - (p->pSqlite->flags&SQLITE_ReadUncommitted) && - (eLock==READ_LOCK) && - iTable!=MASTER_ROOT - ){ - return SQLITE_OK; - } - - /* First search the list for an existing lock on this table. */ - for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ - if( pIter->iTable==iTable && pIter->pBtree==p ){ - pLock = pIter; - break; - } - } - - /* If the above search did not find a BtLock struct associating Btree p - ** with table iTable, allocate one and link it into the list. - */ - if( !pLock ){ - pLock = (BtLock *)sqliteMalloc(sizeof(BtLock)); - if( !pLock ){ - return SQLITE_NOMEM; - } - pLock->iTable = iTable; - pLock->pBtree = p; - pLock->pNext = pBt->pLock; - pBt->pLock = pLock; - } - - /* Set the BtLock.eLock variable to the maximum of the current lock - ** and the requested lock. This means if a write-lock was already held - ** and a read-lock requested, we don't incorrectly downgrade the lock. - */ - assert( WRITE_LOCK>READ_LOCK ); - if( eLock>pLock->eLock ){ - pLock->eLock = eLock; - } - - return SQLITE_OK; -} - -/* -** Release all the table locks (locks obtained via calls to the lockTable() -** procedure) held by Btree handle p. -*/ -static void unlockAllTables(Btree *p){ - BtLock **ppIter = &p->pBt->pLock; - - /* If the shared-cache extension is not enabled, there should be no - ** locks in the BtShared.pLock list, making this procedure a no-op. Assert - ** that this is the case. - */ - assert( sqlite3ThreadDataReadOnly()->useSharedData || 0==*ppIter ); - - while( *ppIter ){ - BtLock *pLock = *ppIter; - if( pLock->pBtree==p ){ - *ppIter = pLock->pNext; - sqliteFree(pLock); - }else{ - ppIter = &pLock->pNext; - } - } -} -#endif /* SQLITE_OMIT_SHARED_CACHE */ - #ifndef SQLITE_OMIT_AUTOVACUUM /* ** These macros define the location of the pointer-map entry for a ** database page. The first argument to each is the number of usable ** bytes on each page of the database (often 1024). The second is the @@ -801,19 +473,19 @@ ** ** This routine updates the pointer map entry for page number 'key' ** so that it maps to type 'eType' and parent page number 'pgno'. ** An error code is returned if something goes wrong, otherwise SQLITE_OK. */ -static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){ +static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){ u8 *pPtrmap; /* The pointer map page */ Pgno iPtrmap; /* The pointer map page number */ int offset; /* Offset in pointer map page */ int rc; assert( pBt->autoVacuum ); if( key==0 ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; } iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key); rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap); if( rc!=SQLITE_OK ){ return rc; @@ -838,11 +510,11 @@ ** ** This routine retrieves the pointer map entry for page 'key', writing ** the type and parent page number to *pEType and *pPgno respectively. ** An error code is returned if something goes wrong, otherwise SQLITE_OK. */ -static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ +static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ int iPtrmap; /* Pointer map page index */ u8 *pPtrmap; /* Pointer map page data */ int offset; /* Offset of entry in pointer map */ int rc; @@ -855,11 +527,11 @@ offset = PTRMAP_PTROFFSET(pBt->usableSize, key); if( pEType ) *pEType = pPtrmap[offset]; if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); sqlite3pager_unref(pPtrmap); - if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT; + if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT; return SQLITE_OK; } #endif /* SQLITE_OMIT_AUTOVACUUM */ @@ -1039,11 +711,11 @@ u8 *used; used = sqliteMallocRaw( pPage->pBt->pageSize ); if( used==0 ) return; usableSize = pPage->pBt->usableSize; - assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] ); + assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->psAligned] ); hdr = pPage->hdrOffset; assert( hdr==(pPage->pgno==1 ? 100 : 0) ); assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) ); c = pPage->aData[hdr]; if( pPage->isInit ){ @@ -1105,24 +777,14 @@ #define pageIntegrity(X) _pageIntegrity(X) #else # define pageIntegrity(X) #endif -/* A bunch of assert() statements to check the transaction state variables -** of handle p (type Btree*) are internally consistent. -*/ -#define btreeIntegrity(p) \ - assert( p->inTrans!=TRANS_NONE || p->pBt->nTransactionpBt->nRef ); \ - assert( p->pBt->nTransaction<=p->pBt->nRef ); \ - assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \ - assert( p->pBt->inTransaction>=p->inTrans ); - /* ** Defragment the page given. All Cells are moved to the -** end of the page and all free space is collected into one -** big FreeBlk that occurs in between the header and cell -** pointer array and the cell content area. +** beginning of the page and all free space is collected +** into one big FreeBlk at the end of the page. */ static int defragmentPage(MemPage *pPage){ int i; /* Loop counter */ int pc; /* Address of a i-th cell */ int addr; /* Offset of first byte after cell pointer array */ @@ -1302,11 +964,11 @@ /* ** Decode the flags byte (the first byte of the header) for a page ** and initialize fields of the MemPage structure accordingly. */ static void decodeFlags(MemPage *pPage, int flagByte){ - BtShared *pBt; /* A copy of pPage->pBt */ + Btree *pBt; /* A copy of pPage->pBt */ assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0; pPage->zeroData = (flagByte & PTF_ZERODATA)!=0; pPage->leaf = (flagByte & PTF_LEAF)!=0; @@ -1342,24 +1004,24 @@ MemPage *pParent /* The parent. Might be NULL */ ){ int pc; /* Address of a freeblock within pPage->aData[] */ int hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ - BtShared *pBt; /* The main btree structure */ + Btree *pBt; /* The main btree structure */ int usableSize; /* Amount of usable space on each page */ int cellOffset; /* Offset from start of page to first cell pointer */ int nFree; /* Number of unused bytes on the page */ int top; /* First byte of the cell content area */ pBt = pPage->pBt; assert( pBt!=0 ); assert( pParent==0 || pParent->pBt==pBt ); assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) ); - assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] ); + assert( pPage->aData == &((unsigned char*)pPage)[-pBt->psAligned] ); if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){ /* The parent page should never change unless the file is corrupt */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } if( pPage->isInit ) return SQLITE_OK; if( pPage->pParent==0 && pParent!=0 ){ pPage->pParent = pParent; sqlite3pager_ref(pParent->aData); @@ -1373,39 +1035,39 @@ pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf; top = get2byte(&data[hdr+5]); pPage->nCell = get2byte(&data[hdr+3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){ /* All pages must have at least one cell, except for root pages */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } /* Compute the total free space on the page */ pc = get2byte(&data[hdr+1]); nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell); while( pc>0 ){ int next, size; if( pc>usableSize-4 ){ /* Free block is off the page */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); if( next>0 && next<=pc+size+3 ){ /* Free blocks must be in accending order */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } nFree += size; pc = next; } pPage->nFree = nFree; if( nFree>=usableSize ){ /* Free space cannot exceed total page size */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } pPage->isInit = 1; pageIntegrity(pPage); return SQLITE_OK; @@ -1415,16 +1077,16 @@ ** Set up a raw page so that it looks like a database page holding ** no entries. */ static void zeroPage(MemPage *pPage, int flags){ unsigned char *data = pPage->aData; - BtShared *pBt = pPage->pBt; + Btree *pBt = pPage->pBt; int hdr = pPage->hdrOffset; int first; assert( sqlite3pager_pagenumber(data)==pPage->pgno ); - assert( &data[pBt->pageSize] == (unsigned char*)pPage ); + assert( &data[pBt->psAligned] == (unsigned char*)pPage ); assert( sqlite3pager_iswriteable(data) ); memset(&data[hdr], 0, pBt->usableSize - hdr); data[hdr] = flags; first = hdr + 8 + 4*((flags&PTF_LEAF)==0); memset(&data[hdr+1], 0, 4); @@ -1443,17 +1105,17 @@ /* ** Get a page from the pager. Initialize the MemPage.pBt and ** MemPage.aData elements if needed. */ -static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){ +static int getPage(Btree *pBt, Pgno pgno, MemPage **ppPage){ int rc; unsigned char *aData; MemPage *pPage; rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData); if( rc ) return rc; - pPage = (MemPage*)&aData[pBt->pageSize]; + pPage = (MemPage*)&aData[pBt->psAligned]; pPage->aData = aData; pPage->pBt = pBt; pPage->pgno = pgno; pPage->hdrOffset = pPage->pgno==1 ? 100 : 0; *ppPage = pPage; @@ -1464,18 +1126,18 @@ ** Get a page from the pager and initialize it. This routine ** is just a convenience wrapper around separate calls to ** getPage() and initPage(). */ static int getAndInitPage( - BtShared *pBt, /* The database file */ + Btree *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ MemPage **ppPage, /* Write the page pointer here */ MemPage *pParent /* Parent of the page */ ){ int rc; if( pgno==0 ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } rc = getPage(pBt, pgno, ppPage); if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){ rc = initPage(*ppPage, pParent); } @@ -1488,11 +1150,11 @@ */ static void releasePage(MemPage *pPage){ if( pPage ){ assert( pPage->aData ); assert( pPage->pBt ); - assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage ); + assert( &pPage->aData[pPage->pBt->psAligned]==(unsigned char*)pPage ); sqlite3pager_unref(pPage->aData); } } /* @@ -1499,13 +1161,11 @@ ** This routine is called when the reference count for a page ** reaches zero. We need to unref the pParent pointer when that ** happens. */ static void pageDestructor(void *pData, int pageSize){ - MemPage *pPage; - assert( (pageSize & 7)==0 ); - pPage = (MemPage*)&((char*)pData)[pageSize]; + MemPage *pPage = (MemPage*)&((char*)pData)[FORCE_ALIGNMENT(pageSize)]; if( pPage->pParent ){ MemPage *pParent = pPage->pParent; pPage->pParent = 0; releasePage(pParent); } @@ -1519,13 +1179,11 @@ ** ** This routine needs to reset the extra data section at the end of the ** page to agree with the restored data. */ static void pageReinit(void *pData, int pageSize){ - MemPage *pPage; - assert( (pageSize & 7)==0 ); - pPage = (MemPage*)&((char*)pData)[pageSize]; + MemPage *pPage = (MemPage*)&((char*)pData)[FORCE_ALIGNMENT(pageSize)]; if( pPage->isInit ){ pPage->isInit = 0; initPage(pPage, pPage->pParent); } } @@ -1537,65 +1195,17 @@ ** a new database with a random name is created. This randomly named ** database file will be deleted when sqlite3BtreeClose() is called. */ int sqlite3BtreeOpen( const char *zFilename, /* Name of the file containing the BTree database */ - sqlite3 *pSqlite, /* Associated database handle */ Btree **ppBtree, /* Pointer to new Btree object written here */ int flags /* Options */ ){ - BtShared *pBt; /* Shared part of btree structure */ - Btree *p; /* Handle to return */ + Btree *pBt; int rc; int nReserve; unsigned char zDbHeader[100]; -#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) - const ThreadData *pTsdro; -#endif - - /* Set the variable isMemdb to true for an in-memory database, or - ** false for a file-based database. This symbol is only required if - ** either of the shared-data or autovacuum features are compiled - ** into the library. - */ -#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM) - #ifdef SQLITE_OMIT_MEMORYDB - const int isMemdb = !zFilename; - #else - const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1); - #endif -#endif - - p = sqliteMalloc(sizeof(Btree)); - if( !p ){ - return SQLITE_NOMEM; - } - p->inTrans = TRANS_NONE; - p->pSqlite = pSqlite; - - /* Try to find an existing Btree structure opened on zFilename. */ -#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) - pTsdro = sqlite3ThreadDataReadOnly(); - if( pTsdro->useSharedData && zFilename && !isMemdb ){ - char *zFullPathname = sqlite3OsFullPathname(zFilename); - if( !zFullPathname ){ - sqliteFree(p); - return SQLITE_NOMEM; - } - for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){ - assert( pBt->nRef>0 ); - if( 0==strcmp(zFullPathname, sqlite3pager_filename(pBt->pPager)) ){ - p->pBt = pBt; - *ppBtree = p; - pBt->nRef++; - sqliteFree(zFullPathname); - return SQLITE_OK; - } - } - sqliteFree(zFullPathname); - } -#endif /* ** The following asserts make sure that structures used by the btree are ** the right size. This is to guard against size changes that result ** when compiling on a different architecture. @@ -1603,36 +1213,33 @@ assert( sizeof(i64)==8 ); assert( sizeof(u64)==8 ); assert( sizeof(u32)==4 ); assert( sizeof(u16)==2 ); assert( sizeof(Pgno)==4 ); + assert( sizeof(ptr)==sizeof(char*) ); + assert( sizeof(uptr)==sizeof(ptr) ); pBt = sqliteMalloc( sizeof(*pBt) ); if( pBt==0 ){ *ppBtree = 0; - sqliteFree(p); return SQLITE_NOMEM; } rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags); if( rc!=SQLITE_OK ){ if( pBt->pPager ) sqlite3pager_close(pBt->pPager); sqliteFree(pBt); - sqliteFree(p); *ppBtree = 0; return rc; } - p->pBt = pBt; - sqlite3pager_set_destructor(pBt->pPager, pageDestructor); sqlite3pager_set_reiniter(pBt->pPager, pageReinit); pBt->pCursor = 0; pBt->pPage1 = 0; pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager); sqlite3pager_read_fileheader(pBt->pPager, sizeof(zDbHeader), zDbHeader); pBt->pageSize = get2byte(&zDbHeader[16]); - if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE - || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ + if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE ){ pBt->pageSize = SQLITE_DEFAULT_PAGE_SIZE; pBt->maxEmbedFrac = 64; /* 25% */ pBt->minEmbedFrac = 32; /* 12.5% */ pBt->minLeafFrac = 32; /* 12.5% */ #ifndef SQLITE_OMIT_AUTOVACUUM @@ -1640,11 +1247,15 @@ ** do not set the auto-vacuum flag, even if SQLITE_DEFAULT_AUTOVACUUM ** is true. On the other hand, if SQLITE_OMIT_MEMORYDB has been defined, ** then ":memory:" is just a regular file-name. Respect the auto-vacuum ** default in this case. */ - if( zFilename && !isMemdb ){ +#ifndef SQLITE_OMIT_MEMORYDB + if( zFilename && strcmp(zFilename,":memory:") ){ +#else + if( zFilename ){ +#endif pBt->autoVacuum = SQLITE_DEFAULT_AUTOVACUUM; } #endif nReserve = 0; }else{ @@ -1656,94 +1267,32 @@ #ifndef SQLITE_OMIT_AUTOVACUUM pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0); #endif } pBt->usableSize = pBt->pageSize - nReserve; - assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ + pBt->psAligned = FORCE_ALIGNMENT(pBt->pageSize); sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize); - -#ifndef SQLITE_OMIT_SHARED_CACHE - /* Add the new btree to the linked list starting at ThreadData.pBtree */ - if( pTsdro->useSharedData && zFilename && !isMemdb ){ - pBt->pNext = pTsdro->pBtree; - sqlite3ThreadData()->pBtree = pBt; - } -#endif - pBt->nRef = 1; - *ppBtree = p; + *ppBtree = pBt; return SQLITE_OK; } /* ** Close an open database and invalidate all cursors. */ -int sqlite3BtreeClose(Btree *p){ - BtShared *pBt = p->pBt; - BtCursor *pCur; - -#ifndef SQLITE_OMIT_SHARED_CACHE - ThreadData *pTsd; -#endif - - /* Drop any table-locks */ - unlockAllTables(p); - - /* Close all cursors opened via this handle. */ - pCur = pBt->pCursor; - while( pCur ){ - BtCursor *pTmp = pCur; - pCur = pCur->pNext; - if( pTmp->pBtree==p ){ - sqlite3BtreeCloseCursor(pTmp); - } - } - - /* Rollback any active transaction and free the handle structure */ - sqlite3BtreeRollback(p); - sqliteFree(p); - -#ifndef SQLITE_OMIT_SHARED_CACHE - /* If there are still other outstanding references to the shared-btree - ** structure, return now. The remainder of this procedure cleans - ** up the shared-btree. - */ - assert( pBt->nRef>0 ); - pBt->nRef--; - if( pBt->nRef ){ - return SQLITE_OK; - } - - /* Remove the shared-btree from the thread wide list */ - pTsd = sqlite3ThreadData(); - if( pTsd->pBtree==pBt ){ - pTsd->pBtree = pBt->pNext; - }else{ - BtShared *pPrev; - for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext); - if( pPrev ){ - pPrev->pNext = pBt->pNext; - } - } -#endif - - /* Close the pager and free the shared-btree structure */ - assert( !pBt->pCursor ); - sqlite3pager_close(pBt->pPager); - if( pBt->xFreeSchema && pBt->pSchema ){ - pBt->xFreeSchema(pBt->pSchema); - } - sqliteFree(pBt->pSchema); +int sqlite3BtreeClose(Btree *pBt){ + while( pBt->pCursor ){ + sqlite3BtreeCloseCursor(pBt->pCursor); + } + sqlite3pager_close(pBt->pPager); sqliteFree(pBt); return SQLITE_OK; } /* ** Change the busy handler callback function. */ -int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){ - BtShared *pBt = p->pBt; - pBt->pBusyHandler = pHandler; +int sqlite3BtreeSetBusyHandler(Btree *pBt, BusyHandler *pHandler){ sqlite3pager_set_busyhandler(pBt->pPager, pHandler); return SQLITE_OK; } /* @@ -1759,12 +1308,11 @@ ** an abrupt power failure when synchronous is off, the database ** could be left in an inconsistent and unrecoverable state. ** Synchronous is on by default so database corruption is not ** normally a worry. */ -int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ - BtShared *pBt = p->pBt; +int sqlite3BtreeSetCacheSize(Btree *pBt, int mxPage){ sqlite3pager_set_cachesize(pBt->pPager, mxPage); return SQLITE_OK; } /* @@ -1774,27 +1322,16 @@ ** there is a high probability of damage) Level 2 is the default. There ** is a very low but non-zero probability of damage. Level 3 reduces the ** probability of damage to near zero but with a write performance reduction. */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS -int sqlite3BtreeSetSafetyLevel(Btree *p, int level){ - BtShared *pBt = p->pBt; +int sqlite3BtreeSetSafetyLevel(Btree *pBt, int level){ sqlite3pager_set_safety_level(pBt->pPager, level); return SQLITE_OK; } #endif -/* -** Return TRUE if the given btree is set to safety level 1. In other -** words, return TRUE if no sync() occurs on the disk files. -*/ -int sqlite3BtreeSyncDisabled(Btree *p){ - BtShared *pBt = p->pBt; - assert( pBt && pBt->pPager ); - return sqlite3pager_nosync(pBt->pPager); -} - #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) /* ** Change the default pages size and the number of reserved bytes per page. ** ** The page size must be a power of 2 between 512 and 65536. If the page @@ -1807,47 +1344,45 @@ ** at the beginning of a page. ** ** If parameter nReserve is less than zero, then the number of reserved ** bytes per page is left unchanged. */ -int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){ - BtShared *pBt = p->pBt; +int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){ if( pBt->pageSizeFixed ){ return SQLITE_READONLY; } if( nReserve<0 ){ nReserve = pBt->pageSize - pBt->usableSize; } if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && ((pageSize-1)&pageSize)==0 ){ - assert( (pageSize & 7)==0 ); - assert( !pBt->pPage1 && !pBt->pCursor ); - pBt->pageSize = sqlite3pager_set_pagesize(pBt->pPager, pageSize); + pBt->pageSize = pageSize; + pBt->psAligned = FORCE_ALIGNMENT(pageSize); + sqlite3pager_set_pagesize(pBt->pPager, pageSize); } pBt->usableSize = pBt->pageSize - nReserve; return SQLITE_OK; } /* ** Return the currently defined page size */ -int sqlite3BtreeGetPageSize(Btree *p){ - return p->pBt->pageSize; +int sqlite3BtreeGetPageSize(Btree *pBt){ + return pBt->pageSize; } -int sqlite3BtreeGetReserve(Btree *p){ - return p->pBt->pageSize - p->pBt->usableSize; +int sqlite3BtreeGetReserve(Btree *pBt){ + return pBt->pageSize - pBt->usableSize; } #endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */ /* ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' ** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it ** is disabled. The default value for the auto-vacuum property is ** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. */ -int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ - BtShared *pBt = p->pBt;; +int sqlite3BtreeSetAutoVacuum(Btree *pBt, int autoVacuum){ #ifdef SQLITE_OMIT_AUTOVACUUM return SQLITE_READONLY; #else if( pBt->pageSizeFixed ){ return SQLITE_READONLY; @@ -1859,15 +1394,15 @@ /* ** Return the value of the 'auto-vacuum' property. If auto-vacuum is ** enabled 1 is returned. Otherwise 0. */ -int sqlite3BtreeGetAutoVacuum(Btree *p){ +int sqlite3BtreeGetAutoVacuum(Btree *pBt){ #ifdef SQLITE_OMIT_AUTOVACUUM return 0; #else - return p->pBt->autoVacuum; + return pBt->autoVacuum; #endif } /* @@ -1878,12 +1413,12 @@ ** well-formed database file, then SQLITE_CORRUPT is returned. ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM ** is returned if we run out of memory. SQLITE_PROTOCOL is returned ** if there is a locking protocol violation. */ -static int lockBtree(BtShared *pBt){ - int rc, pageSize; +static int lockBtree(Btree *pBt){ + int rc; MemPage *pPage1; if( pBt->pPage1 ) return SQLITE_OK; rc = getPage(pBt, 1, &pPage1); if( rc!=SQLITE_OK ) return rc; @@ -1898,20 +1433,16 @@ goto page1_init_failed; } if( page1[18]>1 || page1[19]>1 ){ goto page1_init_failed; } - pageSize = get2byte(&page1[16]); - if( ((pageSize-1)&pageSize)!=0 ){ - goto page1_init_failed; - } - assert( (pageSize & 7)==0 ); - pBt->pageSize = pageSize; - pBt->usableSize = pageSize - page1[20]; + pBt->pageSize = get2byte(&page1[16]); + pBt->usableSize = pBt->pageSize - page1[20]; if( pBt->usableSize<500 ){ goto page1_init_failed; } + pBt->psAligned = FORCE_ALIGNMENT(pBt->pageSize); pBt->maxEmbedFrac = page1[21]; pBt->minEmbedFrac = page1[22]; pBt->minLeafFrac = page1[23]; #ifndef SQLITE_OMIT_AUTOVACUUM pBt->autoVacuum = (get4byte(&page1[36 + 4*4])?1:0); @@ -1946,31 +1477,10 @@ releasePage(pPage1); pBt->pPage1 = 0; return rc; } -/* -** This routine works like lockBtree() except that it also invokes the -** busy callback if there is lock contention. -*/ -static int lockBtreeWithRetry(Btree *pRef){ - int rc = SQLITE_OK; - if( pRef->inTrans==TRANS_NONE ){ - u8 inTransaction = pRef->pBt->inTransaction; - btreeIntegrity(pRef); - rc = sqlite3BtreeBeginTrans(pRef, 0); - pRef->pBt->inTransaction = inTransaction; - pRef->inTrans = TRANS_NONE; - if( rc==SQLITE_OK ){ - pRef->pBt->nTransaction--; - } - btreeIntegrity(pRef); - } - return rc; -} - - /* ** If there are no outstanding cursors and we are not in the middle ** of a transaction but there is a read lock on the database, then ** this routine unrefs the first page of the database file which ** has the effect of releasing the read lock. @@ -1977,15 +1487,15 @@ ** ** If there are any outstanding cursors, this routine is a no-op. ** ** If there is a transaction in progress, this routine is a no-op. */ -static void unlockBtreeIfUnused(BtShared *pBt){ - if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ +static void unlockBtreeIfUnused(Btree *pBt){ + if( pBt->inTrans==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ if( pBt->pPage1->aData==0 ){ MemPage *pPage = pBt->pPage1; - pPage->aData = &((u8*)pPage)[-pBt->pageSize]; + pPage->aData = &((char*)pPage)[-pBt->psAligned]; pPage->pBt = pBt; pPage->pgno = 1; } releasePage(pBt->pPage1); pBt->pPage1 = 0; @@ -1995,11 +1505,11 @@ /* ** Create a new database by initializing the first page of the ** file. */ -static int newDatabase(BtShared *pBt){ +static int newDatabase(Btree *pBt){ MemPage *pP1; unsigned char *data; int rc; if( sqlite3pager_pagecount(pBt->pPager)>0 ) return SQLITE_OK; pP1 = pBt->pPage1; @@ -2031,11 +1541,11 @@ ** Attempt to start a new transaction. A write-transaction ** is started if the second argument is nonzero, otherwise a read- ** transaction. If the second argument is 2 or more and exclusive ** transaction is started, meaning that no other process is allowed ** to access the database. A preexisting transaction may not be -** upgraded to exclusive by calling this routine a second time - the +** upgrade to exclusive by calling this routine a second time - the ** exclusivity flag only works for a new transaction. ** ** A write-transaction must be started before attempting any ** changes to the database. None of the following routines ** will work unless a transaction is started first: @@ -2046,82 +1556,47 @@ ** sqlite3BtreeDropTable() ** sqlite3BtreeInsert() ** sqlite3BtreeDelete() ** sqlite3BtreeUpdateMeta() ** -** If an initial attempt to acquire the lock fails because of lock contention -** and the database was previously unlocked, then invoke the busy handler -** if there is one. But if there was previously a read-lock, do not -** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is -** returned when there is already a read-lock in order to avoid a deadlock. -** -** Suppose there are two processes A and B. A has a read lock and B has -** a reserved lock. B tries to promote to exclusive but is blocked because -** of A's read lock. A tries to promote to reserved but is blocked by B. -** One or the other of the two processes must give way or there can be -** no progress. By returning SQLITE_BUSY and not invoking the busy callback -** when A already has a read lock, we encourage A to give up and let B -** proceed. +** If wrflag is true, then nMaster specifies the maximum length of +** a master journal file name supplied later via sqlite3BtreeSync(). +** This is so that appropriate space can be allocated in the journal file +** when it is created.. */ -int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ - BtShared *pBt = p->pBt; +int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){ int rc = SQLITE_OK; - btreeIntegrity(p); - /* If the btree is already in a write-transaction, or it ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ - if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ + if( pBt->inTrans==TRANS_WRITE || + (pBt->inTrans==TRANS_READ && !wrflag) ){ return SQLITE_OK; } - - /* Write transactions are not possible on a read-only database */ if( pBt->readOnly && wrflag ){ return SQLITE_READONLY; } - /* If another database handle has already opened a write transaction - ** on this shared-btree structure and a second write transaction is - ** requested, return SQLITE_BUSY. - */ - if( pBt->inTransaction==TRANS_WRITE && wrflag ){ - return SQLITE_BUSY; - } - - do { - if( pBt->pPage1==0 ){ - rc = lockBtree(pBt); - } - - if( rc==SQLITE_OK && wrflag ){ - rc = sqlite3pager_begin(pBt->pPage1->aData, wrflag>1); - if( rc==SQLITE_OK ){ - rc = newDatabase(pBt); - } - } - - if( rc==SQLITE_OK ){ - if( wrflag ) pBt->inStmt = 0; - }else{ - unlockBtreeIfUnused(pBt); - } - }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && - sqlite3InvokeBusyHandler(pBt->pBusyHandler) ); - - if( rc==SQLITE_OK ){ - if( p->inTrans==TRANS_NONE ){ - pBt->nTransaction++; - } - p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); - if( p->inTrans>pBt->inTransaction ){ - pBt->inTransaction = p->inTrans; - } - } - - btreeIntegrity(p); + if( pBt->pPage1==0 ){ + rc = lockBtree(pBt); + } + + if( rc==SQLITE_OK && wrflag ){ + rc = sqlite3pager_begin(pBt->pPage1->aData, wrflag>1); + if( rc==SQLITE_OK ){ + rc = newDatabase(pBt); + } + } + + if( rc==SQLITE_OK ){ + pBt->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); + if( wrflag ) pBt->inStmt = 0; + }else{ + unlockBtreeIfUnused(pBt); + } return rc; } #ifndef SQLITE_OMIT_AUTOVACUUM @@ -2132,11 +1607,11 @@ */ static int setChildPtrmaps(MemPage *pPage){ int i; /* Counter variable */ int nCell; /* Number of cells in page pPage */ int rc = SQLITE_OK; /* Return code */ - BtShared *pBt = pPage->pBt; + Btree *pBt = pPage->pBt; int isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; initPage(pPage, 0); nCell = pPage->nCell; @@ -2183,11 +1658,11 @@ */ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; } put4byte(pPage->aData, iTo); }else{ int isInitOrig = pPage->isInit; int i; @@ -2216,11 +1691,11 @@ } if( i==nCell ){ if( eType!=PTRMAP_BTREE || get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; } put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); } pPage->isInit = isInitOrig; @@ -2232,11 +1707,11 @@ /* ** Move the open database page pDbPage to location iFreePage in the ** database. The pDbPage reference remains valid. */ static int relocatePage( - BtShared *pBt, /* Btree */ + Btree *pBt, /* Btree */ MemPage *pDbPage, /* Open page to move */ u8 eType, /* Pointer map 'type' entry for pDbPage */ Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */ Pgno iFreePage /* The location to move pDbPage to */ ){ @@ -2302,23 +1777,23 @@ } return rc; } /* Forward declaration required by autoVacuumCommit(). */ -static int allocatePage(BtShared *, MemPage **, Pgno *, Pgno, u8); +static int allocatePage(Btree *, MemPage **, Pgno *, Pgno, u8); /* ** This routine is called prior to sqlite3pager_commit when a transaction ** is commited for an auto-vacuum database. */ -static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){ +static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){ Pager *pPager = pBt->pPager; - Pgno nFreeList; /* Number of pages remaining on the free-list. */ - int nPtrMap; /* Number of pointer-map pages deallocated */ - Pgno origSize; /* Pages in the database file */ - Pgno finSize; /* Pages in the database file after truncation */ - int rc; /* Return code */ + Pgno nFreeList; /* Number of pages remaining on the free-list. */ + int nPtrMap; /* Number of pointer-map pages deallocated */ + Pgno origSize; /* Pages in the database file */ + Pgno finSize; /* Pages in the database file after truncation */ + int rc; /* Return code */ u8 eType; int pgsz = pBt->pageSize; /* Page size for this database */ Pgno iDbPage; /* The database page to move */ MemPage *pDbMemPage = 0; /* "" */ Pgno iPtrPage; /* The page that contains a pointer to iDbPage */ @@ -2329,11 +1804,11 @@ int nRef = *sqlite3pager_stats(pPager); #endif assert( pBt->autoVacuum ); if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; } /* Figure out how many free-pages are in the database. If there are no ** free pages, then auto-vacuum is a no-op. */ @@ -2344,11 +1819,11 @@ } origSize = sqlite3pager_pagecount(pPager); nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5); finSize = origSize - nFreeList - nPtrMap; - if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){ + if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){ finSize--; if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){ finSize--; } } @@ -2366,14 +1841,11 @@ continue; } rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage); if( rc!=SQLITE_OK ) goto autovacuum_out; - if( eType==PTRMAP_ROOTPAGE ){ - rc = SQLITE_CORRUPT_BKPT; - goto autovacuum_out; - } + assert( eType!=PTRMAP_ROOTPAGE ); /* If iDbPage is free, do not swap it. */ if( eType==PTRMAP_FREEPAGE ){ continue; } @@ -2397,16 +1869,10 @@ assert( iFreePage<=origSize ); }while( iFreePage>finSize ); releasePage(pFreeMemPage); pFreeMemPage = 0; - /* Relocate the page into the body of the file. Note that although the - ** page has moved within the database file, the pDbMemPage pointer - ** remains valid. This means that this function can run without - ** invalidating cursors open on the btree. This is important in - ** shared-cache mode. - */ rc = relocatePage(pBt, pDbMemPage, eType, iPtrPage, iFreePage); releasePage(pDbMemPage); if( rc!=SQLITE_OK ) goto autovacuum_out; } @@ -2434,80 +1900,50 @@ ** Commit the transaction currently in progress. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqlite3BtreeCommit(Btree *p){ +int sqlite3BtreeCommit(Btree *pBt){ int rc = SQLITE_OK; - BtShared *pBt = p->pBt; - - btreeIntegrity(p); - unlockAllTables(p); - - /* If the handle has a write-transaction open, commit the shared-btrees - ** transaction and set the shared state to TRANS_READ. - */ - if( p->inTrans==TRANS_WRITE ){ - assert( pBt->inTransaction==TRANS_WRITE ); - assert( pBt->nTransaction>0 ); + if( pBt->inTrans==TRANS_WRITE ){ rc = sqlite3pager_commit(pBt->pPager); - pBt->inTransaction = TRANS_READ; - pBt->inStmt = 0; - } - - /* If the handle has any kind of transaction open, decrement the transaction - ** count of the shared btree. If the transaction count reaches 0, set - ** the shared state to TRANS_NONE. The unlockBtreeIfUnused() call below - ** will unlock the pager. - */ - if( p->inTrans!=TRANS_NONE ){ - pBt->nTransaction--; - if( 0==pBt->nTransaction ){ - pBt->inTransaction = TRANS_NONE; - } - } - - /* Set the handles current transaction state to TRANS_NONE and unlock - ** the pager if this call closed the only read or write transaction. - */ - p->inTrans = TRANS_NONE; - unlockBtreeIfUnused(pBt); - - btreeIntegrity(p); + } + pBt->inTrans = TRANS_NONE; + pBt->inStmt = 0; + unlockBtreeIfUnused(pBt); return rc; } #ifndef NDEBUG /* ** Return the number of write-cursors open on this handle. This is for use ** in assert() expressions, so it is only compiled if NDEBUG is not ** defined. */ -static int countWriteCursors(BtShared *pBt){ +static int countWriteCursors(Btree *pBt){ BtCursor *pCur; int r = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - if( pCur->wrFlag ) r++; + if( pCur->wrFlag ) r++; } return r; } #endif #ifdef SQLITE_TEST /* ** Print debugging information about all cursors to standard output. */ -void sqlite3BtreeCursorList(Btree *p){ +void sqlite3BtreeCursorList(Btree *pBt){ BtCursor *pCur; - BtShared *pBt = p->pBt; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ MemPage *pPage = pCur->pPage; char *zMode = pCur->wrFlag ? "rw" : "ro"; sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n", pCur, pCur->pgnoRoot, zMode, pPage ? pPage->pgno : 0, pCur->idx, - (pCur->eState==CURSOR_VALID) ? "" : " eof" + pCur->isValid ? "" : " eof" ); } } #endif @@ -2518,45 +1954,26 @@ ** in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqlite3BtreeRollback(Btree *p){ +int sqlite3BtreeRollback(Btree *pBt){ int rc = SQLITE_OK; - BtShared *pBt = p->pBt; MemPage *pPage1; - - btreeIntegrity(p); - unlockAllTables(p); - - if( p->inTrans==TRANS_WRITE ){ - assert( TRANS_WRITE==pBt->inTransaction ); - + if( pBt->inTrans==TRANS_WRITE ){ rc = sqlite3pager_rollback(pBt->pPager); /* The rollback may have destroyed the pPage1->aData value. So ** call getPage() on page 1 again to make sure pPage1->aData is ** set correctly. */ if( getPage(pBt, 1, &pPage1)==SQLITE_OK ){ releasePage(pPage1); } assert( countWriteCursors(pBt)==0 ); - pBt->inTransaction = TRANS_READ; - } - - if( p->inTrans!=TRANS_NONE ){ - assert( pBt->nTransaction>0 ); - pBt->nTransaction--; - if( 0==pBt->nTransaction ){ - pBt->inTransaction = TRANS_NONE; - } - } - - p->inTrans = TRANS_NONE; + } + pBt->inTrans = TRANS_NONE; pBt->inStmt = 0; unlockBtreeIfUnused(pBt); - - btreeIntegrity(p); return rc; } /* ** Start a statement subtransaction. The subtransaction can @@ -2571,17 +1988,15 @@ ** Statement subtransactions are used around individual SQL statements ** that are contained within a BEGIN...COMMIT block. If a constraint ** error occurs within the statement, the effect of that one statement ** can be rolled back without having to rollback the entire transaction. */ -int sqlite3BtreeBeginStmt(Btree *p){ +int sqlite3BtreeBeginStmt(Btree *pBt){ int rc; - BtShared *pBt = p->pBt; - if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){ + if( (pBt->inTrans!=TRANS_WRITE) || pBt->inStmt ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } - assert( pBt->inTransaction==TRANS_WRITE ); rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_stmt_begin(pBt->pPager); pBt->inStmt = 1; return rc; } @@ -2588,13 +2003,12 @@ /* ** Commit the statment subtransaction currently in progress. If no ** subtransaction is active, this is a no-op. */ -int sqlite3BtreeCommitStmt(Btree *p){ +int sqlite3BtreeCommitStmt(Btree *pBt){ int rc; - BtShared *pBt = p->pBt; if( pBt->inStmt && !pBt->readOnly ){ rc = sqlite3pager_stmt_commit(pBt->pPager); }else{ rc = SQLITE_OK; } @@ -2608,13 +2022,12 @@ ** ** All cursors will be invalidated by this operation. Any attempt ** to use a cursor that was open at the beginning of this operation ** will result in an error. */ -int sqlite3BtreeRollbackStmt(Btree *p){ +int sqlite3BtreeRollbackStmt(Btree *pBt){ int rc; - BtShared *pBt = p->pBt; if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK; rc = sqlite3pager_stmt_rollback(pBt->pPager); assert( countWriteCursors(pBt)==0 ); pBt->inStmt = 0; return rc; @@ -2678,20 +2091,19 @@ ** in incorrect operations. If the comparison function is NULL, a ** default comparison function is used. The comparison function is ** always ignored for INTKEY tables. */ int sqlite3BtreeCursor( - Btree *p, /* The btree */ + Btree *pBt, /* The btree */ int iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */ void *pArg, /* First arg to xCompare() */ BtCursor **ppCur /* Write new cursor here */ ){ int rc; BtCursor *pCur; - BtShared *pBt = p->pBt; *ppCur = 0; if( wrFlag ){ if( pBt->readOnly ){ return SQLITE_READONLY; @@ -2698,49 +2110,48 @@ } if( checkReadLocks(pBt, iTable, 0) ){ return SQLITE_LOCKED; } } - if( pBt->pPage1==0 ){ - rc = lockBtreeWithRetry(p); + rc = lockBtree(pBt); if( rc!=SQLITE_OK ){ return rc; } } - pCur = sqliteMalloc( sizeof(*pCur) ); + pCur = sqliteMallocRaw( sizeof(*pCur) ); if( pCur==0 ){ rc = SQLITE_NOMEM; goto create_cursor_exception; } pCur->pgnoRoot = (Pgno)iTable; if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){ rc = SQLITE_EMPTY; + pCur->pPage = 0; goto create_cursor_exception; } + pCur->pPage = 0; /* For exit-handler, in case getAndInitPage() fails. */ rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->pPage, 0); if( rc!=SQLITE_OK ){ goto create_cursor_exception; } - - /* Now that no other errors can occur, finish filling in the BtCursor - ** variables, link the cursor into the BtShared list and set *ppCur (the - ** output argument to this function). - */ pCur->xCompare = xCmp ? xCmp : dfltCompare; pCur->pArg = pArg; - pCur->pBtree = p; + pCur->pBt = pBt; pCur->wrFlag = wrFlag; + pCur->idx = 0; + memset(&pCur->info, 0, sizeof(pCur->info)); pCur->pNext = pBt->pCursor; if( pCur->pNext ){ pCur->pNext->pPrev = pCur; } + pCur->pPrev = 0; pBt->pCursor = pCur; - pCur->eState = CURSOR_INVALID; + pCur->isValid = 0; *ppCur = pCur; - return SQLITE_OK; + create_cursor_exception: if( pCur ){ releasePage(pCur->pPage); sqliteFree(pCur); } @@ -2765,12 +2176,11 @@ /* ** Close a cursor. The read lock on the database file is released ** when the last cursor is closed. */ int sqlite3BtreeCloseCursor(BtCursor *pCur){ - BtShared *pBt = pCur->pBtree->pBt; - restoreOrClearCursorPosition(pCur, 0); + Btree *pBt = pCur->pBt; if( pCur->pPrev ){ pCur->pPrev->pNext = pCur->pNext; }else{ pBt->pCursor = pCur->pNext; } @@ -2833,21 +2243,17 @@ ** ** For a table with the INTKEY flag set, this routine returns the key ** itself, not the number of bytes in the key. */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ - int rc = restoreOrClearCursorPosition(pCur, 1); - if( rc==SQLITE_OK ){ - assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); - if( pCur->eState==CURSOR_INVALID ){ - *pSize = 0; - }else{ - getCellInfo(pCur); - *pSize = pCur->info.nKey; - } - } - return rc; + if( !pCur->isValid ){ + *pSize = 0; + }else{ + getCellInfo(pCur); + *pSize = pCur->info.nKey; + } + return SQLITE_OK; } /* ** Set *pSize to the number of bytes of data in the entry the ** cursor currently points to. Always return SQLITE_OK. @@ -2854,22 +2260,18 @@ ** Failure is not possible. If the cursor is not currently ** pointing to an entry (which can happen, for example, if ** the database is empty) then *pSize is set to 0. */ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ - int rc = restoreOrClearCursorPosition(pCur, 1); - if( rc==SQLITE_OK ){ - assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); - if( pCur->eState==CURSOR_INVALID ){ - /* Not pointing at a valid entry - set *pSize to 0. */ - *pSize = 0; - }else{ - getCellInfo(pCur); - *pSize = pCur->info.nData; - } - } - return rc; + if( !pCur->isValid ){ + /* Not pointing at a valid entry - set *pSize to 0. */ + *pSize = 0; + }else{ + getCellInfo(pCur); + *pSize = pCur->info.nData; + } + return SQLITE_OK; } /* ** Read payload information from the entry that the pCur cursor is ** pointing to. Begin reading the payload at "offset" and read @@ -2888,22 +2290,23 @@ ){ unsigned char *aPayload; Pgno nextPage; int rc; MemPage *pPage; - BtShared *pBt; + Btree *pBt; int ovflSize; u32 nKey; assert( pCur!=0 && pCur->pPage!=0 ); - assert( pCur->eState==CURSOR_VALID ); - pBt = pCur->pBtree->pBt; + assert( pCur->isValid ); + pBt = pCur->pBt; pPage = pCur->pPage; pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idxnCell ); getCellInfo(pCur); - aPayload = pCur->info.pCell + pCur->info.nHeader; + aPayload = pCur->info.pCell; + aPayload += pCur->info.nHeader; if( pPage->intKey ){ nKey = 0; }else{ nKey = pCur->info.nKey; } @@ -2953,11 +2356,11 @@ sqlite3pager_unref(aPayload); } } if( amt>0 ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } return SQLITE_OK; } /* @@ -2968,22 +2371,15 @@ ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - int rc = restoreOrClearCursorPosition(pCur, 1); - if( rc==SQLITE_OK ){ - assert( pCur->eState==CURSOR_VALID ); - assert( pCur->pPage!=0 ); - if( pCur->pPage->intKey ){ - return SQLITE_CORRUPT_BKPT; - } - assert( pCur->pPage->intKey==0 ); - assert( pCur->idx>=0 && pCur->idxpPage->nCell ); - rc = getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); - } - return rc; + assert( pCur->isValid ); + assert( pCur->pPage!=0 ); + assert( pCur->pPage->intKey==0 ); + assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } /* ** Read part of the data associated with cursor pCur. Exactly ** "amt" bytes will be transfered into pBuf[]. The transfer @@ -2992,18 +2388,14 @@ ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - int rc = restoreOrClearCursorPosition(pCur, 1); - if( rc==SQLITE_OK ){ - assert( pCur->eState==CURSOR_VALID ); - assert( pCur->pPage!=0 ); - assert( pCur->idx>=0 && pCur->idxpPage->nCell ); - rc = getPayload(pCur, offset, amt, pBuf, 1); - } - return rc; + assert( pCur->isValid ); + assert( pCur->pPage!=0 ); + assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + return getPayload(pCur, offset, amt, pBuf, 1); } /* ** Return a pointer to payload information from the entry that the ** pCur cursor is pointing to. The pointer is to the beginning of @@ -3028,15 +2420,17 @@ int *pAmt, /* Write the number of available bytes here */ int skipKey /* read beginning at data if this is true */ ){ unsigned char *aPayload; MemPage *pPage; + Btree *pBt; u32 nKey; int nLocal; assert( pCur!=0 && pCur->pPage!=0 ); - assert( pCur->eState==CURSOR_VALID ); + assert( pCur->isValid ); + pBt = pCur->pBt; pPage = pCur->pPage; pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idxnCell ); getCellInfo(pCur); aPayload = pCur->info.pCell; @@ -3070,20 +2464,14 @@ ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){ - if( pCur->eState==CURSOR_VALID ){ - return (const void*)fetchPayload(pCur, pAmt, 0); - } - return 0; + return (const void*)fetchPayload(pCur, pAmt, 0); } const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){ - if( pCur->eState==CURSOR_VALID ){ - return (const void*)fetchPayload(pCur, pAmt, 1); - } - return 0; + return (const void*)fetchPayload(pCur, pAmt, 1); } /* ** Move the cursor down to a new child page. The newPgno argument is the @@ -3091,13 +2479,13 @@ */ static int moveToChild(BtCursor *pCur, u32 newPgno){ int rc; MemPage *pNewPage; MemPage *pOldPage; - BtShared *pBt = pCur->pBtree->pBt; + Btree *pBt = pCur->pBt; - assert( pCur->eState==CURSOR_VALID ); + assert( pCur->isValid ); rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage); if( rc ) return rc; pageIntegrity(pNewPage); pNewPage->idxParent = pCur->idx; pOldPage = pCur->pPage; @@ -3105,11 +2493,11 @@ releasePage(pOldPage); pCur->pPage = pNewPage; pCur->idx = 0; pCur->info.nSize = 0; if( pNewPage->nCell<1 ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } return SQLITE_OK; } /* @@ -3136,24 +2524,26 @@ ** to the page we are coming from. If we are coming from the ** right-most child page then pCur->idx is set to one more than ** the largest cell index. */ static void moveToParent(BtCursor *pCur){ + Pgno oldPgno; MemPage *pParent; MemPage *pPage; int idxParent; - assert( pCur->eState==CURSOR_VALID ); + assert( pCur->isValid ); pPage = pCur->pPage; assert( pPage!=0 ); assert( !isRootPage(pPage) ); pageIntegrity(pPage); pParent = pPage->pParent; assert( pParent!=0 ); pageIntegrity(pParent); idxParent = pPage->idxParent; sqlite3pager_ref(pParent->aData); + oldPgno = pPage->pgno; releasePage(pPage); pCur->pPage = pParent; pCur->info.nSize = 0; assert( pParent->idxShift==0 ); pCur->idx = idxParent; @@ -3162,56 +2552,45 @@ /* ** Move the cursor to the root page */ static int moveToRoot(BtCursor *pCur){ MemPage *pRoot; - int rc = SQLITE_OK; - BtShared *pBt = pCur->pBtree->pBt; - - restoreOrClearCursorPosition(pCur, 0); - assert( pCur->pPage ); - pRoot = pCur->pPage; - if( pRoot->pgno==pCur->pgnoRoot ){ - assert( pRoot->isInit ); - }else{ - if( - SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0)) - ){ - pCur->eState = CURSOR_INVALID; - return rc; - } - releasePage(pCur->pPage); - pageIntegrity(pRoot); - pCur->pPage = pRoot; - } + int rc; + Btree *pBt = pCur->pBt; + + rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0); + if( rc ){ + pCur->isValid = 0; + return rc; + } + releasePage(pCur->pPage); + pageIntegrity(pRoot); + pCur->pPage = pRoot; pCur->idx = 0; pCur->info.nSize = 0; if( pRoot->nCell==0 && !pRoot->leaf ){ Pgno subpage; assert( pRoot->pgno==1 ); subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); assert( subpage>0 ); - pCur->eState = CURSOR_VALID; + pCur->isValid = 1; rc = moveToChild(pCur, subpage); } - pCur->eState = ((pCur->pPage->nCell>0)?CURSOR_VALID:CURSOR_INVALID); + pCur->isValid = pCur->pPage->nCell>0; return rc; } /* ** Move the cursor down to the left-most leaf entry beneath the ** entry to which it is currently pointing. -** -** The left-most leaf is the one with the smallest key - the first -** in ascending order. */ static int moveToLeftmost(BtCursor *pCur){ Pgno pgno; int rc; MemPage *pPage; - assert( pCur->eState==CURSOR_VALID ); + assert( pCur->isValid ); while( !(pPage = pCur->pPage)->leaf ){ assert( pCur->idx>=0 && pCur->idxnCell ); pgno = get4byte(findCell(pPage, pCur->idx)); rc = moveToChild(pCur, pgno); if( rc ) return rc; @@ -3223,20 +2602,17 @@ ** Move the cursor down to the right-most leaf entry beneath the ** page to which it is currently pointing. Notice the difference ** between moveToLeftmost() and moveToRightmost(). moveToLeftmost() ** finds the left-most entry beneath the *entry* whereas moveToRightmost() ** finds the right-most entry beneath the *page*. -** -** The right-most entry is the one with the largest key - the last -** key in ascending order. */ static int moveToRightmost(BtCursor *pCur){ Pgno pgno; int rc; MemPage *pPage; - assert( pCur->eState==CURSOR_VALID ); + assert( pCur->isValid ); while( !(pPage = pCur->pPage)->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pCur->idx = pPage->nCell; rc = moveToChild(pCur, pgno); if( rc ) return rc; @@ -3252,11 +2628,11 @@ */ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; rc = moveToRoot(pCur); if( rc ) return rc; - if( pCur->eState==CURSOR_INVALID ){ + if( pCur->isValid==0 ){ assert( pCur->pPage->nCell==0 ); *pRes = 1; return SQLITE_OK; } assert( pCur->pPage->nCell>0 ); @@ -3271,16 +2647,16 @@ */ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; rc = moveToRoot(pCur); if( rc ) return rc; - if( CURSOR_INVALID==pCur->eState ){ + if( pCur->isValid==0 ){ assert( pCur->pPage->nCell==0 ); *pRes = 1; return SQLITE_OK; } - assert( pCur->eState==CURSOR_VALID ); + assert( pCur->isValid ); *pRes = 0; rc = moveToRightmost(pCur); return rc; } @@ -3287,11 +2663,11 @@ /* Move the cursor so that it points to an entry near pKey/nKey. ** Return a success code. ** ** For INTKEY tables, only the nKey parameter is used. pKey is ** ignored. For other tables, nKey is the number of bytes of data -** in pKey. The comparison function specified when the cursor was +** in nKey. The comparison function specified when the cursor was ** created is used to compare keys. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it ** were present. The cursor might point to an entry that comes @@ -3311,17 +2687,15 @@ ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pKey. */ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){ int rc; - int tryRightmost; rc = moveToRoot(pCur); if( rc ) return rc; assert( pCur->pPage ); assert( pCur->pPage->isInit ); - tryRightmost = pCur->pPage->intKey; - if( pCur->eState==CURSOR_INVALID ){ + if( pCur->isValid==0 ){ *pRes = -1; assert( pCur->pPage->nCell==0 ); return SQLITE_OK; } for(;;){ @@ -3330,41 +2704,30 @@ MemPage *pPage = pCur->pPage; int c = -1; /* pRes return if table is empty must be -1 */ lwr = 0; upr = pPage->nCell-1; if( !pPage->intKey && pKey==0 ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; } pageIntegrity(pPage); while( lwr<=upr ){ void *pCellKey; i64 nCellKey; pCur->idx = (lwr+upr)/2; pCur->info.nSize = 0; + sqlite3BtreeKeySize(pCur, &nCellKey); if( pPage->intKey ){ - u8 *pCell; - if( tryRightmost ){ - pCur->idx = upr; - } - pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize; - if( pPage->hasData ){ - int dummy; - pCell += getVarint32(pCell, &dummy); - } - getVarint(pCell, &nCellKey); if( nCellKeynKey ){ c = +1; - tryRightmost = 0; }else{ c = 0; } }else{ int available; pCellKey = (void *)fetchPayload(pCur, &available, 0); - nCellKey = pCur->info.nKey; if( available>=nCellKey ){ c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey); }else{ pCellKey = sqliteMallocRaw( nCellKey ); if( pCellKey==0 ) return SQLITE_NOMEM; @@ -3420,15 +2783,11 @@ ** TRUE will be returned after a call to sqlite3BtreeNext() moves ** past the last entry in the table or sqlite3BtreePrev() moves past ** the first entry. TRUE is also returned if the table is empty. */ int sqlite3BtreeEof(BtCursor *pCur){ - /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries - ** have been deleted? This API will need to change to return an error code - ** as well as the boolean result value. - */ - return (CURSOR_VALID!=pCur->eState); + return pCur->isValid==0; } /* ** Advance the cursor to the next entry in the database. If ** successful then set *pRes=0. If the cursor @@ -3437,25 +2796,12 @@ */ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ int rc; MemPage *pPage = pCur->pPage; -#ifndef SQLITE_OMIT_SHARED_CACHE - rc = restoreOrClearCursorPosition(pCur, 1); - if( rc!=SQLITE_OK ){ - return rc; - } - if( pCur->skip>0 ){ - pCur->skip = 0; - *pRes = 0; - return SQLITE_OK; - } - pCur->skip = 0; -#endif - assert( pRes!=0 ); - if( CURSOR_INVALID==pCur->eState ){ + if( pCur->isValid==0 ){ *pRes = 1; return SQLITE_OK; } assert( pPage->isInit ); assert( pCur->idxnCell ); @@ -3471,11 +2817,11 @@ return rc; } do{ if( isRootPage(pPage) ){ *pRes = 1; - pCur->eState = CURSOR_INVALID; + pCur->isValid = 0; return SQLITE_OK; } moveToParent(pCur); pPage = pCur->pPage; }while( pCur->idx>=pPage->nCell ); @@ -3503,25 +2849,11 @@ */ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ int rc; Pgno pgno; MemPage *pPage; - -#ifndef SQLITE_OMIT_SHARED_CACHE - rc = restoreOrClearCursorPosition(pCur, 1); - if( rc!=SQLITE_OK ){ - return rc; - } - if( pCur->skip<0 ){ - pCur->skip = 0; - *pRes = 0; - return SQLITE_OK; - } - pCur->skip = 0; -#endif - - if( CURSOR_INVALID==pCur->eState ){ + if( pCur->isValid==0 ){ *pRes = 1; return SQLITE_OK; } pPage = pCur->pPage; @@ -3533,11 +2865,11 @@ if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->idx==0 ){ if( isRootPage(pPage) ){ - pCur->eState = CURSOR_INVALID; + pCur->isValid = 0; *pRes = 1; return SQLITE_OK; } moveToParent(pCur); pPage = pCur->pPage; @@ -3574,11 +2906,11 @@ ** If the "exact" parameter is not 0, and the page-number nearby exists ** anywhere on the free-list, then it is guarenteed to be returned. This ** is only used by auto-vacuum databases when allocating a new table. */ static int allocatePage( - BtShared *pBt, + Btree *pBt, MemPage **ppPage, Pgno *pPgno, Pgno nearby, u8 exact ){ @@ -3657,11 +2989,11 @@ *ppPage = pTrunk; pTrunk = 0; TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); }else if( k>pBt->usableSize/4 - 8 ){ /* Value of k is out of range. Database corruption */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ #ifndef SQLITE_OMIT_AUTOVACUUM }else if( searchList && nearby==iTrunk ){ /* The list is being searched and this trunk page is the page ** to allocate, regardless of whether it has leaves. */ @@ -3732,11 +3064,11 @@ iPage = get4byte(&aData[8+closest*4]); if( !searchList || iPage==nearby ){ *pPgno = iPage; if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){ /* Free page off the end of the file */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" ": %d more free pages\n", *pPgno, closest+1, k, pTrunk->pgno, n-1)); if( closestpBt; + Btree *pBt = pPage->pBt; MemPage *pPage1 = pBt->pPage1; int rc, n, k; /* Prepare the page for freeing */ assert( pPage->pgno>1 ); @@ -3860,11 +3192,11 @@ /* ** Free any overflow pages associated with the given Cell. */ static int clearCell(MemPage *pPage, unsigned char *pCell){ - BtShared *pBt = pPage->pBt; + Btree *pBt = pPage->pBt; CellInfo info; Pgno ovflPgno; int rc; parseCellPtr(pPage, pCell, &info); @@ -3873,18 +3205,18 @@ } ovflPgno = get4byte(&pCell[info.iOverflow]); while( ovflPgno!=0 ){ MemPage *pOvfl; if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; } rc = getPage(pBt, ovflPgno, &pOvfl); if( rc ) return rc; ovflPgno = get4byte(pOvfl->aData); rc = freePage(pOvfl); - sqlite3pager_unref(pOvfl->aData); if( rc ) return rc; + sqlite3pager_unref(pOvfl->aData); } return SQLITE_OK; } /* @@ -3912,11 +3244,11 @@ int spaceLeft; MemPage *pOvfl = 0; MemPage *pToRelease = 0; unsigned char *pPrior; unsigned char *pPayload; - BtShared *pBt = pPage->pBt; + Btree *pBt = pPage->pBt; Pgno pgnoOvfl = 0; int nHeader; CellInfo info; /* Fill in the header. */ @@ -4001,19 +3333,19 @@ /* ** Change the MemPage.pParent pointer on the page whose number is ** given in the second argument so that MemPage.pParent holds the ** pointer in the third argument. */ -static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){ +static int reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){ MemPage *pThis; unsigned char *aData; if( pgno==0 ) return SQLITE_OK; assert( pBt->pPager!=0 ); aData = sqlite3pager_lookup(pBt->pPager, pgno); if( aData ){ - pThis = (MemPage*)&aData[pBt->pageSize]; + pThis = (MemPage*)&aData[pBt->psAligned]; assert( pThis->aData==aData ); if( pThis->isInit ){ if( pThis->pParent!=pNewParent ){ if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData); pThis->pParent = pNewParent; @@ -4044,11 +3376,11 @@ ** This routine gets called after you memcpy() one page into ** another. */ static int reparentChildPages(MemPage *pPage){ int i; - BtShared *pBt = pPage->pBt; + Btree *pBt = pPage->pBt; int rc = SQLITE_OK; if( pPage->leaf ) return SQLITE_OK; for(i=0; inCell; i++){ @@ -4152,12 +3484,11 @@ top = get2byte(&data[hdr+5]); cellOffset = pPage->cellOffset; end = cellOffset + 2*pPage->nCell + 2; ins = cellOffset + 2*i; if( end > top - sz ){ - int rc = defragmentPage(pPage); - if( rc!=SQLITE_OK ) return rc; + defragmentPage(pPage); top = get2byte(&data[hdr+5]); assert( end + sz <= top ); } idx = allocateSpace(pPage, sz); assert( idx>0 ); @@ -4218,23 +3549,21 @@ assert( pPage->nCell==0 ); cellptr = pPage->cellOffset; data = pPage->aData; hdr = pPage->hdrOffset; put2byte(&data[hdr+3], nCell); - if( nCell ){ - cellbody = allocateSpace(pPage, totalSize); - assert( cellbody>0 ); - assert( pPage->nFree >= 2*nCell ); - pPage->nFree -= 2*nCell; - for(i=0; ipBt->usableSize ); - } + cellbody = allocateSpace(pPage, totalSize); + assert( cellbody>0 ); + assert( pPage->nFree >= 2*nCell ); + pPage->nFree -= 2*nCell; + for(i=0; ipBt->usableSize ); pPage->nCell = nCell; } /* ** The following parameters determine how many adjacent pages get involved @@ -4277,11 +3606,11 @@ MemPage *pNew; Pgno pgnoNew; u8 *pCell; int szCell; CellInfo info; - BtShared *pBt = pPage->pBt; + Btree *pBt = pPage->pBt; int parentIdx = pParent->nCell; /* pParent new divider cell index */ int parentSize; /* Size of new divider cell */ u8 parentCell[64]; /* Space for the new divider cell */ /* Allocate a new page. Insert the overflow cell from pPage @@ -4386,13 +3715,12 @@ ** in a corrupted state. So if this routine fails, the database should ** be rolled back. */ static int balance_nonroot(MemPage *pPage){ MemPage *pParent; /* The parent of pPage */ - BtShared *pBt; /* The whole database */ - int nCell = 0; /* Number of cells in apCell[] */ - int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ + Btree *pBt; /* The whole database */ + int nCell = 0; /* Number of cells in aCell[] */ int nOld; /* Number of pages in apOld[] */ int nNew; /* Number of pages in apNew[] */ int nDiv; /* Number of cells in apDiv[] */ int i, j, k; /* Loop counters */ int idx; /* Index of pPage in pParent->aCell[] */ @@ -4402,19 +3730,21 @@ int leafData; /* True if pPage is a leaf of a LEAFDATA tree */ int usableSpace; /* Bytes in pPage beyond the header */ int pageFlags; /* Value of pPage->aData[0] */ int subtotal; /* Subtotal of bytes in cells on one page */ int iSpace = 0; /* First unused byte of aSpace[] */ + int mxCellPerPage; /* Maximum number of cells in one page */ MemPage *apOld[NB]; /* pPage and up to two siblings */ Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */ MemPage *apCopy[NB]; /* Private copies of apOld[] pages */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ Pgno pgnoNew[NB+2]; /* Page numbers for each page in apNew[] */ + int idxDiv[NB]; /* Indices of divider cells in pParent */ u8 *apDiv[NB]; /* Divider cells in pParent */ int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */ int szNew[NB+2]; /* Combined size of cells place on i-th page */ - u8 **apCell = 0; /* All cells begin balanced */ + u8 **apCell; /* All cells begin balanced */ int *szCell; /* Local size of all cells in apCell[] */ u8 *aCopy[NB]; /* Space for holding data of apCopy[] */ u8 *aSpace; /* Space to hold copies of dividers cells */ #ifndef SQLITE_OMIT_AUTOVACUUM u8 *aFrom = 0; @@ -4433,11 +3763,11 @@ #ifndef SQLITE_OMIT_QUICKBALANCE /* ** A special case: If a new entry has just been inserted into a ** table (that is, a btree with integer keys and all data at the leaves) - ** and the new entry is the right-most entry in the tree (it has the + ** an the new entry is the right-most entry in the tree (it has the ** largest key) then use the special balance_quick() routine for ** balancing. balance_quick() is much faster and results in a tighter ** packing of data in the common case. */ if( pPage->leaf && @@ -4454,10 +3784,35 @@ */ return balance_quick(pPage, pParent); } #endif + /* + ** Allocate space for memory structures + */ + mxCellPerPage = MX_CELL(pBt); + apCell = sqliteMallocRaw( + (mxCellPerPage+2)*NB*(sizeof(u8*)+sizeof(int)) + + sizeof(MemPage)*NB + + pBt->psAligned*(5+NB) + + (ISAUTOVACUUM ? (mxCellPerPage+2)*NN*2 : 0) + ); + if( apCell==0 ){ + return SQLITE_NOMEM; + } + szCell = (int*)&apCell[(mxCellPerPage+2)*NB]; + aCopy[0] = (u8*)&szCell[(mxCellPerPage+2)*NB]; + for(i=1; ipsAligned+sizeof(MemPage)]; + } + aSpace = &aCopy[NB-1][pBt->psAligned+sizeof(MemPage)]; +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pBt->autoVacuum ){ + aFrom = &aSpace[5*pBt->psAligned]; + } +#endif + /* ** Find the cell in the parent page whose left child points back ** to pPage. The "idx" variable is the index of that cell. If pPage ** is the rightmost child of pParent then set idx to pParent->nCell */ @@ -4498,10 +3853,11 @@ nxDiv = 0; } nDiv = 0; for(i=0, k=nxDiv; inCell ){ + idxDiv[i] = k; apDiv[i] = findCell(pParent, k); nDiv++; assert( !pParent->leaf ); pgnoOld[i] = get4byte(apDiv[i]); }else if( k==pParent->nCell ){ @@ -4513,59 +3869,23 @@ if( rc ) goto balance_cleanup; apOld[i]->idxParent = k; apCopy[i] = 0; assert( i==nOld ); nOld++; - nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; - } - - /* Make nMaxCells a multiple of 2 in order to preserve 8-byte - ** alignment */ - nMaxCells = (nMaxCells + 1)&~1; - - /* - ** Allocate space for memory structures - */ - apCell = sqliteMallocRaw( - nMaxCells*sizeof(u8*) /* apCell */ - + nMaxCells*sizeof(int) /* szCell */ - + ROUND8(sizeof(MemPage))*NB /* aCopy */ - + pBt->pageSize*(5+NB) /* aSpace */ - + (ISAUTOVACUUM ? nMaxCells : 0) /* aFrom */ - ); - if( apCell==0 ){ - rc = SQLITE_NOMEM; - goto balance_cleanup; - } - szCell = (int*)&apCell[nMaxCells]; - aCopy[0] = (u8*)&szCell[nMaxCells]; - assert( ((aCopy[0] - (u8*)apCell) & 7)==0 ); /* 8-byte alignment required */ - for(i=1; ipageSize+ROUND8(sizeof(MemPage))]; - assert( ((aCopy[i] - (u8*)apCell) & 7)==0 ); /* 8-byte alignment required */ - } - aSpace = &aCopy[NB-1][pBt->pageSize+ROUND8(sizeof(MemPage))]; - assert( ((aSpace - (u8*)apCell) & 7)==0 ); /* 8-byte alignment required */ -#ifndef SQLITE_OMIT_AUTOVACUUM - if( pBt->autoVacuum ){ - aFrom = &aSpace[5*pBt->pageSize]; - } -#endif - + } + /* ** Make copies of the content of pPage and its siblings into aOld[]. ** The rest of this function will use data from the copies rather ** that the original pages since the original pages will be in the ** process of being overwritten. */ for(i=0; ipageSize]; - p->aData = &((u8*)p)[-pBt->pageSize]; - memcpy(p->aData, apOld[i]->aData, pBt->pageSize + sizeof(MemPage)); - /* The memcpy() above changes the value of p->aData so we have to - ** set it again. */ - p->aData = &((u8*)p)[-pBt->pageSize]; + MemPage *p = apCopy[i] = (MemPage*)&aCopy[i][pBt->psAligned]; + p->aData = &((u8*)p)[-pBt->psAligned]; + memcpy(p->aData, apOld[i]->aData, pBt->psAligned + sizeof(MemPage)); + p->aData = &((u8*)p)[-pBt->psAligned]; } /* ** Load pointers to all cells on sibling pages and the divider cells ** into the local apCell[] array. Make copies of the divider cells @@ -4587,11 +3907,10 @@ leafData = pPage->leafData && pPage->leaf; for(i=0; inCell+pOld->nOverflow; for(j=0; jautoVacuum ){ int a; @@ -4615,15 +3934,14 @@ ** added to apCell[] because they are duplicates of child cells. */ dropCell(pParent, nxDiv, sz); }else{ u8 *pTemp; - assert( nCellpageSize*5 ); + assert( iSpace<=pBt->psAligned*5 ); memcpy(pTemp, apDiv[i], sz); apCell[nCell] = pTemp+leafCorrection; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ aFrom[nCell] = 0xFF; @@ -4661,11 +3979,10 @@ ** usableSpace: Number of bytes of space available on each sibling. ** */ usableSpace = pBt->usableSize - 12 + leafCorrection; for(subtotal=k=i=0; i usableSpace ){ szNew[k] = subtotal - szCell[i]; cntNew[k] = i; if( leafData ){ i--; } @@ -4693,12 +4010,10 @@ int r; /* Index of right-most cell in left sibling */ int d; /* Index of first cell to the left of right sibling */ r = cntNew[i-1] - 1; d = r + 1 - leafData; - assert( d0) or we are the - ** a virtual root page. A virtual root page is when the real root - ** page is page 1 and we are the only child of that page. - */ - assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) ); + assert( cntNew[0]>0 ); /* ** Allocate k new pages. Reuse old pages where possible. */ assert( pPage->pgno>1 ); @@ -4796,14 +4106,13 @@ */ j = 0; for(i=0; ipgno==pgnoNew[i] ); assemblePage(pNew, cntNew[i]-j, &apCell[j], &szCell[j]); - assert( pNew->nCell>0 || (nNew==1 && cntNew[0]==0) ); + assert( pNew->nCell>0 ); assert( pNew->nOverflow==0 ); #ifndef SQLITE_OMIT_AUTOVACUUM /* If this is an auto-vacuum database, update the pointer map entries ** that point to the siblings that were rearranged. These can be: left @@ -4810,11 +4119,10 @@ ** children of cells, the right-child of the page, or overflow pages ** pointed to by cells. */ if( pBt->autoVacuum ){ for(k=j; kpgno!=pNew->pgno ){ rc = ptrmapPutOvfl(pNew, k-j); if( rc!=SQLITE_OK ){ goto balance_cleanup; } @@ -4830,12 +4138,10 @@ */ if( ileaf ){ memcpy(&pNew->aData[8], pCell, 4); pTemp = 0; @@ -4849,17 +4155,17 @@ j--; parseCellPtr(pNew, apCell[j], &info); pCell = &aSpace[iSpace]; fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz); iSpace += sz; - assert( iSpace<=pBt->pageSize*5 ); + assert( iSpace<=pBt->psAligned*5 ); pTemp = 0; }else{ pCell -= 4; pTemp = &aSpace[iSpace]; iSpace += sz; - assert( iSpace<=pBt->pageSize*5 ); + assert( iSpace<=pBt->psAligned*5 ); } rc = insertCell(pParent, nxDiv, pCell, sz, pTemp, 4); if( rc!=SQLITE_OK ) goto balance_cleanup; put4byte(findOverflowCell(pParent,nxDiv), pNew->pgno); #ifndef SQLITE_OMIT_AUTOVACUUM @@ -4935,11 +4241,11 @@ */ static int balance_shallower(MemPage *pPage){ MemPage *pChild; /* The only child page of pPage */ Pgno pgnoChild; /* Page number for pChild */ int rc = SQLITE_OK; /* Return code from subprocedures */ - BtShared *pBt; /* The main BTree structure */ + Btree *pBt; /* The main BTree structure */ int mxCellPerPage; /* Maximum number of cells per page */ u8 **apCell; /* All cells from pages being balanced */ int *szCell; /* Local size of all cells */ assert( pPage->pParent==0 ); @@ -5037,11 +4343,11 @@ */ static int balance_deeper(MemPage *pPage){ int rc; /* Return value from subprocedures */ MemPage *pChild; /* Pointer to a new child page */ Pgno pgnoChild; /* Page number of the new child page */ - BtShared *pBt; /* The BTree */ + Btree *pBt; /* The BTree */ int usableSize; /* Total usable size of a page */ u8 *data; /* Content of the parent page */ u8 *cdata; /* Content of the child page */ int hdr; /* Offset to page header in parent */ int brk; /* Offset to content of first cell in parent */ @@ -5059,11 +4365,11 @@ cdata = pChild->aData; memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr); memcpy(&cdata[brk], &data[brk], usableSize-brk); assert( pChild->isInit==0 ); rc = initPage(pChild, pPage); - if( rc ) goto balancedeeper_out; + if( rc ) return rc; memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0])); pChild->nOverflow = pPage->nOverflow; if( pChild->nOverflow ){ pChild->nFree = 0; } @@ -5073,22 +4379,20 @@ TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno)); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ int i; rc = ptrmapPut(pBt, pChild->pgno, PTRMAP_BTREE, pPage->pgno); - if( rc ) goto balancedeeper_out; + if( rc ) return rc; for(i=0; inCell; i++){ rc = ptrmapPutOvfl(pChild, i); if( rc!=SQLITE_OK ){ return rc; } } } #endif rc = balance_nonroot(pChild); - -balancedeeper_out: releasePage(pChild); return rc; } /* @@ -5126,16 +4430,14 @@ ** first Cell on root page. This is necessary because an insert ** or delete might change the number of cells on a page or delete ** a page entirely and we do not want to leave any cursors ** pointing to non-existant pages or cells. */ -static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){ +static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){ BtCursor *p; for(p=pBt->pCursor; p; p=p->pNext){ - u32 flags = (p->pBtree->pSqlite ? p->pBtree->pSqlite->flags : 0); if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue; - if( p->wrFlag==0 && flags&SQLITE_ReadUncommitted ) continue; if( p->wrFlag==0 ) return SQLITE_LOCKED; if( p->pPage->pgno!=p->pgnoRoot ){ moveToRoot(p); } } @@ -5158,15 +4460,15 @@ ){ int rc; int loc; int szNew; MemPage *pPage; - BtShared *pBt = pCur->pBtree->pBt; + Btree *pBt = pCur->pBt; unsigned char *oldCell; unsigned char *newCell = 0; - if( pBt->inTransaction!=TRANS_WRITE ){ + if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing an insert */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); if( !pCur->wrFlag ){ @@ -5173,20 +4475,12 @@ return SQLITE_PERM; /* Cursor not open for writing */ } if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } - - /* Save the positions of any other cursors open on this table */ - restoreOrClearCursorPosition(pCur, 0); - if( - SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || - SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc)) - ){ - return rc; - } - + rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc); + if( rc ) return rc; pPage = pCur->pPage; assert( pPage->intKey || nKey>=0 ); assert( pPage->leaf || !pPage->leafData ); TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, nKey, nData, pPage->pgno, @@ -5198,11 +4492,11 @@ if( newCell==0 ) return SQLITE_NOMEM; rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, &szNew); if( rc ) goto end_insert; assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew<=MX_CELL_SIZE(pBt) ); - if( loc==0 && CURSOR_VALID==pCur->eState ){ + if( loc==0 && pCur->isValid ){ int szOld; assert( pCur->idx>=0 && pCur->idxnCell ); oldCell = findCell(pPage, pCur->idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); @@ -5238,14 +4532,14 @@ int sqlite3BtreeDelete(BtCursor *pCur){ MemPage *pPage = pCur->pPage; unsigned char *pCell; int rc; Pgno pgnoChild = 0; - BtShared *pBt = pCur->pBtree->pBt; + Btree *pBt = pCur->pBt; assert( pPage->isInit ); - if( pBt->inTransaction!=TRANS_WRITE ){ + if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); if( pCur->idx >= pPage->nCell ){ @@ -5255,23 +4549,12 @@ return SQLITE_PERM; /* Did not open this cursor for writing */ } if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } - - /* Restore the current cursor position (a no-op if the cursor is not in - ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors - ** open on the same table. Then call sqlite3pager_write() on the page - ** that the entry will be deleted from. - */ - if( - (rc = restoreOrClearCursorPosition(pCur, 1)) || - (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || - (rc = sqlite3pager_write(pPage->aData)) - ){ - return rc; - } + rc = sqlite3pager_write(pPage->aData); + if( rc ) return rc; /* Locate the cell within it's page and leave pCell pointing to the ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ @@ -5292,56 +4575,46 @@ */ BtCursor leafCur; unsigned char *pNext; int szNext; int notUsed; - unsigned char *tempCell = 0; + unsigned char *tempCell; assert( !pPage->leafData ); getTempCursor(pCur, &leafCur); rc = sqlite3BtreeNext(&leafCur, ¬Used); if( rc!=SQLITE_OK ){ if( rc!=SQLITE_NOMEM ){ - rc = SQLITE_CORRUPT_BKPT; - } - } - if( rc==SQLITE_OK ){ - rc = sqlite3pager_write(leafCur.pPage->aData); - } - if( rc==SQLITE_OK ){ - TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", - pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); - dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); - pNext = findCell(leafCur.pPage, leafCur.idx); - szNext = cellSizePtr(leafCur.pPage, pNext); - assert( MX_CELL_SIZE(pBt)>=szNext+4 ); - tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); - if( tempCell==0 ){ - rc = SQLITE_NOMEM; - } - } - if( rc==SQLITE_OK ){ - rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0); - } - if( rc==SQLITE_OK ){ - put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild); - rc = balance(pPage, 0); - } - if( rc==SQLITE_OK ){ - dropCell(leafCur.pPage, leafCur.idx, szNext); - rc = balance(leafCur.pPage, 0); - } + rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */ + } + return rc; + } + rc = sqlite3pager_write(leafCur.pPage->aData); + if( rc ) return rc; + TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", + pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); + dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); + pNext = findCell(leafCur.pPage, leafCur.idx); + szNext = cellSizePtr(leafCur.pPage, pNext); + assert( MX_CELL_SIZE(pBt)>=szNext+4 ); + tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); + if( tempCell==0 ) return SQLITE_NOMEM; + rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0); + if( rc!=SQLITE_OK ) return rc; + put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild); + rc = balance(pPage, 0); sqliteFree(tempCell); + if( rc ) return rc; + dropCell(leafCur.pPage, leafCur.idx, szNext); + rc = balance(leafCur.pPage, 0); releaseTempCursor(&leafCur); }else{ TRACE(("DELETE: table=%d delete from leaf %d\n", pCur->pgnoRoot, pPage->pgno)); dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); rc = balance(pPage, 0); } - if( rc==SQLITE_OK ){ - moveToRoot(pCur); - } + moveToRoot(pCur); return rc; } /* ** Create a new BTree table. Write into *piTable the page @@ -5352,16 +4625,15 @@ ** flags might not work: ** ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys ** BTREE_ZERODATA Used for SQL indices */ -int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ - BtShared *pBt = p->pBt; +int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){ MemPage *pRoot; Pgno pgnoRoot; int rc; - if( pBt->inTransaction!=TRANS_WRITE ){ + if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction first */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); @@ -5384,11 +4656,11 @@ /* Read the value of meta[3] from the database to determine where the ** root page of the new table should go. meta[3] is the largest root-page ** created so far, so the new root-page is (meta[3]+1). */ - rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot); + rc = sqlite3BtreeGetMeta(pBt, 4, &pgnoRoot); if( rc!=SQLITE_OK ) return rc; pgnoRoot++; /* The new root-page may not be allocated on a pointer-map page, or the ** PENDING_BYTE page. @@ -5416,17 +4688,12 @@ rc = getPage(pBt, pgnoRoot, &pRoot); if( rc!=SQLITE_OK ){ return rc; } rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); - if( rc!=SQLITE_OK || eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ - releasePage(pRoot); - return rc; - } assert( eType!=PTRMAP_ROOTPAGE ); assert( eType!=PTRMAP_FREEPAGE ); - rc = sqlite3pager_write(pRoot->aData); if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; } rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove); @@ -5451,11 +4718,11 @@ rc = ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0); if( rc ){ releasePage(pRoot); return rc; } - rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot); + rc = sqlite3BtreeUpdateMeta(pBt, 4, pgnoRoot); if( rc ){ releasePage(pRoot); return rc; } @@ -5474,48 +4741,46 @@ /* ** Erase the given database page and all its children. Return ** the page to the freelist. */ static int clearDatabasePage( - BtShared *pBt, /* The BTree that contains the table */ + Btree *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ MemPage *pParent, /* Parent page. NULL for the root */ int freePageFlag /* Deallocate page if true */ ){ - MemPage *pPage = 0; + MemPage *pPage; int rc; unsigned char *pCell; int i; if( pgno>sqlite3pager_pagecount(pBt->pPager) ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT; } rc = getAndInitPage(pBt, pgno, &pPage, pParent); - if( rc ) goto cleardatabasepage_out; + if( rc ) return rc; rc = sqlite3pager_write(pPage->aData); - if( rc ) goto cleardatabasepage_out; + if( rc ) return rc; for(i=0; inCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1); - if( rc ) goto cleardatabasepage_out; + if( rc ) return rc; } rc = clearCell(pPage, pCell); - if( rc ) goto cleardatabasepage_out; + if( rc ) return rc; } if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage->pParent, 1); - if( rc ) goto cleardatabasepage_out; + if( rc ) return rc; } if( freePageFlag ){ rc = freePage(pPage); }else{ zeroPage(pPage, pPage->aData[0] | PTF_LEAF); } - -cleardatabasepage_out: releasePage(pPage); return rc; } /* @@ -5525,29 +4790,26 @@ ** ** This routine will fail with SQLITE_LOCKED if there are any open ** read cursors on the table. Open write cursors are moved to the ** root of the table. */ -int sqlite3BtreeClearTable(Btree *p, int iTable){ +int sqlite3BtreeClearTable(Btree *pBt, int iTable){ int rc; BtCursor *pCur; - BtShared *pBt = p->pBt; - if( p->inTrans!=TRANS_WRITE ){ + if( pBt->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->pgnoRoot==(Pgno)iTable ){ if( pCur->wrFlag==0 ) return SQLITE_LOCKED; moveToRoot(pCur); } } rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0); -#if 0 if( rc ){ sqlite3BtreeRollback(pBt); } -#endif return rc; } /* ** Erase all information in a table and add the root of the table to @@ -5567,16 +4829,15 @@ ** page number that used to be the last root page in the file before ** the move. If no page gets moved, *piMoved is set to 0. ** The last root page is recorded in meta[3] and the value of ** meta[3] is updated by this procedure. */ -int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ +int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){ int rc; MemPage *pPage = 0; - BtShared *pBt = p->pBt; - if( p->inTrans!=TRANS_WRITE ){ + if( pBt->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } /* It is illegal to drop a table if any cursors are open on the ** database. This is because in auto-vacuum mode the backend may @@ -5588,15 +4849,12 @@ return SQLITE_LOCKED; } rc = getPage(pBt, (Pgno)iTable, &pPage); if( rc ) return rc; - rc = sqlite3BtreeClearTable(p, iTable); - if( rc ){ - releasePage(pPage); - return rc; - } + rc = sqlite3BtreeClearTable(pBt, iTable); + if( rc ) return rc; *piMoved = 0; if( iTable>1 ){ #ifdef SQLITE_OMIT_AUTOVACUUM @@ -5603,11 +4861,11 @@ rc = freePage(pPage); releasePage(pPage); #else if( pBt->autoVacuum ){ Pgno maxRootPgno; - rc = sqlite3BtreeGetMeta(p, 4, &maxRootPgno); + rc = sqlite3BtreeGetMeta(pBt, 4, &maxRootPgno); if( rc!=SQLITE_OK ){ releasePage(pPage); return rc; } @@ -5660,11 +4918,11 @@ if( maxRootPgno==PTRMAP_PAGENO(pBt->usableSize, maxRootPgno) ){ maxRootPgno--; } assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); - rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); + rc = sqlite3BtreeUpdateMeta(pBt, 4, maxRootPgno); }else{ rc = freePage(pPage); releasePage(pPage); } #endif @@ -5685,24 +4943,13 @@ ** ** The schema layer numbers meta values differently. At the schema ** layer (and the SetCookie and ReadCookie opcodes) the number of ** free pages is not visible. So Cookie[0] is the same as Meta[1]. */ -int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ +int sqlite3BtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){ int rc; unsigned char *pP1; - BtShared *pBt = p->pBt; - - /* Reading a meta-data value requires a read-lock on page 1 (and hence - ** the sqlite_master table. We grab this lock regardless of whether or - ** not the SQLITE_ReadUncommitted flag is set (the table rooted at page - ** 1 is treated as a special case by queryTableLock() and lockTable()). - */ - rc = queryTableLock(p, 1, READ_LOCK); - if( rc!=SQLITE_OK ){ - return rc; - } assert( idx>=0 && idx<=15 ); rc = sqlite3pager_get(pBt->pPager, 1, (void**)&pP1); if( rc ) return rc; *pMeta = get4byte(&pP1[36 + idx*4]); @@ -5713,25 +4960,22 @@ */ #ifdef SQLITE_OMIT_AUTOVACUUM if( idx==4 && *pMeta>0 ) pBt->readOnly = 1; #endif - /* Grab the read-lock on page 1. */ - rc = lockTable(p, 1, READ_LOCK); - return rc; + return SQLITE_OK; } /* ** Write meta-information back into the database. Meta[0] is ** read-only and may not be written. */ -int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ - BtShared *pBt = p->pBt; +int sqlite3BtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){ unsigned char *pP1; int rc; assert( idx>=1 && idx<=15 ); - if( p->inTrans!=TRANS_WRITE ){ + if( pBt->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( pBt->pPage1!=0 ); pP1 = pBt->pPage1->aData; rc = sqlite3pager_write(pP1); @@ -5743,23 +4987,20 @@ /* ** Return the flag byte at the beginning of the page that the cursor ** is currently pointing to. */ int sqlite3BtreeFlags(BtCursor *pCur){ - /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call - ** restoreOrClearCursorPosition() here. - */ MemPage *pPage = pCur->pPage; return pPage ? pPage->aData[pPage->hdrOffset] : 0; } #ifdef SQLITE_DEBUG /* ** Print a disassembly of the given page on standard output. This routine ** is used for debugging and testing only. */ -static int btreePageDump(BtShared *pBt, int pgno, int recursive, MemPage *pParent){ +static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){ int rc; MemPage *pPage; int i, j, c; int nFree; u16 idx; @@ -5851,12 +5092,12 @@ pPage->isInit = isInit; sqlite3pager_unref(data); fflush(stdout); return SQLITE_OK; } -int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){ - return btreePageDump(p->pBt, pgno, recursive, 0); +int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){ + return btreePageDump(pBt, pgno, recursive, 0); } #endif #ifdef SQLITE_TEST /* @@ -5879,15 +5120,10 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){ int cnt, idx; MemPage *pPage = pCur->pPage; BtCursor tmpCur; - int rc = restoreOrClearCursorPosition(pCur, 1); - if( rc!=SQLITE_OK ){ - return rc; - } - pageIntegrity(pPage); assert( pPage->isInit ); getTempCursor(pCur, &tmpCur); while( upCnt-- ){ moveToParent(&tmpCur); @@ -5930,21 +5166,21 @@ /* ** Return the pager associated with a BTree. This routine is used for ** testing and debugging only. */ -Pager *sqlite3BtreePager(Btree *p){ - return p->pBt->pPager; +Pager *sqlite3BtreePager(Btree *pBt){ + return pBt->pPager; } /* ** This structure is passed around through all the sanity checking routines ** in order to keep track of some global state information. */ typedef struct IntegrityCk IntegrityCk; struct IntegrityCk { - BtShared *pBt; /* The tree being checked out */ + Btree *pBt; /* The tree being checked out */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ int nPage; /* Number of pages in the database */ int *anRef; /* Number of times each page is referenced */ char *zErrMsg; /* An error message. NULL of no errors seen. */ }; @@ -6131,37 +5367,40 @@ MemPage *pPage; int i, rc, depth, d2, pgno, cnt; int hdr, cellStart; int nCell; u8 *data; - BtShared *pBt; - int usableSize; + BtCursor cur; + Btree *pBt; + int maxLocal, usableSize; char zContext[100]; char *hit; sprintf(zContext, "Page %d: ", iPage); /* Check that the page exists */ - pBt = pCheck->pBt; + cur.pBt = pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){ checkAppendMsg(pCheck, zContext, "unable to get the page. error code=%d", rc); return 0; } + maxLocal = pPage->leafData ? pBt->maxLeaf : pBt->maxLocal; if( (rc = initPage(pPage, pParent))!=0 ){ checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc); releasePage(pPage); return 0; } /* Check out all the cells. */ depth = 0; + cur.pPage = pPage; for(i=0; inCell; i++){ u8 *pCell; int sz; CellInfo info; @@ -6273,18 +5512,17 @@ ** If everything checks out, this routine returns NULL. If something is ** amiss, an error message is written into memory obtained from malloc() ** and a pointer to that error message is returned. The calling function ** is responsible for freeing the error message when it is done. */ -char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){ +char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){ int i; int nRef; IntegrityCk sCheck; - BtShared *pBt = p->pBt; nRef = *sqlite3pager_stats(pBt->pPager); - if( lockBtreeWithRetry(p)!=SQLITE_OK ){ + if( lockBtree(pBt)!=SQLITE_OK ){ return sqliteStrDup("Unable to acquire a read lock on the database"); } sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager); @@ -6362,31 +5600,31 @@ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* ** Return the full pathname of the underlying database file. */ -const char *sqlite3BtreeGetFilename(Btree *p){ - assert( p->pBt->pPager!=0 ); - return sqlite3pager_filename(p->pBt->pPager); +const char *sqlite3BtreeGetFilename(Btree *pBt){ + assert( pBt->pPager!=0 ); + return sqlite3pager_filename(pBt->pPager); } /* ** Return the pathname of the directory that contains the database file. */ -const char *sqlite3BtreeGetDirname(Btree *p){ - assert( p->pBt->pPager!=0 ); - return sqlite3pager_dirname(p->pBt->pPager); +const char *sqlite3BtreeGetDirname(Btree *pBt){ + assert( pBt->pPager!=0 ); + return sqlite3pager_dirname(pBt->pPager); } /* ** Return the pathname of the journal file for this database. The return ** value of this routine is the same regardless of whether the journal file ** has been created or not. */ -const char *sqlite3BtreeGetJournalname(Btree *p){ - assert( p->pBt->pPager!=0 ); - return sqlite3pager_journalname(p->pBt->pPager); +const char *sqlite3BtreeGetJournalname(Btree *pBt){ + assert( pBt->pPager!=0 ); + return sqlite3pager_journalname(pBt->pPager); } #ifndef SQLITE_OMIT_VACUUM /* ** Copy the complete content of pBtFrom into pBtTo. A transaction @@ -6393,36 +5631,30 @@ ** must be active for both files. ** ** The size of file pBtFrom may be reduced by this operation. ** If anything goes wrong, the transaction on pBtFrom is rolled back. */ -int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ - int rc = SQLITE_OK; - Pgno i, nPage, nToPage, iSkip; - - BtShared *pBtTo = pTo->pBt; - BtShared *pBtFrom = pFrom->pBt; - - if( pTo->inTrans!=TRANS_WRITE || pFrom->inTrans!=TRANS_WRITE ){ +int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ + int rc = SQLITE_OK; + Pgno i, nPage, nToPage; + + if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){ return SQLITE_ERROR; } if( pBtTo->pCursor ) return SQLITE_BUSY; nToPage = sqlite3pager_pagecount(pBtTo->pPager); nPage = sqlite3pager_pagecount(pBtFrom->pPager); - iSkip = PENDING_BYTE_PAGE(pBtTo); for(i=1; rc==SQLITE_OK && i<=nPage; i++){ void *pPage; - if( i==iSkip ) continue; rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage); if( rc ) break; rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage); if( rc ) break; sqlite3pager_unref(pPage); } for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ void *pPage; - if( i==iSkip ) continue; rc = sqlite3pager_get(pBtTo->pPager, i, &pPage); if( rc ) break; rc = sqlite3pager_write(pPage); sqlite3pager_unref(pPage); sqlite3pager_dont_write(pBtTo->pPager, i); @@ -6429,28 +5661,28 @@ } if( !rc && nPagepPager, nPage); } if( rc ){ - sqlite3BtreeRollback(pTo); + sqlite3BtreeRollback(pBtTo); } return rc; } #endif /* SQLITE_OMIT_VACUUM */ /* ** Return non-zero if a transaction is active. */ -int sqlite3BtreeIsInTrans(Btree *p){ - return (p && (p->inTrans==TRANS_WRITE)); +int sqlite3BtreeIsInTrans(Btree *pBt){ + return (pBt && (pBt->inTrans==TRANS_WRITE)); } /* ** Return non-zero if a statement transaction is active. */ -int sqlite3BtreeIsInStmt(Btree *p){ - return (p->pBt && p->pBt->inStmt); +int sqlite3BtreeIsInStmt(Btree *pBt){ + return (pBt && pBt->inStmt); } /* ** This call is a no-op if no write-transaction is currently active on pBt. ** @@ -6463,13 +5695,12 @@ ** created, populated with this journal pointer and synced to disk. ** ** Once this is routine has returned, the only thing required to commit ** the write-transaction for this database file is to delete the journal. */ -int sqlite3BtreeSync(Btree *p, const char *zMaster){ - if( p->inTrans==TRANS_WRITE ){ - BtShared *pBt = p->pBt; +int sqlite3BtreeSync(Btree *pBt, const char *zMaster){ + if( pBt->inTrans==TRANS_WRITE ){ #ifndef SQLITE_OMIT_AUTOVACUUM Pgno nTrunc = 0; if( pBt->autoVacuum ){ int rc = autoVacuumCommit(pBt, &nTrunc); if( rc!=SQLITE_OK ) return rc; @@ -6478,78 +5709,5 @@ #endif return sqlite3pager_sync(pBt->pPager, zMaster, 0); } return SQLITE_OK; } - -/* -** This function returns a pointer to a blob of memory associated with -** a single shared-btree. The memory is used by client code for it's own -** purposes (for example, to store a high-level schema associated with -** the shared-btree). The btree layer manages reference counting issues. -** -** The first time this is called on a shared-btree, nBytes bytes of memory -** are allocated, zeroed, and returned to the caller. For each subsequent -** call the nBytes parameter is ignored and a pointer to the same blob -** of memory returned. -** -** Just before the shared-btree is closed, the function passed as the -** xFree argument when the memory allocation was made is invoked on the -** blob of allocated memory. This function should not call sqliteFree() -** on the memory, the btree layer does that. -*/ -void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ - BtShared *pBt = p->pBt; - if( !pBt->pSchema ){ - pBt->pSchema = sqliteMalloc(nBytes); - pBt->xFreeSchema = xFree; - } - return pBt->pSchema; -} - -/* -** Return true if another user of the same shared btree as the argument -** handle holds an exclusive lock on the sqlite_master table. -*/ -int sqlite3BtreeSchemaLocked(Btree *p){ - return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK); -} - -int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ - int rc = SQLITE_OK; -#ifndef SQLITE_OMIT_SHARED_CACHE - u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK); - rc = queryTableLock(p, iTab, lockType); - if( rc==SQLITE_OK ){ - rc = lockTable(p, iTab, lockType); - } -#endif - return rc; -} - -/* -** The following debugging interface has to be in this file (rather -** than in, for example, test1.c) so that it can get access to -** the definition of BtShared. -*/ -#if defined(SQLITE_TEST) && defined(TCLSH) -#include -int sqlite3_shared_cache_report( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - const ThreadData *pTd = sqlite3ThreadDataReadOnly(); - if( pTd->useSharedData ){ - BtShared *pBt; - Tcl_Obj *pRet = Tcl_NewObj(); - for(pBt=pTd->pBtree; pBt; pBt=pBt->pNext){ - const char *zFile = sqlite3pager_filename(pBt->pPager); - Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1)); - Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef)); - } - Tcl_SetObjResult(interp, pRet); - } - return TCL_OK; -} -#endif Index: SQLite.Interop/src/btree.h ================================================================== --- SQLite.Interop/src/btree.h +++ SQLite.Interop/src/btree.h @@ -11,11 +11,11 @@ ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: btree.h,v 1.1 2005/03/01 16:04:27 rmsimpson Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ /* TODO: This definition is just included so other modules compile. It @@ -34,16 +34,14 @@ /* ** Forward declarations of structure */ typedef struct Btree Btree; typedef struct BtCursor BtCursor; -typedef struct BtShared BtShared; int sqlite3BtreeOpen( const char *zFilename, /* Name of database file to open */ - sqlite3 *db, /* Associated database connection */ Btree **, /* Return open Btree* here */ int flags /* Flags */ ); /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the @@ -58,11 +56,10 @@ int sqlite3BtreeClose(Btree*); int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*); int sqlite3BtreeSetCacheSize(Btree*,int); int sqlite3BtreeSetSafetyLevel(Btree*,int); -int sqlite3BtreeSyncDisabled(Btree*); int sqlite3BtreeSetPageSize(Btree*,int,int); int sqlite3BtreeGetPageSize(Btree*); int sqlite3BtreeGetReserve(Btree*); int sqlite3BtreeSetAutoVacuum(Btree *, int); int sqlite3BtreeGetAutoVacuum(Btree *); @@ -74,13 +71,10 @@ int sqlite3BtreeRollbackStmt(Btree*); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); int sqlite3BtreeIsInStmt(Btree*); int sqlite3BtreeSync(Btree*, const char *zMaster); -void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); -int sqlite3BtreeSchemaLocked(Btree *); -int sqlite3BtreeLockTable(Btree *, int, u8); const char *sqlite3BtreeGetFilename(Btree *); const char *sqlite3BtreeGetDirname(Btree *); const char *sqlite3BtreeGetJournalname(Btree *); int sqlite3BtreeCopyFile(Btree *, Btree *); Index: SQLite.Interop/src/build.c ================================================================== --- SQLite.Interop/src/build.c +++ SQLite.Interop/src/build.c @@ -20,11 +20,11 @@ ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: build.c,v 1.1 2005/03/01 16:04:28 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* @@ -34,90 +34,10 @@ void sqlite3BeginParse(Parse *pParse, int explainFlag){ pParse->explain = explainFlag; pParse->nVar = 0; } -#ifndef SQLITE_OMIT_SHARED_CACHE -/* -** The TableLock structure is only used by the sqlite3TableLock() and -** codeTableLocks() functions. -*/ -struct TableLock { - int iDb; - int iTab; - u8 isWriteLock; - const char *zName; -}; - -/* -** Have the compiled statement lock the table with rootpage iTab in database -** iDb at the shared-cache level when executed. The isWriteLock argument -** is zero for a read-lock, or non-zero for a write-lock. -** -** The zName parameter should point to the unqualified table name. This is -** used to provide a more informative error message should the lock fail. -*/ -void sqlite3TableLock( - Parse *pParse, - int iDb, - int iTab, - u8 isWriteLock, - const char *zName -){ - int i; - int nBytes; - TableLock *p; - - if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){ - return; - } - - for(i=0; inTableLock; i++){ - p = &pParse->aTableLock[i]; - if( p->iDb==iDb && p->iTab==iTab ){ - p->isWriteLock = (p->isWriteLock || isWriteLock); - return; - } - } - - nBytes = sizeof(TableLock) * (pParse->nTableLock+1); - sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes); - if( pParse->aTableLock ){ - p = &pParse->aTableLock[pParse->nTableLock++]; - p->iDb = iDb; - p->iTab = iTab; - p->isWriteLock = isWriteLock; - p->zName = zName; - } -} - -/* -** Code an OP_TableLock instruction for each table locked by the -** statement (configured by calls to sqlite3TableLock()). -*/ -static void codeTableLocks(Parse *pParse){ - int i; - Vdbe *pVdbe; - assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 ); - - if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){ - return; - } - - for(i=0; inTableLock; i++){ - TableLock *p = &pParse->aTableLock[i]; - int p1 = p->iDb; - if( p->isWriteLock ){ - p1 = -1*(p1+1); - } - sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC); - } -} -#else - #define codeTableLocks(x) -#endif - /* ** This routine is called after a single SQL statement has been ** parsed and a VDBE program to execute that statement has been ** prepared. This routine puts the finishing touches on the ** VDBE program and resets the pParse structure for the next @@ -128,11 +48,11 @@ */ void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; - if( sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( sqlite3_malloc_failed ) return; if( pParse->nested ) return; if( !pParse->pVdbe ){ if( pParse->rc==SQLITE_OK && pParse->nErr ){ pParse->rc = SQLITE_ERROR; } @@ -154,44 +74,36 @@ ** on each used database. */ if( pParse->cookieGoto>0 ){ u32 mask; int iDb; - sqlite3VdbeJumpHere(v, pParse->cookieGoto-1); + sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v)); for(iDb=0, mask=1; iDbnDb; mask<<=1, iDb++){ if( (mask & pParse->cookieMask)==0 ) continue; sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); } - - /* Once all the cookies have been verified and transactions opened, - ** obtain the required table-locks. This is a no-op unless the - ** shared-cache feature is enabled. - */ - codeTableLocks(pParse); sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto); } -#ifndef SQLITE_OMIT_TRACE /* Add a No-op that contains the complete text of the compiled SQL ** statement as its P3 argument. This does not change the functionality ** of the program. ** ** This is used to implement sqlite3_trace(). */ sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql); -#endif /* SQLITE_OMIT_TRACE */ } /* Get the VDBE program ready for execution */ if( v && pParse->nErr==0 ){ FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; sqlite3VdbeTrace(v, trace); sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3, - pParse->nTab+3, pParse->explain); + pParse->nTab+3, pParse->nMaxDepth+1, pParse->explain); pParse->rc = SQLITE_DONE; pParse->colNamesSet = 0; }else if( pParse->rc==SQLITE_OK ){ pParse->rc = SQLITE_ERROR; } @@ -216,10 +128,11 @@ ** care if you decide to try to use this routine for some other purposes. */ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ va_list ap; char *zSql; + int rc; # define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar)) char saveBuf[SAVE_SZ]; if( pParse->nErr ) return; assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ @@ -230,11 +143,11 @@ return; /* A malloc must have failed */ } pParse->nested++; memcpy(saveBuf, &pParse->nVar, SAVE_SZ); memset(&pParse->nVar, 0, SAVE_SZ); - sqlite3RunParser(pParse, zSql, 0); + rc = sqlite3RunParser(pParse, zSql, 0); sqliteFree(zSql); memcpy(&pParse->nVar, saveBuf, SAVE_SZ); pParse->nested--; } @@ -252,14 +165,15 @@ */ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; assert( zName!=0 ); - for(i=OMIT_TEMPDB; inDb; i++){ + assert( (db->flags & SQLITE_Initialized) || db->init.busy ); + for(i=0; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; - p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, strlen(zName)+1); + p = sqlite3HashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1); if( p ) break; } return p; } @@ -284,10 +198,13 @@ p = sqlite3FindTable(pParse->db, zName, zDbase); if( p==0 ){ if( zDbase ){ sqlite3ErrorMsg(pParse, "no such table: %s.%s", zDbase, zName); + }else if( sqlite3FindTable(pParse->db, zName, 0)!=0 ){ + sqlite3ErrorMsg(pParse, "table \"%s\" is not in database \"%s\"", + zName, zDbase); }else{ sqlite3ErrorMsg(pParse, "no such table: %s", zName); } pParse->checkSchema = 1; } @@ -307,18 +224,15 @@ ** using the ATTACH command. */ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){ Index *p = 0; int i; - for(i=OMIT_TEMPDB; inDb; i++){ + assert( (db->flags & SQLITE_Initialized) || db->init.busy ); + for(i=0; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - Schema *pSchema = db->aDb[j].pSchema; if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; - assert( pSchema || (j==1 && !db->aDb[1].pBt) ); - if( pSchema ){ - p = sqlite3HashFind(&pSchema->idxHash, zName, strlen(zName)+1); - } + p = sqlite3HashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1); if( p ) break; } return p; } @@ -338,30 +252,32 @@ ** it is not unlinked from the Table that it indexes. ** Unlinking from the Table must be done by the calling function. */ static void sqliteDeleteIndex(sqlite3 *db, Index *p){ Index *pOld; - const char *zName = p->zName; - pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName, strlen( zName)+1, 0); - assert( pOld==0 || pOld==p ); + assert( db!=0 && p->zName!=0 ); + pOld = sqlite3HashInsert(&db->aDb[p->iDb].idxHash, p->zName, + strlen(p->zName)+1, 0); + if( pOld!=0 && pOld!=p ){ + sqlite3HashInsert(&db->aDb[p->iDb].idxHash, pOld->zName, + strlen(pOld->zName)+1, pOld); + } freeIndex(p); } /* -** For the index called zIdxName which is found in the database iDb, -** unlike that index from its Table then remove the index from -** the index hash table and free all memory structures associated -** with the index. +** Unlink the given index from its table, then remove +** the index from the index hash table and free its memory +** structures. */ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ Index *pIndex; int len; - Hash *pHash = &db->aDb[iDb].pSchema->idxHash; len = strlen(zIdxName); - pIndex = sqlite3HashInsert(pHash, zIdxName, len+1, 0); + pIndex = sqlite3HashInsert(&db->aDb[iDb].idxHash, zIdxName, len+1, 0); if( pIndex ){ if( pIndex->pTable->pIndex==pIndex ){ pIndex->pTable->pIndex = pIndex->pNext; }else{ Index *p; @@ -385,25 +301,43 @@ ** If iDb<=0 then reset the internal schema tables for all database ** files. If iDb>=2 then reset the internal schema for only the ** single file indicated. */ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ + HashElem *pElem; + Hash temp1; + Hash temp2; int i, j; assert( iDb>=0 && iDbnDb ); + db->flags &= ~SQLITE_Initialized; for(i=iDb; inDb; i++){ Db *pDb = &db->aDb[i]; - if( pDb->pSchema ){ - sqlite3SchemaFree(pDb->pSchema); + temp1 = pDb->tblHash; + temp2 = pDb->trigHash; + sqlite3HashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0); + sqlite3HashClear(&pDb->aFKey); + sqlite3HashClear(&pDb->idxHash); + for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ + sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); } + sqlite3HashClear(&temp2); + sqlite3HashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0); + for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ + Table *pTab = sqliteHashData(pElem); + sqlite3DeleteTable(db, pTab); + } + sqlite3HashClear(&temp1); + pDb->pSeqTab = 0; + DbClearProperty(db, i, DB_SchemaLoaded); if( iDb>0 ) return; } assert( iDb==0 ); db->flags &= ~SQLITE_InternChanges; /* If one or more of the auxiliary database files has been closed, - ** then remove them from the auxiliary database list. We take the + ** then remove then from the auxiliary database list. We take the ** opportunity to do this here since we have just deleted all of the ** schema hash tables and therefore do not have to make any changes ** to any of those tables. */ for(i=0; inDb; i++){ @@ -457,19 +391,16 @@ */ static void sqliteResetColumnNames(Table *pTable){ int i; Column *pCol; assert( pTable!=0 ); - if( (pCol = pTable->aCol)!=0 ){ - for(i=0; inCol; i++, pCol++){ - sqliteFree(pCol->zName); - sqlite3ExprDelete(pCol->pDflt); - sqliteFree(pCol->zType); - sqliteFree(pCol->zColl); - } - sqliteFree(pTable->aCol); - } + for(i=0, pCol=pTable->aCol; inCol; i++, pCol++){ + sqliteFree(pCol->zName); + sqlite3ExprDelete(pCol->pDflt); + sqliteFree(pCol->zType); + } + sqliteFree(pTable->aCol); pTable->aCol = 0; pTable->nCol = 0; } /* @@ -489,36 +420,28 @@ */ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; FKey *pFKey, *pNextFKey; - db = 0; - if( pTable==0 ) return; - /* Do not delete the table until the reference count reaches zero. */ - pTable->nRef--; - if( pTable->nRef>0 ){ - return; - } - assert( pTable->nRef==0 ); - /* Delete all indices associated with this table */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; - assert( pIndex->pSchema==pTable->pSchema ); + assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) ); sqliteDeleteIndex(db, pIndex); } #ifndef SQLITE_OMIT_FOREIGN_KEY /* Delete all foreign keys associated with this table. The keys ** should have already been unlinked from the db->aFKey hash table */ for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){ pNextFKey = pFKey->pNextFrom; - assert( sqlite3HashFind(&pTable->pSchema->aFKey, + assert( pTable->iDbnDb ); + assert( sqlite3HashFind(&db->aDb[pTable->iDb].aFKey, pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey ); sqliteFree(pFKey); } #endif @@ -526,13 +449,10 @@ */ sqliteResetColumnNames(pTable); sqliteFree(pTable->zName); sqliteFree(pTable->zColAff); sqlite3SelectDelete(pTable->pSelect); -#ifndef SQLITE_OMIT_CHECK - sqlite3ExprDelete(pTable->pCheck); -#endif sqliteFree(pTable); } /* ** Unlink the given table from the hash tables and the delete the @@ -545,18 +465,18 @@ assert( db!=0 ); assert( iDb>=0 && iDbnDb ); assert( zTabName && zTabName[0] ); pDb = &db->aDb[iDb]; - p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, strlen(zTabName)+1,0); + p = sqlite3HashInsert(&pDb->tblHash, zTabName, strlen(zTabName)+1, 0); if( p ){ #ifndef SQLITE_OMIT_FOREIGN_KEY for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){ int nTo = strlen(pF1->zTo) + 1; - pF2 = sqlite3HashFind(&pDb->pSchema->aFKey, pF1->zTo, nTo); + pF2 = sqlite3HashFind(&pDb->aFKey, pF1->zTo, nTo); if( pF2==pF1 ){ - sqlite3HashInsert(&pDb->pSchema->aFKey, pF1->zTo, nTo, pF1->pNextTo); + sqlite3HashInsert(&pDb->aFKey, pF1->zTo, nTo, pF1->pNextTo); }else{ while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; } if( pF2 ){ pF2->pNextTo = pF1->pNextTo; } @@ -572,18 +492,18 @@ ** Given a token, return a string that consists of the text of that ** token with any quotations removed. Space to hold the returned string ** is obtained from sqliteMalloc() and must be freed by the calling ** function. ** -** Tokens are often just pointers into the original SQL text and so +** Tokens are really just pointers into the original SQL text and so ** are not \000 terminated and are not persistent. The returned string ** is \000 terminated and is persistent. */ char *sqlite3NameFromToken(Token *pName){ char *zName; if( pName ){ - zName = sqliteStrNDup((char*)pName->z, pName->n); + zName = sqliteStrNDup(pName->z, pName->n); sqlite3Dequote(zName); }else{ zName = 0; } return zName; @@ -591,13 +511,11 @@ /* ** Open the sqlite_master table stored in database number iDb for ** writing. The table is opened using cursor 0. */ -void sqlite3OpenMasterTable(Parse *p, int iDb){ - Vdbe *v = sqlite3GetVdbe(p); - sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb)); +void sqlite3OpenMasterTable(Vdbe *v, int iDb){ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT); sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */ } @@ -605,22 +523,21 @@ ** The token *pName contains the name of a database (either "main" or ** "temp" or the name of an attached db). This routine returns the ** index of the named database in db->aDb[], or -1 if the named db ** does not exist. */ -int sqlite3FindDb(sqlite3 *db, Token *pName){ +static int findDb(sqlite3 *db, Token *pName){ int i = -1; /* Database number */ int n; /* Number of characters in the name */ Db *pDb; /* A database whose name space is being searched */ char *zName; /* Name we are searching for */ zName = sqlite3NameFromToken(pName); if( zName ){ n = strlen(zName); for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ - if( (!OMIT_TEMPDB || i!=1 ) && n==strlen(pDb->zName) && - 0==sqlite3StrICmp(pDb->zName, zName) ){ + if( n==strlen(pDb->zName) && 0==sqlite3StrICmp(pDb->zName, zName) ){ break; } } sqliteFree(zName); } @@ -653,11 +570,11 @@ sqlite3 *db = pParse->db; if( pName2 && pName2->n>0 ){ assert( !db->init.busy ); *pUnqual = pName2; - iDb = sqlite3FindDb(db, pName1); + iDb = findDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); pParse->nErr++; return -1; } @@ -676,11 +593,10 @@ ** "sqlite_" (in upper, lower or mixed case). This portion of the namespace ** is reserved for internal use. */ int sqlite3CheckObjectName(Parse *pParse, const char *zName){ if( !pParse->db->init.busy && pParse->nested==0 - && (pParse->db->flags & SQLITE_WriteSchema)==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); return SQLITE_ERROR; } return SQLITE_OK; @@ -707,14 +623,14 @@ Parse *pParse, /* Parser context */ Token *pStart, /* The "CREATE" token */ Token *pName1, /* First part of the name of the table or view */ Token *pName2, /* Second part of the name of the table or view */ int isTemp, /* True if this is a TEMP table */ - int isView, /* True if this is a VIEW */ - int noErr /* Do nothing if table already exists */ + int isView /* True if this is a VIEW */ ){ Table *pTable; + Index *pIdx; char *zName = 0; /* The name of the new table */ sqlite3 *db = pParse->db; Vdbe *v; int iDb; /* Database number to create the table in */ Token *pName; /* Unqualified name of the table to create */ @@ -736,16 +652,16 @@ ** set to the index of the database that the table or view is to be ** created in. */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); if( iDb<0 ) return; - if( !OMIT_TEMPDB && isTemp && iDb>1 ){ + if( isTemp && iDb>1 ){ /* If creating a temp table, the name may not be qualified */ sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); return; } - if( !OMIT_TEMPDB && isTemp ) iDb = 1; + if( isTemp ) iDb = 1; pParse->sNameToken = *pName; zName = sqlite3NameFromToken(pName); if( zName==0 ) return; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ @@ -759,17 +675,17 @@ char *zDb = db->aDb[iDb].zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ goto begin_table_error; } if( isView ){ - if( !OMIT_TEMPDB && isTemp ){ + if( isTemp ){ code = SQLITE_CREATE_TEMP_VIEW; }else{ code = SQLITE_CREATE_VIEW; } }else{ - if( !OMIT_TEMPDB && isTemp ){ + if( isTemp ){ code = SQLITE_CREATE_TEMP_TABLE; }else{ code = SQLITE_CREATE_TABLE; } } @@ -786,16 +702,15 @@ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName); if( pTable ){ - if( !noErr ){ - sqlite3ErrorMsg(pParse, "table %T already exists", pName); - } + sqlite3ErrorMsg(pParse, "table %T already exists", pName); goto begin_table_error; } - if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){ + if( (pIdx = sqlite3FindIndex(db, zName, 0))!=0 && + ( iDb==0 || !db->init.busy) ){ sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); goto begin_table_error; } pTable = sqliteMalloc( sizeof(Table) ); if( pTable==0 ){ @@ -806,22 +721,21 @@ pTable->zName = zName; pTable->nCol = 0; pTable->aCol = 0; pTable->iPKey = -1; pTable->pIndex = 0; - pTable->pSchema = db->aDb[iDb].pSchema; - pTable->nRef = 1; + pTable->iDb = iDb; if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; /* If this is the magic sqlite_sequence table used by autoincrement, ** then record a pointer to this table in the main database structure ** so that INSERT can find the table easily. */ #ifndef SQLITE_OMIT_AUTOINCREMENT - if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){ - pTable->pSchema->pSeqTab = pTable; + if( strcmp(zName, "sqlite_sequence")==0 ){ + db->aDb[iDb].pSeqTab = pTable; } #endif /* Begin generating the code that will insert the table record into ** the SQLITE_MASTER table. Note in particular that we must go ahead @@ -831,24 +745,21 @@ ** indices. Hence, the record number for the table must be allocated ** now. */ if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){ int lbl; - int fileFormat; sqlite3BeginWriteOperation(pParse, 0, iDb); /* If the file format and encoding in the database have not been set, ** set them now. */ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */ lbl = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_If, 0, lbl); - fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? - 1 : SQLITE_DEFAULT_FILE_FORMAT; - sqlite3VdbeAddOp(v, OP_Integer, fileFormat, 0); + sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); - sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0); + sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4); sqlite3VdbeResolveLabel(v, lbl); /* This just creates a place-holder record in the sqlite_master table. ** The record created does not contain anything yet. It will be replaced @@ -864,15 +775,15 @@ }else #endif { sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0); } - sqlite3OpenMasterTable(pParse, iDb); - sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0); + sqlite3OpenMasterTable(v, iDb); + sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0); sqlite3VdbeAddOp(v, OP_Dup, 0, 0); - sqlite3VdbeAddOp(v, OP_Null, 0, 0); - sqlite3VdbeAddOp(v, OP_Insert, 0, 0); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); + sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0); sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); } /* Normal (non-error) return. */ @@ -921,14 +832,11 @@ } } if( (p->nCol & 0x7)==0 ){ Column *aNew; aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0])); - if( aNew==0 ){ - sqliteFree(z); - return; - } + if( aNew==0 ) return; p->aCol = aNew; } pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zName = z; @@ -936,10 +844,11 @@ /* If there is no type specified, columns have the default affinity ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will ** be called next to set pCol->affinity correctly. */ pCol->affinity = SQLITE_AFF_NONE; + pCol->pColl = pParse->db->pDfltColl; p->nCol++; } /* ** This routine is called by the parser while in the middle of @@ -971,22 +880,19 @@ ** 'INT' | SQLITE_AFF_INTEGER ** 'CHAR' | SQLITE_AFF_TEXT ** 'CLOB' | SQLITE_AFF_TEXT ** 'TEXT' | SQLITE_AFF_TEXT ** 'BLOB' | SQLITE_AFF_NONE -** 'REAL' | SQLITE_AFF_REAL -** 'FLOA' | SQLITE_AFF_REAL -** 'DOUB' | SQLITE_AFF_REAL ** ** If none of the substrings in the above table are found, ** SQLITE_AFF_NUMERIC is returned. */ -char sqlite3AffinityType(const Token *pType){ +static char sqlite3AffinityType(const char *zType, int nType){ u32 h = 0; char aff = SQLITE_AFF_NUMERIC; - const unsigned char *zIn = pType->z; - const unsigned char *zEnd = &pType->z[pType->n]; + const unsigned char *zIn = zType; + const unsigned char *zEnd = (zIn+nType); while( zIn!=zEnd ){ h = (h<<8) + sqlite3UpperToLower[*zIn]; zIn++; if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */ @@ -994,25 +900,14 @@ }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */ aff = SQLITE_AFF_TEXT; }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */ aff = SQLITE_AFF_TEXT; }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ - && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){ + && aff==SQLITE_AFF_NUMERIC ){ aff = SQLITE_AFF_NONE; -#ifndef SQLITE_OMIT_FLOATING_POINT - }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */ - && aff==SQLITE_AFF_NUMERIC ){ - aff = SQLITE_AFF_REAL; - }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */ - && aff==SQLITE_AFF_NUMERIC ){ - aff = SQLITE_AFF_REAL; - }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */ - && aff==SQLITE_AFF_NUMERIC ){ - aff = SQLITE_AFF_REAL; -#endif }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */ - aff = SQLITE_AFF_INTEGER; + aff = SQLITE_AFF_INTEGER; break; } } return aff; @@ -1025,22 +920,34 @@ ** column currently under construction. pLast is the last token ** in the sequence. Use this information to construct a string ** that contains the typename of the column and store that string ** in zType. */ -void sqlite3AddColumnType(Parse *pParse, Token *pType){ +void sqlite3AddColumnType(Parse *pParse, Token *pFirst, Token *pLast){ Table *p; - int i; + int i, j; + int n; + char *z; + const unsigned char *zIn; + Column *pCol; - if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; if( i<0 ) return; pCol = &p->aCol[i]; - sqliteFree(pCol->zType); - pCol->zType = sqlite3NameFromToken(pType); - pCol->affinity = sqlite3AffinityType(pType); + zIn = pFirst->z; + n = pLast->n + (pLast->z - zIn); + assert( pCol->zType==0 ); + z = pCol->zType = sqliteMallocRaw(n+1); + if( z==0 ) return; + for(i=j=0; iaffinity = sqlite3AffinityType(z, n); } /* ** The expression is the default value for the most recently added column ** of the table currently under construction. @@ -1052,19 +959,18 @@ ** parsing a CREATE TABLE statement. */ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){ Table *p; Column *pCol; - if( (p = pParse->pNewTable)!=0 ){ - pCol = &(p->aCol[p->nCol-1]); - if( !sqlite3ExprIsConstantOrFunction(pExpr) ){ - sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", - pCol->zName); - }else{ - sqlite3ExprDelete(pCol->pDflt); - pCol->pDflt = sqlite3ExprDup(pExpr); - } + if( (p = pParse->pNewTable)==0 ) return; + pCol = &(p->aCol[p->nCol-1]); + if( !sqlite3ExprIsConstant(pExpr) ){ + sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", + pCol->zName); + }else{ + sqlite3ExprDelete(pCol->pDflt); + pCol->pDflt = sqlite3ExprDup(pExpr); } sqlite3ExprDelete(pExpr); } /* @@ -1087,12 +993,11 @@ */ void sqlite3AddPrimaryKey( Parse *pParse, /* Parsing context */ ExprList *pList, /* List of field names to be indexed */ int onError, /* What to do with a uniqueness conflict */ - int autoInc, /* True if the AUTOINCREMENT keyword is present */ - int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ + int autoInc /* True if the AUTOINCREMENT keyword is present */ ){ Table *pTab = pParse->pNewTable; char *zType = 0; int iCol = -1, i; if( pTab==0 ) goto primary_key_exit; @@ -1110,84 +1015,217 @@ for(iCol=0; iColnCol; iCol++){ if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){ break; } } - if( iColnCol ){ - pTab->aCol[iCol].isPrimKey = 1; - } + if( iColnCol ) pTab->aCol[iCol].isPrimKey = 1; } if( pList->nExpr>1 ) iCol = -1; } if( iCol>=0 && iColnCol ){ zType = pTab->aCol[iCol].zType; } - if( zType && sqlite3StrICmp(zType, "INTEGER")==0 - && sortOrder==SQLITE_SO_ASC ){ + if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){ pTab->iPKey = iCol; pTab->keyConf = onError; pTab->autoInc = autoInc; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ - sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); + sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pList); return; } -/* -** Add a new CHECK constraint to the table currently under construction. -*/ -void sqlite3AddCheckConstraint( - Parse *pParse, /* Parsing context */ - Expr *pCheckExpr /* The check expression */ -){ -#ifndef SQLITE_OMIT_CHECK - Table *pTab = pParse->pNewTable; - if( pTab ){ - /* The CHECK expression must be duplicated so that tokens refer - ** to malloced space and not the (ephemeral) text of the CREATE TABLE - ** statement */ - pTab->pCheck = sqlite3ExprAnd(pTab->pCheck, sqlite3ExprDup(pCheckExpr)); - } -#endif - sqlite3ExprDelete(pCheckExpr); -} - /* ** Set the collation function of the most recently parsed table column ** to the CollSeq given. */ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){ Table *p; + Index *pIdx; + CollSeq *pColl; int i; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; - if( sqlite3LocateCollSeq(pParse, zType, nType) ){ - Index *pIdx; - p->aCol[i].zColl = sqliteStrNDup(zType, nType); - - /* If the column is declared as " PRIMARY KEY COLLATE ", - ** then an index may have been created on this column before the - ** collation type was added. Correct this if it is the case. + pColl = sqlite3LocateCollSeq(pParse, zType, nType); + p->aCol[i].pColl = pColl; + + /* If the column is declared as " PRIMARY KEY COLLATE ", + ** then an index may have been created on this column before the + ** collation type was added. Correct this if it is the case. + */ + for(pIdx = p->pIndex; pIdx; pIdx=pIdx->pNext){ + assert( pIdx->nColumn==1 ); + if( pIdx->aiColumn[0]==i ) pIdx->keyInfo.aColl[0] = pColl; + } +} + +/* +** Locate and return an entry from the db.aCollSeq hash table. If the entry +** specified by zName and nName is not found and parameter 'create' is +** true, then create a new entry. Otherwise return NULL. +** +** Each pointer stored in the sqlite3.aCollSeq hash table contains an +** array of three CollSeq structures. The first is the collation sequence +** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be. +** +** Stored immediately after the three collation sequences is a copy of +** the collation sequence name. A pointer to this string is stored in +** each collation sequence structure. +*/ +static CollSeq * findCollSeqEntry( + sqlite3 *db, + const char *zName, + int nName, + int create +){ + CollSeq *pColl; + if( nName<0 ) nName = strlen(zName); + pColl = sqlite3HashFind(&db->aCollSeq, zName, nName); + + if( 0==pColl && create ){ + pColl = sqliteMalloc( 3*sizeof(*pColl) + nName + 1 ); + if( pColl ){ + pColl[0].zName = (char*)&pColl[3]; + pColl[0].enc = SQLITE_UTF8; + pColl[1].zName = (char*)&pColl[3]; + pColl[1].enc = SQLITE_UTF16LE; + pColl[2].zName = (char*)&pColl[3]; + pColl[2].enc = SQLITE_UTF16BE; + memcpy(pColl[0].zName, zName, nName); + pColl[0].zName[nName] = 0; + sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl); + } + } + return pColl; +} + +/* +** Parameter zName points to a UTF-8 encoded string nName bytes long. +** Return the CollSeq* pointer for the collation sequence named zName +** for the encoding 'enc' from the database 'db'. +** +** If the entry specified is not found and 'create' is true, then create a +** new entry. Otherwise return NULL. +*/ +CollSeq *sqlite3FindCollSeq( + sqlite3 *db, + u8 enc, + const char *zName, + int nName, + int create +){ + CollSeq *pColl = findCollSeqEntry(db, zName, nName, create); + assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); + assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); + if( pColl ) pColl += enc-1; + return pColl; +} + +/* +** Invoke the 'collation needed' callback to request a collation sequence +** in the database text encoding of name zName, length nName. +** If the collation sequence +*/ +static void callCollNeeded(sqlite3 *db, const char *zName, int nName){ + assert( !db->xCollNeeded || !db->xCollNeeded16 ); + if( nName<0 ) nName = strlen(zName); + if( db->xCollNeeded ){ + char *zExternal = sqliteStrNDup(zName, nName); + if( !zExternal ) return; + db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal); + sqliteFree(zExternal); + } +#ifndef SQLITE_OMIT_UTF16 + if( db->xCollNeeded16 ){ + char const *zExternal; + sqlite3_value *pTmp = sqlite3GetTransientValue(db); + sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC); + zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE); + if( !zExternal ) return; + db->xCollNeeded16(db->pCollNeededArg, db, (int)db->enc, zExternal); + } +#endif +} + +/* +** This routine is called if the collation factory fails to deliver a +** collation function in the best encoding but there may be other versions +** of this collation function (for other text encodings) available. Use one +** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if +** possible. +*/ +static int synthCollSeq(Parse *pParse, CollSeq *pColl){ + CollSeq *pColl2; + char *z = pColl->zName; + int n = strlen(z); + sqlite3 *db = pParse->db; + int i; + static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 }; + for(i=0; i<3; i++){ + pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, n, 0); + if( pColl2->xCmp!=0 ){ + memcpy(pColl, pColl2, sizeof(CollSeq)); + return SQLITE_OK; + } + } + if( pParse->nErr==0 ){ + sqlite3ErrorMsg(pParse, "no such collation sequence: %.*s", n, z); + } + pParse->nErr++; + return SQLITE_ERROR; +} + +/* +** This routine is called on a collation sequence before it is used to +** check that it is defined. An undefined collation sequence exists when +** a database is loaded that contains references to collation sequences +** that have not been defined by sqlite3_create_collation() etc. +** +** If required, this routine calls the 'collation needed' callback to +** request a definition of the collating sequence. If this doesn't work, +** an equivalent collating sequence that uses a text encoding different +** from the main database is substituted, if one is available. +*/ +int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ + if( pColl && !pColl->xCmp ){ + /* No collation sequence of this type for this encoding is registered. + ** Call the collation factory to see if it can supply us with one. */ - for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ - assert( pIdx->nColumn==1 ); - if( pIdx->aiColumn[0]==i ){ - pIdx->azColl[0] = p->aCol[i].zColl; + callCollNeeded(pParse->db, pColl->zName, strlen(pColl->zName)); + if( !pColl->xCmp && synthCollSeq(pParse, pColl) ){ + return SQLITE_ERROR; + } + } + return SQLITE_OK; +} + +/* +** Call sqlite3CheckCollSeq() for all collating sequences in an index, +** in order to verify that all the necessary collating sequences are +** loaded. +*/ +int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){ + if( pIdx ){ + int i; + for(i=0; inColumn; i++){ + if( sqlite3CheckCollSeq(pParse, pIdx->keyInfo.aColl[i]) ){ + return SQLITE_ERROR; } } } + return SQLITE_OK; } /* ** This function returns the collation sequence for database native text ** encoding identified by the string zName, length nName. @@ -1201,27 +1239,37 @@ ** If no versions of the requested collations sequence are available, or ** another error occurs, NULL is returned and an error message written into ** pParse. */ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){ - sqlite3 *db = pParse->db; - u8 enc = ENC(db); - u8 initbusy = db->init.busy; - CollSeq *pColl; + u8 enc = pParse->db->enc; + u8 initbusy = pParse->db->init.busy; + CollSeq *pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, initbusy); + if( nName<0 ) nName = strlen(zName); + if( !initbusy && (!pColl || !pColl->xCmp) ){ + /* No collation sequence of this type for this encoding is registered. + ** Call the collation factory to see if it can supply us with one. + */ + callCollNeeded(pParse->db, zName, nName); + pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, 0); + if( pColl && !pColl->xCmp ){ + /* There may be a version of the collation sequence that requires + ** translation between encodings. Search for it with synthCollSeq(). + */ + if( synthCollSeq(pParse, pColl) ){ + return 0; + } + } + } - pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy); + /* If nothing has been found, write the error message into pParse */ if( !initbusy && (!pColl || !pColl->xCmp) ){ - pColl = sqlite3GetCollSeq(db, pColl, zName, nName); - if( !pColl ){ - if( nName<0 ){ - nName = strlen(zName); - } + if( pParse->nErr==0 ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %.*s", nName, zName); - pColl = 0; } + pColl = 0; } - return pColl; } /* @@ -1239,11 +1287,11 @@ ** set back to prior value. But schema changes are infrequent ** and the probability of hitting the same cookie value is only ** 1 chance in 2^32. So we're safe enough. */ void sqlite3ChangeCookie(sqlite3 *db, Vdbe *v, int iDb){ - sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, 0); + sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].schema_cookie+1, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0); } /* ** Measure the number of characters needed to output the given @@ -1287,11 +1335,11 @@ /* ** Generate a CREATE TABLE statement appropriate for the given ** table. Memory to hold the text of the statement is obtained ** from sqliteMalloc() and must be freed by the calling function. */ -static char *createTableStmt(Table *p, int isTemp){ +static char *createTableStmt(Table *p){ int i, k, n; char *zStmt; char *zSep, *zSep2, *zEnd, *z; Column *pCol; n = 0; @@ -1313,11 +1361,11 @@ zEnd = "\n)"; } n += 35 + 6*p->nCol; zStmt = sqliteMallocRaw( n ); if( zStmt==0 ) return 0; - strcpy(zStmt, !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE "); + strcpy(zStmt, p->iDb==1 ? "CREATE TEMP TABLE " : "CREATE TABLE "); k = strlen(zStmt); identPut(zStmt, &k, p->zName); zStmt[k++] = '('; for(pCol=p->aCol, i=0; inCol; i++, pCol++){ strcpy(&zStmt[k], zSep); @@ -1344,61 +1392,28 @@ ** ** An entry for the table is made in the master table on disk, unless ** this is a temporary table or db->init.busy==1. When db->init.busy==1 ** it means we are reading the sqlite_master table because we just ** connected to the database or because the sqlite_master table has -** recently changed, so the entry for this table already exists in +** recently changes, so the entry for this table already exists in ** the sqlite_master table. We do not want to create it again. ** ** If the pSelect argument is not NULL, it means that this routine ** was called to create a table generated from a ** "CREATE TABLE ... AS SELECT ..." statement. The column names of ** the new table will match the result set of the SELECT. */ -void sqlite3EndTable( - Parse *pParse, /* Parse context */ - Token *pCons, /* The ',' token after the last column defn. */ - Token *pEnd, /* The final ')' token in the CREATE TABLE */ - Select *pSelect /* Select from a "CREATE ... AS SELECT" */ -){ +void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){ Table *p; sqlite3 *db = pParse->db; - int iDb; - if( (pEnd==0 && pSelect==0) || - pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) { - return; - } + if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3_malloc_failed ) return; p = pParse->pNewTable; if( p==0 ) return; assert( !db->init.busy || !pSelect ); - iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); - -#ifndef SQLITE_OMIT_CHECK - /* Resolve names in all CHECK constraint expressions. - */ - if( p->pCheck ){ - SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ - NameContext sNC; /* Name context for pParse->pNewTable */ - - memset(&sNC, 0, sizeof(sNC)); - memset(&sSrc, 0, sizeof(sSrc)); - sSrc.nSrc = 1; - sSrc.a[0].zName = p->zName; - sSrc.a[0].pTab = p; - sSrc.a[0].iCursor = -1; - sNC.pParse = pParse; - sNC.pSrcList = &sSrc; - sNC.isCheck = 1; - if( sqlite3ExprResolveNames(&sNC, p->pCheck) ){ - return; - } - } -#endif /* !defined(SQLITE_OMIT_CHECK) */ - /* If the db->init.busy is 1 it means we are reading the SQL off the ** "sqlite_master" or "sqlite_temp_master" table on the disk. ** So do not write to the disk again. Extract the root page number ** for the table from the db->init.newTnum field. (The page number ** should have been put there by the sqliteOpenCb routine.) @@ -1430,15 +1445,17 @@ ** A view has no rootpage, so just push a zero onto the stack for ** views. Initialize zType at the same time. */ if( p->pSelect==0 ){ /* A regular table */ + /* sqlite3VdbeAddOp(v, OP_CreateTable, p->iDb, 0); */ zType = "table"; zType2 = "TABLE"; #ifndef SQLITE_OMIT_VIEW }else{ /* A view */ + /* sqlite3VdbeAddOp(v, OP_Integer, 0, 0); */ zType = "view"; zType2 = "VIEW"; #endif } @@ -1447,20 +1464,15 @@ ** new table is on the top of the vdbe stack. ** ** Once the SELECT has been coded by sqlite3Select(), it is in a ** suitable state to query for the column names and types to be used ** by the new table. - ** - ** A shared-cache write-lock is not required to write to the new table, - ** as a schema-lock must have already been obtained to create it. Since - ** a schema-lock excludes all other database users, the write-lock would - ** be redundant. */ if( pSelect ){ Table *pSelTab; sqlite3VdbeAddOp(v, OP_Dup, 0, 0); - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); + sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0); pParse->nTab = 2; sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0); sqlite3VdbeAddOp(v, OP_Close, 1, 0); if( pParse->nErr==0 ){ @@ -1475,13 +1487,13 @@ } } /* Compute the complete text of the CREATE statement */ if( pSelect ){ - zStmt = createTableStmt(p, p->pSchema==pParse->db->aDb[1].pSchema); + zStmt = createTableStmt(p); }else{ - n = pEnd->z - pParse->sNameToken.z + 1; + n = Addr(pEnd->z) - Addr(pParse->sNameToken.z) + 1; zStmt = sqlite3MPrintf("CREATE %s %.*s", zType2, n, pParse->sNameToken.z); } /* A slot for the record has already been allocated in the ** SQLITE_MASTER table. We just need to update that slot with all @@ -1491,70 +1503,61 @@ */ sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q " "WHERE rowid=#1", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + db->aDb[p->iDb].zName, SCHEMA_TABLE(p->iDb), zType, p->zName, p->zName, zStmt ); sqliteFree(zStmt); - sqlite3ChangeCookie(db, v, iDb); + sqlite3ChangeCookie(db, v, p->iDb); #ifndef SQLITE_OMIT_AUTOINCREMENT /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ if( p->autoInc ){ - Db *pDb = &db->aDb[iDb]; - if( pDb->pSchema->pSeqTab==0 ){ + Db *pDb = &db->aDb[p->iDb]; + if( pDb->pSeqTab==0 ){ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_sequence(name,seq)", pDb->zName ); } } #endif /* Reparse everything to update our internal data structures */ - sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, + sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0, sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC); } /* Add the table to the in-memory representation of the database. */ if( db->init.busy && pParse->nErr==0 ){ Table *pOld; FKey *pFKey; - Schema *pSchema = p->pSchema; - pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, strlen(p->zName)+1,p); + Db *pDb = &db->aDb[p->iDb]; + pOld = sqlite3HashInsert(&pDb->tblHash, p->zName, strlen(p->zName)+1, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ return; } #ifndef SQLITE_OMIT_FOREIGN_KEY for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){ int nTo = strlen(pFKey->zTo) + 1; - pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo); - sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey); + pFKey->pNextTo = sqlite3HashFind(&pDb->aFKey, pFKey->zTo, nTo); + sqlite3HashInsert(&pDb->aFKey, pFKey->zTo, nTo, pFKey); } #endif pParse->pNewTable = 0; db->nTable++; db->flags |= SQLITE_InternChanges; - -#ifndef SQLITE_OMIT_ALTERTABLE - if( !p->pSelect ){ - const unsigned char *zName = pParse->sNameToken.z; - assert( !pSelect && pCons && pEnd ); - if( pCons->z==0 ) pCons = pEnd; - p->addColOffset = 13 + sqlite3utf8CharLen(zName, pCons->z - zName); - } -#endif } } #ifndef SQLITE_OMIT_VIEW /* @@ -1572,26 +1575,19 @@ int n; const unsigned char *z; Token sEnd; DbFixer sFix; Token *pName; - int iDb; - - if( pParse->nVar>0 ){ - sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); - sqlite3SelectDelete(pSelect); - return; - } - sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1, 0); + + sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1); p = pParse->pNewTable; if( p==0 || pParse->nErr ){ sqlite3SelectDelete(pSelect); return; } sqlite3TwoPartName(pParse, pName1, pName2, &pName); - iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); - if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName) + if( sqlite3FixInit(&sFix, pParse, p->iDb, "view", pName) && sqlite3FixSelect(&sFix, pSelect) ){ sqlite3SelectDelete(pSelect); return; } @@ -1601,13 +1597,10 @@ ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ p->pSelect = sqlite3SelectDup(pSelect); sqlite3SelectDelete(pSelect); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ - return; - } if( !pParse->db->init.busy ){ sqlite3ViewGetColumnNames(pParse, p); } /* Locate the end of the CREATE VIEW statement. Make sEnd point to @@ -1623,11 +1616,11 @@ while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; } sEnd.z = &z[n-1]; sEnd.n = 1; /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ - sqlite3EndTable(pParse, 0, &sEnd, 0); + sqlite3EndTable(pParse, &sEnd, 0); return; } #endif /* SQLITE_OMIT_VIEW */ #ifndef SQLITE_OMIT_VIEW @@ -1657,17 +1650,14 @@ ** CREATE VIEW two AS SELECT * FROM one; ** ** Actually, this error is caught previously and so the following test ** should always fail. But we will leave it in place just to be safe. */ -#if 0 if( pTable->nCol<0 ){ sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName); return 1; } -#endif - assert( pTable->nCol>=0 ); /* If we get this far, it means we need to compute the table names. ** Note that the call to sqlite3ResultSetOfSelect() will expand any ** "*" elements in the results set of the view and will assign cursors ** to the elements of the FROM clause. But we do not want these changes @@ -1674,32 +1664,28 @@ ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( pTable->pSelect ); pSel = sqlite3SelectDup(pTable->pSelect); - if( pSel ){ - n = pParse->nTab; - sqlite3SrcListAssignCursors(pParse, pSel->pSrc); - pTable->nCol = -1; - pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel); - pParse->nTab = n; - if( pSelTab ){ - assert( pTable->aCol==0 ); - pTable->nCol = pSelTab->nCol; - pTable->aCol = pSelTab->aCol; - pSelTab->nCol = 0; - pSelTab->aCol = 0; - sqlite3DeleteTable(0, pSelTab); - pTable->pSchema->flags |= DB_UnresetViews; - }else{ - pTable->nCol = 0; - nErr++; - } - sqlite3SelectDelete(pSel); - } else { - nErr++; - } + n = pParse->nTab; + sqlite3SrcListAssignCursors(pParse, pSel->pSrc); + pTable->nCol = -1; + pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel); + pParse->nTab = n; + if( pSelTab ){ + assert( pTable->aCol==0 ); + pTable->nCol = pSelTab->nCol; + pTable->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + sqlite3DeleteTable(0, pSelTab); + DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews); + }else{ + pTable->nCol = 0; + nErr++; + } + sqlite3SelectDelete(pSel); return nErr; } #endif /* SQLITE_OMIT_VIEW */ #ifndef SQLITE_OMIT_VIEW @@ -1707,11 +1693,11 @@ ** Clear the column names from every VIEW in database idx. */ static void sqliteViewResetAll(sqlite3 *db, int idx){ HashElem *i; if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; - for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( pTab->pSelect ){ sqliteResetColumnNames(pTab); } } @@ -1728,22 +1714,19 @@ ** to iTo. */ #ifndef SQLITE_OMIT_AUTOVACUUM void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){ HashElem *pElem; - Hash *pHash; - - pHash = &pDb->pSchema->tblHash; - for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ + + for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); if( pTab->tnum==iFrom ){ pTab->tnum = iTo; return; } } - pHash = &pDb->pSchema->idxHash; - for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ + for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){ Index *pIdx = sqliteHashData(pElem); if( pIdx->tnum==iFrom ){ pIdx->tnum = iTo; return; } @@ -1783,14 +1766,13 @@ ** is also added (this can happen with an auto-vacuum database). */ static void destroyTable(Parse *pParse, Table *pTab){ #ifdef SQLITE_OMIT_AUTOVACUUM Index *pIdx; - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - destroyRootPage(pParse, pTab->tnum, iDb); + destroyRootPage(pParse, pTab->tnum, pTab->iDb); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - destroyRootPage(pParse, pIdx->tnum, iDb); + destroyRootPage(pParse, pIdx->tnum, pIdx->iDb); } #else /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM ** is not defined), then it is important to call OP_Destroy on the ** table and index root-pages in order, starting with the numerically @@ -1817,66 +1799,55 @@ if( iDestroyed==0 || iTabpIndex; pIdx; pIdx=pIdx->pNext){ int iIdx = pIdx->tnum; - assert( pIdx->pSchema==pTab->pSchema ); + assert( pIdx->iDb==pTab->iDb ); if( (iDestroyed==0 || (iIdxiLargest ){ iLargest = iIdx; } } - if( iLargest==0 ){ - return; - }else{ - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - destroyRootPage(pParse, iLargest, iDb); - iDestroyed = iLargest; - } + if( iLargest==0 ) return; + destroyRootPage(pParse, iLargest, pTab->iDb); + iDestroyed = iLargest; } #endif } /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. */ -void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ +void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ Table *pTab; Vdbe *v; sqlite3 *db = pParse->db; int iDb; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ - goto exit_drop_table; - } + if( pParse->nErr || sqlite3_malloc_failed ) goto exit_drop_table; assert( pName->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase); - if( pTab==0 ){ - if( noErr ){ - sqlite3ErrorClear(pParse); - } - goto exit_drop_table; - } - iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + if( pTab==0 ) goto exit_drop_table; + iDb = pTab->iDb; assert( iDb>=0 && iDbnDb ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code; - const char *zTab = SCHEMA_TABLE(iDb); - const char *zDb = db->aDb[iDb].zName; + const char *zTab = SCHEMA_TABLE(pTab->iDb); + const char *zDb = db->aDb[pTab->iDb].zName; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ goto exit_drop_table; } if( isView ){ - if( !OMIT_TEMPDB && iDb==1 ){ + if( iDb==1 ){ code = SQLITE_DROP_TEMP_VIEW; }else{ code = SQLITE_DROP_VIEW; } }else{ - if( !OMIT_TEMPDB && iDb==1 ){ + if( iDb==1 ){ code = SQLITE_DROP_TEMP_TABLE; }else{ code = SQLITE_DROP_TABLE; } } @@ -1886,11 +1857,11 @@ if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto exit_drop_table; } } #endif - if( pTab->readOnly || pTab==db->aDb[iDb].pSchema->pSeqTab ){ + if( pTab->readOnly || pTab==db->aDb[iDb].pSeqTab ){ sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); goto exit_drop_table; } #ifndef SQLITE_OMIT_VIEW @@ -1911,21 +1882,21 @@ ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ Trigger *pTrigger; + int iDb = pTab->iDb; Db *pDb = &db->aDb[iDb]; sqlite3BeginWriteOperation(pParse, 0, iDb); /* Drop all triggers associated with the table being dropped. Code ** is generated to remove entries from sqlite_master and/or ** sqlite_temp_master if required. */ pTrigger = pTab->pTrigger; while( pTrigger ){ - assert( pTrigger->pSchema==pTab->pSchema || - pTrigger->pSchema==db->aDb[1].pSchema ); + assert( pTrigger->iDb==iDb || pTrigger->iDb==1 ); sqlite3DropTriggerPtr(pParse, pTrigger, 1); pTrigger = pTrigger->pNext; } #ifndef SQLITE_OMIT_AUTOINCREMENT @@ -2117,52 +2088,51 @@ int iTab = pParse->nTab; /* Btree cursor used for pTab */ int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */ int addr1; /* Address of top of loop */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ - KeyInfo *pKey; /* KeyInfo for index */ - int iDb = sqlite3SchemaToIndex(pParse->db, pIndex->pSchema); + int isUnique; /* True for a unique index */ #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, - pParse->db->aDb[iDb].zName ) ){ + pParse->db->aDb[pIndex->iDb].zName ) ){ + return; + } +#endif + + /* Ensure all the required collation sequences are available. This + ** routine will invoke the collation-needed callback if necessary (and + ** if one has been registered). + */ + if( sqlite3CheckIndexCollSeq(pParse, pIndex) ){ return; } -#endif - - /* Require a write-lock on the table to perform this operation */ - sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ sqlite3VdbeAddOp(v, OP_MemLoad, memRootPage, 0); tnum = 0; }else{ tnum = pIndex->tnum; - sqlite3VdbeAddOp(v, OP_Clear, tnum, iDb); + sqlite3VdbeAddOp(v, OP_Clear, tnum, pIndex->iDb); } - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - pKey = sqlite3IndexKeyinfo(pParse, pIndex); - sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char *)pKey, P3_KEYINFO_HANDOFF); - sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp(v, OP_Integer, pIndex->iDb, 0); + sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, + (char*)&pIndex->keyInfo, P3_KEYINFO); + sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqlite3VdbeAddOp(v, OP_OpenRead, iTab, pTab->tnum); + sqlite3VdbeAddOp(v, OP_SetNumColumns, iTab, pTab->nCol); addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); sqlite3GenerateIndexKey(v, pIndex, iTab); - if( pIndex->onError!=OE_None ){ - int curaddr = sqlite3VdbeCurrentAddr(v); - int addr2 = curaddr+4; - sqlite3VdbeChangeP2(v, curaddr-1, addr2); - sqlite3VdbeAddOp(v, OP_Rowid, iTab, 0); - sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); - sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2); - sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, - "indexed columns are not unique", P3_STATIC); - assert( addr2==sqlite3VdbeCurrentAddr(v) ); - } - sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0); + isUnique = pIndex->onError!=OE_None; + sqlite3VdbeAddOp(v, OP_IdxPut, iIdx, isUnique); + if( isUnique ){ + sqlite3VdbeChangeP3(v, -1, "indexed columns are not unique", P3_STATIC); + } sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1); - sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeChangeP2(v, addr1, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp(v, OP_Close, iTab, 0); sqlite3VdbeAddOp(v, OP_Close, iIdx, 0); } /* @@ -2183,34 +2153,25 @@ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */ - Token *pEnd, /* The ")" that closes the CREATE INDEX statement */ - int sortOrder, /* Sort order of primary key when pList==NULL */ - int ifNotExist /* Omit error if index already exists */ + Token *pEnd /* The ")" that closes the CREATE INDEX statement */ ){ - Table *pTab = 0; /* Table to be indexed */ - Index *pIndex = 0; /* The index to be created */ - char *zName = 0; /* Name of the index */ - int nName; /* Number of characters in zName */ + Table *pTab = 0; /* Table to be indexed */ + Index *pIndex = 0; /* The index to be created */ + char *zName = 0; int i, j; - Token nullId; /* Fake token for an empty ID list */ - DbFixer sFix; /* For assigning database names to pTable */ - int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ + Token nullId; /* Fake token for an empty ID list */ + DbFixer sFix; /* For assigning database names to pTable */ + int isTemp; /* True for a temporary index */ sqlite3 *db = pParse->db; - Db *pDb; /* The specific table containing the indexed database */ - int iDb; /* Index of the database that is being written */ - Token *pName = 0; /* Unqualified name of the index to create */ - struct ExprList_item *pListItem; /* For looping over pList */ - int nCol; - int nExtra = 0; - char *zExtra; - - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ - goto exit_create_index; - } + + int iDb; /* Index of the database that is being written */ + Token *pName = 0; /* Unqualified name of the index to create */ + + if( pParse->nErr || sqlite3_malloc_failed ) goto exit_create_index; /* ** Find the table that is to be indexed. Return early if not found. */ if( pTblName!=0 ){ @@ -2221,38 +2182,32 @@ */ assert( pName1 && pName2 ); iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); if( iDb<0 ) goto exit_create_index; -#ifndef SQLITE_OMIT_TEMPDB /* If the index name was unqualified, check if the the table ** is a temp table. If so, set the database to 1. */ pTab = sqlite3SrcListLookup(pParse, pTblName); - if( pName2 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ + if( pName2 && pName2->n==0 && pTab && pTab->iDb==1 ){ iDb = 1; } -#endif if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) && sqlite3FixSrcList(&sFix, pTblName) ){ - /* Because the parser constructs pTblName from a single identifier, - ** sqlite3FixSrcList can never fail. */ - assert(0); + goto exit_create_index; } pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName, pTblName->a[0].zDatabase); if( !pTab ) goto exit_create_index; - assert( db->aDb[iDb].pSchema==pTab->pSchema ); + assert( iDb==pTab->iDb ); }else{ assert( pName==0 ); - pTab = pParse->pNewTable; - if( !pTab ) goto exit_create_index; - iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + pTab = pParse->pNewTable; + iDb = pTab->iDb; } - pDb = &db->aDb[iDb]; if( pTab==0 || pParse->nErr ) goto exit_create_index; if( pTab->readOnly ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -2261,10 +2216,11 @@ if( pTab->pSelect ){ sqlite3ErrorMsg(pParse, "views may not be indexed"); goto exit_create_index; } #endif + isTemp = pTab->iDb==1; /* ** Find the name of the index. Make sure there is not already another ** index or table with the same name. ** @@ -2283,18 +2239,18 @@ if( zName==0 ) goto exit_create_index; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } if( !db->init.busy ){ + Index *pISameName; /* Another index with the same name */ + Table *pTSameName; /* A table with same name as the index */ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; - if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ - if( !ifNotExist ){ - sqlite3ErrorMsg(pParse, "index %s already exists", zName); - } + if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){ + sqlite3ErrorMsg(pParse, "index %s already exists", zName); goto exit_create_index; } - if( sqlite3FindTable(db, zName, 0)!=0 ){ + if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; } } }else{ @@ -2310,16 +2266,16 @@ /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION { - const char *zDb = pDb->zName; - if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ + const char *zDb = db->aDb[pTab->iDb].zName; + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ goto exit_create_index; } i = SQLITE_CREATE_INDEX; - if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; + if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX; if( sqlite3AuthCheck(pParse, i, zName, pTab->zName, zDb) ){ goto exit_create_index; } } #endif @@ -2327,101 +2283,59 @@ /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ - nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName; - nullId.n = strlen((char*)nullId.z); + nullId.z = pTab->aCol[pTab->nCol-1].zName; + nullId.n = strlen(nullId.z); pList = sqlite3ExprListAppend(0, 0, &nullId); if( pList==0 ) goto exit_create_index; - pList->a[0].sortOrder = sortOrder; - } - - /* Figure out how many bytes of space are required to store explicitly - ** specified collation sequence names. - */ - for(i=0; inExpr; i++){ - Expr *pExpr = pList->a[i].pExpr; - if( pExpr ){ - nExtra += (1 + strlen(pExpr->pColl->zName)); - } } /* ** Allocate the index structure. */ - nName = strlen(zName); - nCol = pList->nExpr; - pIndex = sqliteMalloc( - sizeof(Index) + /* Index structure */ - sizeof(int)*nCol + /* Index.aiColumn */ - sizeof(int)*(nCol+1) + /* Index.aiRowEst */ - sizeof(char *)*nCol + /* Index.azColl */ - sizeof(u8)*nCol + /* Index.aSortOrder */ - nName + 1 + /* Index.zName */ - nExtra /* Collation sequence names */ - ); - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_create_index; - pIndex->aiColumn = (int *)(&pIndex[1]); - pIndex->aiRowEst = (int *)(&pIndex->aiColumn[nCol]); - pIndex->azColl = (char **)(&pIndex->aiRowEst[nCol+1]); - pIndex->aSortOrder = (u8 *)(&pIndex->azColl[nCol]); - pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]); - zExtra = (char *)(&pIndex->zName[nName+1]); + pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + + (sizeof(int) + sizeof(CollSeq*))*pList->nExpr ); + if( pIndex==0 ) goto exit_create_index; + pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr]; + pIndex->zName = (char*)&pIndex->aiColumn[pList->nExpr]; strcpy(pIndex->zName, zName); pIndex->pTable = pTab; pIndex->nColumn = pList->nExpr; pIndex->onError = onError; pIndex->autoIndex = pName==0; - pIndex->pSchema = db->aDb[iDb].pSchema; - - /* Check to see if we should honor DESC requests on index columns - */ - if( pDb->pSchema->file_format>=4 ){ - sortOrderMask = -1; /* Honor DESC */ - }else{ - sortOrderMask = 0; /* Ignore DESC */ - } + pIndex->iDb = iDb; /* Scan the names of the columns of the table to be indexed and ** load the column indices into the Index structure. Report an error ** if any column is not found. */ - for(i=0, pListItem=pList->a; inExpr; i++, pListItem++){ - const char *zColName = pListItem->zName; - Column *pTabCol; - int requestedSortOrder; - char *zColl; /* Collation sequence */ - - for(j=0, pTabCol=pTab->aCol; jnCol; j++, pTabCol++){ - if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; + for(i=0; inExpr; i++){ + for(j=0; jnCol; j++){ + if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break; } if( j>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "table %s has no column named %s", - pTab->zName, zColName); + pTab->zName, pList->a[i].zName); goto exit_create_index; } pIndex->aiColumn[i] = j; - if( pListItem->pExpr ){ - assert( pListItem->pExpr->pColl ); - zColl = zExtra; - strcpy(zExtra, pListItem->pExpr->pColl->zName); - zExtra += (strlen(zColl) + 1); + if( pList->a[i].pExpr ){ + assert( pList->a[i].pExpr->pColl ); + pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl; }else{ - zColl = pTab->aCol[j].zColl; - if( !zColl ){ - zColl = db->pDfltColl->zName; - } + pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl; } - if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl, -1) ){ + assert( pIndex->keyInfo.aColl[i] ); + if( !db->init.busy && + sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i]) + ){ goto exit_create_index; } - pIndex->azColl[i] = zColl; - requestedSortOrder = pListItem->sortOrder & sortOrderMask; - pIndex->aSortOrder[i] = requestedSortOrder; } - sqlite3DefaultRowEst(pIndex); + pIndex->keyInfo.nField = pList->nExpr; if( pTab==pParse->pNewTable ){ /* This routine has been called to create an automatic index as a ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or ** a PRIMARY KEY or UNIQUE clause following the column definitions. @@ -2442,15 +2356,12 @@ assert( pIdx->autoIndex ); assert( pIndex->onError!=OE_None ); if( pIdx->nColumn!=pIndex->nColumn ) continue; for(k=0; knColumn; k++){ - const char *z1 = pIdx->azColl[k]; - const char *z2 = pIndex->azColl[k]; if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; - if( pIdx->aSortOrder[k]!=pIndex->aSortOrder[k] ) break; - if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break; + if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break; } if( k==pIdx->nColumn ){ if( pIdx->onError!=pIndex->onError ){ /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. @@ -2475,11 +2386,11 @@ /* Link the new Index structure to its table and to the other ** in-memory database structures. */ if( db->init.busy ){ Index *p; - p = sqlite3HashInsert(&pIndex->pSchema->idxHash, + p = sqlite3HashInsert(&db->aDb[pIndex->iDb].idxHash, pIndex->zName, strlen(pIndex->zName)+1, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ goto exit_create_index; } @@ -2510,11 +2421,10 @@ int iMem = pParse->nMem++; v = sqlite3GetVdbe(pParse); if( v==0 ) goto exit_create_index; - /* Create the rootpage for the index */ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3VdbeAddOp(v, OP_CreateIndex, iDb, 0); sqlite3VdbeAddOp(v, OP_MemStore, iMem, 0); @@ -2524,11 +2434,11 @@ */ if( pStart && pEnd ){ /* A named index with an explicit CREATE INDEX statement */ zStmt = sqlite3MPrintf("CREATE%s INDEX %.*s", onError==OE_None ? "" : " UNIQUE", - pEnd->z - pName->z + 1, + Addr(pEnd->z) - Addr(pName->z) + 1, pName->z); }else{ /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ /* zStmt = sqlite3MPrintf(""); */ zStmt = 0; @@ -2588,107 +2498,53 @@ sqlite3SrcListDelete(pTblName); sqliteFree(zName); return; } -/* -** Generate code to make sure the file format number is at least minFormat. -** The generated code will increase the file format number if necessary. -*/ -void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ - Vdbe *v; - v = sqlite3GetVdbe(pParse); - if( v ){ - sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); - sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); - sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); - sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); - } -} - -/* -** Fill the Index.aiRowEst[] array with default information - information -** to be used when we have not run the ANALYZE command. -** -** aiRowEst[0] is suppose to contain the number of elements in the index. -** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the -** number of rows in the table that match any particular value of the -** first column of the index. aiRowEst[2] is an estimate of the number -** of rows that match any particular combiniation of the first 2 columns -** of the index. And so forth. It must always be the case that -* -** aiRowEst[N]<=aiRowEst[N-1] -** aiRowEst[N]>=1 -** -** Apart from that, we have little to go on besides intuition as to -** how aiRowEst[] should be initialized. The numbers generated here -** are based on typical values found in actual indices. -*/ -void sqlite3DefaultRowEst(Index *pIdx){ - unsigned *a = pIdx->aiRowEst; - int i; - assert( a!=0 ); - a[0] = 1000000; - for(i=pIdx->nColumn; i>=1; i--){ - a[i] = 10; - } - if( pIdx->onError!=OE_None ){ - a[pIdx->nColumn] = 1; - } -} - /* ** This routine will drop an existing named index. This routine ** implements the DROP INDEX statement. */ -void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ +void sqlite3DropIndex(Parse *pParse, SrcList *pName){ Index *pIndex; Vdbe *v; sqlite3 *db = pParse->db; - int iDb; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ - goto exit_drop_index; - } + if( pParse->nErr || sqlite3_malloc_failed ) return; assert( pName->nSrc==1 ); - if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ - goto exit_drop_index; - } + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) return; pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ - if( !ifExists ){ - sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); - } + sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); pParse->checkSchema = 1; goto exit_drop_index; } if( pIndex->autoIndex ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; } - iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; - const char *zDb = db->aDb[iDb].zName; - const char *zTab = SCHEMA_TABLE(iDb); + const char *zDb = db->aDb[pIndex->iDb].zName; + const char *zTab = SCHEMA_TABLE(pIndex->iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; } - if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX; + if( pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX; if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ goto exit_drop_index; } } #endif /* Generate code to remove the index and from the master table */ v = sqlite3GetVdbe(pParse); if( v ){ + int iDb = pIndex->iDb; sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q", db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName ); @@ -2699,97 +2555,36 @@ exit_drop_index: sqlite3SrcListDelete(pName); } -/* -** ppArray points into a structure where there is an array pointer -** followed by two integers. The first integer is the -** number of elements in the structure array. The second integer -** is the number of allocated slots in the array. -** -** In other words, the structure looks something like this: -** -** struct Example1 { -** struct subElem *aEntry; -** int nEntry; -** int nAlloc; -** } -** -** The pnEntry parameter points to the equivalent of Example1.nEntry. -** -** This routine allocates a new slot in the array, zeros it out, -** and returns its index. If malloc fails a negative number is returned. -** -** szEntry is the sizeof of a single array entry. initSize is the -** number of array entries allocated on the initial allocation. -*/ -int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){ - char *p; - int *an = (int*)&ppArray[1]; - if( an[0]>=an[1] ){ - void *pNew; - int newSize; - newSize = an[1]*2 + initSize; - pNew = sqliteRealloc(*ppArray, newSize*szEntry); - if( pNew==0 ){ - return -1; - } - an[1] = newSize; - *ppArray = pNew; - } - p = *ppArray; - memset(&p[an[0]*szEntry], 0, szEntry); - return an[0]++; -} - /* ** Append a new element to the given IdList. Create a new IdList if ** need be. ** ** A new IdList is returned, or NULL if malloc() fails. */ IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){ - int i; if( pList==0 ){ pList = sqliteMalloc( sizeof(IdList) ); if( pList==0 ) return 0; pList->nAlloc = 0; } - i = sqlite3ArrayAllocate((void**)&pList->a, sizeof(pList->a[0]), 5); - if( i<0 ){ - sqlite3IdListDelete(pList); - return 0; - } - pList->a[i].zName = sqlite3NameFromToken(pToken); - return pList; -} - -/* -** Delete an IdList. -*/ -void sqlite3IdListDelete(IdList *pList){ - int i; - if( pList==0 ) return; - for(i=0; inId; i++){ - sqliteFree(pList->a[i].zName); - } - sqliteFree(pList->a); - sqliteFree(pList); -} - -/* -** Return the index in pList of the identifier named zId. Return -1 -** if not found. -*/ -int sqlite3IdListIndex(IdList *pList, const char *zName){ - int i; - if( pList==0 ) return -1; - for(i=0; inId; i++){ - if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; - } - return -1; + if( pList->nId>=pList->nAlloc ){ + struct IdList_item *a; + pList->nAlloc = pList->nAlloc*2 + 5; + a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]) ); + if( a==0 ){ + sqlite3IdListDelete(pList); + return 0; + } + pList->a = a; + } + memset(&pList->a[pList->nId], 0, sizeof(pList->a[0])); + pList->a[pList->nId].zName = sqlite3NameFromToken(pToken); + pList->nId++; + return pList; } /* ** Append a new table name to the given SrcList. Create a new SrcList if ** need be. A new entry is created in the SrcList even if pToken is NULL. @@ -2854,18 +2649,15 @@ ** Assign cursors to all tables in a SrcList */ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; struct SrcList_item *pItem; - assert(pList || sqlite3ThreadDataReadOnly()->mallocFailed); - if( pList ){ - for(i=0, pItem=pList->a; inSrc; i++, pItem++){ - if( pItem->iCursor>=0 ) break; - pItem->iCursor = pParse->nTab++; - if( pItem->pSelect ){ - sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); - } + for(i=0, pItem=pList->a; inSrc; i++, pItem++){ + if( pItem->iCursor>=0 ) break; + pItem->iCursor = pParse->nTab++; + if( pItem->pSelect ){ + sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); } } } /* @@ -2874,10 +2666,36 @@ void sqlite3SrcListAddAlias(SrcList *pList, Token *pToken){ if( pList && pList->nSrc>0 ){ pList->a[pList->nSrc-1].zAlias = sqlite3NameFromToken(pToken); } } + +/* +** Delete an IdList. +*/ +void sqlite3IdListDelete(IdList *pList){ + int i; + if( pList==0 ) return; + for(i=0; inId; i++){ + sqliteFree(pList->a[i].zName); + } + sqliteFree(pList->a); + sqliteFree(pList); +} + +/* +** Return the index in pList of the identifier named zId. Return -1 +** if not found. +*/ +int sqlite3IdListIndex(IdList *pList, const char *zName){ + int i; + if( pList==0 ) return -1; + for(i=0; inId; i++){ + if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; + } + return -1; +} /* ** Delete an entire SrcList including all its substructure. */ void sqlite3SrcListDelete(SrcList *pList){ @@ -2886,11 +2704,13 @@ if( pList==0 ) return; for(pItem=pList->a, i=0; inSrc; i++, pItem++){ sqliteFree(pItem->zDatabase); sqliteFree(pItem->zName); sqliteFree(pItem->zAlias); - sqlite3DeleteTable(0, pItem->pTab); + if( pItem->pTab && pItem->pTab->isTransient ){ + sqlite3DeleteTable(0, pItem->pTab); + } sqlite3SelectDelete(pItem->pSelect); sqlite3ExprDelete(pItem->pOn); sqlite3IdListDelete(pItem->pUsing); } sqliteFree(pList); @@ -2903,11 +2723,11 @@ sqlite3 *db; Vdbe *v; int i; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( pParse->nErr || sqlite3_malloc_failed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( !v ) return; if( type!=TK_DEFERRED ){ @@ -2924,11 +2744,11 @@ void sqlite3CommitTransaction(Parse *pParse){ sqlite3 *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( pParse->nErr || sqlite3_malloc_failed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 0); @@ -2941,11 +2761,11 @@ void sqlite3RollbackTransaction(Parse *pParse){ sqlite3 *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( pParse->nErr || sqlite3_malloc_failed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 1); @@ -2973,11 +2793,10 @@ "the temporary database file"); pParse->rc = rc; return 1; } } - assert( db->aDb[1].pSchema ); } return 0; } /* @@ -3018,12 +2837,12 @@ assert( db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDb<32 ); mask = 1<cookieMask & mask)==0 ){ pParse->cookieMask |= mask; - pParse->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; - if( !OMIT_TEMPDB && iDb==1 ){ + pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie; + if( iDb==1 ){ sqlite3OpenTempDatabase(pParse); } } } } @@ -3052,27 +2871,39 @@ sqlite3CodeVerifySchema(pParse, iDb); pParse->writeMask |= 1<nested==0 ){ sqlite3VdbeAddOp(v, OP_Statement, iDb, 0); } - if( (OMIT_TEMPDB || iDb!=1) && pParse->db->aDb[1].pBt!=0 ){ + if( iDb!=1 && pParse->db->aDb[1].pBt!=0 ){ sqlite3BeginWriteOperation(pParse, setStatement, 1); } } + +#ifndef SQLITE_OMIT_UTF16 +/* +** Return the transient sqlite3_value object used for encoding conversions +** during SQL compilation. +*/ +sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){ + if( !db->pValue ){ + db->pValue = sqlite3ValueNew(); + } + return db->pValue; +} +#endif /* ** Check to see if pIndex uses the collating sequence pColl. Return ** true if it does and false if it does not. */ #ifndef SQLITE_OMIT_REINDEX -static int collationMatch(const char *zColl, Index *pIndex){ - int i; - for(i=0; inColumn; i++){ - const char *z = pIndex->azColl[i]; - if( z==zColl || (z && zColl && 0==sqlite3StrICmp(z, zColl)) ){ - return 1; - } +static int collationMatch(CollSeq *pColl, Index *pIndex){ + int n = pIndex->keyInfo.nField; + CollSeq **pp = pIndex->keyInfo.aColl; + while( n-- ){ + if( *pp==pColl ) return 1; + pp++; } return 0; } #endif @@ -3079,17 +2910,16 @@ /* ** Recompute all indices of pTab that use the collating sequence pColl. ** If pColl==0 then recompute all indices of pTab. */ #ifndef SQLITE_OMIT_REINDEX -static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ +void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){ Index *pIndex; /* An index associated with pTab */ for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ - if( zColl==0 || collationMatch(zColl, pIndex) ){ - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - sqlite3BeginWriteOperation(pParse, 0, iDb); + if( pColl==0 || collationMatch(pColl,pIndex) ){ + sqlite3BeginWriteOperation(pParse, 0, pTab->iDb); sqlite3RefillIndex(pParse, pIndex, -1); } } } #endif @@ -3098,22 +2928,22 @@ ** Recompute all indices of all tables in all databases where the ** indices use the collating sequence pColl. If pColl==0 then recompute ** all indices everywhere. */ #ifndef SQLITE_OMIT_REINDEX -static void reindexDatabases(Parse *pParse, char const *zColl){ +void reindexDatabases(Parse *pParse, CollSeq *pColl){ Db *pDb; /* A single database */ int iDb; /* The database index number */ sqlite3 *db = pParse->db; /* The database connection */ HashElem *k; /* For looping over tables in pDb */ Table *pTab; /* A table in the database */ for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ if( pDb==0 ) continue; - for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ + for(k=sqliteHashFirst(&pDb->tblHash); k; k=sqliteHashNext(k)){ pTab = (Table*)sqliteHashData(k); - reindexTable(pParse, pTab, zColl); + reindexTable(pParse, pTab, pColl); } } } #endif @@ -3149,18 +2979,13 @@ if( pName1==0 || pName1->z==0 ){ reindexDatabases(pParse, 0); return; }else if( pName2==0 || pName2->z==0 ){ - assert( pName1->z ); - pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0); + pColl = sqlite3FindCollSeq(db, db->enc, pName1->z, pName1->n, 0); if( pColl ){ - char *z = sqliteStrNDup(pName1->z, pName1->n); - if( z ){ - reindexDatabases(pParse, z); - sqliteFree(z); - } + reindexDatabases(pParse, pColl); return; } } iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); if( iDb<0 ) return; @@ -3180,40 +3005,5 @@ return; } sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } #endif - -/* -** Return a dynamicly allocated KeyInfo structure that can be used -** with OP_OpenRead or OP_OpenWrite to access database index pIdx. -** -** If successful, a pointer to the new structure is returned. In this case -** the caller is responsible for calling sqliteFree() on the returned -** pointer. If an error occurs (out of memory or missing collation -** sequence), NULL is returned and the state of pParse updated to reflect -** the error. -*/ -KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){ - int i; - int nCol = pIdx->nColumn; - int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol; - KeyInfo *pKey = (KeyInfo *)sqliteMalloc(nBytes); - - if( pKey ){ - pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]); - assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) ); - for(i=0; iazColl[i]; - assert( zColl ); - pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl, -1); - pKey->aSortOrder[i] = pIdx->aSortOrder[i]; - } - pKey->nField = nCol; - } - - if( pParse->nErr ){ - sqliteFree(pKey); - pKey = 0; - } - return pKey; -} DELETED SQLite.Interop/src/callback.c Index: SQLite.Interop/src/callback.c ================================================================== --- SQLite.Interop/src/callback.c +++ /dev/null @@ -1,314 +0,0 @@ -/* -** 2005 May 23 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file contains functions used to access the internal hash tables -** of user defined functions and collation sequences. -** -** $Id: callback.c,v 1.11 2006/01/16 15:51:47 rmsimpson Exp $ -*/ - -#include "sqliteInt.h" - -/* -** Invoke the 'collation needed' callback to request a collation sequence -** in the database text encoding of name zName, length nName. -** If the collation sequence -*/ -static void callCollNeeded(sqlite3 *db, const char *zName, int nName){ - assert( !db->xCollNeeded || !db->xCollNeeded16 ); - if( nName<0 ) nName = strlen(zName); - if( db->xCollNeeded ){ - char *zExternal = sqliteStrNDup(zName, nName); - if( !zExternal ) return; - db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal); - sqliteFree(zExternal); - } -#ifndef SQLITE_OMIT_UTF16 - if( db->xCollNeeded16 ){ - char const *zExternal; - sqlite3_value *pTmp = sqlite3ValueNew(); - sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC); - zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE); - if( zExternal ){ - db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal); - } - sqlite3ValueFree(pTmp); - } -#endif -} - -/* -** This routine is called if the collation factory fails to deliver a -** collation function in the best encoding but there may be other versions -** of this collation function (for other text encodings) available. Use one -** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if -** possible. -*/ -static int synthCollSeq(sqlite3 *db, CollSeq *pColl){ - CollSeq *pColl2; - char *z = pColl->zName; - int n = strlen(z); - int i; - static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 }; - for(i=0; i<3; i++){ - pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, n, 0); - if( pColl2->xCmp!=0 ){ - memcpy(pColl, pColl2, sizeof(CollSeq)); - return SQLITE_OK; - } - } - return SQLITE_ERROR; -} - -/* -** This function is responsible for invoking the collation factory callback -** or substituting a collation sequence of a different encoding when the -** requested collation sequence is not available in the database native -** encoding. -** -** If it is not NULL, then pColl must point to the database native encoding -** collation sequence with name zName, length nName. -** -** The return value is either the collation sequence to be used in database -** db for collation type name zName, length nName, or NULL, if no collation -** sequence can be found. -*/ -CollSeq *sqlite3GetCollSeq( - sqlite3* db, - CollSeq *pColl, - const char *zName, - int nName -){ - CollSeq *p; - - p = pColl; - if( !p ){ - p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0); - } - if( !p || !p->xCmp ){ - /* No collation sequence of this type for this encoding is registered. - ** Call the collation factory to see if it can supply us with one. - */ - callCollNeeded(db, zName, nName); - p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0); - } - if( p && !p->xCmp && synthCollSeq(db, p) ){ - p = 0; - } - assert( !p || p->xCmp ); - return p; -} - -/* -** This routine is called on a collation sequence before it is used to -** check that it is defined. An undefined collation sequence exists when -** a database is loaded that contains references to collation sequences -** that have not been defined by sqlite3_create_collation() etc. -** -** If required, this routine calls the 'collation needed' callback to -** request a definition of the collating sequence. If this doesn't work, -** an equivalent collating sequence that uses a text encoding different -** from the main database is substituted, if one is available. -*/ -int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ - if( pColl ){ - const char *zName = pColl->zName; - CollSeq *p = sqlite3GetCollSeq(pParse->db, pColl, zName, -1); - if( !p ){ - if( pParse->nErr==0 ){ - sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); - } - pParse->nErr++; - return SQLITE_ERROR; - } - assert( p==pColl ); - } - return SQLITE_OK; -} - - - -/* -** Locate and return an entry from the db.aCollSeq hash table. If the entry -** specified by zName and nName is not found and parameter 'create' is -** true, then create a new entry. Otherwise return NULL. -** -** Each pointer stored in the sqlite3.aCollSeq hash table contains an -** array of three CollSeq structures. The first is the collation sequence -** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be. -** -** Stored immediately after the three collation sequences is a copy of -** the collation sequence name. A pointer to this string is stored in -** each collation sequence structure. -*/ -static CollSeq *findCollSeqEntry( - sqlite3 *db, - const char *zName, - int nName, - int create -){ - CollSeq *pColl; - if( nName<0 ) nName = strlen(zName); - pColl = sqlite3HashFind(&db->aCollSeq, zName, nName); - - if( 0==pColl && create ){ - pColl = sqliteMalloc( 3*sizeof(*pColl) + nName + 1 ); - if( pColl ){ - CollSeq *pDel = 0; - pColl[0].zName = (char*)&pColl[3]; - pColl[0].enc = SQLITE_UTF8; - pColl[1].zName = (char*)&pColl[3]; - pColl[1].enc = SQLITE_UTF16LE; - pColl[2].zName = (char*)&pColl[3]; - pColl[2].enc = SQLITE_UTF16BE; - memcpy(pColl[0].zName, zName, nName); - pColl[0].zName[nName] = 0; - pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl); - - /* If a malloc() failure occured in sqlite3HashInsert(), it will - ** return the pColl pointer to be deleted (because it wasn't added - ** to the hash table). - */ - assert( !pDel || - (sqlite3ThreadDataReadOnly()->mallocFailed && pDel==pColl) ); - sqliteFree(pDel); - } - } - return pColl; -} - -/* -** Parameter zName points to a UTF-8 encoded string nName bytes long. -** Return the CollSeq* pointer for the collation sequence named zName -** for the encoding 'enc' from the database 'db'. -** -** If the entry specified is not found and 'create' is true, then create a -** new entry. Otherwise return NULL. -*/ -CollSeq *sqlite3FindCollSeq( - sqlite3 *db, - u8 enc, - const char *zName, - int nName, - int create -){ - CollSeq *pColl; - if( zName ){ - pColl = findCollSeqEntry(db, zName, nName, create); - }else{ - pColl = db->pDfltColl; - } - assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); - assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); - if( pColl ) pColl += enc-1; - return pColl; -} - -/* -** Locate a user function given a name, a number of arguments and a flag -** indicating whether the function prefers UTF-16 over UTF-8. Return a -** pointer to the FuncDef structure that defines that function, or return -** NULL if the function does not exist. -** -** If the createFlag argument is true, then a new (blank) FuncDef -** structure is created and liked into the "db" structure if a -** no matching function previously existed. When createFlag is true -** and the nArg parameter is -1, then only a function that accepts -** any number of arguments will be returned. -** -** If createFlag is false and nArg is -1, then the first valid -** function found is returned. A function is valid if either xFunc -** or xStep is non-zero. -** -** If createFlag is false, then a function with the required name and -** number of arguments may be returned even if the eTextRep flag does not -** match that requested. -*/ -FuncDef *sqlite3FindFunction( - sqlite3 *db, /* An open database */ - const char *zName, /* Name of the function. Not null-terminated */ - int nName, /* Number of characters in the name */ - int nArg, /* Number of arguments. -1 means any number */ - u8 enc, /* Preferred text encoding */ - int createFlag /* Create new entry if true and does not otherwise exist */ -){ - FuncDef *p; /* Iterator variable */ - FuncDef *pFirst; /* First function with this name */ - FuncDef *pBest = 0; /* Best match found so far */ - int bestmatch = 0; - - - assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); - if( nArg<-1 ) nArg = -1; - - pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName); - for(p=pFirst; p; p=p->pNext){ - /* During the search for the best function definition, bestmatch is set - ** as follows to indicate the quality of the match with the definition - ** pointed to by pBest: - ** - ** 0: pBest is NULL. No match has been found. - ** 1: A variable arguments function that prefers UTF-8 when a UTF-16 - ** encoding is requested, or vice versa. - ** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is - ** requested, or vice versa. - ** 3: A variable arguments function using the same text encoding. - ** 4: A function with the exact number of arguments requested that - ** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa. - ** 5: A function with the exact number of arguments requested that - ** prefers UTF-16LE when UTF-16BE is requested, or vice versa. - ** 6: An exact match. - ** - ** A larger value of 'matchqual' indicates a more desirable match. - */ - if( p->nArg==-1 || p->nArg==nArg || nArg==-1 ){ - int match = 1; /* Quality of this match */ - if( p->nArg==nArg || nArg==-1 ){ - match = 4; - } - if( enc==p->iPrefEnc ){ - match += 2; - } - else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) || - (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){ - match += 1; - } - - if( match>bestmatch ){ - pBest = p; - bestmatch = match; - } - } - } - - /* If the createFlag parameter is true, and the seach did not reveal an - ** exact match for the name, number of arguments and encoding, then add a - ** new entry to the hash table and return it. - */ - if( createFlag && bestmatch<6 && - (pBest = sqliteMalloc(sizeof(*pBest)+nName))!=0 ){ - pBest->nArg = nArg; - pBest->pNext = pFirst; - pBest->iPrefEnc = enc; - memcpy(pBest->zName, zName, nName); - pBest->zName[nName] = 0; - if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){ - sqliteFree(pBest); - return 0; - } - } - - if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){ - return pBest; - } - return 0; -} DELETED SQLite.Interop/src/complete.c Index: SQLite.Interop/src/complete.c ================================================================== --- SQLite.Interop/src/complete.c +++ /dev/null @@ -1,266 +0,0 @@ -/* -** 2001 September 15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** An tokenizer for SQL -** -** This file contains C code that implements the sqlite3_complete() API. -** This code used to be part of the tokenizer.c source file. But by -** separating it out, the code will be automatically omitted from -** static links that do not use it. -** -** $Id: complete.c,v 1.9 2006/01/16 15:51:47 rmsimpson Exp $ -*/ -#include "sqliteInt.h" -#ifndef SQLITE_OMIT_COMPLETE - -/* -** This is defined in tokenize.c. We just have to import the definition. -*/ -extern const char sqlite3IsIdChar[]; -#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20])) - - -/* -** Token types used by the sqlite3_complete() routine. See the header -** comments on that procedure for additional information. -*/ -#define tkSEMI 0 -#define tkWS 1 -#define tkOTHER 2 -#define tkEXPLAIN 3 -#define tkCREATE 4 -#define tkTEMP 5 -#define tkTRIGGER 6 -#define tkEND 7 - -/* -** Return TRUE if the given SQL string ends in a semicolon. -** -** Special handling is require for CREATE TRIGGER statements. -** Whenever the CREATE TRIGGER keywords are seen, the statement -** must end with ";END;". -** -** This implementation uses a state machine with 7 states: -** -** (0) START At the beginning or end of an SQL statement. This routine -** returns 1 if it ends in the START state and 0 if it ends -** in any other state. -** -** (1) NORMAL We are in the middle of statement which ends with a single -** semicolon. -** -** (2) EXPLAIN The keyword EXPLAIN has been seen at the beginning of -** a statement. -** -** (3) CREATE The keyword CREATE has been seen at the beginning of a -** statement, possibly preceeded by EXPLAIN and/or followed by -** TEMP or TEMPORARY -** -** (4) TRIGGER We are in the middle of a trigger definition that must be -** ended by a semicolon, the keyword END, and another semicolon. -** -** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at -** the end of a trigger definition. -** -** (6) END We've seen the ";END" of the ";END;" that occurs at the end -** of a trigger difinition. -** -** Transitions between states above are determined by tokens extracted -** from the input. The following tokens are significant: -** -** (0) tkSEMI A semicolon. -** (1) tkWS Whitespace -** (2) tkOTHER Any other SQL token. -** (3) tkEXPLAIN The "explain" keyword. -** (4) tkCREATE The "create" keyword. -** (5) tkTEMP The "temp" or "temporary" keyword. -** (6) tkTRIGGER The "trigger" keyword. -** (7) tkEND The "end" keyword. -** -** Whitespace never causes a state transition and is always ignored. -** -** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed -** to recognize the end of a trigger can be omitted. All we have to do -** is look for a semicolon that is not part of an string or comment. -*/ -int sqlite3_complete(const char *zSql){ - u8 state = 0; /* Current state, using numbers defined in header comment */ - u8 token; /* Value of the next token */ - -#ifndef SQLITE_OMIT_TRIGGER - /* A complex statement machine used to detect the end of a CREATE TRIGGER - ** statement. This is the normal case. - */ - static const u8 trans[7][8] = { - /* Token: */ - /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ - /* 0 START: */ { 0, 0, 1, 2, 3, 1, 1, 1, }, - /* 1 NORMAL: */ { 0, 1, 1, 1, 1, 1, 1, 1, }, - /* 2 EXPLAIN: */ { 0, 2, 1, 1, 3, 1, 1, 1, }, - /* 3 CREATE: */ { 0, 3, 1, 1, 1, 3, 4, 1, }, - /* 4 TRIGGER: */ { 5, 4, 4, 4, 4, 4, 4, 4, }, - /* 5 SEMI: */ { 5, 5, 4, 4, 4, 4, 4, 6, }, - /* 6 END: */ { 0, 6, 4, 4, 4, 4, 4, 4, }, - }; -#else - /* If triggers are not suppored by this compile then the statement machine - ** used to detect the end of a statement is much simplier - */ - static const u8 trans[2][3] = { - /* Token: */ - /* State: ** SEMI WS OTHER */ - /* 0 START: */ { 0, 0, 1, }, - /* 1 NORMAL: */ { 0, 1, 1, }, - }; -#endif /* SQLITE_OMIT_TRIGGER */ - - while( *zSql ){ - switch( *zSql ){ - case ';': { /* A semicolon */ - token = tkSEMI; - break; - } - case ' ': - case '\r': - case '\t': - case '\n': - case '\f': { /* White space is ignored */ - token = tkWS; - break; - } - case '/': { /* C-style comments */ - if( zSql[1]!='*' ){ - token = tkOTHER; - break; - } - zSql += 2; - while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } - if( zSql[0]==0 ) return 0; - zSql++; - token = tkWS; - break; - } - case '-': { /* SQL-style comments from "--" to end of line */ - if( zSql[1]!='-' ){ - token = tkOTHER; - break; - } - while( *zSql && *zSql!='\n' ){ zSql++; } - if( *zSql==0 ) return state==0; - token = tkWS; - break; - } - case '[': { /* Microsoft-style identifiers in [...] */ - zSql++; - while( *zSql && *zSql!=']' ){ zSql++; } - if( *zSql==0 ) return 0; - token = tkOTHER; - break; - } - case '`': /* Grave-accent quoted symbols used by MySQL */ - case '"': /* single- and double-quoted strings */ - case '\'': { - int c = *zSql; - zSql++; - while( *zSql && *zSql!=c ){ zSql++; } - if( *zSql==0 ) return 0; - token = tkOTHER; - break; - } - default: { - int c; - if( IdChar((u8)*zSql) ){ - /* Keywords and unquoted identifiers */ - int nId; - for(nId=1; IdChar(zSql[nId]); nId++){} -#ifdef SQLITE_OMIT_TRIGGER - token = tkOTHER; -#else - switch( *zSql ){ - case 'c': case 'C': { - if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){ - token = tkCREATE; - }else{ - token = tkOTHER; - } - break; - } - case 't': case 'T': { - if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){ - token = tkTRIGGER; - }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){ - token = tkTEMP; - }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){ - token = tkTEMP; - }else{ - token = tkOTHER; - } - break; - } - case 'e': case 'E': { - if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){ - token = tkEND; - }else -#ifndef SQLITE_OMIT_EXPLAIN - if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){ - token = tkEXPLAIN; - }else -#endif - { - token = tkOTHER; - } - break; - } - default: { - token = tkOTHER; - break; - } - } -#endif /* SQLITE_OMIT_TRIGGER */ - zSql += nId-1; - }else{ - /* Operators and special symbols */ - token = tkOTHER; - } - break; - } - } - state = trans[state][token]; - zSql++; - } - return state==0; -} - -#ifndef SQLITE_OMIT_UTF16 -/* -** This routine is the same as the sqlite3_complete() routine described -** above, except that the parameter is required to be UTF-16 encoded, not -** UTF-8. -*/ -int sqlite3_complete16(const void *zSql){ - sqlite3_value *pVal; - char const *zSql8; - int rc = 0; - - pVal = sqlite3ValueNew(); - sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); - zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); - if( zSql8 ){ - rc = sqlite3_complete(zSql8); - }else if( zSql ){ - rc = SQLITE_NOMEM; - sqlite3MallocClearFailed(); - } - sqlite3ValueFree(pVal); - return rc; -} -#endif /* SQLITE_OMIT_UTF16 */ -#endif /* SQLITE_OMIT_COMPLETE */ ADDED SQLite.Interop/src/config.h Index: SQLite.Interop/src/config.h ================================================================== --- /dev/null +++ SQLite.Interop/src/config.h @@ -0,0 +1,1 @@ +#define SQLITE_PTR_SZ 4 Index: SQLite.Interop/src/date.c ================================================================== --- SQLite.Interop/src/date.c +++ SQLite.Interop/src/date.c @@ -14,11 +14,11 @@ ** ** There is only one exported symbol in this file - the function ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: date.c,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: date.c,v 1.1 2005/03/01 16:04:28 rmsimpson Exp $ ** ** NOTES: ** ** SQLite processes all times and dates as Julian Day numbers. The ** dates and times are stored as the number of days since noon @@ -103,32 +103,34 @@ nextC = va_arg(ap, int); pVal = va_arg(ap, int*); val = 0; while( N-- ){ if( !isdigit(*(u8*)zDate) ){ - goto end_getDigits; + return cnt; } val = val*10 + *zDate - '0'; zDate++; } if( valmax || (nextC!=0 && nextC!=*zDate) ){ - goto end_getDigits; + return cnt; } *pVal = val; zDate++; cnt++; }while( nextC ); - va_end(ap); -end_getDigits: return cnt; } /* ** Read text from z[] and convert into a floating point number. Return ** the number of digits converted. */ -#define getValue sqlite3AtoF +static int getValue(const char *z, double *pR){ + const char *zEnd; + *pR = sqlite3AtoF(z, &zEnd); + return zEnd - z; +} /* ** Parse a timezone extension on the end of a date-time. ** The extension is of the form: ** @@ -236,11 +238,11 @@ p->validJD = 1; p->validYMD = 0; if( p->validHMS ){ p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0; if( p->validTZ ){ - p->rJD -= p->tz*60/86400.0; + p->rJD += p->tz*60/86400.0; p->validHMS = 0; p->validTZ = 0; } } } @@ -268,11 +270,11 @@ } if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){ return 1; } zDate += 10; - while( isspace(*(u8*)zDate) || 'T'==*(u8*)zDate ){ zDate++; } + while( isspace(*(u8*)zDate) ){ zDate++; } if( parseHhMmSs(zDate, p)==0 ){ /* We got the time */ }else if( *zDate==0 ){ p->validHMS = 0; }else{ @@ -316,11 +318,11 @@ sqlite3OsCurrentTime(&r); p->rJD = r; p->validJD = 1; return 0; }else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){ - getValue(zDate, &p->rJD); + p->rJD = sqlite3AtoF(zDate, 0); p->validJD = 1; return 0; } return 1; } @@ -639,14 +641,14 @@ */ static int isDate(int argc, sqlite3_value **argv, DateTime *p){ int i; if( argc==0 ) return 1; if( SQLITE_NULL==sqlite3_value_type(argv[0]) || - parseDateOrTime((char*)sqlite3_value_text(argv[0]), p) ) return 1; + parseDateOrTime(sqlite3_value_text(argv[0]), p) ) return 1; for(i=1; ia; inSrc; i++, pItem++){ pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase); - sqlite3DeleteTable(pParse->db, pItem->pTab); pItem->pTab = pTab; - if( pTab ){ - pTab->nRef++; - } } return pTab; } /* @@ -57,23 +53,18 @@ } /* ** Generate code that will open a table for reading. */ -void sqlite3OpenTable( - Parse *p, /* Generate code into this VDBE */ +void sqlite3OpenTableForReading( + Vdbe *v, /* Generate code into this VDBE */ int iCur, /* The cursor number of the table */ - int iDb, /* The database index in sqlite3.aDb[] */ - Table *pTab, /* The table to be opened */ - int opcode /* OP_OpenRead or OP_OpenWrite */ + Table *pTab /* The table to be opened */ ){ - Vdbe *v = sqlite3GetVdbe(p); - assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); - sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName); - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); + sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); VdbeComment((v, "# %s", pTab->zName)); - sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } /* @@ -98,19 +89,19 @@ int iCur; /* VDBE Cursor number for pTab */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ NameContext sNC; /* Name context to resolve expressions in */ - int iDb; #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ int triggers_exist = 0; /* True if any triggers exist */ #endif sContext.pParse = 0; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( pParse->nErr || sqlite3_malloc_failed ){ + pTabList = 0; goto delete_from_cleanup; } db = pParse->db; assert( pTabList->nSrc==1 ); @@ -138,13 +129,12 @@ #endif if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){ goto delete_from_cleanup; } - iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - assert( iDbnDb ); - zDb = db->aDb[iDb].zName; + assert( pTab->iDbnDb ); + zDb = db->aDb[pTab->iDb].zName; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto delete_from_cleanup; } /* If pTab is really a view, make sure it has been initialized. @@ -181,18 +171,18 @@ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto delete_from_cleanup; } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); - sqlite3BeginWriteOperation(pParse, triggers_exist, iDb); + sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb); - /* If we are trying to delete from a view, realize that view into - ** a ephemeral table. + /* If we are trying to delete from a view, construct that view into + ** a temporary table. */ if( isView ){ Select *pView = sqlite3SelectDup(pTab->pSelect); - sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0); + sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } /* Initialize the counter of the number of rows deleted, if ** we are counting rows. @@ -210,43 +200,46 @@ /* If counting rows deleted, just count the total number of ** entries in the table. */ int endOfLoop = sqlite3VdbeMakeLabel(v); int addr; if( !isView ){ - sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); + sqlite3OpenTableForReading(v, iCur, pTab); } sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2); addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); sqlite3VdbeAddOp(v, OP_Next, iCur, addr); sqlite3VdbeResolveLabel(v, endOfLoop); sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } if( !isView ){ - sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb); - if( !pParse->nested ){ - sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); - } + sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - assert( pIdx->pSchema==pTab->pSchema ); - sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb); + sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb); } } } /* The usual case: There is a WHERE clause so we have to scan through ** the table and pick which records to delete. */ else{ + /* Ensure all required collation sequences are available. */ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){ + goto delete_from_cleanup; + } + } + /* Begin the database scan */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0); if( pWInfo==0 ) goto delete_from_cleanup; /* Remember the rowid of every item to be deleted. */ - sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); - sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); + sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); + sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0); if( db->flags & SQLITE_CountRows ){ sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); } /* End the database scan loop. @@ -262,47 +255,48 @@ /* Delete every item whose key was written to the list during the ** database scan. We have to delete items after the scan is complete ** because deleting an item can change the scan order. */ + sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0); end = sqlite3VdbeMakeLabel(v); /* This is the beginning of the delete loop when there are ** row triggers. */ if( triggers_exist ){ - addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); + addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end); + sqlite3VdbeAddOp(v, OP_Dup, 0, 0); if( !isView ){ - sqlite3VdbeAddOp(v, OP_Dup, 0, 0); - sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); + sqlite3OpenTableForReading(v, iCur, pTab); } sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); - sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); + sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); - sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0); + sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0); if( !isView ){ sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, - addr); + addr); } if( !isView ){ /* Open cursors for the table we are deleting from and all its ** indices. If there are row triggers, this happens inside the - ** OP_FifoRead loop because the cursor have to all be closed + ** OP_ListRead loop because the cursor have to all be closed ** before the trigger fires. If there are no row triggers, the ** cursors are opened only once on the outside the loop. */ sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite); /* This is the beginning of the delete loop when there are no ** row triggers */ if( !triggers_exist ){ - addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); + addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end); } /* Delete the row */ sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); } @@ -317,16 +311,17 @@ } sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, - addr); + addr); } /* End of the delete loop */ sqlite3VdbeAddOp(v, OP_Goto, 0, addr); sqlite3VdbeResolveLabel(v, end); + sqlite3VdbeAddOp(v, OP_ListReset, 0, 0); /* Close the cursors after the loop if there are no row triggers */ if( !triggers_exist ){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); @@ -382,14 +377,11 @@ ){ int addr; addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0); sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0); sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); - if( count ){ - sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); - } - sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); } /* ** This routine generates VDBE code that causes the deletion of all ** index entries associated with a single row of a single table. @@ -435,18 +427,17 @@ int iCur /* Cursor number for the pIdx->pTable table */ ){ int j; Table *pTab = pIdx->pTable; - sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); + sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); for(j=0; jnColumn; j++){ int idx = pIdx->aiColumn[j]; if( idx==pTab->iPKey ){ sqlite3VdbeAddOp(v, OP_Dup, j, 0); }else{ sqlite3VdbeAddOp(v, OP_Column, iCur, idx); - sqlite3ColumnDefault(v, pTab, idx); } } - sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0); + sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24)); sqlite3IndexAffinityStr(v, pIdx); } DELETED SQLite.Interop/src/experimental.c Index: SQLite.Interop/src/experimental.c ================================================================== --- SQLite.Interop/src/experimental.c +++ /dev/null @@ -1,36 +0,0 @@ -/* -** 2005 January 20 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains C code routines that are not a part of the official -** SQLite API. These routines are unsupported. -** -** $Id: experimental.c,v 1.5 2006/01/16 15:51:47 rmsimpson Exp $ -*/ -#include "sqliteInt.h" - -/* -** Set all the parameters in the compiled SQL statement to NULL. -*/ -int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ - int i; - int rc = SQLITE_OK; - for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){ - rc = sqlite3_bind_null(pStmt, i); - } - return rc; -} - -/* -** Sleep for a little while. Return the amount of time slept. -*/ -int sqlite3_sleep(int ms){ - return sqlite3OsSleep(ms); -} Index: SQLite.Interop/src/expr.c ================================================================== --- SQLite.Interop/src/expr.c +++ SQLite.Interop/src/expr.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.22 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: expr.c,v 1.1 2005/03/01 16:04:29 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* @@ -32,22 +32,16 @@ ** SELECT * FROM t1 WHERE a; ** SELECT a AS b FROM t1 WHERE b; ** SELECT * FROM t1 WHERE (select a from t1); */ char sqlite3ExprAffinity(Expr *pExpr){ - int op = pExpr->op; - if( op==TK_AS ){ + if( pExpr->op==TK_AS ){ return sqlite3ExprAffinity(pExpr->pLeft); } - if( op==TK_SELECT ){ + if( pExpr->op==TK_SELECT ){ return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr); } -#ifndef SQLITE_OMIT_CAST - if( op==TK_CAST ){ - return sqlite3AffinityType(&pExpr->token); - } -#endif return pExpr->affinity; } /* ** Return the default collation sequence for the expression pExpr. If @@ -55,11 +49,11 @@ */ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ CollSeq *pColl = 0; if( pExpr ){ pColl = pExpr->pColl; - if( (pExpr->op==TK_AS || pExpr->op==TK_CAST) && !pColl ){ + if( pExpr->op==TK_AS && !pColl ){ return sqlite3ExprCollSeq(pParse, pExpr->pLeft); } } if( sqlite3CheckCollSeq(pParse, pColl) ){ pColl = 0; @@ -73,26 +67,28 @@ ** type affinity that should be used for the comparison operator. */ char sqlite3CompareAffinity(Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); if( aff1 && aff2 ){ - /* Both sides of the comparison are columns. If one has numeric - ** affinity, use that. Otherwise use no affinity. + /* Both sides of the comparison are columns. If one has numeric or + ** integer affinity, use that. Otherwise use no affinity. */ - if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){ + if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){ + return SQLITE_AFF_INTEGER; + }else if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){ return SQLITE_AFF_NUMERIC; }else{ return SQLITE_AFF_NONE; } }else if( !aff1 && !aff2 ){ /* Neither side of the comparison is a column. Compare the ** results directly. */ + /* return SQLITE_AFF_NUMERIC; // Ticket #805 */ return SQLITE_AFF_NONE; }else{ /* One side is a column, the other is not. Use the columns affinity. */ - assert( aff1==0 || aff2==0 ); return (aff1 + aff2); } } /* @@ -124,18 +120,15 @@ ** if the index with affinity idx_affinity may be used to implement ** the comparison in pExpr. */ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){ char aff = comparisonAffinity(pExpr); - switch( aff ){ - case SQLITE_AFF_NONE: - return 1; - case SQLITE_AFF_TEXT: - return idx_affinity==SQLITE_AFF_TEXT; - default: - return sqlite3IsNumericAffinity(idx_affinity); - } + return + (aff==SQLITE_AFF_NONE) || + (aff==SQLITE_AFF_NUMERIC && idx_affinity==SQLITE_AFF_INTEGER) || + (aff==SQLITE_AFF_INTEGER && idx_affinity==SQLITE_AFF_NUMERIC) || + (aff==idx_affinity); } /* ** Return the P1 value that should be used for a binary comparison ** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2. @@ -143,11 +136,11 @@ ** P1 value to tell the opcode to jump if either expression ** evaluates to NULL. */ static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){ char aff = sqlite3ExprAffinity(pExpr2); - return ((int)sqlite3CompareAffinity(pExpr1, aff))+(jumpIfNull?0x100:0); + return (((int)sqlite3CompareAffinity(pExpr1, aff))<<8)+(jumpIfNull?1:0); } /* ** Return a pointer to the collation sequence that should be used by ** a binary comparison operator comparing pLeft and pRight. @@ -188,16 +181,11 @@ */ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){ Expr *pNew; pNew = sqliteMalloc( sizeof(Expr) ); if( pNew==0 ){ - /* When malloc fails, delete pLeft and pRight. Expressions passed to - ** this function must always be allocated with sqlite3Expr() for this - ** reason. - */ - sqlite3ExprDelete(pLeft); - sqlite3ExprDelete(pRight); + /* When malloc fails, we leak memory from pLeft and pRight */ return 0; } pNew->op = op; pNew->pLeft = pLeft; pNew->pRight = pRight; @@ -212,12 +200,13 @@ } /* ** When doing a nested parse, you can include terms in an expression ** that look like this: #0 #1 #2 ... These terms refer to elements -** on the stack. "#0" means the top of the stack. -** "#1" means the next down on the stack. And so forth. +** on the stack. "#0" (or just "#") means the top of the stack. +** "#1" means the next down on the stack. And so forth. #-1 means +** memory location 0. #-2 means memory location 1. And so forth. ** ** This routine is called by the parser to deal with on of those terms. ** It immediately generates code to store the value in a memory location. ** The returns an expression that will code to extract the value from ** that memory location as needed. @@ -224,23 +213,27 @@ */ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){ Vdbe *v = pParse->pVdbe; Expr *p; int depth; + if( v==0 ) return 0; if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken); return 0; } - if( v==0 ) return 0; p = sqlite3Expr(TK_REGISTER, 0, 0, pToken); if( p==0 ){ return 0; /* Malloc failed */ } - depth = atoi((char*)&pToken->z[1]); - p->iTable = pParse->nMem++; - sqlite3VdbeAddOp(v, OP_Dup, depth, 0); - sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1); + depth = atoi(&pToken->z[1]); + if( depth>=0 ){ + p->iTable = pParse->nMem++; + sqlite3VdbeAddOp(v, OP_Dup, depth, 0); + sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1); + }else{ + p->iTable = -1-depth; + } return p; } /* ** Join two expressions using an AND operator. If either expression is @@ -261,15 +254,15 @@ ** text between the two given tokens. */ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ assert( pRight!=0 ); assert( pLeft!=0 ); - if( !sqlite3ThreadDataReadOnly()->mallocFailed && pRight->z && pLeft->z ){ + if( !sqlite3_malloc_failed && pRight->z && pLeft->z ){ assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 ); if( pLeft->dyn==0 && pRight->dyn==0 ){ pExpr->span.z = pLeft->z; - pExpr->span.n = pRight->n + (pRight->z - pLeft->z); + pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z); }else{ pExpr->span.z = 0; } } } @@ -280,11 +273,11 @@ */ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){ Expr *pNew; pNew = sqliteMalloc( sizeof(Expr) ); if( pNew==0 ){ - sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */ + /* sqlite3ExprListDelete(pList); // Leak pList when malloc fails */ return 0; } pNew->op = TK_FUNCTION; pNew->pList = pList; if( pToken ){ @@ -325,11 +318,11 @@ pExpr->iTable = ++pParse->nVar; }else if( pToken->z[0]=='?' ){ /* Wildcard of the form "?nnn". Convert "nnn" to an integer and ** use it as the variable number */ int i; - pExpr->iTable = i = atoi((char*)&pToken->z[1]); + pExpr->iTable = i = atoi(&pToken->z[1]); if( i<1 || i>SQLITE_MAX_VARIABLE_NUMBER ){ sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", SQLITE_MAX_VARIABLE_NUMBER); } if( i>pParse->nVar ){ @@ -353,14 +346,14 @@ } if( i>=pParse->nVarExpr ){ pExpr->iTable = ++pParse->nVar; if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){ pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10; - sqliteReallocOrFree((void**)&pParse->apVarExpr, + pParse->apVarExpr = sqliteRealloc(pParse->apVarExpr, pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) ); } - if( !sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( !sqlite3_malloc_failed ){ assert( pParse->apVarExpr!=0 ); pParse->apVarExpr[pParse->nVarExpr++] = pExpr; } } } @@ -378,25 +371,10 @@ sqlite3ExprListDelete(p->pList); sqlite3SelectDelete(p->pSelect); sqliteFree(p); } -/* -** The Expr.token field might be a string literal that is quoted. -** If so, remove the quotation marks. -*/ -void sqlite3DequoteExpr(Expr *p){ - if( ExprHasAnyProperty(p, EP_Dequoted) ){ - return; - } - ExprSetProperty(p, EP_Dequoted); - if( p->token.dyn==0 ){ - sqlite3TokenCopy(&p->token, &p->token); - } - sqlite3Dequote((char*)p->token.z); -} - /* ** The following group of routines make deep copies of expressions, ** expression lists, ID lists, and select statements. The copies can ** be deleted (by being passed to their respective ...Delete() routines) @@ -413,28 +391,27 @@ if( p==0 ) return 0; pNew = sqliteMallocRaw( sizeof(*p) ); if( pNew==0 ) return 0; memcpy(pNew, p, sizeof(*pNew)); if( p->token.z!=0 ){ - pNew->token.z = (u8*)sqliteStrNDup((char*)p->token.z, p->token.n); + pNew->token.z = sqliteStrNDup(p->token.z, p->token.n); pNew->token.dyn = 1; }else{ assert( pNew->token.z==0 ); } pNew->span.z = 0; pNew->pLeft = sqlite3ExprDup(p->pLeft); pNew->pRight = sqlite3ExprDup(p->pRight); pNew->pList = sqlite3ExprListDup(p->pList); pNew->pSelect = sqlite3SelectDup(p->pSelect); - pNew->pTab = p->pTab; return pNew; } void sqlite3TokenCopy(Token *pTo, Token *pFrom){ if( pTo->dyn ) sqliteFree((char*)pTo->z); if( pFrom->z ){ pTo->n = pFrom->n; - pTo->z = (u8*)sqliteStrNDup((char*)pFrom->z, pFrom->n); + pTo->z = sqliteStrNDup(pFrom->z, pFrom->n); pTo->dyn = 1; }else{ pTo->z = 0; } } @@ -460,12 +437,11 @@ ** expression list. The logic in SELECT processing that determines ** the names of columns in the result set needs this information */ sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span); } assert( pNewExpr==0 || pNewExpr->span.z!=0 - || pOldExpr->span.z==0 - || sqlite3ThreadDataReadOnly()->mallocFailed ); + || pOldExpr->span.z==0 || sqlite3_malloc_failed ); pItem->zName = sqliteStrDup(pOldItem->zName); pItem->sortOrder = pOldItem->sortOrder; pItem->isAgg = pOldItem->isAgg; pItem->done = 0; } @@ -490,19 +466,18 @@ if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ struct SrcList_item *pNewItem = &pNew->a[i]; struct SrcList_item *pOldItem = &p->a[i]; - Table *pTab; pNewItem->zDatabase = sqliteStrDup(pOldItem->zDatabase); pNewItem->zName = sqliteStrDup(pOldItem->zName); pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias); pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; - pTab = pNewItem->pTab = pOldItem->pTab; - if( pTab ){ - pTab->nRef++; + pNewItem->pTab = pOldItem->pTab; + if( pNewItem->pTab ){ + pNewItem->pTab->isTransient = 0; } pNewItem->pSelect = sqlite3SelectDup(pOldItem->pSelect); pNewItem->pOn = sqlite3ExprDup(pOldItem->pOn); pNewItem->pUsing = sqlite3IdListDup(pOldItem->pUsing); pNewItem->colUsed = pOldItem->colUsed; @@ -515,14 +490,11 @@ if( p==0 ) return 0; pNew = sqliteMallocRaw( sizeof(*pNew) ); if( pNew==0 ) return 0; pNew->nId = pNew->nAlloc = p->nId; pNew->a = sqliteMallocRaw( p->nId*sizeof(p->a[0]) ); - if( pNew->a==0 ){ - sqliteFree(pNew); - return 0; - } + if( pNew->a==0 ) return 0; for(i=0; inId; i++){ struct IdList_item *pNewItem = &pNew->a[i]; struct IdList_item *pOldItem = &p->a[i]; pNewItem->zName = sqliteStrDup(pOldItem->zName); pNewItem->idx = pOldItem->idx; @@ -545,18 +517,14 @@ pNew->pPrior = sqlite3SelectDup(p->pPrior); pNew->pLimit = sqlite3ExprDup(p->pLimit); pNew->pOffset = sqlite3ExprDup(p->pOffset); pNew->iLimit = -1; pNew->iOffset = -1; + pNew->ppOpenTemp = 0; + pNew->pFetch = 0; pNew->isResolved = p->isResolved; pNew->isAgg = p->isAgg; - pNew->usesVirt = 0; - pNew->disallowOrderBy = 0; - pNew->pRightmost = 0; - pNew->addrOpenVirt[0] = -1; - pNew->addrOpenVirt[1] = -1; - pNew->addrOpenVirt[2] = -1; return pNew; } #else Select *sqlite3SelectDup(Select *p){ assert( p==0 ); @@ -571,38 +539,32 @@ */ ExprList *sqlite3ExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){ if( pList==0 ){ pList = sqliteMalloc( sizeof(ExprList) ); if( pList==0 ){ - goto no_mem; + /* sqlite3ExprDelete(pExpr); // Leak memory if malloc fails */ + return 0; } assert( pList->nAlloc==0 ); } if( pList->nAlloc<=pList->nExpr ){ - struct ExprList_item *a; - int n = pList->nAlloc*2 + 4; - a = sqliteRealloc(pList->a, n*sizeof(pList->a[0])); - if( a==0 ){ - goto no_mem; - } - pList->a = a; - pList->nAlloc = n; + pList->nAlloc = pList->nAlloc*2 + 4; + pList->a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0])); + if( pList->a==0 ){ + /* sqlite3ExprDelete(pExpr); // Leak memory if malloc fails */ + pList->nExpr = pList->nAlloc = 0; + return pList; + } } assert( pList->a!=0 ); if( pExpr || pName ){ struct ExprList_item *pItem = &pList->a[pList->nExpr++]; memset(pItem, 0, sizeof(*pItem)); - pItem->zName = sqlite3NameFromToken(pName); pItem->pExpr = pExpr; + pItem->zName = sqlite3NameFromToken(pName); } return pList; - -no_mem: - /* Avoid leaking memory if malloc has failed. */ - sqlite3ExprDelete(pExpr); - sqlite3ExprListDelete(pList); - return 0; } /* ** Delete an entire expression list. */ @@ -628,12 +590,10 @@ ** of the current node but continue with siblings. 2 means abandon ** the tree walk completely. ** ** The return value from this routine is 1 to abandon the tree walk ** and 0 to continue. -** -** NOTICE: This routine does *not* descend into subqueries. */ static int walkExprList(ExprList *, int (*)(void *, Expr*), void *); static int walkExprTree(Expr *pExpr, int (*xFunc)(void*,Expr*), void *pArg){ int rc; if( pExpr==0 ) return 0; @@ -687,39 +647,29 @@ ** the expression as constant, then we assume the whole expression ** is constant. See sqlite3ExprIsConstant() for additional information. */ static int exprNodeIsConstant(void *pArg, Expr *pExpr){ switch( pExpr->op ){ - /* Consider functions to be constant if all their arguments are constant - ** and *pArg==2 */ - case TK_FUNCTION: - if( *((int*)pArg)==2 ) return 0; - /* Fall through */ case TK_ID: case TK_COLUMN: case TK_DOT: case TK_AGG_FUNCTION: - case TK_AGG_COLUMN: + case TK_FUNCTION: #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: case TK_EXISTS: #endif *((int*)pArg) = 0; return 2; - case TK_IN: - if( pExpr->pSelect ){ - *((int*)pArg) = 0; - return 2; - } default: return 0; } } /* ** Walk an expression tree. Return 1 if the expression is constant -** and 0 if it involves variables or function calls. +** and 0 if it involves variables. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ @@ -727,35 +677,20 @@ int isConst = 1; walkExprTree(p, exprNodeIsConstant, &isConst); return isConst; } -/* -** Walk an expression tree. Return 1 if the expression is constant -** or a function call with constant arguments. Return and 0 if there -** are any variables. -** -** For the purposes of this function, a double-quoted string (ex: "abc") -** is considered a variable but a single-quoted string (ex: 'abc') is -** a constant. -*/ -int sqlite3ExprIsConstantOrFunction(Expr *p){ - int isConst = 2; - walkExprTree(p, exprNodeIsConstant, &isConst); - return isConst!=0; -} - /* ** If the expression p codes a constant integer that is small enough ** to fit in a 32-bit integer, return 1 and put the value of the integer ** in *pValue. If the expression is not an integer or if it is too big ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ int sqlite3ExprIsInteger(Expr *p, int *pValue){ switch( p->op ){ case TK_INTEGER: { - if( sqlite3GetInt32((char*)p->token.z, pValue) ){ + if( sqlite3GetInt32(p->token.z, pValue) ){ return 1; } break; } case TK_UPLUS: { @@ -808,11 +743,11 @@ ** ** If the name cannot be resolved unambiguously, leave an error message ** in pParse and return non-zero. Return zero on success. */ static int lookupName( - Parse *pParse, /* The parsing context */ + Parse *pParse, /* The parsing context */ Token *pDbToken, /* Name of the database containing table, or NULL */ Token *pTableToken, /* Name of table containing column, or NULL */ Token *pColumnToken, /* Name of the column. */ NameContext *pNC, /* The name context used to resolve the name */ Expr *pExpr /* Make this EXPR node point to the selected column */ @@ -830,23 +765,24 @@ assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */ zDb = sqlite3NameFromToken(pDbToken); zTab = sqlite3NameFromToken(pTableToken); zCol = sqlite3NameFromToken(pColumnToken); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ - goto lookupname_end; + if( sqlite3_malloc_failed ){ + return 1; /* Leak memory (zDb and zTab) if malloc fails */ } pExpr->iTable = -1; while( pNC && cnt==0 ){ - ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; + ExprList *pEList = pNC->pEList; + pNC->nRef++; + /* assert( zTab==0 || pEList==0 ); */ if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ Table *pTab = pItem->pTab; - int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); Column *pCol; if( pTab==0 ) continue; assert( pTab->nCol>0 ); if( zTab ){ @@ -854,51 +790,30 @@ char *zTabName = pItem->zAlias; if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue; }else{ char *zTabName = pTab->zName; if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue; - if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){ + if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){ continue; } } } if( 0==(cntTab++) ){ pExpr->iTable = pItem->iCursor; - pExpr->pSchema = pTab->pSchema; + pExpr->iDb = pTab->iDb; pMatch = pItem; } for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ - const char *zColl = pTab->aCol[j].zColl; - IdList *pUsing; cnt++; pExpr->iTable = pItem->iCursor; pMatch = pItem; - pExpr->pSchema = pTab->pSchema; + pExpr->iDb = pTab->iDb; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->affinity = pTab->aCol[j].affinity; - pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0); - if( pItem->jointype & JT_NATURAL ){ - /* If this match occurred in the left table of a natural join, - ** then skip the right table to avoid a duplicate match */ - pItem++; - i++; - } - if( (pUsing = pItem->pUsing)!=0 ){ - /* If this match occurs on a column that is in the USING clause - ** of a join, skip the search of the right table of the join - ** to avoid a duplicate match there. */ - int k; - for(k=0; knId; k++){ - if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){ - pItem++; - i++; - break; - } - } - } + pExpr->pColl = pTab->aCol[j].pColl; break; } } } } @@ -922,20 +837,18 @@ if( pTab ){ int j; Column *pCol = pTab->aCol; - pExpr->pSchema = pTab->pSchema; + pExpr->iDb = pTab->iDb; cntTab++; for(j=0; j < pTab->nCol; j++, pCol++) { if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ - const char *zColl = pTab->aCol[j].zColl; cnt++; pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->affinity = pTab->aCol[j].affinity; - pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0); - pExpr->pTab = pTab; + pExpr->pColl = pTab->aCol[j].pColl; break; } } } } @@ -960,21 +873,21 @@ ** In cases like this, replace pExpr with a copy of the expression that ** forms the result set entry ("a+b" in the example) and return immediately. ** Note that the expression in the result set should have already been ** resolved by the time the WHERE clause is resolved. */ - if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){ + if( cnt==0 && pEList!=0 && zTab==0 ){ for(j=0; jnExpr; j++){ char *zAs = pEList->a[j].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ assert( pExpr->pLeft==0 && pExpr->pRight==0 ); pExpr->op = TK_AS; pExpr->iColumn = j; pExpr->pLeft = sqlite3ExprDup(pEList->a[j].pExpr); - cnt = 1; + sqliteFree(zCol); assert( zTab==0 && zDb==0 ); - goto lookupname_end_2; + return 0; } } } /* Advance to the next name context. The loop will exit when either @@ -989,13 +902,10 @@ ** If X and Y are NULL (in other words if only the column name Z is ** supplied) and the value of Z is enclosed in double-quotes, then ** Z is a string literal if it doesn't match any column names. In that ** case, we need to return right away and not make any changes to ** pExpr. - ** - ** Because no reference was made to outer contexts, the pNC->nRef - ** fields are not changed in any context. */ if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){ sqliteFree(zCol); return 0; } @@ -1007,13 +917,13 @@ if( cnt!=1 ){ char *z = 0; char *zErr; zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s"; if( zDb ){ - sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, (char*)0); + sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, 0); }else if( zTab ){ - sqlite3SetString(&z, zTab, ".", zCol, (char*)0); + sqlite3SetString(&z, zTab, ".", zCol, 0); }else{ z = sqliteStrDup(zCol); } sqlite3ErrorMsg(pParse, zErr, z); sqliteFree(z); @@ -1033,39 +943,67 @@ } assert( pMatch->iCursor==pExpr->iTable ); pMatch->colUsed |= 1<pLeft); pExpr->pLeft = 0; sqlite3ExprDelete(pExpr->pRight); pExpr->pRight = 0; pExpr->op = TK_COLUMN; -lookupname_end_2: - sqliteFree(zCol); if( cnt==1 ){ assert( pNC!=0 ); sqlite3AuthRead(pParse, pExpr, pNC->pSrcList); - if( pMatch && !pMatch->pSelect ){ - pExpr->pTab = pMatch->pTab; - } - /* Increment the nRef value on all name contexts from TopNC up to - ** the point where the name matched. */ - for(;;){ - assert( pTopNC!=0 ); - pTopNC->nRef++; - if( pTopNC==pNC ) break; - pTopNC = pTopNC->pNext; - } - return 0; - } else { - return 1; + } + return cnt!=1; +} + +/* +** pExpr is a node that defines a function of some kind. It might +** be a syntactic function like "count(x)" or it might be a function +** that implements an operator, like "a LIKE b". +** +** This routine makes *pzName point to the name of the function and +** *pnName hold the number of characters in the function name. +*/ +static void getFunctionName(Expr *pExpr, const char **pzName, int *pnName){ + switch( pExpr->op ){ + case TK_FUNCTION: { + *pzName = pExpr->token.z; + *pnName = pExpr->token.n; + break; + } + case TK_LIKE: { + *pzName = "like"; + *pnName = 4; + break; + } + case TK_GLOB: { + *pzName = "glob"; + *pnName = 4; + break; + } + case TK_CTIME: { + *pzName = "current_time"; + *pnName = 12; + break; + } + case TK_CDATE: { + *pzName = "current_date"; + *pnName = 12; + break; + } + case TK_CTIMESTAMP: { + *pzName = "current_timestamp"; + *pnName = 17; + break; + } } } /* ** This routine is designed as an xFunc for walkExprTree(). @@ -1089,11 +1027,11 @@ pParse = pNC->pParse; if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1; ExprSetProperty(pExpr, EP_Resolved); #ifndef NDEBUG - if( pSrcList && pSrcList->nAlloc>0 ){ + if( pSrcList ){ int i; for(i=0; inSrc; i++){ assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursornTab); } } @@ -1139,11 +1077,15 @@ return 1; } /* Resolve function names */ - case TK_CONST_FUNC: + case TK_CTIME: + case TK_CTIMESTAMP: + case TK_CDATE: + case TK_GLOB: + case TK_LIKE: case TK_FUNCTION: { ExprList *pList = pExpr->pList; /* The argument list */ int n = pList ? pList->nExpr : 0; /* Number of arguments */ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ @@ -1150,14 +1092,13 @@ int is_agg = 0; /* True if is an aggregate function */ int i; int nId; /* Number of characters in function name */ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ - int enc = ENC(pParse->db); /* The database encoding */ + int enc = pParse->db->enc; /* The database encoding */ - zId = (char*)pExpr->token.z; - nId = pExpr->token.n; + getFunctionName(pExpr, &zId, &nId); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); if( pDef==0 ){ pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); if( pDef==0 ){ no_such_func = 1; @@ -1198,31 +1139,17 @@ case TK_EXISTS: #endif case TK_IN: { if( pExpr->pSelect ){ int nRef = pNC->nRef; -#ifndef SQLITE_OMIT_CHECK - if( pNC->isCheck ){ - sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints"); - } -#endif sqlite3SelectResolve(pParse, pExpr->pSelect, pNC); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); } } - break; - } -#ifndef SQLITE_OMIT_CHECK - case TK_VARIABLE: { - if( pNC->isCheck ){ - sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints"); - } - break; - } -#endif + } } return 0; } /* @@ -1248,23 +1175,15 @@ */ int sqlite3ExprResolveNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ - int savedHasAgg; if( pExpr==0 ) return 0; - savedHasAgg = pNC->hasAgg; - pNC->hasAgg = 0; walkExprTree(pExpr, nameResolverStep, pNC); if( pNC->nErr>0 ){ ExprSetProperty(pExpr, EP_Error); } - if( pNC->hasAgg ){ - ExprSetProperty(pExpr, EP_Agg); - }else if( savedHasAgg ){ - pNC->hasAgg = 1; - } return ExprHasProperty(pExpr, EP_Error); } /* ** A pointer instance of this structure is used to pass information @@ -1276,55 +1195,55 @@ NameContext *pNC; /* Namespace of first enclosing query */ }; /* -** Generate code for scalar subqueries used as an expression -** and IN operators. Examples: -** -** (SELECT a FROM b) -- subquery -** EXISTS (SELECT a FROM b) -- EXISTS subquery -** x IN (4,5,11) -- IN operator with list on right-hand side -** x IN (SELECT a FROM b) -- IN operator with subquery on the right -** -** The pExpr parameter describes the expression that contains the IN -** operator or subquery. +** Generate code for subqueries and IN operators. +** +** IN operators comes in two forms: +** +** expr IN (exprlist) +** and +** expr IN (SELECT ...) +** +** The first form is handled by creating a set holding the list +** of allowed values. The second form causes the SELECT to generate +** a temporary table. */ #ifndef SQLITE_OMIT_SUBQUERY void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ - int testAddr = 0; /* One-time test address */ + int label = 0; /* Address after sub-select code */ Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; - /* This code must be run in its entirety every time it is encountered - ** if any of the following is true: - ** - ** * The right-hand side is a correlated subquery - ** * The right-hand side is an expression list containing variables - ** * We are inside a trigger - ** - ** If all of the above are false, then we can run this code just once - ** save the results, and reuse the same result on subsequent invocations. + /* If this is not a variable (correlated) select, then execute + ** it only once. Unless this is part of a trigger program. In + ** that case re-execute every time (this could be optimized). */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ int mem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); - testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); - assert( testAddr>0 || sqlite3ThreadDataReadOnly()->mallocFailed ); - sqlite3VdbeAddOp(v, OP_MemInt, 1, mem); + label = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp(v, OP_If, 0, label); + sqlite3VdbeAddOp(v, OP_Integer, 1, 0); + sqlite3VdbeAddOp(v, OP_MemStore, mem, 1); + } + + if( pExpr->pSelect ){ + sqlite3VdbeAddOp(v, OP_AggContextPush, 0, 0); } switch( pExpr->op ){ case TK_IN: { char affinity; KeyInfo keyInfo; - int addr; /* Address of OP_OpenVirtual instruction */ + int addr; /* Address of OP_OpenTemp instruction */ affinity = sqlite3ExprAffinity(pExpr->pLeft); /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' - ** expression it is handled the same way. A virtual table is + ** expression it is handled the same way. A temporary table is ** filled with single-field index keys representing the results ** from the SELECT or the . ** ** If the 'x' expression is a column value, or the SELECT... ** statement returns a column value, then the affinity of that @@ -1333,11 +1252,11 @@ ** if either column has NUMERIC or INTEGER affinity. If neither ** 'x' nor the SELECT... statement are columns, then numeric affinity ** is used. */ pExpr->iTable = pParse->nTab++; - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, pExpr->iTable, 0); + addr = sqlite3VdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 0); memset(&keyInfo, 0, sizeof(keyInfo)); keyInfo.nField = 1; sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1); if( pExpr->pSelect ){ @@ -1362,40 +1281,31 @@ ** store it in the temporary table. If is a column, then use ** that columns affinity when building index keys. If is not ** a column, use numeric affinity. */ int i; - ExprList *pList = pExpr->pList; - struct ExprList_item *pItem; - if( !affinity ){ affinity = SQLITE_AFF_NUMERIC; } keyInfo.aColl[0] = pExpr->pLeft->pColl; /* Loop through each expression in . */ - for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ - Expr *pE2 = pItem->pExpr; - - /* If the expression is not constant then we will need to - ** disable the test that was generated above that makes sure - ** this code only executes once. Because for a non-constant - ** expression we need to rerun this code each time. - */ - if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){ - VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1); - int i; - for(i=0; i<3; i++){ - aOp[i].opcode = OP_Noop; - } - testAddr = 0; + for(i=0; ipList->nExpr; i++){ + Expr *pE2 = pExpr->pList->a[i].pExpr; + + /* Check that the expression is constant and valid. */ + if( !sqlite3ExprIsConstant(pE2) ){ + sqlite3ErrorMsg(pParse, + "right-hand side of IN operator must be constant"); + return; } /* Evaluate the expression and insert it into the temp table */ sqlite3ExprCode(pParse, pE2); sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); - sqlite3VdbeAddOp(v, OP_IdxInsert, pExpr->iTable, 0); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); + sqlite3VdbeAddOp(v, OP_PutStrKey, pExpr->iTable, 0); } } sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO); break; } @@ -1404,35 +1314,34 @@ case TK_SELECT: { /* This has to be a scalar SELECT. Generate code to put the ** value of this select in a memory cell and record the number ** of the memory cell in iColumn. */ - static const Token one = { (u8*)"1", 0, 1 }; + int sop; Select *pSel; - int iMem; - int sop; - pExpr->iColumn = iMem = pParse->nMem++; + pExpr->iColumn = pParse->nMem++; pSel = pExpr->pSelect; if( pExpr->op==TK_SELECT ){ sop = SRT_Mem; - sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0); - VdbeComment((v, "# Init subquery result")); }else{ + static const Token one = { "1", 0, 1 }; sop = SRT_Exists; - sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem); - VdbeComment((v, "# Init EXISTS result")); - } - sqlite3ExprDelete(pSel->pLimit); - pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one); - sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0); - break; - } - } - - if( testAddr ){ - sqlite3VdbeJumpHere(v, testAddr); + sqlite3ExprListDelete(pSel->pEList); + pSel->pEList = sqlite3ExprListAppend(0, + sqlite3Expr(TK_INTEGER, 0, 0, &one), 0); + } + sqlite3Select(pParse, pSel, sop, pExpr->iColumn, 0, 0, 0, 0); + break; + } + } + + if( pExpr->pSelect ){ + sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0); + } + if( label<0 ){ + sqlite3VdbeResolveLabel(v, label); } return; } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -1443,11 +1352,11 @@ static void codeInteger(Vdbe *v, const char *z, int n){ int i; if( sqlite3GetInt32(z, &i) ){ sqlite3VdbeAddOp(v, OP_Integer, i, 0); }else if( sqlite3FitsIn64Bits(z) ){ - sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n); + sqlite3VdbeOp3(v, OP_Integer, 0, 0, z, n); }else{ sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n); } } @@ -1462,111 +1371,67 @@ ** below verify that the numbers are aligned correctly. */ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ Vdbe *v = pParse->pVdbe; int op; - int stackChng = 1; /* Amount of change to stack depth */ - if( v==0 ) return; if( pExpr==0 ){ - sqlite3VdbeAddOp(v, OP_Null, 0, 0); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); /* Empty expression evals to NULL */ return; } op = pExpr->op; switch( op ){ - case TK_AGG_COLUMN: { - AggInfo *pAggInfo = pExpr->pAggInfo; - struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; - if( !pAggInfo->directMode ){ - sqlite3VdbeAddOp(v, OP_MemLoad, pCol->iMem, 0); - break; - }else if( pAggInfo->useSortingIdx ){ - sqlite3VdbeAddOp(v, OP_Column, pAggInfo->sortingIdx, - pCol->iSorterColumn); - break; - } - /* Otherwise, fall thru into the TK_COLUMN case */ - } case TK_COLUMN: { - if( pExpr->iTable<0 ){ - /* This only happens when coding check constraints */ - assert( pParse->ckOffset>0 ); - sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1); + if( !pParse->fillAgg && pExpr->iAgg>=0 ){ + sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg); }else if( pExpr->iColumn>=0 ){ - Table *pTab = pExpr->pTab; - int iCol = pExpr->iColumn; - sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, iCol); - sqlite3ColumnDefault(v, pTab, iCol); -#ifndef SQLITE_OMIT_FLOATING_POINT - if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){ - sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0); + sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn); +#ifndef NDEBUG + if( pExpr->span.z && pExpr->span.n>0 && pExpr->span.n<100 ){ + VdbeComment((v, "# %T", &pExpr->span)); } #endif }else{ - sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0); + sqlite3VdbeAddOp(v, OP_Recno, pExpr->iTable, 0); } break; } case TK_INTEGER: { - codeInteger(v, (char*)pExpr->token.z, pExpr->token.n); + codeInteger(v, pExpr->token.z, pExpr->token.n); break; } case TK_FLOAT: case TK_STRING: { assert( TK_FLOAT==OP_Real ); assert( TK_STRING==OP_String8 ); - sqlite3DequoteExpr(pExpr); - sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n); - break; - } - case TK_NULL: { - sqlite3VdbeAddOp(v, OP_Null, 0, 0); + sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n); + sqlite3VdbeDequoteP3(v, -1); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { - int n; - const char *z; assert( TK_BLOB==OP_HexBlob ); - n = pExpr->token.n - 3; - z = (char*)pExpr->token.z + 2; - assert( n>=0 ); - if( n==0 ){ - z = ""; - } - sqlite3VdbeOp3(v, op, 0, 0, z, n); + sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z+1, pExpr->token.n-1); + sqlite3VdbeDequoteP3(v, -1); break; } #endif + case TK_NULL: { + sqlite3VdbeAddOp(v, OP_String8, 0, 0); + break; + } case TK_VARIABLE: { sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0); if( pExpr->token.n>1 ){ - sqlite3VdbeChangeP3(v, -1, (char*)pExpr->token.z, pExpr->token.n); + sqlite3VdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n); } break; } case TK_REGISTER: { sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iTable, 0); break; } -#ifndef SQLITE_OMIT_CAST - case TK_CAST: { - /* Expressions of the form: CAST(pLeft AS token) */ - int aff, op; - sqlite3ExprCode(pParse, pExpr->pLeft); - aff = sqlite3AffinityType(&pExpr->token); - op = aff - SQLITE_AFF_TEXT + OP_ToText; - assert( op==OP_ToText || aff!=SQLITE_AFF_TEXT ); - assert( op==OP_ToBlob || aff!=SQLITE_AFF_NONE ); - assert( op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); - assert( op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); - assert( op==OP_ToReal || aff!=SQLITE_AFF_REAL ); - sqlite3VdbeAddOp(v, op, 0, 0); - stackChng = 0; - break; - } -#endif /* SQLITE_OMIT_CAST */ case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: @@ -1578,11 +1443,10 @@ assert( TK_EQ==OP_Eq ); assert( TK_NE==OP_Ne ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0); - stackChng = -1; break; } case TK_AND: case TK_OR: case TK_PLUS: @@ -1607,19 +1471,19 @@ assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_CONCAT==OP_Concat ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); sqlite3VdbeAddOp(v, op, 0, 0); - stackChng = -1; break; } case TK_UMINUS: { Expr *pLeft = pExpr->pLeft; assert( pLeft ); if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){ Token *p = &pLeft->token; - char *z = sqlite3MPrintf("-%.*s", p->n, p->z); + char *z = sqliteMalloc( p->n + 2 ); + sprintf(z, "-%.*s", p->n, p->z); if( pLeft->op==TK_FLOAT ){ sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1); }else{ codeInteger(v, z, p->n+1); } @@ -1632,11 +1496,10 @@ case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); assert( TK_NOT==OP_Not ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3VdbeAddOp(v, op, 0, 0); - stackChng = 0; break; } case TK_ISNULL: case TK_NOTNULL: { int dest; @@ -1645,53 +1508,48 @@ sqlite3VdbeAddOp(v, OP_Integer, 1, 0); sqlite3ExprCode(pParse, pExpr->pLeft); dest = sqlite3VdbeCurrentAddr(v) + 2; sqlite3VdbeAddOp(v, op, 1, dest); sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); - stackChng = 0; break; } case TK_AGG_FUNCTION: { - AggInfo *pInfo = pExpr->pAggInfo; - if( pInfo==0 ){ - sqlite3ErrorMsg(pParse, "misuse of aggregate: %T", - &pExpr->span); - }else{ - sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0); - } + sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); break; } - case TK_CONST_FUNC: + case TK_CDATE: + case TK_CTIME: + case TK_CTIMESTAMP: + case TK_GLOB: + case TK_LIKE: case TK_FUNCTION: { ExprList *pList = pExpr->pList; int nExpr = pList ? pList->nExpr : 0; FuncDef *pDef; int nId; const char *zId; - int constMask = 0; + int p2 = 0; int i; - u8 enc = ENC(pParse->db); + u8 enc = pParse->db->enc; CollSeq *pColl = 0; - zId = (char*)pExpr->token.z; - nId = pExpr->token.n; + getFunctionName(pExpr, &zId, &nId); pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0); assert( pDef!=0 ); nExpr = sqlite3ExprCodeExprList(pParse, pList); for(i=0; ia[i].pExpr) ){ - constMask |= (1<needCollSeq && !pColl ){ pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); } } if( pDef->needCollSeq ){ if( !pColl ) pColl = pParse->db->pDfltColl; sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); } - sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF); - stackChng = 1-nExpr; + sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { @@ -1718,11 +1576,11 @@ */ sqlite3ExprCode(pParse, pExpr->pLeft); addr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+4); /* addr + 0 */ sqlite3VdbeAddOp(v, OP_Pop, 2, 0); - sqlite3VdbeAddOp(v, OP_Null, 0, 0); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, addr+7); sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); /* addr + 4 */ sqlite3VdbeAddOp(v, OP_Found, pExpr->iTable, addr+7); sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); /* addr + 6 */ @@ -1746,16 +1604,16 @@ break; } case TK_UPLUS: case TK_AS: { sqlite3ExprCode(pParse, pExpr->pLeft); - stackChng = 0; break; } case TK_CASE: { int expr_end_label; int jumpInst; + int addr; int nExpr; int i; ExprList *pEList; struct ExprList_item *aListelem; @@ -1779,19 +1637,20 @@ }else{ jumpInst = sqlite3VdbeAddOp(v, OP_IfNot, 1, 0); } sqlite3ExprCode(pParse, aListelem[i+1].pExpr); sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label); - sqlite3VdbeJumpHere(v, jumpInst); + addr = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeChangeP2(v, jumpInst, addr); } if( pExpr->pLeft ){ sqlite3VdbeAddOp(v, OP_Pop, 1, 0); } if( pExpr->pRight ){ sqlite3ExprCode(pParse, pExpr->pRight); }else{ - sqlite3VdbeAddOp(v, OP_Null, 0, 0); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); } sqlite3VdbeResolveLabel(v, expr_end_label); break; } #ifndef SQLITE_OMIT_TRIGGER @@ -1803,28 +1662,22 @@ } if( pExpr->iColumn!=OE_Ignore ){ assert( pExpr->iColumn==OE_Rollback || pExpr->iColumn == OE_Abort || pExpr->iColumn == OE_Fail ); - sqlite3DequoteExpr(pExpr); sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, - (char*)pExpr->token.z, pExpr->token.n); + pExpr->token.z, pExpr->token.n); + sqlite3VdbeDequoteP3(v, -1); } else { assert( pExpr->iColumn == OE_Ignore ); sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump); VdbeComment((v, "# raise(IGNORE)")); } - stackChng = 0; - break; } #endif - } - - if( pParse->ckOffset ){ - pParse->ckOffset += stackChng; - assert( pParse->ckOffset ); + break; } } #ifndef SQLITE_OMIT_TRIGGER /* @@ -1863,13 +1716,15 @@ Parse *pParse, /* Parsing context */ ExprList *pList /* The expression list to be coded */ ){ struct ExprList_item *pItem; int i, n; + Vdbe *v; if( pList==0 ) return 0; + v = sqlite3GetVdbe(pParse); n = pList->nExpr; - for(pItem=pList->a, i=n; i>0; i--, pItem++){ + for(pItem=pList->a, i=0; ipExpr); } return n; } @@ -1888,11 +1743,10 @@ ** below verify that the numbers are aligned correctly. */ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; - int ckOffset = pParse->ckOffset; if( v==0 || pExpr==0 ) return; op = pExpr->op; switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); @@ -1953,21 +1807,20 @@ pRight = pExpr->pList->a[1].pExpr; sqlite3ExprCode(pParse, pRight); codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull); sqlite3VdbeAddOp(v, OP_Integer, 0, 0); - sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); break; } default: { sqlite3ExprCode(pParse, pExpr); sqlite3VdbeAddOp(v, OP_If, jumpIfNull, dest); break; } } - pParse->ckOffset = ckOffset; } /* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is false but execution @@ -1977,11 +1830,10 @@ ** jump if jumpIfNull is true or fall through if jumpIfNull is false. */ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; - int ckOffset = pParse->ckOffset; if( v==0 || pExpr==0 ) return; /* The value of pExpr->op and op are related as follows: ** ** pExpr->op op @@ -2074,11 +1926,10 @@ sqlite3ExprCode(pParse, pExpr); sqlite3VdbeAddOp(v, OP_IfNot, jumpIfNull, dest); break; } } - pParse->ckOffset = ckOffset; } /* ** Do a deep comparison of two expression trees. Return TRUE (non-zero) ** if they are identical and return FALSE if they differ in any way. @@ -2089,11 +1940,10 @@ return pB==0; }else if( pB==0 ){ return 0; } if( pA->op!=pB->op ) return 0; - if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0; if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0; if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0; if( pA->pList ){ if( pB->pList==0 ) return 0; if( pA->pList->nExpr!=pB->pList->nExpr ) return 0; @@ -2108,43 +1958,32 @@ if( pA->pSelect || pB->pSelect ) return 0; if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0; if( pA->token.z ){ if( pB->token.z==0 ) return 0; if( pB->token.n!=pA->token.n ) return 0; - if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){ - return 0; - } + if( sqlite3StrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0; } return 1; } - -/* -** Add a new element to the pAggInfo->aCol[] array. Return the index of -** the new element. Return a negative number if malloc fails. -*/ -static int addAggInfoColumn(AggInfo *pInfo){ - int i; - i = sqlite3ArrayAllocate((void**)&pInfo->aCol, sizeof(pInfo->aCol[0]), 3); - if( i<0 ){ - return -1; - } - return i; -} - -/* -** Add a new element to the pAggInfo->aFunc[] array. Return the index of -** the new element. Return a negative number if malloc fails. -*/ -static int addAggInfoFunc(AggInfo *pInfo){ - int i; - i = sqlite3ArrayAllocate((void**)&pInfo->aFunc, sizeof(pInfo->aFunc[0]), 2); - if( i<0 ){ - return -1; - } - return i; -} +/* +** Add a new element to the pParse->aAgg[] array and return its index. +** The new element is initialized to zero. The calling function is +** expected to fill it in. +*/ +static int appendAggInfo(Parse *pParse){ + if( (pParse->nAgg & 0x7)==0 ){ + int amt = pParse->nAgg + 8; + AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0])); + if( aAgg==0 ){ + return -1; + } + pParse->aAgg = aAgg; + } + memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0])); + return pParse->nAgg++; +} /* ** This is an xFunc for walkExprTree() used to implement ** sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates ** for additional information. @@ -2151,122 +1990,64 @@ ** ** This routine analyzes the aggregate function at pExpr. */ static int analyzeAggregate(void *pArg, Expr *pExpr){ int i; + AggExpr *aAgg; NameContext *pNC = (NameContext *)pArg; Parse *pParse = pNC->pParse; SrcList *pSrcList = pNC->pSrcList; - AggInfo *pAggInfo = pNC->pAggInfo; - switch( pExpr->op ){ case TK_COLUMN: { - /* Check to see if the column is in one of the tables in the FROM - ** clause of the aggregate query */ - if( pSrcList ){ - struct SrcList_item *pItem = pSrcList->a; - for(i=0; inSrc; i++, pItem++){ - struct AggInfo_col *pCol; - if( pExpr->iTable==pItem->iCursor ){ - /* If we reach this point, it means that pExpr refers to a table - ** that is in the FROM clause of the aggregate query. - ** - ** Make an entry for the column in pAggInfo->aCol[] if there - ** is not an entry there already. - */ - pCol = pAggInfo->aCol; - for(i=0; inColumn; i++, pCol++){ - if( pCol->iTable==pExpr->iTable && - pCol->iColumn==pExpr->iColumn ){ - break; - } - } - if( i>=pAggInfo->nColumn && (i = addAggInfoColumn(pAggInfo))>=0 ){ - pCol = &pAggInfo->aCol[i]; - pCol->iTable = pExpr->iTable; - pCol->iColumn = pExpr->iColumn; - pCol->iMem = pParse->nMem++; - pCol->iSorterColumn = -1; - pCol->pExpr = pExpr; - if( pAggInfo->pGroupBy ){ - int j, n; - ExprList *pGB = pAggInfo->pGroupBy; - struct ExprList_item *pTerm = pGB->a; - n = pGB->nExpr; - for(j=0; jpExpr; - if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable && - pE->iColumn==pExpr->iColumn ){ - pCol->iSorterColumn = j; - break; - } - } - } - if( pCol->iSorterColumn<0 ){ - pCol->iSorterColumn = pAggInfo->nSortingColumn++; - } - } - /* There is now an entry for pExpr in pAggInfo->aCol[] (either - ** because it was there before or because we just created it). - ** Convert the pExpr to be a TK_AGG_COLUMN referring to that - ** pAggInfo->aCol[] entry. - */ - pExpr->pAggInfo = pAggInfo; - pExpr->op = TK_AGG_COLUMN; - pExpr->iAgg = i; - break; - } /* endif pExpr->iTable==pItem->iCursor */ - } /* end loop over pSrcList */ + for(i=0; pSrcList && inSrc; i++){ + if( pExpr->iTable==pSrcList->a[i].iCursor ){ + aAgg = pParse->aAgg; + for(i=0; inAgg; i++){ + if( aAgg[i].isAgg ) continue; + if( aAgg[i].pExpr->iTable==pExpr->iTable + && aAgg[i].pExpr->iColumn==pExpr->iColumn ){ + break; + } + } + if( i>=pParse->nAgg ){ + i = appendAggInfo(pParse); + if( i<0 ) return 1; + pParse->aAgg[i].isAgg = 0; + pParse->aAgg[i].pExpr = pExpr; + } + pExpr->iAgg = i; + pExpr->iAggCtx = pNC->nDepth; + return 1; + } } return 1; } case TK_AGG_FUNCTION: { - /* The pNC->nDepth==0 test causes aggregate functions in subqueries - ** to be ignored */ if( pNC->nDepth==0 ){ - /* Check to see if pExpr is a duplicate of another aggregate - ** function that is already in the pAggInfo structure - */ - struct AggInfo_func *pItem = pAggInfo->aFunc; - for(i=0; inFunc; i++, pItem++){ - if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){ + aAgg = pParse->aAgg; + for(i=0; inAgg; i++){ + if( !aAgg[i].isAgg ) continue; + if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){ break; } } - if( i>=pAggInfo->nFunc ){ - /* pExpr is original. Make a new entry in pAggInfo->aFunc[] - */ - u8 enc = ENC(pParse->db); - i = addAggInfoFunc(pAggInfo); - if( i>=0 ){ - pItem = &pAggInfo->aFunc[i]; - pItem->pExpr = pExpr; - pItem->iMem = pParse->nMem++; - pItem->pFunc = sqlite3FindFunction(pParse->db, - (char*)pExpr->token.z, pExpr->token.n, - pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); - if( pExpr->flags & EP_Distinct ){ - pItem->iDistinct = pParse->nTab++; - }else{ - pItem->iDistinct = -1; - } - } - } - /* Make pExpr point to the appropriate pAggInfo->aFunc[] entry - */ - pExpr->iAgg = i; - pExpr->pAggInfo = pAggInfo; + if( i>=pParse->nAgg ){ + u8 enc = pParse->db->enc; + i = appendAggInfo(pParse); + if( i<0 ) return 1; + pParse->aAgg[i].isAgg = 1; + pParse->aAgg[i].pExpr = pExpr; + pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db, + pExpr->token.z, pExpr->token.n, + pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); + } + pExpr->iAgg = i; return 1; } } } - - /* Recursively walk subqueries looking for TK_COLUMN nodes that need - ** to be changed to TK_AGG_COLUMN. But increment nDepth so that - ** TK_AGG_FUNCTION nodes in subqueries will be unchanged. - */ if( pExpr->pSelect ){ pNC->nDepth++; walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC); pNC->nDepth--; } @@ -2289,21 +2070,104 @@ walkExprTree(pExpr, analyzeAggregate, pNC); return pNC->pParse->nErr - nErr; } /* -** Call sqlite3ExprAnalyzeAggregates() for every expression in an -** expression list. Return the number of errors. -** -** If an error is found, the analysis is cut short. -*/ -int sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){ - struct ExprList_item *pItem; - int i; - int nErr = 0; - if( pList ){ - for(pItem=pList->a, i=0; nErr==0 && inExpr; i++, pItem++){ - nErr += sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr); - } - } - return nErr; +** Locate a user function given a name, a number of arguments and a flag +** indicating whether the function prefers UTF-16 over UTF-8. Return a +** pointer to the FuncDef structure that defines that function, or return +** NULL if the function does not exist. +** +** If the createFlag argument is true, then a new (blank) FuncDef +** structure is created and liked into the "db" structure if a +** no matching function previously existed. When createFlag is true +** and the nArg parameter is -1, then only a function that accepts +** any number of arguments will be returned. +** +** If createFlag is false and nArg is -1, then the first valid +** function found is returned. A function is valid if either xFunc +** or xStep is non-zero. +** +** If createFlag is false, then a function with the required name and +** number of arguments may be returned even if the eTextRep flag does not +** match that requested. +*/ +FuncDef *sqlite3FindFunction( + sqlite3 *db, /* An open database */ + const char *zName, /* Name of the function. Not null-terminated */ + int nName, /* Number of characters in the name */ + int nArg, /* Number of arguments. -1 means any number */ + u8 enc, /* Preferred text encoding */ + int createFlag /* Create new entry if true and does not otherwise exist */ +){ + FuncDef *p; /* Iterator variable */ + FuncDef *pFirst; /* First function with this name */ + FuncDef *pBest = 0; /* Best match found so far */ + int bestmatch = 0; + + + assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); + if( nArg<-1 ) nArg = -1; + + pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName); + for(p=pFirst; p; p=p->pNext){ + /* During the search for the best function definition, bestmatch is set + ** as follows to indicate the quality of the match with the definition + ** pointed to by pBest: + ** + ** 0: pBest is NULL. No match has been found. + ** 1: A variable arguments function that prefers UTF-8 when a UTF-16 + ** encoding is requested, or vice versa. + ** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is + ** requested, or vice versa. + ** 3: A variable arguments function using the same text encoding. + ** 4: A function with the exact number of arguments requested that + ** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa. + ** 5: A function with the exact number of arguments requested that + ** prefers UTF-16LE when UTF-16BE is requested, or vice versa. + ** 6: An exact match. + ** + ** A larger value of 'matchqual' indicates a more desirable match. + */ + if( p->nArg==-1 || p->nArg==nArg || nArg==-1 ){ + int match = 1; /* Quality of this match */ + if( p->nArg==nArg || nArg==-1 ){ + match = 4; + } + if( enc==p->iPrefEnc ){ + match += 2; + } + else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) || + (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){ + match += 1; + } + + if( match>bestmatch ){ + pBest = p; + bestmatch = match; + } + } + } + + /* If the createFlag parameter is true, and the seach did not reveal an + ** exact match for the name, number of arguments and encoding, then add a + ** new entry to the hash table and return it. + */ + if( createFlag && bestmatch<6 && + (pBest = sqliteMalloc(sizeof(*pBest)+nName+1)) ){ + pBest->nArg = nArg; + pBest->pNext = pFirst; + pBest->zName = (char*)&pBest[1]; + pBest->iPrefEnc = enc; + memcpy(pBest->zName, zName, nName); + pBest->zName[nName] = 0; + if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){ + sqliteFree(pBest); + return 0; + } + } + + if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){ + return pBest; + } + return 0; } Index: SQLite.Interop/src/func.c ================================================================== --- SQLite.Interop/src/func.c +++ SQLite.Interop/src/func.c @@ -14,23 +14,20 @@ ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.17 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: func.c,v 1.1 2005/03/01 16:04:29 rmsimpson Exp $ */ #include "sqliteInt.h" #include -/* #include */ +#include #include #include #include "vdbeInt.h" #include "os.h" -/* -** Return the collating function associated with a function. -*/ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ return context->pColl; } /* @@ -79,11 +76,10 @@ case SQLITE_BLOB: z = "blob"; break; } sqlite3_result_text(context, z, -1, SQLITE_STATIC); } - /* ** Implementation of the length() function */ static void lengthFunc( sqlite3_context *context, @@ -99,11 +95,11 @@ case SQLITE_FLOAT: { sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); break; } case SQLITE_TEXT: { - const unsigned char *z = sqlite3_value_text(argv[0]); + const char *z = sqlite3_value_text(argv[0]); for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; } sqlite3_result_int(context, len); break; } default: { @@ -144,12 +140,12 @@ static void substrFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ - const unsigned char *z; - const unsigned char *z2; + const char *z; + const char *z2; int i; int p1, p2, len; assert( argc==3 ); z = sqlite3_value_text(argv[0]); @@ -176,30 +172,30 @@ for(; i30 ) n = 30; if( n<0 ) n = 0; } if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; r = sqlite3_value_double(argv[0]); - sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r); + sprintf(zBuf,"%.*f",n,r); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } /* ** Implementation of the upper() and lower() SQL functions. @@ -208,28 +204,28 @@ unsigned char *z; int i; if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1); if( z==0 ) return; - strcpy((char*)z, (char*)sqlite3_value_text(argv[0])); + strcpy(z, sqlite3_value_text(argv[0])); for(i=0; z[i]; i++){ z[i] = toupper(z[i]); } - sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT); + sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); sqliteFree(z); } static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ unsigned char *z; int i; if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1); if( z==0 ) return; - strcpy((char*)z, (char*)sqlite3_value_text(argv[0])); + strcpy(z, sqlite3_value_text(argv[0])); for(i=0; z[i]; i++){ z[i] = tolower(z[i]); } - sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT); + sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); sqliteFree(z); } /* ** Implementation of the IFNULL(), NVL(), and COALESCE() functions. @@ -309,18 +305,12 @@ u8 matchAll; u8 matchOne; u8 matchSet; u8 noCase; }; - static const struct compareInfo globInfo = { '*', '?', '[', 0 }; -/* The correct SQL-92 behavior is for the LIKE operator to ignore -** case. Thus 'a' LIKE 'A' would be true. */ -static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 }; -/* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator -** is case sensitive causing 'a' LIKE 'A' to be false */ -static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; +static const struct compareInfo likeInfo = { '%', '_', 0, 1 }; /* ** X is a pointer to the first byte of a UTF-8 character. Increment ** X so that it points to the next character. This only works right ** if X points to a well-formed UTF-8 string. @@ -458,19 +448,10 @@ } } return *zString==0; } -/* -** Count the number of times that the LIKE operator (or GLOB which is -** just a variation of LIKE) gets called. This is used for testing -** only. -*/ -#ifdef SQLITE_TEST -int sqlite3_like_count = 0; -#endif - /* ** Implementation of the like() SQL function. This function implements ** the build-in LIKE operator. The first argument to the function is the ** pattern and the second argument is the string. So, the SQL statements: @@ -477,12 +458,12 @@ ** ** A LIKE B ** ** is implemented as like(B,A). ** -** This same function (with a different compareInfo structure) computes -** the GLOB operator. +** If the pointer retrieved by via a call to sqlite3_user_data() is +** not NULL, then this function uses UTF-16. Otherwise UTF-8. */ static void likeFunc( sqlite3_context *context, int argc, sqlite3_value **argv @@ -493,23 +474,36 @@ if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. */ const unsigned char *zEsc = sqlite3_value_text(argv[2]); - if( sqlite3utf8CharLen((char*)zEsc, -1)!=1 ){ + if( sqlite3utf8CharLen(zEsc, -1)!=1 ){ sqlite3_result_error(context, "ESCAPE expression must be a single character", -1); return; } escape = sqlite3ReadUtf8(zEsc); } if( zA && zB ){ - struct compareInfo *pInfo = sqlite3_user_data(context); -#ifdef SQLITE_TEST - sqlite3_like_count++; -#endif - sqlite3_result_int(context, patternCompare(zA, zB, pInfo, escape)); + sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo, escape)); + } +} + +/* +** Implementation of the glob() SQL function. This function implements +** the build-in GLOB operator. The first argument to the function is the +** string and the second argument is the pattern. So, the SQL statements: +** +** A GLOB B +** +** is implemented as glob(B,A). +*/ +static void globFunc(sqlite3_context *context, int arg, sqlite3_value **argv){ + const unsigned char *zA = sqlite3_value_text(argv[0]); + const unsigned char *zB = sqlite3_value_text(argv[1]); + if( zA && zB ){ + sqlite3_result_int(context, patternCompare(zA, zB, &globInfo, 0)); } } /* ** Implementation of the NULLIF(x,y) function. The result is the first @@ -590,11 +584,11 @@ } break; } case SQLITE_TEXT: { int i,j,n; - const unsigned char *zArg = sqlite3_value_text(argv[0]); + const char *zArg = sqlite3_value_text(argv[0]); char *z; for(i=n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; } z = sqliteMalloc( i+n+3 ); if( z==0 ) return; @@ -690,11 +684,11 @@ sqlite3Randomness(n, zBuf); for(i=0; ienc); zVal = sqliteMalloc(len+3); zVal[len] = 0; zVal[len-1] = 0; assert( zVal ); zVal++; - memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len); - if( ENC(db)==SQLITE_UTF8 ){ + memcpy(zVal, sqlite3ValueText(argv[0], db->enc), len); + if( db->enc==SQLITE_UTF8 ){ sqlite3_result_text(pCtx, zVal, -1, destructor); #ifndef SQLITE_OMIT_UTF16 - }else if( ENC(db)==SQLITE_UTF16LE ){ + }else if( db->enc==SQLITE_UTF16LE ){ sqlite3_result_text16le(pCtx, zVal, -1, destructor); }else{ sqlite3_result_text16be(pCtx, zVal, -1, destructor); #endif /* SQLITE_OMIT_UTF16 */ } @@ -774,11 +768,11 @@ ){ int i; char *zRet = sqliteMalloc(nArg*2); if( !zRet ) return; for(i=0; isum += sqlite3_value_double(argv[0]); p->cnt++; - if( type==SQLITE_FLOAT ){ - p->seenFloat = 1; - } } } static void sumFinalize(sqlite3_context *context){ SumCtx *p; - p = sqlite3_aggregate_context(context, 0); - if( p && p->cnt>0 ){ - if( p->seenFloat ){ - sqlite3_result_double(context, p->sum); - }else{ - sqlite3_result_int64(context, (i64)p->sum); - } - } + p = sqlite3_aggregate_context(context, sizeof(*p)); + sqlite3_result_double(context, p ? p->sum : 0.0); } static void avgFinalize(sqlite3_context *context){ SumCtx *p; - p = sqlite3_aggregate_context(context, 0); + p = sqlite3_aggregate_context(context, sizeof(*p)); if( p && p->cnt>0 ){ sqlite3_result_double(context, p->sum/(double)p->cnt); } } -static void totalFinalize(sqlite3_context *context){ - SumCtx *p; - p = sqlite3_aggregate_context(context, 0); - sqlite3_result_double(context, p ? p->sum : 0.0); -} /* ** An instance of the following structure holds the context of a ** variance or standard deviation computation. */ @@ -899,13 +870,23 @@ p->n++; } } static void countFinalize(sqlite3_context *context){ CountCtx *p; - p = sqlite3_aggregate_context(context, 0); + p = sqlite3_aggregate_context(context, sizeof(*p)); sqlite3_result_int(context, p ? p->n : 0); } + +/* +** This function tracks state information for the min() and max() +** aggregate functions. +*/ +typedef struct MinMaxCtx MinMaxCtx; +struct MinMaxCtx { + char *z; /* The best so far */ + char zBuf[28]; /* Space that can be used for storage */ +}; /* ** Routines to implement min() and max() aggregate functions. */ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv){ @@ -937,17 +918,15 @@ sqlite3VdbeMemCopy(pBest, pArg); } } static void minMaxFinalize(sqlite3_context *context){ sqlite3_value *pRes; - pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0); - if( pRes ){ - if( pRes->flags ){ - sqlite3_result_value(context, pRes); - } - sqlite3VdbeMemRelease(pRes); + pRes = (sqlite3_value *)sqlite3_aggregate_context(context, sizeof(Mem)); + if( pRes->flags ){ + sqlite3_result_value(context, pRes); } + sqlite3VdbeMemRelease(pRes); } /* ** This function registered all of the above C functions as SQL @@ -981,10 +960,13 @@ { "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc }, { "coalesce", 0, 0, SQLITE_UTF8, 0, 0 }, { "coalesce", 1, 0, SQLITE_UTF8, 0, 0 }, { "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc }, { "random", -1, 0, SQLITE_UTF8, 0, randomFunc }, + { "like", 2, 0, SQLITE_UTF8, 0, likeFunc }, + { "like", 3, 0, SQLITE_UTF8, 0, likeFunc }, + { "glob", 2, 0, SQLITE_UTF8, 0, globFunc }, { "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc }, { "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc}, { "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc }, { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid }, { "changes", 0, 1, SQLITE_UTF8, 0, changes }, @@ -1009,11 +991,10 @@ void (*xFinalize)(sqlite3_context*); } aAggs[] = { { "min", 1, 0, 1, minmaxStep, minMaxFinalize }, { "max", 1, 2, 1, minmaxStep, minMaxFinalize }, { "sum", 1, 0, 0, sumStep, sumFinalize }, - { "total", 1, 0, 0, sumStep, totalFinalize }, { "avg", 1, 0, 0, sumStep, avgFinalize }, { "count", 0, 0, 0, countStep, countFinalize }, { "count", 1, 0, 0, countStep, countFinalize }, }; int i; @@ -1035,13 +1016,10 @@ } } #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(db); #endif -#ifndef SQLITE_OMIT_PARSER - sqlite3AttachFunctions(db); -#endif for(i=0; ineedCollSeq = 1; } } } sqlite3RegisterDateTimeFunctions(db); -#ifdef SQLITE_SSE - sqlite3SseFunctions(db); -#endif -#ifdef SQLITE_CASE_SENSITIVE_LIKE - sqlite3RegisterLikeFunctions(db, 1); -#else - sqlite3RegisterLikeFunctions(db, 0); -#endif -} - -/* -** Set the LIKEOPT flag on the 2-argument function with the given name. -*/ -static void setLikeOptFlag(sqlite3 *db, const char *zName, int flagVal){ - FuncDef *pDef; - pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0); - if( pDef ){ - pDef->flags = flagVal; - } -} - -/* -** Register the built-in LIKE and GLOB functions. The caseSensitive -** parameter determines whether or not the LIKE operator is case -** sensitive. GLOB is always case sensitive. -*/ -void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ - struct compareInfo *pInfo; - if( caseSensitive ){ - pInfo = (struct compareInfo*)&likeInfoAlt; - }else{ - pInfo = (struct compareInfo*)&likeInfoNorm; - } - sqlite3_create_function(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0); - sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0); - sqlite3_create_function(db, "glob", 2, SQLITE_UTF8, - (struct compareInfo*)&globInfo, likeFunc, 0,0); - setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); - setLikeOptFlag(db, "like", - caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); -} - -/* -** pExpr points to an expression which implements a function. If -** it is appropriate to apply the LIKE optimization to that function -** then set aWc[0] through aWc[2] to the wildcard characters and -** return TRUE. If the function is not a LIKE-style function then -** return FALSE. -*/ -int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ - FuncDef *pDef; - if( pExpr->op!=TK_FUNCTION ){ - return 0; - } - if( pExpr->pList->nExpr!=2 ){ - return 0; - } - pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2, - SQLITE_UTF8, 0); - if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){ - return 0; - } - - /* The memcpy() statement assumes that the wildcard characters are - ** the first three statements in the compareInfo structure. The - ** asserts() that follow verify that assumption - */ - memcpy(aWc, pDef->pUserData, 3); - assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll ); - assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne ); - assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet ); - *pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0; - return 1; } Index: SQLite.Interop/src/hash.c ================================================================== --- SQLite.Interop/src/hash.c +++ SQLite.Interop/src/hash.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This is the implementation of generic hash-tables ** used in SQLite. ** -** $Id: hash.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: hash.c,v 1.1 2005/03/01 16:04:29 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* Turn bulk memory into a hash table object by initializing the @@ -292,15 +292,10 @@ if( pH->copyKey && elem->pKey ){ sqliteFree(elem->pKey); } sqliteFree( elem ); pH->count--; - if( pH->count<=0 ){ - assert( pH->first==0 ); - assert( pH->count==0 ); - sqlite3HashClear(pH); - } } /* Attempt to locate an element of the hash table pH with a key ** that matches pKey,nKey. Return the data for this element if it is ** found, or NULL if there is no match. Index: SQLite.Interop/src/hash.h ================================================================== --- SQLite.Interop/src/hash.h +++ SQLite.Interop/src/hash.h @@ -10,11 +10,11 @@ ** ************************************************************************* ** This is the header file for the generic hash-table implemenation ** used in SQLite. ** -** $Id: hash.h,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: hash.h,v 1.1 2005/03/01 16:04:29 rmsimpson Exp $ */ #ifndef _SQLITE_HASH_H_ #define _SQLITE_HASH_H_ /* Forward declarations of structures. */ Index: SQLite.Interop/src/insert.c ================================================================== --- SQLite.Interop/src/insert.c +++ SQLite.Interop/src/insert.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: insert.c,v 1.1 2005/03/01 16:04:30 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** Set P3 of the most recently inserted opcode to a column affinity @@ -21,15 +21,14 @@ ** string for index pIdx. A column affinity string has one character ** for each column in the table, according to the affinity of the column: ** ** Character Column affinity ** ------------------------------ -** 'a' TEXT -** 'b' NONE -** 'c' NUMERIC -** 'd' INTEGER -** 'e' REAL +** 'n' NUMERIC +** 'i' INTEGER +** 't' TEXT +** 'o' NONE */ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ if( !pIdx->zColAff ){ /* The first time a column affinity string for a particular index is ** required, it is allocated and populated here. It is then stored as @@ -60,15 +59,14 @@ ** for each column indexed by the index, according to the affinity of the ** column: ** ** Character Column affinity ** ------------------------------ -** 'a' TEXT -** 'b' NONE -** 'c' NUMERIC -** 'd' INTEGER -** 'e' REAL +** 'n' NUMERIC +** 'i' INTEGER +** 't' TEXT +** 'o' NONE */ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){ /* The first time a column affinity string for a particular table ** is required, it is allocated and populated here. It is then ** stored as a member of the Table structure for subsequent use. @@ -102,19 +100,19 @@ ** "INSERT INTO SELECT ..." can run without using temporary ** table for the results of the SELECT. ** ** No checking is done for sub-selects that are part of expressions. */ -static int selectReadsTable(Select *p, Schema *pSchema, int iTab){ +static int selectReadsTable(Select *p, int iDb, int iTab){ int i; struct SrcList_item *pItem; if( p->pSrc==0 ) return 0; for(i=0, pItem=p->pSrc->a; ipSrc->nSrc; i++, pItem++){ if( pItem->pSelect ){ - if( selectReadsTable(pItem->pSelect, pSchema, iTab) ) return 1; + if( selectReadsTable(p, iDb, iTab) ) return 1; }else{ - if( pItem->pTab->pSchema==pSchema && pItem->pTab->tnum==iTab ) return 1; + if( pItem->pTab->iDb==iDb && pItem->pTab->tnum==iTab ) return 1; } } return 0; } @@ -212,11 +210,10 @@ int iInsertBlock = 0; /* Address of the subroutine used to insert data */ int iCntMem = 0; /* Memory cell used for the row counter */ int newIdx = -1; /* Cursor for the NEW table */ Db *pDb; /* The database containing table being inserted into */ int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */ - int iDb; #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ #endif @@ -223,13 +220,11 @@ #ifndef SQLITE_OMIT_AUTOINCREMENT int counterRowid; /* Memory cell holding rowid of autoinc counter */ #endif - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ - goto insert_cleanup; - } + if( pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup; db = pParse->db; /* Locate the table into which we will be inserting new information. */ assert( pTabList->nSrc==1 ); @@ -237,13 +232,12 @@ if( zTab==0 ) goto insert_cleanup; pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ){ goto insert_cleanup; } - iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - assert( iDbnDb ); - pDb = &db->aDb[iDb]; + assert( pTab->iDbnDb ); + pDb = &db->aDb[pTab->iDb]; zDb = pDb->zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ goto insert_cleanup; } @@ -274,17 +268,24 @@ /* If pTab is really a view, make sure it has been initialized. */ if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){ goto insert_cleanup; } + + /* Ensure all required collation sequences are available. */ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){ + goto insert_cleanup; + } + } /* Allocate a VDBE */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto insert_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); - sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, iDb); + sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, pTab->iDb); /* if there are row triggers, allocate a temp table for new.* references. */ if( triggers_exist ){ newIdx = pParse->nTab++; } @@ -298,16 +299,18 @@ if( pTab->autoInc ){ int iCur = pParse->nTab; int base = sqlite3VdbeCurrentAddr(v); counterRowid = pParse->nMem++; counterMem = pParse->nMem++; - sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); + sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pDb->pSeqTab->tnum); + sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2); sqlite3VdbeAddOp(v, OP_Rewind, iCur, base+13); sqlite3VdbeAddOp(v, OP_Column, iCur, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); - sqlite3VdbeAddOp(v, OP_Ne, 0x100, base+12); - sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); + sqlite3VdbeAddOp(v, OP_Ne, 28417, base+12); + sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_MemStore, counterRowid, 1); sqlite3VdbeAddOp(v, OP_Column, iCur, 1); sqlite3VdbeAddOp(v, OP_MemStore, counterMem, 1); sqlite3VdbeAddOp(v, OP_Goto, 0, base+13); sqlite3VdbeAddOp(v, OP_Next, iCur, base+4); @@ -331,13 +334,11 @@ iSelectLoop = sqlite3VdbeCurrentAddr(v); iInsertBlock = sqlite3VdbeMakeLabel(v); /* Resolve the expressions in the SELECT statement and execute it. */ rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0); - if( rc || pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ - goto insert_cleanup; - } + if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup; iCleanup = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup); assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; @@ -348,11 +349,11 @@ ** ** A temp table must be used if the table being updated is also one ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ - if( triggers_exist || selectReadsTable(pSelect,pTab->pSchema,pTab->tnum) ){ + if( triggers_exist || selectReadsTable(pSelect, pTab->iDb, pTab->tnum) ){ useTempTable = 1; } if( useTempTable ){ /* Generate the subroutine that SELECT calls to process each row of @@ -359,26 +360,27 @@ ** the result. Store the result in a temporary table */ srcTab = pParse->nTab++; sqlite3VdbeResolveLabel(v, iInsertBlock); sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); - sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0); + sqlite3TableAffinityStr(v, pTab); + sqlite3VdbeAddOp(v, OP_NewRecno, srcTab, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); - sqlite3VdbeAddOp(v, OP_Insert, srcTab, 0); + sqlite3VdbeAddOp(v, OP_PutIntKey, srcTab, 0); sqlite3VdbeAddOp(v, OP_Return, 0, 0); /* The following code runs first because the GOTO at the very top ** of the program jumps to it. Create the temporary table, then jump ** back up and execute the SELECT code above. */ - sqlite3VdbeJumpHere(v, iInitCode); - sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0); + sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeAddOp(v, OP_OpenTemp, srcTab, 0); sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn); sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop); sqlite3VdbeResolveLabel(v, iCleanup); }else{ - sqlite3VdbeJumpHere(v, iInitCode); + sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v)); } }else{ /* This is the case if the data for the INSERT is coming from a VALUES ** clause */ @@ -466,11 +468,12 @@ /* Initialize the count of rows to be inserted */ if( db->flags & SQLITE_CountRows ){ iCntMem = pParse->nMem++; - sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem); + sqlite3VdbeAddOp(v, OP_Integer, 0, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iCntMem, 1); } /* Open tables and indices if there are no row triggers */ if( !triggers_exist ){ base = pParse->nTab; @@ -542,11 +545,11 @@ ** table column affinities. */ if( !isView ){ sqlite3TableAffinityStr(v, pTab); } - sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0); + sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0); /* Fire BEFORE or INSTEAD OF triggers */ if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab, newIdx, -1, onError, endOfLoop) ){ goto insert_cleanup; @@ -560,11 +563,11 @@ base = pParse->nTab; sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite); } /* Push the record number for the new entry onto the stack. The - ** record number is a randomly generate integer created by NewRowid + ** record number is a randomly generate integer created by NewRecno ** except when the table has an INTEGER PRIMARY KEY column, in which ** case the record number is the same as that column. */ if( !isView ){ if( keyColumn>=0 ){ @@ -573,19 +576,19 @@ }else if( pSelect ){ sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1); }else{ sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr); } - /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid + /* If the PRIMARY KEY expression is NULL, then use OP_NewRecno ** to generate a unique primary key value. */ sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem); + sqlite3VdbeAddOp(v, OP_NewRecno, base, counterMem); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); }else{ - sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem); + sqlite3VdbeAddOp(v, OP_NewRecno, base, counterMem); } #ifndef SQLITE_OMIT_AUTOINCREMENT if( pTab->autoInc ){ sqlite3VdbeAddOp(v, OP_MemMax, counterMem, 0); } @@ -598,11 +601,11 @@ if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the record number will be substituted ** in its place. So will fill this column with a NULL to avoid ** taking up data space with information that will never be used. */ - sqlite3VdbeAddOp(v, OP_Null, 0, 0); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); continue; } if( pColumn==0 ){ j = i; }else{ @@ -631,11 +634,11 @@ } /* Update the count of rows that are inserted */ if( (db->flags & SQLITE_CountRows)!=0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, 1, iCntMem); + sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0); } if( triggers_exist ){ /* Close all tables opened */ if( !isView ){ @@ -679,19 +682,21 @@ ** table. */ if( pTab->autoInc ){ int iCur = pParse->nTab; int base = sqlite3VdbeCurrentAddr(v); - sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); + sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pDb->pSeqTab->tnum); + sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2); sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0); sqlite3VdbeAddOp(v, OP_NotNull, -1, base+7); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0); + sqlite3VdbeAddOp(v, OP_NewRecno, iCur, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); sqlite3VdbeAddOp(v, OP_MemLoad, counterMem, 0); sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0); - sqlite3VdbeAddOp(v, OP_Insert, iCur, 0); + sqlite3VdbeAddOp(v, OP_PutIntKey, iCur, 0); sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } #endif /* @@ -706,36 +711,36 @@ sqlite3VdbeSetColName(v, 0, "rows inserted", P3_STATIC); } insert_cleanup: sqlite3SrcListDelete(pTabList); - sqlite3ExprListDelete(pList); - sqlite3SelectDelete(pSelect); + if( pList ) sqlite3ExprListDelete(pList); + if( pSelect ) sqlite3SelectDelete(pSelect); sqlite3IdListDelete(pColumn); } /* ** Generate code to do a constraint check prior to an INSERT or an UPDATE. ** ** When this routine is called, the stack contains (from bottom to top) ** the following values: ** -** 1. The rowid of the row to be updated before the update. This +** 1. The recno of the row to be updated before the update. This ** value is omitted unless we are doing an UPDATE that involves a ** change to the record number. ** -** 2. The rowid of the row after the update. +** 2. The recno of the row after the update. ** ** 3. The data in the first column of the entry after the update. ** ** i. Data from middle columns... ** ** N. The data in the last column of the entry after the update. ** -** The old rowid shown as entry (1) above is omitted unless both isUpdate -** and rowidChng are 1. isUpdate is true for UPDATEs and false for -** INSERTs and rowidChng is true if the record number is being changed. +** The old recno shown as entry (1) above is omitted unless both isUpdate +** and recnoChng are 1. isUpdate is true for UPDATEs and false for +** INSERTs and recnoChng is true if the record number is being changed. ** ** The code generated by this routine pushes additional entries onto ** the stack which are the keys for new index entries for the new record. ** The order of index keys is the same as the order of the indices on ** the pTable->pIndex list. A key is only created for index i if @@ -795,11 +800,11 @@ void sqlite3GenerateConstraintChecks( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int base, /* Index of a read/write cursor pointing at pTab */ char *aIdxUsed, /* Which indices are used. NULL means all are used */ - int rowidChng, /* True if the record number will change */ + int recnoChng, /* True if the record number will change */ int isUpdate, /* True for UPDATE, False for INSERT */ int overrideError, /* Override onError to this if not OE_Default */ int ignoreDest /* Jump to this label on an OE_Ignore resolution */ ){ int i; @@ -810,11 +815,12 @@ int extra; int iCur; Index *pIdx; int seenReplace = 0; int jumpInst1=0, jumpInst2; - int hasTwoRowids = (isUpdate && rowidChng); + int contAddr; + int hasTwoRecnos = (isUpdate && recnoChng); v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; @@ -849,43 +855,32 @@ " may not be NULL", (char*)0); sqlite3VdbeChangeP3(v, -1, zMsg, P3_DYNAMIC); break; } case OE_Ignore: { - sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0); + sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3ExprCode(pParse, pTab->aCol[i].pDflt); sqlite3VdbeAddOp(v, OP_Push, nCol-i, 0); break; } } - sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); } /* Test all CHECK constraints */ -#ifndef SQLITE_OMIT_CHECK - if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){ - int allOk = sqlite3VdbeMakeLabel(v); - assert( pParse->ckOffset==0 ); - pParse->ckOffset = nCol; - sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1); - assert( pParse->ckOffset==nCol ); - pParse->ckOffset = 0; - sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort); - sqlite3VdbeResolveLabel(v, allOk); - } -#endif /* !defined(SQLITE_OMIT_CHECK) */ + /**** TBD ****/ /* If we have an INTEGER PRIMARY KEY, make sure the primary key ** of the new record does not previously exist. Except, if this ** is an UPDATE and the primary key is not changing, that is OK. */ - if( rowidChng ){ + if( recnoChng ){ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; @@ -911,26 +906,27 @@ break; } case OE_Replace: { sqlite3GenerateRowIndexDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ - sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRowids, 1); + sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } case OE_Ignore: { assert( seenReplace==0 ); - sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0); + sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } } - sqlite3VdbeJumpHere(v, jumpInst2); + contAddr = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeChangeP2(v, jumpInst2, contAddr); if( isUpdate ){ - sqlite3VdbeJumpHere(v, jumpInst1); + sqlite3VdbeChangeP2(v, jumpInst1, contAddr); sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); } } @@ -951,11 +947,11 @@ sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1); }else{ sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1); } } - jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0); + jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24)); sqlite3IndexAffinityStr(v, pIdx); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx->onError; if( onError==OE_None ) continue; /* pIdx is not a UNIQUE index */ @@ -969,11 +965,11 @@ else if( onError==OE_Fail ) onError = OE_Abort; } /* Check to see if the new index entry will be unique */ - sqlite3VdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRowids, 1); + sqlite3VdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1); jumpInst2 = sqlite3VdbeAddOp(v, OP_IsUnique, base+iCur+1, 0); /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); @@ -1006,36 +1002,38 @@ sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0); break; } case OE_Ignore: { assert( seenReplace==0 ); - sqlite3VdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRowids, 0); + sqlite3VdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRecnos, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3GenerateRowDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ - sqlite3VdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRowids, 1); + sqlite3VdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } } + contAddr = sqlite3VdbeCurrentAddr(v); + assert( contAddr<(1<<24) ); #if NULL_DISTINCT_FOR_UNIQUE - sqlite3VdbeJumpHere(v, jumpInst1); + sqlite3VdbeChangeP2(v, jumpInst1, contAddr | (1<<24)); #endif - sqlite3VdbeJumpHere(v, jumpInst2); + sqlite3VdbeChangeP2(v, jumpInst2, contAddr); } } /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqlite3GenerateConstraintChecks. ** The stack must contain keys for all active indices followed by data -** and the rowid for the new entry. This routine creates the new +** and the recno for the new entry. This routine creates the new ** entries in all indices and in the main table. ** ** The arguments to this routine should be the same as the first six ** arguments to sqlite3GenerateConstraintChecks. */ @@ -1042,11 +1040,11 @@ void sqlite3CompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int base, /* Index of a read/write cursor pointing at pTab */ char *aIdxUsed, /* Which indices are used. NULL means all are used */ - int rowidChng, /* True if the record number will change */ + int recnoChng, /* True if the record number will change */ int isUpdate, /* True for UPDATE, False for INSERT */ int newIdx /* Index of NEW table for triggers. -1 if none */ ){ int i; Vdbe *v; @@ -1058,33 +1056,29 @@ assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} for(i=nIdx-1; i>=0; i--){ if( aIdxUsed && aIdxUsed[i]==0 ) continue; - sqlite3VdbeAddOp(v, OP_IdxInsert, base+i+1, 0); + sqlite3VdbeAddOp(v, OP_IdxPut, base+i+1, 0); } sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); sqlite3TableAffinityStr(v, pTab); #ifndef SQLITE_OMIT_TRIGGER if( newIdx>=0 ){ sqlite3VdbeAddOp(v, OP_Dup, 1, 0); sqlite3VdbeAddOp(v, OP_Dup, 1, 0); - sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0); + sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0); } #endif if( pParse->nested ){ pik_flags = 0; }else{ - pik_flags = OPFLAG_NCHANGE; - pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID); - } - sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags); - if( !pParse->nested ){ - sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); - } - - if( isUpdate && rowidChng ){ + pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID)); + } + sqlite3VdbeAddOp(v, OP_PutIntKey, base, pik_flags); + + if( isUpdate && recnoChng ){ sqlite3VdbeAddOp(v, OP_Pop, 1, 0); } } /* @@ -1097,21 +1091,21 @@ Table *pTab, /* Table to be opened */ int base, /* Cursor number assigned to the table */ int op /* OP_OpenRead or OP_OpenWrite */ ){ int i; - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); Index *pIdx; Vdbe *v = sqlite3GetVdbe(pParse); assert( v!=0 ); - sqlite3OpenTable(pParse, base, iDb, pTab, op); + sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqlite3VdbeAddOp(v, op, base, pTab->tnum); + VdbeComment((v, "# %s", pTab->zName)); + sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ - KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); - assert( pIdx->pSchema==pTab->pSchema ); - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - VdbeComment((v, "# %s", pIdx->zName)); - sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, (char*)pKey, P3_KEYINFO_HANDOFF); + sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, + (char*)&pIdx->keyInfo, P3_KEYINFO); } if( pParse->nTab<=base+i ){ pParse->nTab = base+i; } } Index: SQLite.Interop/src/keywordhash.h ================================================================== --- SQLite.Interop/src/keywordhash.h +++ SQLite.Interop/src/keywordhash.h @@ -1,87 +1,84 @@ -/* Hash score: 159 */ -static int keywordCode(const char *z, int n){ - static const char zText[537] = - "ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER" - "AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE" - "XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX" - "AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE" - "CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS" - "CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH" - "FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL" - "JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION" - "UNIQUEUSINGVACUUMVALUESVIEWHERE"; - static const unsigned char aHash[127] = { - 92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0, - 96, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0, - 113, 0, 110, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71, - 0, 63, 19, 0, 105, 36, 104, 0, 108, 75, 0, 0, 33, - 0, 61, 37, 0, 8, 0, 115, 38, 12, 0, 77, 40, 25, - 66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0, - 74, 26, 0, 72, 0, 0, 0, 64, 47, 67, 22, 87, 29, - 69, 86, 0, 1, 0, 9, 101, 58, 18, 0, 112, 82, 99, - 55, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0, - 15, 0, 116, 51, 56, 0, 2, 54, 0, 111, - }; - static const unsigned char aNext[116] = { - 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, - 0, 11, 0, 0, 0, 0, 5, 13, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, - 0, 16, 0, 0, 23, 52, 0, 0, 0, 0, 45, 0, 59, - 0, 0, 0, 0, 0, 0, 0, 0, 43, 73, 0, 24, 60, - 21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0, - 0, 0, 0, 0, 0, 39, 95, 98, 0, 0, 100, 0, 32, - 0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0, - }; - static const unsigned char aLen[116] = { - 5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7, - 11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6, - 7, 6, 7, 9, 3, 7, 9, 6, 9, 3, 10, 6, 6, - 4, 6, 7, 3, 6, 7, 5, 13, 2, 2, 5, 5, 6, - 7, 7, 3, 4, 4, 2, 7, 3, 8, 6, 4, 4, 7, - 6, 6, 8, 10, 9, 6, 5, 12, 17, 12, 4, 4, 6, - 8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9, - 6, 7, 4, 6, 2, 3, 6, 4, 5, 7, 5, 8, 7, - 5, 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5, - }; - static const unsigned short int aOffset[116] = { - 0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36, - 42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94, - 99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167, - 172, 175, 177, 177, 181, 185, 187, 192, 194, 196, 205, 208, 212, - 218, 224, 224, 227, 230, 234, 236, 237, 241, 248, 254, 258, 262, - 269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352, - 358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405, - 414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469, - 476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531, - }; - static const unsigned char aCode[116] = { - TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP, - TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, - TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON, - TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EACH, TK_CHECK, - TK_KEY, TK_AFTER, TK_REFERENCES, TK_ESCAPE, TK_ELSE, - TK_EXCEPT, TK_TRIGGER, TK_LIKE_KW, TK_EXPLAIN, TK_INITIALLY, - TK_ALL, TK_ANALYZE, TK_EXCLUSIVE, TK_EXISTS, TK_STATEMENT, - TK_AND, TK_DEFERRABLE, TK_ATTACH, TK_HAVING, TK_LIKE_KW, - TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_REINDEX, - TK_INDEX, TK_AUTOINCR, TK_TO, TK_IN, TK_BEGIN, - TK_JOIN_KW, TK_RENAME, TK_BETWEEN, TK_NOTNULL, TK_NOT, - TK_NULL, TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC, - TK_DEFERRED, TK_DELETE, TK_CASE, TK_CAST, TK_COLLATE, - TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_INTERSECT, - TK_CREATE, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CTIME_KW, - TK_PLAN, TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS, - TK_DROP, TK_PRAGMA, TK_MATCH, TK_FAIL, TK_LIMIT, - TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IF, - TK_IMMEDIATE, TK_INSERT, TK_INSTEAD, TK_INTO, TK_OFFSET, - TK_OF, TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER, - TK_REPLACE, TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY, - TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION, - TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW, - TK_WHERE, +/* Hash score: 148 */ +static int keywordCode(const char *z, int n){ + static const char zText[504] = + "ABORTABLEFTEMPORARYAFTERAISELECTHENDATABASEACHECKEYALTEREFERENCES" + "CAPELSEXCEPTRANSACTIONATURALIKEXCLUSIVEXISTSTATEMENTRIGGEREINDEX" + "PLAINITIALLYANDEFAULTATTACHAVINGLOBEFOREIGNORENAMEAUTOINCREMENT" + "BEGINNEREPLACEBETWEENOTNULLIMITBYCASCADEFERRABLECASECOLLATECOMMIT" + "CONFLICTCONSTRAINTERSECTCREATECROSSCURRENT_DATECURRENT_TIMESTAMP" + "RAGMATCHDEFERREDELETEDESCDETACHDISTINCTDROPRIMARYFAILFROMFULL" + "GROUPDATEIMMEDIATEINSERTINSTEADINTOFFSETISNULLJOINORDERESTRICT" + "OUTERIGHTROLLBACKROWHENUNIONUNIQUEUSINGVACUUMVALUESVIEWHERE"; + static const unsigned char aHash[127] = { + 87, 78, 99, 86, 0, 4, 0, 0, 106, 0, 72, 0, 0, + 90, 43, 0, 88, 0, 98, 101, 92, 0, 0, 9, 0, 0, + 105, 0, 102, 96, 0, 10, 46, 0, 40, 0, 0, 61, 66, + 0, 60, 14, 0, 0, 35, 80, 0, 100, 69, 0, 0, 26, + 0, 73, 59, 0, 12, 0, 107, 37, 11, 0, 75, 39, 20, + 0, 0, 0, 34, 79, 51, 33, 48, 15, 84, 0, 36, 0, + 70, 21, 0, 67, 0, 0, 0, 0, 45, 62, 17, 83, 32, + 64, 82, 0, 1, 0, 13, 50, 56, 8, 0, 104, 71, 94, + 52, 6, 55, 0, 0, 47, 89, 0, 97, 0, 65, 0, 0, + 23, 0, 108, 49, 54, 0, 2, 53, 0, 103, + }; + static const unsigned char aNext[108] = { + 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 18, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, + 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, + 24, 0, 0, 44, 0, 0, 0, 30, 57, 0, 0, 0, 0, + 0, 0, 0, 68, 41, 0, 0, 0, 0, 19, 58, 16, 0, + 77, 0, 63, 0, 81, 31, 0, 0, 0, 0, 0, 0, 0, + 38, 91, 93, 0, 0, 95, 22, 29, 76, 0, 25, 85, 0, + 28, 0, 74, 0, + }; + static const unsigned char aLen[108] = { + 5, 5, 4, 4, 9, 2, 5, 5, 6, 4, 3, 8, 2, + 4, 5, 3, 5, 10, 6, 4, 6, 11, 2, 7, 4, 9, + 6, 9, 7, 7, 5, 7, 9, 3, 3, 7, 6, 6, 4, + 6, 3, 7, 6, 6, 13, 2, 2, 5, 5, 7, 7, 3, + 7, 4, 5, 2, 7, 3, 10, 4, 7, 6, 8, 10, 9, + 6, 5, 12, 12, 17, 6, 5, 8, 6, 4, 6, 8, 2, + 4, 7, 4, 4, 4, 5, 6, 9, 6, 7, 4, 2, 6, + 3, 6, 4, 5, 8, 5, 5, 8, 3, 4, 5, 6, 5, + 6, 6, 4, 5, + }; + static const unsigned short int aOffset[108] = { + 0, 4, 7, 10, 10, 14, 19, 23, 26, 31, 33, 35, 40, + 42, 44, 48, 51, 55, 63, 68, 71, 76, 85, 86, 92, 95, + 103, 108, 116, 122, 124, 127, 132, 137, 141, 143, 150, 155, 160, + 163, 165, 165, 169, 173, 179, 181, 183, 192, 195, 199, 206, 212, + 212, 215, 218, 223, 225, 226, 230, 240, 244, 251, 257, 265, 272, + 281, 287, 292, 304, 304, 320, 324, 329, 336, 342, 346, 352, 353, + 360, 363, 370, 374, 378, 382, 385, 391, 400, 406, 413, 416, 416, + 419, 422, 428, 432, 436, 444, 448, 453, 461, 463, 467, 472, 478, + 483, 489, 495, 498, + }; + static const unsigned char aCode[108] = { + TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP, + TK_OR, TK_AFTER, TK_RAISE, TK_SELECT, TK_THEN, + TK_END, TK_DATABASE, TK_AS, TK_EACH, TK_CHECK, + TK_KEY, TK_ALTER, TK_REFERENCES, TK_ESCAPE, TK_ELSE, + TK_EXCEPT, TK_TRANSACTION,TK_ON, TK_JOIN_KW, TK_LIKE, + TK_EXCLUSIVE, TK_EXISTS, TK_STATEMENT, TK_TRIGGER, TK_REINDEX, + TK_INDEX, TK_EXPLAIN, TK_INITIALLY, TK_ALL, TK_AND, + TK_DEFAULT, TK_ATTACH, TK_HAVING, TK_GLOB, TK_BEFORE, + TK_FOR, TK_FOREIGN, TK_IGNORE, TK_RENAME, TK_AUTOINCR, + TK_TO, TK_IN, TK_BEGIN, TK_JOIN_KW, TK_REPLACE, + TK_BETWEEN, TK_NOT, TK_NOTNULL, TK_NULL, TK_LIMIT, + TK_BY, TK_CASCADE, TK_ASC, TK_DEFERRABLE, TK_CASE, + TK_COLLATE, TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_INTERSECT, + TK_CREATE, TK_JOIN_KW, TK_CDATE, TK_CTIME, TK_CTIMESTAMP, + TK_PRAGMA, TK_MATCH, TK_DEFERRED, TK_DELETE, TK_DESC, + TK_DETACH, TK_DISTINCT, TK_IS, TK_DROP, TK_PRIMARY, + TK_FAIL, TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, + TK_IMMEDIATE, TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF, + TK_OFFSET, TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER, + TK_RESTRICT, TK_JOIN_KW, TK_JOIN_KW, TK_ROLLBACK, TK_ROW, + TK_WHEN, TK_UNION, TK_UNIQUE, TK_USING, TK_VACUUM, + TK_VALUES, TK_VIEW, TK_WHERE, }; int h, i; if( n<2 ) return TK_ID; h = ((sqlite3UpperToLower[((unsigned char*)z)[0]]*4) ^ (sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3) ^ @@ -91,8 +88,8 @@ return aCode[i]; } } return TK_ID; } -int sqlite3KeywordCode(const unsigned char *z, int n){ - return keywordCode((char*)z, n); +int sqlite3KeywordCode(const char *z, int n){ + return keywordCode(z, n); } Index: SQLite.Interop/src/legacy.c ================================================================== --- SQLite.Interop/src/legacy.c +++ SQLite.Interop/src/legacy.c @@ -12,11 +12,11 @@ ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: legacy.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: legacy.c,v 1.1 2005/03/01 16:04:30 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -68,10 +68,11 @@ nCallback = 0; nCol = sqlite3_column_count(pStmt); azCols = sqliteMalloc(2*nCol*sizeof(const char *)); if( nCol && !azCols ){ + rc = SQLITE_NOMEM; goto exec_out; } while( 1 ){ int i; @@ -119,15 +120,13 @@ exec_out: if( pStmt ) sqlite3_finalize(pStmt); if( azCols ) sqliteFree(azCols); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3_malloc_failed ){ rc = SQLITE_NOMEM; - sqlite3MallocClearFailed(); } - if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){ *pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db))); if( *pzErrMsg ){ strcpy(*pzErrMsg, sqlite3_errmsg(db)); } Index: SQLite.Interop/src/main.c ================================================================== --- SQLite.Interop/src/main.c +++ SQLite.Interop/src/main.c @@ -12,11 +12,11 @@ ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: main.c,v 1.1 2005/03/01 16:04:30 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -23,10 +23,362 @@ /* ** The following constant value is used by the SQLITE_BIGENDIAN and ** SQLITE_LITTLEENDIAN macros. */ const int sqlite3one = 1; + +/* +** Fill the InitData structure with an error message that indicates +** that the database is corrupt. +*/ +static void corruptSchema(InitData *pData, const char *zExtra){ + if( !sqlite3_malloc_failed ){ + sqlite3SetString(pData->pzErrMsg, "malformed database schema", + zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); + } +} + +/* +** This is the callback routine for the code that initializes the +** database. See sqlite3Init() below for additional information. +** This routine is also called from the OP_ParseSchema opcode of the VDBE. +** +** Each callback contains the following information: +** +** argv[0] = name of thing being created +** argv[1] = root page number for table or index. NULL for trigger or view. +** argv[2] = SQL text for the CREATE statement. +** argv[3] = "1" for temporary files, "0" for main database, "2" or more +** for auxiliary database files. +** +*/ +int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ + InitData *pData = (InitData*)pInit; + sqlite3 *db = pData->db; + int iDb; + + assert( argc==4 ); + if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ + if( argv[1]==0 || argv[3]==0 ){ + corruptSchema(pData, 0); + return 1; + } + iDb = atoi(argv[3]); + assert( iDb>=0 && iDbnDb ); + if( argv[2] && argv[2][0] ){ + /* Call the parser to process a CREATE TABLE, INDEX or VIEW. + ** But because db->init.busy is set to 1, no VDBE code is generated + ** or executed. All the parser does is build the internal data + ** structures that describe the table, index, or view. + */ + char *zErr; + int rc; + assert( db->init.busy ); + db->init.iDb = iDb; + db->init.newTnum = atoi(argv[1]); + rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); + db->init.iDb = 0; + if( SQLITE_OK!=rc ){ + corruptSchema(pData, zErr); + sqlite3_free(zErr); + return rc; + } + }else{ + /* If the SQL column is blank it means this is an index that + ** was created to be the PRIMARY KEY or to fulfill a UNIQUE + ** constraint for a CREATE TABLE. The index should have already + ** been created when we processed the CREATE TABLE. All we have + ** to do here is record the root page number for that index. + */ + Index *pIndex; + pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName); + if( pIndex==0 || pIndex->tnum!=0 ){ + /* This can occur if there exists an index on a TEMP table which + ** has the same name as another index on a permanent index. Since + ** the permanent table is hidden by the TEMP table, we can also + ** safely ignore the index on the permanent table. + */ + /* Do Nothing */; + }else{ + pIndex->tnum = atoi(argv[1]); + } + } + return 0; +} + +/* +** Attempt to read the database schema and initialize internal +** data structures for a single database file. The index of the +** database file is given by iDb. iDb==0 is used for the main +** database. iDb==1 should never be used. iDb>=2 is used for +** auxiliary databases. Return one of the SQLITE_ error codes to +** indicate success or failure. +*/ +static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ + int rc; + BtCursor *curMain; + int size; + Table *pTab; + char const *azArg[5]; + char zDbNum[30]; + int meta[10]; + InitData initData; + char const *zMasterSchema; + char const *zMasterName; + + /* + ** The master database table has a structure like this + */ + static const char master_schema[] = + "CREATE TABLE sqlite_master(\n" + " type text,\n" + " name text,\n" + " tbl_name text,\n" + " rootpage integer,\n" + " sql text\n" + ")" + ; + static const char temp_master_schema[] = + "CREATE TEMP TABLE sqlite_temp_master(\n" + " type text,\n" + " name text,\n" + " tbl_name text,\n" + " rootpage integer,\n" + " sql text\n" + ")" + ; + + assert( iDb>=0 && iDbnDb ); + + /* zMasterSchema and zInitScript are set to point at the master schema + ** and initialisation script appropriate for the database being + ** initialised. zMasterName is the name of the master table. + */ + if( iDb==1 ){ + zMasterSchema = temp_master_schema; + zMasterName = TEMP_MASTER_NAME; + }else{ + zMasterSchema = master_schema; + zMasterName = MASTER_NAME; + } + + /* Construct the schema tables. */ + sqlite3SafetyOff(db); + azArg[0] = zMasterName; + azArg[1] = "1"; + azArg[2] = zMasterSchema; + sprintf(zDbNum, "%d", iDb); + azArg[3] = zDbNum; + azArg[4] = 0; + initData.db = db; + initData.pzErrMsg = pzErrMsg; + rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0); + if( rc!=SQLITE_OK ){ + sqlite3SafetyOn(db); + return rc; + } + pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); + if( pTab ){ + pTab->readOnly = 1; + } + sqlite3SafetyOn(db); + + /* Create a cursor to hold the database open + */ + if( db->aDb[iDb].pBt==0 ){ + if( iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded); + return SQLITE_OK; + } + rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain); + if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ + sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); + return rc; + } + + /* Get the database meta information. + ** + ** Meta values are as follows: + ** meta[0] Schema cookie. Changes with each schema change. + ** meta[1] File format of schema layer. + ** meta[2] Size of the page cache. + ** meta[3] Use freelist if 0. Autovacuum if greater than zero. + ** meta[4] Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE + ** meta[5] The user cookie. Used by the application. + ** meta[6] + ** meta[7] + ** meta[8] + ** meta[9] + ** + ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to + ** the possible values of meta[4]. + */ + if( rc==SQLITE_OK ){ + int i; + for(i=0; rc==SQLITE_OK && iaDb[iDb].pBt, i+1, (u32 *)&meta[i]); + } + if( rc ){ + sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); + sqlite3BtreeCloseCursor(curMain); + return rc; + } + }else{ + memset(meta, 0, sizeof(meta)); + } + db->aDb[iDb].schema_cookie = meta[0]; + + /* If opening a non-empty database, check the text encoding. For the + ** main database, set sqlite3.enc to the encoding of the main database. + ** For an attached db, it is an error if the encoding is not the same + ** as sqlite3.enc. + */ + if( meta[4] ){ /* text encoding */ + if( iDb==0 ){ + /* If opening the main database, set db->enc. */ + db->enc = (u8)meta[4]; + db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0); + }else{ + /* If opening an attached database, the encoding much match db->enc */ + if( meta[4]!=db->enc ){ + sqlite3BtreeCloseCursor(curMain); + sqlite3SetString(pzErrMsg, "attached databases must use the same" + " text encoding as main database", (char*)0); + return SQLITE_ERROR; + } + } + } + + size = meta[2]; + if( size==0 ){ size = MAX_PAGES; } + db->aDb[iDb].cache_size = size; + + if( iDb==0 ){ + db->file_format = meta[1]; + if( db->file_format==0 ){ + /* This happens if the database was initially empty */ + db->file_format = 1; + } + + if( db->file_format==2 ){ + /* File format 2 is treated exactly as file format 1. New + ** databases are created with file format 1. + */ + db->file_format = 1; + } + } + + /* + ** file_format==1 Version 3.0.0. + ** file_format==2 Version 3.1.3. + ** + ** Version 3.0 can only use files with file_format==1. Version 3.1.3 + ** can read and write files with file_format==1 or file_format==2. + */ + if( meta[1]>2 ){ + sqlite3BtreeCloseCursor(curMain); + sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); + return SQLITE_ERROR; + } + + sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size); + + /* Read the schema information out of the schema tables + */ + assert( db->init.busy ); + if( rc==SQLITE_EMPTY ){ + /* For an empty database, there is nothing to read */ + rc = SQLITE_OK; + }else{ + char *zSql; + zSql = sqlite3MPrintf( + "SELECT name, rootpage, sql, '%s' FROM '%q'.%s", + zDbNum, db->aDb[iDb].zName, zMasterName); + sqlite3SafetyOff(db); + rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); + sqlite3SafetyOn(db); + sqliteFree(zSql); + sqlite3BtreeCloseCursor(curMain); + } + if( sqlite3_malloc_failed ){ + sqlite3SetString(pzErrMsg, "out of memory", (char*)0); + rc = SQLITE_NOMEM; + sqlite3ResetInternalSchema(db, 0); + } + if( rc==SQLITE_OK ){ + DbSetProperty(db, iDb, DB_SchemaLoaded); + }else{ + sqlite3ResetInternalSchema(db, iDb); + } + return rc; +} + +/* +** Initialize all database files - the main database file, the file +** used to store temporary tables, and any additional database files +** created using ATTACH statements. Return a success code. If an +** error occurs, write an error message into *pzErrMsg. +** +** After the database is initialized, the SQLITE_Initialized +** bit is set in the flags field of the sqlite structure. +*/ +int sqlite3Init(sqlite3 *db, char **pzErrMsg){ + int i, rc; + + if( db->init.busy ) return SQLITE_OK; + assert( (db->flags & SQLITE_Initialized)==0 ); + rc = SQLITE_OK; + db->init.busy = 1; + for(i=0; rc==SQLITE_OK && inDb; i++){ + if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; + rc = sqlite3InitOne(db, i, pzErrMsg); + if( rc ){ + sqlite3ResetInternalSchema(db, i); + } + } + + /* Once all the other databases have been initialised, load the schema + ** for the TEMP database. This is loaded last, as the TEMP database + ** schema may contain references to objects in other databases. + */ + if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ + rc = sqlite3InitOne(db, 1, pzErrMsg); + if( rc ){ + sqlite3ResetInternalSchema(db, 1); + } + } + + db->init.busy = 0; + if( rc==SQLITE_OK ){ + db->flags |= SQLITE_Initialized; + sqlite3CommitInternalChanges(db); + } + + if( rc!=SQLITE_OK ){ + db->flags &= ~SQLITE_Initialized; + } + return rc; +} + +/* +** This routine is a no-op if the database schema is already initialised. +** Otherwise, the schema is loaded. An error code is returned. +*/ +int sqlite3ReadSchema(Parse *pParse){ + int rc = SQLITE_OK; + sqlite3 *db = pParse->db; + if( !db->init.busy ){ + if( (db->flags & SQLITE_Initialized)==0 ){ + rc = sqlite3Init(db, &pParse->zErrMsg); + } + } + assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized)||db->init.busy ); + if( rc!=SQLITE_OK ){ + pParse->rc = rc; + pParse->nErr++; + } + return rc; +} /* ** The version of the library */ const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $"; @@ -107,14 +459,10 @@ } if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } -#ifdef SQLITE_SSE - sqlite3_finalize(db->pFetch); -#endif - /* If there are any outstanding VMs, return SQLITE_BUSY. */ if( db->pVdbe ){ sqlite3Error(db, SQLITE_BUSY, "Unable to close due to unfinalised statements"); return SQLITE_BUSY; @@ -129,21 +477,15 @@ if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){ /* printf("DID NOT CLOSE\n"); fflush(stdout); */ return SQLITE_ERROR; } - /* sqlite3_close() may not invoke sqliteMalloc(). */ - sqlite3MallocDisallow(); - for(j=0; jnDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; - if( j!=1 ){ - pDb->pSchema = 0; - } } } sqlite3ResetInternalSchema(db, 0); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); @@ -161,52 +503,34 @@ } sqlite3HashClear(&db->aCollSeq); sqlite3HashClear(&db->aFunc); sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ + if( db->pValue ){ + sqlite3ValueFree(db->pValue); + } if( db->pErr ){ sqlite3ValueFree(db->pErr); } db->magic = SQLITE_MAGIC_ERROR; - - /* The temp-database schema is allocated differently from the other schema - ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). - ** So it needs to be freed here. Todo: Why not roll the temp schema into - ** the same sqliteMalloc() as the one that allocates the database - ** structure? - */ - sqliteFree(db->aDb[1].pSchema); sqliteFree(db); - sqlite3MallocAllow(); - sqlite3ReleaseThreadData(); return SQLITE_OK; } /* ** Rollback all database files. */ void sqlite3RollbackAll(sqlite3 *db){ int i; - int inTrans = 0; for(i=0; inDb; i++){ if( db->aDb[i].pBt ){ - if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){ - inTrans = 1; - } sqlite3BtreeRollback(db->aDb[i].pBt); db->aDb[i].inTrans = 0; } } - if( db->flags&SQLITE_InternChanges ){ - sqlite3ResetInternalSchema(db, 0); - } - - /* If one has been configured, invoke the rollback-hook callback */ - if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ - db->xRollbackCallback(db->pRollbackArg); - } + sqlite3ResetInternalSchema(db, 0); } /* ** Return a static string that describes the kind of error specified in the ** argument. @@ -216,24 +540,27 @@ switch( rc ){ case SQLITE_ROW: case SQLITE_DONE: case SQLITE_OK: z = "not an error"; break; case SQLITE_ERROR: z = "SQL logic error or missing database"; break; + case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break; case SQLITE_PERM: z = "access permission denied"; break; case SQLITE_ABORT: z = "callback requested query abort"; break; case SQLITE_BUSY: z = "database is locked"; break; case SQLITE_LOCKED: z = "database table is locked"; break; case SQLITE_NOMEM: z = "out of memory"; break; case SQLITE_READONLY: z = "attempt to write a readonly database"; break; case SQLITE_INTERRUPT: z = "interrupted"; break; case SQLITE_IOERR: z = "disk I/O error"; break; case SQLITE_CORRUPT: z = "database disk image is malformed"; break; - case SQLITE_FULL: z = "database or disk is full"; break; + case SQLITE_NOTFOUND: z = "table or record not found"; break; + case SQLITE_FULL: z = "database is full"; break; case SQLITE_CANTOPEN: z = "unable to open database file"; break; case SQLITE_PROTOCOL: z = "database locking protocol failure"; break; case SQLITE_EMPTY: z = "table contains no data"; break; case SQLITE_SCHEMA: z = "database schema has changed"; break; + case SQLITE_TOOBIG: z = "too much data for one table row"; break; case SQLITE_CONSTRAINT: z = "constraint failed"; break; case SQLITE_MISMATCH: z = "datatype mismatch"; break; case SQLITE_MISUSE: z = "library routine called out of sequence";break; case SQLITE_NOLFS: z = "kernel lacks large file support"; break; case SQLITE_AUTH: z = "authorization denied"; break; @@ -250,65 +577,45 @@ ** again until a timeout value is reached. The timeout value is ** an integer number of milliseconds passed in as the first ** argument. */ static int sqliteDefaultBusyCallback( - void *ptr, /* Database connection */ + void *Timeout, /* Maximum amount of time to wait */ int count /* Number of times table has been busy */ ){ #if SQLITE_MIN_SLEEP_MS==1 - static const u8 delays[] = - { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 }; - static const u8 totals[] = - { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 }; + static const char delays[] = + { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 50, 100}; + static const short int totals[] = + { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228, 287}; # define NDELAY (sizeof(delays)/sizeof(delays[0])) - int timeout = ((sqlite3 *)ptr)->busyTimeout; - int delay, prior; + ptr timeout = (ptr)Timeout; + ptr delay, prior; - assert( count>=0 ); - if( count < NDELAY ){ - delay = delays[count]; - prior = totals[count]; + if( count <= NDELAY ){ + delay = delays[count-1]; + prior = totals[count-1]; }else{ delay = delays[NDELAY-1]; - prior = totals[NDELAY-1] + delay*(count-(NDELAY-1)); + prior = totals[NDELAY-1] + delay*(count-NDELAY-1); } if( prior + delay > timeout ){ delay = timeout - prior; if( delay<=0 ) return 0; } sqlite3OsSleep(delay); return 1; #else - int timeout = ((sqlite3 *)ptr)->busyTimeout; + int timeout = (int)Timeout; if( (count+1)*1000 > timeout ){ return 0; } sqlite3OsSleep(1000); return 1; #endif } -/* -** Invoke the given busy handler. -** -** This routine is called when an operation failed with a lock. -** If this routine returns non-zero, the lock is retried. If it -** returns 0, the operation aborts with an SQLITE_BUSY error. -*/ -int sqlite3InvokeBusyHandler(BusyHandler *p){ - int rc; - if( p==0 || p->xFunc==0 || p->nBusy<0 ) return 0; - rc = p->xFunc(p->pArg, p->nBusy); - if( rc==0 ){ - p->nBusy = -1; - }else{ - p->nBusy++; - } - return rc; -} - /* ** This routine sets the busy callback for an Sqlite database to the ** given callback function with the given argument. */ int sqlite3_busy_handler( @@ -319,11 +626,10 @@ if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } db->busyHandler.xFunc = xBusy; db->busyHandler.pArg = pArg; - db->busyHandler.nBusy = 0; return SQLITE_OK; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* @@ -356,12 +662,11 @@ ** This routine installs a default busy handler that waits for the ** specified number of milliseconds before returning 0. */ int sqlite3_busy_timeout(sqlite3 *db, int ms){ if( ms>0 ){ - db->busyTimeout = ms; - sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db); + sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)(ptr)ms); }else{ sqlite3_busy_handler(db, 0, 0); } return SQLITE_OK; } @@ -453,11 +758,10 @@ } } p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1); if( p==0 ) return SQLITE_NOMEM; - p->flags = 0; p->xFunc = xFunc; p->xStep = xStep; p->xFinalize = xFinal; p->pUserData = pUserData; return SQLITE_OK; @@ -472,65 +776,48 @@ void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ){ int rc; - char *zFunc8; + char const *zFunc8; + sqlite3_value *pTmp; if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } - zFunc8 = sqlite3utf16to8(zFunctionName, -1); + pTmp = sqlite3GetTransientValue(db); + sqlite3ValueSetStr(pTmp, -1, zFunctionName, SQLITE_UTF16NATIVE,SQLITE_STATIC); + zFunc8 = sqlite3ValueText(pTmp, SQLITE_UTF8); + if( !zFunc8 ){ return SQLITE_NOMEM; } rc = sqlite3_create_function(db, zFunc8, nArg, eTextRep, pUserData, xFunc, xStep, xFinal); - sqliteFree(zFunc8); return rc; } #endif -#ifndef SQLITE_OMIT_TRACE /* ** Register a trace function. The pArg from the previously registered trace ** is returned. ** ** A NULL trace function means that no tracing is executes. A non-NULL ** trace is a pointer to a function that is invoked at the start of each -** SQL statement. +** sqlite3_exec(). */ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ void *pOld = db->pTraceArg; db->xTrace = xTrace; db->pTraceArg = pArg; return pOld; } -/* -** Register a profile function. The pArg from the previously registered -** profile function is returned. -** -** A NULL profile function means that no profiling is executes. A non-NULL -** profile is a pointer to a function that is invoked at the conclusion of -** each SQL statement that is run. -*/ -void *sqlite3_profile( - sqlite3 *db, - void (*xProfile)(void*,const char*,sqlite_uint64), - void *pArg -){ - void *pOld = db->pProfileArg; - db->xProfile = xProfile; - db->pProfileArg = pArg; - return pOld; -} -#endif /* SQLITE_OMIT_TRACE */ /*** EXPERIMENTAL *** ** ** Register a function to be invoked when a transaction comments. -** If the invoked function returns non-zero, then the commit becomes a +** If either function returns non-zero, then the commit becomes a ** rollback. */ void *sqlite3_commit_hook( sqlite3 *db, /* Attach the hook to this database */ int (*xCallback)(void*), /* Function to invoke on each commit */ @@ -540,51 +827,22 @@ db->xCommitCallback = xCallback; db->pCommitArg = pArg; return pOld; } -/* -** Register a callback to be invoked each time a row is updated, -** inserted or deleted using this database connection. -*/ -void *sqlite3_update_hook( - sqlite3 *db, /* Attach the hook to this database */ - void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), - void *pArg /* Argument to the function */ -){ - void *pRet = db->pUpdateArg; - db->xUpdateCallback = xCallback; - db->pUpdateArg = pArg; - return pRet; -} - -/* -** Register a callback to be invoked each time a transaction is rolled -** back by this database connection. -*/ -void *sqlite3_rollback_hook( - sqlite3 *db, /* Attach the hook to this database */ - void (*xCallback)(void*), /* Callback function */ - void *pArg /* Argument to the function */ -){ - void *pRet = db->pRollbackArg; - db->xRollbackCallback = xCallback; - db->pRollbackArg = pArg; - return pRet; -} /* ** This routine is called to create a connection to a database BTree ** driver. If zFilename is the name of a file, then that file is ** opened and used. If zFilename is the magic name ":memory:" then ** the database is stored in memory (and is thus forgotten as soon as ** the connection is closed.) If zFilename is NULL then the database -** is a "virtual" database for transient use only and is deleted as -** soon as the connection is closed. +** is for temporary use only and is deleted as soon as the connection +** is closed. ** -** A virtual database can be either a disk file (that is automatically -** deleted when the file is closed) or it an be held entirely in memory, +** A temporary database can be either a disk file (that is automatically +** deleted when the file is closed) or a set of red-black trees held in memory, ** depending on the values of the TEMP_STORE compile-time macro and the ** db->temp_store variable, according to the following chart: ** ** TEMP_STORE db->temp_store Location of temporary database ** ---------- -------------- ------------------------------ @@ -629,11 +887,11 @@ zFilename = ":memory:"; #endif #endif /* SQLITE_OMIT_MEMORYDB */ } - rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags); + rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags); if( rc==SQLITE_OK ){ sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler); sqlite3BtreeSetCacheSize(*ppBtree, nCache); } return rc; @@ -643,17 +901,17 @@ ** Return UTF-8 encoded English language explanation of the most recent ** error. */ const char *sqlite3_errmsg(sqlite3 *db){ const char *z; - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3_malloc_failed ){ return sqlite3ErrStr(SQLITE_NOMEM); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ return sqlite3ErrStr(SQLITE_MISUSE); } - z = (char*)sqlite3_value_text(db->pErr); + z = sqlite3_value_text(db->pErr); if( z==0 ){ z = sqlite3ErrStr(db->errCode); } return z; } @@ -682,11 +940,11 @@ 0, 'o', 0, 'f', 0, ' ', 0, 's', 0, 'e', 0, 'q', 0, 'u', 0, 'e', 0, 'n', 0, 'c', 0, 'e', 0, 0, 0 }; const void *z; - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3_malloc_failed ){ return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); } @@ -699,110 +957,234 @@ return z; } #endif /* SQLITE_OMIT_UTF16 */ /* -** Return the most recent error code generated by an SQLite routine. If NULL is -** passed to this function, we assume a malloc() failed during sqlite3_open(). +** Return the most recent error code generated by an SQLite routine. */ int sqlite3_errcode(sqlite3 *db){ - if( !db || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3_malloc_failed ){ return SQLITE_NOMEM; } if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } return db->errCode; } +/* +** Check schema cookies in all databases. If any cookie is out +** of date, return 0. If all schema cookies are current, return 1. +*/ +static int schemaIsValid(sqlite3 *db){ + int iDb; + int rc; + BtCursor *curTemp; + int cookie; + int allOk = 1; + + for(iDb=0; allOk && iDbnDb; iDb++){ + Btree *pBt; + pBt = db->aDb[iDb].pBt; + if( pBt==0 ) continue; + rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie); + if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){ + allOk = 0; + } + sqlite3BtreeCloseCursor(curTemp); + } + } + return allOk; +} + +/* +** Compile the UTF-8 encoded SQL statement zSql into a statement handle. +*/ +int sqlite3_prepare( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char** pzTail /* OUT: End of parsed string */ +){ + Parse sParse; + char *zErrMsg = 0; + int rc = SQLITE_OK; + + if( sqlite3_malloc_failed ){ + return SQLITE_NOMEM; + } + + assert( ppStmt ); + *ppStmt = 0; + if( sqlite3SafetyOn(db) ){ + return SQLITE_MISUSE; + } + + memset(&sParse, 0, sizeof(sParse)); + sParse.db = db; + sqlite3RunParser(&sParse, zSql, &zErrMsg); + + if( sqlite3_malloc_failed ){ + rc = SQLITE_NOMEM; + sqlite3RollbackAll(db); + sqlite3ResetInternalSchema(db, 0); + db->flags &= ~SQLITE_InTrans; + goto prepare_out; + } + if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; + if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){ + sParse.rc = SQLITE_SCHEMA; + } + if( sParse.rc==SQLITE_SCHEMA ){ + sqlite3ResetInternalSchema(db, 0); + } + if( pzTail ) *pzTail = sParse.zTail; + rc = sParse.rc; + +#ifndef SQLITE_OMIT_EXPLAIN + if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ + sqlite3VdbeSetNumCols(sParse.pVdbe, 5); + sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC); + } +#endif + +prepare_out: + if( sqlite3SafetyOff(db) ){ + rc = SQLITE_MISUSE; + } + if( rc==SQLITE_OK ){ + *ppStmt = (sqlite3_stmt*)sParse.pVdbe; + }else if( sParse.pVdbe ){ + sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); + } + + if( zErrMsg ){ + sqlite3Error(db, rc, "%s", zErrMsg); + sqliteFree(zErrMsg); + }else{ + sqlite3Error(db, rc, 0); + } + return rc; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Compile the UTF-16 encoded SQL statement zSql into a statement handle. +*/ +int sqlite3_prepare16( + sqlite3 *db, /* Database handle. */ + const void *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: End of parsed string */ +){ + /* This function currently works by first transforming the UTF-16 + ** encoded string to UTF-8, then invoking sqlite3_prepare(). The + ** tricky bit is figuring out the pointer to return in *pzTail. + */ + char const *zSql8 = 0; + char const *zTail8 = 0; + int rc; + sqlite3_value *pTmp; + + if( sqlite3SafetyCheck(db) ){ + return SQLITE_MISUSE; + } + pTmp = sqlite3GetTransientValue(db); + sqlite3ValueSetStr(pTmp, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); + zSql8 = sqlite3ValueText(pTmp, SQLITE_UTF8); + if( !zSql8 ){ + sqlite3Error(db, SQLITE_NOMEM, 0); + return SQLITE_NOMEM; + } + rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8); + + if( zTail8 && pzTail ){ + /* If sqlite3_prepare returns a tail pointer, we calculate the + ** equivalent pointer into the UTF-16 string by counting the unicode + ** characters between zSql8 and zTail8, and then returning a pointer + ** the same number of characters into the UTF-16 string. + */ + int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8); + *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed); + } + + return rc; +} +#endif /* SQLITE_OMIT_UTF16 */ + /* ** This routine does the work of opening a database on behalf of ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" -** is UTF-8 encoded. +** is UTF-8 encoded. The fourth argument, "def_enc" is one of the TEXT_* +** macros from sqliteInt.h. If we end up creating a new database file +** (not opening an existing one), the text encoding of the database +** will be set to this value. */ static int openDatabase( const char *zFilename, /* Database filename UTF-8 encoded */ sqlite3 **ppDb /* OUT: Returned database handle */ ){ sqlite3 *db; - int rc; - CollSeq *pColl; - - assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); + int rc, i; /* Allocate the sqlite data structure */ db = sqliteMalloc( sizeof(sqlite3) ); if( db==0 ) goto opendb_out; db->priorNewRowid = 0; db->magic = SQLITE_MAGIC_BUSY; db->nDb = 2; db->aDb = db->aDbStatic; + db->enc = SQLITE_UTF8; db->autoCommit = 1; db->flags |= SQLITE_ShortColNames; sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); - -#if 0 for(i=0; inDb; i++){ sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1); } -#endif - + /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. */ if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) || sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) || - (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0 - ){ - /* sqlite3_create_collation() is an external API. So the mallocFailed flag - ** will have been cleared before returning. So set it explicitly here. - */ - sqlite3ThreadData()->mallocFailed = 1; + !(db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0)) ){ + rc = db->errCode; + assert( rc!=SQLITE_OK ); db->magic = SQLITE_MAGIC_CLOSED; goto opendb_out; } /* Also add a UTF-8 case-insensitive collation sequence. */ sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc); - /* Set flags on the built-in collating sequences */ - db->pDfltColl->type = SQLITE_COLL_BINARY; - pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 6, 0); - if( pColl ){ - pColl->type = SQLITE_COLL_NOCASE; - } - /* Open the backend database driver */ rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt); if( rc!=SQLITE_OK ){ sqlite3Error(db, rc, 0); db->magic = SQLITE_MAGIC_CLOSED; goto opendb_out; } -#ifndef SQLITE_OMIT_PARSER - db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt); - db->aDb[1].pSchema = sqlite3SchemaGet(0); -#endif - - if( db->aDb[0].pSchema ){ - ENC(db) = SQLITE_UTF8; - } - - /* The default safety_level for the main database is 'full'; for the temp - ** database it is 'NONE'. This matches the pager layer defaults. - */ db->aDb[0].zName = "main"; + db->aDb[1].zName = "temp"; + + /* The default safety_level for the main database is 'full' for the temp + ** database it is 'NONE'. This matches the pager layer defaults. */ db->aDb[0].safety_level = 3; -#ifndef SQLITE_OMIT_TEMPDB - db->aDb[1].zName = "temp"; db->aDb[1].safety_level = 1; -#endif /* Register all built-in functions, but do not attempt to read the ** database schema yet. This is delayed until the first time the database ** is accessed. */ @@ -809,17 +1191,15 @@ sqlite3RegisterBuiltinFunctions(db); sqlite3Error(db, SQLITE_OK, 0); db->magic = SQLITE_MAGIC_OPEN; opendb_out: - if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){ - sqlite3_close(db); - db = 0; + if( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){ + sqlite3Error(db, SQLITE_NOMEM, 0); } *ppDb = db; - sqlite3MallocClearFailed(); - return rc; + return sqlite3_errcode(db); } /* ** Open a new database handle. */ @@ -840,26 +1220,24 @@ ){ char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ int rc = SQLITE_NOMEM; sqlite3_value *pVal; - assert( zFilename ); assert( ppDb ); *ppDb = 0; pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zFilename8 ){ rc = openDatabase(zFilename8, ppDb); if( rc==SQLITE_OK && *ppDb ){ - rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); + sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); } - }else{ - assert( sqlite3ThreadDataReadOnly()->mallocFailed ); - sqlite3MallocClearFailed(); } - sqlite3ValueFree(pVal); + if( pVal ){ + sqlite3ValueFree(pVal); + } return rc; } #endif /* SQLITE_OMIT_UTF16 */ @@ -894,11 +1272,11 @@ int rc; if( pStmt==0 ){ rc = SQLITE_OK; }else{ rc = sqlite3VdbeReset((Vdbe*)pStmt); - sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0); + sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0, 0); } return rc; } /* @@ -948,11 +1326,11 @@ sqlite3ExpirePreparedStatements(db); } pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1); if( 0==pColl ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM; }else{ pColl->xCmp = xCompare; pColl->pUser = pCtx; pColl->enc = enc; } @@ -969,19 +1347,19 @@ const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ - char *zName8; - int rc; + char const *zName8; + sqlite3_value *pTmp; if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } - zName8 = sqlite3utf16to8(zName, -1); - rc = sqlite3_create_collation(db, zName8, enc, pCtx, xCompare); - sqliteFree(zName8); - return rc; + pTmp = sqlite3GetTransientValue(db); + sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF16NATIVE, SQLITE_STATIC); + zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8); + return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare); } #endif /* SQLITE_OMIT_UTF16 */ /* ** Register a collation sequence factory callback with the database handle @@ -1018,76 +1396,5 @@ db->xCollNeeded16 = xCollNeeded16; db->pCollNeededArg = pCollNeededArg; return SQLITE_OK; } #endif /* SQLITE_OMIT_UTF16 */ - -#ifndef SQLITE_OMIT_GLOBALRECOVER -/* -** This function is now an anachronism. It used to be used to recover from a -** malloc() failure, but SQLite now does this automatically. -*/ -int sqlite3_global_recover(){ - return SQLITE_OK; -} -#endif - -/* -** Test to see whether or not the database connection is in autocommit -** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on -** by default. Autocommit is disabled by a BEGIN statement and reenabled -** by the next COMMIT or ROLLBACK. -** -******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** -*/ -int sqlite3_get_autocommit(sqlite3 *db){ - return db->autoCommit; -} - -#ifdef SQLITE_DEBUG -/* -** The following routine is subtituted for constant SQLITE_CORRUPT in -** debugging builds. This provides a way to set a breakpoint for when -** corruption is first detected. -*/ -int sqlite3Corrupt(void){ - return SQLITE_CORRUPT; -} -#endif - - -#ifndef SQLITE_OMIT_SHARED_CACHE -/* -** Enable or disable the shared pager and schema features for the -** current thread. -** -** This routine should only be called when there are no open -** database connections. -*/ -int sqlite3_enable_shared_cache(int enable){ - ThreadData *pTd = sqlite3ThreadData(); - - /* It is only legal to call sqlite3_enable_shared_cache() when there - ** are no currently open b-trees that were opened by the calling thread. - ** This condition is only easy to detect if the shared-cache were - ** previously enabled (and is being disabled). - */ - if( pTd->pBtree && !enable ){ - assert( pTd->useSharedData ); - return SQLITE_MISUSE; - } - - pTd->useSharedData = enable; - sqlite3ReleaseThreadData(); - return SQLITE_OK; -} -#endif - -/* -** This is a convenience routine that makes sure that all thread-specific -** data for this thread has been deallocated. -*/ -void sqlite3_thread_cleanup(void){ - ThreadData *pTd = sqlite3ThreadData(); - memset(pTd, 0, sizeof(*pTd)); - sqlite3ReleaseThreadData(); -} DELETED SQLite.Interop/src/md5.c Index: SQLite.Interop/src/md5.c ================================================================== --- SQLite.Interop/src/md5.c +++ /dev/null @@ -1,387 +0,0 @@ -/* -** SQLite uses this code for testing only. It is not a part of -** the SQLite library. This file implements two new TCL commands -** "md5" and "md5file" that compute md5 checksums on arbitrary text -** and on complete files. These commands are used by the "testfixture" -** program to help verify the correct operation of the SQLite library. -** -** The original use of these TCL commands was to test the ROLLBACK -** feature of SQLite. First compute the MD5-checksum of the database. -** Then make some changes but rollback the changes rather than commit -** them. Compute a second MD5-checksum of the file and verify that the -** two checksums are the same. Such is the original use of this code. -** New uses may have been added since this comment was written. -*/ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ -#include -#include -#include "sqlite3.h" - -/* - * If compiled on a machine that doesn't have a 32-bit integer, - * you just set "uint32" to the appropriate datatype for an - * unsigned 32-bit integer. For example: - * - * cc -Duint32='unsigned long' md5.c - * - */ -#ifndef uint32 -# define uint32 unsigned int -#endif - -struct Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; -typedef char MD5Context[88]; - -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse (unsigned char *buf, unsigned longs){ - uint32 t; - do { - t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | - ((unsigned)buf[1]<<8 | buf[0]); - *(uint32 *)buf = t; - buf += 4; - } while (--longs); -} -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(uint32 buf[4], const uint32 in[16]){ - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -static void MD5Init(MD5Context *pCtx){ - struct Context *ctx = (struct Context *)pCtx; - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -static -void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){ - struct Context *ctx = (struct Context *)pCtx; - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if ( t ) { - unsigned char *p = (unsigned char *)ctx->in + t; - - t = 64-t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += t; - len -= t; - } - - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -static void MD5Final(unsigned char digest[16], MD5Context *pCtx){ - struct Context *ctx = (struct Context *)pCtx; - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count-8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; - ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32 *)ctx->in); - byteReverse((unsigned char *)ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - -/* -** Convert a digest into base-16. digest should be declared as -** "unsigned char digest[16]" in the calling function. The MD5 -** digest is stored in the first 16 bytes. zBuf should -** be "char zBuf[33]". -*/ -static void DigestToBase16(unsigned char *digest, char *zBuf){ - static char const zEncode[] = "0123456789abcdef"; - int i, j; - - for(j=i=0; i<16; i++){ - int a = digest[i]; - zBuf[j++] = zEncode[(a>>4)&0xf]; - zBuf[j++] = zEncode[a & 0xf]; - } - zBuf[j] = 0; -} - -/* -** A TCL command for md5. The argument is the text to be hashed. The -** Result is the hash in base64. -*/ -static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){ - MD5Context ctx; - unsigned char digest[16]; - - if( argc!=2 ){ - Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], - " TEXT\"", 0); - return TCL_ERROR; - } - MD5Init(&ctx); - MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1])); - MD5Final(digest, &ctx); - DigestToBase16(digest, interp->result); - return TCL_OK; -} - -/* -** A TCL command to take the md5 hash of a file. The argument is the -** name of the file. -*/ -static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){ - FILE *in; - MD5Context ctx; - unsigned char digest[16]; - char zBuf[10240]; - - if( argc!=2 ){ - Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], - " FILENAME\"", 0); - return TCL_ERROR; - } - in = fopen(argv[1],"rb"); - if( in==0 ){ - Tcl_AppendResult(interp,"unable to open file \"", argv[1], - "\" for reading", 0); - return TCL_ERROR; - } - MD5Init(&ctx); - for(;;){ - int n; - n = fread(zBuf, 1, sizeof(zBuf), in); - if( n<=0 ) break; - MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n); - } - fclose(in); - MD5Final(digest, &ctx); - DigestToBase16(digest, interp->result); - return TCL_OK; -} - -/* -** Register the two TCL commands above with the TCL interpreter. -*/ -int Md5_Init(Tcl_Interp *interp){ - Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, 0, 0); - Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, 0, 0); - return TCL_OK; -} - -/* -** During testing, the special md5sum() aggregate function is available. -** inside SQLite. The following routines implement that function. -*/ -static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){ - MD5Context *p; - int i; - if( argc<1 ) return; - p = sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( sqlite3_aggregate_count(context)==1 ){ - MD5Init(p); - } - for(i=0; ipMethod->xClose(pId); - }else{ - return SQLITE_OK; - } -} -int sqlite3OsOpenDirectory(OsFile *id, const char *zName){ - return id->pMethod->xOpenDirectory(id, zName); -} -int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ - return id->pMethod->xRead(id, pBuf, amt); -} -int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ - return id->pMethod->xWrite(id, pBuf, amt); -} -int sqlite3OsSeek(OsFile *id, i64 offset){ - return id->pMethod->xSeek(id, offset); -} -int sqlite3OsTruncate(OsFile *id, i64 size){ - return id->pMethod->xTruncate(id, size); -} -int sqlite3OsSync(OsFile *id, int fullsync){ - return id->pMethod->xSync(id, fullsync); -} -void sqlite3OsSetFullSync(OsFile *id, int value){ - id->pMethod->xSetFullSync(id, value); -} -int sqlite3OsFileHandle(OsFile *id){ - return id->pMethod->xFileHandle(id); -} -int sqlite3OsFileSize(OsFile *id, i64 *pSize){ - return id->pMethod->xFileSize(id, pSize); -} -int sqlite3OsLock(OsFile *id, int lockType){ - return id->pMethod->xLock(id, lockType); -} -int sqlite3OsUnlock(OsFile *id, int lockType){ - return id->pMethod->xUnlock(id, lockType); -} -int sqlite3OsLockState(OsFile *id){ - return id->pMethod->xLockState(id); -} -int sqlite3OsCheckReservedLock(OsFile *id){ - return id->pMethod->xCheckReservedLock(id); -} - -#ifdef SQLITE_ENABLE_REDEF_IO -/* -** A function to return a pointer to the virtual function table. -** This routine really does not accomplish very much since the -** virtual function table is a global variable and anybody who -** can call this function can just as easily access the variable -** for themselves. Nevertheless, we include this routine for -** backwards compatibility with an earlier redefinable I/O -** interface design. -*/ -struct sqlite3OsVtbl *sqlite3_os_switch(void){ - return &sqlite3Os; -} -#endif Index: SQLite.Interop/src/os.h ================================================================== --- SQLite.Interop/src/os.h +++ SQLite.Interop/src/os.h @@ -16,15 +16,16 @@ */ #ifndef _SQLITE_OS_H_ #define _SQLITE_OS_H_ /* -** Figure out if we are dealing with Unix, Windows, or some other -** operating system. +** Figure out if we are dealing with Unix, Windows or MacOS. +** +** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix. +** The MacOS build is designed to use CodeWarrior (tested with v8) */ -#if !defined(OS_UNIX) && !defined(OS_OTHER) -# define OS_OTHER 0 +#if !defined(OS_UNIX) && !defined(OS_TEST) # ifndef OS_WIN # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) # define OS_WIN 1 # define OS_UNIX 0 # else @@ -38,26 +39,21 @@ # ifndef OS_WIN # define OS_WIN 0 # endif #endif - /* -** Define the maximum size of a temporary filename +** Invoke the appropriate operating-system specific header file. */ -#if OS_WIN -# include -# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) -#else -# define SQLITE_TEMPNAME_SIZE 200 +#if OS_TEST +# include "os_test.h" +#endif +#if OS_UNIX +# include "os_unix.h" #endif - -/* If the SET_FULLSYNC macro is not defined above, then make it -** a no-op -*/ -#ifndef SET_FULLSYNC -# define SET_FULLSYNC(x,y) +#if OS_WIN +# include "os_win.h" #endif /* ** Temporary files are named starting with this prefix followed by 16 random ** alphanumeric characters, and no file extension. They are stored in the @@ -69,108 +65,10 @@ */ #ifndef TEMP_FILE_PREFIX # define TEMP_FILE_PREFIX "sqlite_" #endif -/* -** Define the interfaces for Unix and for Windows. -*/ -#if OS_UNIX -#define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite -#define sqlite3OsOpenExclusive sqlite3UnixOpenExclusive -#define sqlite3OsOpenReadOnly sqlite3UnixOpenReadOnly -#define sqlite3OsDelete sqlite3UnixDelete -#define sqlite3OsFileExists sqlite3UnixFileExists -#define sqlite3OsFullPathname sqlite3UnixFullPathname -#define sqlite3OsIsDirWritable sqlite3UnixIsDirWritable -#define sqlite3OsSyncDirectory sqlite3UnixSyncDirectory -#define sqlite3OsTempFileName sqlite3UnixTempFileName -#define sqlite3OsRandomSeed sqlite3UnixRandomSeed -#define sqlite3OsSleep sqlite3UnixSleep -#define sqlite3OsCurrentTime sqlite3UnixCurrentTime -#define sqlite3OsEnterMutex sqlite3UnixEnterMutex -#define sqlite3OsLeaveMutex sqlite3UnixLeaveMutex -#define sqlite3OsInMutex sqlite3UnixInMutex -#define sqlite3OsThreadSpecificData sqlite3UnixThreadSpecificData -#define sqlite3OsMalloc sqlite3GenericMalloc -#define sqlite3OsRealloc sqlite3GenericRealloc -#define sqlite3OsFree sqlite3GenericFree -#define sqlite3OsAllocationSize sqlite3GenericAllocationSize -#endif -#if OS_WIN -#define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite -#define sqlite3OsOpenExclusive sqlite3WinOpenExclusive -#define sqlite3OsOpenReadOnly sqlite3WinOpenReadOnly -#define sqlite3OsDelete sqlite3WinDelete -#define sqlite3OsFileExists sqlite3WinFileExists -#define sqlite3OsFullPathname sqlite3WinFullPathname -#define sqlite3OsIsDirWritable sqlite3WinIsDirWritable -#define sqlite3OsSyncDirectory sqlite3WinSyncDirectory -#define sqlite3OsTempFileName sqlite3WinTempFileName -#define sqlite3OsRandomSeed sqlite3WinRandomSeed -#define sqlite3OsSleep sqlite3WinSleep -#define sqlite3OsCurrentTime sqlite3WinCurrentTime -#define sqlite3OsEnterMutex sqlite3WinEnterMutex -#define sqlite3OsLeaveMutex sqlite3WinLeaveMutex -#define sqlite3OsInMutex sqlite3WinInMutex -#define sqlite3OsThreadSpecificData sqlite3WinThreadSpecificData -#define sqlite3OsMalloc sqlite3GenericMalloc -#define sqlite3OsRealloc sqlite3GenericRealloc -#define sqlite3OsFree sqlite3GenericFree -#define sqlite3OsAllocationSize sqlite3GenericAllocationSize -#endif - -/* -** If using an alternative OS interface, then we must have an "os_other.h" -** header file available for that interface. Presumably the "os_other.h" -** header file contains #defines similar to those above. -*/ -#if OS_OTHER -# include "os_other.h" -#endif - - - -/* -** Forward declarations -*/ -typedef struct OsFile OsFile; -typedef struct IoMethod IoMethod; - -/* -** An instance of the following structure contains pointers to all -** methods on an OsFile object. -*/ -struct IoMethod { - int (*xClose)(OsFile**); - int (*xOpenDirectory)(OsFile*, const char*); - int (*xRead)(OsFile*, void*, int amt); - int (*xWrite)(OsFile*, const void*, int amt); - int (*xSeek)(OsFile*, i64 offset); - int (*xTruncate)(OsFile*, i64 size); - int (*xSync)(OsFile*, int); - void (*xSetFullSync)(OsFile *id, int setting); - int (*xFileHandle)(OsFile *id); - int (*xFileSize)(OsFile*, i64 *pSize); - int (*xLock)(OsFile*, int); - int (*xUnlock)(OsFile*, int); - int (*xLockState)(OsFile *id); - int (*xCheckReservedLock)(OsFile *id); -}; - -/* -** The OsFile object describes an open disk file in an OS-dependent way. -** The version of OsFile defined here is a generic version. Each OS -** implementation defines its own subclass of this structure that contains -** additional information needed to handle file I/O. But the pMethod -** entry (pointing to the virtual function table) always occurs first -** so that we can always find the appropriate methods. -*/ -struct OsFile { - IoMethod const *pMethod; -}; - /* ** The following values may be passed as the second argument to ** sqlite3OsLock(). The various locks exhibit the following semantics: ** ** SHARED: Any number of processes may hold a SHARED lock simultaneously. @@ -221,14 +119,12 @@ ** The following #defines specify the range of bytes used for locking. ** SHARED_SIZE is the number of bytes available in the pool from which ** a random byte is selected for a shared lock. The pool of bytes for ** shared locks begins at SHARED_FIRST. ** -** These #defines are available in sqlite_aux.h so that adaptors for -** connecting SQLite to other operating systems can use the same byte -** ranges for locking. In particular, the same locking strategy and -** byte ranges are used for Unix. This leaves open the possiblity of having +** These #defines are available in os.h so that Unix can use the same +** byte ranges for locking. This leaves open the possiblity of having ** clients on win95, winNT, and unix all talking to the same shared file ** and all locking correctly. To do so would require that samba (or whatever ** tool is being used for file sharing) implements locks correctly between ** windows and unix. I'm guessing that isn't likely to happen, but by ** using the same locking range we are at least open to the possibility. @@ -247,194 +143,40 @@ ** the incompatibility right away, even running a full regression test. ** The default location of PENDING_BYTE is the first byte past the ** 1GB boundary. ** */ -#ifndef SQLITE_TEST #define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */ -#else -extern unsigned int sqlite3_pending_byte; -#define PENDING_BYTE sqlite3_pending_byte -#endif - +/* #define PENDING_BYTE 0x5400 // Page 22 - for testing */ #define RESERVED_BYTE (PENDING_BYTE+1) #define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_SIZE 510 -/* -** Prototypes for operating system interface routines. -*/ -int sqlite3OsClose(OsFile**); -int sqlite3OsOpenDirectory(OsFile*, const char*); + +int sqlite3OsDelete(const char*); +int sqlite3OsFileExists(const char*); +int sqlite3OsOpenReadWrite(const char*, OsFile*, int*); +int sqlite3OsOpenExclusive(const char*, OsFile*, int); +int sqlite3OsOpenReadOnly(const char*, OsFile*); +int sqlite3OsOpenDirectory(const char*, OsFile*); +int sqlite3OsSyncDirectory(const char*); +int sqlite3OsTempFileName(char*); +int sqlite3OsIsDirWritable(char*); +int sqlite3OsClose(OsFile*); int sqlite3OsRead(OsFile*, void*, int amt); int sqlite3OsWrite(OsFile*, const void*, int amt); int sqlite3OsSeek(OsFile*, i64 offset); +int sqlite3OsSync(OsFile*); int sqlite3OsTruncate(OsFile*, i64 size); -int sqlite3OsSync(OsFile*, int); -void sqlite3OsSetFullSync(OsFile *id, int setting); -int sqlite3OsFileHandle(OsFile *id); int sqlite3OsFileSize(OsFile*, i64 *pSize); -int sqlite3OsLock(OsFile*, int); -int sqlite3OsUnlock(OsFile*, int); -int sqlite3OsLockState(OsFile *id); -int sqlite3OsCheckReservedLock(OsFile *id); -int sqlite3OsOpenReadWrite(const char*, OsFile**, int*); -int sqlite3OsOpenExclusive(const char*, OsFile**, int); -int sqlite3OsOpenReadOnly(const char*, OsFile**); -int sqlite3OsDelete(const char*); -int sqlite3OsFileExists(const char*); -char *sqlite3OsFullPathname(const char*); -int sqlite3OsIsDirWritable(char*); -int sqlite3OsSyncDirectory(const char*); -int sqlite3OsTempFileName(char*); int sqlite3OsRandomSeed(char*); int sqlite3OsSleep(int ms); int sqlite3OsCurrentTime(double*); +int sqlite3OsFileModTime(OsFile*, double*); void sqlite3OsEnterMutex(void); void sqlite3OsLeaveMutex(void); -int sqlite3OsInMutex(void); -ThreadData *sqlite3OsThreadSpecificData(int); -void *sqlite3OsMalloc(int); -void *sqlite3OsRealloc(void *, int); -void sqlite3OsFree(void *); -int sqlite3OsAllocationSize(void *); - -/* -** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer -** interface routines are not called directly but are invoked using -** pointers to functions. This allows the implementation of various -** OS-layer interface routines to be modified at run-time. There are -** obscure but legitimate reasons for wanting to do this. But for -** most users, a direct call to the underlying interface is preferable -** so the the redefinable I/O interface is turned off by default. -*/ -#ifdef SQLITE_ENABLE_REDEF_IO - -/* -** When redefinable I/O is enabled, a single global instance of the -** following structure holds pointers to the routines that SQLite -** uses to talk with the underlying operating system. Modify this -** structure (before using any SQLite API!) to accomodate perculiar -** operating system interfaces or behaviors. -*/ -struct sqlite3OsVtbl { - int (*xOpenReadWrite)(const char*, OsFile**, int*); - int (*xOpenExclusive)(const char*, OsFile**, int); - int (*xOpenReadOnly)(const char*, OsFile**); - - int (*xDelete)(const char*); - int (*xFileExists)(const char*); - char *(*xFullPathname)(const char*); - int (*xIsDirWritable)(char*); - int (*xSyncDirectory)(const char*); - int (*xTempFileName)(char*); - - int (*xRandomSeed)(char*); - int (*xSleep)(int ms); - int (*xCurrentTime)(double*); - - void (*xEnterMutex)(void); - void (*xLeaveMutex)(void); - int (*xInMutex)(void); - ThreadData *(*xThreadSpecificData)(int); - - void *(*xMalloc)(int); - void *(*xRealloc)(void *, int); - void (*xFree)(void *); - int (*xAllocationSize)(void *); -}; - -/* Macro used to comment out routines that do not exists when there is -** no disk I/O -*/ -#ifdef SQLITE_OMIT_DISKIO -# define IF_DISKIO(X) 0 -#else -# define IF_DISKIO(X) X -#endif - -#ifdef _SQLITE_OS_C_ - /* - ** The os.c file implements the global virtual function table. - */ - struct sqlite3OsVtbl sqlite3Os = { - IF_DISKIO( sqlite3OsOpenReadWrite ), - IF_DISKIO( sqlite3OsOpenExclusive ), - IF_DISKIO( sqlite3OsOpenReadOnly ), - IF_DISKIO( sqlite3OsDelete ), - IF_DISKIO( sqlite3OsFileExists ), - IF_DISKIO( sqlite3OsFullPathname ), - IF_DISKIO( sqlite3OsIsDirWritable ), - IF_DISKIO( sqlite3OsSyncDirectory ), - IF_DISKIO( sqlite3OsTempFileName ), - sqlite3OsRandomSeed, - sqlite3OsSleep, - sqlite3OsCurrentTime, - sqlite3OsEnterMutex, - sqlite3OsLeaveMutex, - sqlite3OsInMutex, - sqlite3OsThreadSpecificData, - sqlite3OsMalloc, - sqlite3OsRealloc, - sqlite3OsFree, - sqlite3OsAllocationSize - }; -#else - /* - ** Files other than os.c just reference the global virtual function table. - */ - extern struct sqlite3OsVtbl sqlite3Os; -#endif /* _SQLITE_OS_C_ */ - - -/* This additional API routine is available with redefinable I/O */ -struct sqlite3OsVtbl *sqlite3_os_switch(void); - - -/* -** Redefine the OS interface to go through the virtual function table -** rather than calling routines directly. -*/ -#undef sqlite3OsOpenReadWrite -#undef sqlite3OsOpenExclusive -#undef sqlite3OsOpenReadOnly -#undef sqlite3OsDelete -#undef sqlite3OsFileExists -#undef sqlite3OsFullPathname -#undef sqlite3OsIsDirWritable -#undef sqlite3OsSyncDirectory -#undef sqlite3OsTempFileName -#undef sqlite3OsRandomSeed -#undef sqlite3OsSleep -#undef sqlite3OsCurrentTime -#undef sqlite3OsEnterMutex -#undef sqlite3OsLeaveMutex -#undef sqlite3OsInMutex -#undef sqlite3OsThreadSpecificData -#undef sqlite3OsMalloc -#undef sqlite3OsRealloc -#undef sqlite3OsFree -#undef sqlite3OsAllocationSize -#define sqlite3OsOpenReadWrite sqlite3Os.xOpenReadWrite -#define sqlite3OsOpenExclusive sqlite3Os.xOpenExclusive -#define sqlite3OsOpenReadOnly sqlite3Os.xOpenReadOnly -#define sqlite3OsDelete sqlite3Os.xDelete -#define sqlite3OsFileExists sqlite3Os.xFileExists -#define sqlite3OsFullPathname sqlite3Os.xFullPathname -#define sqlite3OsIsDirWritable sqlite3Os.xIsDirWritable -#define sqlite3OsSyncDirectory sqlite3Os.xSyncDirectory -#define sqlite3OsTempFileName sqlite3Os.xTempFileName -#define sqlite3OsRandomSeed sqlite3Os.xRandomSeed -#define sqlite3OsSleep sqlite3Os.xSleep -#define sqlite3OsCurrentTime sqlite3Os.xCurrentTime -#define sqlite3OsEnterMutex sqlite3Os.xEnterMutex -#define sqlite3OsLeaveMutex sqlite3Os.xLeaveMutex -#define sqlite3OsInMutex sqlite3Os.xInMutex -#define sqlite3OsThreadSpecificData sqlite3Os.xThreadSpecificData -#define sqlite3OsMalloc sqlite3Os.xMalloc -#define sqlite3OsRealloc sqlite3Os.xRealloc -#define sqlite3OsFree sqlite3Os.xFree -#define sqlite3OsAllocationSize sqlite3Os.xAllocationSize - -#endif /* SQLITE_ENABLE_REDEF_IO */ +char *sqlite3OsFullPathname(const char*); +int sqlite3OsLock(OsFile*, int); +int sqlite3OsUnlock(OsFile*, int); +int sqlite3OsCheckReservedLock(OsFile *id); #endif /* _SQLITE_OS_H_ */ Index: SQLite.Interop/src/os_common.h ================================================================== --- SQLite.Interop/src/os_common.h +++ SQLite.Interop/src/os_common.h @@ -26,18 +26,10 @@ #ifdef MEMORY_DEBUG # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif -/* - * When testing, this global variable stores the location of the - * pending-byte in the database file. - */ -#ifdef SQLITE_TEST -unsigned int sqlite3_pending_byte = 0x40000000; -#endif - int sqlite3_os_trace = 0; #ifdef SQLITE_DEBUG static int last_page = 0; #define SEEK(X) last_page=(X) #define TRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X) @@ -86,30 +78,21 @@ ** If we compile with the SQLITE_TEST macro set, then the following block ** of code will give us the ability to simulate a disk I/O error. This ** is used for testing the I/O recovery logic. */ #ifdef SQLITE_TEST -int sqlite3_io_error_hit = 0; int sqlite3_io_error_pending = 0; int sqlite3_diskfull_pending = 0; -int sqlite3_diskfull = 0; #define SimulateIOError(A) \ if( sqlite3_io_error_pending ) \ if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; } static void local_ioerr(){ - sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */ + sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */ } #define SimulateDiskfullError \ - if( sqlite3_diskfull_pending ){ \ - if( sqlite3_diskfull_pending == 1 ){ \ - local_ioerr(); \ - sqlite3_diskfull = 1; \ - return SQLITE_FULL; \ - }else{ \ - sqlite3_diskfull_pending--; \ - } \ - } + if( sqlite3_diskfull_pending ) \ + if( sqlite3_diskfull_pending-- == 1 ){ local_ioerr(); return SQLITE_FULL; } #else #define SimulateIOError(A) #define SimulateDiskfullError #endif @@ -119,73 +102,6 @@ #ifdef SQLITE_TEST int sqlite3_open_file_count = 0; #define OpenCounter(X) sqlite3_open_file_count+=(X) #else #define OpenCounter(X) -#endif - -/* -** sqlite3GenericMalloc -** sqlite3GenericRealloc -** sqlite3GenericOsFree -** sqlite3GenericAllocationSize -** -** Implementation of the os level dynamic memory allocation interface in terms -** of the standard malloc(), realloc() and free() found in many operating -** systems. No rocket science here. -** -** There are two versions of these four functions here. The version -** implemented here is only used if memory-management or memory-debugging is -** enabled. This version allocates an extra 8-bytes at the beginning of each -** block and stores the size of the allocation there. -** -** If neither memory-management or debugging is enabled, the second -** set of implementations is used instead. -*/ -#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || defined (SQLITE_MEMDEBUG) -void *sqlite3GenericMalloc(int n){ - char *p = (char *)malloc(n+8); - assert(n>0); - assert(sizeof(int)<=8); - if( p ){ - *(int *)p = n; - p += 8; - } - return (void *)p; -} -void *sqlite3GenericRealloc(void *p, int n){ - char *p2 = ((char *)p - 8); - assert(n>0); - p2 = realloc(p2, n+8); - if( p2 ){ - *(int *)p2 = n; - p2 += 8; - } - return (void *)p2; -} -void sqlite3GenericFree(void *p){ - assert(p); - free((void *)((char *)p - 8)); -} -int sqlite3GenericAllocationSize(void *p){ - return p ? *(int *)((char *)p - 8) : 0; -} -#else -void *sqlite3GenericMalloc(int n){ - char *p = (char *)malloc(n); - return (void *)p; -} -void *sqlite3GenericRealloc(void *p, int n){ - assert(n>0); - p = realloc(p, n); - return p; -} -void sqlite3GenericFree(void *p){ - assert(p); - free(p); -} -#if 0 /* Never actually invoked */ -int sqlite3GenericAllocationSize(void *p){ - assert(0); -} -#endif #endif Index: SQLite.Interop/src/os_unix.c ================================================================== --- SQLite.Interop/src/os_unix.c +++ SQLite.Interop/src/os_unix.c @@ -14,112 +14,14 @@ */ #include "sqliteInt.h" #include "os.h" #if OS_UNIX /* This file is used on unix only */ -/* -** These #defines should enable >2GB file support on Posix if the -** underlying operating system supports it. If the OS lacks -** large file support, these should be no-ops. -** -** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch -** on the compiler command line. This is necessary if you are compiling -** on a recent machine (ex: RedHat 7.2) but you want your code to work -** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 -** without this option, LFS is enable. But LFS does not exist in the kernel -** in RedHat 6.0, so the code won't work. Hence, for maximum binary -** portability you should omit LFS. -*/ -#ifndef SQLITE_DISABLE_LFS -# define _LARGE_FILE 1 -# ifndef _FILE_OFFSET_BITS -# define _FILE_OFFSET_BITS 64 -# endif -# define _LARGEFILE_SOURCE 1 -#endif - -/* -** standard include files. -*/ -#include -#include -#include -#include -#include -#include + +#include #include - -/* -** If we are to be thread-safe, include the pthreads header and define -** the SQLITE_UNIX_THREADS macro. -*/ -#if defined(THREADSAFE) && THREADSAFE -# include -# define SQLITE_UNIX_THREADS 1 -#endif - -/* -** Default permissions when creating a new file -*/ -#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS -# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 -#endif - - - -/* -** The unixFile structure is subclass of OsFile specific for the unix -** protability layer. -*/ -typedef struct unixFile unixFile; -struct unixFile { - IoMethod const *pMethod; /* Always the first entry */ - struct openCnt *pOpen; /* Info about all open fd's on this inode */ - struct lockInfo *pLock; /* Info about locks on this inode */ - int h; /* The file descriptor */ - unsigned char locktype; /* The type of lock held on this fd */ - unsigned char isOpen; /* True if needs to be closed */ - unsigned char fullSync; /* Use F_FULLSYNC if available */ - int dirfd; /* File descriptor for the directory */ -#ifdef SQLITE_UNIX_THREADS - pthread_t tid; /* The thread that "owns" this OsFile */ -#endif -}; - -/* -** Provide the ability to override some OS-layer functions during -** testing. This is used to simulate OS crashes to verify that -** commits are atomic even in the event of an OS crash. -*/ -#ifdef SQLITE_CRASH_TEST - extern int sqlite3CrashTestEnable; - extern int sqlite3CrashOpenReadWrite(const char*, OsFile**, int*); - extern int sqlite3CrashOpenExclusive(const char*, OsFile**, int); - extern int sqlite3CrashOpenReadOnly(const char*, OsFile**, int); -# define CRASH_TEST_OVERRIDE(X,A,B,C) \ - if(sqlite3CrashTestEnable){ return X(A,B,C); } -#else -# define CRASH_TEST_OVERRIDE(X,A,B,C) /* no-op */ -#endif - - -/* -** Include code that is common to all os_*.c files -*/ -#include "os_common.h" - -/* -** Do not include any of the File I/O interface procedures if the -** SQLITE_OMIT_DISKIO macro is defined (indicating that the database -** will be in-memory only) -*/ -#ifndef SQLITE_OMIT_DISKIO - - -/* -** Define various macros that are missing from some systems. -*/ +#include #ifndef O_LARGEFILE # define O_LARGEFILE 0 #endif #ifdef SQLITE_DISABLE_LFS # undef O_LARGEFILE @@ -129,54 +31,41 @@ # define O_NOFOLLOW 0 #endif #ifndef O_BINARY # define O_BINARY 0 #endif + /* ** The DJGPP compiler environment looks mostly like Unix, but it ** lacks the fcntl() system call. So redefine fcntl() to be something ** that always succeeds. This means that locking does not occur under -** DJGPP. But it's DOS - what did you expect? +** DJGPP. But its DOS - what did you expect? */ #ifdef __DJGPP__ # define fcntl(A,B,C) 0 #endif /* -** The threadid macro resolves to the thread-id or to 0. Used for -** testing and debugging only. +** Macros used to determine whether or not to use threads. The +** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for +** Posix threads and SQLITE_W32_THREADS is defined if we are +** synchronizing using Win32 threads. */ -#ifdef SQLITE_UNIX_THREADS -#define threadid pthread_self() -#else -#define threadid 0 +#if defined(THREADSAFE) && THREADSAFE +# include +# define SQLITE_UNIX_THREADS 1 #endif + /* -** Set or check the OsFile.tid field. This field is set when an OsFile -** is first opened. All subsequent uses of the OsFile verify that the -** same thread is operating on the OsFile. Some operating systems do -** not allow locks to be overridden by other threads and that restriction -** means that sqlite3* database handles cannot be moved from one thread -** to another. This logic makes sure a user does not try to do that -** by mistake. -** -** Version 3.3.1 (2006-01-15): OsFiles can be moved from one thread to -** another as long as we are running on a system that supports threads -** overriding each others locks (which now the most common behavior) -** or if no locks are held. But the OsFile.pLock field needs to be -** recomputed because its key includes the thread-id. See the -** transferOwnership() function below for additional information +** Include code that is common to all os_*.c files */ -#if defined(SQLITE_UNIX_THREADS) -# define SET_THREADID(X) (X)->tid = pthread_self() -# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \ - !pthread_equal((X)->tid, pthread_self())) -#else -# define SET_THREADID(X) -# define CHECK_THREADID(X) 0 +#include "os_common.h" + +#if defined(THREADSAFE) && THREADSAFE && defined(__linux__) +#define getpid pthread_self #endif /* ** Here is the dirt on POSIX advisory locks: ANSI STD 1003.1 (1996) ** section 6.5.2.2 lines 483 through 490 specify that when a process @@ -281,18 +170,18 @@ ** An instance of the following structure serves as the key used ** to locate a particular lockInfo structure given its inode. ** ** If threads cannot override each others locks, then we set the ** lockKey.tid field to the thread ID. If threads can override -** each others locks then tid is always set to zero. tid is omitted -** if we compile without threading support. +** each others locks then tid is always set to zero. tid is also +** set to zero if we compile without threading support. */ struct lockKey { dev_t dev; /* Device number */ ino_t ino; /* Inode number */ #ifdef SQLITE_UNIX_THREADS - pthread_t tid; /* Thread ID or zero if threads can override each other */ + pthread_t tid; /* Thread ID or zero if threads cannot override each other */ #endif }; /* ** An instance of the following structure is allocated for each open @@ -334,13 +223,12 @@ int nPending; /* Number of pending close() operations */ int *aPending; /* Malloced space holding fd's awaiting a close() */ }; /* -** These hash tables map inodes and file descriptors (really, lockKey and -** openKey structures) into lockInfo and openCnt structures. Access to -** these hash tables must be protected by a mutex. +** These hash table maps inodes and process IDs into lockInfo and openCnt +** structures. Access to these hash tables must be protected by a mutex. */ static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; @@ -350,20 +238,12 @@ ** locks. ** ** 0: No. Threads cannot override each others locks. ** 1: Yes. Threads can override each others locks. ** -1: We don't know yet. -** -** This variable normally has file scope only. But during testing, we make -** it a global so that the test code can change its value in order to verify -** that the right stuff happens in either case. */ -#ifdef SQLITE_TEST -int threadsOverrideEachOthersLocks = -1; -#else static int threadsOverrideEachOthersLocks = -1; -#endif /* ** This structure holds information passed into individual test ** threads by the testThreadLockingBehavior() routine. */ @@ -371,69 +251,10 @@ int fd; /* File to be locked */ struct flock lock; /* The locking operation */ int result; /* Result of the locking operation */ }; -#ifdef SQLITE_LOCK_TRACE -/* -** Print out information about all locking operations. -** -** This routine is used for troubleshooting locks on multithreaded -** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE -** command-line option on the compiler. This code is normally -** turned off. -*/ -static int lockTrace(int fd, int op, struct flock *p){ - char *zOpName, *zType; - int s; - int savedErrno; - if( op==F_GETLK ){ - zOpName = "GETLK"; - }else if( op==F_SETLK ){ - zOpName = "SETLK"; - }else{ - s = fcntl(fd, op, p); - sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); - return s; - } - if( p->l_type==F_RDLCK ){ - zType = "RDLCK"; - }else if( p->l_type==F_WRLCK ){ - zType = "WRLCK"; - }else if( p->l_type==F_UNLCK ){ - zType = "UNLCK"; - }else{ - assert( 0 ); - } - assert( p->l_whence==SEEK_SET ); - s = fcntl(fd, op, p); - savedErrno = errno; - sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", - threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, - (int)p->l_pid, s); - if( s && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ - struct flock l2; - l2 = *p; - fcntl(fd, F_GETLK, &l2); - if( l2.l_type==F_RDLCK ){ - zType = "RDLCK"; - }else if( l2.l_type==F_WRLCK ){ - zType = "WRLCK"; - }else if( l2.l_type==F_UNLCK ){ - zType = "UNLCK"; - }else{ - assert( 0 ); - } - sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n", - zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid); - } - errno = savedErrno; - return s; -} -#define fcntl lockTrace -#endif /* SQLITE_LOCK_TRACE */ - /* ** The testThreadLockingBehavior() routine launches two separate ** threads on this routine. This routine attempts to lock a file ** descriptor then returns. The success or failure of that attempt ** allows the testThreadLockingBehavior() procedure to determine @@ -476,11 +297,10 @@ /* ** Release a lockInfo structure previously allocated by findLockInfo(). */ static void releaseLockInfo(struct lockInfo *pLock){ - assert( sqlite3OsInMutex() ); pLock->nRef--; if( pLock->nRef==0 ){ sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); sqliteFree(pLock); } @@ -488,23 +308,22 @@ /* ** Release a openCnt structure previously allocated by findLockInfo(). */ static void releaseOpenCnt(struct openCnt *pOpen){ - assert( sqlite3OsInMutex() ); pOpen->nRef--; if( pOpen->nRef==0 ){ sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); - free(pOpen->aPending); + sqliteFree(pOpen->aPending); sqliteFree(pOpen); } } /* ** Given a file descriptor, locate lockInfo and openCnt structures that -** describes that file descriptor. Create new ones if necessary. The -** return values might be uninitialized if an error occurs. +** describes that file descriptor. Create a new ones if necessary. The +** return values might be unset if an error occurs. ** ** Return the number of errors. */ static int findLockInfo( int fd, /* The file descriptor used in the key */ @@ -517,12 +336,10 @@ struct stat statbuf; struct lockInfo *pLock; struct openCnt *pOpen; rc = fstat(fd, &statbuf); if( rc!=0 ) return 1; - - assert( sqlite3OsInMutex() ); memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino; #ifdef SQLITE_UNIX_THREADS if( threadsOverrideEachOthersLocks<0 ){ @@ -535,143 +352,67 @@ key2.ino = statbuf.st_ino; pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1)); if( pLock==0 ){ struct lockInfo *pOld; pLock = sqliteMallocRaw( sizeof(*pLock) ); - if( pLock==0 ){ - rc = 1; - goto exit_findlockinfo; - } + if( pLock==0 ) return 1; pLock->key = key1; pLock->nRef = 1; pLock->cnt = 0; pLock->locktype = 0; pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); if( pOld!=0 ){ assert( pOld==pLock ); sqliteFree(pLock); - rc = 1; - goto exit_findlockinfo; + return 1; } }else{ pLock->nRef++; } *ppLock = pLock; - if( ppOpen!=0 ){ - pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2)); - if( pOpen==0 ){ - struct openCnt *pOld; - pOpen = sqliteMallocRaw( sizeof(*pOpen) ); - if( pOpen==0 ){ - releaseLockInfo(pLock); - rc = 1; - goto exit_findlockinfo; - } - pOpen->key = key2; - pOpen->nRef = 1; - pOpen->nLock = 0; - pOpen->nPending = 0; - pOpen->aPending = 0; - pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); - if( pOld!=0 ){ - assert( pOld==pOpen ); - sqliteFree(pOpen); - releaseLockInfo(pLock); - rc = 1; - goto exit_findlockinfo; - } - }else{ - pOpen->nRef++; - } - *ppOpen = pOpen; - } - -exit_findlockinfo: - return rc; -} - -#ifdef SQLITE_DEBUG -/* -** Helper function for printing out trace information from debugging -** binaries. This returns the string represetation of the supplied -** integer lock-type. -*/ -static const char *locktypeName(int locktype){ - switch( locktype ){ - case NO_LOCK: return "NONE"; - case SHARED_LOCK: return "SHARED"; - case RESERVED_LOCK: return "RESERVED"; - case PENDING_LOCK: return "PENDING"; - case EXCLUSIVE_LOCK: return "EXCLUSIVE"; - } - return "ERROR"; -} -#endif - -/* -** If we are currently in a different thread than the thread that the -** unixFile argument belongs to, then transfer ownership of the unixFile -** over to the current thread. -** -** A unixFile is only owned by a thread on systems where one thread is -** unable to override locks created by a different thread. RedHat9 is -** an example of such a system. -** -** Ownership transfer is only allowed if the unixFile is currently unlocked. -** If the unixFile is locked and an ownership is wrong, then return -** SQLITE_MISUSE. SQLITE_OK is returned if everything works. -*/ -#ifdef SQLITE_UNIX_THREADS -static int transferOwnership(unixFile *pFile){ - int rc; - pthread_t hSelf; - if( threadsOverrideEachOthersLocks ){ - /* Ownership transfers not needed on this system */ - return SQLITE_OK; - } - hSelf = pthread_self(); - if( pthread_equal(pFile->tid, hSelf) ){ - /* We are still in the same thread */ - TRACE1("No-transfer, same thread\n"); - return SQLITE_OK; - } - if( pFile->locktype!=NO_LOCK ){ - /* We cannot change ownership while we are holding a lock! */ - return SQLITE_MISUSE; - } - TRACE4("Transfer ownership of %d from %d to %d\n", pFile->h,pFile->tid,hSelf); - pFile->tid = hSelf; - releaseLockInfo(pFile->pLock); - rc = findLockInfo(pFile->h, &pFile->pLock, 0); - TRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h, - locktypeName(pFile->locktype), - locktypeName(pFile->pLock->locktype), pFile->pLock->cnt); - return rc; -} -#else - /* On single-threaded builds, ownership transfer is a no-op */ -# define transferOwnership(X) SQLITE_OK -#endif + pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2)); + if( pOpen==0 ){ + struct openCnt *pOld; + pOpen = sqliteMallocRaw( sizeof(*pOpen) ); + if( pOpen==0 ){ + releaseLockInfo(pLock); + return 1; + } + pOpen->key = key2; + pOpen->nRef = 1; + pOpen->nLock = 0; + pOpen->nPending = 0; + pOpen->aPending = 0; + pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); + if( pOld!=0 ){ + assert( pOld==pOpen ); + sqliteFree(pOpen); + releaseLockInfo(pLock); + return 1; + } + }else{ + pOpen->nRef++; + } + *ppOpen = pOpen; + return 0; +} /* ** Delete the named file */ -int sqlite3UnixDelete(const char *zFilename){ +int sqlite3OsDelete(const char *zFilename){ unlink(zFilename); return SQLITE_OK; } /* ** Return TRUE if the named file exists. */ -int sqlite3UnixFileExists(const char *zFilename){ +int sqlite3OsFileExists(const char *zFilename){ return access(zFilename, 0)==0; } -/* Forward declaration */ -static int allocateUnixFile(unixFile *pInit, OsFile **pId); - /* ** Attempt to open a file for both reading and writing. If that ** fails, try opening it read-only. If the file does not exist, ** try to create it. ** @@ -681,48 +422,45 @@ ** SQLITE_OK. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id and *pReadonly unchanged. */ -int sqlite3UnixOpenReadWrite( +int sqlite3OsOpenReadWrite( const char *zFilename, - OsFile **pId, + OsFile *id, int *pReadonly ){ int rc; - unixFile f; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly); - assert( 0==*pId ); - f.dirfd = -1; - SET_THREADID(&f); - f.h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, - SQLITE_DEFAULT_FILE_PERMISSIONS); - if( f.h<0 ){ + assert( !id->isOpen ); + id->dirfd = -1; + id->h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644); + if( id->h<0 ){ #ifdef EISDIR if( errno==EISDIR ){ return SQLITE_CANTOPEN; } #endif - f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); - if( f.h<0 ){ + id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); + if( id->h<0 ){ return SQLITE_CANTOPEN; } *pReadonly = 1; }else{ *pReadonly = 0; } sqlite3OsEnterMutex(); - rc = findLockInfo(f.h, &f.pLock, &f.pOpen); + rc = findLockInfo(id->h, &id->pLock, &id->pOpen); sqlite3OsLeaveMutex(); if( rc ){ - close(f.h); + close(id->h); return SQLITE_NOMEM; } - f.locktype = 0; - TRACE3("OPEN %-3d %s\n", f.h, zFilename); - return allocateUnixFile(&f, pId); + id->locktype = 0; + id->isOpen = 1; + TRACE3("OPEN %-3d %s\n", id->h, zFilename); + OpenCounter(+1); + return SQLITE_OK; } /* ** Attempt to open a new file for exclusive access by this process. @@ -736,73 +474,67 @@ ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ -int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ +int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ int rc; - unixFile f; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag); - assert( 0==*pId ); + assert( !id->isOpen ); if( access(zFilename, 0)==0 ){ return SQLITE_CANTOPEN; } - SET_THREADID(&f); - f.dirfd = -1; - f.h = open(zFilename, - O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, - SQLITE_DEFAULT_FILE_PERMISSIONS); - if( f.h<0 ){ + id->dirfd = -1; + id->h = open(zFilename, + O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600); + if( id->h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); - rc = findLockInfo(f.h, &f.pLock, &f.pOpen); + rc = findLockInfo(id->h, &id->pLock, &id->pOpen); sqlite3OsLeaveMutex(); if( rc ){ - close(f.h); + close(id->h); unlink(zFilename); return SQLITE_NOMEM; } - f.locktype = 0; + id->locktype = 0; + id->isOpen = 1; if( delFlag ){ unlink(zFilename); } - TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename); - return allocateUnixFile(&f, pId); + TRACE3("OPEN-EX %-3d %s\n", id->h, zFilename); + OpenCounter(+1); + return SQLITE_OK; } /* ** Attempt to open a new file for read-only access. ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ -int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){ +int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ int rc; - unixFile f; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0); - assert( 0==*pId ); - SET_THREADID(&f); - f.dirfd = -1; - f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); - if( f.h<0 ){ + assert( !id->isOpen ); + id->dirfd = -1; + id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); + if( id->h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); - rc = findLockInfo(f.h, &f.pLock, &f.pOpen); + rc = findLockInfo(id->h, &id->pLock, &id->pOpen); sqlite3OsLeaveMutex(); if( rc ){ - close(f.h); + close(id->h); return SQLITE_NOMEM; } - f.locktype = 0; - TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename); - - return allocateUnixFile(&f, pId); + id->locktype = 0; + id->isOpen = 1; + TRACE3("OPEN-RO %-3d %s\n", id->h, zFilename); + OpenCounter(+1); + return SQLITE_OK; } /* ** Attempt to open a file descriptor for the directory that contains a ** file. This file descriptor can be used to fsync() the directory @@ -810,51 +542,47 @@ ** to disk. ** ** This routine is only meaningful for Unix. It is a no-op under ** windows since windows does not support hard links. ** -** On success, a handle for a previously open file at *id is +** On success, a handle for a previously open file is at *id is ** updated with the new directory file descriptor and SQLITE_OK is ** returned. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id unchanged. */ -static int unixOpenDirectory( - OsFile *id, - const char *zDirname +int sqlite3OsOpenDirectory( + const char *zDirname, + OsFile *id ){ - unixFile *pFile = (unixFile*)id; - if( pFile==0 ){ + if( !id->isOpen ){ /* Do not open the directory if the corresponding file is not already ** open. */ return SQLITE_CANTOPEN; } - SET_THREADID(pFile); - assert( pFile->dirfd<0 ); - pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); - if( pFile->dirfd<0 ){ + assert( id->dirfd<0 ); + id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644); + if( id->dirfd<0 ){ return SQLITE_CANTOPEN; } - TRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname); + TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname); return SQLITE_OK; } /* ** If the following global variable points to a string which is the ** name of a directory, then that directory will be used to store ** temporary files. -** -** See also the "PRAGMA temp_store_directory" SQL command. */ char *sqlite3_temp_directory = 0; /* ** Create a temporary file name in zBuf. zBuf must be big enough to ** hold at least SQLITE_TEMPNAME_SIZE characters. */ -int sqlite3UnixTempFileName(char *zBuf){ +int sqlite3OsTempFileName(char *zBuf){ static const char *azDirs[] = { 0, "/var/tmp", "/usr/tmp", "/tmp", @@ -886,40 +614,39 @@ zBuf[j] = 0; }while( access(zBuf,0)==0 ); return SQLITE_OK; } +#ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Check that a given pathname is a directory and is writable ** */ -int sqlite3UnixIsDirWritable(char *zBuf){ -#ifndef SQLITE_OMIT_PAGER_PRAGMAS +int sqlite3OsIsDirWritable(char *zBuf){ struct stat buf; if( zBuf==0 ) return 0; if( zBuf[0]==0 ) return 0; if( stat(zBuf, &buf) ) return 0; if( !S_ISDIR(buf.st_mode) ) return 0; if( access(zBuf, 07) ) return 0; -#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ return 1; } +#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ -static int unixRead(OsFile *id, void *pBuf, int amt){ +int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ int got; - assert( id ); + assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); TIMER_START; - got = read(((unixFile*)id)->h, pBuf, amt); + got = read(id->h, pBuf, amt); TIMER_END; - TRACE5("READ %-3d %5d %7d %d\n", ((unixFile*)id)->h, got, - last_page, TIMER_ELAPSED); + TRACE4("READ %-3d %7d %d\n", id->h, last_page, TIMER_ELAPSED); SEEK(0); /* if( got<0 ) got = 0; */ if( got==amt ){ return SQLITE_OK; }else{ @@ -929,24 +656,23 @@ /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ -static int unixWrite(OsFile *id, const void *pBuf, int amt){ +int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ int wrote = 0; - assert( id ); + assert( id->isOpen ); assert( amt>0 ); SimulateIOError(SQLITE_IOERR); SimulateDiskfullError; TIMER_START; - while( amt>0 && (wrote = write(((unixFile*)id)->h, pBuf, amt))>0 ){ + while( amt>0 && (wrote = write(id->h, pBuf, amt))>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } TIMER_END; - TRACE5("WRITE %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote, - last_page, TIMER_ELAPSED); + TRACE4("WRITE %-3d %7d %d\n", id->h, last_page, TIMER_ELAPSED); SEEK(0); if( amt>0 ){ return SQLITE_FULL; } return SQLITE_OK; @@ -953,37 +679,16 @@ } /* ** Move the read/write pointer in a file. */ -static int unixSeek(OsFile *id, i64 offset){ - assert( id ); +int sqlite3OsSeek(OsFile *id, i64 offset){ + assert( id->isOpen ); SEEK(offset/1024 + 1); -#ifdef SQLITE_TEST - if( offset ) SimulateDiskfullError -#endif - lseek(((unixFile*)id)->h, offset, SEEK_SET); + lseek(id->h, offset, SEEK_SET); return SQLITE_OK; } - -#ifdef SQLITE_TEST -/* -** Count the number of fullsyncs and normal syncs. This is used to test -** that syncs and fullsyncs are occuring at the right times. -*/ -int sqlite3_sync_count = 0; -int sqlite3_fullsync_count = 0; -#endif - -/* -** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined. -** Otherwise use fsync() in its place. -*/ -#ifndef HAVE_FDATASYNC -# define fdatasync fsync -#endif - /* ** The fsync() system call does not work as advertised on many ** unix systems. The following procedure is an attempt to make ** it work better. @@ -992,129 +697,87 @@ ** for testing when we want to run through the test suite quickly. ** You are strongly advised *not* to deploy with SQLITE_NO_SYNC ** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash ** or power failure will likely corrupt the database file. */ -static int full_fsync(int fd, int fullSync, int dataOnly){ +static int full_fsync(int fd){ +#ifdef SQLITE_NO_SYNC + return SQLITE_OK; +#else int rc; - - /* Record the number of times that we do a normal fsync() and - ** FULLSYNC. This is used during testing to verify that this procedure - ** gets called with the correct arguments. - */ -#ifdef SQLITE_TEST - if( fullSync ) sqlite3_fullsync_count++; - sqlite3_sync_count++; -#endif - - /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a - ** no-op - */ -#ifdef SQLITE_NO_SYNC - rc = SQLITE_OK; +#ifdef F_FULLFSYNC + rc = fcntl(fd, F_FULLFSYNC, 0); + if( rc ) rc = fsync(fd); #else - -#ifdef F_FULLFSYNC - if( fullSync ){ - rc = fcntl(fd, F_FULLFSYNC, 0); - }else{ - rc = 1; - } - /* If the FULLSYNC failed, try to do a normal fsync() */ - if( rc ) rc = fsync(fd); - -#else /* if !defined(F_FULLSYNC) */ - if( dataOnly ){ - rc = fdatasync(fd); - }else{ - rc = fsync(fd); - } -#endif /* defined(F_FULLFSYNC) */ -#endif /* defined(SQLITE_NO_SYNC) */ - + rc = fsync(fd); +#endif return rc; +#endif } /* ** Make sure all writes to a particular file are committed to disk. ** -** If dataOnly==0 then both the file itself and its metadata (file -** size, access time, etc) are synced. If dataOnly!=0 then only the -** file data is synced. -** ** Under Unix, also make sure that the directory entry for the file ** has been created by fsync-ing the directory that contains the file. ** If we do not do this and we encounter a power failure, the directory ** entry for the journal might not exist after we reboot. The next ** SQLite to access the file will not know that the journal exists (because ** the directory entry for the journal was never created) and the transaction ** will not roll back - possibly leading to database corruption. */ -static int unixSync(OsFile *id, int dataOnly){ - unixFile *pFile = (unixFile*)id; - assert( pFile ); - SimulateIOError(SQLITE_IOERR); - TRACE2("SYNC %-3d\n", pFile->h); - if( full_fsync(pFile->h, pFile->fullSync, dataOnly) ){ - return SQLITE_IOERR; - } - if( pFile->dirfd>=0 ){ - TRACE2("DIRSYNC %-3d\n", pFile->dirfd); -#ifndef SQLITE_DISABLE_DIRSYNC - if( full_fsync(pFile->dirfd, pFile->fullSync, 0) ){ - return SQLITE_IOERR; - } -#endif - close(pFile->dirfd); /* Only need to sync once, so close the directory */ - pFile->dirfd = -1; /* when we are done. */ +int sqlite3OsSync(OsFile *id){ + assert( id->isOpen ); + SimulateIOError(SQLITE_IOERR); + TRACE2("SYNC %-3d\n", id->h); + if( full_fsync(id->h) ){ + return SQLITE_IOERR; + } + if( id->dirfd>=0 ){ + TRACE2("DIRSYNC %-3d\n", id->dirfd); + full_fsync(id->dirfd); + close(id->dirfd); /* Only need to sync once, so close the directory */ + id->dirfd = -1; /* when we are done. */ } return SQLITE_OK; } /* ** Sync the directory zDirname. This is a no-op on operating systems other ** than UNIX. -** -** This is used to make sure the master journal file has truely been deleted -** before making changes to individual journals on a multi-database commit. -** The F_FULLFSYNC option is not needed here. */ -int sqlite3UnixSyncDirectory(const char *zDirname){ -#ifdef SQLITE_DISABLE_DIRSYNC - return SQLITE_OK; -#else +int sqlite3OsSyncDirectory(const char *zDirname){ int fd; int r; SimulateIOError(SQLITE_IOERR); - fd = open(zDirname, O_RDONLY|O_BINARY, 0); + fd = open(zDirname, O_RDONLY|O_BINARY, 0644); TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname); if( fd<0 ){ return SQLITE_CANTOPEN; } r = fsync(fd); close(fd); return ((r==0)?SQLITE_OK:SQLITE_IOERR); -#endif } /* ** Truncate an open file to a specified size */ -static int unixTruncate(OsFile *id, i64 nByte){ - assert( id ); +int sqlite3OsTruncate(OsFile *id, i64 nByte){ + assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); - return ftruncate(((unixFile*)id)->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR; + return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR; } /* ** Determine the current size of a file in bytes */ -static int unixFileSize(OsFile *id, i64 *pSize){ +int sqlite3OsFileSize(OsFile *id, i64 *pSize){ struct stat buf; - assert( id ); + assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); - if( fstat(((unixFile*)id)->h, &buf)!=0 ){ + if( fstat(id->h, &buf)!=0 ){ return SQLITE_IOERR; } *pSize = buf.st_size; return SQLITE_OK; } @@ -1123,19 +786,18 @@ ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */ -static int unixCheckReservedLock(OsFile *id){ +int sqlite3OsCheckReservedLock(OsFile *id){ int r = 0; - unixFile *pFile = (unixFile*)id; - assert( pFile ); - sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */ + assert( id->isOpen ); + sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ - if( pFile->pLock->locktype>SHARED_LOCK ){ + if( id->pLock->locktype>SHARED_LOCK ){ r = 1; } /* Otherwise see if some other process holds it. */ @@ -1143,21 +805,39 @@ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = RESERVED_BYTE; lock.l_len = 1; lock.l_type = F_WRLCK; - fcntl(pFile->h, F_GETLK, &lock); + fcntl(id->h, F_GETLK, &lock); if( lock.l_type!=F_UNLCK ){ r = 1; } } sqlite3OsLeaveMutex(); - TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); + TRACE3("TEST WR-LOCK %d %d\n", id->h, r); return r; } + +#ifdef SQLITE_DEBUG +/* +** Helper function for printing out trace information from debugging +** binaries. This returns the string represetation of the supplied +** integer lock-type. +*/ +static const char * locktypeName(int locktype){ + switch( locktype ){ + case NO_LOCK: return "NONE"; + case SHARED_LOCK: return "SHARED"; + case RESERVED_LOCK: return "RESERVED"; + case PENDING_LOCK: return "PENDING"; + case EXCLUSIVE_LOCK: return "EXCLUSIVE"; + } + return "ERROR"; +} +#endif /* ** Lock the file with the lock specified by parameter locktype - one ** of the following: ** @@ -1179,11 +859,11 @@ ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ -static int unixLock(OsFile *id, int locktype){ +int sqlite3OsLock(OsFile *id, int locktype){ /* The following describes the implementation of the various locks and ** lock transitions in terms of the POSIX advisory shared and exclusive ** lock primitives (called read-locks and write-locks below, to avoid ** confusion with SQLite lock names). The algorithms are complicated ** slightly in order to be compatible with windows systems simultaneously @@ -1219,53 +899,42 @@ ** range' is that some versions of windows do not support read-locks. By ** locking a random byte from a range, concurrent SHARED locks may exist ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; - unixFile *pFile = (unixFile*)id; - struct lockInfo *pLock = pFile->pLock; + struct lockInfo *pLock = id->pLock; struct flock lock; int s; - assert( pFile ); - TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h, - locktypeName(locktype), locktypeName(pFile->locktype), - locktypeName(pLock->locktype), pLock->cnt , getpid()); + assert( id->isOpen ); + TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype), + locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt + ,getpid() ); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ - if( pFile->locktype>=locktype ){ - TRACE3("LOCK %d %s ok (already held)\n", pFile->h, - locktypeName(locktype)); + if( id->locktype>=locktype ){ + TRACE3("LOCK %d %s ok (already held)\n", id->h, locktypeName(locktype)); return SQLITE_OK; } /* Make sure the locking sequence is correct */ - assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); + assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); - assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); + assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK ); - /* This mutex is needed because pFile->pLock is shared across threads + /* This mutex is needed because id->pLock is shared across threads */ sqlite3OsEnterMutex(); - /* Make sure the current thread owns the pFile. - */ - rc = transferOwnership(pFile); - if( rc!=SQLITE_OK ){ - sqlite3OsLeaveMutex(); - return rc; - } - pLock = pFile->pLock; - /* If some thread using this PID has a lock via a different OsFile* ** handle that precludes the requested lock, return BUSY. */ - if( (pFile->locktype!=pLock->locktype && + if( (id->locktype!=pLock->locktype && (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK)) ){ rc = SQLITE_BUSY; goto end_lock; } @@ -1275,32 +944,31 @@ ** return SQLITE_OK. */ if( locktype==SHARED_LOCK && (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){ assert( locktype==SHARED_LOCK ); - assert( pFile->locktype==0 ); + assert( id->locktype==0 ); assert( pLock->cnt>0 ); - pFile->locktype = SHARED_LOCK; + id->locktype = SHARED_LOCK; pLock->cnt++; - pFile->pOpen->nLock++; + id->pOpen->nLock++; goto end_lock; } lock.l_len = 1L; - lock.l_whence = SEEK_SET; /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ if( locktype==SHARED_LOCK - || (locktype==EXCLUSIVE_LOCK && pFile->locktypelocktypeh, F_SETLK, &lock); + s = fcntl(id->h, F_SETLK, &lock); if( s ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; goto end_lock; } } @@ -1314,25 +982,22 @@ assert( pLock->locktype==0 ); /* Now get the read-lock */ lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - s = fcntl(pFile->h, F_SETLK, &lock); + s = fcntl(id->h, F_SETLK, &lock); /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; - if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ - rc = SQLITE_IOERR; /* This should never happen */ - goto end_lock; - } + fcntl(id->h, F_SETLK, &lock); if( s ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; }else{ - pFile->locktype = SHARED_LOCK; - pFile->pOpen->nLock++; + id->locktype = SHARED_LOCK; + id->pOpen->nLock++; pLock->cnt = 1; } }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ @@ -1340,11 +1005,11 @@ }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file ** already. */ - assert( 0!=pFile->locktype ); + assert( 0!=id->locktype ); lock.l_type = F_WRLCK; switch( locktype ){ case RESERVED_LOCK: lock.l_start = RESERVED_BYTE; break; @@ -1353,79 +1018,76 @@ lock.l_len = SHARED_SIZE; break; default: assert(0); } - s = fcntl(pFile->h, F_SETLK, &lock); + s = fcntl(id->h, F_SETLK, &lock); if( s ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; } } if( rc==SQLITE_OK ){ - pFile->locktype = locktype; + id->locktype = locktype; pLock->locktype = locktype; }else if( locktype==EXCLUSIVE_LOCK ){ - pFile->locktype = PENDING_LOCK; + id->locktype = PENDING_LOCK; pLock->locktype = PENDING_LOCK; } end_lock: sqlite3OsLeaveMutex(); - TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), + TRACE4("LOCK %d %s %s\n", id->h, locktypeName(locktype), rc==SQLITE_OK ? "ok" : "failed"); return rc; } /* -** Lower the locking level on file descriptor pFile to locktype. locktype +** Lower the locking level on file descriptor id to locktype. locktype ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. +** +** It is not possible for this routine to fail if the second argument +** is NO_LOCK. If the second argument is SHARED_LOCK, this routine +** might return SQLITE_IOERR instead of SQLITE_OK. */ -static int unixUnlock(OsFile *id, int locktype){ +int sqlite3OsUnlock(OsFile *id, int locktype){ struct lockInfo *pLock; struct flock lock; int rc = SQLITE_OK; - unixFile *pFile = (unixFile*)id; - assert( pFile ); - TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype, - pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid()); + assert( id->isOpen ); + TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype, + id->pLock->locktype, id->pLock->cnt, getpid()); assert( locktype<=SHARED_LOCK ); - if( pFile->locktype<=locktype ){ + if( id->locktype<=locktype ){ return SQLITE_OK; } - if( CHECK_THREADID(pFile) ){ - return SQLITE_MISUSE; - } sqlite3OsEnterMutex(); - pLock = pFile->pLock; + pLock = id->pLock; assert( pLock->cnt!=0 ); - if( pFile->locktype>SHARED_LOCK ){ - assert( pLock->locktype==pFile->locktype ); + if( id->locktype>SHARED_LOCK ){ + assert( pLock->locktype==id->locktype ); if( locktype==SHARED_LOCK ){ lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ + if( fcntl(id->h, F_SETLK, &lock)!=0 ){ /* This should never happen */ rc = SQLITE_IOERR; } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); - if( fcntl(pFile->h, F_SETLK, &lock)==0 ){ - pLock->locktype = SHARED_LOCK; - }else{ - rc = SQLITE_IOERR; /* This should never happen */ - } + fcntl(id->h, F_SETLK, &lock); + pLock->locktype = SHARED_LOCK; } if( locktype==NO_LOCK ){ struct openCnt *pOpen; /* Decrement the shared lock counter. Release the lock using an @@ -1435,210 +1097,99 @@ pLock->cnt--; if( pLock->cnt==0 ){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; - if( fcntl(pFile->h, F_SETLK, &lock)==0 ){ - pLock->locktype = NO_LOCK; - }else{ - rc = SQLITE_IOERR; /* This should never happen */ - } + fcntl(id->h, F_SETLK, &lock); + pLock->locktype = NO_LOCK; } /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ - pOpen = pFile->pOpen; + pOpen = id->pOpen; pOpen->nLock--; assert( pOpen->nLock>=0 ); if( pOpen->nLock==0 && pOpen->nPending>0 ){ int i; for(i=0; inPending; i++){ close(pOpen->aPending[i]); } - free(pOpen->aPending); + sqliteFree(pOpen->aPending); pOpen->nPending = 0; pOpen->aPending = 0; } } sqlite3OsLeaveMutex(); - pFile->locktype = locktype; + id->locktype = locktype; return rc; } /* ** Close a file. */ -static int unixClose(OsFile **pId){ - unixFile *id = (unixFile*)*pId; - int rc; - - if( !id ) return SQLITE_OK; - unixUnlock(*pId, NO_LOCK); +int sqlite3OsClose(OsFile *id){ + if( !id->isOpen ) return SQLITE_OK; + sqlite3OsUnlock(id, NO_LOCK); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqlite3OsEnterMutex(); - if( id->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pOpen->aPending. It will be automatically closed when ** the last lock is cleared. */ int *aNew; struct openCnt *pOpen = id->pOpen; - aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) ); + pOpen->nPending++; + aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) ); if( aNew==0 ){ /* If a malloc fails, just leak the file descriptor */ }else{ pOpen->aPending = aNew; - pOpen->aPending[pOpen->nPending] = id->h; - pOpen->nPending++; + pOpen->aPending[pOpen->nPending-1] = id->h; } }else{ /* There are no outstanding locks so we can close the file immediately */ close(id->h); } releaseLockInfo(id->pLock); releaseOpenCnt(id->pOpen); - sqlite3OsLeaveMutex(); id->isOpen = 0; TRACE2("CLOSE %-3d\n", id->h); OpenCounter(-1); - sqliteFree(id); - *pId = 0; - return rc; -} - -/* -** Turn a relative pathname into a full pathname. Return a pointer -** to the full pathname stored in space obtained from sqliteMalloc(). -** The calling function is responsible for freeing this space once it -** is no longer needed. -*/ -char *sqlite3UnixFullPathname(const char *zRelative){ - char *zFull = 0; - if( zRelative[0]=='/' ){ - sqlite3SetString(&zFull, zRelative, (char*)0); - }else{ - char *zBuf = sqliteMalloc(5000); - if( zBuf==0 ){ - return 0; - } - zBuf[0] = 0; - sqlite3SetString(&zFull, getcwd(zBuf, 5000), "/", zRelative, - (char*)0); - sqliteFree(zBuf); - } - return zFull; -} - -/* -** Change the value of the fullsync flag in the given file descriptor. -*/ -static void unixSetFullSync(OsFile *id, int v){ - ((unixFile*)id)->fullSync = v; -} - -/* -** Return the underlying file handle for an OsFile -*/ -static int unixFileHandle(OsFile *id){ - return ((unixFile*)id)->h; -} - -/* -** Return an integer that indices the type of lock currently held -** by this handle. (Used for testing and analysis only.) -*/ -static int unixLockState(OsFile *id){ - return ((unixFile*)id)->locktype; -} - -/* -** This vector defines all the methods that can operate on an OsFile -** for unix. -*/ -static const IoMethod sqlite3UnixIoMethod = { - unixClose, - unixOpenDirectory, - unixRead, - unixWrite, - unixSeek, - unixTruncate, - unixSync, - unixSetFullSync, - unixFileHandle, - unixFileSize, - unixLock, - unixUnlock, - unixLockState, - unixCheckReservedLock, -}; - -/* -** Allocate memory for a unixFile. Initialize the new unixFile -** to the value given in pInit and return a pointer to the new -** OsFile. If we run out of memory, close the file and return NULL. -*/ -static int allocateUnixFile(unixFile *pInit, OsFile **pId){ - unixFile *pNew; - pNew = sqliteMalloc( sizeof(unixFile) ); - if( pNew==0 ){ - close(pInit->h); - sqlite3OsEnterMutex(); - releaseLockInfo(pInit->pLock); - releaseOpenCnt(pInit->pOpen); - sqlite3OsLeaveMutex(); - *pId = 0; - return SQLITE_NOMEM; - }else{ - *pNew = *pInit; - pNew->pMethod = &sqlite3UnixIoMethod; - *pId = (OsFile*)pNew; - OpenCounter(+1); - return SQLITE_OK; - } -} - - -#endif /* SQLITE_OMIT_DISKIO */ -/*************************************************************************** -** Everything above deals with file I/O. Everything that follows deals -** with other miscellanous aspects of the operating system interface -****************************************************************************/ - + return SQLITE_OK; +} /* ** Get information to seed the random number generator. The seed ** is written into the buffer zBuf[256]. The calling function must ** supply a sufficiently large buffer. */ -int sqlite3UnixRandomSeed(char *zBuf){ +int sqlite3OsRandomSeed(char *zBuf){ /* We have to initialize zBuf to prevent valgrind from reporting ** errors. The reports issued by valgrind are incorrect - we would ** prefer that the randomness be increased by making use of the ** uninitialized space in zBuf - but valgrind errors tend to worry ** some users. Rather than argue, it seems easier just to initialize ** the whole array and silence valgrind, even if that means less randomness ** in the random seed. ** ** When testing, initializing zBuf[] to zero is all we do. That means - ** that we always use the same random number sequence. This makes the + ** that we always use the same random number sequence.* This makes the ** tests repeatable. */ memset(zBuf, 0, 256); #if !defined(SQLITE_TEST) { int pid, fd; fd = open("/dev/urandom", O_RDONLY); if( fd<0 ){ - time_t t; - time(&t); - memcpy(zBuf, &t, sizeof(t)); + time((time_t*)zBuf); pid = getpid(); memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid)); }else{ read(fd, zBuf, 256); close(fd); @@ -1648,13 +1199,12 @@ return SQLITE_OK; } /* ** Sleep for a little while. Return the amount of time slept. -** The argument is the number of milliseconds we want to sleep. */ -int sqlite3UnixSleep(int ms){ +int sqlite3OsSleep(int ms){ #if defined(HAVE_USLEEP) && HAVE_USLEEP usleep(ms*1000); return ms; #else sleep((ms+999)/1000); @@ -1675,127 +1225,42 @@ ** multi-threaded processes. Only a single thread is allowed to ** executed code that is surrounded by EnterMutex() and LeaveMutex(). ** ** SQLite uses only a single Mutex. There is not much critical ** code and what little there is executes quickly and without blocking. -** -** This mutex is not recursive. */ -void sqlite3UnixEnterMutex(){ +void sqlite3OsEnterMutex(){ #ifdef SQLITE_UNIX_THREADS pthread_mutex_lock(&mutex); #endif assert( !inMutex ); inMutex = 1; } -void sqlite3UnixLeaveMutex(){ +void sqlite3OsLeaveMutex(){ assert( inMutex ); inMutex = 0; #ifdef SQLITE_UNIX_THREADS pthread_mutex_unlock(&mutex); #endif } /* -** Return TRUE if we are currently within the mutex and FALSE if not. -*/ -int sqlite3UnixInMutex(){ - return inMutex; -} - -/* -** Remember the number of thread-specific-data blocks allocated. -** Use this to verify that we are not leaking thread-specific-data. -** Ticket #1601 -*/ -#ifdef SQLITE_TEST -int sqlite3_tsd_count = 0; -# ifdef SQLITE_UNIX_THREADS - static pthread_mutex_t tsd_counter_mutex = PTHREAD_MUTEX_INITIALIZER; -# define TSD_COUNTER(N) \ - pthread_mutex_lock(&tsd_counter_mutex); \ - sqlite3_tsd_count += N; \ - pthread_mutex_unlock(&tsd_counter_mutex); -# else -# define TSD_COUNTER(N) sqlite3_tsd_count += N -# endif -#else -# define TSD_COUNTER(N) /* no-op */ -#endif - - -/* -** If called with allocateFlag>0, then return a pointer to thread -** specific data for the current thread. Allocate and zero the -** thread-specific data if it does not already exist. -** -** If called with allocateFlag==0, then check the current thread -** specific data. Return it if it exists. If it does not exist, -** then return NULL. -** -** If called with allocateFlag<0, check to see if the thread specific -** data is allocated and is all zero. If it is then deallocate it. -** Return a pointer to the thread specific data or NULL if it is -** unallocated or gets deallocated. -*/ -ThreadData *sqlite3UnixThreadSpecificData(int allocateFlag){ - static const ThreadData zeroData; -#ifdef SQLITE_UNIX_THREADS - static pthread_key_t key; - static int keyInit = 0; - ThreadData *pTsd; - - if( !keyInit ){ - sqlite3OsEnterMutex(); - if( !keyInit ){ - int rc; - rc = pthread_key_create(&key, 0); - if( rc ){ - sqlite3OsLeaveMutex(); - return 0; - } - keyInit = 1; - } - sqlite3OsLeaveMutex(); - } - - pTsd = pthread_getspecific(key); - if( allocateFlag>0 ){ - if( pTsd==0 ){ - pTsd = sqlite3OsMalloc(sizeof(zeroData)); - if( pTsd ){ - *pTsd = zeroData; - pthread_setspecific(key, pTsd); - TSD_COUNTER(+1); - } - } - }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){ - sqlite3OsFree(pTsd); - pthread_setspecific(key, 0); - TSD_COUNTER(-1); - pTsd = 0; - } - return pTsd; -#else - static ThreadData *pTsd = 0; - if( allocateFlag>0 ){ - if( pTsd==0 ){ - pTsd = sqlite3OsMalloc( sizeof(zeroData) ); - if( pTsd ){ - *pTsd = zeroData; - TSD_COUNTER(+1); - } - } - }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){ - sqlite3OsFree(pTsd); - TSD_COUNTER(-1); - pTsd = 0; - } - return pTsd; -#endif +** Turn a relative pathname into a full pathname. Return a pointer +** to the full pathname stored in space obtained from sqliteMalloc(). +** The calling function is responsible for freeing this space once it +** is no longer needed. +*/ +char *sqlite3OsFullPathname(const char *zRelative){ + char *zFull = 0; + if( zRelative[0]=='/' ){ + sqlite3SetString(&zFull, zRelative, (char*)0); + }else{ + char zBuf[5000]; + sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative, + (char*)0); + } + return zFull; } /* ** The following variable, if set to a non-zero value, becomes the result ** returned from sqlite3OsCurrentTime(). This is used for testing. @@ -1807,25 +1272,38 @@ /* ** Find the current time (in Universal Coordinated Time). Write the ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int sqlite3UnixCurrentTime(double *prNow){ -#ifdef NO_GETTOD +int sqlite3OsCurrentTime(double *prNow){ time_t t; time(&t); *prNow = t/86400.0 + 2440587.5; -#else - struct timeval sNow; - struct timezone sTz; /* Not used */ - gettimeofday(&sNow, &sTz); - *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0; -#endif #ifdef SQLITE_TEST if( sqlite3_current_time ){ *prNow = sqlite3_current_time/86400.0 + 2440587.5; } #endif return 0; } +#if 0 /* NOT USED */ +/* +** Find the time that the file was last modified. Write the +** modification time and date as a Julian Day number into *prNow and +** return SQLITE_OK. Return SQLITE_ERROR if the modification +** time cannot be found. +*/ +int sqlite3OsFileModTime(OsFile *id, double *prNow){ + int rc; + struct stat statbuf; + if( fstat(id->h, &statbuf)==0 ){ + *prNow = statbuf.st_mtime/86400.0 + 2440587.5; + rc = SQLITE_OK; + }else{ + rc = SQLITE_ERROR; + } + return rc; +} +#endif /* NOT USED */ + #endif /* OS_UNIX */ ADDED SQLite.Interop/src/os_unix.h Index: SQLite.Interop/src/os_unix.h ================================================================== --- /dev/null +++ SQLite.Interop/src/os_unix.h @@ -0,0 +1,89 @@ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file defined OS-specific features for Unix. +*/ +#ifndef _SQLITE_OS_UNIX_H_ +#define _SQLITE_OS_UNIX_H_ + +/* +** Helpful hint: To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE +** to the compiler command line. +*/ + +/* +** These #defines should enable >2GB file support on Posix if the +** underlying operating system supports it. If the OS lacks +** large file support, or if the OS is windows, these should be no-ops. +** +** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch +** on the compiler command line. This is necessary if you are compiling +** on a recent machine (ex: RedHat 7.2) but you want your code to work +** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 +** without this option, LFS is enable. But LFS does not exist in the kernel +** in RedHat 6.0, so the code won't work. Hence, for maximum binary +** portability you should omit LFS. +** +** Similar is true for MacOS. LFS is only supported on MacOS 9 and later. +*/ +#ifndef SQLITE_DISABLE_LFS +# define _LARGE_FILE 1 +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# define _LARGEFILE_SOURCE 1 +#endif + +/* +** standard include files. +*/ +#include +#include +#include +#include + +/* +** The OsFile structure is a operating-system independing representation +** of an open file handle. It is defined differently for each architecture. +** +** This is the definition for Unix. +** +** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK, +** PENDING_LOCK or EXCLUSIVE_LOCK. +*/ +typedef struct OsFile OsFile; +struct OsFile { + struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */ + struct openCnt *pOpen; /* Info about all open fd's on this inode */ + struct lockInfo *pLock; /* Info about locks on this inode */ + int h; /* The file descriptor */ + unsigned char locktype; /* The type of lock held on this fd */ + unsigned char isOpen; /* True if needs to be closed */ + int dirfd; /* File descriptor for the directory */ +}; + +/* +** Maximum number of characters in a temporary file name +*/ +#define SQLITE_TEMPNAME_SIZE 200 + +/* +** Minimum interval supported by sqlite3OsSleep(). +*/ +#if defined(HAVE_USLEEP) && HAVE_USLEEP +# define SQLITE_MIN_SLEEP_MS 1 +#else +# define SQLITE_MIN_SLEEP_MS 1000 +#endif + + +#endif /* _SQLITE_OS_UNIX_H_ */ Index: SQLite.Interop/src/os_win.c ================================================================== --- SQLite.Interop/src/os_win.c +++ SQLite.Interop/src/os_win.c @@ -16,14 +16,10 @@ #include "os.h" #if OS_WIN /* This file is used for windows only */ #include -#ifdef __CYGWIN__ -# include -#endif - /* ** Macros used to determine whether or not to use threads. */ #if defined(THREADSAFE) && THREADSAFE # define SQLITE_W32_THREADS 1 @@ -32,491 +28,25 @@ /* ** Include code that is common to all os_*.c files */ #include "os_common.h" -/* -** Determine if we are dealing with WindowsCE - which has a much -** reduced API. -*/ -#if defined(_WIN32_WCE) -# define OS_WINCE 1 -#else -# define OS_WINCE 0 -#endif - -/* -** WinCE lacks native support for file locking so we have to fake it -** with some code of our own. -*/ -#if OS_WINCE -typedef struct winceLock { - int nReaders; /* Number of reader locks obtained */ - BOOL bPending; /* Indicates a pending lock has been obtained */ - BOOL bReserved; /* Indicates a reserved lock has been obtained */ - BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ -} winceLock; -#endif - -/* -** The winFile structure is a subclass of OsFile specific to the win32 -** portability layer. -*/ -typedef struct winFile winFile; -struct winFile { - IoMethod const *pMethod;/* Must be first */ - HANDLE h; /* Handle for accessing the file */ - unsigned char locktype; /* Type of lock currently held on this file */ - short sharedLockByte; /* Randomly chosen byte used as a shared lock */ -#if OS_WINCE - WCHAR *zDeleteOnClose; /* Name of file to delete when closing */ - HANDLE hMutex; /* Mutex used to control access to shared lock */ - HANDLE hShared; /* Shared memory segment used for locking */ - winceLock local; /* Locks obtained by this instance of winFile */ - winceLock *shared; /* Global shared lock memory for the file */ -#endif -}; - - -/* -** Do not include any of the File I/O interface procedures if the -** SQLITE_OMIT_DISKIO macro is defined (indicating that there database -** will be in-memory only) -*/ -#ifndef SQLITE_OMIT_DISKIO - -/* -** The following variable is (normally) set once and never changes -** thereafter. It records whether the operating system is Win95 -** or WinNT. -** -** 0: Operating system unknown. -** 1: Operating system is Win95. -** 2: Operating system is WinNT. -** -** In order to facilitate testing on a WinNT system, the test fixture -** can manually set this value to 1 to emulate Win98 behavior. -*/ -int sqlite3_os_type = 0; - -/* -** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, -** or WinCE. Return false (zero) for Win95, Win98, or WinME. -** -** Here is an interesting observation: Win95, Win98, and WinME lack -** the LockFileEx() API. But we can still statically link against that -** API as long as we don't call it win running Win95/98/ME. A call to -** this routine is used to determine if the host is Win95/98/ME or -** WinNT/2K/XP so that we will know whether or not we can safely call -** the LockFileEx() API. -*/ -#if OS_WINCE -# define isNT() (1) -#else - static int isNT(void){ - if( sqlite3_os_type==0 ){ - OSVERSIONINFO sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - GetVersionEx(&sInfo); - sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; - } - return sqlite3_os_type==2; - } -#endif /* OS_WINCE */ - -/* -** Convert a UTF-8 string to UTF-32. Space to hold the returned string -** is obtained from sqliteMalloc. -*/ -static WCHAR *utf8ToUnicode(const char *zFilename){ - int nByte; - WCHAR *zWideFilename; - - if( !isNT() ){ - return 0; - } - nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0)*sizeof(WCHAR); - zWideFilename = sqliteMalloc( nByte*sizeof(zWideFilename[0]) ); - if( zWideFilename==0 ){ - return 0; - } - nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nByte); - if( nByte==0 ){ - sqliteFree(zWideFilename); - zWideFilename = 0; - } - return zWideFilename; -} - -/* -** Convert UTF-32 to UTF-8. Space to hold the returned string is -** obtained from sqliteMalloc(). -*/ -static char *unicodeToUtf8(const WCHAR *zWideFilename){ - int nByte; - char *zFilename; - - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); - zFilename = sqliteMalloc( nByte ); - if( zFilename==0 ){ - return 0; - } - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, - 0, 0); - if( nByte == 0 ){ - sqliteFree(zFilename); - zFilename = 0; - } - return zFilename; -} - -#if OS_WINCE -/************************************************************************* -** This section contains code for WinCE only. -*/ -/* -** WindowsCE does not have a localtime() function. So create a -** substitute. -*/ -#include -struct tm *__cdecl localtime(const time_t *t) -{ - static struct tm y; - FILETIME uTm, lTm; - SYSTEMTIME pTm; - i64 t64; - t64 = *t; - t64 = (t64 + 11644473600)*10000000; - uTm.dwLowDateTime = t64 & 0xFFFFFFFF; - uTm.dwHighDateTime= t64 >> 32; - FileTimeToLocalFileTime(&uTm,&lTm); - FileTimeToSystemTime(&lTm,&pTm); - y.tm_year = pTm.wYear - 1900; - y.tm_mon = pTm.wMonth - 1; - y.tm_wday = pTm.wDayOfWeek; - y.tm_mday = pTm.wDay; - y.tm_hour = pTm.wHour; - y.tm_min = pTm.wMinute; - y.tm_sec = pTm.wSecond; - return &y; -} - -/* This will never be called, but defined to make the code compile */ -#define GetTempPathA(a,b) - -#define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e) -#define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e) -#define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f) - -#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-offsetof(winFile,h)] - -/* -** Acquire a lock on the handle h -*/ -static void winceMutexAcquire(HANDLE h){ - DWORD dwErr; - do { - dwErr = WaitForSingleObject(h, INFINITE); - } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); -} -/* -** Release a lock acquired by winceMutexAcquire() -*/ -#define winceMutexRelease(h) ReleaseMutex(h) - -/* -** Create the mutex and shared memory used for locking in the file -** descriptor pFile -*/ -static BOOL winceCreateLock(const char *zFilename, winFile *pFile){ - WCHAR *zTok; - WCHAR *zName = utf8ToUnicode(zFilename); - BOOL bInit = TRUE; - - /* Initialize the local lockdata */ - ZeroMemory(&pFile->local, sizeof(pFile->local)); - - /* Replace the backslashes from the filename and lowercase it - ** to derive a mutex name. */ - zTok = CharLowerW(zName); - for (;*zTok;zTok++){ - if (*zTok == '\\') *zTok = '_'; - } - - /* Create/open the named mutex */ - pFile->hMutex = CreateMutexW(NULL, FALSE, zName); - if (!pFile->hMutex){ - sqliteFree(zName); - return FALSE; - } - - /* Acquire the mutex before continuing */ - winceMutexAcquire(pFile->hMutex); - - /* Since the names of named mutexes, semaphores, file mappings etc are - ** case-sensitive, take advantage of that by uppercasing the mutex name - ** and using that as the shared filemapping name. - */ - CharUpperW(zName); - pFile->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, - PAGE_READWRITE, 0, sizeof(winceLock), - zName); - - /* Set a flag that indicates we're the first to create the memory so it - ** must be zero-initialized */ - if (GetLastError() == ERROR_ALREADY_EXISTS){ - bInit = FALSE; - } - - sqliteFree(zName); - - /* If we succeeded in making the shared memory handle, map it. */ - if (pFile->hShared){ - pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, - FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); - /* If mapping failed, close the shared memory handle and erase it */ - if (!pFile->shared){ - CloseHandle(pFile->hShared); - pFile->hShared = NULL; - } - } - - /* If shared memory could not be created, then close the mutex and fail */ - if (pFile->hShared == NULL){ - winceMutexRelease(pFile->hMutex); - CloseHandle(pFile->hMutex); - pFile->hMutex = NULL; - return FALSE; - } - - /* Initialize the shared memory if we're supposed to */ - if (bInit) { - ZeroMemory(pFile->shared, sizeof(winceLock)); - } - - winceMutexRelease(pFile->hMutex); - return TRUE; -} - -/* -** Destroy the part of winFile that deals with wince locks -*/ -static void winceDestroyLock(winFile *pFile){ - if (pFile->hMutex){ - /* Acquire the mutex */ - winceMutexAcquire(pFile->hMutex); - - /* The following blocks should probably assert in debug mode, but they - are to cleanup in case any locks remained open */ - if (pFile->local.nReaders){ - pFile->shared->nReaders --; - } - if (pFile->local.bReserved){ - pFile->shared->bReserved = FALSE; - } - if (pFile->local.bPending){ - pFile->shared->bPending = FALSE; - } - if (pFile->local.bExclusive){ - pFile->shared->bExclusive = FALSE; - } - - /* De-reference and close our copy of the shared memory handle */ - UnmapViewOfFile(pFile->shared); - CloseHandle(pFile->hShared); - - /* Done with the mutex */ - winceMutexRelease(pFile->hMutex); - CloseHandle(pFile->hMutex); - pFile->hMutex = NULL; - } -} - -/* -** An implementation of the LockFile() API of windows for wince -*/ -static BOOL winceLockFile( - HANDLE *phFile, - DWORD dwFileOffsetLow, - DWORD dwFileOffsetHigh, - DWORD nNumberOfBytesToLockLow, - DWORD nNumberOfBytesToLockHigh -){ - winFile *pFile = HANDLE_TO_WINFILE(phFile); - BOOL bReturn = FALSE; - - if (!pFile->hMutex) return TRUE; - winceMutexAcquire(pFile->hMutex); - - /* Wanting an exclusive lock? */ - if (dwFileOffsetLow == SHARED_FIRST - && nNumberOfBytesToLockLow == SHARED_SIZE){ - if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){ - pFile->shared->bExclusive = TRUE; - pFile->local.bExclusive = TRUE; - bReturn = TRUE; - } - } - - /* Want a read-only lock? */ - else if ((dwFileOffsetLow >= SHARED_FIRST && - dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) && - nNumberOfBytesToLockLow == 1){ - if (pFile->shared->bExclusive == 0){ - pFile->local.nReaders ++; - if (pFile->local.nReaders == 1){ - pFile->shared->nReaders ++; - } - bReturn = TRUE; - } - } - - /* Want a pending lock? */ - else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToLockLow == 1){ - /* If no pending lock has been acquired, then acquire it */ - if (pFile->shared->bPending == 0) { - pFile->shared->bPending = TRUE; - pFile->local.bPending = TRUE; - bReturn = TRUE; - } - } - /* Want a reserved lock? */ - else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToLockLow == 1){ - if (pFile->shared->bReserved == 0) { - pFile->shared->bReserved = TRUE; - pFile->local.bReserved = TRUE; - bReturn = TRUE; - } - } - - winceMutexRelease(pFile->hMutex); - return bReturn; -} - -/* -** An implementation of the UnlockFile API of windows for wince -*/ -static BOOL winceUnlockFile( - HANDLE *phFile, - DWORD dwFileOffsetLow, - DWORD dwFileOffsetHigh, - DWORD nNumberOfBytesToUnlockLow, - DWORD nNumberOfBytesToUnlockHigh -){ - winFile *pFile = HANDLE_TO_WINFILE(phFile); - BOOL bReturn = FALSE; - - if (!pFile->hMutex) return TRUE; - winceMutexAcquire(pFile->hMutex); - - /* Releasing a reader lock or an exclusive lock */ - if (dwFileOffsetLow >= SHARED_FIRST && - dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE){ - /* Did we have an exclusive lock? */ - if (pFile->local.bExclusive){ - pFile->local.bExclusive = FALSE; - pFile->shared->bExclusive = FALSE; - bReturn = TRUE; - } - - /* Did we just have a reader lock? */ - else if (pFile->local.nReaders){ - pFile->local.nReaders --; - if (pFile->local.nReaders == 0) - { - pFile->shared->nReaders --; - } - bReturn = TRUE; - } - } - - /* Releasing a pending lock */ - else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){ - if (pFile->local.bPending){ - pFile->local.bPending = FALSE; - pFile->shared->bPending = FALSE; - bReturn = TRUE; - } - } - /* Releasing a reserved lock */ - else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){ - if (pFile->local.bReserved) { - pFile->local.bReserved = FALSE; - pFile->shared->bReserved = FALSE; - bReturn = TRUE; - } - } - - winceMutexRelease(pFile->hMutex); - return bReturn; -} - -/* -** An implementation of the LockFileEx() API of windows for wince -*/ -static BOOL winceLockFileEx( - HANDLE *phFile, - DWORD dwFlags, - DWORD dwReserved, - DWORD nNumberOfBytesToLockLow, - DWORD nNumberOfBytesToLockHigh, - LPOVERLAPPED lpOverlapped -){ - /* If the caller wants a shared read lock, forward this call - ** to winceLockFile */ - if (lpOverlapped->Offset == SHARED_FIRST && - dwFlags == 1 && - nNumberOfBytesToLockLow == SHARED_SIZE){ - return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0); - } - return FALSE; -} -/* -** End of the special code for wince -*****************************************************************************/ -#endif /* OS_WINCE */ - /* ** Delete the named file */ -int sqlite3WinDelete(const char *zFilename){ - WCHAR *zWide = utf8ToUnicode(zFilename); - if( zWide ){ - DeleteFileW(zWide); - sqliteFree(zWide); - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - DeleteFileA(zFilename); -#endif - } +int sqlite3OsDelete(const char *zFilename){ + DeleteFileA(zFilename); TRACE2("DELETE \"%s\"\n", zFilename); return SQLITE_OK; } /* ** Return TRUE if the named file exists. */ -int sqlite3WinFileExists(const char *zFilename){ - int exists = 0; - WCHAR *zWide = utf8ToUnicode(zFilename); - if( zWide ){ - exists = GetFileAttributesW(zWide) != 0xffffffff; - sqliteFree(zWide); - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - exists = GetFileAttributesA(zFilename) != 0xffffffff; -#endif - } - return exists; -} - -/* Forward declaration */ -int allocateWinFile(winFile *pInit, OsFile **pId); +int sqlite3OsFileExists(const char *zFilename){ + return GetFileAttributesA(zFilename) != 0xffffffff; +} /* ** Attempt to open a file for both reading and writing. If that ** fails, try opening it read-only. If the file does not exist, ** try to create it. @@ -527,91 +57,48 @@ ** SQLITE_OK. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id and *pReadonly unchanged. */ -int sqlite3WinOpenReadWrite( +int sqlite3OsOpenReadWrite( const char *zFilename, - OsFile **pId, + OsFile *id, int *pReadonly ){ - winFile f; HANDLE h; - WCHAR *zWide = utf8ToUnicode(zFilename); - assert( *pId==0 ); - if( zWide ){ - h = CreateFileW(zWide, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, + assert( !id->isOpen ); + h = CreateFileA(zFilename, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, + NULL + ); + if( h==INVALID_HANDLE_VALUE ){ + h = CreateFileA(zFilename, + GENERIC_READ, + FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL ); if( h==INVALID_HANDLE_VALUE ){ - h = CreateFileW(zWide, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - sqliteFree(zWide); - return SQLITE_CANTOPEN; - } - *pReadonly = 1; - }else{ - *pReadonly = 0; - } -#if OS_WINCE - if (!winceCreateLock(zFilename, &f)){ - CloseHandle(h); - sqliteFree(zWide); - return SQLITE_CANTOPEN; - } -#endif - sqliteFree(zWide); - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - h = CreateFileA(zFilename, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - h = CreateFileA(zFilename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - return SQLITE_CANTOPEN; - } - *pReadonly = 1; - }else{ - *pReadonly = 0; - } -#endif /* OS_WINCE */ - } - f.h = h; - f.locktype = NO_LOCK; - f.sharedLockByte = 0; -#if OS_WINCE - f.zDeleteOnClose = 0; -#endif - TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename); - return allocateWinFile(&f, pId); + return SQLITE_CANTOPEN; + } + *pReadonly = 1; + }else{ + *pReadonly = 0; + } + id->h = h; + id->locktype = NO_LOCK; + id->sharedLockByte = 0; + id->isOpen = 1; + OpenCounter(+1); + TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename); + return SQLITE_OK; } /* ** Attempt to open a new file for exclusive access by this process. @@ -625,108 +112,68 @@ ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ -int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ - winFile f; +int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ HANDLE h; int fileflags; - WCHAR *zWide = utf8ToUnicode(zFilename); - assert( *pId == 0 ); - fileflags = FILE_FLAG_RANDOM_ACCESS; -#if !OS_WINCE + assert( !id->isOpen ); if( delFlag ){ - fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE; - } -#endif - if( zWide ){ - h = CreateFileW(zWide, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - fileflags, - NULL - ); - sqliteFree(zWide); + fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS + | FILE_FLAG_DELETE_ON_CLOSE; }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - h = CreateFileA(zFilename, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - fileflags, - NULL - ); -#endif /* OS_WINCE */ - } + fileflags = FILE_FLAG_RANDOM_ACCESS; + } + h = CreateFileA(zFilename, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + fileflags, + NULL + ); if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } - f.h = h; - f.locktype = NO_LOCK; - f.sharedLockByte = 0; -#if OS_WINCE - f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0; - f.hMutex = NULL; -#endif + id->h = h; + id->locktype = NO_LOCK; + id->sharedLockByte = 0; + id->isOpen = 1; + OpenCounter(+1); TRACE3("OPEN EX %d \"%s\"\n", h, zFilename); - return allocateWinFile(&f, pId); + return SQLITE_OK; } /* ** Attempt to open a new file for read-only access. ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ -int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){ - winFile f; +int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ HANDLE h; - WCHAR *zWide = utf8ToUnicode(zFilename); - assert( *pId==0 ); - if( zWide ){ - h = CreateFileW(zWide, - GENERIC_READ, - 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - sqliteFree(zWide); - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - h = CreateFileA(zFilename, - GENERIC_READ, - 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); -#endif - } + assert( !id->isOpen ); + h = CreateFileA(zFilename, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, + NULL + ); if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } - f.h = h; - f.locktype = NO_LOCK; - f.sharedLockByte = 0; -#if OS_WINCE - f.zDeleteOnClose = 0; - f.hMutex = NULL; -#endif + id->h = h; + id->locktype = NO_LOCK; + id->sharedLockByte = 0; + id->isOpen = 1; + OpenCounter(+1); TRACE3("OPEN RO %d \"%s\"\n", h, zFilename); - return allocateWinFile(&f, pId); + return SQLITE_OK; } /* ** Attempt to open a file descriptor for the directory that contains a ** file. This file descriptor can be used to fsync() the directory @@ -741,13 +188,13 @@ ** returned. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id unchanged. */ -static int winOpenDirectory( - OsFile *id, - const char *zDirname +int sqlite3OsOpenDirectory( + const char *zDirname, + OsFile *id ){ return SQLITE_OK; } /* @@ -759,30 +206,20 @@ /* ** Create a temporary file name in zBuf. zBuf must be big enough to ** hold at least SQLITE_TEMPNAME_SIZE characters. */ -int sqlite3WinTempFileName(char *zBuf){ +int sqlite3OsTempFileName(char *zBuf){ static char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; int i, j; char zTempPath[SQLITE_TEMPNAME_SIZE]; if( sqlite3_temp_directory ){ strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30); zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; - }else if( isNT() ){ - char *zMulti; - WCHAR zWidePath[SQLITE_TEMPNAME_SIZE]; - GetTempPathW(SQLITE_TEMPNAME_SIZE-30, zWidePath); - zMulti = unicodeToUtf8(zWidePath); - if( zMulti ){ - strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30); - zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; - sqliteFree(zMulti); - } }else{ GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath); } for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} zTempPath[i] = 0; @@ -801,40 +238,31 @@ } /* ** Close a file. */ -static int winClose(OsFile **pId){ - winFile *pFile; - if( pId && (pFile = (winFile*)*pId)!=0 ){ - TRACE2("CLOSE %d\n", pFile->h); - CloseHandle(pFile->h); -#if OS_WINCE - winceDestroyLock(pFile); - if( pFile->zDeleteOnClose ){ - DeleteFileW(pFile->zDeleteOnClose); - sqliteFree(pFile->zDeleteOnClose); - } -#endif +int sqlite3OsClose(OsFile *id){ + if( id->isOpen ){ + TRACE2("CLOSE %d\n", id->h); + CloseHandle(id->h); OpenCounter(-1); - sqliteFree(pFile); - *pId = 0; + id->isOpen = 0; } return SQLITE_OK; } /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ -static int winRead(OsFile *id, void *pBuf, int amt){ +int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ DWORD got; - assert( id!=0 ); + assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); - TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); - if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){ + TRACE3("READ %d lock=%d\n", id->h, id->locktype); + if( !ReadFile(id->h, pBuf, amt, &got, 0) ){ got = 0; } if( got==(DWORD)amt ){ return SQLITE_OK; }else{ @@ -844,63 +272,49 @@ /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ -static int winWrite(OsFile *id, const void *pBuf, int amt){ +int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ int rc = 0; DWORD wrote; - assert( id!=0 ); + assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); SimulateDiskfullError; - TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); + TRACE3("WRITE %d lock=%d\n", id->h, id->locktype); assert( amt>0 ); - while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0 - && wrote>0 ){ + while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } if( !rc || amt>(int)wrote ){ return SQLITE_FULL; } return SQLITE_OK; } -/* -** Some microsoft compilers lack this definition. -*/ -#ifndef INVALID_SET_FILE_POINTER -# define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif - /* ** Move the read/write pointer in a file. */ -static int winSeek(OsFile *id, i64 offset){ +int sqlite3OsSeek(OsFile *id, i64 offset){ LONG upperBits = offset>>32; LONG lowerBits = offset & 0xffffffff; DWORD rc; - assert( id!=0 ); -#ifdef SQLITE_TEST - if( offset ) SimulateDiskfullError -#endif + assert( id->isOpen ); SEEK(offset/1024 + 1); - rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN); - TRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset); - if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ - return SQLITE_FULL; - } + rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN); + TRACE3("SEEK %d %lld\n", id->h, offset); return SQLITE_OK; } /* ** Make sure all writes to a particular file are committed to disk. */ -static int winSync(OsFile *id, int dataOnly){ - assert( id!=0 ); - TRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); - if( FlushFileBuffers(((winFile*)id)->h) ){ +int sqlite3OsSync(OsFile *id){ + assert( id->isOpen ); + TRACE3("SYNC %d lock=%d\n", id->h, id->locktype); + if( FlushFileBuffers(id->h) ){ return SQLITE_OK; }else{ return SQLITE_IOERR; } } @@ -907,53 +321,68 @@ /* ** Sync the directory zDirname. This is a no-op on operating systems other ** than UNIX. */ -int sqlite3WinSyncDirectory(const char *zDirname){ +int sqlite3OsSyncDirectory(const char *zDirname){ SimulateIOError(SQLITE_IOERR); return SQLITE_OK; } /* ** Truncate an open file to a specified size */ -static int winTruncate(OsFile *id, i64 nByte){ +int sqlite3OsTruncate(OsFile *id, i64 nByte){ LONG upperBits = nByte>>32; - assert( id!=0 ); - TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte); + assert( id->isOpen ); + TRACE3("TRUNCATE %d %lld\n", id->h, nByte); SimulateIOError(SQLITE_IOERR); - SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN); - SetEndOfFile(((winFile*)id)->h); + SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN); + SetEndOfFile(id->h); return SQLITE_OK; } /* ** Determine the current size of a file in bytes */ -static int winFileSize(OsFile *id, i64 *pSize){ +int sqlite3OsFileSize(OsFile *id, i64 *pSize){ DWORD upperBits, lowerBits; - assert( id!=0 ); + assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); - lowerBits = GetFileSize(((winFile*)id)->h, &upperBits); + lowerBits = GetFileSize(id->h, &upperBits); *pSize = (((i64)upperBits)<<32) + lowerBits; return SQLITE_OK; } /* -** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. +** Return true (non-zero) if we are running under WinNT, Win2K or WinXP. +** Return false (zero) for Win95, Win98, or WinME. +** +** Here is an interesting observation: Win95, Win98, and WinME lack +** the LockFileEx() API. But we can still statically link against that +** API as long as we don't call it win running Win95/98/ME. A call to +** this routine is used to determine if the host is Win95/98/ME or +** WinNT/2K/XP so that we will know whether or not we can safely call +** the LockFileEx() API. */ -#ifndef LOCKFILE_FAIL_IMMEDIATELY -# define LOCKFILE_FAIL_IMMEDIATELY 1 -#endif +static int isNT(void){ + static int osType = 0; /* 0=unknown 1=win95 2=winNT */ + if( osType==0 ){ + OSVERSIONINFO sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + GetVersionEx(&sInfo); + osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; + } + return osType==2; +} /* ** Acquire a reader lock. ** Different API routines are called depending on whether or not this ** is Win95 or WinNT. */ -static int getReadLock(winFile *id){ +static int getReadLock(OsFile *id){ int res; if( isNT() ){ OVERLAPPED ovlp; ovlp.Offset = SHARED_FIRST; ovlp.OffsetHigh = 0; @@ -969,41 +398,30 @@ } /* ** Undo a readlock */ -static int unlockReadLock(winFile *pFile){ +static int unlockReadLock(OsFile *id){ int res; if( isNT() ){ - res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + res = UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0); }else{ - res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); + res = UnlockFile(id->h, SHARED_FIRST + id->sharedLockByte, 0, 1, 0); } return res; } #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Check that a given pathname is a directory and is writable ** */ -int sqlite3WinIsDirWritable(char *zDirname){ +int sqlite3OsIsDirWritable(char *zBuf){ int fileAttr; - WCHAR *zWide; - if( zDirname==0 ) return 0; - if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0; - zWide = utf8ToUnicode(zDirname); - if( zWide ){ - fileAttr = GetFileAttributesW(zWide); - sqliteFree(zWide); - }else{ -#if OS_WINCE - return 0; -#else - fileAttr = GetFileAttributesA(zDirname); -#endif - } + if(! zBuf ) return 0; + if(! isNT() && strlen(zBuf) > MAX_PATH ) return 0; + fileAttr = GetFileAttributesA(zBuf); if( fileAttr == 0xffffffff ) return 0; if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ return 0; } return 1; @@ -1029,50 +447,49 @@ ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** -** This routine will only increase a lock. The winUnlock() routine +** This routine will only increase a lock. The sqlite3OsUnlock() routine ** erases all locks at once and returns us immediately to locking level 0. ** It is not possible to lower the locking level one step at a time. You ** must go straight to locking level 0. */ -static int winLock(OsFile *id, int locktype){ +int sqlite3OsLock(OsFile *id, int locktype){ int rc = SQLITE_OK; /* Return code from subroutines */ int res = 1; /* Result of a windows lock call */ int newLocktype; /* Set id->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ - winFile *pFile = (winFile*)id; - assert( pFile!=0 ); + assert( id->isOpen ); TRACE5("LOCK %d %d was %d(%d)\n", - pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); + id->h, locktype, id->locktype, id->sharedLockByte); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ - if( pFile->locktype>=locktype ){ + if( id->locktype>=locktype ){ return SQLITE_OK; } /* Make sure the locking sequence is correct */ - assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); + assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); - assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); + assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK ); /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ - newLocktype = pFile->locktype; - if( pFile->locktype==NO_LOCK - || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) + newLocktype = id->locktype; + if( id->locktype==NO_LOCK + || (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK) ){ int cnt = 3; - while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){ + while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){ /* Try 3 times to get the pending lock. The pending lock might be ** held by another reader process who will release it momentarily. */ TRACE2("could not get a PENDING lock. cnt=%d\n", cnt); Sleep(1); @@ -1081,22 +498,22 @@ } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ - assert( pFile->locktype==NO_LOCK ); - res = getReadLock(pFile); + assert( id->locktype==NO_LOCK ); + res = getReadLock(id); if( res ){ newLocktype = SHARED_LOCK; } } /* Acquire a RESERVED lock */ if( locktype==RESERVED_LOCK && res ){ - assert( pFile->locktype==SHARED_LOCK ); - res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); + assert( id->locktype==SHARED_LOCK ); + res = LockFile(id->h, RESERVED_BYTE, 0, 1, 0); if( res ){ newLocktype = RESERVED_LOCK; } } @@ -1108,14 +525,14 @@ } /* Acquire an EXCLUSIVE lock */ if( locktype==EXCLUSIVE_LOCK && res ){ - assert( pFile->locktype>=SHARED_LOCK ); - res = unlockReadLock(pFile); + assert( id->locktype>=SHARED_LOCK ); + res = unlockReadLock(id); TRACE2("unreadlock = %d\n", res); - res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + res = LockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res ){ newLocktype = EXCLUSIVE_LOCK; }else{ TRACE2("error-code = %d\n", GetLastError()); } @@ -1123,46 +540,45 @@ /* If we are holding a PENDING lock that ought to be released, then ** release it now. */ if( gotPendingLock && locktype==SHARED_LOCK ){ - UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); + UnlockFile(id->h, PENDING_BYTE, 0, 1, 0); } /* Update the state of the lock has held in the file descriptor then ** return the appropriate result code. */ if( res ){ rc = SQLITE_OK; }else{ - TRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h, + TRACE4("LOCK FAILED %d trying for %d but got %d\n", id->h, locktype, newLocktype); rc = SQLITE_BUSY; } - pFile->locktype = newLocktype; + id->locktype = newLocktype; return rc; } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero, otherwise zero. */ -static int winCheckReservedLock(OsFile *id){ +int sqlite3OsCheckReservedLock(OsFile *id){ int rc; - winFile *pFile = (winFile*)id; - assert( pFile!=0 ); - if( pFile->locktype>=RESERVED_LOCK ){ + assert( id->isOpen ); + if( id->locktype>=RESERVED_LOCK ){ rc = 1; - TRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); + TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc); }else{ - rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); + rc = LockFile(id->h, RESERVED_BYTE, 0, 1, 0); if( rc ){ - UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); + UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0); } rc = !rc; - TRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc); + TRACE3("TEST WR-LOCK %d %d (remote)\n", id->h, rc); } return rc; } /* @@ -1174,160 +590,45 @@ ** ** It is not possible for this routine to fail if the second argument ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine ** might return SQLITE_IOERR; */ -static int winUnlock(OsFile *id, int locktype){ +int sqlite3OsUnlock(OsFile *id, int locktype){ int type; int rc = SQLITE_OK; - winFile *pFile = (winFile*)id; - assert( pFile!=0 ); + assert( id->isOpen ); assert( locktype<=SHARED_LOCK ); - TRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype, - pFile->locktype, pFile->sharedLockByte); - type = pFile->locktype; + TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype, + id->locktype, id->sharedLockByte); + type = id->locktype; if( type>=EXCLUSIVE_LOCK ){ - UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ + UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + if( locktype==SHARED_LOCK && !getReadLock(id) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = SQLITE_IOERR; } } if( type>=RESERVED_LOCK ){ - UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); + UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0); } if( locktype==NO_LOCK && type>=SHARED_LOCK ){ - unlockReadLock(pFile); + unlockReadLock(id); } if( type>=PENDING_LOCK ){ - UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); + UnlockFile(id->h, PENDING_BYTE, 0, 1, 0); } - pFile->locktype = locktype; + id->locktype = locktype; return rc; } -/* -** Turn a relative pathname into a full pathname. Return a pointer -** to the full pathname stored in space obtained from sqliteMalloc(). -** The calling function is responsible for freeing this space once it -** is no longer needed. -*/ -char *sqlite3WinFullPathname(const char *zRelative){ - char *zFull; -#if defined(__CYGWIN__) - int nByte; - nByte = strlen(zRelative) + MAX_PATH + 1001; - zFull = sqliteMalloc( nByte ); - if( zFull==0 ) return 0; - if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0; -#elif OS_WINCE - /* WinCE has no concept of a relative pathname, or so I am told. */ - zFull = sqliteStrDup(zRelative); -#else - char *zNotUsed; - WCHAR *zWide; - int nByte; - zWide = utf8ToUnicode(zRelative); - if( zWide ){ - WCHAR *zTemp, *zNotUsedW; - nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1; - zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) ); - if( zTemp==0 ) return 0; - GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW); - sqliteFree(zWide); - zFull = unicodeToUtf8(zTemp); - sqliteFree(zTemp); - }else{ - nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1; - zFull = sqliteMalloc( nByte*sizeof(zFull[0]) ); - if( zFull==0 ) return 0; - GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); - } -#endif - return zFull; -} - -/* -** The fullSync option is meaningless on windows. This is a no-op. -*/ -static void winSetFullSync(OsFile *id, int v){ - return; -} - -/* -** Return the underlying file handle for an OsFile -*/ -static int winFileHandle(OsFile *id){ - return (int)((winFile*)id)->h; -} - -/* -** Return an integer that indices the type of lock currently held -** by this handle. (Used for testing and analysis only.) -*/ -static int winLockState(OsFile *id){ - return ((winFile*)id)->locktype; -} - -/* -** This vector defines all the methods that can operate on an OsFile -** for win32. -*/ -static const IoMethod sqlite3WinIoMethod = { - winClose, - winOpenDirectory, - winRead, - winWrite, - winSeek, - winTruncate, - winSync, - winSetFullSync, - winFileHandle, - winFileSize, - winLock, - winUnlock, - winLockState, - winCheckReservedLock, -}; - -/* -** Allocate memory for an OsFile. Initialize the new OsFile -** to the value given in pInit and return a pointer to the new -** OsFile. If we run out of memory, close the file and return NULL. -*/ -int allocateWinFile(winFile *pInit, OsFile **pId){ - winFile *pNew; - pNew = sqliteMalloc( sizeof(*pNew) ); - if( pNew==0 ){ - CloseHandle(pInit->h); -#if OS_WINCE - sqliteFree(pInit->zDeleteOnClose); -#endif - *pId = 0; - return SQLITE_NOMEM; - }else{ - *pNew = *pInit; - pNew->pMethod = &sqlite3WinIoMethod; - *pId = (OsFile*)pNew; - return SQLITE_OK; - } -} - - -#endif /* SQLITE_OMIT_DISKIO */ -/*************************************************************************** -** Everything above deals with file I/O. Everything that follows deals -** with other miscellanous aspects of the operating system interface -****************************************************************************/ - /* ** Get information to seed the random number generator. The seed ** is written into the buffer zBuf[256]. The calling function must ** supply a sufficiently large buffer. */ -int sqlite3WinRandomSeed(char *zBuf){ +int sqlite3OsRandomSeed(char *zBuf){ /* We have to initialize zBuf to prevent valgrind from reporting ** errors. The reports issued by valgrind are incorrect - we would ** prefer that the randomness be increased by making use of the ** uninitialized space in zBuf - but valgrind errors tend to worry ** some users. Rather than argue, it seems easier just to initialize @@ -1344,11 +645,11 @@ } /* ** Sleep for a little while. Return the amount of time slept. */ -int sqlite3WinSleep(int ms){ +int sqlite3OsSleep(int ms){ Sleep(ms); return ms; } /* @@ -1365,11 +666,11 @@ ** executed code that is surrounded by EnterMutex() and LeaveMutex(). ** ** SQLite uses only a single Mutex. There is not much critical ** code and what little there is executes quickly and without blocking. */ -void sqlite3WinEnterMutex(){ +void sqlite3OsEnterMutex(){ #ifdef SQLITE_W32_THREADS static int isInit = 0; while( !isInit ){ static long lock = 0; if( InterlockedIncrement(&lock)==1 ){ @@ -1382,25 +683,34 @@ EnterCriticalSection(&cs); #endif assert( !inMutex ); inMutex = 1; } -void sqlite3WinLeaveMutex(){ +void sqlite3OsLeaveMutex(){ assert( inMutex ); inMutex = 0; #ifdef SQLITE_W32_THREADS LeaveCriticalSection(&cs); #endif } /* -** Return TRUE if we are currently within the mutex and FALSE if not. +** Turn a relative pathname into a full pathname. Return a pointer +** to the full pathname stored in space obtained from sqliteMalloc(). +** The calling function is responsible for freeing this space once it +** is no longer needed. */ -int sqlite3WinInMutex(){ - return inMutex; +char *sqlite3OsFullPathname(const char *zRelative){ + char *zNotUsed; + char *zFull; + int nByte; + nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1; + zFull = sqliteMalloc( nByte ); + if( zFull==0 ) return 0; + GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); + return zFull; } - /* ** The following variable, if set to a non-zero value, becomes the result ** returned from sqlite3OsCurrentTime(). This is used for testing. */ @@ -1411,23 +721,17 @@ /* ** Find the current time (in Universal Coordinated Time). Write the ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int sqlite3WinCurrentTime(double *prNow){ +int sqlite3OsCurrentTime(double *prNow){ FILETIME ft; /* FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). */ double now; -#if OS_WINCE - SYSTEMTIME time; - GetSystemTime(&time); - SystemTimeToFileTime(&time,&ft); -#else GetSystemTimeAsFileTime( &ft ); -#endif now = ((double)ft.dwHighDateTime) * 4294967296.0; *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5; #ifdef SQLITE_TEST if( sqlite3_current_time ){ *prNow = sqlite3_current_time/86400.0 + 2440587.5; @@ -1435,72 +739,28 @@ #endif return 0; } /* -** Remember the number of thread-specific-data blocks allocated. -** Use this to verify that we are not leaking thread-specific-data. -** Ticket #1601 -*/ -#ifdef SQLITE_TEST -int sqlite3_tsd_count = 0; -# define TSD_COUNTER_INCR InterlockedIncrement(&sqlite3_tsd_count) -# define TSD_COUNTER_DECR InterlockedDecrement(&sqlite3_tsd_count) -#else -# define TSD_COUNTER_INCR /* no-op */ -# define TSD_COUNTER_DECR /* no-op */ -#endif - - - -/* -** If called with allocateFlag>1, then return a pointer to thread -** specific data for the current thread. Allocate and zero the -** thread-specific data if it does not already exist necessary. -** -** If called with allocateFlag==0, then check the current thread -** specific data. Return it if it exists. If it does not exist, -** then return NULL. -** -** If called with allocateFlag<0, check to see if the thread specific -** data is allocated and is all zero. If it is then deallocate it. -** Return a pointer to the thread specific data or NULL if it is -** unallocated or gets deallocated. -*/ -ThreadData *sqlite3WinThreadSpecificData(int allocateFlag){ - static int key; - static int keyInit = 0; - static const ThreadData zeroData; - ThreadData *pTsd; - - if( !keyInit ){ - sqlite3OsEnterMutex(); - if( !keyInit ){ - key = TlsAlloc(); - if( key==0xffffffff ){ - sqlite3OsLeaveMutex(); - return 0; - } - keyInit = 1; - } - sqlite3OsLeaveMutex(); - } - pTsd = TlsGetValue(key); - if( allocateFlag>0 ){ - if( !pTsd ){ - pTsd = sqlite3OsMalloc( sizeof(zeroData) ); - if( pTsd ){ - *pTsd = zeroData; - TlsSetValue(key, pTsd); - TSD_COUNTER_INCR; - } - } - }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){ - sqlite3OsFree(pTsd); - TlsSetValue(key, 0); - TSD_COUNTER_DECR; - pTsd = 0; - } - return pTsd; -} +** Find the time that the file was last modified. Write the +** modification time and date as a Julian Day number into *prNow and +** return SQLITE_OK. Return SQLITE_ERROR if the modification +** time cannot be found. +*/ +int sqlite3OsFileModTime(OsFile *id, double *prMTime){ + int rc; + FILETIME ft; + /* FILETIME structure is a 64-bit value representing the number of + ** 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). + */ + if( GetFileTime(id->h, 0, 0, &ft) ){ + double t; + t = ((double)ft.dwHighDateTime) * 4294967296.0; + *prMTime = (t + ft.dwLowDateTime)/864000000000.0 + 2305813.5; + rc = SQLITE_OK; + }else{ + rc = SQLITE_ERROR; + } + return rc; +} + #endif /* OS_WIN */ ADDED SQLite.Interop/src/os_win.h Index: SQLite.Interop/src/os_win.h ================================================================== --- /dev/null +++ SQLite.Interop/src/os_win.h @@ -0,0 +1,40 @@ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file defines OS-specific features for Win32 +*/ +#ifndef _SQLITE_OS_WIN_H_ +#define _SQLITE_OS_WIN_H_ + +#include +#include + +/* +** The OsFile structure is a operating-system independing representation +** of an open file handle. It is defined differently for each architecture. +** +** This is the definition for Win32. +*/ +typedef struct OsFile OsFile; +struct OsFile { + HANDLE h; /* Handle for accessing the file */ + unsigned char locktype; /* Type of lock currently held on this file */ + unsigned char isOpen; /* True if needs to be closed */ + short sharedLockByte; /* Randomly chosen byte used as a shared lock */ +}; + + +#define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) +#define SQLITE_MIN_SLEEP_MS 1 + + +#endif /* _SQLITE_OS_WIN_H_ */ Index: SQLite.Interop/src/pager.c ================================================================== --- SQLite.Interop/src/pager.c +++ SQLite.Interop/src/pager.c @@ -16,13 +16,12 @@ ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.17 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: pager.c,v 1.1 2005/03/01 16:04:31 rmsimpson Exp $ */ -#ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" #include #include @@ -44,18 +43,25 @@ #define TRACE5(X,Y,Z,W,V) #endif /* ** The following two macros are used within the TRACEX() macros above -** to print out file-descriptors. +** to print out file-descriptors. They are required so that tracing +** can be turned on when using both the regular os_unix.c and os_test.c +** backends. ** ** PAGERID() takes a pointer to a Pager struct as it's argument. The ** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile ** struct as it's argument. */ -#define PAGERID(p) FILEHANDLEID(&(p)->fd) -#define FILEHANDLEID(fd) (sqlite3OsFileHandle(&fd)) +#ifdef OS_TEST +#define PAGERID(p) (p->fd->fd.h) +#define FILEHANDLEID(fd) (fd->fd.h) +#else +#define PAGERID(p) (p->fd.h) +#define FILEHANDLEID(fd) (fd.h) +#endif /* ** The page cache as a whole is always in one of the following ** states: ** @@ -163,11 +169,11 @@ short int nRef; /* Number of users of this page */ PgHdr *pDirty; /* Dirty pages sorted by PgHdr.pgno */ #ifdef SQLITE_CHECK_PAGES u32 pageHash; #endif - /* pPager->pageSize bytes of page data follow this header */ + /* pPager->psAligned bytes of page data follow this header */ /* Pager.nExtra bytes of local data follow the page data */ }; /* ** For an in-memory only database, some extra information is recorded about @@ -199,44 +205,53 @@ ** Convert a pointer to a PgHdr into a pointer to its data ** and back again. */ #define PGHDR_TO_DATA(P) ((void*)(&(P)[1])) #define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1]) -#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize]) +#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->psAligned]) #define PGHDR_TO_HIST(P,PGR) \ - ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra]) + ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->psAligned+(PGR)->nExtra]) /* ** How big to make the hash table used for locating in-memory pages -** by page number. This macro looks a little silly, but is evaluated -** at compile-time, not run-time (at least for gcc this is true). +** by page number. */ -#define N_PG_HASH (\ - (MAX_PAGES>1024)?2048: \ - (MAX_PAGES>512)?1024: \ - (MAX_PAGES>256)?512: \ - (MAX_PAGES>128)?256: \ - (MAX_PAGES>64)?128:64 \ -) +#define N_PG_HASH 2048 /* ** Hash a page number */ #define pager_hash(PN) ((PN)&(N_PG_HASH-1)) /* ** A open page cache is an instance of the following structure. -** -** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, SQLITE_PROTOCOL -** or SQLITE_FULL. Once one of the first three errors occurs, it persists -** and is returned as the result of every major pager API call. The -** SQLITE_FULL return code is slightly different. It persists only until the -** next successful rollback is performed on the pager cache. Also, -** SQLITE_FULL does not affect the sqlite3pager_get() and sqlite3pager_lookup() -** APIs, they may still be used successfully. */ struct Pager { + char *zFilename; /* Name of the database file */ + char *zJournal; /* Name of the journal file */ + char *zDirectory; /* Directory hold database and journal files */ + OsFile fd, jfd; /* File descriptors for database and journal */ + OsFile stfd; /* File descriptor for the statement subjournal*/ + int dbSize; /* Number of pages in the file */ + int origDbSize; /* dbSize before the current change */ + int stmtSize; /* Size of database (in pages) at stmt_begin() */ + i64 stmtJSize; /* Size of journal at stmt_begin() */ + int nRec; /* Number of pages written to the journal */ + u32 cksumInit; /* Quasi-random value added to every checksum */ + int stmtNRec; /* Number of records in stmt subjournal */ + int nExtra; /* Add this many bytes to each in-memory page */ + void (*xDestructor)(void*,int); /* Call this routine when freeing pages */ + void (*xReiniter)(void*,int); /* Call this routine when reloading pages */ + int pageSize; /* Number of bytes in a page */ + int psAligned; /* pageSize rounded up to a multiple of 8 */ + int nPage; /* Total number of in-memory pages */ + int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ + int mxPage; /* Maximum number of pages to hold in cache */ + int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */ + int nRead,nWrite; /* Database pages read/written */ + void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ + void *pCodecArg; /* First argument to xCodec() */ u8 journalOpen; /* True if journal file descriptors is valid */ u8 journalStarted; /* True if header of journal is synced */ u8 useJournal; /* Use a rollback journal on this file */ u8 noReadlock; /* Do not bother to obtain readlocks */ u8 stmtOpen; /* True if the statement subjournal is open */ @@ -243,71 +258,41 @@ u8 stmtInUse; /* True we are in a statement subtransaction */ u8 stmtAutoopen; /* Open stmt journal when main journal is opened*/ u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ - u8 errCode; /* One of several kinds of errors */ + u8 errMask; /* One of several kinds of errors */ u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 needSync; /* True if an fsync() is needed on the journal */ u8 dirtyCache; /* True if cached pages have changed */ u8 alwaysRollback; /* Disable dont_rollback() for all pages */ u8 memDb; /* True to inhibit all file I/O */ - u8 setMaster; /* True if a m-j name has been written to jrnl */ - int dbSize; /* Number of pages in the file */ - int origDbSize; /* dbSize before the current change */ - int stmtSize; /* Size of database (in pages) at stmt_begin() */ - int nRec; /* Number of pages written to the journal */ - u32 cksumInit; /* Quasi-random value added to every checksum */ - int stmtNRec; /* Number of records in stmt subjournal */ - int nExtra; /* Add this many bytes to each in-memory page */ - int pageSize; /* Number of bytes in a page */ - int nPage; /* Total number of in-memory pages */ - int nMaxPage; /* High water mark of nPage */ - int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ - int mxPage; /* Maximum number of pages to hold in cache */ u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInStmt; /* One bit for each page in the database */ - char *zFilename; /* Name of the database file */ - char *zJournal; /* Name of the journal file */ - char *zDirectory; /* Directory hold database and journal files */ - OsFile *fd, *jfd; /* File descriptors for database and journal */ - OsFile *stfd; /* File descriptor for the statement subjournal*/ + u8 setMaster; /* True if a m-j name has been written to jrnl */ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ PgHdr *pFirst, *pLast; /* List of free pages */ PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ PgHdr *pAll; /* List of all pages */ PgHdr *pStmt; /* List of pages in the statement subjournal */ i64 journalOff; /* Current byte offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ i64 stmtHdrOff; /* First journal header written this statement */ i64 stmtCksum; /* cksumInit when statement was started */ - i64 stmtJSize; /* Size of journal at stmt_begin() */ int sectorSize; /* Assumed sector size during rollback */ -#ifdef SQLITE_TEST - int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */ - int nRead,nWrite; /* Database pages read/written */ -#endif - void (*xDestructor)(void*,int); /* Call this routine when freeing pages */ - void (*xReiniter)(void*,int); /* Call this routine when reloading pages */ - void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ - void *pCodecArg; /* First argument to xCodec() */ PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - Pager *pNext; /* Linked list of pagers in this thread */ -#endif }; /* -** If SQLITE_TEST is defined then increment the variable given in -** the argument +** These are bits that can be set in Pager.errMask. */ -#ifdef SQLITE_TEST -# define TEST_INCR(x) x++ -#else -# define TEST_INCR(x) -#endif +#define PAGER_ERR_FULL 0x01 /* a write() failed */ +#define PAGER_ERR_MEM 0x02 /* malloc() failed */ +#define PAGER_ERR_LOCK 0x04 /* error in the locking protocol */ +#define PAGER_ERR_CORRUPT 0x08 /* database or journal corruption */ +#define PAGER_ERR_DISK 0x10 /* general disk I/O error - bad hard drive? */ /* ** Journal files begin with the following magic string. The data ** was obtained from /dev/random. It is used only as a sanity check. ** @@ -404,35 +389,32 @@ ** error code is something goes wrong. ** ** All values are stored on disk as big-endian. */ static int read32bits(OsFile *fd, u32 *pRes){ - unsigned char ac[4]; - int rc = sqlite3OsRead(fd, ac, sizeof(ac)); + u32 res; + int rc; + rc = sqlite3OsRead(fd, &res, sizeof(res)); if( rc==SQLITE_OK ){ - *pRes = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3]; - } - return rc; -} - -/* -** Write a 32-bit integer into a string buffer in big-endian byte order. -*/ -static void put32bits(char *ac, u32 val){ - ac[0] = (val>>24) & 0xff; - ac[1] = (val>>16) & 0xff; - ac[2] = (val>>8) & 0xff; - ac[3] = val & 0xff; + unsigned char ac[4]; + memcpy(ac, &res, 4); + res = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3]; + } + *pRes = res; + return rc; } /* ** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK ** on success or an error code is something goes wrong. */ static int write32bits(OsFile *fd, u32 val){ unsigned char ac[4]; - put32bits(ac, val); + ac[0] = (val>>24) & 0xff; + ac[1] = (val>>16) & 0xff; + ac[2] = (val>>8) & 0xff; + ac[3] = val & 0xff; return sqlite3OsWrite(fd, ac, 4); } /* ** Write the 32-bit integer 'val' into the page identified by page header @@ -439,11 +421,14 @@ ** 'p' at offset 'offset'. */ static void store32bits(u32 val, PgHdr *p, int offset){ unsigned char *ac; ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset]; - put32bits(ac, val); + ac[0] = (val>>24) & 0xff; + ac[1] = (val>>16) & 0xff; + ac[2] = (val>>8) & 0xff; + ac[3] = val & 0xff; } /* ** Read a 32-bit integer at offset 'offset' from the page identified by ** page header 'p'. @@ -454,29 +439,20 @@ return (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3]; } /* -** This function should be called when an error occurs within the pager -** code. The first argument is a pointer to the pager structure, the -** second the error-code about to be returned by a pager API function. -** The value returned is a copy of the second argument to this function. -** -** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT or SQLITE_PROTOCOL, -** the error becomes persistent. All subsequent API calls on this Pager -** will immediately return the same error code. +** Convert the bits in the pPager->errMask into an approprate +** return code. */ -static int pager_error(Pager *pPager, int rc){ - assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK ); - if( - rc==SQLITE_FULL || - rc==SQLITE_IOERR || - rc==SQLITE_CORRUPT || - rc==SQLITE_PROTOCOL - ){ - pPager->errCode = rc; - } +static int pager_errcode(Pager *pPager){ + int rc = SQLITE_OK; + if( pPager->errMask & PAGER_ERR_LOCK ) rc = SQLITE_PROTOCOL; + if( pPager->errMask & PAGER_ERR_DISK ) rc = SQLITE_IOERR; + if( pPager->errMask & PAGER_ERR_FULL ) rc = SQLITE_FULL; + if( pPager->errMask & PAGER_ERR_MEM ) rc = SQLITE_NOMEM; + if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT; return rc; } #ifdef SQLITE_CHECK_PAGES /* @@ -498,11 +474,11 @@ ** that the page is either dirty or still matches the calculated page-hash. */ #define CHECK_PAGE(x) checkPage(x) static void checkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; - assert( !pPg->pageHash || pPager->errCode || MEMDB || pPg->dirty || + assert( !pPg->pageHash || pPager->errMask || MEMDB || pPg->dirty || pPg->pageHash==pager_pagehash(pPg) ); } #else #define CHECK_PAGE(x) @@ -599,11 +575,11 @@ } assert( offset%JOURNAL_HDR_SZ(pPager)==0 ); assert( offset>=c ); assert( (offset-c)journalOff = offset; - return sqlite3OsSeek(pPager->jfd, pPager->journalOff); + return sqlite3OsSeek(&pPager->jfd, pPager->journalOff); } /* ** The journal file must be open when this routine is called. A journal ** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the @@ -617,11 +593,10 @@ ** - 4 bytes: Sector size used by the process that wrote this journal. ** ** Followed by (JOURNAL_HDR_SZ - 24) bytes of unused space. */ static int writeJournalHdr(Pager *pPager){ - char zHeader[sizeof(aJournalMagic)+16]; int rc = seekJournalHdr(pPager); if( rc ) return rc; pPager->journalHdr = pPager->journalOff; @@ -636,30 +611,36 @@ ** be written until nRec is filled in as part of next syncJournal(). ** ** Actually maybe the whole journal header should be delayed until that ** point. Think about this. */ - memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); - /* The nRec Field. 0xFFFFFFFF for no-sync journals. */ - put32bits(&zHeader[sizeof(aJournalMagic)], pPager->noSync ? 0xffffffff : 0); - /* The random check-hash initialiser */ - sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); - put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); - /* The initial database size */ - put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbSize); - /* The assumed sector size for this process */ - put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize); - rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader)); + rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); + + if( rc==SQLITE_OK ){ + /* The nRec Field. 0xFFFFFFFF for no-sync journals. */ + rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0); + } + if( rc==SQLITE_OK ){ + /* The random check-hash initialiser */ + sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); + rc = write32bits(&pPager->jfd, pPager->cksumInit); + } + if( rc==SQLITE_OK ){ + /* The initial database size */ + rc = write32bits(&pPager->jfd, pPager->dbSize); + } + if( rc==SQLITE_OK ){ + /* The assumed sector size for this process */ + rc = write32bits(&pPager->jfd, pPager->sectorSize); + } /* The journal header has been written successfully. Seek the journal ** file descriptor to the end of the journal header sector. */ if( rc==SQLITE_OK ){ - rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff-1); - if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(pPager->jfd, "\000", 1); - } + sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1); + rc = sqlite3OsWrite(&pPager->jfd, "\000", 1); } return rc; } /* @@ -692,37 +673,37 @@ if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ return SQLITE_DONE; } - rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic)); + rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic)); if( rc ) return rc; if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ return SQLITE_DONE; } - rc = read32bits(pPager->jfd, pNRec); + rc = read32bits(&pPager->jfd, pNRec); if( rc ) return rc; - rc = read32bits(pPager->jfd, &pPager->cksumInit); + rc = read32bits(&pPager->jfd, &pPager->cksumInit); if( rc ) return rc; - rc = read32bits(pPager->jfd, pDbSize); + rc = read32bits(&pPager->jfd, pDbSize); if( rc ) return rc; /* Update the assumed sector-size to match the value used by ** the process that created this journal. If this journal was ** created by a process other than this one, then this routine ** is being called from within pager_playback(). The local value ** of Pager.sectorSize is restored at the end of that routine. */ - rc = read32bits(pPager->jfd, (u32 *)&pPager->sectorSize); + rc = read32bits(&pPager->jfd, (u32 *)&pPager->sectorSize); if( rc ) return rc; pPager->journalOff += JOURNAL_HDR_SZ(pPager); - rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff); + rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff); return rc; } /* @@ -738,20 +719,16 @@ ** + 4 bytes: Master journal name checksum. ** + 8 bytes: aJournalMagic[]. ** ** The master journal page checksum is the sum of the bytes in the master ** journal name. -** -** If zMaster is a NULL pointer (occurs for a single database transaction), -** this call is a no-op. */ static int writeMasterJournal(Pager *pPager, const char *zMaster){ int rc; int len; int i; - u32 cksum = 0; - char zBuf[sizeof(aJournalMagic)+2*4]; + u32 cksum = 0; if( !zMaster || pPager->setMaster) return SQLITE_OK; pPager->setMaster = 1; len = strlen(zMaster); @@ -767,21 +744,24 @@ rc = seekJournalHdr(pPager); if( rc!=SQLITE_OK ) return rc; } pPager->journalOff += (len+20); - rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager)); + rc = write32bits(&pPager->jfd, PAGER_MJ_PGNO(pPager)); + if( rc!=SQLITE_OK ) return rc; + + rc = sqlite3OsWrite(&pPager->jfd, zMaster, len); + if( rc!=SQLITE_OK ) return rc; + + rc = write32bits(&pPager->jfd, len); if( rc!=SQLITE_OK ) return rc; - rc = sqlite3OsWrite(pPager->jfd, zMaster, len); + rc = write32bits(&pPager->jfd, cksum); if( rc!=SQLITE_OK ) return rc; - put32bits(zBuf, len); - put32bits(&zBuf[4], cksum); - memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic)); - rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic)); - pPager->needSync = !pPager->noSync; + rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); + pPager->needSync = 1; return rc; } /* ** Add or remove a page from the list of all pages that are in the @@ -840,11 +820,10 @@ ** opened. Any outstanding pages are invalidated and subsequent attempts ** to access those pages will likely result in a coredump. */ static void pager_reset(Pager *pPager){ PgHdr *pPg, *pNext; - if( pPager->errCode ) return; for(pPg=pPager->pAll; pPg; pPg=pNext){ pNext = pPg->pNextAll; sqliteFree(pPg); } pPager->pFirst = 0; @@ -854,11 +833,11 @@ memset(pPager->aHash, 0, sizeof(pPager->aHash)); pPager->nPage = 0; if( pPager->state>=PAGER_RESERVED ){ sqlite3pager_rollback(pPager); } - sqlite3OsUnlock(pPager->fd, NO_LOCK); + sqlite3OsUnlock(&pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; pPager->dbSize = -1; pPager->nRef = 0; assert( pPager->journalOpen==0 ); } @@ -900,14 +879,13 @@ #endif } pPager->dirtyCache = 0; pPager->nRec = 0; }else{ - assert( pPager->aInJournal==0 ); assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } - rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK); + rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; pPager->origDbSize = 0; pPager->setMaster = 0; return rc; } @@ -930,11 +908,11 @@ ** FIX ME: Consider adding every 200th (or so) byte of the data to the ** checksum. That way if a single page spans 3 or more disk sectors and ** only the middle sector is corrupt, we will still have a reasonable ** chance of failing the checksum and thus detecting the problem. */ -static u32 pager_cksum(Pager *pPager, Pgno pgno, const u8 *aData){ +static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){ u32 cksum = pPager->cksumInit; int i = pPager->pageSize-200; while( i>0 ){ cksum += aData[i]; i -= 200; @@ -954,16 +932,10 @@ int rc; PgHdr *pPg; /* An existing page in the cache */ Pgno pgno; /* The page number of a page in journal */ u32 cksum; /* Checksum used for sanity checking */ u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */ - - /* useCksum should be true for the main journal and false for - ** statement journals. Verify that this is always the case - */ - assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) ); - rc = read32bits(jfd, &pgno); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsRead(jfd, &aData, pPager->pageSize); if( rc!=SQLITE_OK ) return rc; @@ -995,33 +967,17 @@ ** page in the pager cache. In this case just update the pager cache, ** not the database file. The page is left marked dirty in this case. ** ** If in EXCLUSIVE state, then we update the pager cache if it exists ** and the main file. The page is then marked not dirty. - ** - ** Ticket #1171: The statement journal might contain page content that is - ** different from the page content at the start of the transaction. - ** This occurs when a page is changed prior to the start of a statement - ** then changed again within the statement. When rolling back such a - ** statement we must not write to the original database unless we know - ** for certain that original page contents are in the main rollback - ** journal. Otherwise, if a full ROLLBACK occurs after the statement - ** rollback the full ROLLBACK will not restore the page to its original - ** content. Two conditions must be met before writing to the database - ** files. (1) the database must be locked. (2) we know that the original - ** page content is in the main journal either because the page is not in - ** cache or else it is marked as needSync==0. */ pPg = pager_lookup(pPager, pgno); - assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 ); + assert( pPager->state>=PAGER_EXCLUSIVE || pPg ); TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); - if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ - rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); - if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize); - } - if( pPg ) pPg->dirty = 0; + if( pPager->state>=PAGER_EXCLUSIVE ){ + sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize); + rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize); } if( pPg ){ /* No page should ever be explicitly rolled back that is in use, except ** for page 1 which is held in use in order to keep the lock on the ** database active. However such a page may be rolled back as a result @@ -1033,13 +989,17 @@ pData = PGHDR_TO_DATA(pPg); memcpy(pData, aData, pPager->pageSize); if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/ pPager->xDestructor(pData, pPager->pageSize); } + if( pPager->state>=PAGER_EXCLUSIVE ){ + pPg->dirty = 0; + pPg->needSync = 0; #ifdef SQLITE_CHECK_PAGES - pPg->pageHash = pager_pagehash(pPg); + pPg->pageHash = pager_pagehash(pPg); #endif + } CODEC(pPager, pData, pPg->pgno, 3); } return rc; } @@ -1055,21 +1015,22 @@ ** a different master journal, then this master journal can be deleted. */ static int pager_delmaster(const char *zMaster){ int rc; int master_open = 0; - OsFile *master = 0; + OsFile master; char *zMasterJournal = 0; /* Contents of master journal file */ i64 nMasterJournal; /* Size of master journal file */ /* Open the master journal file exclusively in case some other process ** is running this routine also. Not that it makes too much difference. */ + memset(&master, 0, sizeof(master)); rc = sqlite3OsOpenReadOnly(zMaster, &master); if( rc!=SQLITE_OK ) goto delmaster_out; master_open = 1; - rc = sqlite3OsFileSize(master, &nMasterJournal); + rc = sqlite3OsFileSize(&master, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; if( nMasterJournal>0 ){ char *zJournal; char *zMasterPtr = 0; @@ -1080,29 +1041,30 @@ zMasterJournal = (char *)sqliteMalloc(nMasterJournal); if( !zMasterJournal ){ rc = SQLITE_NOMEM; goto delmaster_out; } - rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal); + rc = sqlite3OsRead(&master, zMasterJournal, nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; zJournal = zMasterJournal; while( (zJournal-zMasterJournal)pAll; pPg; pPg=pPg->pNextAll){ char zBuf[SQLITE_MAX_PAGE_SIZE]; if( !pPg->dirty ) continue; if( (int)pPg->pgno <= pPager->origDbSize ){ - rc = sqlite3OsSeek(pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1)); - if( rc==SQLITE_OK ){ - rc = sqlite3OsRead(pPager->fd, zBuf, pPager->pageSize); - } + sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1)); + rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize); TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno); if( rc ) break; CODEC(pPager, zBuf, pPg->pgno, 2); }else{ memset(zBuf, 0, pPager->pageSize); @@ -1176,11 +1136,11 @@ ** Truncate the main file of the given pager to the number of pages ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ assert( pPager->state>=PAGER_EXCLUSIVE ); - return sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage); + return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage); } /* ** Playback the journal and thus restore the database file to ** the state it was in before we started making changes. @@ -1244,29 +1204,29 @@ /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( pPager->journalOpen ); - rc = sqlite3OsFileSize(pPager->jfd, &szJ); + rc = sqlite3OsFileSize(&pPager->jfd, &szJ); if( rc!=SQLITE_OK ){ goto end_playback; } /* Read the master journal name from the journal, if it is present. ** If a master journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. */ - rc = readMasterJournal(pPager->jfd, &zMaster); + rc = readMasterJournal(&pPager->jfd, &zMaster); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){ sqliteFree(zMaster); zMaster = 0; if( rc==SQLITE_DONE ) rc = SQLITE_OK; goto end_playback; } - sqlite3OsSeek(pPager->jfd, 0); + sqlite3OsSeek(&pPager->jfd, 0); pPager->journalOff = 0; /* This loop terminates either when the readJournalHdr() call returns ** SQLITE_DONE or an IO error occurs. */ while( 1 ){ @@ -1305,17 +1265,17 @@ goto end_playback; } pPager->dbSize = mxPg; } - /* rc = sqlite3OsSeek(pPager->jfd, JOURNAL_HDR_SZ(pPager)); */ + /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */ if( rc!=SQLITE_OK ) goto end_playback; /* Copy original pages out of the journal and back into the database file. */ for(i=0; ijfd, 1); + rc = pager_playback_one_page(pPager, &pPager->jfd, 1); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; pPager->journalOff = szJ; break; @@ -1378,11 +1338,11 @@ szJ = pPager->journalOff; #ifndef NDEBUG { i64 os_szJ; - rc = sqlite3OsFileSize(pPager->jfd, &os_szJ); + rc = sqlite3OsFileSize(&pPager->jfd, &os_szJ); if( rc!=SQLITE_OK ) return rc; assert( szJ==os_szJ ); } #endif @@ -1404,20 +1364,20 @@ pPager->dbSize = pPager->stmtSize; /* Figure out how many records are in the statement journal. */ assert( pPager->stmtInUse && pPager->journalOpen ); - sqlite3OsSeek(pPager->stfd, 0); + sqlite3OsSeek(&pPager->stfd, 0); nRec = pPager->stmtNRec; /* Copy original pages out of the statement journal and back into the ** database file. Note that the statement journal omits checksums from ** each record since power-failure recovery is not important to statement ** journals. */ for(i=nRec-1; i>=0; i--){ - rc = pager_playback_one_page(pPager, pPager->stfd, 0); + rc = pager_playback_one_page(pPager, &pPager->stfd, 0); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } /* Now roll some pages back from the transaction journal. Pager.stmtJSize @@ -1426,19 +1386,19 @@ ** database, the memory cache, or both. ** ** If it is not zero, then Pager.stmtHdrOff is the offset to the start ** of the first journal header written during this statement transaction. */ - rc = sqlite3OsSeek(pPager->jfd, pPager->stmtJSize); + rc = sqlite3OsSeek(&pPager->jfd, pPager->stmtJSize); if( rc!=SQLITE_OK ){ goto end_stmt_playback; } pPager->journalOff = pPager->stmtJSize; pPager->cksumInit = pPager->stmtCksum; assert( JOURNAL_HDR_SZ(pPager)<(pPager->pageSize+8) ); while( pPager->journalOff <= (hdrOff-(pPager->pageSize+8)) ){ - rc = pager_playback_one_page(pPager, pPager->jfd, 1); + rc = pager_playback_one_page(pPager, &pPager->jfd, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } while( pPager->journalOff < szJ ){ @@ -1451,32 +1411,47 @@ } if( nRec==0 ){ nRec = (szJ - pPager->journalOff) / (pPager->pageSize+8); } for(i=nRec-1; i>=0 && pPager->journalOff < szJ; i--){ - rc = pager_playback_one_page(pPager, pPager->jfd, 1); + rc = pager_playback_one_page(pPager, &pPager->jfd, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } } pPager->journalOff = szJ; end_stmt_playback: if( rc!=SQLITE_OK ){ - rc = pager_error(pPager, SQLITE_CORRUPT); + pPager->errMask |= PAGER_ERR_CORRUPT; + rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */ }else{ pPager->journalOff = szJ; /* pager_reload_cache(pPager); */ } return rc; } /* ** Change the maximum number of in-memory pages that are allowed. +** +** The maximum number is the absolute value of the mxPage parameter. +** If mxPage is negative, the noSync flag is also set. noSync bypasses +** calls to sqlite3OsSync(). The pager runs much faster with noSync on, +** but if the operating system crashes or there is an abrupt power +** failure, the database file might be left in an inconsistent and +** unrepairable state. */ void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){ + if( mxPage>=0 ){ + pPager->noSync = pPager->tempFile; + if( pPager->noSync ) pPager->needSync = 0; + }else{ + pPager->noSync = 1; + mxPage = -mxPage; + } if( mxPage>10 ){ pPager->mxPage = mxPage; }else{ pPager->mxPage = 10; } @@ -1515,33 +1490,25 @@ if( pPager->noSync ) pPager->needSync = 0; } #endif /* -** The following global variable is incremented whenever the library -** attempts to open a temporary file. This information is used for -** testing and analysis only. -*/ -int sqlite3_opentemp_count = 0; - -/* -** Open a temporary file. Write the name of the file into zFile -** (zFile must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write +** Open a temporary file. Write the name of the file into zName +** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write ** the file descriptor into *fd. Return SQLITE_OK on success or some ** other error code if we fail. ** ** The OS will automatically delete the temporary file when it is ** closed. */ -static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){ +static int sqlite3pager_opentemp(char *zFile, OsFile *fd){ int cnt = 8; int rc; - sqlite3_opentemp_count++; /* Used for testing and analysis only */ do{ cnt--; sqlite3OsTempFileName(zFile); - rc = sqlite3OsOpenExclusive(zFile, pFd, 1); + rc = sqlite3OsOpenExclusive(zFile, fd, 1); }while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM ); return rc; } /* @@ -1562,44 +1529,34 @@ Pager **ppPager, /* Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ int flags /* flags controlling this file */ ){ - Pager *pPager = 0; + Pager *pPager; char *zFullPathname = 0; int nameLen; - OsFile *fd; + OsFile fd; int rc = SQLITE_OK; int i; int tempFile = 0; int memDb = 0; int readOnly = 0; int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; int noReadlock = (flags & PAGER_NO_READLOCK)!=0; char zTemp[SQLITE_TEMPNAME_SIZE]; -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - const ThreadData *pTsdro = sqlite3ThreadDataReadOnly(); -#endif - - /* If malloc() has already failed return SQLITE_NOMEM. Before even - ** testing for this, set *ppPager to NULL so the caller knows the pager - ** structure was never allocated. - */ + *ppPager = 0; - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + memset(&fd, 0, sizeof(fd)); + if( sqlite3_malloc_failed ){ return SQLITE_NOMEM; } - memset(&fd, 0, sizeof(fd)); - - /* Open the pager file and set zFullPathname to point at malloc()ed - ** memory containing the complete filename (i.e. including the directory). - */ if( zFilename && zFilename[0] ){ #ifndef SQLITE_OMIT_MEMORYDB if( strcmp(zFilename,":memory:")==0 ){ memDb = 1; zFullPathname = sqliteStrDup(""); + rc = SQLITE_OK; }else #endif { zFullPathname = sqlite3OsFullPathname(zFilename); if( zFullPathname ){ @@ -1612,82 +1569,70 @@ zFullPathname = sqlite3OsFullPathname(zFilename); if( rc==SQLITE_OK ){ tempFile = 1; } } - - /* Allocate the Pager structure. As part of the same allocation, allocate - ** space for the full paths of the file, directory and journal - ** (Pager.zFilename, Pager.zDirectory and Pager.zJournal). - */ - if( zFullPathname ){ - nameLen = strlen(zFullPathname); - pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); - } - - /* If an error occured in either of the blocks above, free the memory - ** pointed to by zFullPathname, free the Pager structure and close the - ** file. Since the pager is not allocated there is no need to set - ** any Pager.errMask variables. - */ - if( !pPager || !zFullPathname || rc!=SQLITE_OK ){ + if( !zFullPathname ){ + sqlite3OsClose(&fd); + return SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + sqlite3OsClose(&fd); + sqliteFree(zFullPathname); + return rc; + } + nameLen = strlen(zFullPathname); + pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); + if( pPager==0 ){ sqlite3OsClose(&fd); sqliteFree(zFullPathname); - sqliteFree(pPager); - return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc); + return SQLITE_NOMEM; } - TRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname); pPager->zFilename = (char*)&pPager[1]; pPager->zDirectory = &pPager->zFilename[nameLen+1]; pPager->zJournal = &pPager->zDirectory[nameLen+1]; strcpy(pPager->zFilename, zFullPathname); strcpy(pPager->zDirectory, zFullPathname); - for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){} if( i>0 ) pPager->zDirectory[i-1] = 0; strcpy(pPager->zJournal, zFullPathname); sqliteFree(zFullPathname); strcpy(&pPager->zJournal[nameLen], "-journal"); pPager->fd = fd; - /* pPager->journalOpen = 0; */ +#if OS_UNIX + pPager->fd.pPager = pPager; +#endif + pPager->journalOpen = 0; pPager->useJournal = useJournal && !memDb; pPager->noReadlock = noReadlock && readOnly; - /* pPager->stmtOpen = 0; */ - /* pPager->stmtInUse = 0; */ - /* pPager->nRef = 0; */ + pPager->stmtOpen = 0; + pPager->stmtInUse = 0; + pPager->nRef = 0; pPager->dbSize = memDb-1; pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE; - /* pPager->stmtSize = 0; */ - /* pPager->stmtJSize = 0; */ - /* pPager->nPage = 0; */ - /* pPager->nMaxPage = 0; */ + pPager->psAligned = FORCE_ALIGNMENT(pPager->pageSize); + pPager->stmtSize = 0; + pPager->stmtJSize = 0; + pPager->nPage = 0; pPager->mxPage = 100; - assert( PAGER_UNLOCK==0 ); - /* pPager->state = PAGER_UNLOCK; */ - /* pPager->errMask = 0; */ + pPager->state = PAGER_UNLOCK; + pPager->errMask = 0; pPager->tempFile = tempFile; pPager->memDb = memDb; pPager->readOnly = readOnly; - /* pPager->needSync = 0; */ + pPager->needSync = 0; pPager->noSync = pPager->tempFile || !useJournal; pPager->fullSync = (pPager->noSync?0:1); - /* pPager->pFirst = 0; */ - /* pPager->pFirstSynced = 0; */ - /* pPager->pLast = 0; */ + pPager->pFirst = 0; + pPager->pFirstSynced = 0; + pPager->pLast = 0; pPager->nExtra = FORCE_ALIGNMENT(nExtra); pPager->sectorSize = PAGER_SECTOR_SIZE; - /* pPager->pBusyHandler = 0; */ - /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ + pPager->pBusyHandler = 0; + memset(pPager->aHash, 0, sizeof(pPager->aHash)); *ppPager = pPager; -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - if( pTsdro->useMemoryManagement ){ - ThreadData *pTsd = sqlite3ThreadData(); - pPager->pNext = pTsd->pPager; - pTsd->pPager = pPager; - } -#endif return SQLITE_OK; } /* ** Set the busy handler function. @@ -1718,99 +1663,52 @@ void sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,int)){ pPager->xReiniter = xReinit; } /* -** Set the page size. Return the new size. If the suggest new page -** size is inappropriate, then an alternative page size is selected -** and returned. +** Set the page size. +** +** The page size must only be changed when the cache is empty. */ -int sqlite3pager_set_pagesize(Pager *pPager, int pageSize){ +void sqlite3pager_set_pagesize(Pager *pPager, int pageSize){ assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE ); - if( !pPager->memDb ){ - pPager->pageSize = pageSize; - } - return pPager->pageSize; -} - -/* -** The following set of routines are used to disable the simulated -** I/O error mechanism. These routines are used to avoid simulated -** errors in places where we do not care about errors. -** -** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops -** and generate no code. -*/ -#ifdef SQLITE_TEST -extern int sqlite3_io_error_pending; -extern int sqlite3_io_error_hit; -static int saved_cnt; -void clear_simulated_io_error(){ - sqlite3_io_error_hit = 0; -} -void disable_simulated_io_errors(void){ - saved_cnt = sqlite3_io_error_pending; - sqlite3_io_error_pending = -1; -} -void enable_simulated_io_errors(void){ - sqlite3_io_error_pending = saved_cnt; -} -#else -# define clear_simulated_io_error() -# define disable_simulated_io_errors() -# define enable_simulated_io_errors() -#endif + pPager->pageSize = pageSize; + pPager->psAligned = FORCE_ALIGNMENT(pageSize); +} /* ** Read the first N bytes from the beginning of the file into memory -** that pDest points to. -** -** No error checking is done. The rational for this is that this function -** may be called even if the file does not exist or contain a header. In -** these cases sqlite3OsRead() will return an error, to which the correct -** response is to zero the memory at pDest and continue. A real IO error -** will presumably recur and be picked up later (Todo: Think about this). +** that pDest points to. No error checking is done. */ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){ memset(pDest, 0, N); if( MEMDB==0 ){ - sqlite3OsSeek(pPager->fd, 0); - sqlite3OsRead(pPager->fd, pDest, N); - clear_simulated_io_error(); + sqlite3OsSeek(&pPager->fd, 0); + sqlite3OsRead(&pPager->fd, pDest, N); } } /* ** Return the total number of pages in the disk file associated with -** pPager. -** -** If the PENDING_BYTE lies on the page directly after the end of the -** file, then consider this page part of the file too. For example, if -** PENDING_BYTE is byte 4096 (the first byte of page 5) and the size of the -** file is 4096 bytes, 5 is returned instead of 4. +** pPager. */ int sqlite3pager_pagecount(Pager *pPager){ i64 n; assert( pPager!=0 ); if( pPager->dbSize>=0 ){ - n = pPager->dbSize; - } else { - if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){ - pager_error(pPager, SQLITE_IOERR); - return 0; - } - if( n>0 && npageSize ){ - n = 1; - }else{ - n /= pPager->pageSize; - } - if( pPager->state!=PAGER_UNLOCK ){ - pPager->dbSize = n; - } - } - if( n==(PENDING_BYTE/pPager->pageSize) ){ + return pPager->dbSize; + } + if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){ + pPager->errMask |= PAGER_ERR_DISK; + return 0; + } + n /= pPager->pageSize; + if( !MEMDB && n==PENDING_BYTE/pPager->pageSize ){ n++; + } + if( pPager->state!=PAGER_UNLOCK ){ + pPager->dbSize = n; } return n; } /* @@ -1909,11 +1807,11 @@ #define memoryTruncate(p) #endif /* ** Try to obtain a lock on a file. Invoke the busy callback if the lock -** is currently not available. Repeat until the busy callback returns +** is currently not available. Repeate until the busy callback returns ** false or until the lock succeeds. ** ** Return SQLITE_OK on success and an error code if we cannot obtain ** the lock. */ @@ -1923,13 +1821,18 @@ assert( PAGER_RESERVED==RESERVED_LOCK ); assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); if( pPager->state>=locktype ){ rc = SQLITE_OK; }else{ + int busy = 1; do { - rc = sqlite3OsLock(pPager->fd, locktype); - }while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) ); + rc = sqlite3OsLock(&pPager->fd, locktype); + }while( rc==SQLITE_BUSY && + pPager->pBusyHandler && + pPager->pBusyHandler->xFunc && + pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) + ); if( rc==SQLITE_OK ){ pPager->state = locktype; } } return rc; @@ -1939,12 +1842,12 @@ ** Truncate the file to the number of pages specified. */ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){ int rc; sqlite3pager_pagecount(pPager); - if( pPager->errCode ){ - rc = pPager->errCode; + if( pPager->errMask!=0 ){ + rc = pager_errcode(pPager); return rc; } if( nPage>=(unsigned)pPager->dbSize ){ return SQLITE_OK; } @@ -1977,42 +1880,39 @@ ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated ** and their memory is freed. Any attempt to use a page associated ** with this page cache after this function returns will likely ** result in a coredump. -** -** This function always succeeds. If a transaction is active an attempt -** is made to roll it back. If an error occurs during the rollback -** a hot journal may be left in the filesystem but no error is returned -** to the caller. */ int sqlite3pager_close(Pager *pPager){ PgHdr *pPg, *pNext; -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - const ThreadData *pTsd = sqlite3ThreadDataReadOnly(); -#endif - switch( pPager->state ){ case PAGER_RESERVED: case PAGER_SYNCED: case PAGER_EXCLUSIVE: { /* We ignore any IO errors that occur during the rollback ** operation. So disable IO error simulation so that testing ** works more easily. */ - disable_simulated_io_errors(); +#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN)) + extern int sqlite3_io_error_pending; + int ioerr_cnt = sqlite3_io_error_pending; + sqlite3_io_error_pending = -1; +#endif sqlite3pager_rollback(pPager); - enable_simulated_io_errors(); +#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN)) + sqlite3_io_error_pending = ioerr_cnt; +#endif if( !MEMDB ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); + sqlite3OsUnlock(&pPager->fd, NO_LOCK); } - assert( pPager->errCode || pPager->journalOpen==0 ); + assert( pPager->journalOpen==0 ); break; } case PAGER_SHARED: { if( !MEMDB ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); + sqlite3OsUnlock(&pPager->fd, NO_LOCK); } break; } default: { /* Do nothing */ @@ -2030,43 +1930,18 @@ #endif pNext = pPg->pNextAll; sqliteFree(pPg); } TRACE2("CLOSE %d\n", PAGERID(pPager)); - assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) ); - if( pPager->journalOpen ){ - sqlite3OsClose(&pPager->jfd); - } - sqliteFree(pPager->aInJournal); - if( pPager->stmtOpen ){ - sqlite3OsClose(&pPager->stfd); - } sqlite3OsClose(&pPager->fd); + assert( pPager->journalOpen==0 ); /* Temp files are automatically deleted by the OS ** if( pPager->tempFile ){ ** sqlite3OsDelete(pPager->zFilename); ** } */ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - /* Remove the pager from the linked list of pagers starting at - ** ThreadData.pPager if memory-management is enabled. - */ - if( pTsd->useMemoryManagement ){ - if( pPager==pTsd->pPager ){ - pTsd->pPager = pPager->pNext; - }else{ - Pager *pTmp; - for(pTmp = pTsd->pPager; pTmp->pNext!=pPager; pTmp=pTmp->pNext); - pTmp->pNext = pPager->pNext; - } - } -#endif - -#ifdef SQLITE_HAS_CODEC - sqlite3pager_free_codecarg(pPager->pCodecArg); -#endif sqliteFree(pPager); return SQLITE_OK; } /* @@ -2168,11 +2043,11 @@ { /* Make sure the pPager->nRec counter we are keeping agrees ** with the nRec computed from the size of the journal file. */ i64 jSz; - rc = sqlite3OsFileSize(pPager->jfd, &jSz); + rc = sqlite3OsFileSize(&pPager->jfd, &jSz); if( rc!=0 ) return rc; assert( pPager->journalOff==jSz ); } #endif { @@ -2181,24 +2056,21 @@ ** all data has really hit the disk before nRec is updated to mark ** it as a candidate for rollback. */ if( pPager->fullSync ){ TRACE2("SYNC journal of %d\n", PAGERID(pPager)); - rc = sqlite3OsSync(pPager->jfd, 0); + rc = sqlite3OsSync(&pPager->jfd); if( rc!=0 ) return rc; } - rc = sqlite3OsSeek(pPager->jfd, - pPager->journalHdr + sizeof(aJournalMagic)); - if( rc ) return rc; - rc = write32bits(pPager->jfd, pPager->nRec); + sqlite3OsSeek(&pPager->jfd, pPager->journalHdr + sizeof(aJournalMagic)); + rc = write32bits(&pPager->jfd, pPager->nRec); if( rc ) return rc; - rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff); - if( rc ) return rc; + sqlite3OsSeek(&pPager->jfd, pPager->journalOff); } TRACE2("SYNC journal of %d\n", PAGERID(pPager)); - rc = sqlite3OsSync(pPager->jfd, pPager->fullSync); + rc = sqlite3OsSync(&pPager->jfd); if( rc!=0 ) return rc; pPager->journalStarted = 1; } pPager->needSync = 0; @@ -2259,24 +2131,22 @@ return rc; } while( pList ){ assert( pList->dirty ); - rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); - if( rc ) return rc; + sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3pager_truncate() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. */ if( pList->pgno<=pPager->dbSize ){ CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno); - rc = sqlite3OsWrite(pPager->fd, PGHDR_TO_DATA(pList), - pPager->pageSize); + rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize); CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0); - TEST_INCR(pPager->nWrite); + pPager->nWrite++; } #ifndef NDEBUG else{ TRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno); } @@ -2306,194 +2176,10 @@ } } return pList; } -/* -** Return TRUE if there is a hot journal on the given pager. -** A hot journal is one that needs to be played back. -** -** If the current size of the database file is 0 but a journal file -** exists, that is probably an old journal left over from a prior -** database with the same name. Just delete the journal. -*/ -static int hasHotJournal(Pager *pPager){ - if( !pPager->useJournal ) return 0; - if( !sqlite3OsFileExists(pPager->zJournal) ) return 0; - if( sqlite3OsCheckReservedLock(pPager->fd) ) return 0; - if( sqlite3pager_pagecount(pPager)==0 ){ - sqlite3OsDelete(pPager->zJournal); - return 0; - }else{ - return 1; - } -} - -/* -** Try to find a page in the cache that can be recycled. -** -** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It -** does not set the pPager->errCode variable. -*/ -static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){ - PgHdr *pPg; - *ppPg = 0; - - /* Find a page to recycle. Try to locate a page that does not - ** require us to do an fsync() on the journal. - */ - pPg = pPager->pFirstSynced; - - /* If we could not find a page that does not require an fsync() - ** on the journal file then fsync the journal file. This is a - ** very slow operation, so we work hard to avoid it. But sometimes - ** it can't be helped. - */ - if( pPg==0 && pPager->pFirst && syncOk && !MEMDB){ - int rc = syncJournal(pPager); - if( rc!=0 ){ - return rc; - } - if( pPager->fullSync ){ - /* If in full-sync mode, write a new journal header into the - ** journal file. This is done to avoid ever modifying a journal - ** header that is involved in the rollback of pages that have - ** already been written to the database (in case the header is - ** trashed when the nRec field is updated). - */ - pPager->nRec = 0; - assert( pPager->journalOff > 0 ); - rc = writeJournalHdr(pPager); - if( rc!=0 ){ - return rc; - } - } - pPg = pPager->pFirst; - } - if( pPg==0 ){ - return SQLITE_OK; - } - - assert( pPg->nRef==0 ); - - /* Write the page to the database file if it is dirty. - */ - if( pPg->dirty ){ - int rc; - assert( pPg->needSync==0 ); - pPg->pDirty = 0; - rc = pager_write_pagelist( pPg ); - if( rc!=SQLITE_OK ){ - return rc; - } - } - assert( pPg->dirty==0 ); - - /* If the page we are recycling is marked as alwaysRollback, then - ** set the global alwaysRollback flag, thus disabling the - ** sqlite_dont_rollback() optimization for the rest of this transaction. - ** It is necessary to do this because the page marked alwaysRollback - ** might be reloaded at a later time but at that point we won't remember - ** that is was marked alwaysRollback. This means that all pages must - ** be marked as alwaysRollback from here on out. - */ - if( pPg->alwaysRollback ){ - pPager->alwaysRollback = 1; - } - - /* Unlink the old page from the free list and the hash table - */ - unlinkPage(pPg); - TEST_INCR(pPager->nOvfl); - - *ppPg = pPg; - return SQLITE_OK; -} - -/* -** This function is called to free superfluous dynamically allocated memory -** held by the pager system. Memory in use by any SQLite pager allocated -** by the current thread may be sqliteFree()ed. -** -** nReq is the number of bytes of memory required. Once this much has -** been released, the function returns. A negative value for nReq means -** free as much memory as possible. The return value is the total number -** of bytes of memory released. -*/ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT -int sqlite3pager_release_memory(int nReq){ - const ThreadData *pTsdro = sqlite3ThreadDataReadOnly(); - Pager *p; - int nReleased = 0; - int i; - - /* If the the global mutex is held, this subroutine becomes a - ** o-op; zero bytes of memory are freed. This is because - ** some of the code invoked by this function may also - ** try to obtain the mutex, resulting in a deadlock. - */ - if( sqlite3OsInMutex() ){ - return 0; - } - - /* Outermost loop runs for at most two iterations. First iteration we - ** try to find memory that can be released without calling fsync(). Second - ** iteration (which only runs if the first failed to free nReq bytes of - ** memory) is permitted to call fsync(). This is of course much more - ** expensive. - */ - for(i=0; i<=1; i++){ - - /* Loop through all the SQLite pagers opened by the current thread. */ - for(p=pTsdro->pPager; p && (nReq<0 || nReleasedpNext){ - PgHdr *pPg; - int rc; - - /* For each pager, try to free as many pages as possible (without - ** calling fsync() if this is the first iteration of the outermost - ** loop). - */ - while( SQLITE_OK==(rc = pager_recycle(p, i, &pPg)) && pPg) { - /* We've found a page to free. At this point the page has been - ** removed from the page hash-table, free-list and synced-list - ** (pFirstSynced). It is still in the all pages (pAll) list. - ** Remove it from this list before freeing. - ** - ** Todo: Check the Pager.pStmt list to make sure this is Ok. It - ** probably is though. - */ - PgHdr *pTmp; - assert( pPg ); - page_remove_from_stmt_list(pPg); - if( pPg==p->pAll ){ - p->pAll = pPg->pNextAll; - }else{ - for( pTmp=p->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ); - pTmp->pNextAll = pPg->pNextAll; - } - nReleased += sqliteAllocSize(pPg); - sqliteFree(pPg); - } - - if( rc!=SQLITE_OK ){ - /* An error occured whilst writing to the database file or - ** journal in pager_recycle(). The error is not returned to the - ** caller of this function. Instead, set the Pager.errCode variable. - ** The error will be returned to the user (or users, in the case - ** of a shared pager cache) of the pager for which the error occured. - */ - assert( rc==SQLITE_IOERR || rc==SQLITE_FULL ); - assert( p->state>=PAGER_RESERVED ); - pager_error(p, rc); - } - } - } - - return nReleased; -} -#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ - /* ** Acquire a page. ** ** A read lock on the disk file is obtained when the first page is acquired. ** This read lock is dropped when the last page is released. @@ -2515,42 +2201,45 @@ ** Since _lookup() never goes to disk, it never has to deal with locks ** or journal files. */ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){ PgHdr *pPg; - int rc; + int rc, n; /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page ** number greater than this, or zero, is requested. */ - if( pgno>PAGER_MAX_PGNO || pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){ - return SQLITE_CORRUPT_BKPT; + if( pgno>PAGER_MAX_PGNO || pgno==0 ){ + return SQLITE_CORRUPT; } /* Make sure we have not hit any critical errors. */ assert( pPager!=0 ); *ppPage = 0; - if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ - return pPager->errCode; + if( pPager->errMask & ~(PAGER_ERR_FULL) ){ + return pager_errcode(pPager); } /* If this is the first page accessed, then get a SHARED lock ** on the database file. */ if( pPager->nRef==0 && !MEMDB ){ if( !pPager->noReadlock ){ rc = pager_wait_on_lock(pPager, SHARED_LOCK); if( rc!=SQLITE_OK ){ - return pager_error(pPager, rc); + return rc; } } /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. */ - if( hasHotJournal(pPager) ){ + if( pPager->useJournal && + sqlite3OsFileExists(pPager->zJournal) && + !sqlite3OsCheckReservedLock(&pPager->fd) + ){ int rc; /* Get an EXCLUSIVE lock on the database file. At this point it is ** important that a RESERVED lock is not obtained on the way to the ** EXCLUSIVE lock. If it were, another process might open the @@ -2560,15 +2249,15 @@ ** ** Because the intermediate RESERVED lock is not requested, the ** second process will get to this point in the code and fail to ** obtain it's own EXCLUSIVE lock on the database file. */ - rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK); + rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); + sqlite3OsUnlock(&pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; - return pager_error(pPager, rc); + return rc; } pPager->state = PAGER_EXCLUSIVE; /* Open the journal for reading only. Return SQLITE_BUSY if ** we are unable to open the journal file. @@ -2578,11 +2267,11 @@ ** a write lock, so there is never any chance of two or more ** processes opening the journal at the same time. */ rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd); if( rc!=SQLITE_OK ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); + sqlite3OsUnlock(&pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; return SQLITE_BUSY; } pPager->journalOpen = 1; pPager->journalStarted = 0; @@ -2593,11 +2282,11 @@ /* Playback and delete the journal. Drop the database write ** lock and reacquire the read lock. */ rc = pager_playback(pPager); if( rc!=SQLITE_OK ){ - return pager_error(pPager, rc); + return rc; } } pPg = 0; }else{ /* Search for page in cache */ @@ -2607,17 +2296,21 @@ } } if( pPg==0 ){ /* The requested page is not in the page cache. */ int h; - TEST_INCR(pPager->nMiss); + pPager->nMiss++; if( pPager->nPagemxPage || pPager->pFirst==0 || MEMDB ){ /* Create a new page */ - pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize + pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->psAligned + sizeof(u32) + pPager->nExtra + MEMDB*sizeof(PgHistory) ); if( pPg==0 ){ + if( !MEMDB ){ + pager_unwritelock(pPager); + } + pPager->errMask |= PAGER_ERR_MEM; return SQLITE_NOMEM; } memset(pPg, 0, sizeof(*pPg)); if( MEMDB ){ memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory)); @@ -2624,20 +2317,75 @@ } pPg->pPager = pPager; pPg->pNextAll = pPager->pAll; pPager->pAll = pPg; pPager->nPage++; - if( pPager->nPage>pPager->nMaxPage ){ - assert( pPager->nMaxPage==(pPager->nPage-1) ); - pPager->nMaxPage++; - } }else{ - rc = pager_recycle(pPager, 1, &pPg); - if( rc!=SQLITE_OK ){ - return pager_error(pPager, rc); + /* Find a page to recycle. Try to locate a page that does not + ** require us to do an fsync() on the journal. + */ + pPg = pPager->pFirstSynced; + + /* If we could not find a page that does not require an fsync() + ** on the journal file then fsync the journal file. This is a + ** very slow operation, so we work hard to avoid it. But sometimes + ** it can't be helped. + */ + if( pPg==0 ){ + int rc = syncJournal(pPager); + if( rc!=0 ){ + sqlite3pager_rollback(pPager); + return SQLITE_IOERR; + } + if( pPager->fullSync ){ + /* If in full-sync mode, write a new journal header into the + ** journal file. This is done to avoid ever modifying a journal + ** header that is involved in the rollback of pages that have + ** already been written to the database (in case the header is + ** trashed when the nRec field is updated). + */ + pPager->nRec = 0; + assert( pPager->journalOff > 0 ); + rc = writeJournalHdr(pPager); + if( rc!=0 ){ + sqlite3pager_rollback(pPager); + return SQLITE_IOERR; + } + } + pPg = pPager->pFirst; + } + assert( pPg->nRef==0 ); + + /* Write the page to the database file if it is dirty. + */ + if( pPg->dirty ){ + assert( pPg->needSync==0 ); + pPg->pDirty = 0; + rc = pager_write_pagelist( pPg ); + if( rc!=SQLITE_OK ){ + sqlite3pager_rollback(pPager); + return SQLITE_IOERR; + } + } + assert( pPg->dirty==0 ); + + /* If the page we are recycling is marked as alwaysRollback, then + ** set the global alwaysRollback flag, thus disabling the + ** sqlite_dont_rollback() optimization for the rest of this transaction. + ** It is necessary to do this because the page marked alwaysRollback + ** might be reloaded at a later time but at that point we won't remember + ** that is was marked alwaysRollback. This means that all pages must + ** be marked as alwaysRollback from here on out. + */ + if( pPg->alwaysRollback ){ + pPager->alwaysRollback = 1; } - assert(pPg) ; + + /* Unlink the old page from the free list and the hash table + */ + unlinkPage(pPg); + pPager->nOvfl++; } pPg->pgno = pgno; if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ sqlite3CheckMemory(pPager->aInJournal, pgno/8); assert( pPager->journalOpen ); @@ -2665,47 +2413,44 @@ pPg->pNextHash->pPrevHash = pPg; } if( pPager->nExtra>0 ){ memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra); } - if( pPager->errCode ){ + n = sqlite3pager_pagecount(pPager); + if( pPager->errMask!=0 ){ sqlite3pager_unref(PGHDR_TO_DATA(pPg)); - rc = pPager->errCode; + rc = pager_errcode(pPager); return rc; } - if( sqlite3pager_pagecount(pPager)<(int)pgno ){ + if( n<(int)pgno ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); }else{ int rc; assert( MEMDB==0 ); - rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); - if( rc==SQLITE_OK ){ - rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), - pPager->pageSize); - } + sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize); + rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize); TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno); CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); if( rc!=SQLITE_OK ){ i64 fileSize; - if( sqlite3OsFileSize(pPager->fd,&fileSize)!=SQLITE_OK + if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){ sqlite3pager_unref(PGHDR_TO_DATA(pPg)); - return pager_error(pPager, rc); + return rc; }else{ - clear_simulated_io_error(); memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); } }else{ - TEST_INCR(pPager->nRead); + pPager->nRead++; } } #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif }else{ /* The requested page is in the page cache. */ - TEST_INCR(pPager->nHit); + pPager->nHit++; page_ref(pPg); } *ppPage = PGHDR_TO_DATA(pPg); return SQLITE_OK; } @@ -2724,11 +2469,11 @@ void *sqlite3pager_lookup(Pager *pPager, Pgno pgno){ PgHdr *pPg; assert( pPager!=0 ); assert( pgno!=0 ); - if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ + if( pPager->errMask & ~(PAGER_ERR_FULL) ){ return 0; } pPg = pager_lookup(pPager, pgno); if( pPg==0 ) return 0; page_ref(pPg); @@ -2799,45 +2544,41 @@ int rc; assert( !MEMDB ); assert( pPager->state>=PAGER_RESERVED ); assert( pPager->journalOpen==0 ); assert( pPager->useJournal ); - assert( pPager->aInJournal==0 ); sqlite3pager_pagecount(pPager); pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInJournal==0 ){ rc = SQLITE_NOMEM; goto failed_to_open_journal; } - rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd, - pPager->tempFile); + rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile); pPager->journalOff = 0; pPager->setMaster = 0; pPager->journalHdr = 0; if( rc!=SQLITE_OK ){ goto failed_to_open_journal; } - sqlite3OsSetFullSync(pPager->jfd, pPager->fullSync); - sqlite3OsSetFullSync(pPager->fd, pPager->fullSync); - sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory); + sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd); pPager->journalOpen = 1; pPager->journalStarted = 0; pPager->needSync = 0; pPager->alwaysRollback = 0; pPager->nRec = 0; - if( pPager->errCode ){ - rc = pPager->errCode; - goto failed_to_open_journal; + if( pPager->errMask!=0 ){ + rc = pager_errcode(pPager); + return rc; } pPager->origDbSize = pPager->dbSize; rc = writeJournalHdr(pPager); if( pPager->stmtAutoopen && rc==SQLITE_OK ){ rc = sqlite3pager_stmt_begin(pPager); } - if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ + if( rc!=SQLITE_OK ){ rc = pager_unwritelock(pPager); if( rc==SQLITE_OK ){ rc = SQLITE_FULL; } } @@ -2844,21 +2585,12 @@ return rc; failed_to_open_journal: sqliteFree(pPager->aInJournal); pPager->aInJournal = 0; - if( rc==SQLITE_NOMEM ){ - /* If this was a malloc() failure, then we will not be closing the pager - ** file. So delete any journal file we may have just created. Otherwise, - ** the system will get confused, we have a read-lock on the file and a - ** mysterious journal has appeared in the filesystem. - */ - sqlite3OsDelete(pPager->zJournal); - }else{ - sqlite3OsUnlock(pPager->fd, NO_LOCK); - pPager->state = PAGER_UNLOCK; - } + sqlite3OsUnlock(&pPager->fd, NO_LOCK); + pPager->state = PAGER_UNLOCK; return rc; } /* ** Acquire a write-lock on the database. The lock is removed when @@ -2897,11 +2629,15 @@ assert( pPager->aInJournal==0 ); if( MEMDB ){ pPager->state = PAGER_EXCLUSIVE; pPager->origDbSize = pPager->dbSize; }else{ - rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK); + if( SQLITE_BUSY_RESERVED_LOCK || exFlag ){ + rc = pager_wait_on_lock(pPager, RESERVED_LOCK); + }else{ + rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK); + } if( rc==SQLITE_OK ){ pPager->state = PAGER_RESERVED; if( exFlag ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } @@ -2941,12 +2677,12 @@ Pager *pPager = pPg->pPager; int rc = SQLITE_OK; /* Check for errors */ - if( pPager->errCode ){ - return pPager->errCode; + if( pPager->errMask ){ + return pager_errcode(pPager); } if( pPager->readOnly ){ return SQLITE_PERM; } @@ -2998,31 +2734,25 @@ if( pHist->pOrig ){ memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize); } }else{ u32 cksum; - /* We should never write to the journal file the page that - ** contains the database locks. The following assert verifies - ** that we do not. */ - assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); CODEC(pPager, pData, pPg->pgno, 7); cksum = pager_cksum(pPager, pPg->pgno, pData); saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager); store32bits(cksum, pPg, pPager->pageSize); szPg = pPager->pageSize+8; store32bits(pPg->pgno, pPg, -4); - rc = sqlite3OsWrite(pPager->jfd, &((char*)pData)[-4], szPg); + rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg); pPager->journalOff += szPg; TRACE4("JOURNAL %d page %d needSync=%d\n", PAGERID(pPager), pPg->pgno, pPg->needSync); CODEC(pPager, pData, pPg->pgno, 0); *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved; if( rc!=SQLITE_OK ){ sqlite3pager_rollback(pPager); - if( !pPager->errCode ){ - pager_error(pPager, SQLITE_FULL); - } + pPager->errMask |= PAGER_ERR_FULL; return rc; } pPager->nRec++; assert( pPager->aInJournal!=0 ); pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); @@ -3059,19 +2789,16 @@ } TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); }else{ store32bits(pPg->pgno, pPg, -4); CODEC(pPager, pData, pPg->pgno, 7); - rc = sqlite3OsWrite(pPager->stfd,((char*)pData)-4, - pPager->pageSize+4); + rc = sqlite3OsWrite(&pPager->stfd,((char*)pData)-4, pPager->pageSize+4); TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); CODEC(pPager, pData, pPg->pgno, 0); if( rc!=SQLITE_OK ){ sqlite3pager_rollback(pPager); - if( !pPager->errCode ){ - pager_error(pPager, SQLITE_FULL); - } + pPager->errMask |= PAGER_ERR_FULL; return rc; } pPager->stmtNRec++; assert( pPager->aInStmt!=0 ); pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); @@ -3151,11 +2878,11 @@ if( MEMDB ) return; pPg = pager_lookup(pPager, pgno); pPg->alwaysRollback = 1; - if( pPg && pPg->dirty && !pPager->stmtInUse ){ + if( pPg && pPg->dirty ){ if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSizedbSize ){ /* If this pages is the last page in the file and the file has grown ** during the current transaction, then do NOT mark the page as clean. ** When the database file grows, we must make sure that the last page ** gets written at least once so that the disk file will be the correct @@ -3227,19 +2954,19 @@ */ int sqlite3pager_commit(Pager *pPager){ int rc; PgHdr *pPg; - if( pPager->errCode==SQLITE_FULL ){ + if( pPager->errMask==PAGER_ERR_FULL ){ rc = sqlite3pager_rollback(pPager); if( rc==SQLITE_OK ){ rc = SQLITE_FULL; } return rc; } - if( pPager->errCode ){ - rc = pPager->errCode; + if( pPager->errMask!=0 ){ + rc = pager_errcode(pPager); return rc; } if( pPager->statedbSize = -1; return rc; } - if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ + if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){ if( pPager->state>=PAGER_EXCLUSIVE ){ pager_playback(pPager); } - return pPager->errCode; + return pager_errcode(pPager); } if( pPager->state==PAGER_RESERVED ){ int rc2; rc = pager_reload_cache(pPager); rc2 = pager_unwritelock(pPager); @@ -3363,12 +3090,12 @@ } }else{ rc = pager_playback(pPager); } if( rc!=SQLITE_OK ){ - rc = SQLITE_CORRUPT_BKPT; - pager_error(pPager, SQLITE_CORRUPT); + rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */ + pPager->errMask |= PAGER_ERR_CORRUPT; } pPager->dbSize = -1; return rc; } @@ -3388,18 +3115,16 @@ a[0] = pPager->nRef; a[1] = pPager->nPage; a[2] = pPager->mxPage; a[3] = pPager->dbSize; a[4] = pPager->state; - a[5] = pPager->errCode; -#ifdef SQLITE_TEST + a[5] = pPager->errMask; a[6] = pPager->nHit; a[7] = pPager->nMiss; a[8] = pPager->nOvfl; a[9] = pPager->nRead; a[10] = pPager->nWrite; -#endif return a; } /* ** Set the statement rollback point. @@ -3424,15 +3149,15 @@ return SQLITE_OK; } assert( pPager->journalOpen ); pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInStmt==0 ){ - /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */ + sqlite3OsLock(&pPager->fd, SHARED_LOCK); return SQLITE_NOMEM; } #ifndef NDEBUG - rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize); + rc = sqlite3OsFileSize(&pPager->jfd, &pPager->stmtJSize); if( rc ) goto stmt_begin_failed; assert( pPager->stmtJSize == pPager->journalOff ); #endif pPager->stmtJSize = pPager->journalOff; pPager->stmtSize = pPager->dbSize; @@ -3461,12 +3186,12 @@ int sqlite3pager_stmt_commit(Pager *pPager){ if( pPager->stmtInUse ){ PgHdr *pPg, *pNext; TRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); if( !MEMDB ){ - sqlite3OsSeek(pPager->stfd, 0); - /* sqlite3OsTruncate(pPager->stfd, 0); */ + sqlite3OsSeek(&pPager->stfd, 0); + /* sqlite3OsTruncate(&pPager->stfd, 0); */ sqliteFree( pPager->aInStmt ); pPager->aInStmt = 0; } for(pPg=pPager->pStmt; pPg; pPg=pNext){ pNext = pPg->pNextStmt; @@ -3537,18 +3262,10 @@ */ const char *sqlite3pager_journalname(Pager *pPager){ return pPager->zJournal; } -/* -** Return true if fsync() calls are disabled for this pager. Return FALSE -** if fsync()s are executed normally. -*/ -int sqlite3pager_nosync(Pager *pPager){ - return pPager->noSync; -} - /* ** Set the codec for this pager */ void sqlite3pager_set_codec( Pager *pPager, @@ -3633,13 +3350,12 @@ ** being discarded by the truncation must be written to the journal ** file. */ Pgno i; void *pPage; - int iSkip = PAGER_MJ_PGNO(pPager); for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){ - if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){ + if( !(pPager->aInJournal[i/8] & (1<<(i&7))) ){ rc = sqlite3pager_get(pPager, i, &pPage); if( rc!=SQLITE_OK ) goto sync_exit; rc = sqlite3pager_write(pPage); sqlite3pager_unref(pPage); if( rc!=SQLITE_OK ) goto sync_exit; @@ -3665,11 +3381,11 @@ rc = pager_write_pagelist(pPg); if( rc!=SQLITE_OK ) goto sync_exit; /* Sync the database file. */ if( !pPager->noSync ){ - rc = sqlite3OsSync(pPager->fd, 0); + rc = sqlite3OsSync(&pPager->fd); } pPager->state = PAGER_SYNCED; } @@ -3688,21 +3404,20 @@ ** ** References to the page refered to by pData remain valid. Updating any ** meta-data associated with page pData (i.e. data stored in the nExtra bytes ** allocated along with the page) is the responsibility of the caller. ** -** A transaction must be active when this routine is called. It used to be -** required that a statement transaction was not active, but this restriction -** has been removed (CREATE INDEX needs to move a page when a statement -** transaction is active). +** A transaction must be active when this routine is called, however it is +** illegal to call this routine if a statment transaction is active. */ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){ PgHdr *pPg = DATA_TO_PGHDR(pData); PgHdr *pPgOld; int h; Pgno needSyncPgno = 0; + assert( !pPager->stmtInUse ); assert( pPg->nRef>0 ); TRACE5("MOVE %d page %d (needSync=%d) moves to %d\n", PAGERID(pPager), pPg->pgno, pPg->needSync, pgno); @@ -3779,11 +3494,15 @@ ** Return the current state of the file lock for the given pager. ** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK, or EXCLUSIVE_LOCK. */ int sqlite3pager_lockstate(Pager *pPager){ - return sqlite3OsLockState(pPager->fd); +#ifdef OS_TEST + return pPager->fd->fd.locktype; +#else + return pPager->fd.locktype; +#endif } #endif #ifdef SQLITE_DEBUG /* @@ -3796,7 +3515,5 @@ sqlite3DebugPrintf("PAGE %3d addr=%p nRef=%d\n", pPg->pgno, PGHDR_TO_DATA(pPg), pPg->nRef); } } #endif - -#endif /* SQLITE_OMIT_DISKIO */ Index: SQLite.Interop/src/pager.h ================================================================== --- SQLite.Interop/src/pager.h +++ SQLite.Interop/src/pager.h @@ -11,35 +11,29 @@ ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** -** @(#) $Id: pager.h,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: pager.h,v 1.1 2005/03/01 16:04:31 rmsimpson Exp $ */ -#ifndef _PAGER_H_ -#define _PAGER_H_ - /* ** The default size of a database page. */ #ifndef SQLITE_DEFAULT_PAGE_SIZE # define SQLITE_DEFAULT_PAGE_SIZE 1024 #endif -/* Maximum page size. The upper bound on this value is 32768. This a limit -** imposed by necessity of storing the value in a 2-byte unsigned integer -** and the fact that the page size must be a power of 2. -** -** This value is used to initialize certain arrays on the stack at -** various places in the code. On embedded machines where stack space -** is limited and the flexibility of having large pages is not needed, -** it makes good sense to reduce the maximum page size to something more -** reasonable, like 1024. +/* Maximum page size. The upper bound on this value is 65536 (a limit +** imposed by the 2-byte size of cell array pointers.) The +** maximum page size determines the amount of stack space allocated +** by many of the routines in pager.c and btree.c On embedded architectures +** or any machine where memory and especially stack memory is limited, +** one may wish to chose a smaller value for the maximum page size. */ #ifndef SQLITE_MAX_PAGE_SIZE -# define SQLITE_MAX_PAGE_SIZE 32768 +# define SQLITE_MAX_PAGE_SIZE 8192 #endif /* ** Maximum number of pages in one database. */ @@ -72,11 +66,11 @@ int sqlite3pager_open(Pager **ppPager, const char *zFilename, int nExtra, int flags); void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler); void sqlite3pager_set_destructor(Pager*, void(*)(void*,int)); void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int)); -int sqlite3pager_set_pagesize(Pager*, int); +void sqlite3pager_set_pagesize(Pager*, int); void sqlite3pager_read_fileheader(Pager*, int, unsigned char*); void sqlite3pager_set_cachesize(Pager*, int); int sqlite3pager_close(Pager *pPager); int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage); void *sqlite3pager_lookup(Pager *pPager, Pgno pgno); @@ -101,22 +95,17 @@ int *sqlite3pager_stats(Pager*); void sqlite3pager_set_safety_level(Pager*,int); const char *sqlite3pager_filename(Pager*); const char *sqlite3pager_dirname(Pager*); const char *sqlite3pager_journalname(Pager*); -int sqlite3pager_nosync(Pager*); int sqlite3pager_rename(Pager*, const char *zNewName); void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*); int sqlite3pager_movepage(Pager*,void*,Pgno); -int sqlite3pager_reset(Pager*); -int sqlite3pager_release_memory(int); #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) int sqlite3pager_lockstate(Pager*); #endif #ifdef SQLITE_TEST void sqlite3pager_refdump(Pager*); int pager3_refinfo_enable; #endif - -#endif /* _PAGER_H_ */ Index: SQLite.Interop/src/parse.c ================================================================== --- SQLite.Interop/src/parse.c +++ SQLite.Interop/src/parse.c @@ -2,11 +2,11 @@ ** The author disclaims copyright to this source code. */ /* First off, code is include which follows the "include" declaration ** in the input file. */ #include -#line 51 "parse.y" +#line 33 "parse.y" #include "sqliteInt.h" #include "parse.h" /* @@ -21,12 +21,12 @@ /* ** An instance of this structure is used to store the LIKE, ** GLOB, NOT LIKE, and NOT GLOB operators. */ struct LikeOp { - Token operator; /* "like" or "glob" or "regexp" */ - int not; /* True if the NOT keyword is present */ + int opcode; /* Either TK_GLOB or TK_LIKE */ + int not; /* True if the NOT keyword is present */ }; /* ** An instance of the following structure describes the event of a ** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, @@ -91,39 +91,39 @@ ** YYNRULE the number of rules in the grammar ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. */ #define YYCODETYPE unsigned char -#define YYNOCODE 240 +#define YYNOCODE 239 #define YYACTIONTYPE unsigned short int #define sqlite3ParserTOKENTYPE Token typedef union { sqlite3ParserTOKENTYPE yy0; - struct {int value; int mask;} yy13; - struct TrigEvent yy132; - IdList* yy160; - Expr* yy178; - int yy230; - Select* yy239; - TriggerStep* yy247; - struct LimitVal yy270; - SrcList* yy285; - Expr * yy292; - Token yy384; - struct LikeOp yy440; - ExprList* yy462; - int yy479; + struct AttachKey yy40; + int yy60; + struct TrigEvent yy62; + struct {int value; int mask;} yy243; + struct LikeOp yy258; + ExprList* yy266; + IdList* yy272; + Select* yy331; + struct LimitVal yy348; + Token yy406; + SrcList* yy427; + Expr* yy454; + TriggerStep* yy455; + int yy477; } YYMINORTYPE; #define YYSTACKDEPTH 100 #define sqlite3ParserARG_SDECL Parse *pParse; #define sqlite3ParserARG_PDECL ,Parse *pParse #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse #define sqlite3ParserARG_STORE yypParser->pParse = pParse -#define YYNSTATE 561 -#define YYNRULE 295 -#define YYERRORSYMBOL 137 -#define YYERRSYMDT yy479 +#define YYNSTATE 564 +#define YYNRULE 305 +#define YYERRORSYMBOL 141 +#define YYERRSYMDT yy477 #define YYFALLBACK 1 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) @@ -173,401 +173,485 @@ ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ static const YYACTIONTYPE yy_action[] = { - /* 0 */ 281, 67, 344, 80, 150, 157, 225, 517, 92, 92, - /* 10 */ 92, 92, 288, 59, 59, 59, 59, 58, 58, 57, - /* 20 */ 57, 57, 65, 346, 478, 48, 544, 86, 59, 59, - /* 30 */ 59, 59, 58, 58, 57, 57, 57, 65, 67, 481, - /* 40 */ 80, 150, 231, 64, 88, 295, 525, 518, 530, 530, - /* 50 */ 72, 72, 92, 92, 92, 92, 219, 59, 59, 59, - /* 60 */ 59, 58, 58, 57, 57, 57, 65, 281, 252, 189, - /* 70 */ 517, 296, 344, 81, 59, 59, 59, 59, 58, 58, - /* 80 */ 57, 57, 57, 65, 166, 115, 246, 303, 264, 323, - /* 90 */ 196, 236, 158, 544, 478, 49, 387, 69, 228, 857, - /* 100 */ 128, 560, 247, 56, 2, 381, 22, 476, 456, 363, - /* 110 */ 64, 88, 295, 525, 518, 530, 530, 72, 72, 92, - /* 120 */ 92, 92, 92, 283, 59, 59, 59, 59, 58, 58, - /* 130 */ 57, 57, 57, 65, 281, 344, 279, 386, 395, 553, - /* 140 */ 388, 165, 386, 276, 361, 288, 223, 439, 520, 451, - /* 150 */ 344, 58, 58, 57, 57, 57, 65, 478, 38, 365, - /* 160 */ 544, 145, 143, 282, 67, 393, 80, 150, 451, 500, - /* 170 */ 393, 189, 478, 36, 500, 424, 425, 64, 88, 295, - /* 180 */ 525, 518, 530, 530, 72, 72, 92, 92, 92, 92, - /* 190 */ 71, 59, 59, 59, 59, 58, 58, 57, 57, 57, - /* 200 */ 65, 281, 508, 508, 508, 429, 146, 508, 508, 508, - /* 210 */ 294, 512, 507, 198, 344, 520, 350, 357, 362, 246, - /* 220 */ 303, 264, 323, 196, 236, 283, 221, 544, 367, 310, - /* 230 */ 228, 228, 57, 57, 57, 65, 478, 48, 308, 299, - /* 240 */ 534, 537, 306, 417, 64, 88, 295, 525, 518, 530, - /* 250 */ 530, 72, 72, 92, 92, 92, 92, 551, 59, 59, - /* 260 */ 59, 59, 58, 58, 57, 57, 57, 65, 281, 550, - /* 270 */ 202, 416, 198, 375, 520, 350, 357, 362, 512, 507, - /* 280 */ 413, 414, 344, 293, 344, 372, 21, 367, 198, 522, - /* 290 */ 517, 350, 357, 362, 544, 359, 539, 371, 374, 126, - /* 300 */ 403, 209, 200, 367, 478, 18, 478, 43, 194, 169, - /* 310 */ 384, 64, 88, 295, 525, 518, 530, 530, 72, 72, - /* 320 */ 92, 92, 92, 92, 232, 59, 59, 59, 59, 58, - /* 330 */ 58, 57, 57, 57, 65, 511, 344, 512, 507, 427, - /* 340 */ 281, 420, 479, 479, 148, 419, 331, 233, 344, 67, - /* 350 */ 344, 80, 150, 517, 344, 176, 155, 309, 478, 32, - /* 360 */ 315, 436, 149, 184, 464, 195, 544, 348, 78, 533, - /* 370 */ 478, 51, 478, 51, 378, 428, 478, 51, 479, 443, - /* 380 */ 158, 377, 85, 64, 88, 295, 525, 518, 530, 530, - /* 390 */ 72, 72, 92, 92, 92, 92, 479, 59, 59, 59, - /* 400 */ 59, 58, 58, 57, 57, 57, 65, 281, 387, 467, - /* 410 */ 504, 162, 77, 324, 344, 290, 521, 457, 22, 300, - /* 420 */ 353, 520, 513, 513, 432, 487, 14, 487, 329, 271, - /* 430 */ 257, 487, 426, 544, 523, 524, 478, 51, 217, 208, - /* 440 */ 206, 144, 380, 355, 534, 537, 353, 55, 513, 513, - /* 450 */ 64, 88, 295, 525, 518, 530, 530, 72, 72, 92, - /* 460 */ 92, 92, 92, 375, 59, 59, 59, 59, 58, 58, - /* 470 */ 57, 57, 57, 65, 281, 372, 11, 127, 71, 218, - /* 480 */ 520, 241, 182, 126, 512, 507, 164, 155, 374, 520, - /* 490 */ 338, 488, 452, 398, 543, 353, 200, 513, 513, 1, - /* 500 */ 544, 401, 353, 520, 513, 513, 200, 553, 366, 165, - /* 510 */ 157, 463, 517, 358, 540, 538, 479, 64, 88, 295, - /* 520 */ 525, 518, 530, 530, 72, 72, 92, 92, 92, 92, - /* 530 */ 468, 59, 59, 59, 59, 58, 58, 57, 57, 57, - /* 540 */ 65, 370, 541, 512, 507, 437, 281, 344, 172, 506, - /* 550 */ 239, 344, 512, 507, 344, 387, 224, 448, 93, 344, - /* 560 */ 89, 344, 313, 344, 555, 22, 512, 507, 182, 478, - /* 570 */ 27, 520, 544, 478, 43, 517, 478, 50, 561, 547, - /* 580 */ 369, 478, 47, 478, 114, 478, 95, 528, 91, 64, - /* 590 */ 88, 295, 525, 518, 530, 530, 72, 72, 92, 92, - /* 600 */ 92, 92, 479, 59, 59, 59, 59, 58, 58, 57, - /* 610 */ 57, 57, 65, 281, 226, 344, 251, 174, 110, 344, - /* 620 */ 141, 147, 344, 465, 344, 449, 325, 370, 270, 344, - /* 630 */ 421, 344, 450, 554, 512, 507, 2, 478, 52, 544, - /* 640 */ 595, 478, 44, 311, 478, 30, 478, 45, 313, 173, - /* 650 */ 418, 478, 53, 478, 25, 479, 64, 88, 295, 525, - /* 660 */ 518, 530, 530, 72, 72, 92, 92, 92, 92, 344, - /* 670 */ 59, 59, 59, 59, 58, 58, 57, 57, 57, 65, - /* 680 */ 281, 344, 404, 479, 433, 344, 470, 344, 152, 344, - /* 690 */ 469, 478, 112, 344, 415, 314, 415, 344, 411, 344, - /* 700 */ 126, 287, 161, 478, 94, 440, 544, 478, 113, 478, - /* 710 */ 12, 478, 99, 401, 465, 478, 41, 292, 456, 478, - /* 720 */ 100, 478, 46, 64, 88, 295, 525, 518, 530, 530, - /* 730 */ 72, 72, 92, 92, 92, 92, 344, 59, 59, 59, - /* 740 */ 59, 58, 58, 57, 57, 57, 65, 281, 344, 485, - /* 750 */ 19, 404, 344, 514, 344, 79, 307, 260, 478, 111, - /* 760 */ 344, 242, 344, 548, 548, 344, 503, 501, 497, 466, - /* 770 */ 478, 42, 404, 544, 478, 26, 478, 39, 478, 3, - /* 780 */ 304, 423, 478, 31, 478, 40, 291, 478, 37, 305, - /* 790 */ 64, 88, 295, 525, 518, 530, 530, 72, 72, 92, - /* 800 */ 92, 92, 92, 344, 59, 59, 59, 59, 58, 58, - /* 810 */ 57, 57, 57, 65, 281, 344, 470, 404, 126, 344, - /* 820 */ 469, 344, 20, 344, 139, 478, 97, 344, 320, 7, - /* 830 */ 242, 344, 190, 181, 180, 208, 451, 478, 28, 258, - /* 840 */ 544, 478, 54, 478, 35, 478, 33, 222, 327, 478, - /* 850 */ 34, 262, 204, 478, 29, 435, 191, 64, 76, 295, - /* 860 */ 525, 518, 530, 530, 72, 72, 92, 92, 92, 92, - /* 870 */ 404, 59, 59, 59, 59, 58, 58, 57, 57, 57, - /* 880 */ 65, 281, 404, 454, 177, 162, 344, 208, 344, 175, - /* 890 */ 479, 320, 447, 235, 211, 794, 242, 286, 456, 516, - /* 900 */ 352, 441, 409, 410, 409, 298, 385, 544, 478, 24, - /* 910 */ 478, 98, 252, 252, 252, 252, 275, 284, 479, 252, - /* 920 */ 334, 252, 252, 479, 281, 88, 295, 525, 518, 530, - /* 930 */ 530, 72, 72, 92, 92, 92, 92, 274, 59, 59, - /* 940 */ 59, 59, 58, 58, 57, 57, 57, 65, 517, 242, - /* 950 */ 544, 244, 252, 237, 340, 215, 494, 214, 390, 546, - /* 960 */ 492, 242, 256, 489, 475, 406, 79, 397, 273, 295, - /* 970 */ 525, 518, 530, 530, 72, 72, 92, 92, 92, 92, - /* 980 */ 116, 59, 59, 59, 59, 58, 58, 57, 57, 57, - /* 990 */ 65, 62, 345, 484, 4, 407, 412, 269, 289, 126, - /* 1000 */ 519, 259, 23, 550, 202, 552, 349, 62, 345, 549, - /* 1010 */ 4, 517, 354, 493, 289, 14, 547, 369, 402, 316, - /* 1020 */ 240, 453, 349, 339, 472, 356, 142, 266, 471, 477, - /* 1030 */ 249, 319, 505, 386, 459, 343, 529, 428, 255, 339, - /* 1040 */ 71, 458, 499, 118, 333, 130, 121, 192, 389, 386, - /* 1050 */ 123, 156, 60, 61, 483, 103, 87, 125, 212, 480, - /* 1060 */ 62, 328, 330, 178, 277, 500, 229, 210, 60, 61, - /* 1070 */ 438, 297, 399, 491, 476, 473, 62, 328, 330, 62, - /* 1080 */ 345, 500, 4, 474, 208, 302, 289, 342, 207, 186, - /* 1090 */ 498, 68, 278, 120, 349, 136, 400, 556, 508, 508, - /* 1100 */ 508, 509, 510, 17, 312, 106, 243, 326, 205, 245, - /* 1110 */ 373, 339, 434, 285, 508, 508, 508, 509, 510, 17, - /* 1120 */ 74, 386, 160, 431, 248, 8, 321, 227, 220, 230, - /* 1130 */ 102, 332, 137, 382, 383, 536, 405, 234, 75, 183, - /* 1140 */ 60, 61, 317, 170, 265, 254, 135, 336, 62, 328, - /* 1150 */ 330, 442, 267, 500, 263, 66, 318, 261, 201, 455, - /* 1160 */ 447, 73, 461, 408, 168, 531, 443, 83, 482, 446, - /* 1170 */ 376, 171, 396, 167, 444, 542, 545, 208, 238, 272, - /* 1180 */ 213, 163, 188, 101, 364, 96, 508, 508, 508, 509, - /* 1190 */ 510, 17, 490, 63, 270, 322, 153, 105, 335, 535, - /* 1200 */ 526, 108, 558, 394, 527, 532, 250, 515, 379, 391, - /* 1210 */ 13, 368, 557, 107, 351, 337, 216, 257, 82, 132, - /* 1220 */ 559, 280, 109, 179, 347, 140, 208, 159, 65, 185, - /* 1230 */ 502, 341, 268, 193, 392, 131, 129, 203, 496, 151, - /* 1240 */ 10, 104, 154, 430, 486, 138, 253, 199, 495, 422, - /* 1250 */ 360, 162, 445, 5, 15, 597, 9, 187, 117, 122, - /* 1260 */ 596, 119, 133, 16, 6, 124, 301, 134, 14, 90, - /* 1270 */ 70, 462, 84, 460, 197, + /* 0 */ 263, 261, 261, 154, 124, 126, 128, 130, 132, 134, + /* 10 */ 136, 138, 140, 142, 350, 567, 145, 641, 261, 369, + /* 20 */ 144, 114, 116, 112, 118, 7, 124, 126, 128, 130, + /* 30 */ 132, 134, 136, 138, 140, 142, 136, 138, 140, 142, + /* 40 */ 110, 94, 146, 157, 162, 167, 156, 161, 120, 122, + /* 50 */ 114, 116, 112, 118, 9, 124, 126, 128, 130, 132, + /* 60 */ 134, 136, 138, 140, 142, 574, 223, 262, 262, 124, + /* 70 */ 126, 128, 130, 132, 134, 136, 138, 140, 142, 13, + /* 80 */ 96, 145, 13, 2, 262, 144, 4, 78, 371, 92, + /* 90 */ 10, 373, 380, 385, 132, 134, 136, 138, 140, 142, + /* 100 */ 75, 3, 562, 388, 296, 110, 94, 146, 157, 162, + /* 110 */ 167, 156, 161, 120, 122, 114, 116, 112, 118, 77, + /* 120 */ 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, + /* 130 */ 145, 65, 573, 13, 144, 11, 371, 66, 292, 373, + /* 140 */ 380, 385, 870, 1, 563, 14, 15, 4, 14, 15, + /* 150 */ 172, 388, 51, 665, 110, 94, 146, 157, 162, 167, + /* 160 */ 156, 161, 120, 122, 114, 116, 112, 118, 72, 124, + /* 170 */ 126, 128, 130, 132, 134, 136, 138, 140, 142, 51, + /* 180 */ 37, 341, 40, 59, 67, 69, 305, 336, 107, 106, + /* 190 */ 108, 847, 572, 34, 338, 96, 366, 349, 13, 14, + /* 200 */ 15, 371, 12, 145, 373, 380, 385, 144, 564, 40, + /* 210 */ 59, 67, 69, 305, 336, 75, 388, 3, 562, 190, + /* 220 */ 345, 338, 44, 45, 95, 460, 802, 110, 94, 146, + /* 230 */ 157, 162, 167, 156, 161, 120, 122, 114, 116, 112, + /* 240 */ 118, 575, 124, 126, 128, 130, 132, 134, 136, 138, + /* 250 */ 140, 142, 20, 48, 800, 364, 362, 101, 102, 367, + /* 260 */ 499, 295, 49, 596, 14, 15, 191, 32, 33, 27, + /* 270 */ 148, 403, 96, 50, 147, 534, 46, 145, 494, 466, + /* 280 */ 456, 144, 580, 279, 36, 340, 47, 399, 309, 81, + /* 290 */ 368, 401, 75, 335, 398, 505, 176, 501, 150, 151, + /* 300 */ 197, 110, 94, 146, 157, 162, 167, 156, 161, 120, + /* 310 */ 122, 114, 116, 112, 118, 77, 124, 126, 128, 130, + /* 320 */ 132, 134, 136, 138, 140, 142, 149, 280, 258, 169, + /* 330 */ 96, 39, 281, 13, 298, 367, 96, 175, 22, 335, + /* 340 */ 28, 145, 188, 402, 33, 144, 217, 6, 5, 171, + /* 350 */ 75, 173, 174, 25, 176, 581, 75, 57, 58, 507, + /* 360 */ 235, 351, 356, 357, 265, 110, 94, 146, 157, 162, + /* 370 */ 167, 156, 161, 120, 122, 114, 116, 112, 118, 503, + /* 380 */ 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, + /* 390 */ 457, 77, 243, 294, 48, 227, 236, 293, 297, 14, + /* 400 */ 15, 288, 96, 49, 217, 152, 222, 163, 168, 278, + /* 410 */ 24, 13, 687, 13, 50, 145, 518, 201, 152, 144, + /* 420 */ 163, 168, 75, 358, 582, 171, 176, 173, 174, 263, + /* 430 */ 171, 261, 173, 174, 354, 356, 357, 588, 211, 110, + /* 440 */ 94, 146, 157, 162, 167, 156, 161, 120, 122, 114, + /* 450 */ 116, 112, 118, 654, 124, 126, 128, 130, 132, 134, + /* 460 */ 136, 138, 140, 142, 303, 13, 688, 96, 250, 817, + /* 470 */ 96, 16, 17, 18, 246, 81, 216, 14, 15, 14, + /* 480 */ 15, 145, 13, 406, 435, 144, 13, 75, 487, 387, + /* 490 */ 75, 493, 248, 258, 235, 660, 358, 262, 310, 852, + /* 500 */ 171, 26, 173, 174, 253, 110, 94, 146, 157, 162, + /* 510 */ 167, 156, 161, 120, 122, 114, 116, 112, 118, 397, + /* 520 */ 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, + /* 530 */ 229, 14, 15, 489, 250, 152, 252, 163, 168, 171, + /* 540 */ 839, 173, 174, 360, 361, 96, 145, 533, 14, 15, + /* 550 */ 144, 866, 14, 15, 801, 442, 312, 275, 255, 453, + /* 560 */ 850, 338, 251, 535, 536, 75, 662, 247, 13, 493, + /* 570 */ 110, 94, 146, 157, 162, 167, 156, 161, 120, 122, + /* 580 */ 114, 116, 112, 118, 845, 124, 126, 128, 130, 132, + /* 590 */ 134, 136, 138, 140, 142, 726, 96, 171, 96, 173, + /* 600 */ 174, 171, 252, 173, 174, 152, 583, 163, 168, 42, + /* 610 */ 720, 525, 96, 145, 441, 271, 75, 144, 75, 170, + /* 620 */ 302, 640, 91, 31, 358, 313, 320, 322, 251, 432, + /* 630 */ 434, 433, 75, 844, 14, 15, 176, 110, 94, 146, + /* 640 */ 157, 162, 167, 156, 161, 120, 122, 114, 116, 112, + /* 650 */ 118, 77, 124, 126, 128, 130, 132, 134, 136, 138, + /* 660 */ 140, 142, 171, 96, 173, 174, 331, 52, 171, 96, + /* 670 */ 173, 174, 96, 195, 213, 207, 29, 348, 145, 54, + /* 680 */ 310, 318, 144, 75, 455, 342, 217, 93, 83, 75, + /* 690 */ 30, 452, 75, 109, 587, 286, 111, 171, 265, 173, + /* 700 */ 174, 319, 110, 94, 146, 157, 162, 167, 156, 161, + /* 710 */ 120, 122, 114, 116, 112, 118, 77, 124, 126, 128, + /* 720 */ 130, 132, 134, 136, 138, 140, 142, 244, 96, 187, + /* 730 */ 96, 96, 810, 331, 214, 266, 215, 35, 312, 96, + /* 740 */ 96, 479, 328, 145, 623, 38, 327, 144, 75, 455, + /* 750 */ 75, 75, 113, 689, 115, 117, 315, 461, 426, 75, + /* 760 */ 75, 77, 463, 119, 121, 407, 325, 110, 165, 146, + /* 770 */ 157, 162, 167, 156, 161, 120, 122, 114, 116, 112, + /* 780 */ 118, 77, 124, 126, 128, 130, 132, 134, 136, 138, + /* 790 */ 140, 142, 42, 96, 96, 96, 96, 824, 273, 159, + /* 800 */ 415, 96, 410, 272, 96, 273, 479, 41, 145, 332, + /* 810 */ 537, 43, 144, 75, 75, 75, 75, 123, 125, 127, + /* 820 */ 129, 75, 465, 64, 75, 131, 53, 463, 133, 158, + /* 830 */ 317, 316, 265, 94, 146, 157, 162, 167, 156, 161, + /* 840 */ 120, 122, 114, 116, 112, 118, 219, 124, 126, 128, + /* 850 */ 130, 132, 134, 136, 138, 140, 142, 96, 689, 96, + /* 860 */ 96, 532, 96, 331, 299, 96, 215, 96, 96, 283, + /* 870 */ 96, 261, 219, 96, 145, 96, 840, 75, 144, 75, + /* 880 */ 75, 135, 75, 137, 139, 75, 141, 75, 75, 143, + /* 890 */ 75, 153, 155, 75, 164, 75, 376, 166, 56, 178, + /* 900 */ 146, 157, 162, 167, 156, 161, 120, 122, 114, 116, + /* 910 */ 112, 118, 652, 124, 126, 128, 130, 132, 134, 136, + /* 920 */ 138, 140, 142, 76, 96, 96, 96, 71, 438, 364, + /* 930 */ 362, 437, 96, 96, 96, 96, 331, 262, 233, 332, + /* 940 */ 96, 55, 331, 439, 75, 75, 75, 331, 180, 182, + /* 950 */ 184, 199, 75, 75, 75, 75, 196, 198, 208, 210, + /* 960 */ 75, 107, 106, 108, 212, 720, 326, 177, 327, 382, + /* 970 */ 430, 431, 107, 106, 108, 391, 548, 61, 96, 96, + /* 980 */ 449, 471, 458, 45, 183, 181, 300, 96, 476, 352, + /* 990 */ 96, 353, 179, 73, 74, 343, 346, 95, 75, 75, + /* 1000 */ 290, 96, 224, 240, 345, 275, 42, 75, 95, 76, + /* 1010 */ 75, 245, 332, 71, 277, 383, 275, 327, 332, 96, + /* 1020 */ 75, 75, 404, 332, 287, 386, 96, 392, 421, 327, + /* 1030 */ 101, 102, 103, 104, 105, 185, 189, 199, 96, 75, + /* 1040 */ 96, 101, 102, 427, 414, 60, 75, 107, 106, 108, + /* 1050 */ 474, 470, 486, 177, 77, 450, 421, 327, 75, 484, + /* 1060 */ 75, 273, 478, 436, 491, 492, 423, 490, 421, 421, + /* 1070 */ 183, 181, 421, 421, 483, 421, 77, 421, 179, 73, + /* 1080 */ 74, 476, 244, 95, 77, 81, 526, 860, 490, 421, + /* 1090 */ 689, 522, 62, 64, 500, 70, 597, 63, 523, 68, + /* 1100 */ 598, 76, 81, 79, 81, 71, 502, 504, 84, 80, + /* 1110 */ 506, 510, 244, 514, 239, 520, 101, 102, 103, 104, + /* 1120 */ 105, 185, 189, 77, 546, 241, 82, 558, 86, 199, + /* 1130 */ 85, 225, 90, 87, 97, 88, 99, 142, 89, 107, + /* 1140 */ 106, 108, 160, 98, 516, 177, 100, 218, 666, 667, + /* 1150 */ 668, 186, 209, 193, 192, 194, 200, 204, 203, 202, + /* 1160 */ 206, 205, 183, 181, 219, 220, 221, 226, 228, 232, + /* 1170 */ 179, 73, 74, 230, 233, 95, 234, 231, 237, 242, + /* 1180 */ 238, 215, 260, 249, 257, 276, 267, 254, 256, 259, + /* 1190 */ 264, 269, 270, 76, 274, 282, 301, 71, 219, 268, + /* 1200 */ 285, 291, 284, 306, 324, 307, 311, 308, 101, 102, + /* 1210 */ 103, 104, 105, 185, 189, 803, 355, 329, 375, 304, + /* 1220 */ 314, 199, 321, 337, 330, 365, 334, 372, 309, 333, + /* 1230 */ 323, 107, 106, 108, 344, 339, 347, 177, 374, 378, + /* 1240 */ 400, 359, 370, 377, 381, 379, 384, 389, 363, 390, + /* 1250 */ 393, 394, 396, 54, 183, 181, 289, 408, 395, 409, + /* 1260 */ 411, 413, 179, 73, 74, 412, 416, 95, 417, 420, + /* 1270 */ 428, 422, 832, 429, 443, 440, 444, 837, 838, 76, + /* 1280 */ 446, 445, 448, 71, 451, 808, 809, 459, 454, 447, + /* 1290 */ 418, 727, 728, 831, 464, 462, 846, 457, 469, 419, + /* 1300 */ 101, 102, 103, 104, 105, 185, 189, 199, 467, 468, + /* 1310 */ 472, 473, 475, 424, 848, 477, 480, 107, 106, 108, + /* 1320 */ 425, 482, 488, 177, 485, 849, 481, 495, 496, 851, + /* 1330 */ 659, 661, 816, 858, 497, 509, 511, 719, 513, 515, + /* 1340 */ 183, 181, 722, 517, 725, 519, 521, 524, 179, 73, + /* 1350 */ 74, 818, 528, 95, 530, 819, 820, 531, 538, 821, + /* 1360 */ 8, 822, 539, 823, 549, 19, 21, 23, 405, 541, + /* 1370 */ 542, 544, 543, 859, 547, 861, 862, 865, 545, 540, + /* 1380 */ 551, 867, 557, 555, 552, 550, 101, 102, 103, 104, + /* 1390 */ 105, 185, 189, 554, 560, 559, 561, 868, 529, 545, + /* 1400 */ 460, 545, 545, 545, 545, 527, 545, 553, 545, 545, + /* 1410 */ 545, 545, 556, 545, 545, 545, 545, 545, 545, 545, + /* 1420 */ 545, 545, 545, 545, 545, 545, 545, 545, 545, 545, + /* 1430 */ 545, 545, 545, 545, 545, 545, 545, 545, 545, 545, + /* 1440 */ 545, 545, 545, 545, 545, 545, 545, 545, 545, 545, + /* 1450 */ 545, 545, 545, 508, 512, 456, 545, 545, 545, 498, + /* 1460 */ 545, 545, 545, 545, 81, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 16, 216, 146, 218, 219, 21, 146, 23, 68, 69, - /* 10 */ 70, 71, 16, 73, 74, 75, 76, 77, 78, 79, - /* 20 */ 80, 81, 82, 146, 168, 169, 42, 72, 73, 74, - /* 30 */ 75, 76, 77, 78, 79, 80, 81, 82, 216, 217, - /* 40 */ 218, 219, 146, 59, 60, 61, 62, 63, 64, 65, - /* 50 */ 66, 67, 68, 69, 70, 71, 146, 73, 74, 75, - /* 60 */ 76, 77, 78, 79, 80, 81, 82, 16, 146, 43, - /* 70 */ 86, 215, 146, 22, 73, 74, 75, 76, 77, 78, - /* 80 */ 79, 80, 81, 82, 88, 89, 90, 91, 92, 93, - /* 90 */ 94, 95, 22, 42, 168, 169, 146, 46, 102, 138, - /* 100 */ 139, 140, 152, 19, 143, 155, 156, 23, 160, 187, - /* 110 */ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - /* 120 */ 69, 70, 71, 97, 73, 74, 75, 76, 77, 78, - /* 130 */ 79, 80, 81, 82, 16, 146, 157, 58, 20, 160, - /* 140 */ 161, 162, 58, 189, 16, 16, 220, 199, 23, 146, - /* 150 */ 146, 77, 78, 79, 80, 81, 82, 168, 169, 237, - /* 160 */ 42, 77, 78, 149, 216, 86, 218, 219, 146, 90, - /* 170 */ 86, 43, 168, 169, 90, 89, 90, 59, 60, 61, - /* 180 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - /* 190 */ 120, 73, 74, 75, 76, 77, 78, 79, 80, 81, - /* 200 */ 82, 16, 123, 124, 125, 20, 22, 123, 124, 125, - /* 210 */ 207, 86, 87, 88, 146, 23, 91, 92, 93, 90, - /* 220 */ 91, 92, 93, 94, 95, 97, 146, 42, 103, 207, - /* 230 */ 102, 102, 79, 80, 81, 82, 168, 169, 224, 163, - /* 240 */ 164, 165, 228, 177, 59, 60, 61, 62, 63, 64, - /* 250 */ 65, 66, 67, 68, 69, 70, 71, 146, 73, 74, - /* 260 */ 75, 76, 77, 78, 79, 80, 81, 82, 16, 77, - /* 270 */ 78, 177, 88, 12, 23, 91, 92, 93, 86, 87, - /* 280 */ 51, 52, 146, 215, 146, 24, 19, 103, 88, 97, - /* 290 */ 23, 91, 92, 93, 42, 141, 142, 20, 37, 22, - /* 300 */ 39, 147, 226, 103, 168, 169, 168, 169, 154, 154, - /* 310 */ 49, 59, 60, 61, 62, 63, 64, 65, 66, 67, - /* 320 */ 68, 69, 70, 71, 14, 73, 74, 75, 76, 77, - /* 330 */ 78, 79, 80, 81, 82, 20, 146, 86, 87, 146, - /* 340 */ 16, 25, 188, 188, 154, 29, 208, 209, 146, 216, - /* 350 */ 146, 218, 219, 86, 146, 200, 201, 41, 168, 169, - /* 360 */ 205, 20, 154, 53, 113, 55, 42, 213, 44, 236, - /* 370 */ 168, 169, 168, 169, 175, 176, 168, 169, 188, 49, - /* 380 */ 22, 182, 130, 59, 60, 61, 62, 63, 64, 65, - /* 390 */ 66, 67, 68, 69, 70, 71, 188, 73, 74, 75, - /* 400 */ 76, 77, 78, 79, 80, 81, 82, 16, 146, 20, - /* 410 */ 20, 22, 21, 211, 146, 211, 146, 155, 156, 211, - /* 420 */ 105, 23, 107, 108, 20, 223, 22, 223, 98, 99, - /* 430 */ 100, 223, 177, 42, 164, 165, 168, 169, 14, 109, - /* 440 */ 191, 179, 180, 163, 164, 165, 105, 198, 107, 108, - /* 450 */ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - /* 460 */ 69, 70, 71, 12, 73, 74, 75, 76, 77, 78, - /* 470 */ 79, 80, 81, 82, 16, 24, 19, 53, 120, 55, - /* 480 */ 23, 20, 154, 22, 86, 87, 200, 201, 37, 23, - /* 490 */ 39, 223, 166, 167, 42, 105, 226, 107, 108, 19, - /* 500 */ 42, 175, 105, 23, 107, 108, 226, 160, 161, 162, - /* 510 */ 21, 113, 23, 16, 62, 63, 188, 59, 60, 61, - /* 520 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - /* 530 */ 22, 73, 74, 75, 76, 77, 78, 79, 80, 81, - /* 540 */ 82, 213, 90, 86, 87, 79, 16, 146, 19, 146, - /* 550 */ 20, 146, 86, 87, 146, 146, 132, 229, 129, 146, - /* 560 */ 131, 146, 234, 146, 155, 156, 86, 87, 154, 168, - /* 570 */ 169, 23, 42, 168, 169, 86, 168, 169, 0, 1, - /* 580 */ 2, 168, 169, 168, 169, 168, 169, 90, 130, 59, - /* 590 */ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - /* 600 */ 70, 71, 188, 73, 74, 75, 76, 77, 78, 79, - /* 610 */ 80, 81, 82, 16, 209, 146, 90, 230, 21, 146, - /* 620 */ 112, 154, 146, 22, 146, 27, 231, 213, 102, 146, - /* 630 */ 30, 146, 34, 140, 86, 87, 143, 168, 169, 42, - /* 640 */ 111, 168, 169, 229, 168, 169, 168, 169, 234, 154, - /* 650 */ 50, 168, 169, 168, 169, 188, 59, 60, 61, 62, - /* 660 */ 63, 64, 65, 66, 67, 68, 69, 70, 71, 146, - /* 670 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - /* 680 */ 16, 146, 146, 188, 20, 146, 106, 146, 87, 146, - /* 690 */ 110, 168, 169, 146, 98, 99, 100, 146, 20, 146, - /* 700 */ 22, 101, 19, 168, 169, 167, 42, 168, 169, 168, - /* 710 */ 169, 168, 169, 175, 113, 168, 169, 181, 160, 168, - /* 720 */ 169, 168, 169, 59, 60, 61, 62, 63, 64, 65, - /* 730 */ 66, 67, 68, 69, 70, 71, 146, 73, 74, 75, - /* 740 */ 76, 77, 78, 79, 80, 81, 82, 16, 146, 146, - /* 750 */ 67, 146, 146, 20, 146, 22, 146, 199, 168, 169, - /* 760 */ 146, 225, 146, 123, 124, 146, 7, 8, 9, 202, - /* 770 */ 168, 169, 146, 42, 168, 169, 168, 169, 168, 169, - /* 780 */ 146, 18, 168, 169, 168, 169, 181, 168, 169, 79, - /* 790 */ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - /* 800 */ 69, 70, 71, 146, 73, 74, 75, 76, 77, 78, - /* 810 */ 79, 80, 81, 82, 16, 146, 106, 146, 22, 146, - /* 820 */ 110, 146, 19, 146, 21, 168, 169, 146, 146, 190, - /* 830 */ 225, 146, 98, 99, 100, 109, 146, 168, 169, 146, - /* 840 */ 42, 168, 169, 168, 169, 168, 169, 146, 122, 168, - /* 850 */ 169, 225, 181, 168, 169, 92, 154, 59, 60, 61, - /* 860 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - /* 870 */ 146, 73, 74, 75, 76, 77, 78, 79, 80, 81, - /* 880 */ 82, 16, 146, 20, 154, 22, 146, 109, 146, 154, - /* 890 */ 188, 146, 96, 146, 212, 132, 225, 207, 160, 146, - /* 900 */ 122, 184, 185, 184, 185, 181, 146, 42, 168, 169, - /* 910 */ 168, 169, 146, 146, 146, 146, 146, 181, 188, 146, - /* 920 */ 146, 146, 146, 188, 16, 60, 61, 62, 63, 64, - /* 930 */ 65, 66, 67, 68, 69, 70, 71, 199, 73, 74, - /* 940 */ 75, 76, 77, 78, 79, 80, 81, 82, 23, 225, - /* 950 */ 42, 146, 146, 187, 187, 187, 187, 212, 159, 227, - /* 960 */ 187, 225, 187, 187, 20, 171, 22, 168, 146, 61, - /* 970 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - /* 980 */ 146, 73, 74, 75, 76, 77, 78, 79, 80, 81, - /* 990 */ 82, 16, 17, 187, 19, 7, 8, 20, 23, 22, - /* 1000 */ 20, 171, 22, 77, 78, 160, 31, 16, 17, 227, - /* 1010 */ 19, 86, 172, 20, 23, 22, 1, 2, 171, 146, - /* 1020 */ 192, 146, 31, 48, 171, 146, 190, 144, 148, 171, - /* 1030 */ 146, 146, 193, 58, 146, 222, 146, 176, 146, 48, - /* 1040 */ 120, 193, 193, 59, 15, 183, 186, 111, 151, 58, - /* 1050 */ 186, 6, 77, 78, 145, 19, 129, 186, 221, 193, - /* 1060 */ 85, 86, 87, 151, 173, 90, 95, 210, 77, 78, - /* 1070 */ 79, 40, 178, 145, 23, 159, 85, 86, 87, 16, - /* 1080 */ 17, 90, 19, 145, 109, 151, 23, 15, 210, 150, - /* 1090 */ 197, 119, 173, 19, 31, 214, 159, 136, 123, 124, - /* 1100 */ 125, 126, 127, 128, 97, 238, 193, 117, 210, 194, - /* 1110 */ 170, 48, 170, 151, 123, 124, 125, 126, 127, 128, - /* 1120 */ 118, 58, 5, 170, 195, 22, 153, 10, 11, 12, - /* 1130 */ 13, 115, 214, 170, 170, 33, 151, 196, 235, 150, - /* 1140 */ 77, 78, 38, 26, 170, 28, 151, 151, 85, 86, - /* 1150 */ 87, 183, 35, 90, 232, 97, 114, 203, 210, 204, - /* 1160 */ 96, 129, 170, 233, 47, 145, 49, 235, 151, 172, - /* 1170 */ 170, 54, 178, 56, 204, 151, 151, 109, 135, 203, - /* 1180 */ 174, 183, 134, 174, 57, 158, 123, 124, 125, 126, - /* 1190 */ 127, 128, 188, 19, 102, 146, 146, 14, 185, 1, - /* 1200 */ 90, 19, 180, 168, 20, 20, 20, 106, 180, 168, - /* 1210 */ 19, 44, 20, 19, 44, 98, 99, 100, 19, 121, - /* 1220 */ 4, 104, 19, 111, 3, 19, 109, 121, 82, 111, - /* 1230 */ 11, 16, 146, 97, 17, 101, 112, 44, 20, 19, - /* 1240 */ 5, 19, 111, 20, 17, 21, 132, 22, 20, 45, - /* 1250 */ 133, 22, 11, 116, 22, 111, 1, 112, 32, 45, - /* 1260 */ 111, 101, 20, 19, 116, 97, 36, 19, 22, 67, - /* 1270 */ 19, 113, 67, 20, 94, + /* 0 */ 24, 26, 26, 78, 79, 80, 81, 82, 83, 84, + /* 10 */ 85, 86, 87, 88, 22, 9, 40, 23, 26, 25, + /* 20 */ 44, 74, 75, 76, 77, 9, 79, 80, 81, 82, + /* 30 */ 83, 84, 85, 86, 87, 88, 85, 86, 87, 88, + /* 40 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + /* 50 */ 74, 75, 76, 77, 148, 79, 80, 81, 82, 83, + /* 60 */ 84, 85, 86, 87, 88, 9, 25, 92, 92, 79, + /* 70 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 26, + /* 80 */ 150, 40, 26, 144, 92, 44, 147, 157, 94, 48, + /* 90 */ 149, 97, 98, 99, 83, 84, 85, 86, 87, 88, + /* 100 */ 170, 9, 10, 109, 174, 64, 65, 66, 67, 68, + /* 110 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 189, + /* 120 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + /* 130 */ 40, 29, 9, 26, 44, 12, 94, 35, 85, 97, + /* 140 */ 98, 99, 142, 143, 144, 92, 93, 147, 92, 93, + /* 150 */ 112, 109, 66, 115, 64, 65, 66, 67, 68, 69, + /* 160 */ 70, 71, 72, 73, 74, 75, 76, 77, 22, 79, + /* 170 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 66, + /* 180 */ 94, 95, 96, 97, 98, 99, 100, 101, 60, 61, + /* 190 */ 62, 17, 9, 160, 108, 150, 163, 164, 26, 92, + /* 200 */ 93, 94, 150, 40, 97, 98, 99, 44, 0, 96, + /* 210 */ 97, 98, 99, 100, 101, 170, 109, 9, 10, 174, + /* 220 */ 92, 108, 186, 187, 96, 51, 136, 64, 65, 66, + /* 230 */ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + /* 240 */ 77, 9, 79, 80, 81, 82, 83, 84, 85, 86, + /* 250 */ 87, 88, 149, 18, 17, 83, 84, 129, 130, 150, + /* 260 */ 20, 23, 27, 117, 92, 93, 221, 158, 159, 22, + /* 270 */ 40, 24, 150, 38, 44, 103, 41, 40, 104, 105, + /* 280 */ 106, 44, 9, 157, 168, 169, 51, 177, 178, 115, + /* 290 */ 181, 182, 170, 177, 184, 55, 174, 57, 68, 69, + /* 300 */ 137, 64, 65, 66, 67, 68, 69, 70, 71, 72, + /* 310 */ 73, 74, 75, 76, 77, 189, 79, 80, 81, 82, + /* 320 */ 83, 84, 85, 86, 87, 88, 96, 201, 202, 22, + /* 330 */ 150, 169, 206, 26, 212, 150, 150, 23, 149, 177, + /* 340 */ 155, 40, 23, 158, 159, 44, 224, 145, 146, 111, + /* 350 */ 170, 113, 114, 151, 174, 9, 170, 13, 14, 157, + /* 360 */ 174, 165, 166, 167, 163, 64, 65, 66, 67, 68, + /* 370 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 139, + /* 380 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + /* 390 */ 64, 189, 212, 112, 18, 209, 210, 116, 23, 92, + /* 400 */ 93, 200, 150, 27, 224, 217, 218, 219, 220, 22, + /* 410 */ 149, 26, 23, 26, 38, 40, 214, 41, 217, 44, + /* 420 */ 219, 220, 170, 227, 9, 111, 174, 113, 114, 24, + /* 430 */ 111, 26, 113, 114, 165, 166, 167, 9, 137, 64, + /* 440 */ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + /* 450 */ 75, 76, 77, 127, 79, 80, 81, 82, 83, 84, + /* 460 */ 85, 86, 87, 88, 23, 26, 23, 150, 25, 9, + /* 470 */ 150, 13, 14, 15, 25, 115, 224, 92, 93, 92, + /* 480 */ 93, 40, 26, 153, 47, 44, 26, 170, 128, 171, + /* 490 */ 170, 174, 201, 202, 174, 9, 227, 92, 45, 9, + /* 500 */ 111, 152, 113, 114, 119, 64, 65, 66, 67, 68, + /* 510 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 66, + /* 520 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + /* 530 */ 210, 92, 93, 216, 25, 217, 93, 219, 220, 111, + /* 540 */ 103, 113, 114, 129, 130, 150, 40, 150, 92, 93, + /* 550 */ 44, 9, 92, 93, 17, 225, 103, 150, 119, 229, + /* 560 */ 9, 108, 119, 166, 167, 170, 9, 118, 26, 174, + /* 570 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + /* 580 */ 74, 75, 76, 77, 11, 79, 80, 81, 82, 83, + /* 590 */ 84, 85, 86, 87, 88, 9, 150, 111, 150, 113, + /* 600 */ 114, 111, 93, 113, 114, 217, 9, 219, 220, 103, + /* 610 */ 9, 216, 150, 40, 21, 208, 170, 44, 170, 157, + /* 620 */ 174, 23, 174, 25, 227, 104, 105, 106, 119, 104, + /* 630 */ 105, 106, 170, 11, 92, 93, 174, 64, 65, 66, + /* 640 */ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + /* 650 */ 77, 189, 79, 80, 81, 82, 83, 84, 85, 86, + /* 660 */ 87, 88, 111, 150, 113, 114, 150, 96, 111, 150, + /* 670 */ 113, 114, 150, 136, 212, 138, 156, 162, 40, 108, + /* 680 */ 45, 32, 44, 170, 157, 170, 224, 174, 192, 170, + /* 690 */ 23, 98, 170, 174, 9, 199, 174, 111, 163, 113, + /* 700 */ 114, 52, 64, 65, 66, 67, 68, 69, 70, 71, + /* 710 */ 72, 73, 74, 75, 76, 77, 189, 79, 80, 81, + /* 720 */ 82, 83, 84, 85, 86, 87, 88, 126, 150, 157, + /* 730 */ 150, 150, 139, 150, 23, 200, 25, 161, 103, 150, + /* 740 */ 150, 214, 226, 40, 23, 150, 25, 44, 170, 157, + /* 750 */ 170, 170, 174, 24, 174, 174, 107, 230, 136, 170, + /* 760 */ 170, 189, 235, 174, 174, 20, 183, 64, 65, 66, + /* 770 */ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + /* 780 */ 77, 189, 79, 80, 81, 82, 83, 84, 85, 86, + /* 790 */ 87, 88, 103, 150, 150, 150, 150, 9, 25, 66, + /* 800 */ 55, 150, 57, 23, 150, 25, 214, 171, 40, 226, + /* 810 */ 22, 33, 44, 170, 170, 170, 170, 174, 174, 174, + /* 820 */ 174, 170, 230, 102, 170, 174, 171, 235, 174, 96, + /* 830 */ 95, 96, 163, 65, 66, 67, 68, 69, 70, 71, + /* 840 */ 72, 73, 74, 75, 76, 77, 117, 79, 80, 81, + /* 850 */ 82, 83, 84, 85, 86, 87, 88, 150, 103, 150, + /* 860 */ 150, 73, 150, 150, 23, 150, 25, 150, 150, 200, + /* 870 */ 150, 26, 117, 150, 40, 150, 103, 170, 44, 170, + /* 880 */ 170, 174, 170, 174, 174, 170, 174, 170, 170, 174, + /* 890 */ 170, 174, 174, 170, 174, 170, 183, 174, 42, 174, + /* 900 */ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + /* 910 */ 76, 77, 9, 79, 80, 81, 82, 83, 84, 85, + /* 920 */ 86, 87, 88, 22, 150, 150, 150, 26, 28, 83, + /* 930 */ 84, 31, 150, 150, 150, 150, 150, 92, 26, 226, + /* 940 */ 150, 180, 150, 43, 170, 170, 170, 150, 174, 174, + /* 950 */ 174, 50, 170, 170, 170, 170, 174, 174, 174, 174, + /* 960 */ 170, 60, 61, 62, 174, 9, 23, 66, 25, 183, + /* 970 */ 53, 54, 60, 61, 62, 183, 131, 172, 150, 150, + /* 980 */ 183, 25, 186, 187, 83, 84, 85, 150, 150, 23, + /* 990 */ 150, 25, 91, 92, 93, 83, 84, 96, 170, 170, + /* 1000 */ 150, 150, 174, 174, 92, 150, 103, 170, 96, 22, + /* 1010 */ 170, 174, 226, 26, 174, 23, 150, 25, 226, 150, + /* 1020 */ 170, 170, 157, 226, 174, 174, 150, 23, 150, 25, + /* 1030 */ 129, 130, 131, 132, 133, 134, 135, 50, 150, 170, + /* 1040 */ 150, 129, 130, 174, 157, 46, 170, 60, 61, 62, + /* 1050 */ 174, 213, 157, 66, 189, 23, 150, 25, 170, 23, + /* 1060 */ 170, 25, 174, 208, 174, 23, 188, 25, 150, 150, + /* 1070 */ 83, 84, 150, 150, 208, 150, 189, 150, 91, 92, + /* 1080 */ 93, 150, 126, 96, 189, 115, 23, 9, 25, 150, + /* 1090 */ 9, 157, 171, 102, 188, 22, 117, 173, 128, 171, + /* 1100 */ 117, 22, 115, 190, 115, 26, 188, 188, 193, 189, + /* 1110 */ 188, 188, 126, 188, 124, 188, 129, 130, 131, 132, + /* 1120 */ 133, 134, 135, 189, 46, 123, 191, 188, 195, 50, + /* 1130 */ 194, 121, 125, 196, 117, 197, 117, 88, 198, 60, + /* 1140 */ 61, 62, 96, 150, 213, 66, 150, 150, 115, 115, + /* 1150 */ 115, 22, 136, 223, 222, 17, 22, 25, 187, 23, + /* 1160 */ 23, 150, 83, 84, 117, 150, 154, 122, 25, 101, + /* 1170 */ 91, 92, 93, 211, 26, 96, 162, 172, 211, 122, + /* 1180 */ 172, 25, 154, 203, 119, 103, 204, 150, 150, 150, + /* 1190 */ 150, 120, 22, 22, 150, 23, 23, 26, 117, 205, + /* 1200 */ 205, 117, 204, 150, 22, 175, 150, 176, 129, 130, + /* 1210 */ 131, 132, 133, 134, 135, 136, 23, 211, 22, 171, + /* 1220 */ 179, 50, 179, 162, 172, 163, 172, 150, 178, 211, + /* 1230 */ 179, 60, 61, 62, 170, 180, 170, 66, 46, 23, + /* 1240 */ 182, 228, 182, 173, 22, 171, 171, 46, 228, 22, + /* 1250 */ 100, 150, 176, 108, 83, 84, 85, 150, 175, 154, + /* 1260 */ 150, 24, 91, 92, 93, 154, 150, 96, 154, 103, + /* 1270 */ 39, 154, 11, 37, 139, 47, 150, 103, 103, 22, + /* 1280 */ 103, 154, 22, 26, 171, 9, 139, 185, 11, 150, + /* 1290 */ 231, 127, 127, 9, 9, 17, 17, 64, 107, 232, + /* 1300 */ 129, 130, 131, 132, 133, 134, 135, 50, 185, 150, + /* 1310 */ 150, 73, 194, 233, 9, 73, 127, 60, 61, 62, + /* 1320 */ 234, 22, 22, 66, 215, 9, 150, 118, 150, 9, + /* 1330 */ 9, 9, 9, 9, 194, 118, 194, 9, 185, 107, + /* 1340 */ 83, 84, 9, 194, 9, 127, 215, 22, 91, 92, + /* 1350 */ 93, 9, 150, 96, 150, 9, 9, 154, 150, 9, + /* 1360 */ 11, 9, 23, 9, 34, 16, 17, 18, 19, 236, + /* 1370 */ 163, 150, 24, 9, 163, 9, 9, 9, 237, 30, + /* 1380 */ 236, 9, 20, 154, 150, 36, 129, 130, 131, 132, + /* 1390 */ 133, 134, 135, 150, 140, 59, 150, 9, 49, 238, + /* 1400 */ 51, 238, 238, 238, 238, 56, 238, 58, 238, 238, + /* 1410 */ 238, 238, 63, 238, 238, 238, 238, 238, 238, 238, + /* 1420 */ 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + /* 1430 */ 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + /* 1440 */ 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + /* 1450 */ 238, 238, 238, 104, 105, 106, 238, 238, 238, 110, + /* 1460 */ 238, 238, 238, 238, 115, }; -#define YY_SHIFT_USE_DFLT (-61) -#define YY_SHIFT_MAX 371 +#define YY_SHIFT_USE_DFLT (-76) static const short yy_shift_ofst[] = { - /* 0 */ 1015, 975, 1117, -16, 975, 1063, 1063, 1063, 125, 330, - /* 10 */ 330, 1068, 324, 1063, 1063, 1063, 1063, 1063, -45, 192, - /* 20 */ 548, 926, 925, 926, 51, 391, 118, 185, 252, 458, - /* 30 */ 530, 597, 664, 731, 731, 731, 731, 731, 731, 731, - /* 40 */ 731, 731, 798, 731, 731, 731, 731, 731, 731, 731, - /* 50 */ 731, 731, 865, 908, 908, 991, 1063, 1063, 1063, 1063, - /* 60 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, - /* 70 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, - /* 80 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, - /* 90 */ 1063, 1063, 1063, 1063, -60, -60, -4, 1, 1, 74, - /* 100 */ 153, 128, 763, 548, 548, 548, 548, 548, 548, 548, - /* 110 */ 925, 1146, -61, -61, -61, 84, 129, 261, 261, 548, - /* 120 */ 548, 548, 548, 548, 548, 548, 548, 548, 578, 548, - /* 130 */ 548, 548, 548, 489, 548, 489, 778, 726, 1068, 1068, - /* 140 */ 1068, -61, -61, 79, 184, 79, 200, 390, 341, 315, - /* 150 */ 480, 451, 251, 398, 466, 457, 548, 548, 548, 548, - /* 160 */ 759, 548, 548, 548, 601, 267, 548, 548, 548, 397, - /* 170 */ 548, 548, 710, 397, 596, 397, 601, 397, 316, 548, - /* 180 */ 600, 600, 397, 548, 548, 548, 548, 548, 548, 548, - /* 190 */ 600, 397, 548, 548, 397, 548, 548, 548, 548, 548, - /* 200 */ 640, 598, 640, 598, 796, 598, 508, 598, 580, 803, - /* 210 */ 598, 70, 429, 26, 358, 920, 984, 1029, 1029, 936, - /* 220 */ 1045, 920, 1036, 927, 1029, 936, 971, 1045, 1031, 1051, - /* 230 */ 1045, 936, 1072, 971, 972, 1036, 1051, 1074, 961, 1007, - /* 240 */ 920, 1007, 971, 990, 936, 1002, 1007, 1103, 1016, 1074, - /* 250 */ 1007, 1007, 936, 1072, 1102, 936, 1104, 984, 936, 1007, - /* 260 */ 1058, 1042, 971, 1032, 1007, 1064, 1045, 1102, 936, 1007, - /* 270 */ 1031, 984, 1042, 936, 1058, 936, 1068, -61, -61, -61, - /* 280 */ 424, 452, 310, 734, 277, 683, 389, 86, 526, 529, - /* 290 */ 404, 461, 678, 733, 863, 497, 944, 988, 977, 980, - /* 300 */ 993, 229, 1136, 1193, 1222, 1223, 1235, 1131, 1114, 1204, - /* 310 */ 1229, 1241, 1226, 1255, 1214, 1242, 1160, 1230, 1248, 1202, - /* 320 */ 1205, 1253, 1158, 1251, 1246, 1168, 1148, 1244, 1149, 1145, - /* 330 */ 1144, 1232, 1137, 1227, 1228, 1225, 1224, 1124, 1218, 1220, - /* 340 */ 1134, 1217, 1215, 1219, 1118, 1206, 1112, 1216, 1098, 1199, - /* 350 */ 1170, 1194, 1191, 1101, 1186, 1185, 1184, 1182, 1110, 1198, - /* 360 */ 1183, 1092, 1174, 1127, 1048, 1043, 1192, 1167, 1203, 1221, - /* 370 */ 1106, 1180, + /* 0 */ 92, 208, -76, -76, 1349, 6, 16, -76, 458, 123, + /* 10 */ 183, 56, 232, -76, -76, -76, -76, -76, -76, 123, + /* 20 */ 273, 123, 346, 123, 415, 247, 597, 456, 598, 667, + /* 30 */ 685, 107, -76, -25, -76, 86, -76, 456, 113, -76, + /* 40 */ 689, -76, 778, 235, -76, -76, -76, -76, -76, -76, + /* 50 */ -76, 571, 689, -76, 856, -76, 344, -76, -76, 999, + /* 60 */ 102, 689, 991, -76, -76, -76, -76, 689, -76, 1073, + /* 70 */ 1257, 146, 901, 979, 983, -76, 987, -76, 238, 989, + /* 80 */ -76, 281, -76, 449, 986, 1002, 990, 1010, 1007, -76, + /* 90 */ 1257, 41, 1257, 638, 1257, -76, 1017, 456, 1019, 456, + /* 100 */ -76, -76, -76, -76, -76, -76, -76, -76, -76, 834, + /* 110 */ 1257, 768, 1257, -10, 1257, -10, 1257, -10, 1257, -10, + /* 120 */ 1257, -53, 1257, -53, 1257, 11, 1257, 11, 1257, 11, + /* 130 */ 1257, 11, 1257, -49, 1257, -49, 1257, 1049, 1257, 1049, + /* 140 */ 1257, 1049, 1257, -76, -76, -76, 230, -76, -76, -76, + /* 150 */ -76, -76, 1257, -75, 1257, -10, -76, 733, -76, 1046, + /* 160 */ -76, -76, -76, 1257, 703, 1257, -53, -76, 307, 987, + /* 170 */ 314, 38, 1033, 1034, 1035, -76, 638, 1257, 834, 1257, + /* 180 */ -76, 1257, -76, 1257, -76, 1129, 989, 319, -76, 1079, + /* 190 */ 90, 1016, 537, 1138, -76, 1257, 163, 1257, 638, 1134, + /* 200 */ 376, 1136, -76, 1132, 456, 1137, -76, 1257, 237, 1257, + /* 210 */ 301, 1257, 638, 711, -76, 1257, -76, -76, 1047, 456, + /* 220 */ -76, -76, -76, 1257, 638, 1045, 1257, 1143, 1257, 1068, + /* 230 */ 102, -76, 1148, -76, -76, 638, 1068, 102, -76, 1257, + /* 240 */ 638, 1057, 1257, 1156, 1257, 638, -76, -76, 509, -76, + /* 250 */ -76, -76, 385, -76, 439, -76, 1065, -76, 387, 1047, + /* 260 */ 405, -76, -76, 456, -76, -76, 1082, 1071, -76, 1170, + /* 270 */ 456, 780, -76, 456, -76, -76, 1257, 638, 989, 389, + /* 280 */ 443, 1172, 405, 1082, 1071, -76, 1171, -24, -76, -76, + /* 290 */ 1084, 53, -76, -76, -76, -76, 375, -76, 841, -76, + /* 300 */ 1173, -76, 441, 689, -76, 456, 1182, -76, 635, -76, + /* 310 */ 456, -76, 521, 649, -76, 735, -76, -76, -76, -76, + /* 320 */ 649, -76, 649, -76, 456, 943, -76, 456, 1068, 102, + /* 330 */ -76, -76, 1068, 102, -76, -76, 1148, -76, 856, -76, + /* 340 */ -76, 912, -76, 128, -76, -76, 128, -76, -76, -8, + /* 350 */ 846, 966, -76, 846, 1193, -76, -76, -76, 414, -76, + /* 360 */ -76, -76, 414, -76, -76, -76, -76, -76, -6, 42, + /* 370 */ -76, 456, -76, 1192, 1196, 456, 721, 1216, 689, -76, + /* 380 */ 1222, 456, 992, 689, -76, 1257, 506, -76, 1201, 1227, + /* 390 */ 456, 1004, 1150, 456, 1182, -76, 453, 1145, -76, -76, + /* 400 */ -76, -76, -76, 989, 428, 593, 745, 456, 1047, -76, + /* 410 */ 456, 729, 1237, 989, 486, 456, 1047, 900, 525, 1166, + /* 420 */ 456, 1047, -76, 1231, 622, 1261, 1257, 573, 1236, 917, + /* 430 */ -76, -76, 1174, 1175, 437, 456, 773, -76, -76, 1228, + /* 440 */ -76, -76, 1135, 456, 755, 1177, 456, 1260, 456, 1032, + /* 450 */ 903, 1276, 1147, 1277, 174, 490, 326, 235, -76, 1164, + /* 460 */ 1165, 1278, 1284, 1285, 174, 1279, 1233, 456, 1191, 456, + /* 470 */ 956, 456, 1238, 1257, 638, 1305, 1242, 1257, 638, 1189, + /* 480 */ 456, 1299, 456, 1036, -76, 360, 551, 1300, 1257, 1042, + /* 490 */ 1257, 638, 1316, 638, 1209, 456, 601, 1320, 240, 456, + /* 500 */ 1321, 456, 1322, 456, 1323, 456, 1324, 557, 1217, 456, + /* 510 */ 601, 1328, 1233, 456, 1232, 456, 956, 1333, 1218, 456, + /* 520 */ 1299, 970, 586, 1325, 1257, 1063, 1335, 460, 1342, 456, + /* 530 */ 1047, 788, 172, 1346, 1347, 1350, 1352, 456, 1339, 1354, + /* 540 */ 1330, -25, 1348, 456, 1078, 1364, 845, 1366, 1367, -76, + /* 550 */ 1330, 456, 1368, 542, 1081, 1372, 1362, 456, 1336, 1254, + /* 560 */ 456, 1388, -76, -76, }; -#define YY_REDUCE_USE_DFLT (-216) -#define YY_REDUCE_MAX 279 +#define YY_REDUCE_USE_DFLT (-95) static const short yy_reduce_ofst[] = { - /* 0 */ -39, 208, 154, -52, 190, 138, 202, 204, 262, 328, - /* 10 */ 414, 155, 133, 68, 268, 405, -144, -74, -178, 270, - /* 20 */ -50, 76, -21, 280, -215, -215, -215, -215, -215, -215, - /* 30 */ -215, -215, -215, -215, -215, -215, -215, -215, -215, -215, - /* 40 */ -215, -215, -215, -215, -215, -215, -215, -215, -215, -215, - /* 50 */ -215, -215, -215, -215, -215, 610, 606, 590, 551, 543, - /* 60 */ 539, 523, 483, 476, 469, 415, 408, 136, 740, -11, - /* 70 */ 401, 413, 417, 473, 478, 485, 535, 541, 547, 553, - /* 80 */ 602, 608, 614, 4, 616, 619, 657, 669, 673, 675, - /* 90 */ 677, 681, 742, 685, -215, -215, 326, -215, -215, -215, - /* 100 */ -215, 199, 14, 536, 605, -78, 409, 671, 724, 736, - /* 110 */ 347, -215, -215, -215, -215, 799, 538, 719, 717, 745, - /* 120 */ 690, 806, 22, 776, 775, 773, 626, 769, 493, 768, - /* 130 */ 767, 682, 766, 738, 3, 558, 735, 730, 702, 495, - /* 140 */ 467, 286, 249, 1041, 1028, 1035, 1022, -46, -46, -46, - /* 150 */ 1086, 1013, 1050, 1049, -123, 892, 890, 888, 885, 884, - /* 160 */ 883, 879, 875, 873, 567, 845, 834, 822, 805, -46, - /* 170 */ 770, 753, 639, -46, 395, -46, 567, -46, 387, 403, - /* 180 */ 94, 66, -46, -104, -140, -123, -90, 80, 111, 193, - /* 190 */ 255, -46, 603, 634, -46, 693, 701, 747, 760, 774, - /* 200 */ 732, 794, 782, 830, 840, 847, 828, 853, 836, 880, - /* 210 */ 858, 839, 813, 861, 848, 849, 862, 860, 864, 897, - /* 220 */ 909, 866, 891, 837, 871, 912, 857, 928, 894, 916, - /* 230 */ 938, 934, 939, 878, 893, 919, 937, 881, 867, 940, - /* 240 */ 913, 942, 898, 915, 962, 929, 953, 973, 941, 918, - /* 250 */ 963, 964, 985, 989, 903, 995, 922, 968, 996, 974, - /* 260 */ 954, 955, 948, 930, 992, 997, 1020, 932, 1017, 1000, - /* 270 */ 994, 998, 970, 1024, 976, 1025, 1004, 1006, 1009, 1027, + /* 0 */ 0, -61, -95, -95, 202, -95, -95, -95, -94, -59, + /* 10 */ -95, 52, -95, -95, -95, -95, -95, -95, -95, 103, + /* 20 */ -95, 189, -95, 261, -95, 349, -95, 185, 520, -95, + /* 30 */ -95, 109, -95, 33, 576, 116, -95, 595, 162, -95, + /* 40 */ 636, -95, -95, 36, -95, -95, -95, -95, -95, -95, + /* 50 */ -95, -95, 655, -95, 761, -95, -95, -95, -95, -95, + /* 60 */ 805, 921, 924, -95, -95, -95, -95, 928, -95, -95, + /* 70 */ 446, -95, 122, -95, -95, -95, -70, -95, 913, 920, + /* 80 */ -95, 935, 496, 915, 936, 933, 937, 938, 940, -95, + /* 90 */ 448, 388, 513, 388, 519, -95, -95, 993, -95, 996, + /* 100 */ -95, -95, -95, -95, -95, -95, -95, -95, -95, 388, + /* 110 */ 522, 388, 578, 388, 580, 388, 581, 388, 589, 388, + /* 120 */ 590, 388, 643, 388, 644, 388, 645, 388, 646, 388, + /* 130 */ 651, 388, 654, 388, 707, 388, 709, 388, 710, 388, + /* 140 */ 712, 388, 715, 388, -95, -95, -95, -95, -95, -95, + /* 150 */ -95, -95, 717, 188, 718, 388, -95, -95, -95, -95, + /* 160 */ -95, -95, -95, 720, 388, 723, 388, -95, 997, 462, + /* 170 */ 913, -95, -95, -95, -95, -95, 388, 725, 388, 774, + /* 180 */ 388, 775, 388, 776, 388, -95, 572, 913, -95, 45, + /* 190 */ 388, 932, 930, -95, -95, 782, 388, 783, 388, -95, + /* 200 */ 971, -95, -95, -95, 1011, -95, -95, 784, 388, 785, + /* 210 */ 388, 790, 388, -95, -95, 252, -95, -95, 1012, 1015, + /* 220 */ -95, -95, -95, 828, 388, -95, 186, -95, 320, 962, + /* 230 */ 1005, -95, 1014, -95, -95, 388, 967, 1008, -95, 829, + /* 240 */ 388, -95, 180, -95, 837, 388, -95, 291, 980, -95, + /* 250 */ -95, -95, 1037, -95, 1038, -95, -95, -95, 1039, 1028, + /* 260 */ 535, -95, -95, 1040, -95, -95, 982, 994, -95, -95, + /* 270 */ 407, -95, -95, 1044, -95, -95, 840, 388, 126, 913, + /* 280 */ 980, -95, 669, 998, 995, -95, 850, 201, -95, -95, + /* 290 */ -95, 993, -95, -95, -95, -95, 388, -95, -95, -95, + /* 300 */ -95, -95, 388, 1048, -95, 1053, 1030, 1031, 1050, -95, + /* 310 */ 1056, -95, -95, 1041, -95, -95, -95, -95, -95, -95, + /* 320 */ 1043, -95, 1051, -95, 583, -95, -95, 516, 1006, 1052, + /* 330 */ -95, -95, 1018, 1054, -95, -95, 1061, -95, 1055, -95, + /* 340 */ -95, 515, -95, 1064, -95, -95, 1066, -95, -95, 1062, + /* 350 */ 196, -95, -95, 269, -95, -95, -95, -95, 1013, -95, + /* 360 */ -95, -95, 1020, -95, -95, -95, -95, -95, 1058, 1060, + /* 370 */ -95, 1077, -95, -95, -95, 713, 1070, -95, 1074, -95, + /* 380 */ -95, 786, -95, 1075, -95, 851, 318, -95, -95, -95, + /* 390 */ 792, -95, -95, 1101, 1083, 1076, 110, -95, -95, -95, + /* 400 */ -95, -95, -95, 865, 913, 330, -95, 1107, 1105, -95, + /* 410 */ 1110, 1111, -95, 887, 913, 1116, 1114, 1059, 1067, -95, + /* 420 */ 878, 1117, -95, 1080, 1086, -95, 869, 388, -95, -95, + /* 430 */ -95, -95, -95, -95, -95, 855, -95, -95, -95, -95, + /* 440 */ -95, -95, -95, 1126, 1127, -95, 1139, -95, 797, -95, + /* 450 */ 1113, -95, -95, -95, 527, 913, 1102, 796, -95, -95, + /* 460 */ -95, -95, -95, -95, 592, -95, 1123, 1159, -95, 838, + /* 470 */ 1118, 1160, -95, 876, 388, -95, -95, 888, 388, -95, + /* 480 */ 1176, 1109, 866, -95, -95, 895, 913, -95, 317, -95, + /* 490 */ 890, 388, -95, 388, -95, 1178, 1140, -95, -95, 906, + /* 500 */ -95, 918, -95, 919, -95, 922, -95, 913, -95, 923, + /* 510 */ 1142, -95, 1153, 925, -95, 931, 1149, -95, -95, 927, + /* 520 */ 1131, 934, 913, -95, 395, -95, -95, 1202, -95, 1204, + /* 530 */ 1203, -95, 397, -95, -95, -95, -95, 1208, -95, -95, + /* 540 */ 1133, 1207, -95, 1221, 1141, -95, 1211, -95, -95, -95, + /* 550 */ 1144, 1234, -95, 1243, 1229, -95, -95, 939, -95, -95, + /* 560 */ 1246, -95, -95, -95, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 567, 791, 856, 682, 856, 856, 791, 791, 856, 829, - /* 10 */ 829, 686, 842, 856, 791, 856, 856, 787, 762, 813, - /* 20 */ 856, 813, 598, 813, 717, 856, 856, 856, 856, 856, - /* 30 */ 856, 856, 856, 724, 782, 784, 846, 783, 718, 719, - /* 40 */ 725, 843, 856, 706, 827, 715, 730, 722, 731, 786, - /* 50 */ 698, 790, 752, 768, 751, 856, 856, 856, 856, 856, - /* 60 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, - /* 70 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, - /* 80 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, - /* 90 */ 856, 856, 856, 856, 773, 754, 591, 761, 753, 755, - /* 100 */ 756, 651, 586, 856, 856, 856, 856, 856, 856, 856, - /* 110 */ 856, 757, 769, 770, 758, 856, 856, 856, 856, 856, - /* 120 */ 856, 856, 856, 856, 856, 856, 856, 856, 567, 856, - /* 130 */ 856, 856, 856, 682, 856, 682, 856, 856, 856, 856, - /* 140 */ 856, 686, 676, 856, 642, 856, 856, 856, 856, 856, - /* 150 */ 856, 856, 856, 856, 856, 856, 572, 856, 856, 856, - /* 160 */ 574, 856, 856, 856, 684, 600, 856, 847, 856, 689, - /* 170 */ 849, 801, 674, 588, 856, 727, 690, 832, 819, 856, - /* 180 */ 856, 856, 834, 856, 856, 856, 856, 856, 856, 856, - /* 190 */ 856, 663, 856, 856, 665, 856, 856, 856, 856, 856, - /* 200 */ 856, 709, 856, 709, 624, 709, 683, 709, 674, 856, - /* 210 */ 709, 721, 785, 621, 721, 721, 655, 662, 662, 691, - /* 220 */ 571, 721, 795, 856, 662, 691, 710, 571, 638, 856, - /* 230 */ 571, 691, 583, 710, 716, 795, 856, 732, 854, 653, - /* 240 */ 721, 653, 710, 712, 691, 714, 653, 641, 702, 732, - /* 250 */ 653, 653, 691, 583, 845, 691, 823, 655, 691, 653, - /* 260 */ 699, 701, 710, 826, 653, 624, 571, 845, 691, 653, - /* 270 */ 638, 655, 701, 691, 699, 691, 856, 626, 626, 608, - /* 280 */ 856, 856, 856, 856, 856, 808, 856, 856, 856, 739, - /* 290 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, - /* 300 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, - /* 310 */ 822, 856, 856, 856, 821, 856, 856, 856, 856, 856, - /* 320 */ 856, 856, 856, 856, 713, 856, 856, 856, 744, 856, - /* 330 */ 740, 703, 856, 856, 856, 856, 856, 856, 856, 856, - /* 340 */ 856, 856, 856, 856, 856, 856, 741, 856, 856, 856, - /* 350 */ 856, 856, 856, 668, 856, 856, 856, 856, 856, 856, - /* 360 */ 856, 856, 856, 853, 856, 856, 856, 856, 856, 568, - /* 370 */ 856, 856, 838, 649, 839, 837, 648, 650, 652, 644, - /* 380 */ 645, 590, 647, 617, 659, 646, 750, 592, 599, 582, - /* 390 */ 615, 614, 584, 744, 613, 612, 636, 611, 610, 637, - /* 400 */ 623, 622, 798, 658, 799, 693, 797, 639, 815, 657, - /* 410 */ 654, 796, 640, 824, 825, 820, 631, 630, 635, 816, - /* 420 */ 817, 634, 818, 585, 633, 632, 629, 628, 627, 620, - /* 430 */ 749, 616, 748, 737, 792, 793, 777, 679, 678, 677, - /* 440 */ 609, 656, 728, 729, 688, 814, 618, 625, 828, 707, - /* 450 */ 708, 735, 607, 734, 700, 687, 681, 589, 830, 680, - /* 460 */ 587, 619, 697, 696, 695, 694, 685, 733, 675, 672, - /* 470 */ 673, 581, 705, 711, 580, 831, 593, 704, 736, 666, - /* 480 */ 833, 763, 779, 579, 660, 692, 661, 789, 788, 664, - /* 490 */ 667, 578, 800, 776, 840, 836, 835, 577, 671, 720, - /* 500 */ 738, 576, 781, 575, 780, 723, 742, 597, 743, 745, - /* 510 */ 746, 778, 596, 670, 726, 669, 802, 594, 774, 601, - /* 520 */ 595, 803, 804, 805, 806, 771, 767, 807, 765, 573, - /* 530 */ 764, 570, 602, 841, 605, 566, 844, 606, 775, 564, - /* 540 */ 772, 766, 848, 760, 759, 850, 809, 565, 811, 810, - /* 550 */ 812, 851, 604, 603, 562, 852, 855, 747, 643, 569, - /* 560 */ 563, + /* 0 */ 570, 570, 565, 568, 869, 869, 869, 569, 576, 869, + /* 10 */ 869, 869, 869, 596, 597, 598, 577, 578, 579, 869, + /* 20 */ 869, 869, 869, 869, 869, 869, 869, 869, 869, 869, + /* 30 */ 869, 869, 589, 599, 608, 591, 607, 869, 869, 609, + /* 40 */ 652, 615, 869, 869, 653, 656, 657, 658, 855, 856, + /* 50 */ 857, 869, 652, 616, 637, 635, 869, 638, 639, 869, + /* 60 */ 708, 652, 623, 617, 624, 706, 707, 652, 618, 869, + /* 70 */ 869, 738, 807, 744, 739, 735, 869, 663, 869, 869, + /* 80 */ 664, 672, 674, 681, 720, 711, 713, 701, 715, 669, + /* 90 */ 869, 716, 869, 717, 869, 737, 869, 869, 740, 869, + /* 100 */ 741, 742, 743, 745, 746, 747, 750, 751, 752, 753, + /* 110 */ 869, 754, 869, 755, 869, 756, 869, 757, 869, 758, + /* 120 */ 869, 759, 869, 760, 869, 761, 869, 762, 869, 763, + /* 130 */ 869, 764, 869, 765, 869, 766, 869, 767, 869, 768, + /* 140 */ 869, 769, 869, 770, 771, 772, 869, 773, 774, 781, + /* 150 */ 788, 791, 869, 776, 869, 775, 778, 869, 779, 869, + /* 160 */ 782, 780, 787, 869, 869, 869, 789, 790, 869, 807, + /* 170 */ 869, 869, 869, 869, 869, 794, 806, 869, 783, 869, + /* 180 */ 784, 869, 785, 869, 786, 869, 869, 869, 796, 869, + /* 190 */ 869, 869, 869, 869, 797, 869, 869, 869, 798, 869, + /* 200 */ 869, 869, 853, 869, 869, 869, 854, 869, 869, 869, + /* 210 */ 869, 869, 799, 869, 792, 807, 804, 805, 689, 869, + /* 220 */ 690, 795, 777, 869, 718, 869, 869, 702, 869, 709, + /* 230 */ 708, 703, 869, 593, 710, 705, 709, 708, 704, 869, + /* 240 */ 714, 869, 807, 712, 869, 721, 673, 684, 682, 683, + /* 250 */ 692, 693, 869, 694, 869, 695, 869, 696, 869, 689, + /* 260 */ 680, 594, 595, 869, 678, 679, 698, 700, 685, 869, + /* 270 */ 869, 869, 699, 869, 733, 734, 869, 697, 684, 869, + /* 280 */ 869, 869, 680, 698, 700, 686, 869, 680, 675, 676, + /* 290 */ 869, 869, 677, 670, 671, 793, 869, 736, 869, 748, + /* 300 */ 869, 749, 869, 652, 619, 869, 811, 625, 620, 626, + /* 310 */ 869, 627, 869, 869, 628, 869, 631, 632, 633, 634, + /* 320 */ 869, 629, 869, 630, 869, 869, 812, 869, 709, 708, + /* 330 */ 813, 815, 709, 708, 814, 621, 869, 622, 637, 636, + /* 340 */ 610, 869, 611, 869, 612, 744, 869, 613, 614, 600, + /* 350 */ 830, 869, 601, 830, 869, 602, 605, 606, 869, 825, + /* 360 */ 827, 828, 869, 826, 829, 604, 603, 592, 869, 869, + /* 370 */ 642, 869, 645, 869, 869, 869, 869, 869, 652, 646, + /* 380 */ 869, 869, 869, 652, 647, 869, 652, 648, 869, 869, + /* 390 */ 869, 869, 869, 869, 811, 625, 650, 869, 649, 651, + /* 400 */ 643, 644, 590, 869, 869, 586, 869, 869, 689, 584, + /* 410 */ 869, 869, 869, 869, 869, 869, 689, 836, 869, 869, + /* 420 */ 869, 689, 691, 841, 869, 869, 869, 869, 869, 869, + /* 430 */ 842, 843, 869, 869, 869, 869, 869, 833, 834, 869, + /* 440 */ 835, 585, 869, 869, 869, 869, 869, 869, 869, 869, + /* 450 */ 869, 869, 869, 869, 869, 869, 869, 869, 655, 869, + /* 460 */ 869, 869, 869, 869, 869, 869, 654, 869, 869, 869, + /* 470 */ 869, 869, 869, 869, 723, 869, 869, 869, 724, 869, + /* 480 */ 869, 731, 869, 869, 732, 869, 869, 869, 869, 869, + /* 490 */ 869, 729, 869, 730, 869, 869, 869, 869, 869, 869, + /* 500 */ 869, 869, 869, 869, 869, 869, 869, 869, 869, 869, + /* 510 */ 869, 869, 654, 869, 869, 869, 869, 869, 869, 869, + /* 520 */ 731, 869, 869, 869, 869, 869, 869, 869, 869, 869, + /* 530 */ 689, 869, 830, 869, 869, 869, 869, 869, 869, 869, + /* 540 */ 864, 869, 869, 869, 869, 869, 869, 869, 869, 863, + /* 550 */ 864, 869, 869, 869, 869, 869, 869, 869, 869, 869, + /* 560 */ 869, 869, 571, 566, }; #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0])) /* The next table maps tokens into fallback tokens. If a construct ** like the following: @@ -580,70 +664,76 @@ ** the parse is retried before an error is thrown. */ #ifdef YYFALLBACK static const YYCODETYPE yyFallback[] = { 0, /* $ => nothing */ + 0, /* END_OF_FILE => nothing */ + 0, /* ILLEGAL => nothing */ + 0, /* SPACE => nothing */ + 0, /* UNCLOSED_STRING => nothing */ + 0, /* COMMENT => nothing */ + 0, /* FUNCTION => nothing */ + 0, /* COLUMN => nothing */ + 0, /* AGG_FUNCTION => nothing */ 0, /* SEMI => nothing */ - 23, /* EXPLAIN => ID */ - 23, /* QUERY => ID */ - 23, /* PLAN => ID */ - 23, /* BEGIN => ID */ + 26, /* EXPLAIN => ID */ + 26, /* BEGIN => ID */ 0, /* TRANSACTION => nothing */ - 23, /* DEFERRED => ID */ - 23, /* IMMEDIATE => ID */ - 23, /* EXCLUSIVE => ID */ + 26, /* DEFERRED => ID */ + 26, /* IMMEDIATE => ID */ + 26, /* EXCLUSIVE => ID */ 0, /* COMMIT => nothing */ - 23, /* END => ID */ + 26, /* END => ID */ 0, /* ROLLBACK => nothing */ 0, /* CREATE => nothing */ 0, /* TABLE => nothing */ - 23, /* IF => ID */ - 0, /* NOT => nothing */ - 0, /* EXISTS => nothing */ - 23, /* TEMP => ID */ + 26, /* TEMP => ID */ 0, /* LP => nothing */ 0, /* RP => nothing */ 0, /* AS => nothing */ 0, /* COMMA => nothing */ 0, /* ID => nothing */ - 23, /* ABORT => ID */ - 23, /* AFTER => ID */ - 23, /* ANALYZE => ID */ - 23, /* ASC => ID */ - 23, /* ATTACH => ID */ - 23, /* BEFORE => ID */ - 23, /* CASCADE => ID */ - 23, /* CAST => ID */ - 23, /* CONFLICT => ID */ - 23, /* DATABASE => ID */ - 23, /* DESC => ID */ - 23, /* DETACH => ID */ - 23, /* EACH => ID */ - 23, /* FAIL => ID */ - 23, /* FOR => ID */ - 23, /* IGNORE => ID */ - 23, /* INITIALLY => ID */ - 23, /* INSTEAD => ID */ - 23, /* LIKE_KW => ID */ - 23, /* MATCH => ID */ - 23, /* KEY => ID */ - 23, /* OF => ID */ - 23, /* OFFSET => ID */ - 23, /* PRAGMA => ID */ - 23, /* RAISE => ID */ - 23, /* REPLACE => ID */ - 23, /* RESTRICT => ID */ - 23, /* ROW => ID */ - 23, /* STATEMENT => ID */ - 23, /* TRIGGER => ID */ - 23, /* VACUUM => ID */ - 23, /* VIEW => ID */ - 23, /* REINDEX => ID */ - 23, /* RENAME => ID */ - 23, /* CTIME_KW => ID */ + 26, /* ABORT => ID */ + 26, /* AFTER => ID */ + 26, /* ASC => ID */ + 26, /* ATTACH => ID */ + 26, /* BEFORE => ID */ + 26, /* CASCADE => ID */ + 26, /* CONFLICT => ID */ + 26, /* DATABASE => ID */ + 26, /* DESC => ID */ + 26, /* DETACH => ID */ + 26, /* EACH => ID */ + 26, /* FAIL => ID */ + 26, /* FOR => ID */ + 26, /* GLOB => ID */ + 26, /* IGNORE => ID */ + 26, /* INITIALLY => ID */ + 26, /* INSTEAD => ID */ + 26, /* LIKE => ID */ + 26, /* MATCH => ID */ + 26, /* KEY => ID */ + 26, /* OF => ID */ + 26, /* OFFSET => ID */ + 26, /* PRAGMA => ID */ + 26, /* RAISE => ID */ + 26, /* REPLACE => ID */ + 26, /* RESTRICT => ID */ + 26, /* ROW => ID */ + 26, /* STATEMENT => ID */ + 26, /* TRIGGER => ID */ + 26, /* VACUUM => ID */ + 26, /* VIEW => ID */ + 26, /* REINDEX => ID */ + 26, /* RENAME => ID */ + 26, /* CDATE => ID */ + 26, /* CTIME => ID */ + 26, /* CTIMESTAMP => ID */ + 26, /* ALTER => ID */ 0, /* OR => nothing */ 0, /* AND => nothing */ + 0, /* NOT => nothing */ 0, /* IS => nothing */ 0, /* BETWEEN => nothing */ 0, /* IN => nothing */ 0, /* ISNULL => nothing */ 0, /* NOTNULL => nothing */ @@ -686,12 +776,12 @@ 0, /* DEFERRABLE => nothing */ 0, /* FOREIGN => nothing */ 0, /* DROP => nothing */ 0, /* UNION => nothing */ 0, /* ALL => nothing */ - 0, /* EXCEPT => nothing */ 0, /* INTERSECT => nothing */ + 0, /* EXCEPT => nothing */ 0, /* SELECT => nothing */ 0, /* DISTINCT => nothing */ 0, /* DOT => nothing */ 0, /* FROM => nothing */ 0, /* JOIN => nothing */ @@ -707,19 +797,17 @@ 0, /* INTEGER => nothing */ 0, /* FLOAT => nothing */ 0, /* BLOB => nothing */ 0, /* REGISTER => nothing */ 0, /* VARIABLE => nothing */ + 0, /* EXISTS => nothing */ 0, /* CASE => nothing */ 0, /* WHEN => nothing */ 0, /* THEN => nothing */ 0, /* ELSE => nothing */ 0, /* INDEX => nothing */ - 0, /* ALTER => nothing */ 0, /* TO => nothing */ - 0, /* ADD => nothing */ - 0, /* COLUMNKW => nothing */ }; #endif /* YYFALLBACK */ /* The following structure represents a single element of the ** parser's stack. Information stored includes: @@ -786,70 +874,70 @@ #ifndef NDEBUG /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ static const char *const yyTokenName[] = { - "$", "SEMI", "EXPLAIN", "QUERY", - "PLAN", "BEGIN", "TRANSACTION", "DEFERRED", - "IMMEDIATE", "EXCLUSIVE", "COMMIT", "END", - "ROLLBACK", "CREATE", "TABLE", "IF", - "NOT", "EXISTS", "TEMP", "LP", - "RP", "AS", "COMMA", "ID", - "ABORT", "AFTER", "ANALYZE", "ASC", - "ATTACH", "BEFORE", "CASCADE", "CAST", - "CONFLICT", "DATABASE", "DESC", "DETACH", - "EACH", "FAIL", "FOR", "IGNORE", - "INITIALLY", "INSTEAD", "LIKE_KW", "MATCH", - "KEY", "OF", "OFFSET", "PRAGMA", - "RAISE", "REPLACE", "RESTRICT", "ROW", - "STATEMENT", "TRIGGER", "VACUUM", "VIEW", - "REINDEX", "RENAME", "CTIME_KW", "OR", - "AND", "IS", "BETWEEN", "IN", - "ISNULL", "NOTNULL", "NE", "EQ", - "GT", "LE", "LT", "GE", - "ESCAPE", "BITAND", "BITOR", "LSHIFT", - "RSHIFT", "PLUS", "MINUS", "STAR", - "SLASH", "REM", "CONCAT", "UMINUS", - "UPLUS", "BITNOT", "STRING", "JOIN_KW", - "CONSTRAINT", "DEFAULT", "NULL", "PRIMARY", - "UNIQUE", "CHECK", "REFERENCES", "COLLATE", - "AUTOINCR", "ON", "DELETE", "UPDATE", - "INSERT", "SET", "DEFERRABLE", "FOREIGN", - "DROP", "UNION", "ALL", "EXCEPT", - "INTERSECT", "SELECT", "DISTINCT", "DOT", - "FROM", "JOIN", "USING", "ORDER", - "BY", "GROUP", "HAVING", "LIMIT", - "WHERE", "INTO", "VALUES", "INTEGER", - "FLOAT", "BLOB", "REGISTER", "VARIABLE", - "CASE", "WHEN", "THEN", "ELSE", - "INDEX", "ALTER", "TO", "ADD", - "COLUMNKW", "error", "input", "cmdlist", + "$", "END_OF_FILE", "ILLEGAL", "SPACE", + "UNCLOSED_STRING", "COMMENT", "FUNCTION", "COLUMN", + "AGG_FUNCTION", "SEMI", "EXPLAIN", "BEGIN", + "TRANSACTION", "DEFERRED", "IMMEDIATE", "EXCLUSIVE", + "COMMIT", "END", "ROLLBACK", "CREATE", + "TABLE", "TEMP", "LP", "RP", + "AS", "COMMA", "ID", "ABORT", + "AFTER", "ASC", "ATTACH", "BEFORE", + "CASCADE", "CONFLICT", "DATABASE", "DESC", + "DETACH", "EACH", "FAIL", "FOR", + "GLOB", "IGNORE", "INITIALLY", "INSTEAD", + "LIKE", "MATCH", "KEY", "OF", + "OFFSET", "PRAGMA", "RAISE", "REPLACE", + "RESTRICT", "ROW", "STATEMENT", "TRIGGER", + "VACUUM", "VIEW", "REINDEX", "RENAME", + "CDATE", "CTIME", "CTIMESTAMP", "ALTER", + "OR", "AND", "NOT", "IS", + "BETWEEN", "IN", "ISNULL", "NOTNULL", + "NE", "EQ", "GT", "LE", + "LT", "GE", "ESCAPE", "BITAND", + "BITOR", "LSHIFT", "RSHIFT", "PLUS", + "MINUS", "STAR", "SLASH", "REM", + "CONCAT", "UMINUS", "UPLUS", "BITNOT", + "STRING", "JOIN_KW", "CONSTRAINT", "DEFAULT", + "NULL", "PRIMARY", "UNIQUE", "CHECK", + "REFERENCES", "COLLATE", "AUTOINCR", "ON", + "DELETE", "UPDATE", "INSERT", "SET", + "DEFERRABLE", "FOREIGN", "DROP", "UNION", + "ALL", "INTERSECT", "EXCEPT", "SELECT", + "DISTINCT", "DOT", "FROM", "JOIN", + "USING", "ORDER", "BY", "GROUP", + "HAVING", "LIMIT", "WHERE", "INTO", + "VALUES", "INTEGER", "FLOAT", "BLOB", + "REGISTER", "VARIABLE", "EXISTS", "CASE", + "WHEN", "THEN", "ELSE", "INDEX", + "TO", "error", "input", "cmdlist", "ecmd", "cmdx", "cmd", "explain", "transtype", "trans_opt", "nm", "create_table", - "create_table_args", "temp", "ifnotexists", "dbnm", - "columnlist", "conslist_opt", "select", "column", - "columnid", "type", "carglist", "id", - "ids", "typetoken", "typename", "signed", - "plus_num", "minus_num", "carg", "ccons", - "term", "expr", "onconf", "sortorder", - "autoinc", "idxlist_opt", "refargs", "defer_subclause", - "refarg", "refact", "init_deferred_pred_opt", "conslist", - "tcons", "idxlist", "defer_subclause_opt", "orconf", - "resolvetype", "raisetype", "ifexists", "fullname", - "oneselect", "multiselect_op", "distinct", "selcollist", - "from", "where_opt", "groupby_opt", "having_opt", - "orderby_opt", "limit_opt", "sclp", "as", - "seltablist", "stl_prefix", "joinop", "on_opt", - "using_opt", "seltablist_paren", "joinop2", "inscollist", - "sortlist", "sortitem", "collate", "exprlist", - "setlist", "insert_cmd", "inscollist_opt", "itemlist", - "likeop", "escape", "between_op", "in_op", - "case_operand", "case_exprlist", "case_else", "expritem", - "uniqueflag", "idxitem", "plus_opt", "number", - "trigger_decl", "trigger_cmd_list", "trigger_time", "trigger_event", - "foreach_clause", "when_clause", "trigger_cmd", "database_kw_opt", - "key_opt", "add_column_fullname", "kwcolumn_opt", + "create_table_args", "temp", "dbnm", "columnlist", + "conslist_opt", "select", "column", "columnid", + "type", "carglist", "id", "ids", + "typename", "signed", "plus_num", "minus_num", + "carg", "ccons", "term", "onconf", + "sortorder", "autoinc", "expr", "idxlist_opt", + "refargs", "defer_subclause", "refarg", "refact", + "init_deferred_pred_opt", "conslist", "tcons", "idxlist", + "defer_subclause_opt", "orconf", "resolvetype", "raisetype", + "fullname", "oneselect", "multiselect_op", "distinct", + "selcollist", "from", "where_opt", "groupby_opt", + "having_opt", "orderby_opt", "limit_opt", "sclp", + "as", "seltablist", "stl_prefix", "joinop", + "on_opt", "using_opt", "seltablist_paren", "joinop2", + "inscollist", "sortlist", "sortitem", "collate", + "exprlist", "setlist", "insert_cmd", "inscollist_opt", + "itemlist", "likeop", "escape", "between_op", + "in_op", "case_operand", "case_exprlist", "case_else", + "expritem", "uniqueflag", "idxitem", "plus_opt", + "number", "trigger_decl", "trigger_cmd_list", "trigger_time", + "trigger_event", "foreach_clause", "when_clause", "trigger_cmd", + "database_kw_opt", "key_opt", }; #endif /* NDEBUG */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. @@ -861,297 +949,307 @@ /* 3 */ "cmdx ::= cmd", /* 4 */ "ecmd ::= SEMI", /* 5 */ "ecmd ::= explain cmdx SEMI", /* 6 */ "explain ::=", /* 7 */ "explain ::= EXPLAIN", - /* 8 */ "explain ::= EXPLAIN QUERY PLAN", - /* 9 */ "cmd ::= BEGIN transtype trans_opt", - /* 10 */ "trans_opt ::=", - /* 11 */ "trans_opt ::= TRANSACTION", - /* 12 */ "trans_opt ::= TRANSACTION nm", - /* 13 */ "transtype ::=", - /* 14 */ "transtype ::= DEFERRED", - /* 15 */ "transtype ::= IMMEDIATE", - /* 16 */ "transtype ::= EXCLUSIVE", - /* 17 */ "cmd ::= COMMIT trans_opt", - /* 18 */ "cmd ::= END trans_opt", - /* 19 */ "cmd ::= ROLLBACK trans_opt", - /* 20 */ "cmd ::= create_table create_table_args", - /* 21 */ "create_table ::= CREATE temp TABLE ifnotexists nm dbnm", - /* 22 */ "ifnotexists ::=", - /* 23 */ "ifnotexists ::= IF NOT EXISTS", - /* 24 */ "temp ::= TEMP", - /* 25 */ "temp ::=", - /* 26 */ "create_table_args ::= LP columnlist conslist_opt RP", - /* 27 */ "create_table_args ::= AS select", - /* 28 */ "columnlist ::= columnlist COMMA column", - /* 29 */ "columnlist ::= column", - /* 30 */ "column ::= columnid type carglist", - /* 31 */ "columnid ::= nm", - /* 32 */ "id ::= ID", - /* 33 */ "ids ::= ID|STRING", - /* 34 */ "nm ::= ID", - /* 35 */ "nm ::= STRING", - /* 36 */ "nm ::= JOIN_KW", - /* 37 */ "type ::=", - /* 38 */ "type ::= typetoken", - /* 39 */ "typetoken ::= typename", - /* 40 */ "typetoken ::= typename LP signed RP", - /* 41 */ "typetoken ::= typename LP signed COMMA signed RP", - /* 42 */ "typename ::= ids", - /* 43 */ "typename ::= typename ids", - /* 44 */ "signed ::= plus_num", - /* 45 */ "signed ::= minus_num", - /* 46 */ "carglist ::= carglist carg", - /* 47 */ "carglist ::=", - /* 48 */ "carg ::= CONSTRAINT nm ccons", - /* 49 */ "carg ::= ccons", - /* 50 */ "carg ::= DEFAULT term", - /* 51 */ "carg ::= DEFAULT LP expr RP", - /* 52 */ "carg ::= DEFAULT PLUS term", - /* 53 */ "carg ::= DEFAULT MINUS term", - /* 54 */ "carg ::= DEFAULT id", - /* 55 */ "ccons ::= NULL onconf", - /* 56 */ "ccons ::= NOT NULL onconf", - /* 57 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 58 */ "ccons ::= UNIQUE onconf", - /* 59 */ "ccons ::= CHECK LP expr RP", - /* 60 */ "ccons ::= REFERENCES nm idxlist_opt refargs", - /* 61 */ "ccons ::= defer_subclause", - /* 62 */ "ccons ::= COLLATE id", - /* 63 */ "autoinc ::=", - /* 64 */ "autoinc ::= AUTOINCR", - /* 65 */ "refargs ::=", - /* 66 */ "refargs ::= refargs refarg", - /* 67 */ "refarg ::= MATCH nm", - /* 68 */ "refarg ::= ON DELETE refact", - /* 69 */ "refarg ::= ON UPDATE refact", - /* 70 */ "refarg ::= ON INSERT refact", - /* 71 */ "refact ::= SET NULL", - /* 72 */ "refact ::= SET DEFAULT", - /* 73 */ "refact ::= CASCADE", - /* 74 */ "refact ::= RESTRICT", - /* 75 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 76 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 77 */ "init_deferred_pred_opt ::=", - /* 78 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 79 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 80 */ "conslist_opt ::=", - /* 81 */ "conslist_opt ::= COMMA conslist", - /* 82 */ "conslist ::= conslist COMMA tcons", - /* 83 */ "conslist ::= conslist tcons", - /* 84 */ "conslist ::= tcons", - /* 85 */ "tcons ::= CONSTRAINT nm", - /* 86 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf", - /* 87 */ "tcons ::= UNIQUE LP idxlist RP onconf", - /* 88 */ "tcons ::= CHECK LP expr RP onconf", - /* 89 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt", - /* 90 */ "defer_subclause_opt ::=", - /* 91 */ "defer_subclause_opt ::= defer_subclause", - /* 92 */ "onconf ::=", - /* 93 */ "onconf ::= ON CONFLICT resolvetype", - /* 94 */ "orconf ::=", - /* 95 */ "orconf ::= OR resolvetype", - /* 96 */ "resolvetype ::= raisetype", - /* 97 */ "resolvetype ::= IGNORE", - /* 98 */ "resolvetype ::= REPLACE", - /* 99 */ "cmd ::= DROP TABLE ifexists fullname", - /* 100 */ "ifexists ::= IF EXISTS", - /* 101 */ "ifexists ::=", - /* 102 */ "cmd ::= CREATE temp VIEW nm dbnm AS select", - /* 103 */ "cmd ::= DROP VIEW ifexists fullname", - /* 104 */ "cmd ::= select", - /* 105 */ "select ::= oneselect", - /* 106 */ "select ::= select multiselect_op oneselect", - /* 107 */ "multiselect_op ::= UNION", - /* 108 */ "multiselect_op ::= UNION ALL", - /* 109 */ "multiselect_op ::= EXCEPT|INTERSECT", - /* 110 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 111 */ "distinct ::= DISTINCT", - /* 112 */ "distinct ::= ALL", - /* 113 */ "distinct ::=", - /* 114 */ "sclp ::= selcollist COMMA", - /* 115 */ "sclp ::=", - /* 116 */ "selcollist ::= sclp expr as", - /* 117 */ "selcollist ::= sclp STAR", - /* 118 */ "selcollist ::= sclp nm DOT STAR", - /* 119 */ "as ::= AS nm", - /* 120 */ "as ::= ids", - /* 121 */ "as ::=", - /* 122 */ "from ::=", - /* 123 */ "from ::= FROM seltablist", - /* 124 */ "stl_prefix ::= seltablist joinop", - /* 125 */ "stl_prefix ::=", - /* 126 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt", - /* 127 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt", - /* 128 */ "seltablist_paren ::= select", - /* 129 */ "seltablist_paren ::= seltablist", - /* 130 */ "dbnm ::=", - /* 131 */ "dbnm ::= DOT nm", - /* 132 */ "fullname ::= nm dbnm", - /* 133 */ "joinop ::= COMMA|JOIN", - /* 134 */ "joinop ::= JOIN_KW JOIN", - /* 135 */ "joinop ::= JOIN_KW nm JOIN", - /* 136 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 137 */ "on_opt ::= ON expr", - /* 138 */ "on_opt ::=", - /* 139 */ "using_opt ::= USING LP inscollist RP", - /* 140 */ "using_opt ::=", - /* 141 */ "orderby_opt ::=", - /* 142 */ "orderby_opt ::= ORDER BY sortlist", - /* 143 */ "sortlist ::= sortlist COMMA sortitem collate sortorder", - /* 144 */ "sortlist ::= sortitem collate sortorder", - /* 145 */ "sortitem ::= expr", - /* 146 */ "sortorder ::= ASC", - /* 147 */ "sortorder ::= DESC", - /* 148 */ "sortorder ::=", - /* 149 */ "collate ::=", - /* 150 */ "collate ::= COLLATE id", - /* 151 */ "groupby_opt ::=", - /* 152 */ "groupby_opt ::= GROUP BY exprlist", - /* 153 */ "having_opt ::=", - /* 154 */ "having_opt ::= HAVING expr", - /* 155 */ "limit_opt ::=", - /* 156 */ "limit_opt ::= LIMIT expr", - /* 157 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 158 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 159 */ "cmd ::= DELETE FROM fullname where_opt", - /* 160 */ "where_opt ::=", - /* 161 */ "where_opt ::= WHERE expr", - /* 162 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt", - /* 163 */ "setlist ::= setlist COMMA nm EQ expr", - /* 164 */ "setlist ::= nm EQ expr", - /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP", - /* 166 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select", - /* 167 */ "insert_cmd ::= INSERT orconf", - /* 168 */ "insert_cmd ::= REPLACE", - /* 169 */ "itemlist ::= itemlist COMMA expr", - /* 170 */ "itemlist ::= expr", - /* 171 */ "inscollist_opt ::=", - /* 172 */ "inscollist_opt ::= LP inscollist RP", - /* 173 */ "inscollist ::= inscollist COMMA nm", - /* 174 */ "inscollist ::= nm", - /* 175 */ "expr ::= term", - /* 176 */ "expr ::= LP expr RP", - /* 177 */ "term ::= NULL", - /* 178 */ "expr ::= ID", - /* 179 */ "expr ::= JOIN_KW", - /* 180 */ "expr ::= nm DOT nm", - /* 181 */ "expr ::= nm DOT nm DOT nm", - /* 182 */ "term ::= INTEGER|FLOAT|BLOB", - /* 183 */ "term ::= STRING", - /* 184 */ "expr ::= REGISTER", - /* 185 */ "expr ::= VARIABLE", - /* 186 */ "expr ::= CAST LP expr AS typetoken RP", - /* 187 */ "expr ::= ID LP distinct exprlist RP", - /* 188 */ "expr ::= ID LP STAR RP", - /* 189 */ "term ::= CTIME_KW", - /* 190 */ "expr ::= expr AND expr", - /* 191 */ "expr ::= expr OR expr", - /* 192 */ "expr ::= expr LT|GT|GE|LE expr", - /* 193 */ "expr ::= expr EQ|NE expr", - /* 194 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 195 */ "expr ::= expr PLUS|MINUS expr", - /* 196 */ "expr ::= expr STAR|SLASH|REM expr", - /* 197 */ "expr ::= expr CONCAT expr", - /* 198 */ "likeop ::= LIKE_KW", - /* 199 */ "likeop ::= NOT LIKE_KW", - /* 200 */ "escape ::= ESCAPE expr", - /* 201 */ "escape ::=", - /* 202 */ "expr ::= expr likeop expr escape", - /* 203 */ "expr ::= expr ISNULL|NOTNULL", - /* 204 */ "expr ::= expr IS NULL", - /* 205 */ "expr ::= expr NOT NULL", - /* 206 */ "expr ::= expr IS NOT NULL", - /* 207 */ "expr ::= NOT|BITNOT expr", - /* 208 */ "expr ::= MINUS expr", - /* 209 */ "expr ::= PLUS expr", - /* 210 */ "between_op ::= BETWEEN", - /* 211 */ "between_op ::= NOT BETWEEN", - /* 212 */ "expr ::= expr between_op expr AND expr", - /* 213 */ "in_op ::= IN", - /* 214 */ "in_op ::= NOT IN", - /* 215 */ "expr ::= expr in_op LP exprlist RP", - /* 216 */ "expr ::= LP select RP", - /* 217 */ "expr ::= expr in_op LP select RP", - /* 218 */ "expr ::= expr in_op nm dbnm", - /* 219 */ "expr ::= EXISTS LP select RP", - /* 220 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 221 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 222 */ "case_exprlist ::= WHEN expr THEN expr", - /* 223 */ "case_else ::= ELSE expr", - /* 224 */ "case_else ::=", - /* 225 */ "case_operand ::= expr", - /* 226 */ "case_operand ::=", - /* 227 */ "exprlist ::= exprlist COMMA expritem", - /* 228 */ "exprlist ::= expritem", - /* 229 */ "expritem ::= expr", - /* 230 */ "expritem ::=", - /* 231 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP onconf", - /* 232 */ "uniqueflag ::= UNIQUE", - /* 233 */ "uniqueflag ::=", - /* 234 */ "idxlist_opt ::=", - /* 235 */ "idxlist_opt ::= LP idxlist RP", - /* 236 */ "idxlist ::= idxlist COMMA idxitem collate sortorder", - /* 237 */ "idxlist ::= idxitem collate sortorder", - /* 238 */ "idxitem ::= nm", - /* 239 */ "cmd ::= DROP INDEX ifexists fullname", - /* 240 */ "cmd ::= VACUUM", - /* 241 */ "cmd ::= VACUUM nm", - /* 242 */ "cmd ::= PRAGMA nm dbnm EQ nm", - /* 243 */ "cmd ::= PRAGMA nm dbnm EQ ON", - /* 244 */ "cmd ::= PRAGMA nm dbnm EQ plus_num", - /* 245 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 246 */ "cmd ::= PRAGMA nm dbnm LP nm RP", - /* 247 */ "cmd ::= PRAGMA nm dbnm", - /* 248 */ "plus_num ::= plus_opt number", - /* 249 */ "minus_num ::= MINUS number", - /* 250 */ "number ::= INTEGER|FLOAT", - /* 251 */ "plus_opt ::= PLUS", - /* 252 */ "plus_opt ::=", - /* 253 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END", - /* 254 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 255 */ "trigger_time ::= BEFORE", - /* 256 */ "trigger_time ::= AFTER", - /* 257 */ "trigger_time ::= INSTEAD OF", - /* 258 */ "trigger_time ::=", - /* 259 */ "trigger_event ::= DELETE|INSERT", - /* 260 */ "trigger_event ::= UPDATE", - /* 261 */ "trigger_event ::= UPDATE OF inscollist", - /* 262 */ "foreach_clause ::=", - /* 263 */ "foreach_clause ::= FOR EACH ROW", - /* 264 */ "foreach_clause ::= FOR EACH STATEMENT", - /* 265 */ "when_clause ::=", - /* 266 */ "when_clause ::= WHEN expr", - /* 267 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list", - /* 268 */ "trigger_cmd_list ::=", - /* 269 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt", - /* 270 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP", - /* 271 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select", - /* 272 */ "trigger_cmd ::= DELETE FROM nm where_opt", - /* 273 */ "trigger_cmd ::= select", - /* 274 */ "expr ::= RAISE LP IGNORE RP", - /* 275 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 276 */ "raisetype ::= ROLLBACK", - /* 277 */ "raisetype ::= ABORT", - /* 278 */ "raisetype ::= FAIL", - /* 279 */ "cmd ::= DROP TRIGGER fullname", - /* 280 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 281 */ "key_opt ::=", - /* 282 */ "key_opt ::= KEY expr", - /* 283 */ "database_kw_opt ::= DATABASE", - /* 284 */ "database_kw_opt ::=", - /* 285 */ "cmd ::= DETACH database_kw_opt expr", - /* 286 */ "cmd ::= REINDEX", - /* 287 */ "cmd ::= REINDEX nm dbnm", - /* 288 */ "cmd ::= ANALYZE", - /* 289 */ "cmd ::= ANALYZE nm dbnm", - /* 290 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 291 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column", - /* 292 */ "add_column_fullname ::= fullname", - /* 293 */ "kwcolumn_opt ::=", - /* 294 */ "kwcolumn_opt ::= COLUMNKW", + /* 8 */ "cmd ::= BEGIN transtype trans_opt", + /* 9 */ "trans_opt ::=", + /* 10 */ "trans_opt ::= TRANSACTION", + /* 11 */ "trans_opt ::= TRANSACTION nm", + /* 12 */ "transtype ::=", + /* 13 */ "transtype ::= DEFERRED", + /* 14 */ "transtype ::= IMMEDIATE", + /* 15 */ "transtype ::= EXCLUSIVE", + /* 16 */ "cmd ::= COMMIT trans_opt", + /* 17 */ "cmd ::= END trans_opt", + /* 18 */ "cmd ::= ROLLBACK trans_opt", + /* 19 */ "cmd ::= create_table create_table_args", + /* 20 */ "create_table ::= CREATE temp TABLE nm dbnm", + /* 21 */ "temp ::= TEMP", + /* 22 */ "temp ::=", + /* 23 */ "create_table_args ::= LP columnlist conslist_opt RP", + /* 24 */ "create_table_args ::= AS select", + /* 25 */ "columnlist ::= columnlist COMMA column", + /* 26 */ "columnlist ::= column", + /* 27 */ "column ::= columnid type carglist", + /* 28 */ "columnid ::= nm", + /* 29 */ "id ::= ID", + /* 30 */ "ids ::= ID", + /* 31 */ "ids ::= STRING", + /* 32 */ "nm ::= ID", + /* 33 */ "nm ::= STRING", + /* 34 */ "nm ::= JOIN_KW", + /* 35 */ "type ::=", + /* 36 */ "type ::= typename", + /* 37 */ "type ::= typename LP signed RP", + /* 38 */ "type ::= typename LP signed COMMA signed RP", + /* 39 */ "typename ::= ids", + /* 40 */ "typename ::= typename ids", + /* 41 */ "signed ::= plus_num", + /* 42 */ "signed ::= minus_num", + /* 43 */ "carglist ::= carglist carg", + /* 44 */ "carglist ::=", + /* 45 */ "carg ::= CONSTRAINT nm ccons", + /* 46 */ "carg ::= ccons", + /* 47 */ "carg ::= DEFAULT term", + /* 48 */ "carg ::= DEFAULT PLUS term", + /* 49 */ "carg ::= DEFAULT MINUS term", + /* 50 */ "carg ::= DEFAULT id", + /* 51 */ "ccons ::= NULL onconf", + /* 52 */ "ccons ::= NOT NULL onconf", + /* 53 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 54 */ "ccons ::= UNIQUE onconf", + /* 55 */ "ccons ::= CHECK LP expr RP onconf", + /* 56 */ "ccons ::= REFERENCES nm idxlist_opt refargs", + /* 57 */ "ccons ::= defer_subclause", + /* 58 */ "ccons ::= COLLATE id", + /* 59 */ "autoinc ::=", + /* 60 */ "autoinc ::= AUTOINCR", + /* 61 */ "refargs ::=", + /* 62 */ "refargs ::= refargs refarg", + /* 63 */ "refarg ::= MATCH nm", + /* 64 */ "refarg ::= ON DELETE refact", + /* 65 */ "refarg ::= ON UPDATE refact", + /* 66 */ "refarg ::= ON INSERT refact", + /* 67 */ "refact ::= SET NULL", + /* 68 */ "refact ::= SET DEFAULT", + /* 69 */ "refact ::= CASCADE", + /* 70 */ "refact ::= RESTRICT", + /* 71 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 72 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 73 */ "init_deferred_pred_opt ::=", + /* 74 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 75 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 76 */ "conslist_opt ::=", + /* 77 */ "conslist_opt ::= COMMA conslist", + /* 78 */ "conslist ::= conslist COMMA tcons", + /* 79 */ "conslist ::= conslist tcons", + /* 80 */ "conslist ::= tcons", + /* 81 */ "tcons ::= CONSTRAINT nm", + /* 82 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf", + /* 83 */ "tcons ::= UNIQUE LP idxlist RP onconf", + /* 84 */ "tcons ::= CHECK expr onconf", + /* 85 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt", + /* 86 */ "defer_subclause_opt ::=", + /* 87 */ "defer_subclause_opt ::= defer_subclause", + /* 88 */ "onconf ::=", + /* 89 */ "onconf ::= ON CONFLICT resolvetype", + /* 90 */ "orconf ::=", + /* 91 */ "orconf ::= OR resolvetype", + /* 92 */ "resolvetype ::= raisetype", + /* 93 */ "resolvetype ::= IGNORE", + /* 94 */ "resolvetype ::= REPLACE", + /* 95 */ "cmd ::= DROP TABLE fullname", + /* 96 */ "cmd ::= CREATE temp VIEW nm dbnm AS select", + /* 97 */ "cmd ::= DROP VIEW fullname", + /* 98 */ "cmd ::= select", + /* 99 */ "select ::= oneselect", + /* 100 */ "select ::= select multiselect_op oneselect", + /* 101 */ "multiselect_op ::= UNION", + /* 102 */ "multiselect_op ::= UNION ALL", + /* 103 */ "multiselect_op ::= INTERSECT", + /* 104 */ "multiselect_op ::= EXCEPT", + /* 105 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 106 */ "distinct ::= DISTINCT", + /* 107 */ "distinct ::= ALL", + /* 108 */ "distinct ::=", + /* 109 */ "sclp ::= selcollist COMMA", + /* 110 */ "sclp ::=", + /* 111 */ "selcollist ::= sclp expr as", + /* 112 */ "selcollist ::= sclp STAR", + /* 113 */ "selcollist ::= sclp nm DOT STAR", + /* 114 */ "as ::= AS nm", + /* 115 */ "as ::= ids", + /* 116 */ "as ::=", + /* 117 */ "from ::=", + /* 118 */ "from ::= FROM seltablist", + /* 119 */ "stl_prefix ::= seltablist joinop", + /* 120 */ "stl_prefix ::=", + /* 121 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt", + /* 122 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt", + /* 123 */ "seltablist_paren ::= select", + /* 124 */ "seltablist_paren ::= seltablist", + /* 125 */ "dbnm ::=", + /* 126 */ "dbnm ::= DOT nm", + /* 127 */ "fullname ::= nm dbnm", + /* 128 */ "joinop ::= COMMA", + /* 129 */ "joinop ::= JOIN", + /* 130 */ "joinop ::= JOIN_KW JOIN", + /* 131 */ "joinop ::= JOIN_KW nm JOIN", + /* 132 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 133 */ "on_opt ::= ON expr", + /* 134 */ "on_opt ::=", + /* 135 */ "using_opt ::= USING LP inscollist RP", + /* 136 */ "using_opt ::=", + /* 137 */ "orderby_opt ::=", + /* 138 */ "orderby_opt ::= ORDER BY sortlist", + /* 139 */ "sortlist ::= sortlist COMMA sortitem collate sortorder", + /* 140 */ "sortlist ::= sortitem collate sortorder", + /* 141 */ "sortitem ::= expr", + /* 142 */ "sortorder ::= ASC", + /* 143 */ "sortorder ::= DESC", + /* 144 */ "sortorder ::=", + /* 145 */ "collate ::=", + /* 146 */ "collate ::= COLLATE id", + /* 147 */ "groupby_opt ::=", + /* 148 */ "groupby_opt ::= GROUP BY exprlist", + /* 149 */ "having_opt ::=", + /* 150 */ "having_opt ::= HAVING expr", + /* 151 */ "limit_opt ::=", + /* 152 */ "limit_opt ::= LIMIT expr", + /* 153 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 154 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 155 */ "cmd ::= DELETE FROM fullname where_opt", + /* 156 */ "where_opt ::=", + /* 157 */ "where_opt ::= WHERE expr", + /* 158 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt", + /* 159 */ "setlist ::= setlist COMMA nm EQ expr", + /* 160 */ "setlist ::= nm EQ expr", + /* 161 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP", + /* 162 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select", + /* 163 */ "insert_cmd ::= INSERT orconf", + /* 164 */ "insert_cmd ::= REPLACE", + /* 165 */ "itemlist ::= itemlist COMMA expr", + /* 166 */ "itemlist ::= expr", + /* 167 */ "inscollist_opt ::=", + /* 168 */ "inscollist_opt ::= LP inscollist RP", + /* 169 */ "inscollist ::= inscollist COMMA nm", + /* 170 */ "inscollist ::= nm", + /* 171 */ "expr ::= term", + /* 172 */ "expr ::= LP expr RP", + /* 173 */ "term ::= NULL", + /* 174 */ "expr ::= ID", + /* 175 */ "expr ::= JOIN_KW", + /* 176 */ "expr ::= nm DOT nm", + /* 177 */ "expr ::= nm DOT nm DOT nm", + /* 178 */ "term ::= INTEGER", + /* 179 */ "term ::= FLOAT", + /* 180 */ "term ::= STRING", + /* 181 */ "expr ::= BLOB", + /* 182 */ "expr ::= REGISTER", + /* 183 */ "expr ::= VARIABLE", + /* 184 */ "expr ::= ID LP exprlist RP", + /* 185 */ "expr ::= ID LP STAR RP", + /* 186 */ "term ::= CTIME", + /* 187 */ "term ::= CDATE", + /* 188 */ "term ::= CTIMESTAMP", + /* 189 */ "expr ::= expr AND expr", + /* 190 */ "expr ::= expr OR expr", + /* 191 */ "expr ::= expr LT expr", + /* 192 */ "expr ::= expr GT expr", + /* 193 */ "expr ::= expr LE expr", + /* 194 */ "expr ::= expr GE expr", + /* 195 */ "expr ::= expr NE expr", + /* 196 */ "expr ::= expr EQ expr", + /* 197 */ "expr ::= expr BITAND expr", + /* 198 */ "expr ::= expr BITOR expr", + /* 199 */ "expr ::= expr LSHIFT expr", + /* 200 */ "expr ::= expr RSHIFT expr", + /* 201 */ "expr ::= expr PLUS expr", + /* 202 */ "expr ::= expr MINUS expr", + /* 203 */ "expr ::= expr STAR expr", + /* 204 */ "expr ::= expr SLASH expr", + /* 205 */ "expr ::= expr REM expr", + /* 206 */ "expr ::= expr CONCAT expr", + /* 207 */ "likeop ::= LIKE", + /* 208 */ "likeop ::= GLOB", + /* 209 */ "likeop ::= NOT LIKE", + /* 210 */ "likeop ::= NOT GLOB", + /* 211 */ "escape ::= ESCAPE expr", + /* 212 */ "escape ::=", + /* 213 */ "expr ::= expr likeop expr escape", + /* 214 */ "expr ::= expr ISNULL", + /* 215 */ "expr ::= expr IS NULL", + /* 216 */ "expr ::= expr NOTNULL", + /* 217 */ "expr ::= expr NOT NULL", + /* 218 */ "expr ::= expr IS NOT NULL", + /* 219 */ "expr ::= NOT expr", + /* 220 */ "expr ::= BITNOT expr", + /* 221 */ "expr ::= MINUS expr", + /* 222 */ "expr ::= PLUS expr", + /* 223 */ "between_op ::= BETWEEN", + /* 224 */ "between_op ::= NOT BETWEEN", + /* 225 */ "expr ::= expr between_op expr AND expr", + /* 226 */ "in_op ::= IN", + /* 227 */ "in_op ::= NOT IN", + /* 228 */ "expr ::= expr in_op LP exprlist RP", + /* 229 */ "expr ::= LP select RP", + /* 230 */ "expr ::= expr in_op LP select RP", + /* 231 */ "expr ::= expr in_op nm dbnm", + /* 232 */ "expr ::= EXISTS LP select RP", + /* 233 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 234 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 235 */ "case_exprlist ::= WHEN expr THEN expr", + /* 236 */ "case_else ::= ELSE expr", + /* 237 */ "case_else ::=", + /* 238 */ "case_operand ::= expr", + /* 239 */ "case_operand ::=", + /* 240 */ "exprlist ::= exprlist COMMA expritem", + /* 241 */ "exprlist ::= expritem", + /* 242 */ "expritem ::= expr", + /* 243 */ "expritem ::=", + /* 244 */ "cmd ::= CREATE uniqueflag INDEX nm dbnm ON nm LP idxlist RP onconf", + /* 245 */ "uniqueflag ::= UNIQUE", + /* 246 */ "uniqueflag ::=", + /* 247 */ "idxlist_opt ::=", + /* 248 */ "idxlist_opt ::= LP idxlist RP", + /* 249 */ "idxlist ::= idxlist COMMA idxitem collate sortorder", + /* 250 */ "idxlist ::= idxitem collate sortorder", + /* 251 */ "idxitem ::= nm", + /* 252 */ "cmd ::= DROP INDEX fullname", + /* 253 */ "cmd ::= VACUUM", + /* 254 */ "cmd ::= VACUUM nm", + /* 255 */ "cmd ::= PRAGMA nm dbnm EQ nm", + /* 256 */ "cmd ::= PRAGMA nm dbnm EQ ON", + /* 257 */ "cmd ::= PRAGMA nm dbnm EQ plus_num", + /* 258 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 259 */ "cmd ::= PRAGMA nm dbnm LP nm RP", + /* 260 */ "cmd ::= PRAGMA nm dbnm", + /* 261 */ "plus_num ::= plus_opt number", + /* 262 */ "minus_num ::= MINUS number", + /* 263 */ "number ::= INTEGER", + /* 264 */ "number ::= FLOAT", + /* 265 */ "plus_opt ::= PLUS", + /* 266 */ "plus_opt ::=", + /* 267 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END", + /* 268 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 269 */ "trigger_time ::= BEFORE", + /* 270 */ "trigger_time ::= AFTER", + /* 271 */ "trigger_time ::= INSTEAD OF", + /* 272 */ "trigger_time ::=", + /* 273 */ "trigger_event ::= DELETE", + /* 274 */ "trigger_event ::= INSERT", + /* 275 */ "trigger_event ::= UPDATE", + /* 276 */ "trigger_event ::= UPDATE OF inscollist", + /* 277 */ "foreach_clause ::=", + /* 278 */ "foreach_clause ::= FOR EACH ROW", + /* 279 */ "foreach_clause ::= FOR EACH STATEMENT", + /* 280 */ "when_clause ::=", + /* 281 */ "when_clause ::= WHEN expr", + /* 282 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list", + /* 283 */ "trigger_cmd_list ::=", + /* 284 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt", + /* 285 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP", + /* 286 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select", + /* 287 */ "trigger_cmd ::= DELETE FROM nm where_opt", + /* 288 */ "trigger_cmd ::= select", + /* 289 */ "expr ::= RAISE LP IGNORE RP", + /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 291 */ "raisetype ::= ROLLBACK", + /* 292 */ "raisetype ::= ABORT", + /* 293 */ "raisetype ::= FAIL", + /* 294 */ "cmd ::= DROP TRIGGER fullname", + /* 295 */ "cmd ::= ATTACH database_kw_opt ids AS nm key_opt", + /* 296 */ "key_opt ::=", + /* 297 */ "key_opt ::= KEY ids", + /* 298 */ "key_opt ::= KEY BLOB", + /* 299 */ "database_kw_opt ::= DATABASE", + /* 300 */ "database_kw_opt ::=", + /* 301 */ "cmd ::= DETACH database_kw_opt nm", + /* 302 */ "cmd ::= REINDEX", + /* 303 */ "cmd ::= REINDEX nm dbnm", + /* 304 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", }; #endif /* NDEBUG */ /* ** This function returns the symbolic name associated with a token @@ -1205,85 +1303,76 @@ ** ** Note: during a reduce, the only symbols destroyed are those ** which appear on the RHS of the rule, but which are not used ** inside the C code. */ - case 154: - case 188: - case 205: -#line 368 "parse.y" -{sqlite3SelectDelete((yypminor->yy239));} -#line 1217 "parse.c" - break; - case 168: - case 169: - case 193: - case 195: - case 203: - case 209: - case 217: - case 220: - case 222: - case 223: - case 233: -#line 625 "parse.y" -{sqlite3ExprDelete((yypminor->yy178));} -#line 1232 "parse.c" - break; - case 173: - case 181: - case 191: + case 157: + case 189: + case 206: +#line 325 "parse.y" +{sqlite3SelectDelete((yypminor->yy331));} +#line 1315 "parse.c" + break; + case 170: + case 174: case 194: case 196: - case 198: - case 208: - case 211: - case 212: - case 215: - case 221: -#line 857 "parse.y" -{sqlite3ExprListDelete((yypminor->yy462));} -#line 1247 "parse.c" + case 204: + case 210: + case 224: +#line 584 "parse.y" +{sqlite3ExprDelete((yypminor->yy454));} +#line 1326 "parse.c" break; - case 187: + case 175: + case 183: case 192: - case 200: - case 201: -#line 496 "parse.y" -{sqlite3SrcListDelete((yypminor->yy285));} -#line 1255 "parse.c" - break; + case 195: case 197: -#line 557 "parse.y" -{ - sqlite3ExprDelete((yypminor->yy270).pLimit); - sqlite3ExprDelete((yypminor->yy270).pOffset); -} -#line 1263 "parse.c" - break; - case 204: - case 207: - case 214: -#line 513 "parse.y" -{sqlite3IdListDelete((yypminor->yy160));} -#line 1270 "parse.c" - break; - case 229: - case 234: -#line 951 "parse.y" -{sqlite3DeleteTriggerStep((yypminor->yy247));} -#line 1276 "parse.c" - break; - case 231: -#line 935 "parse.y" -{sqlite3IdListDelete((yypminor->yy132).b);} -#line 1281 "parse.c" - break; - case 236: -#line 1010 "parse.y" -{sqlite3ExprDelete((yypminor->yy292));} -#line 1286 "parse.c" + case 199: + case 209: + case 212: + case 213: + case 216: + case 222: +#line 796 "parse.y" +{sqlite3ExprListDelete((yypminor->yy266));} +#line 1341 "parse.c" + break; + case 188: + case 193: + case 201: + case 202: +#line 454 "parse.y" +{sqlite3SrcListDelete((yypminor->yy427));} +#line 1349 "parse.c" + break; + case 198: +#line 516 "parse.y" +{ + sqlite3ExprDelete((yypminor->yy348).pLimit); + sqlite3ExprDelete((yypminor->yy348).pOffset); +} +#line 1357 "parse.c" + break; + case 205: + case 208: + case 215: +#line 472 "parse.y" +{sqlite3IdListDelete((yypminor->yy272));} +#line 1364 "parse.c" + break; + case 230: + case 235: +#line 889 "parse.y" +{sqlite3DeleteTriggerStep((yypminor->yy455));} +#line 1370 "parse.c" + break; + case 232: +#line 873 "parse.y" +{sqlite3IdListDelete((yypminor->yy62).b);} +#line 1375 "parse.c" break; default: break; /* If no destructor action specified: do nothing */ } } @@ -1348,11 +1437,13 @@ int iLookAhead /* The look-ahead token */ ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */ + i = yy_shift_ofst[stateno]; + if( i==YY_SHIFT_USE_DFLT ){ return yy_default[stateno]; } if( iLookAhead==YYNOCODE ){ return YY_NO_ACTION; } @@ -1390,12 +1481,12 @@ int iLookAhead /* The look-ahead token */ ){ int i; /* int stateno = pParser->yystack[pParser->yyidx].stateno; */ - if( stateno>YY_REDUCE_MAX || - (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){ + i = yy_reduce_ofst[stateno]; + if( i==YY_REDUCE_USE_DFLT ){ return yy_default[stateno]; } if( iLookAhead==YYNOCODE ){ return YY_NO_ACTION; } @@ -1453,305 +1544,315 @@ */ static const struct { YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ unsigned char nrhs; /* Number of right-hand side symbols in the rule */ } yyRuleInfo[] = { - { 138, 1 }, - { 139, 2 }, - { 139, 1 }, - { 141, 1 }, - { 140, 1 }, - { 140, 3 }, - { 143, 0 }, - { 143, 1 }, - { 143, 3 }, - { 142, 3 }, - { 145, 0 }, - { 145, 1 }, - { 145, 2 }, - { 144, 0 }, - { 144, 1 }, - { 144, 1 }, - { 144, 1 }, - { 142, 2 }, - { 142, 2 }, - { 142, 2 }, - { 142, 2 }, - { 147, 6 }, - { 150, 0 }, - { 150, 3 }, - { 149, 1 }, - { 149, 0 }, - { 148, 4 }, - { 148, 2 }, - { 152, 3 }, - { 152, 1 }, + { 142, 1 }, + { 143, 2 }, + { 143, 1 }, + { 145, 1 }, + { 144, 1 }, + { 144, 3 }, + { 147, 0 }, + { 147, 1 }, + { 146, 3 }, + { 149, 0 }, + { 149, 1 }, + { 149, 2 }, + { 148, 0 }, + { 148, 1 }, + { 148, 1 }, + { 148, 1 }, + { 146, 2 }, + { 146, 2 }, + { 146, 2 }, + { 146, 2 }, + { 151, 5 }, + { 153, 1 }, + { 153, 0 }, + { 152, 4 }, + { 152, 2 }, { 155, 3 }, - { 156, 1 }, + { 155, 1 }, + { 158, 3 }, { 159, 1 }, - { 160, 1 }, - { 146, 1 }, - { 146, 1 }, - { 146, 1 }, - { 157, 0 }, - { 157, 1 }, - { 161, 1 }, - { 161, 4 }, - { 161, 6 }, { 162, 1 }, - { 162, 2 }, { 163, 1 }, { 163, 1 }, - { 158, 2 }, - { 158, 0 }, - { 166, 3 }, - { 166, 1 }, - { 166, 2 }, - { 166, 4 }, - { 166, 3 }, - { 166, 3 }, - { 166, 2 }, - { 167, 2 }, - { 167, 3 }, - { 167, 5 }, - { 167, 2 }, - { 167, 4 }, - { 167, 4 }, - { 167, 1 }, - { 167, 2 }, - { 172, 0 }, - { 172, 1 }, - { 174, 0 }, - { 174, 2 }, + { 150, 1 }, + { 150, 1 }, + { 150, 1 }, + { 160, 0 }, + { 160, 1 }, + { 160, 4 }, + { 160, 6 }, + { 164, 1 }, + { 164, 2 }, + { 165, 1 }, + { 165, 1 }, + { 161, 2 }, + { 161, 0 }, + { 168, 3 }, + { 168, 1 }, + { 168, 2 }, + { 168, 3 }, + { 168, 3 }, + { 168, 2 }, + { 169, 2 }, + { 169, 3 }, + { 169, 5 }, + { 169, 2 }, + { 169, 5 }, + { 169, 4 }, + { 169, 1 }, + { 169, 2 }, + { 173, 0 }, + { 173, 1 }, + { 176, 0 }, { 176, 2 }, - { 176, 3 }, - { 176, 3 }, - { 176, 3 }, - { 177, 2 }, - { 177, 2 }, - { 177, 1 }, - { 177, 1 }, - { 175, 3 }, - { 175, 2 }, - { 178, 0 }, - { 178, 2 }, - { 178, 2 }, - { 153, 0 }, - { 153, 2 }, - { 179, 3 }, + { 178, 2 }, + { 178, 3 }, + { 178, 3 }, + { 178, 3 }, + { 179, 2 }, { 179, 2 }, { 179, 1 }, - { 180, 2 }, - { 180, 7 }, - { 180, 5 }, - { 180, 5 }, - { 180, 10 }, - { 182, 0 }, - { 182, 1 }, - { 170, 0 }, - { 170, 3 }, - { 183, 0 }, - { 183, 2 }, - { 184, 1 }, - { 184, 1 }, - { 184, 1 }, - { 142, 4 }, - { 186, 2 }, - { 186, 0 }, - { 142, 7 }, - { 142, 4 }, - { 142, 1 }, - { 154, 1 }, - { 154, 3 }, - { 189, 1 }, - { 189, 2 }, - { 189, 1 }, - { 188, 9 }, + { 179, 1 }, + { 177, 3 }, + { 177, 2 }, + { 180, 0 }, + { 180, 2 }, + { 180, 2 }, + { 156, 0 }, + { 156, 2 }, + { 181, 3 }, + { 181, 2 }, + { 181, 1 }, + { 182, 2 }, + { 182, 7 }, + { 182, 5 }, + { 182, 3 }, + { 182, 10 }, + { 184, 0 }, + { 184, 1 }, + { 171, 0 }, + { 171, 3 }, + { 185, 0 }, + { 185, 2 }, + { 186, 1 }, + { 186, 1 }, + { 186, 1 }, + { 146, 3 }, + { 146, 7 }, + { 146, 3 }, + { 146, 1 }, + { 157, 1 }, + { 157, 3 }, + { 190, 1 }, + { 190, 2 }, { 190, 1 }, { 190, 1 }, - { 190, 0 }, - { 198, 2 }, - { 198, 0 }, - { 191, 3 }, - { 191, 2 }, - { 191, 4 }, + { 189, 9 }, + { 191, 1 }, + { 191, 1 }, + { 191, 0 }, { 199, 2 }, - { 199, 1 }, { 199, 0 }, - { 192, 0 }, + { 192, 3 }, { 192, 2 }, - { 201, 2 }, - { 201, 0 }, - { 200, 6 }, - { 200, 7 }, - { 205, 1 }, - { 205, 1 }, - { 151, 0 }, - { 151, 2 }, - { 187, 2 }, - { 202, 1 }, - { 202, 2 }, - { 202, 3 }, - { 202, 4 }, - { 203, 2 }, - { 203, 0 }, - { 204, 4 }, - { 204, 0 }, - { 196, 0 }, - { 196, 3 }, - { 208, 5 }, - { 208, 3 }, - { 209, 1 }, - { 171, 1 }, - { 171, 1 }, - { 171, 0 }, - { 210, 0 }, - { 210, 2 }, - { 194, 0 }, - { 194, 3 }, - { 195, 0 }, - { 195, 2 }, - { 197, 0 }, - { 197, 2 }, - { 197, 4 }, - { 197, 4 }, - { 142, 4 }, + { 192, 4 }, + { 200, 2 }, + { 200, 1 }, + { 200, 0 }, { 193, 0 }, { 193, 2 }, - { 142, 6 }, - { 212, 5 }, - { 212, 3 }, - { 142, 8 }, - { 142, 5 }, - { 213, 2 }, - { 213, 1 }, - { 215, 3 }, - { 215, 1 }, - { 214, 0 }, - { 214, 3 }, - { 207, 3 }, - { 207, 1 }, - { 169, 1 }, - { 169, 3 }, - { 168, 1 }, - { 169, 1 }, - { 169, 1 }, - { 169, 3 }, - { 169, 5 }, - { 168, 1 }, - { 168, 1 }, - { 169, 1 }, - { 169, 1 }, - { 169, 6 }, - { 169, 5 }, - { 169, 4 }, - { 168, 1 }, - { 169, 3 }, - { 169, 3 }, - { 169, 3 }, - { 169, 3 }, - { 169, 3 }, - { 169, 3 }, - { 169, 3 }, - { 169, 3 }, + { 202, 2 }, + { 202, 0 }, + { 201, 6 }, + { 201, 7 }, + { 206, 1 }, + { 206, 1 }, + { 154, 0 }, + { 154, 2 }, + { 188, 2 }, + { 203, 1 }, + { 203, 1 }, + { 203, 2 }, + { 203, 3 }, + { 203, 4 }, + { 204, 2 }, + { 204, 0 }, + { 205, 4 }, + { 205, 0 }, + { 197, 0 }, + { 197, 3 }, + { 209, 5 }, + { 209, 3 }, + { 210, 1 }, + { 172, 1 }, + { 172, 1 }, + { 172, 0 }, + { 211, 0 }, + { 211, 2 }, + { 195, 0 }, + { 195, 3 }, + { 196, 0 }, + { 196, 2 }, + { 198, 0 }, + { 198, 2 }, + { 198, 4 }, + { 198, 4 }, + { 146, 4 }, + { 194, 0 }, + { 194, 2 }, + { 146, 6 }, + { 213, 5 }, + { 213, 3 }, + { 146, 8 }, + { 146, 5 }, + { 214, 2 }, + { 214, 1 }, + { 216, 3 }, { 216, 1 }, - { 216, 2 }, + { 215, 0 }, + { 215, 3 }, + { 208, 3 }, + { 208, 1 }, + { 174, 1 }, + { 174, 3 }, + { 170, 1 }, + { 174, 1 }, + { 174, 1 }, + { 174, 3 }, + { 174, 5 }, + { 170, 1 }, + { 170, 1 }, + { 170, 1 }, + { 174, 1 }, + { 174, 1 }, + { 174, 1 }, + { 174, 4 }, + { 174, 4 }, + { 170, 1 }, + { 170, 1 }, + { 170, 1 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 174, 3 }, + { 217, 1 }, + { 217, 1 }, { 217, 2 }, - { 217, 0 }, - { 169, 4 }, - { 169, 2 }, - { 169, 3 }, - { 169, 3 }, - { 169, 4 }, - { 169, 2 }, - { 169, 2 }, - { 169, 2 }, - { 218, 1 }, + { 217, 2 }, { 218, 2 }, - { 169, 5 }, + { 218, 0 }, + { 174, 4 }, + { 174, 2 }, + { 174, 3 }, + { 174, 2 }, + { 174, 3 }, + { 174, 4 }, + { 174, 2 }, + { 174, 2 }, + { 174, 2 }, + { 174, 2 }, { 219, 1 }, { 219, 2 }, - { 169, 5 }, - { 169, 3 }, - { 169, 5 }, - { 169, 4 }, - { 169, 4 }, - { 169, 5 }, - { 221, 5 }, - { 221, 4 }, - { 222, 2 }, - { 222, 0 }, + { 174, 5 }, { 220, 1 }, - { 220, 0 }, - { 211, 3 }, - { 211, 1 }, - { 223, 1 }, + { 220, 2 }, + { 174, 5 }, + { 174, 3 }, + { 174, 5 }, + { 174, 4 }, + { 174, 4 }, + { 174, 5 }, + { 222, 5 }, + { 222, 4 }, + { 223, 2 }, { 223, 0 }, - { 142, 12 }, + { 221, 1 }, + { 221, 0 }, + { 212, 3 }, + { 212, 1 }, { 224, 1 }, { 224, 0 }, - { 173, 0 }, - { 173, 3 }, - { 181, 5 }, - { 181, 3 }, + { 146, 11 }, { 225, 1 }, - { 142, 4 }, - { 142, 1 }, - { 142, 2 }, - { 142, 5 }, - { 142, 5 }, - { 142, 5 }, - { 142, 5 }, - { 142, 6 }, - { 142, 3 }, - { 164, 2 }, - { 165, 2 }, + { 225, 0 }, + { 175, 0 }, + { 175, 3 }, + { 183, 5 }, + { 183, 3 }, + { 226, 1 }, + { 146, 3 }, + { 146, 1 }, + { 146, 2 }, + { 146, 5 }, + { 146, 5 }, + { 146, 5 }, + { 146, 5 }, + { 146, 6 }, + { 146, 3 }, + { 166, 2 }, + { 167, 2 }, + { 228, 1 }, + { 228, 1 }, { 227, 1 }, - { 226, 1 }, - { 226, 0 }, - { 142, 5 }, - { 228, 10 }, - { 230, 1 }, - { 230, 1 }, - { 230, 2 }, - { 230, 0 }, + { 227, 0 }, + { 146, 5 }, + { 229, 10 }, { 231, 1 }, { 231, 1 }, - { 231, 3 }, - { 232, 0 }, - { 232, 3 }, + { 231, 2 }, + { 231, 0 }, + { 232, 1 }, + { 232, 1 }, + { 232, 1 }, { 232, 3 }, { 233, 0 }, - { 233, 2 }, - { 229, 3 }, - { 229, 0 }, - { 234, 6 }, - { 234, 8 }, - { 234, 5 }, - { 234, 4 }, - { 234, 1 }, - { 169, 4 }, - { 169, 6 }, - { 185, 1 }, - { 185, 1 }, - { 185, 1 }, - { 142, 3 }, - { 142, 6 }, + { 233, 3 }, + { 233, 3 }, + { 234, 0 }, + { 234, 2 }, + { 230, 3 }, + { 230, 0 }, + { 235, 6 }, + { 235, 8 }, + { 235, 5 }, + { 235, 4 }, + { 235, 1 }, + { 174, 4 }, + { 174, 6 }, + { 187, 1 }, + { 187, 1 }, + { 187, 1 }, + { 146, 3 }, + { 146, 6 }, + { 237, 0 }, + { 237, 2 }, + { 237, 2 }, + { 236, 1 }, { 236, 0 }, - { 236, 2 }, - { 235, 1 }, - { 235, 0 }, - { 142, 3 }, - { 142, 1 }, - { 142, 3 }, - { 142, 1 }, - { 142, 3 }, - { 142, 6 }, - { 142, 6 }, - { 237, 1 }, - { 238, 0 }, - { 238, 1 }, + { 146, 3 }, + { 146, 1 }, + { 146, 3 }, + { 146, 6 }, }; static void yy_accept(yyParser*); /* Forward Declaration */ /* @@ -1797,1279 +1898,1202 @@ ** { ... } // User supplied code ** #line ** break; */ case 3: -#line 95 "parse.y" +#line 84 "parse.y" { sqlite3FinishCoding(pParse); } -#line 1806 "parse.c" +#line 1907 "parse.c" break; case 6: -#line 98 "parse.y" +#line 87 "parse.y" { sqlite3BeginParse(pParse, 0); } -#line 1811 "parse.c" +#line 1912 "parse.c" break; case 7: -#line 100 "parse.y" +#line 89 "parse.y" { sqlite3BeginParse(pParse, 1); } -#line 1816 "parse.c" +#line 1917 "parse.c" break; case 8: -#line 101 "parse.y" -{ sqlite3BeginParse(pParse, 2); } -#line 1821 "parse.c" +#line 95 "parse.y" +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy60);} +#line 1922 "parse.c" break; - case 9: -#line 107 "parse.y" -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy230);} -#line 1826 "parse.c" + case 12: +#line 100 "parse.y" +{yygotominor.yy60 = TK_DEFERRED;} +#line 1927 "parse.c" break; case 13: -#line 112 "parse.y" -{yygotominor.yy230 = TK_DEFERRED;} -#line 1831 "parse.c" - break; case 14: case 15: + case 101: + case 103: + case 104: +#line 101 "parse.y" +{yygotominor.yy60 = yymsp[0].major;} +#line 1937 "parse.c" + break; case 16: - case 107: - case 109: -#line 113 "parse.y" -{yygotominor.yy230 = yymsp[0].major;} -#line 1840 "parse.c" - break; case 17: - case 18: -#line 116 "parse.y" +#line 104 "parse.y" {sqlite3CommitTransaction(pParse);} -#line 1846 "parse.c" +#line 1943 "parse.c" break; - case 19: -#line 118 "parse.y" + case 18: +#line 106 "parse.y" {sqlite3RollbackTransaction(pParse);} -#line 1851 "parse.c" +#line 1948 "parse.c" + break; + case 20: +#line 111 "parse.y" +{ + sqlite3StartTable(pParse,&yymsp[-4].minor.yy0,&yymsp[-1].minor.yy406,&yymsp[0].minor.yy406,yymsp[-3].minor.yy60,0); +} +#line 1955 "parse.c" break; case 21: -#line 123 "parse.y" -{ - sqlite3StartTable(pParse,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384,yymsp[-4].minor.yy230,0,yymsp[-2].minor.yy230); -} -#line 1858 "parse.c" + case 60: + case 74: + case 106: + case 224: + case 227: +#line 115 "parse.y" +{yygotominor.yy60 = 1;} +#line 1965 "parse.c" break; case 22: - case 25: - case 63: - case 77: - case 79: - case 90: - case 101: - case 112: - case 113: - case 210: - case 213: -#line 127 "parse.y" -{yygotominor.yy230 = 0;} -#line 1873 "parse.c" + case 59: + case 73: + case 75: + case 86: + case 107: + case 108: + case 223: + case 226: +#line 116 "parse.y" +{yygotominor.yy60 = 0;} +#line 1978 "parse.c" break; case 23: +#line 117 "parse.y" +{ + sqlite3EndTable(pParse,&yymsp[0].minor.yy0,0); +} +#line 1985 "parse.c" + break; case 24: - case 64: - case 78: - case 100: - case 111: - case 211: - case 214: -#line 128 "parse.y" -{yygotominor.yy230 = 1;} -#line 1885 "parse.c" - break; - case 26: -#line 134 "parse.y" -{ - sqlite3EndTable(pParse,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy0,0); -} -#line 1892 "parse.c" - break; - case 27: -#line 137 "parse.y" -{ - sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy239); - sqlite3SelectDelete(yymsp[0].minor.yy239); -} -#line 1900 "parse.c" - break; +#line 120 "parse.y" +{ + sqlite3EndTable(pParse,0,yymsp[0].minor.yy331); + sqlite3SelectDelete(yymsp[0].minor.yy331); +} +#line 1993 "parse.c" + break; + case 28: +#line 132 "parse.y" +{sqlite3AddColumn(pParse,&yymsp[0].minor.yy406);} +#line 1998 "parse.c" + break; + case 29: case 30: -#line 149 "parse.y" -{ - yygotominor.yy384.z = yymsp[-2].minor.yy384.z; - yygotominor.yy384.n = (pParse->sLastToken.z-yymsp[-2].minor.yy384.z) + pParse->sLastToken.n; -} -#line 1908 "parse.c" - break; case 31: -#line 153 "parse.y" -{ - sqlite3AddColumn(pParse,&yymsp[0].minor.yy384); - yygotominor.yy384 = yymsp[0].minor.yy384; -} -#line 1916 "parse.c" - break; case 32: case 33: case 34: - case 35: - case 36: - case 250: -#line 163 "parse.y" -{yygotominor.yy384 = yymsp[0].minor.yy0;} -#line 1926 "parse.c" - break; - case 38: -#line 222 "parse.y" -{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy384);} -#line 1931 "parse.c" - break; - case 39: - case 42: - case 119: - case 120: - case 131: - case 150: - case 238: - case 248: - case 249: -#line 223 "parse.y" -{yygotominor.yy384 = yymsp[0].minor.yy384;} -#line 1944 "parse.c" - break; - case 40: -#line 224 "parse.y" -{ - yygotominor.yy384.z = yymsp[-3].minor.yy384.z; - yygotominor.yy384.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy384.z; -} -#line 1952 "parse.c" - break; - case 41: -#line 228 "parse.y" -{ - yygotominor.yy384.z = yymsp[-5].minor.yy384.z; - yygotominor.yy384.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy384.z; -} -#line 1960 "parse.c" - break; - case 43: -#line 234 "parse.y" -{yygotominor.yy384.z=yymsp[-1].minor.yy384.z; yygotominor.yy384.n=yymsp[0].minor.yy384.n+(yymsp[0].minor.yy384.z-yymsp[-1].minor.yy384.z);} -#line 1965 "parse.c" - break; - case 44: -#line 236 "parse.y" -{ yygotominor.yy230 = atoi((char*)yymsp[0].minor.yy384.z); } -#line 1970 "parse.c" - break; - case 45: -#line 237 "parse.y" -{ yygotominor.yy230 = -atoi((char*)yymsp[0].minor.yy384.z); } -#line 1975 "parse.c" - break; - case 50: - case 52: -#line 246 "parse.y" -{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy178);} -#line 1981 "parse.c" - break; - case 51: -#line 247 "parse.y" -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy178);} -#line 1986 "parse.c" - break; - case 53: -#line 249 "parse.y" -{ - Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy178, 0, 0); - sqlite3AddDefaultValue(pParse,p); -} -#line 1994 "parse.c" - break; - case 54: -#line 253 "parse.y" -{ - Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy384); - sqlite3AddDefaultValue(pParse,p); -} -#line 2002 "parse.c" - break; - case 56: -#line 262 "parse.y" -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy230);} -#line 2007 "parse.c" - break; - case 57: -#line 264 "parse.y" -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy230,yymsp[0].minor.yy230,yymsp[-2].minor.yy230);} -#line 2012 "parse.c" - break; - case 58: -#line 265 "parse.y" -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy230,0,0,0,0);} -#line 2017 "parse.c" - break; - case 59: -#line 266 "parse.y" -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy178);} -#line 2022 "parse.c" - break; - case 60: -#line 268 "parse.y" -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy384,yymsp[-1].minor.yy462,yymsp[0].minor.yy230);} -#line 2027 "parse.c" - break; - case 61: -#line 269 "parse.y" -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy230);} -#line 2032 "parse.c" - break; - case 62: -#line 270 "parse.y" -{sqlite3AddCollateType(pParse, (char*)yymsp[0].minor.yy384.z, yymsp[0].minor.yy384.n);} -#line 2037 "parse.c" - break; - case 65: -#line 283 "parse.y" -{ yygotominor.yy230 = OE_Restrict * 0x010101; } -#line 2042 "parse.c" - break; - case 66: -#line 284 "parse.y" -{ yygotominor.yy230 = (yymsp[-1].minor.yy230 & yymsp[0].minor.yy13.mask) | yymsp[0].minor.yy13.value; } -#line 2047 "parse.c" - break; - case 67: -#line 286 "parse.y" -{ yygotominor.yy13.value = 0; yygotominor.yy13.mask = 0x000000; } -#line 2052 "parse.c" - break; - case 68: -#line 287 "parse.y" -{ yygotominor.yy13.value = yymsp[0].minor.yy230; yygotominor.yy13.mask = 0x0000ff; } -#line 2057 "parse.c" - break; - case 69: -#line 288 "parse.y" -{ yygotominor.yy13.value = yymsp[0].minor.yy230<<8; yygotominor.yy13.mask = 0x00ff00; } -#line 2062 "parse.c" - break; - case 70: -#line 289 "parse.y" -{ yygotominor.yy13.value = yymsp[0].minor.yy230<<16; yygotominor.yy13.mask = 0xff0000; } -#line 2067 "parse.c" + case 263: + case 264: +#line 138 "parse.y" +{yygotominor.yy406 = yymsp[0].minor.yy0;} +#line 2010 "parse.c" + break; + case 36: +#line 193 "parse.y" +{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy406,&yymsp[0].minor.yy406);} +#line 2015 "parse.c" + break; + case 37: +#line 194 "parse.y" +{sqlite3AddColumnType(pParse,&yymsp[-3].minor.yy406,&yymsp[0].minor.yy0);} +#line 2020 "parse.c" + break; + case 38: +#line 196 "parse.y" +{sqlite3AddColumnType(pParse,&yymsp[-5].minor.yy406,&yymsp[0].minor.yy0);} +#line 2025 "parse.c" + break; + case 39: + case 114: + case 115: + case 126: + case 146: + case 251: + case 261: + case 262: +#line 198 "parse.y" +{yygotominor.yy406 = yymsp[0].minor.yy406;} +#line 2037 "parse.c" + break; + case 40: +#line 199 "parse.y" +{yygotominor.yy406.z=yymsp[-1].minor.yy406.z; yygotominor.yy406.n=yymsp[0].minor.yy406.n+(yymsp[0].minor.yy406.z-yymsp[-1].minor.yy406.z);} +#line 2042 "parse.c" + break; + case 41: +#line 201 "parse.y" +{ yygotominor.yy60 = atoi(yymsp[0].minor.yy406.z); } +#line 2047 "parse.c" + break; + case 42: +#line 202 "parse.y" +{ yygotominor.yy60 = -atoi(yymsp[0].minor.yy406.z); } +#line 2052 "parse.c" + break; + case 47: + case 48: +#line 207 "parse.y" +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454);} +#line 2058 "parse.c" + break; + case 49: +#line 209 "parse.y" +{ + Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy454, 0, 0); + sqlite3AddDefaultValue(pParse,p); +} +#line 2066 "parse.c" + break; + case 50: +#line 213 "parse.y" +{ + Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy406); + sqlite3AddDefaultValue(pParse,p); +} +#line 2074 "parse.c" + break; + case 52: +#line 222 "parse.y" +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy60);} +#line 2079 "parse.c" + break; + case 53: +#line 224 "parse.y" +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy60,yymsp[0].minor.yy60);} +#line 2084 "parse.c" + break; + case 54: +#line 225 "parse.y" +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy60,0,0);} +#line 2089 "parse.c" + break; + case 56: +#line 228 "parse.y" +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy406,yymsp[-1].minor.yy266,yymsp[0].minor.yy60);} +#line 2094 "parse.c" + break; + case 57: +#line 229 "parse.y" +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy60);} +#line 2099 "parse.c" + break; + case 58: +#line 230 "parse.y" +{sqlite3AddCollateType(pParse, yymsp[0].minor.yy406.z, yymsp[0].minor.yy406.n);} +#line 2104 "parse.c" + break; + case 61: +#line 243 "parse.y" +{ yygotominor.yy60 = OE_Restrict * 0x010101; } +#line 2109 "parse.c" + break; + case 62: +#line 244 "parse.y" +{ yygotominor.yy60 = (yymsp[-1].minor.yy60 & yymsp[0].minor.yy243.mask) | yymsp[0].minor.yy243.value; } +#line 2114 "parse.c" + break; + case 63: +#line 246 "parse.y" +{ yygotominor.yy243.value = 0; yygotominor.yy243.mask = 0x000000; } +#line 2119 "parse.c" + break; + case 64: +#line 247 "parse.y" +{ yygotominor.yy243.value = yymsp[0].minor.yy60; yygotominor.yy243.mask = 0x0000ff; } +#line 2124 "parse.c" + break; + case 65: +#line 248 "parse.y" +{ yygotominor.yy243.value = yymsp[0].minor.yy60<<8; yygotominor.yy243.mask = 0x00ff00; } +#line 2129 "parse.c" + break; + case 66: +#line 249 "parse.y" +{ yygotominor.yy243.value = yymsp[0].minor.yy60<<16; yygotominor.yy243.mask = 0xff0000; } +#line 2134 "parse.c" + break; + case 67: +#line 251 "parse.y" +{ yygotominor.yy60 = OE_SetNull; } +#line 2139 "parse.c" + break; + case 68: +#line 252 "parse.y" +{ yygotominor.yy60 = OE_SetDflt; } +#line 2144 "parse.c" + break; + case 69: +#line 253 "parse.y" +{ yygotominor.yy60 = OE_Cascade; } +#line 2149 "parse.c" + break; + case 70: +#line 254 "parse.y" +{ yygotominor.yy60 = OE_Restrict; } +#line 2154 "parse.c" break; case 71: -#line 291 "parse.y" -{ yygotominor.yy230 = OE_SetNull; } -#line 2072 "parse.c" - break; case 72: -#line 292 "parse.y" -{ yygotominor.yy230 = OE_SetDflt; } -#line 2077 "parse.c" - break; - case 73: -#line 293 "parse.y" -{ yygotominor.yy230 = OE_Cascade; } -#line 2082 "parse.c" - break; - case 74: -#line 294 "parse.y" -{ yygotominor.yy230 = OE_Restrict; } -#line 2087 "parse.c" - break; - case 75: - case 76: + case 87: + case 89: case 91: - case 93: - case 95: - case 96: - case 167: -#line 296 "parse.y" -{yygotominor.yy230 = yymsp[0].minor.yy230;} -#line 2098 "parse.c" - break; - case 80: -#line 306 "parse.y" -{yygotominor.yy384.n = 0; yygotominor.yy384.z = 0;} -#line 2103 "parse.c" - break; - case 81: -#line 307 "parse.y" -{yygotominor.yy384 = yymsp[-1].minor.yy0;} -#line 2108 "parse.c" - break; - case 86: -#line 313 "parse.y" -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy462,yymsp[0].minor.yy230,yymsp[-2].minor.yy230,0);} -#line 2113 "parse.c" - break; - case 87: -#line 315 "parse.y" -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy462,yymsp[0].minor.yy230,0,0,0,0);} -#line 2118 "parse.c" + case 92: + case 163: +#line 256 "parse.y" +{yygotominor.yy60 = yymsp[0].minor.yy60;} +#line 2165 "parse.c" + break; + case 82: +#line 273 "parse.y" +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy266,yymsp[0].minor.yy60,yymsp[-2].minor.yy60);} +#line 2170 "parse.c" + break; + case 83: +#line 275 "parse.y" +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy266,yymsp[0].minor.yy60,0,0);} +#line 2175 "parse.c" + break; + case 85: +#line 278 "parse.y" +{ + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy266, &yymsp[-3].minor.yy406, yymsp[-2].minor.yy266, yymsp[-1].minor.yy60); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy60); +} +#line 2183 "parse.c" break; case 88: -#line 316 "parse.y" -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy178);} -#line 2123 "parse.c" - break; - case 89: -#line 318 "parse.y" -{ - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy462, &yymsp[-3].minor.yy384, yymsp[-2].minor.yy462, yymsp[-1].minor.yy230); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy230); -} -#line 2131 "parse.c" - break; - case 92: + case 90: +#line 292 "parse.y" +{yygotominor.yy60 = OE_Default;} +#line 2189 "parse.c" + break; + case 93: +#line 297 "parse.y" +{yygotominor.yy60 = OE_Ignore;} +#line 2194 "parse.c" + break; case 94: -#line 332 "parse.y" -{yygotominor.yy230 = OE_Default;} -#line 2137 "parse.c" + case 164: +#line 298 "parse.y" +{yygotominor.yy60 = OE_Replace;} +#line 2200 "parse.c" + break; + case 95: +#line 302 "parse.y" +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy427, 0); +} +#line 2207 "parse.c" + break; + case 96: +#line 309 "parse.y" +{ + sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy406, &yymsp[-2].minor.yy406, yymsp[0].minor.yy331, yymsp[-5].minor.yy60); +} +#line 2214 "parse.c" break; case 97: -#line 337 "parse.y" -{yygotominor.yy230 = OE_Ignore;} -#line 2142 "parse.c" +#line 312 "parse.y" +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy427, 1); +} +#line 2221 "parse.c" break; case 98: - case 168: -#line 338 "parse.y" -{yygotominor.yy230 = OE_Replace;} -#line 2148 "parse.c" +#line 319 "parse.y" +{ + sqlite3Select(pParse, yymsp[0].minor.yy331, SRT_Callback, 0, 0, 0, 0, 0); + sqlite3SelectDelete(yymsp[0].minor.yy331); +} +#line 2229 "parse.c" break; case 99: -#line 342 "parse.y" + case 123: +#line 329 "parse.y" +{yygotominor.yy331 = yymsp[0].minor.yy331;} +#line 2235 "parse.c" + break; + case 100: +#line 331 "parse.y" { - sqlite3DropTable(pParse, yymsp[0].minor.yy285, 0, yymsp[-1].minor.yy230); + if( yymsp[0].minor.yy331 ){ + yymsp[0].minor.yy331->op = yymsp[-1].minor.yy60; + yymsp[0].minor.yy331->pPrior = yymsp[-2].minor.yy331; + } + yygotominor.yy331 = yymsp[0].minor.yy331; } -#line 2155 "parse.c" +#line 2246 "parse.c" break; case 102: -#line 352 "parse.y" -{ - sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy384, &yymsp[-2].minor.yy384, yymsp[0].minor.yy239, yymsp[-5].minor.yy230); -} -#line 2162 "parse.c" - break; - case 103: -#line 355 "parse.y" -{ - sqlite3DropTable(pParse, yymsp[0].minor.yy285, 1, yymsp[-1].minor.yy230); -} -#line 2169 "parse.c" - break; - case 104: -#line 362 "parse.y" -{ - sqlite3Select(pParse, yymsp[0].minor.yy239, SRT_Callback, 0, 0, 0, 0, 0); - sqlite3SelectDelete(yymsp[0].minor.yy239); -} -#line 2177 "parse.c" +#line 340 "parse.y" +{yygotominor.yy60 = TK_ALL;} +#line 2251 "parse.c" break; case 105: - case 128: -#line 372 "parse.y" -{yygotominor.yy239 = yymsp[0].minor.yy239;} -#line 2183 "parse.c" +#line 345 "parse.y" +{ + yygotominor.yy331 = sqlite3SelectNew(yymsp[-6].minor.yy266,yymsp[-5].minor.yy427,yymsp[-4].minor.yy454,yymsp[-3].minor.yy266,yymsp[-2].minor.yy454,yymsp[-1].minor.yy266,yymsp[-7].minor.yy60,yymsp[0].minor.yy348.pLimit,yymsp[0].minor.yy348.pOffset); +} +#line 2258 "parse.c" break; - case 106: + case 109: + case 248: +#line 366 "parse.y" +{yygotominor.yy266 = yymsp[-1].minor.yy266;} +#line 2264 "parse.c" + break; + case 110: + case 137: + case 147: + case 247: +#line 367 "parse.y" +{yygotominor.yy266 = 0;} +#line 2272 "parse.c" + break; + case 111: +#line 368 "parse.y" +{ + yygotominor.yy266 = sqlite3ExprListAppend(yymsp[-2].minor.yy266,yymsp[-1].minor.yy454,yymsp[0].minor.yy406.n?&yymsp[0].minor.yy406:0); +} +#line 2279 "parse.c" + break; + case 112: +#line 371 "parse.y" +{ + yygotominor.yy266 = sqlite3ExprListAppend(yymsp[-1].minor.yy266, sqlite3Expr(TK_ALL, 0, 0, 0), 0); +} +#line 2286 "parse.c" + break; + case 113: #line 374 "parse.y" { - if( yymsp[0].minor.yy239 ){ - yymsp[0].minor.yy239->op = yymsp[-1].minor.yy230; - yymsp[0].minor.yy239->pPrior = yymsp[-2].minor.yy239; - } - yygotominor.yy239 = yymsp[0].minor.yy239; -} -#line 2194 "parse.c" - break; - case 108: -#line 383 "parse.y" -{yygotominor.yy230 = TK_ALL;} -#line 2199 "parse.c" - break; - case 110: -#line 387 "parse.y" -{ - yygotominor.yy239 = sqlite3SelectNew(yymsp[-6].minor.yy462,yymsp[-5].minor.yy285,yymsp[-4].minor.yy178,yymsp[-3].minor.yy462,yymsp[-2].minor.yy178,yymsp[-1].minor.yy462,yymsp[-7].minor.yy230,yymsp[0].minor.yy270.pLimit,yymsp[0].minor.yy270.pOffset); -} -#line 2206 "parse.c" - break; - case 114: - case 235: -#line 408 "parse.y" -{yygotominor.yy462 = yymsp[-1].minor.yy462;} -#line 2212 "parse.c" - break; - case 115: - case 141: - case 151: - case 234: -#line 409 "parse.y" -{yygotominor.yy462 = 0;} -#line 2220 "parse.c" + Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0); + Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy406); + yygotominor.yy266 = sqlite3ExprListAppend(yymsp[-3].minor.yy266, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0); +} +#line 2295 "parse.c" break; case 116: -#line 410 "parse.y" -{ - yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-2].minor.yy462,yymsp[-1].minor.yy178,yymsp[0].minor.yy384.n?&yymsp[0].minor.yy384:0); -} -#line 2227 "parse.c" +#line 386 "parse.y" +{yygotominor.yy406.n = 0;} +#line 2300 "parse.c" break; case 117: -#line 413 "parse.y" -{ - yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-1].minor.yy462, sqlite3Expr(TK_ALL, 0, 0, 0), 0); -} -#line 2234 "parse.c" +#line 398 "parse.y" +{yygotominor.yy427 = sqliteMalloc(sizeof(*yygotominor.yy427));} +#line 2305 "parse.c" break; case 118: -#line 416 "parse.y" +#line 399 "parse.y" +{yygotominor.yy427 = yymsp[0].minor.yy427;} +#line 2310 "parse.c" + break; + case 119: +#line 404 "parse.y" { - Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0); - Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384); - yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-3].minor.yy462, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0); + yygotominor.yy427 = yymsp[-1].minor.yy427; + if( yygotominor.yy427 && yygotominor.yy427->nSrc>0 ) yygotominor.yy427->a[yygotominor.yy427->nSrc-1].jointype = yymsp[0].minor.yy60; } -#line 2243 "parse.c" +#line 2318 "parse.c" + break; + case 120: +#line 408 "parse.y" +{yygotominor.yy427 = 0;} +#line 2323 "parse.c" break; case 121: -#line 428 "parse.y" -{yygotominor.yy384.n = 0;} -#line 2248 "parse.c" +#line 409 "parse.y" +{ + yygotominor.yy427 = sqlite3SrcListAppend(yymsp[-5].minor.yy427,&yymsp[-4].minor.yy406,&yymsp[-3].minor.yy406); + if( yymsp[-2].minor.yy406.n ) sqlite3SrcListAddAlias(yygotominor.yy427,&yymsp[-2].minor.yy406); + if( yymsp[-1].minor.yy454 ){ + if( yygotominor.yy427 && yygotominor.yy427->nSrc>1 ){ yygotominor.yy427->a[yygotominor.yy427->nSrc-2].pOn = yymsp[-1].minor.yy454; } + else { sqlite3ExprDelete(yymsp[-1].minor.yy454); } + } + if( yymsp[0].minor.yy272 ){ + if( yygotominor.yy427 && yygotominor.yy427->nSrc>1 ){ yygotominor.yy427->a[yygotominor.yy427->nSrc-2].pUsing = yymsp[0].minor.yy272; } + else { sqlite3IdListDelete(yymsp[0].minor.yy272); } + } +} +#line 2339 "parse.c" break; case 122: -#line 440 "parse.y" -{yygotominor.yy285 = sqliteMalloc(sizeof(*yygotominor.yy285));} -#line 2253 "parse.c" - break; - case 123: -#line 441 "parse.y" -{yygotominor.yy285 = yymsp[0].minor.yy285;} -#line 2258 "parse.c" +#line 423 "parse.y" +{ + yygotominor.yy427 = sqlite3SrcListAppend(yymsp[-6].minor.yy427,0,0); + yygotominor.yy427->a[yygotominor.yy427->nSrc-1].pSelect = yymsp[-4].minor.yy331; + if( yymsp[-2].minor.yy406.n ) sqlite3SrcListAddAlias(yygotominor.yy427,&yymsp[-2].minor.yy406); + if( yymsp[-1].minor.yy454 ){ + if( yygotominor.yy427 && yygotominor.yy427->nSrc>1 ){ yygotominor.yy427->a[yygotominor.yy427->nSrc-2].pOn = yymsp[-1].minor.yy454; } + else { sqlite3ExprDelete(yymsp[-1].minor.yy454); } + } + if( yymsp[0].minor.yy272 ){ + if( yygotominor.yy427 && yygotominor.yy427->nSrc>1 ){ yygotominor.yy427->a[yygotominor.yy427->nSrc-2].pUsing = yymsp[0].minor.yy272; } + else { sqlite3IdListDelete(yymsp[0].minor.yy272); } + } + } +#line 2356 "parse.c" break; case 124: -#line 446 "parse.y" +#line 444 "parse.y" { - yygotominor.yy285 = yymsp[-1].minor.yy285; - if( yygotominor.yy285 && yygotominor.yy285->nSrc>0 ) yygotominor.yy285->a[yygotominor.yy285->nSrc-1].jointype = yymsp[0].minor.yy230; -} -#line 2266 "parse.c" + yygotominor.yy331 = sqlite3SelectNew(0,yymsp[0].minor.yy427,0,0,0,0,0,0,0); + } +#line 2363 "parse.c" break; case 125: #line 450 "parse.y" -{yygotominor.yy285 = 0;} -#line 2271 "parse.c" - break; - case 126: -#line 451 "parse.y" -{ - yygotominor.yy285 = sqlite3SrcListAppend(yymsp[-5].minor.yy285,&yymsp[-4].minor.yy384,&yymsp[-3].minor.yy384); - if( yymsp[-2].minor.yy384.n ) sqlite3SrcListAddAlias(yygotominor.yy285,&yymsp[-2].minor.yy384); - if( yymsp[-1].minor.yy178 ){ - if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pOn = yymsp[-1].minor.yy178; } - else { sqlite3ExprDelete(yymsp[-1].minor.yy178); } - } - if( yymsp[0].minor.yy160 ){ - if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pUsing = yymsp[0].minor.yy160; } - else { sqlite3IdListDelete(yymsp[0].minor.yy160); } - } -} -#line 2287 "parse.c" +{yygotominor.yy406.z=0; yygotominor.yy406.n=0;} +#line 2368 "parse.c" break; case 127: -#line 465 "parse.y" -{ - yygotominor.yy285 = sqlite3SrcListAppend(yymsp[-6].minor.yy285,0,0); - yygotominor.yy285->a[yygotominor.yy285->nSrc-1].pSelect = yymsp[-4].minor.yy239; - if( yymsp[-2].minor.yy384.n ) sqlite3SrcListAddAlias(yygotominor.yy285,&yymsp[-2].minor.yy384); - if( yymsp[-1].minor.yy178 ){ - if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pOn = yymsp[-1].minor.yy178; } - else { sqlite3ExprDelete(yymsp[-1].minor.yy178); } - } - if( yymsp[0].minor.yy160 ){ - if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pUsing = yymsp[0].minor.yy160; } - else { sqlite3IdListDelete(yymsp[0].minor.yy160); } - } - } -#line 2304 "parse.c" +#line 455 "parse.y" +{yygotominor.yy427 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy406,&yymsp[0].minor.yy406);} +#line 2373 "parse.c" break; + case 128: case 129: -#line 486 "parse.y" -{ - yygotominor.yy239 = sqlite3SelectNew(0,yymsp[0].minor.yy285,0,0,0,0,0,0,0); - } -#line 2311 "parse.c" +#line 459 "parse.y" +{ yygotominor.yy60 = JT_INNER; } +#line 2379 "parse.c" break; case 130: -#line 492 "parse.y" -{yygotominor.yy384.z=0; yygotominor.yy384.n=0;} -#line 2316 "parse.c" +#line 461 "parse.y" +{ yygotominor.yy60 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); } +#line 2384 "parse.c" + break; + case 131: +#line 462 "parse.y" +{ yygotominor.yy60 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy406,0); } +#line 2389 "parse.c" break; case 132: -#line 497 "parse.y" -{yygotominor.yy285 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384);} -#line 2321 "parse.c" +#line 464 "parse.y" +{ yygotominor.yy60 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy406,&yymsp[-1].minor.yy406); } +#line 2394 "parse.c" break; case 133: -#line 501 "parse.y" -{ yygotominor.yy230 = JT_INNER; } -#line 2326 "parse.c" + case 141: + case 150: + case 157: + case 171: + case 211: + case 236: + case 238: + case 242: +#line 468 "parse.y" +{yygotominor.yy454 = yymsp[0].minor.yy454;} +#line 2407 "parse.c" break; case 134: -#line 502 "parse.y" -{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); } -#line 2331 "parse.c" + case 149: + case 156: + case 212: + case 237: + case 239: + case 243: +#line 469 "parse.y" +{yygotominor.yy454 = 0;} +#line 2418 "parse.c" break; case 135: -#line 503 "parse.y" -{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy384,0); } -#line 2336 "parse.c" + case 168: +#line 473 "parse.y" +{yygotominor.yy272 = yymsp[-1].minor.yy272;} +#line 2424 "parse.c" break; case 136: -#line 505 "parse.y" -{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy384,&yymsp[-1].minor.yy384); } -#line 2341 "parse.c" - break; - case 137: - case 145: - case 154: - case 161: - case 175: - case 200: - case 223: - case 225: - case 229: -#line 509 "parse.y" -{yygotominor.yy178 = yymsp[0].minor.yy178;} -#line 2354 "parse.c" + case 167: +#line 474 "parse.y" +{yygotominor.yy272 = 0;} +#line 2430 "parse.c" break; case 138: - case 153: - case 160: - case 201: - case 224: - case 226: - case 230: -#line 510 "parse.y" -{yygotominor.yy178 = 0;} -#line 2365 "parse.c" + case 148: +#line 485 "parse.y" +{yygotominor.yy266 = yymsp[0].minor.yy266;} +#line 2436 "parse.c" break; case 139: - case 172: -#line 514 "parse.y" -{yygotominor.yy160 = yymsp[-1].minor.yy160;} -#line 2371 "parse.c" +#line 486 "parse.y" +{ + yygotominor.yy266 = sqlite3ExprListAppend(yymsp[-4].minor.yy266,yymsp[-2].minor.yy454,yymsp[-1].minor.yy406.n>0?&yymsp[-1].minor.yy406:0); + if( yygotominor.yy266 ) yygotominor.yy266->a[yygotominor.yy266->nExpr-1].sortOrder = yymsp[0].minor.yy60; +} +#line 2444 "parse.c" break; case 140: - case 171: -#line 515 "parse.y" -{yygotominor.yy160 = 0;} -#line 2377 "parse.c" +#line 490 "parse.y" +{ + yygotominor.yy266 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy454,yymsp[-1].minor.yy406.n>0?&yymsp[-1].minor.yy406:0); + if( yygotominor.yy266 && yygotominor.yy266->a ) yygotominor.yy266->a[0].sortOrder = yymsp[0].minor.yy60; +} +#line 2452 "parse.c" break; case 142: - case 152: -#line 526 "parse.y" -{yygotominor.yy462 = yymsp[0].minor.yy462;} -#line 2383 "parse.c" + case 144: +#line 499 "parse.y" +{yygotominor.yy60 = SQLITE_SO_ASC;} +#line 2458 "parse.c" break; case 143: -#line 527 "parse.y" -{ - yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462,yymsp[-2].minor.yy178,yymsp[-1].minor.yy384.n>0?&yymsp[-1].minor.yy384:0); - if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230; -} -#line 2391 "parse.c" - break; - case 144: -#line 531 "parse.y" -{ - yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy178,yymsp[-1].minor.yy384.n>0?&yymsp[-1].minor.yy384:0); - if( yygotominor.yy462 && yygotominor.yy462->a ) yygotominor.yy462->a[0].sortOrder = yymsp[0].minor.yy230; -} -#line 2399 "parse.c" - break; - case 146: - case 148: -#line 540 "parse.y" -{yygotominor.yy230 = SQLITE_SO_ASC;} -#line 2405 "parse.c" - break; - case 147: -#line 541 "parse.y" -{yygotominor.yy230 = SQLITE_SO_DESC;} -#line 2410 "parse.c" - break; - case 149: -#line 543 "parse.y" -{yygotominor.yy384.z = 0; yygotominor.yy384.n = 0;} -#line 2415 "parse.c" +#line 500 "parse.y" +{yygotominor.yy60 = SQLITE_SO_DESC;} +#line 2463 "parse.c" + break; + case 145: +#line 502 "parse.y" +{yygotominor.yy406.z = 0; yygotominor.yy406.n = 0;} +#line 2468 "parse.c" + break; + case 151: +#line 520 "parse.y" +{yygotominor.yy348.pLimit = 0; yygotominor.yy348.pOffset = 0;} +#line 2473 "parse.c" + break; + case 152: +#line 521 "parse.y" +{yygotominor.yy348.pLimit = yymsp[0].minor.yy454; yygotominor.yy348.pOffset = 0;} +#line 2478 "parse.c" + break; + case 153: +#line 523 "parse.y" +{yygotominor.yy348.pLimit = yymsp[-2].minor.yy454; yygotominor.yy348.pOffset = yymsp[0].minor.yy454;} +#line 2483 "parse.c" + break; + case 154: +#line 525 "parse.y" +{yygotominor.yy348.pOffset = yymsp[-2].minor.yy454; yygotominor.yy348.pLimit = yymsp[0].minor.yy454;} +#line 2488 "parse.c" break; case 155: -#line 561 "parse.y" -{yygotominor.yy270.pLimit = 0; yygotominor.yy270.pOffset = 0;} -#line 2420 "parse.c" - break; - case 156: -#line 562 "parse.y" -{yygotominor.yy270.pLimit = yymsp[0].minor.yy178; yygotominor.yy270.pOffset = 0;} -#line 2425 "parse.c" - break; - case 157: -#line 564 "parse.y" -{yygotominor.yy270.pLimit = yymsp[-2].minor.yy178; yygotominor.yy270.pOffset = yymsp[0].minor.yy178;} -#line 2430 "parse.c" +#line 529 "parse.y" +{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy427,yymsp[0].minor.yy454);} +#line 2493 "parse.c" break; case 158: -#line 566 "parse.y" -{yygotominor.yy270.pOffset = yymsp[-2].minor.yy178; yygotominor.yy270.pLimit = yymsp[0].minor.yy178;} -#line 2435 "parse.c" +#line 543 "parse.y" +{sqlite3Update(pParse,yymsp[-3].minor.yy427,yymsp[-1].minor.yy266,yymsp[0].minor.yy454,yymsp[-4].minor.yy60);} +#line 2498 "parse.c" break; case 159: -#line 570 "parse.y" -{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy285,yymsp[0].minor.yy178);} -#line 2440 "parse.c" +#line 546 "parse.y" +{yygotominor.yy266 = sqlite3ExprListAppend(yymsp[-4].minor.yy266,yymsp[0].minor.yy454,&yymsp[-2].minor.yy406);} +#line 2503 "parse.c" + break; + case 160: +#line 547 "parse.y" +{yygotominor.yy266 = sqlite3ExprListAppend(0,yymsp[0].minor.yy454,&yymsp[-2].minor.yy406);} +#line 2508 "parse.c" + break; + case 161: +#line 553 "parse.y" +{sqlite3Insert(pParse, yymsp[-5].minor.yy427, yymsp[-1].minor.yy266, 0, yymsp[-4].minor.yy272, yymsp[-7].minor.yy60);} +#line 2513 "parse.c" break; case 162: -#line 581 "parse.y" -{sqlite3Update(pParse,yymsp[-3].minor.yy285,yymsp[-1].minor.yy462,yymsp[0].minor.yy178,yymsp[-4].minor.yy230);} -#line 2445 "parse.c" - break; - case 163: -#line 587 "parse.y" -{yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462,yymsp[0].minor.yy178,&yymsp[-2].minor.yy384);} -#line 2450 "parse.c" - break; - case 164: -#line 588 "parse.y" -{yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[0].minor.yy178,&yymsp[-2].minor.yy384);} -#line 2455 "parse.c" +#line 555 "parse.y" +{sqlite3Insert(pParse, yymsp[-2].minor.yy427, 0, yymsp[0].minor.yy331, yymsp[-1].minor.yy272, yymsp[-4].minor.yy60);} +#line 2518 "parse.c" break; case 165: -#line 594 "parse.y" -{sqlite3Insert(pParse, yymsp[-5].minor.yy285, yymsp[-1].minor.yy462, 0, yymsp[-4].minor.yy160, yymsp[-7].minor.yy230);} -#line 2460 "parse.c" + case 240: +#line 565 "parse.y" +{yygotominor.yy266 = sqlite3ExprListAppend(yymsp[-2].minor.yy266,yymsp[0].minor.yy454,0);} +#line 2524 "parse.c" break; case 166: -#line 596 "parse.y" -{sqlite3Insert(pParse, yymsp[-2].minor.yy285, 0, yymsp[0].minor.yy239, yymsp[-1].minor.yy160, yymsp[-4].minor.yy230);} -#line 2465 "parse.c" + case 241: +#line 566 "parse.y" +{yygotominor.yy266 = sqlite3ExprListAppend(0,yymsp[0].minor.yy454,0);} +#line 2530 "parse.c" break; case 169: - case 227: -#line 606 "parse.y" -{yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-2].minor.yy462,yymsp[0].minor.yy178,0);} -#line 2471 "parse.c" +#line 575 "parse.y" +{yygotominor.yy272 = sqlite3IdListAppend(yymsp[-2].minor.yy272,&yymsp[0].minor.yy406);} +#line 2535 "parse.c" break; case 170: - case 228: -#line 607 "parse.y" -{yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[0].minor.yy178,0);} -#line 2477 "parse.c" +#line 576 "parse.y" +{yygotominor.yy272 = sqlite3IdListAppend(0,&yymsp[0].minor.yy406);} +#line 2540 "parse.c" + break; + case 172: +#line 587 "parse.y" +{yygotominor.yy454 = yymsp[-1].minor.yy454; sqlite3ExprSpan(yygotominor.yy454,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); } +#line 2545 "parse.c" break; case 173: -#line 616 "parse.y" -{yygotominor.yy160 = sqlite3IdListAppend(yymsp[-2].minor.yy160,&yymsp[0].minor.yy384);} -#line 2482 "parse.c" + case 178: + case 179: + case 180: + case 181: +#line 588 "parse.y" +{yygotominor.yy454 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);} +#line 2554 "parse.c" break; case 174: -#line 617 "parse.y" -{yygotominor.yy160 = sqlite3IdListAppend(0,&yymsp[0].minor.yy384);} -#line 2487 "parse.c" + case 175: +#line 589 "parse.y" +{yygotominor.yy454 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);} +#line 2560 "parse.c" break; case 176: -#line 628 "parse.y" -{yygotominor.yy178 = yymsp[-1].minor.yy178; sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); } -#line 2492 "parse.c" +#line 591 "parse.y" +{ + Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy406); + Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy406); + yygotominor.yy454 = sqlite3Expr(TK_DOT, temp1, temp2, 0); +} +#line 2569 "parse.c" break; case 177: +#line 596 "parse.y" +{ + Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy406); + Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy406); + Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy406); + Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0); + yygotominor.yy454 = sqlite3Expr(TK_DOT, temp1, temp4, 0); +} +#line 2580 "parse.c" + break; case 182: +#line 607 "parse.y" +{yygotominor.yy454 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);} +#line 2585 "parse.c" + break; case 183: -#line 629 "parse.y" -{yygotominor.yy178 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);} -#line 2499 "parse.c" - break; - case 178: - case 179: -#line 630 "parse.y" -{yygotominor.yy178 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);} -#line 2505 "parse.c" - break; - case 180: -#line 632 "parse.y" -{ - Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384); - Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy384); - yygotominor.yy178 = sqlite3Expr(TK_DOT, temp1, temp2, 0); -} -#line 2514 "parse.c" - break; - case 181: -#line 637 "parse.y" -{ - Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy384); - Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384); - Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy384); - Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0); - yygotominor.yy178 = sqlite3Expr(TK_DOT, temp1, temp4, 0); -} -#line 2525 "parse.c" +#line 608 "parse.y" +{ + Token *pToken = &yymsp[0].minor.yy0; + Expr *pExpr = yygotominor.yy454 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken); + sqlite3ExprAssignVarNumber(pParse, pExpr); +} +#line 2594 "parse.c" break; case 184: -#line 646 "parse.y" -{yygotominor.yy178 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);} -#line 2530 "parse.c" +#line 613 "parse.y" +{ + yygotominor.yy454 = sqlite3ExprFunction(yymsp[-1].minor.yy266, &yymsp[-3].minor.yy0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); +} +#line 2602 "parse.c" break; case 185: -#line 647 "parse.y" +#line 617 "parse.y" { - Token *pToken = &yymsp[0].minor.yy0; - Expr *pExpr = yygotominor.yy178 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken); - sqlite3ExprAssignVarNumber(pParse, pExpr); + yygotominor.yy454 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); } -#line 2539 "parse.c" +#line 2610 "parse.c" break; case 186: -#line 653 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy178, 0, &yymsp[-1].minor.yy384); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); -} -#line 2547 "parse.c" - break; case 187: -#line 658 "parse.y" -{ - yygotominor.yy178 = sqlite3ExprFunction(yymsp[-1].minor.yy462, &yymsp[-4].minor.yy0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); - if( yymsp[-2].minor.yy230 ){ - yygotominor.yy178->flags |= EP_Distinct; - } -} -#line 2558 "parse.c" - break; case 188: -#line 665 "parse.y" -{ - yygotominor.yy178 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); -} -#line 2566 "parse.c" +#line 621 "parse.y" +{yygotominor.yy454 = sqlite3Expr(yymsp[0].major,0,0,0);} +#line 2617 "parse.c" break; case 189: -#line 669 "parse.y" -{ - /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are - ** treated as functions that return constants */ - yygotominor.yy178 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0); - if( yygotominor.yy178 ) yygotominor.yy178->op = TK_CONST_FUNC; -} -#line 2576 "parse.c" - break; case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: -#line 675 "parse.y" -{yygotominor.yy178 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy178, yymsp[0].minor.yy178, 0);} -#line 2588 "parse.c" - break; - case 198: -#line 685 "parse.y" -{yygotominor.yy440.operator = yymsp[0].minor.yy0; yygotominor.yy440.not = 0;} -#line 2593 "parse.c" - break; - case 199: -#line 686 "parse.y" -{yygotominor.yy440.operator = yymsp[0].minor.yy0; yygotominor.yy440.not = 1;} -#line 2598 "parse.c" - break; - case 202: -#line 691 "parse.y" -{ - ExprList *pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy178, 0); - pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy178, 0); - if( yymsp[0].minor.yy178 ){ - pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy178, 0); - } - yygotominor.yy178 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy440.operator); - if( yymsp[-2].minor.yy440.not ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178, &yymsp[-3].minor.yy178->span, &yymsp[-1].minor.yy178->span); -} -#line 2612 "parse.c" - break; - case 203: -#line 702 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(yymsp[0].major, yymsp[-1].minor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy178->span,&yymsp[0].minor.yy0); -} -#line 2620 "parse.c" - break; - case 204: -#line 706 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy178->span,&yymsp[0].minor.yy0); -} -#line 2628 "parse.c" - break; - case 205: -#line 710 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy178->span,&yymsp[0].minor.yy0); -} -#line 2636 "parse.c" - break; - case 206: -#line 714 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy178->span,&yymsp[0].minor.yy0); -} -#line 2644 "parse.c" - break; - case 207: -#line 718 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span); -} -#line 2652 "parse.c" - break; - case 208: -#line 722 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span); -} -#line 2660 "parse.c" - break; - case 209: -#line 726 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span); -} -#line 2668 "parse.c" - break; - case 212: -#line 733 "parse.y" -{ - ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy178, 0); - pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy178, 0); - yygotominor.yy178 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy178, 0, 0); - if( yygotominor.yy178 ){ - yygotominor.yy178->pList = pList; - }else{ - sqlite3ExprListDelete(pList); - } - if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy178->span); -} -#line 2684 "parse.c" - break; - case 215: -#line 749 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy178, 0, 0); - if( yygotominor.yy178 ){ - yygotominor.yy178->pList = yymsp[-1].minor.yy462; - }else{ - sqlite3ExprListDelete(yymsp[-1].minor.yy462); - } - if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy0); - } -#line 2698 "parse.c" - break; - case 216: -#line 759 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_SELECT, 0, 0, 0); - if( yygotominor.yy178 ){ - yygotominor.yy178->pSelect = yymsp[-1].minor.yy239; - }else{ - sqlite3SelectDelete(yymsp[-1].minor.yy239); - } - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); - } -#line 2711 "parse.c" - break; - case 217: -#line 768 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy178, 0, 0); - if( yygotominor.yy178 ){ - yygotominor.yy178->pSelect = yymsp[-1].minor.yy239; - }else{ - sqlite3SelectDelete(yymsp[-1].minor.yy239); - } - if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy0); - } -#line 2725 "parse.c" - break; - case 218: -#line 778 "parse.y" -{ - SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384); - yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy178, 0, 0); - if( yygotominor.yy178 ){ - yygotominor.yy178->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0); - }else{ - sqlite3SrcListDelete(pSrc); - } - if( yymsp[-2].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); - sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy178->span,yymsp[0].minor.yy384.z?&yymsp[0].minor.yy384:&yymsp[-1].minor.yy384); - } -#line 2740 "parse.c" - break; - case 219: -#line 789 "parse.y" -{ - Expr *p = yygotominor.yy178 = sqlite3Expr(TK_EXISTS, 0, 0, 0); - if( p ){ - p->pSelect = yymsp[-1].minor.yy239; - sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); - }else{ - sqlite3SelectDelete(yymsp[-1].minor.yy239); - } - } -#line 2753 "parse.c" - break; - case 220: -#line 801 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy178, yymsp[-1].minor.yy178, 0); - if( yygotominor.yy178 ){ - yygotominor.yy178->pList = yymsp[-2].minor.yy462; - }else{ - sqlite3ExprListDelete(yymsp[-2].minor.yy462); - } - sqlite3ExprSpan(yygotominor.yy178, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); -} -#line 2766 "parse.c" - break; - case 221: -#line 812 "parse.y" -{ - yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462, yymsp[-2].minor.yy178, 0); - yygotominor.yy462 = sqlite3ExprListAppend(yygotominor.yy462, yymsp[0].minor.yy178, 0); -} -#line 2774 "parse.c" - break; - case 222: -#line 816 "parse.y" -{ - yygotominor.yy462 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy178, 0); - yygotominor.yy462 = sqlite3ExprListAppend(yygotominor.yy462, yymsp[0].minor.yy178, 0); -} -#line 2782 "parse.c" - break; - case 231: -#line 843 "parse.y" -{ - if( yymsp[-10].minor.yy230!=OE_None ) yymsp[-10].minor.yy230 = yymsp[0].minor.yy230; - if( yymsp[-10].minor.yy230==OE_Default) yymsp[-10].minor.yy230 = OE_Abort; - sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy384, &yymsp[-6].minor.yy384, sqlite3SrcListAppend(0,&yymsp[-4].minor.yy384,0), yymsp[-2].minor.yy462, yymsp[-10].minor.yy230, - &yymsp[-11].minor.yy0, &yymsp[-1].minor.yy0, SQLITE_SO_ASC, yymsp[-8].minor.yy230); -} -#line 2792 "parse.c" - break; - case 232: - case 277: -#line 851 "parse.y" -{yygotominor.yy230 = OE_Abort;} -#line 2798 "parse.c" - break; - case 233: -#line 852 "parse.y" -{yygotominor.yy230 = OE_None;} -#line 2803 "parse.c" - break; - case 236: -#line 862 "parse.y" -{ - Expr *p = 0; - if( yymsp[-1].minor.yy384.n>0 ){ - p = sqlite3Expr(TK_COLUMN, 0, 0, 0); - if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy384.z, yymsp[-1].minor.yy384.n); - } - yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462, p, &yymsp[-2].minor.yy384); - if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230; -} -#line 2816 "parse.c" - break; - case 237: -#line 871 "parse.y" -{ - Expr *p = 0; - if( yymsp[-1].minor.yy384.n>0 ){ - p = sqlite3Expr(TK_COLUMN, 0, 0, 0); - if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy384.z, yymsp[-1].minor.yy384.n); - } - yygotominor.yy462 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy384); - if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230; -} -#line 2829 "parse.c" - break; - case 239: -#line 885 "parse.y" -{sqlite3DropIndex(pParse, yymsp[0].minor.yy285, yymsp[-1].minor.yy230);} -#line 2834 "parse.c" - break; - case 240: - case 241: -#line 889 "parse.y" -{sqlite3Vacuum(pParse,0);} -#line 2840 "parse.c" - break; - case 242: - case 244: -#line 895 "parse.y" -{sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy384,0);} -#line 2846 "parse.c" - break; - case 243: -#line 896 "parse.y" -{sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy0,0);} -#line 2851 "parse.c" - break; - case 245: -#line 898 "parse.y" -{ - sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy384,1); -} -#line 2858 "parse.c" - break; - case 246: -#line 901 "parse.y" -{sqlite3Pragma(pParse,&yymsp[-4].minor.yy384,&yymsp[-3].minor.yy384,&yymsp[-1].minor.yy384,0);} -#line 2863 "parse.c" - break; - case 247: -#line 902 "parse.y" -{sqlite3Pragma(pParse,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384,0,0);} -#line 2868 "parse.c" - break; - case 253: -#line 914 "parse.y" -{ - Token all; - all.z = yymsp[-3].minor.yy384.z; - all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy384.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy247, &all); -} -#line 2878 "parse.c" - break; - case 254: -#line 923 "parse.y" -{ - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy384, &yymsp[-6].minor.yy384, yymsp[-5].minor.yy230, yymsp[-4].minor.yy132.a, yymsp[-4].minor.yy132.b, yymsp[-2].minor.yy285, yymsp[-1].minor.yy230, yymsp[0].minor.yy178, yymsp[-9].minor.yy230); - yygotominor.yy384 = (yymsp[-6].minor.yy384.n==0?yymsp[-7].minor.yy384:yymsp[-6].minor.yy384); -} -#line 2886 "parse.c" - break; - case 255: - case 258: -#line 929 "parse.y" -{ yygotominor.yy230 = TK_BEFORE; } -#line 2892 "parse.c" - break; - case 256: -#line 930 "parse.y" -{ yygotominor.yy230 = TK_AFTER; } -#line 2897 "parse.c" - break; - case 257: -#line 931 "parse.y" -{ yygotominor.yy230 = TK_INSTEAD;} -#line 2902 "parse.c" - break; - case 259: - case 260: -#line 936 "parse.y" -{yygotominor.yy132.a = yymsp[0].major; yygotominor.yy132.b = 0;} -#line 2908 "parse.c" - break; - case 261: -#line 938 "parse.y" -{yygotominor.yy132.a = TK_UPDATE; yygotominor.yy132.b = yymsp[0].minor.yy160;} -#line 2913 "parse.c" - break; - case 262: - case 263: -#line 941 "parse.y" -{ yygotominor.yy230 = TK_ROW; } -#line 2919 "parse.c" - break; - case 264: -#line 943 "parse.y" -{ yygotominor.yy230 = TK_STATEMENT; } -#line 2924 "parse.c" - break; - case 265: -#line 947 "parse.y" -{ yygotominor.yy178 = 0; } -#line 2929 "parse.c" - break; - case 266: -#line 948 "parse.y" -{ yygotominor.yy178 = yymsp[0].minor.yy178; } -#line 2934 "parse.c" - break; - case 267: -#line 952 "parse.y" -{ - yymsp[-2].minor.yy247->pNext = yymsp[0].minor.yy247; - yygotominor.yy247 = yymsp[-2].minor.yy247; -} -#line 2942 "parse.c" - break; - case 268: -#line 956 "parse.y" -{ yygotominor.yy247 = 0; } -#line 2947 "parse.c" - break; - case 269: -#line 962 "parse.y" -{ yygotominor.yy247 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy384, yymsp[-1].minor.yy462, yymsp[0].minor.yy178, yymsp[-4].minor.yy230); } -#line 2952 "parse.c" - break; - case 270: -#line 967 "parse.y" -{yygotominor.yy247 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy384, yymsp[-4].minor.yy160, yymsp[-1].minor.yy462, 0, yymsp[-7].minor.yy230);} -#line 2957 "parse.c" - break; - case 271: -#line 970 "parse.y" -{yygotominor.yy247 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy384, yymsp[-1].minor.yy160, 0, yymsp[0].minor.yy239, yymsp[-4].minor.yy230);} -#line 2962 "parse.c" - break; - case 272: -#line 974 "parse.y" -{yygotominor.yy247 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy384, yymsp[0].minor.yy178);} -#line 2967 "parse.c" - break; - case 273: -#line 977 "parse.y" -{yygotominor.yy247 = sqlite3TriggerSelectStep(yymsp[0].minor.yy239); } -#line 2972 "parse.c" - break; - case 274: -#line 980 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_RAISE, 0, 0, 0); - yygotominor.yy178->iColumn = OE_Ignore; - sqlite3ExprSpan(yygotominor.yy178, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0); -} -#line 2981 "parse.c" - break; - case 275: -#line 985 "parse.y" -{ - yygotominor.yy178 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy384); - yygotominor.yy178->iColumn = yymsp[-3].minor.yy230; - sqlite3ExprSpan(yygotominor.yy178, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); -} -#line 2990 "parse.c" - break; - case 276: -#line 993 "parse.y" -{yygotominor.yy230 = OE_Rollback;} -#line 2995 "parse.c" - break; - case 278: -#line 995 "parse.y" -{yygotominor.yy230 = OE_Fail;} -#line 3000 "parse.c" - break; - case 279: -#line 1000 "parse.y" -{ - sqlite3DropTrigger(pParse,yymsp[0].minor.yy285); -} -#line 3007 "parse.c" - break; - case 280: -#line 1006 "parse.y" -{ - sqlite3Attach(pParse, yymsp[-3].minor.yy178, yymsp[-1].minor.yy178, yymsp[0].minor.yy292); -} -#line 3014 "parse.c" - break; - case 281: -#line 1011 "parse.y" -{ yygotominor.yy292 = 0; } -#line 3019 "parse.c" - break; - case 282: -#line 1012 "parse.y" -{ yygotominor.yy292 = yymsp[0].minor.yy178; } -#line 3024 "parse.c" - break; - case 285: -#line 1018 "parse.y" -{ - sqlite3Detach(pParse, yymsp[0].minor.yy178); -} -#line 3031 "parse.c" - break; - case 286: -#line 1024 "parse.y" -{sqlite3Reindex(pParse, 0, 0);} -#line 3036 "parse.c" - break; - case 287: -#line 1025 "parse.y" -{sqlite3Reindex(pParse, &yymsp[-1].minor.yy384, &yymsp[0].minor.yy384);} -#line 3041 "parse.c" - break; - case 288: -#line 1030 "parse.y" -{sqlite3Analyze(pParse, 0, 0);} -#line 3046 "parse.c" - break; - case 289: -#line 1031 "parse.y" -{sqlite3Analyze(pParse, &yymsp[-1].minor.yy384, &yymsp[0].minor.yy384);} -#line 3051 "parse.c" - break; - case 290: -#line 1036 "parse.y" -{ - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy285,&yymsp[0].minor.yy384); -} -#line 3058 "parse.c" - break; - case 291: -#line 1039 "parse.y" -{ - sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy384); -} -#line 3065 "parse.c" - break; - case 292: -#line 1042 "parse.y" -{ - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy285); -} -#line 3072 "parse.c" + case 198: + case 199: + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: +#line 624 "parse.y" +{yygotominor.yy454 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy454, yymsp[0].minor.yy454, 0);} +#line 2639 "parse.c" + break; + case 207: +#line 643 "parse.y" +{yygotominor.yy258.opcode = TK_LIKE; yygotominor.yy258.not = 0;} +#line 2644 "parse.c" + break; + case 208: +#line 644 "parse.y" +{yygotominor.yy258.opcode = TK_GLOB; yygotominor.yy258.not = 0;} +#line 2649 "parse.c" + break; + case 209: +#line 645 "parse.y" +{yygotominor.yy258.opcode = TK_LIKE; yygotominor.yy258.not = 1;} +#line 2654 "parse.c" + break; + case 210: +#line 646 "parse.y" +{yygotominor.yy258.opcode = TK_GLOB; yygotominor.yy258.not = 1;} +#line 2659 "parse.c" + break; + case 213: +#line 650 "parse.y" +{ + ExprList *pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy454, 0); + pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy454, 0); + if( yymsp[0].minor.yy454 ){ + pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy454, 0); + } + yygotominor.yy454 = sqlite3ExprFunction(pList, 0); + if( yygotominor.yy454 ) yygotominor.yy454->op = yymsp[-2].minor.yy258.opcode; + if( yymsp[-2].minor.yy258.not ) yygotominor.yy454 = sqlite3Expr(TK_NOT, yygotominor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454, &yymsp[-3].minor.yy454->span, &yymsp[-1].minor.yy454->span); +} +#line 2674 "parse.c" + break; + case 214: +#line 662 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_ISNULL, yymsp[-1].minor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-1].minor.yy454->span,&yymsp[0].minor.yy0); +} +#line 2682 "parse.c" + break; + case 215: +#line 666 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-2].minor.yy454->span,&yymsp[0].minor.yy0); +} +#line 2690 "parse.c" + break; + case 216: +#line 670 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_NOTNULL, yymsp[-1].minor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-1].minor.yy454->span,&yymsp[0].minor.yy0); +} +#line 2698 "parse.c" + break; + case 217: +#line 674 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-2].minor.yy454->span,&yymsp[0].minor.yy0); +} +#line 2706 "parse.c" + break; + case 218: +#line 678 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-3].minor.yy454->span,&yymsp[0].minor.yy0); +} +#line 2714 "parse.c" + break; + case 219: + case 220: +#line 682 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy454->span); +} +#line 2723 "parse.c" + break; + case 221: +#line 690 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy454->span); +} +#line 2731 "parse.c" + break; + case 222: +#line 694 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy454->span); +} +#line 2739 "parse.c" + break; + case 225: +#line 701 "parse.y" +{ + ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy454, 0); + pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy454, 0); + yygotominor.yy454 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy454, 0, 0); + if( yygotominor.yy454 ) yygotominor.yy454->pList = pList; + if( yymsp[-3].minor.yy60 ) yygotominor.yy454 = sqlite3Expr(TK_NOT, yygotominor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-4].minor.yy454->span,&yymsp[0].minor.yy454->span); +} +#line 2751 "parse.c" + break; + case 228: +#line 713 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy454, 0, 0); + if( yygotominor.yy454 ) yygotominor.yy454->pList = yymsp[-1].minor.yy266; + if( yymsp[-3].minor.yy60 ) yygotominor.yy454 = sqlite3Expr(TK_NOT, yygotominor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-4].minor.yy454->span,&yymsp[0].minor.yy0); + } +#line 2761 "parse.c" + break; + case 229: +#line 719 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_SELECT, 0, 0, 0); + if( yygotominor.yy454 ) yygotominor.yy454->pSelect = yymsp[-1].minor.yy331; + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + } +#line 2770 "parse.c" + break; + case 230: +#line 724 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy454, 0, 0); + if( yygotominor.yy454 ) yygotominor.yy454->pSelect = yymsp[-1].minor.yy331; + if( yymsp[-3].minor.yy60 ) yygotominor.yy454 = sqlite3Expr(TK_NOT, yygotominor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-4].minor.yy454->span,&yymsp[0].minor.yy0); + } +#line 2780 "parse.c" + break; + case 231: +#line 730 "parse.y" +{ + SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy406,&yymsp[0].minor.yy406); + yygotominor.yy454 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy454, 0, 0); + if( yygotominor.yy454 ) yygotominor.yy454->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0); + if( yymsp[-2].minor.yy60 ) yygotominor.yy454 = sqlite3Expr(TK_NOT, yygotominor.yy454, 0, 0); + sqlite3ExprSpan(yygotominor.yy454,&yymsp[-3].minor.yy454->span,yymsp[0].minor.yy406.z?&yymsp[0].minor.yy406:&yymsp[-1].minor.yy406); + } +#line 2791 "parse.c" + break; + case 232: +#line 737 "parse.y" +{ + Expr *p = yygotominor.yy454 = sqlite3Expr(TK_EXISTS, 0, 0, 0); + if( p ){ + p->pSelect = yymsp[-1].minor.yy331; + sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); + } + } +#line 2802 "parse.c" + break; + case 233: +#line 747 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, 0); + if( yygotominor.yy454 ) yygotominor.yy454->pList = yymsp[-2].minor.yy266; + sqlite3ExprSpan(yygotominor.yy454, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); +} +#line 2811 "parse.c" + break; + case 234: +#line 754 "parse.y" +{ + yygotominor.yy266 = sqlite3ExprListAppend(yymsp[-4].minor.yy266, yymsp[-2].minor.yy454, 0); + yygotominor.yy266 = sqlite3ExprListAppend(yygotominor.yy266, yymsp[0].minor.yy454, 0); +} +#line 2819 "parse.c" + break; + case 235: +#line 758 "parse.y" +{ + yygotominor.yy266 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy454, 0); + yygotominor.yy266 = sqlite3ExprListAppend(yygotominor.yy266, yymsp[0].minor.yy454, 0); +} +#line 2827 "parse.c" + break; + case 244: +#line 783 "parse.y" +{ + if( yymsp[-9].minor.yy60!=OE_None ) yymsp[-9].minor.yy60 = yymsp[0].minor.yy60; + if( yymsp[-9].minor.yy60==OE_Default) yymsp[-9].minor.yy60 = OE_Abort; + sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy406, &yymsp[-6].minor.yy406, sqlite3SrcListAppend(0,&yymsp[-4].minor.yy406,0),yymsp[-2].minor.yy266,yymsp[-9].minor.yy60, &yymsp[-10].minor.yy0, &yymsp[-1].minor.yy0); +} +#line 2836 "parse.c" + break; + case 245: + case 292: +#line 790 "parse.y" +{yygotominor.yy60 = OE_Abort;} +#line 2842 "parse.c" + break; + case 246: +#line 791 "parse.y" +{yygotominor.yy60 = OE_None;} +#line 2847 "parse.c" + break; + case 249: +#line 801 "parse.y" +{ + Expr *p = 0; + if( yymsp[-1].minor.yy406.n>0 ){ + p = sqlite3Expr(TK_COLUMN, 0, 0, 0); + if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy406.z, yymsp[-1].minor.yy406.n); + } + yygotominor.yy266 = sqlite3ExprListAppend(yymsp[-4].minor.yy266, p, &yymsp[-2].minor.yy406); +} +#line 2859 "parse.c" + break; + case 250: +#line 809 "parse.y" +{ + Expr *p = 0; + if( yymsp[-1].minor.yy406.n>0 ){ + p = sqlite3Expr(TK_COLUMN, 0, 0, 0); + if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy406.z, yymsp[-1].minor.yy406.n); + } + yygotominor.yy266 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy406); +} +#line 2871 "parse.c" + break; + case 252: +#line 822 "parse.y" +{sqlite3DropIndex(pParse, yymsp[0].minor.yy427);} +#line 2876 "parse.c" + break; + case 253: + case 254: +#line 826 "parse.y" +{sqlite3Vacuum(pParse,0);} +#line 2882 "parse.c" + break; + case 255: + case 257: +#line 832 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy406,&yymsp[-2].minor.yy406,&yymsp[0].minor.yy406,0);} +#line 2888 "parse.c" + break; + case 256: +#line 833 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy406,&yymsp[-2].minor.yy406,&yymsp[0].minor.yy0,0);} +#line 2893 "parse.c" + break; + case 258: +#line 835 "parse.y" +{ + sqlite3Pragma(pParse,&yymsp[-3].minor.yy406,&yymsp[-2].minor.yy406,&yymsp[0].minor.yy406,1); +} +#line 2900 "parse.c" + break; + case 259: +#line 838 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-4].minor.yy406,&yymsp[-3].minor.yy406,&yymsp[-1].minor.yy406,0);} +#line 2905 "parse.c" + break; + case 260: +#line 839 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-1].minor.yy406,&yymsp[0].minor.yy406,0,0);} +#line 2910 "parse.c" + break; + case 267: +#line 852 "parse.y" +{ + Token all; + all.z = yymsp[-3].minor.yy406.z; + all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy406.z) + yymsp[0].minor.yy0.n; + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy455, &all); +} +#line 2920 "parse.c" + break; + case 268: +#line 861 "parse.y" +{ + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy406, &yymsp[-6].minor.yy406, yymsp[-5].minor.yy60, yymsp[-4].minor.yy62.a, yymsp[-4].minor.yy62.b, yymsp[-2].minor.yy427, yymsp[-1].minor.yy60, yymsp[0].minor.yy454, yymsp[-9].minor.yy60); + yygotominor.yy406 = (yymsp[-6].minor.yy406.n==0?yymsp[-7].minor.yy406:yymsp[-6].minor.yy406); +} +#line 2928 "parse.c" + break; + case 269: + case 272: +#line 867 "parse.y" +{ yygotominor.yy60 = TK_BEFORE; } +#line 2934 "parse.c" + break; + case 270: +#line 868 "parse.y" +{ yygotominor.yy60 = TK_AFTER; } +#line 2939 "parse.c" + break; + case 271: +#line 869 "parse.y" +{ yygotominor.yy60 = TK_INSTEAD;} +#line 2944 "parse.c" + break; + case 273: + case 274: + case 275: +#line 874 "parse.y" +{yygotominor.yy62.a = yymsp[0].major; yygotominor.yy62.b = 0;} +#line 2951 "parse.c" + break; + case 276: +#line 877 "parse.y" +{yygotominor.yy62.a = TK_UPDATE; yygotominor.yy62.b = yymsp[0].minor.yy272;} +#line 2956 "parse.c" + break; + case 277: + case 278: +#line 880 "parse.y" +{ yygotominor.yy60 = TK_ROW; } +#line 2962 "parse.c" + break; + case 279: +#line 882 "parse.y" +{ yygotominor.yy60 = TK_STATEMENT; } +#line 2967 "parse.c" + break; + case 280: +#line 885 "parse.y" +{ yygotominor.yy454 = 0; } +#line 2972 "parse.c" + break; + case 281: +#line 886 "parse.y" +{ yygotominor.yy454 = yymsp[0].minor.yy454; } +#line 2977 "parse.c" + break; + case 282: +#line 890 "parse.y" +{ + yymsp[-2].minor.yy455->pNext = yymsp[0].minor.yy455; + yygotominor.yy455 = yymsp[-2].minor.yy455; +} +#line 2985 "parse.c" + break; + case 283: +#line 894 "parse.y" +{ yygotominor.yy455 = 0; } +#line 2990 "parse.c" + break; + case 284: +#line 900 "parse.y" +{ yygotominor.yy455 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy406, yymsp[-1].minor.yy266, yymsp[0].minor.yy454, yymsp[-4].minor.yy60); } +#line 2995 "parse.c" + break; + case 285: +#line 905 "parse.y" +{yygotominor.yy455 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy406, yymsp[-4].minor.yy272, yymsp[-1].minor.yy266, 0, yymsp[-7].minor.yy60);} +#line 3000 "parse.c" + break; + case 286: +#line 908 "parse.y" +{yygotominor.yy455 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy406, yymsp[-1].minor.yy272, 0, yymsp[0].minor.yy331, yymsp[-4].minor.yy60);} +#line 3005 "parse.c" + break; + case 287: +#line 912 "parse.y" +{yygotominor.yy455 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy406, yymsp[0].minor.yy454);} +#line 3010 "parse.c" + break; + case 288: +#line 915 "parse.y" +{yygotominor.yy455 = sqlite3TriggerSelectStep(yymsp[0].minor.yy331); } +#line 3015 "parse.c" + break; + case 289: +#line 918 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_RAISE, 0, 0, 0); + yygotominor.yy454->iColumn = OE_Ignore; + sqlite3ExprSpan(yygotominor.yy454, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0); +} +#line 3024 "parse.c" + break; + case 290: +#line 923 "parse.y" +{ + yygotominor.yy454 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy406); + yygotominor.yy454->iColumn = yymsp[-3].minor.yy60; + sqlite3ExprSpan(yygotominor.yy454, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); +} +#line 3033 "parse.c" + break; + case 291: +#line 931 "parse.y" +{yygotominor.yy60 = OE_Rollback;} +#line 3038 "parse.c" + break; + case 293: +#line 933 "parse.y" +{yygotominor.yy60 = OE_Fail;} +#line 3043 "parse.c" + break; + case 294: +#line 938 "parse.y" +{ + sqlite3DropTrigger(pParse,yymsp[0].minor.yy427); +} +#line 3050 "parse.c" + break; + case 295: +#line 944 "parse.y" +{ + sqlite3Attach(pParse, &yymsp[-3].minor.yy406, &yymsp[-1].minor.yy406, yymsp[0].minor.yy40.type, &yymsp[0].minor.yy40.key); +} +#line 3057 "parse.c" + break; + case 296: +#line 948 "parse.y" +{ yygotominor.yy40.type = 0; } +#line 3062 "parse.c" + break; + case 297: +#line 949 "parse.y" +{ yygotominor.yy40.type=1; yygotominor.yy40.key = yymsp[0].minor.yy406; } +#line 3067 "parse.c" + break; + case 298: +#line 950 "parse.y" +{ yygotominor.yy40.type=2; yygotominor.yy40.key = yymsp[0].minor.yy0; } +#line 3072 "parse.c" + break; + case 301: +#line 956 "parse.y" +{ + sqlite3Detach(pParse, &yymsp[0].minor.yy406); +} +#line 3079 "parse.c" + break; + case 302: +#line 962 "parse.y" +{sqlite3Reindex(pParse, 0, 0);} +#line 3084 "parse.c" + break; + case 303: +#line 963 "parse.y" +{sqlite3Reindex(pParse, &yymsp[-1].minor.yy406, &yymsp[0].minor.yy406);} +#line 3089 "parse.c" + break; + case 304: +#line 968 "parse.y" +{ + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy427,&yymsp[0].minor.yy406); +} +#line 3096 "parse.c" break; }; yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; @@ -3122,20 +3146,20 @@ int yymajor, /* The major type of the error token */ YYMINORTYPE yyminor /* The minor type of the error token */ ){ sqlite3ParserARG_FETCH; #define TOKEN (yyminor.yy0) -#line 34 "parse.y" +#line 23 "parse.y" if( pParse->zErrMsg==0 ){ if( TOKEN.z[0] ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); }else{ sqlite3ErrorMsg(pParse, "incomplete SQL statement"); } } -#line 3139 "parse.c" +#line 3163 "parse.c" sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ } /* ** The following is executed when the parser accepts @@ -3187,11 +3211,11 @@ yyParser *yypParser; /* The parser */ /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; if( yypParser->yyidx<0 ){ - /* if( yymajor==0 ) return; // not sure why this was here... */ + if( yymajor==0 ) return; yypParser->yyidx = 0; yypParser->yyerrcnt = -1; yypParser->yystack[0].stateno = 0; yypParser->yystack[0].major = 0; } Index: SQLite.Interop/src/parse.h ================================================================== --- SQLite.Interop/src/parse.h +++ SQLite.Interop/src/parse.h @@ -1,151 +1,140 @@ -#define TK_SEMI 1 -#define TK_EXPLAIN 2 -#define TK_QUERY 3 -#define TK_PLAN 4 -#define TK_BEGIN 5 -#define TK_TRANSACTION 6 -#define TK_DEFERRED 7 -#define TK_IMMEDIATE 8 -#define TK_EXCLUSIVE 9 -#define TK_COMMIT 10 -#define TK_END 11 -#define TK_ROLLBACK 12 -#define TK_CREATE 13 -#define TK_TABLE 14 -#define TK_IF 15 -#define TK_NOT 16 -#define TK_EXISTS 17 -#define TK_TEMP 18 -#define TK_LP 19 -#define TK_RP 20 -#define TK_AS 21 -#define TK_COMMA 22 -#define TK_ID 23 -#define TK_ABORT 24 -#define TK_AFTER 25 -#define TK_ANALYZE 26 -#define TK_ASC 27 -#define TK_ATTACH 28 -#define TK_BEFORE 29 -#define TK_CASCADE 30 -#define TK_CAST 31 -#define TK_CONFLICT 32 -#define TK_DATABASE 33 -#define TK_DESC 34 -#define TK_DETACH 35 -#define TK_EACH 36 -#define TK_FAIL 37 -#define TK_FOR 38 -#define TK_IGNORE 39 -#define TK_INITIALLY 40 -#define TK_INSTEAD 41 -#define TK_LIKE_KW 42 -#define TK_MATCH 43 -#define TK_KEY 44 -#define TK_OF 45 -#define TK_OFFSET 46 -#define TK_PRAGMA 47 -#define TK_RAISE 48 -#define TK_REPLACE 49 -#define TK_RESTRICT 50 -#define TK_ROW 51 -#define TK_STATEMENT 52 -#define TK_TRIGGER 53 -#define TK_VACUUM 54 -#define TK_VIEW 55 -#define TK_REINDEX 56 -#define TK_RENAME 57 -#define TK_CTIME_KW 58 -#define TK_OR 59 -#define TK_AND 60 -#define TK_IS 61 -#define TK_BETWEEN 62 -#define TK_IN 63 -#define TK_ISNULL 64 -#define TK_NOTNULL 65 -#define TK_NE 66 -#define TK_EQ 67 -#define TK_GT 68 -#define TK_LE 69 -#define TK_LT 70 -#define TK_GE 71 -#define TK_ESCAPE 72 -#define TK_BITAND 73 -#define TK_BITOR 74 -#define TK_LSHIFT 75 -#define TK_RSHIFT 76 -#define TK_PLUS 77 -#define TK_MINUS 78 -#define TK_STAR 79 -#define TK_SLASH 80 -#define TK_REM 81 -#define TK_CONCAT 82 -#define TK_UMINUS 83 -#define TK_UPLUS 84 -#define TK_BITNOT 85 -#define TK_STRING 86 -#define TK_JOIN_KW 87 -#define TK_CONSTRAINT 88 -#define TK_DEFAULT 89 -#define TK_NULL 90 -#define TK_PRIMARY 91 -#define TK_UNIQUE 92 -#define TK_CHECK 93 -#define TK_REFERENCES 94 -#define TK_COLLATE 95 -#define TK_AUTOINCR 96 -#define TK_ON 97 -#define TK_DELETE 98 -#define TK_UPDATE 99 -#define TK_INSERT 100 -#define TK_SET 101 -#define TK_DEFERRABLE 102 -#define TK_FOREIGN 103 -#define TK_DROP 104 -#define TK_UNION 105 -#define TK_ALL 106 -#define TK_EXCEPT 107 -#define TK_INTERSECT 108 -#define TK_SELECT 109 -#define TK_DISTINCT 110 -#define TK_DOT 111 -#define TK_FROM 112 -#define TK_JOIN 113 -#define TK_USING 114 -#define TK_ORDER 115 -#define TK_BY 116 -#define TK_GROUP 117 -#define TK_HAVING 118 -#define TK_LIMIT 119 -#define TK_WHERE 120 -#define TK_INTO 121 -#define TK_VALUES 122 -#define TK_INTEGER 123 -#define TK_FLOAT 124 -#define TK_BLOB 125 -#define TK_REGISTER 126 -#define TK_VARIABLE 127 -#define TK_CASE 128 -#define TK_WHEN 129 -#define TK_THEN 130 -#define TK_ELSE 131 -#define TK_INDEX 132 -#define TK_ALTER 133 -#define TK_TO 134 -#define TK_ADD 135 -#define TK_COLUMNKW 136 -#define TK_TO_TEXT 137 -#define TK_TO_BLOB 138 -#define TK_TO_NUMERIC 139 -#define TK_TO_INT 140 -#define TK_TO_REAL 141 -#define TK_END_OF_FILE 142 -#define TK_ILLEGAL 143 -#define TK_SPACE 144 -#define TK_UNCLOSED_STRING 145 -#define TK_COMMENT 146 -#define TK_FUNCTION 147 -#define TK_COLUMN 148 -#define TK_AGG_FUNCTION 149 -#define TK_AGG_COLUMN 150 -#define TK_CONST_FUNC 151 +#define TK_END_OF_FILE 1 +#define TK_ILLEGAL 2 +#define TK_SPACE 3 +#define TK_UNCLOSED_STRING 4 +#define TK_COMMENT 5 +#define TK_FUNCTION 6 +#define TK_COLUMN 7 +#define TK_AGG_FUNCTION 8 +#define TK_SEMI 9 +#define TK_EXPLAIN 10 +#define TK_BEGIN 11 +#define TK_TRANSACTION 12 +#define TK_DEFERRED 13 +#define TK_IMMEDIATE 14 +#define TK_EXCLUSIVE 15 +#define TK_COMMIT 16 +#define TK_END 17 +#define TK_ROLLBACK 18 +#define TK_CREATE 19 +#define TK_TABLE 20 +#define TK_TEMP 21 +#define TK_LP 22 +#define TK_RP 23 +#define TK_AS 24 +#define TK_COMMA 25 +#define TK_ID 26 +#define TK_ABORT 27 +#define TK_AFTER 28 +#define TK_ASC 29 +#define TK_ATTACH 30 +#define TK_BEFORE 31 +#define TK_CASCADE 32 +#define TK_CONFLICT 33 +#define TK_DATABASE 34 +#define TK_DESC 35 +#define TK_DETACH 36 +#define TK_EACH 37 +#define TK_FAIL 38 +#define TK_FOR 39 +#define TK_GLOB 40 +#define TK_IGNORE 41 +#define TK_INITIALLY 42 +#define TK_INSTEAD 43 +#define TK_LIKE 44 +#define TK_MATCH 45 +#define TK_KEY 46 +#define TK_OF 47 +#define TK_OFFSET 48 +#define TK_PRAGMA 49 +#define TK_RAISE 50 +#define TK_REPLACE 51 +#define TK_RESTRICT 52 +#define TK_ROW 53 +#define TK_STATEMENT 54 +#define TK_TRIGGER 55 +#define TK_VACUUM 56 +#define TK_VIEW 57 +#define TK_REINDEX 58 +#define TK_RENAME 59 +#define TK_CDATE 60 +#define TK_CTIME 61 +#define TK_CTIMESTAMP 62 +#define TK_ALTER 63 +#define TK_OR 64 +#define TK_AND 65 +#define TK_NOT 66 +#define TK_IS 67 +#define TK_BETWEEN 68 +#define TK_IN 69 +#define TK_ISNULL 70 +#define TK_NOTNULL 71 +#define TK_NE 72 +#define TK_EQ 73 +#define TK_GT 74 +#define TK_LE 75 +#define TK_LT 76 +#define TK_GE 77 +#define TK_ESCAPE 78 +#define TK_BITAND 79 +#define TK_BITOR 80 +#define TK_LSHIFT 81 +#define TK_RSHIFT 82 +#define TK_PLUS 83 +#define TK_MINUS 84 +#define TK_STAR 85 +#define TK_SLASH 86 +#define TK_REM 87 +#define TK_CONCAT 88 +#define TK_UMINUS 89 +#define TK_UPLUS 90 +#define TK_BITNOT 91 +#define TK_STRING 92 +#define TK_JOIN_KW 93 +#define TK_CONSTRAINT 94 +#define TK_DEFAULT 95 +#define TK_NULL 96 +#define TK_PRIMARY 97 +#define TK_UNIQUE 98 +#define TK_CHECK 99 +#define TK_REFERENCES 100 +#define TK_COLLATE 101 +#define TK_AUTOINCR 102 +#define TK_ON 103 +#define TK_DELETE 104 +#define TK_UPDATE 105 +#define TK_INSERT 106 +#define TK_SET 107 +#define TK_DEFERRABLE 108 +#define TK_FOREIGN 109 +#define TK_DROP 110 +#define TK_UNION 111 +#define TK_ALL 112 +#define TK_INTERSECT 113 +#define TK_EXCEPT 114 +#define TK_SELECT 115 +#define TK_DISTINCT 116 +#define TK_DOT 117 +#define TK_FROM 118 +#define TK_JOIN 119 +#define TK_USING 120 +#define TK_ORDER 121 +#define TK_BY 122 +#define TK_GROUP 123 +#define TK_HAVING 124 +#define TK_LIMIT 125 +#define TK_WHERE 126 +#define TK_INTO 127 +#define TK_VALUES 128 +#define TK_INTEGER 129 +#define TK_FLOAT 130 +#define TK_BLOB 131 +#define TK_REGISTER 132 +#define TK_VARIABLE 133 +#define TK_EXISTS 134 +#define TK_CASE 135 +#define TK_WHEN 136 +#define TK_THEN 137 +#define TK_ELSE 138 +#define TK_INDEX 139 +#define TK_TO 140 Index: SQLite.Interop/src/pragma.c ================================================================== --- SQLite.Interop/src/pragma.c +++ SQLite.Interop/src/pragma.c @@ -9,19 +9,19 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: pragma.c,v 1.1 2005/03/01 16:04:34 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include /* Ignore this whole file if pragmas are disabled */ -#if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER) +#ifndef SQLITE_OMIT_PRAGMA #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) # include "pager.h" # include "btree.h" #endif @@ -34,11 +34,11 @@ ** Note that the values returned are one less that the values that ** should be passed into sqlite3BtreeSetSafetyLevel(). The is done ** to support legacy SQL code. The safety level used to be boolean ** and older scripts may have used numbers 0 for OFF and 1 for ON. */ -static int getSafetyLevel(const char *z){ +static int getSafetyLevel(const u8 *z){ /* 123456789 123456789 */ static const char zText[] = "onoffalseyestruefull"; static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16}; static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4}; static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2}; @@ -56,11 +56,11 @@ } /* ** Interpret the given string as a boolean value. */ -static int getBoolean(const char *z){ +static int getBoolean(const u8 *z){ return getSafetyLevel(z)&1; } #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* @@ -77,13 +77,11 @@ return 2; }else{ return 0; } } -#endif /* SQLITE_PAGER_PRAGMAS */ -#ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Invalidate temp storage, either when the temp storage is changed ** from default, or when 'file' and the temp_store_directory has changed */ static int invalidateTempStorage(Parse *pParse){ @@ -98,13 +96,11 @@ db->aDb[1].pBt = 0; sqlite3ResetInternalSchema(db, 0); } return SQLITE_OK; } -#endif /* SQLITE_PAGER_PRAGMAS */ -#ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** If the TEMP database is open, close it and mark the database schema ** as needing reloading. This must be done when using the TEMP_STORE ** or DEFAULT_TEMP_STORE pragmas. */ @@ -116,11 +112,11 @@ return SQLITE_ERROR; } db->temp_store = ts; return SQLITE_OK; } -#endif /* SQLITE_PAGER_PRAGMAS */ +#endif /* ** Generate code to return a single integer value. */ static void returnSingleInt(Parse *pParse, const char *zLabel, int value){ @@ -131,11 +127,10 @@ sqlite3VdbeSetColName(v, 0, zLabel, P3_STATIC); } sqlite3VdbeAddOp(v, OP_Callback, 1, 0); } -#ifndef SQLITE_OMIT_FLAG_PRAGMAS /* ** Check to see if zRight and zLeft refer to a pragma that queries ** or changes one of the flags in db->flags. Return 1 if so and 0 if not. ** Also, implement the pragma. */ @@ -149,21 +144,13 @@ { "vdbe_listing", SQLITE_VdbeListing }, { "full_column_names", SQLITE_FullColNames }, { "short_column_names", SQLITE_ShortColNames }, { "count_changes", SQLITE_CountRows }, { "empty_result_callbacks", SQLITE_NullCallback }, - { "legacy_file_format", SQLITE_LegacyFileFmt }, -#ifndef SQLITE_OMIT_CHECK - { "ignore_check_constraints", SQLITE_IgnoreChecks }, -#endif /* The following is VERY experimental */ { "writable_schema", SQLITE_WriteSchema }, { "omit_readlock", SQLITE_NoReadlock }, - - /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted - ** flag if there are any active statements. */ - { "read_uncommitted", SQLITE_ReadUncommitted }, }; int i; const struct sPragmaType *p; for(i=0, p=aPragma; izName)==0 ){ @@ -188,11 +175,10 @@ return 1; } } return 0; } -#endif /* SQLITE_OMIT_FLAG_PRAGMAS */ /* ** Process a pragma statement. ** ** Pragmas are of this form: @@ -286,12 +272,12 @@ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2); addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3); sqlite3VdbeAddOp(v, OP_Negative, 0, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2); - pDb->pSchema->cache_size = size; - sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); + pDb->cache_size = size; + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size); } }else /* ** PRAGMA [database.]page_size @@ -348,16 +334,16 @@ ** N should be a positive integer. */ if( sqlite3StrICmp(zLeft,"cache_size")==0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( !zRight ){ - returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size); + returnSingleInt(pParse, "cache_size", pDb->cache_size); }else{ int size = atoi(zRight); if( size<0 ) size = -size; - pDb->pSchema->cache_size = size; - sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); + pDb->cache_size = size; + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size); } }else /* ** PRAGMA temp_store @@ -440,16 +426,14 @@ } } }else #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ -#ifndef SQLITE_OMIT_FLAG_PRAGMAS if( flagPragma(pParse, zLeft, zRight) ){ /* The flagPragma() subroutine also generates any necessary code ** there is nothing more to do here */ }else -#endif /* SQLITE_OMIT_FLAG_PRAGMAS */ #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS /* ** PRAGMA table_info() ** @@ -589,17 +573,16 @@ sqlite3VdbeSetColName(v, 3, "from", P3_STATIC); sqlite3VdbeSetColName(v, 4, "to", P3_STATIC); while(pFK){ int j; for(j=0; jnCol; j++){ - char *zCol = pFK->aCol[j].zCol; sqlite3VdbeAddOp(v, OP_Integer, i, 0); sqlite3VdbeAddOp(v, OP_Integer, j, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[pFK->aCol[j].iFrom].zName, 0); - sqlite3VdbeOp3(v, zCol ? OP_String8 : OP_Null, 0, 0, zCol, 0); + sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->aCol[j].zCol, 0); sqlite3VdbeAddOp(v, OP_Callback, 5, 0); } ++i; pFK = pFK->pNextFrom; } @@ -609,32 +592,29 @@ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef NDEBUG if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ extern void sqlite3ParserTrace(FILE*, char *); - if( zRight ){ - if( getBoolean(zRight) ){ - sqlite3ParserTrace(stderr, "parser: "); - }else{ - sqlite3ParserTrace(0, 0); - } + if( getBoolean(zRight) ){ + sqlite3ParserTrace(stdout, "parser: "); + }else{ + sqlite3ParserTrace(0, 0); } }else #endif - /* Reinstall the LIKE and GLOB functions. The variant of LIKE - ** used will be case sensitive or not depending on the RHS. - */ - if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){ - if( zRight ){ - sqlite3RegisterLikeFunctions(db, getBoolean(zRight)); - } - }else - #ifndef SQLITE_OMIT_INTEGRITY_CHECK if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){ int i, j, addr; + + /* Code that initializes the integrity check program. Set the + ** error count 0 + */ + static const VdbeOpList initCode[] = { + { OP_Integer, 0, 0, 0}, + { OP_MemStore, 0, 1, 0}, + }; /* Code that appears at the end of the integrity check. If no error ** messages have been generated, output OK. Otherwise output the ** error message */ @@ -648,108 +628,106 @@ /* Initialize the VDBE program */ if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC); - sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */ + sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode); /* Do an integrity check on each database file */ for(i=0; inDb; i++){ HashElem *x; - Hash *pTbls; int cnt = 0; - if( OMIT_TEMPDB && i==1 ) continue; - sqlite3CodeVerifySchema(pParse, i); /* Do an integrity check of the B-Tree */ - pTbls = &db->aDb[i].pSchema->tblHash; - for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ + for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0); cnt++; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto pragma_out; sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0); cnt++; } } assert( cnt>0 ); sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i); sqlite3VdbeAddOp(v, OP_Dup, 0, 1); addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC); - sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7); + sqlite3VdbeAddOp(v, OP_Eq, 0, addr+6); sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName), P3_DYNAMIC); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Concat, 0, 1); sqlite3VdbeAddOp(v, OP_Callback, 1, 0); - sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); /* Make sure all the indices are constructed correctly. */ sqlite3CodeVerifySchema(pParse, i); - for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ + for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; int loopTop; if( pTab->pIndex==0 ) continue; sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); - sqlite3VdbeAddOp(v, OP_MemInt, 0, 1); + sqlite3VdbeAddOp(v, OP_Integer, 0, 0); + sqlite3VdbeAddOp(v, OP_MemStore, 1, 1); loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0); - sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2; static const VdbeOpList idxErr[] = { - { OP_MemIncr, 1, 0, 0}, + { OP_MemIncr, 0, 0, 0}, { OP_String8, 0, 0, "rowid "}, - { OP_Rowid, 1, 0, 0}, + { OP_Recno, 1, 0, 0}, { OP_String8, 0, 0, " missing from index "}, { OP_String8, 0, 0, 0}, /* 4 */ { OP_Concat, 2, 0, 0}, { OP_Callback, 1, 0, 0}, }; sqlite3GenerateIndexKey(v, pIdx, 1); jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0); addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr); sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC); - sqlite3VdbeJumpHere(v, jmp2); + sqlite3VdbeChangeP2(v, jmp2, sqlite3VdbeCurrentAddr(v)); } sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1); - sqlite3VdbeJumpHere(v, loopTop); + sqlite3VdbeChangeP2(v, loopTop, sqlite3VdbeCurrentAddr(v)); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ static const VdbeOpList cntIdx[] = { - { OP_MemInt, 0, 2, 0}, - { OP_Rewind, 0, 0, 0}, /* 1 */ - { OP_MemIncr, 1, 2, 0}, - { OP_Next, 0, 0, 0}, /* 3 */ + { OP_Integer, 0, 0, 0}, + { OP_MemStore, 2, 1, 0}, + { OP_Rewind, 0, 0, 0}, /* 2 */ + { OP_MemIncr, 2, 0, 0}, + { OP_Next, 0, 0, 0}, /* 4 */ { OP_MemLoad, 1, 0, 0}, { OP_MemLoad, 2, 0, 0}, - { OP_Eq, 0, 0, 0}, /* 6 */ - { OP_MemIncr, 1, 0, 0}, + { OP_Eq, 0, 0, 0}, /* 7 */ + { OP_MemIncr, 0, 0, 0}, { OP_String8, 0, 0, "wrong # of entries in index "}, - { OP_String8, 0, 0, 0}, /* 9 */ + { OP_String8, 0, 0, 0}, /* 10 */ { OP_Concat, 0, 0, 0}, { OP_Callback, 1, 0, 0}, }; if( pIdx->tnum==0 ) continue; addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx); - sqlite3VdbeChangeP1(v, addr+1, j+2); - sqlite3VdbeChangeP2(v, addr+1, addr+4); - sqlite3VdbeChangeP1(v, addr+3, j+2); - sqlite3VdbeChangeP2(v, addr+3, addr+2); - sqlite3VdbeJumpHere(v, addr+6); - sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC); + sqlite3VdbeChangeP1(v, addr+2, j+2); + sqlite3VdbeChangeP2(v, addr+2, addr+5); + sqlite3VdbeChangeP1(v, addr+4, j+2); + sqlite3VdbeChangeP2(v, addr+4, addr+3); + sqlite3VdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx)); + sqlite3VdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC); } } } addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); - sqlite3VdbeJumpHere(v, addr+2); + sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode)); }else #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_UTF16 /* @@ -795,11 +773,11 @@ if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC); sqlite3VdbeAddOp(v, OP_String8, 0, 0); for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ - if( pEnc->enc==ENC(pParse->db) ){ + if( pEnc->enc==pParse->db->enc ){ sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC); break; } } sqlite3VdbeAddOp(v, OP_Callback, 1, 0); @@ -807,17 +785,14 @@ /* Only change the value of sqlite.enc if the database handle is not ** initialized. If the main database exists, the new sqlite.enc value ** will be overwritten when the schema is next loaded. If it does not ** already exists, it will be created to use the new encoding value. */ - if( - !(DbHasProperty(db, 0, DB_SchemaLoaded)) || - DbHasProperty(db, 0, DB_Empty) - ){ + if( !(pParse->db->flags&SQLITE_Initialized) ){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ - ENC(pParse->db) = pEnc->enc; + pParse->db->enc = pEnc->enc; break; } } if( !pEnc->zName ){ sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight); @@ -904,41 +879,24 @@ sqlite3VdbeSetColName(v, 1, "status", P3_STATIC); for(i=0; inDb; i++){ Btree *pBt; Pager *pPager; if( db->aDb[i].zName==0 ) continue; - sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC); + sqlite3VdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, P3_STATIC); pBt = db->aDb[i].pBt; if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){ - sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC); + sqlite3VdbeOp3(v, OP_String, 0, 0, "closed", P3_STATIC); }else{ int j = sqlite3pager_lockstate(pPager); - sqlite3VdbeOp3(v, OP_String8, 0, 0, + sqlite3VdbeOp3(v, OP_String, 0, 0, (j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC); } sqlite3VdbeAddOp(v, OP_Callback, 2, 0); } }else #endif -#ifdef SQLITE_SSE - /* - ** Check to see if the sqlite_statements table exists. Create it - ** if it does not. - */ - if( sqlite3StrICmp(zLeft, "create_sqlite_statement_table")==0 ){ - extern int sqlite3CreateStatementsTable(Parse*); - sqlite3CreateStatementsTable(pParse); - }else -#endif - -#if SQLITE_HAS_CODEC - if( sqlite3StrICmp(zLeft, "key")==0 ){ - sqlite3_key(db, zRight, strlen(zRight)); - }else -#endif - {} if( v ){ /* Code an OP_Expire at the end of each PRAGMA program to cause ** the VDBE implementing the pragma to expire. Most (all?) pragmas @@ -949,6 +907,6 @@ pragma_out: sqliteFree(zLeft); sqliteFree(zRight); } -#endif /* SQLITE_OMIT_PRAGMA || SQLITE_OMIT_PARSER */ +#endif /* SQLITE_OMIT_PRAGMA */ DELETED SQLite.Interop/src/prepare.c Index: SQLite.Interop/src/prepare.c ================================================================== --- SQLite.Interop/src/prepare.c +++ /dev/null @@ -1,628 +0,0 @@ -/* -** 2005 May 25 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains the implementation of the sqlite3_prepare() -** interface, and routines that contribute to loading the database schema -** from disk. -** -** $Id: prepare.c,v 1.11 2006/01/16 15:51:47 rmsimpson Exp $ -*/ -#include "sqliteInt.h" -#include "os.h" -#include - -/* -** Fill the InitData structure with an error message that indicates -** that the database is corrupt. -*/ -static void corruptSchema(InitData *pData, const char *zExtra){ - if( !sqlite3ThreadDataReadOnly()->mallocFailed ){ - sqlite3SetString(pData->pzErrMsg, "malformed database schema", - zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); - } -} - -/* -** This is the callback routine for the code that initializes the -** database. See sqlite3Init() below for additional information. -** This routine is also called from the OP_ParseSchema opcode of the VDBE. -** -** Each callback contains the following information: -** -** argv[0] = name of thing being created -** argv[1] = root page number for table or index. NULL for trigger or view. -** argv[2] = SQL text for the CREATE statement. -** argv[3] = "1" for temporary files, "0" for main database, "2" or more -** for auxiliary database files. -** -*/ -int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ - InitData *pData = (InitData*)pInit; - sqlite3 *db = pData->db; - int iDb; - - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ - return SQLITE_NOMEM; - } - - assert( argc==4 ); - if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ - if( argv[1]==0 || argv[3]==0 ){ - corruptSchema(pData, 0); - return 1; - } - iDb = atoi(argv[3]); - assert( iDb>=0 && iDbnDb ); - if( argv[2] && argv[2][0] ){ - /* Call the parser to process a CREATE TABLE, INDEX or VIEW. - ** But because db->init.busy is set to 1, no VDBE code is generated - ** or executed. All the parser does is build the internal data - ** structures that describe the table, index, or view. - */ - char *zErr; - int rc; - assert( db->init.busy ); - db->init.iDb = iDb; - db->init.newTnum = atoi(argv[1]); - rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); - db->init.iDb = 0; - if( SQLITE_OK!=rc ){ - if( rc==SQLITE_NOMEM ){ - sqlite3ThreadData()->mallocFailed = 1; - }else{ - corruptSchema(pData, zErr); - } - sqlite3_free(zErr); - return rc; - } - }else{ - /* If the SQL column is blank it means this is an index that - ** was created to be the PRIMARY KEY or to fulfill a UNIQUE - ** constraint for a CREATE TABLE. The index should have already - ** been created when we processed the CREATE TABLE. All we have - ** to do here is record the root page number for that index. - */ - Index *pIndex; - pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName); - if( pIndex==0 || pIndex->tnum!=0 ){ - /* This can occur if there exists an index on a TEMP table which - ** has the same name as another index on a permanent index. Since - ** the permanent table is hidden by the TEMP table, we can also - ** safely ignore the index on the permanent table. - */ - /* Do Nothing */; - }else{ - pIndex->tnum = atoi(argv[1]); - } - } - return 0; -} - -/* -** Attempt to read the database schema and initialize internal -** data structures for a single database file. The index of the -** database file is given by iDb. iDb==0 is used for the main -** database. iDb==1 should never be used. iDb>=2 is used for -** auxiliary databases. Return one of the SQLITE_ error codes to -** indicate success or failure. -*/ -static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ - int rc; - BtCursor *curMain; - int size; - Table *pTab; - Db *pDb; - char const *azArg[5]; - char zDbNum[30]; - int meta[10]; - InitData initData; - char const *zMasterSchema; - char const *zMasterName = SCHEMA_TABLE(iDb); - - /* - ** The master database table has a structure like this - */ - static const char master_schema[] = - "CREATE TABLE sqlite_master(\n" - " type text,\n" - " name text,\n" - " tbl_name text,\n" - " rootpage integer,\n" - " sql text\n" - ")" - ; -#ifndef SQLITE_OMIT_TEMPDB - static const char temp_master_schema[] = - "CREATE TEMP TABLE sqlite_temp_master(\n" - " type text,\n" - " name text,\n" - " tbl_name text,\n" - " rootpage integer,\n" - " sql text\n" - ")" - ; -#else - #define temp_master_schema 0 -#endif - - assert( iDb>=0 && iDbnDb ); - assert( db->aDb[iDb].pSchema ); - - /* zMasterSchema and zInitScript are set to point at the master schema - ** and initialisation script appropriate for the database being - ** initialised. zMasterName is the name of the master table. - */ - if( !OMIT_TEMPDB && iDb==1 ){ - zMasterSchema = temp_master_schema; - }else{ - zMasterSchema = master_schema; - } - zMasterName = SCHEMA_TABLE(iDb); - - /* Construct the schema tables. */ - sqlite3SafetyOff(db); - azArg[0] = zMasterName; - azArg[1] = "1"; - azArg[2] = zMasterSchema; - sprintf(zDbNum, "%d", iDb); - azArg[3] = zDbNum; - azArg[4] = 0; - initData.db = db; - initData.pzErrMsg = pzErrMsg; - rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0); - if( rc!=SQLITE_OK ){ - sqlite3SafetyOn(db); - return rc; - } - pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); - if( pTab ){ - pTab->readOnly = 1; - } - sqlite3SafetyOn(db); - - /* Create a cursor to hold the database open - */ - pDb = &db->aDb[iDb]; - if( pDb->pBt==0 ){ - if( !OMIT_TEMPDB && iDb==1 ){ - DbSetProperty(db, 1, DB_SchemaLoaded); - } - return SQLITE_OK; - } - rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain); - if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ - sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); - return rc; - } - - /* Get the database meta information. - ** - ** Meta values are as follows: - ** meta[0] Schema cookie. Changes with each schema change. - ** meta[1] File format of schema layer. - ** meta[2] Size of the page cache. - ** meta[3] Use freelist if 0. Autovacuum if greater than zero. - ** meta[4] Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE - ** meta[5] The user cookie. Used by the application. - ** meta[6] - ** meta[7] - ** meta[8] - ** meta[9] - ** - ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to - ** the possible values of meta[4]. - */ - if( rc==SQLITE_OK ){ - int i; - for(i=0; rc==SQLITE_OK && ipBt, i+1, (u32 *)&meta[i]); - } - if( rc ){ - sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); - sqlite3BtreeCloseCursor(curMain); - return rc; - } - }else{ - memset(meta, 0, sizeof(meta)); - } - pDb->pSchema->schema_cookie = meta[0]; - - /* If opening a non-empty database, check the text encoding. For the - ** main database, set sqlite3.enc to the encoding of the main database. - ** For an attached db, it is an error if the encoding is not the same - ** as sqlite3.enc. - */ - if( meta[4] ){ /* text encoding */ - if( iDb==0 ){ - /* If opening the main database, set ENC(db). */ - ENC(db) = (u8)meta[4]; - db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0); - }else{ - /* If opening an attached database, the encoding much match ENC(db) */ - if( meta[4]!=ENC(db) ){ - sqlite3BtreeCloseCursor(curMain); - sqlite3SetString(pzErrMsg, "attached databases must use the same" - " text encoding as main database", (char*)0); - return SQLITE_ERROR; - } - } - }else{ - DbSetProperty(db, iDb, DB_Empty); - } - pDb->pSchema->enc = ENC(db); - - size = meta[2]; - if( size==0 ){ size = MAX_PAGES; } - pDb->pSchema->cache_size = size; - sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); - - /* - ** file_format==1 Version 3.0.0. - ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN - ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults - ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants - */ - pDb->pSchema->file_format = meta[1]; - if( pDb->pSchema->file_format==0 ){ - pDb->pSchema->file_format = 1; - } - if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ - sqlite3BtreeCloseCursor(curMain); - sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); - return SQLITE_ERROR; - } - - - /* Read the schema information out of the schema tables - */ - assert( db->init.busy ); - if( rc==SQLITE_EMPTY ){ - /* For an empty database, there is nothing to read */ - rc = SQLITE_OK; - }else{ - char *zSql; - zSql = sqlite3MPrintf( - "SELECT name, rootpage, sql, '%s' FROM '%q'.%s", - zDbNum, db->aDb[iDb].zName, zMasterName); - sqlite3SafetyOff(db); - rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); - sqlite3SafetyOn(db); - sqliteFree(zSql); -#ifndef SQLITE_OMIT_ANALYZE - if( rc==SQLITE_OK ){ - sqlite3AnalysisLoad(db, iDb); - } -#endif - sqlite3BtreeCloseCursor(curMain); - } - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ - sqlite3SetString(pzErrMsg, "out of memory", (char*)0); - rc = SQLITE_NOMEM; - sqlite3ResetInternalSchema(db, 0); - } - if( rc==SQLITE_OK ){ - DbSetProperty(db, iDb, DB_SchemaLoaded); - }else{ - sqlite3ResetInternalSchema(db, iDb); - } - return rc; -} - -/* -** Initialize all database files - the main database file, the file -** used to store temporary tables, and any additional database files -** created using ATTACH statements. Return a success code. If an -** error occurs, write an error message into *pzErrMsg. -** -** After a database is initialized, the DB_SchemaLoaded bit is set -** bit is set in the flags field of the Db structure. If the database -** file was of zero-length, then the DB_Empty flag is also set. -*/ -int sqlite3Init(sqlite3 *db, char **pzErrMsg){ - int i, rc; - int called_initone = 0; - - if( db->init.busy ) return SQLITE_OK; - rc = SQLITE_OK; - db->init.busy = 1; - for(i=0; rc==SQLITE_OK && inDb; i++){ - if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; - rc = sqlite3InitOne(db, i, pzErrMsg); - if( rc ){ - sqlite3ResetInternalSchema(db, i); - } - called_initone = 1; - } - - /* Once all the other databases have been initialised, load the schema - ** for the TEMP database. This is loaded last, as the TEMP database - ** schema may contain references to objects in other databases. - */ -#ifndef SQLITE_OMIT_TEMPDB - if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ - rc = sqlite3InitOne(db, 1, pzErrMsg); - if( rc ){ - sqlite3ResetInternalSchema(db, 1); - } - called_initone = 1; - } -#endif - - db->init.busy = 0; - if( rc==SQLITE_OK && called_initone ){ - sqlite3CommitInternalChanges(db); - } - - return rc; -} - -/* -** This routine is a no-op if the database schema is already initialised. -** Otherwise, the schema is loaded. An error code is returned. -*/ -int sqlite3ReadSchema(Parse *pParse){ - int rc = SQLITE_OK; - sqlite3 *db = pParse->db; - if( !db->init.busy ){ - rc = sqlite3Init(db, &pParse->zErrMsg); - } - if( rc!=SQLITE_OK ){ - pParse->rc = rc; - pParse->nErr++; - } - return rc; -} - - -/* -** Check schema cookies in all databases. If any cookie is out -** of date, return 0. If all schema cookies are current, return 1. -*/ -static int schemaIsValid(sqlite3 *db){ - int iDb; - int rc; - BtCursor *curTemp; - int cookie; - int allOk = 1; - - for(iDb=0; allOk && iDbnDb; iDb++){ - Btree *pBt; - pBt = db->aDb[iDb].pBt; - if( pBt==0 ) continue; - rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp); - if( rc==SQLITE_OK ){ - rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie); - if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){ - allOk = 0; - } - sqlite3BtreeCloseCursor(curTemp); - } - } - return allOk; -} - -/* -** Free all resources held by the schema structure. The void* argument points -** at a Schema struct. This function does not call sqliteFree() on the -** pointer itself, it just cleans up subsiduary resources (i.e. the contents -** of the schema hash tables). -*/ -void sqlite3SchemaFree(void *p){ - Hash temp1; - Hash temp2; - HashElem *pElem; - Schema *pSchema = (Schema *)p; - - temp1 = pSchema->tblHash; - temp2 = pSchema->trigHash; - sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0); - sqlite3HashClear(&pSchema->aFKey); - sqlite3HashClear(&pSchema->idxHash); - for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ - sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); - } - sqlite3HashClear(&temp2); - sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0); - for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ - Table *pTab = sqliteHashData(pElem); - sqlite3DeleteTable(0, pTab); - } - sqlite3HashClear(&temp1); - pSchema->pSeqTab = 0; - pSchema->flags &= ~DB_SchemaLoaded; -} - -Schema *sqlite3SchemaGet(Btree *pBt){ - Schema * p; - if( pBt ){ - p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree); - }else{ - p = (Schema *)sqliteMalloc(sizeof(Schema)); - } - if( p && 0==p->file_format ){ - sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1); - } - return p; -} - -int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ - int i = -1000000; - - /* If pSchema is NULL, then return -1000000. This happens when code in - ** expr.c is trying to resolve a reference to a transient table (i.e. one - ** created by a sub-select). In this case the return value of this - ** function should never be used. - ** - ** We return -1000000 instead of the more usual -1 simply because using - ** -1000000 as incorrectly using -1000000 index into db->aDb[] is much - ** more likely to cause a segfault than -1 (of course there are assert() - ** statements too, but it never hurts to play the odds). - */ - if( pSchema ){ - for(i=0; inDb; i++){ - if( db->aDb[i].pSchema==pSchema ){ - break; - } - } - assert( i>=0 &&i>=0 && inDb ); - } - return i; -} - -/* -** Compile the UTF-8 encoded SQL statement zSql into a statement handle. -*/ -int sqlite3_prepare( - sqlite3 *db, /* Database handle. */ - const char *zSql, /* UTF-8 encoded SQL statement. */ - int nBytes, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ - const char** pzTail /* OUT: End of parsed string */ -){ - Parse sParse; - char *zErrMsg = 0; - int rc = SQLITE_OK; - int i; - - /* Assert that malloc() has not failed */ - assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); - - assert( ppStmt ); - *ppStmt = 0; - if( sqlite3SafetyOn(db) ){ - return SQLITE_MISUSE; - } - - /* If any attached database schemas are locked, do not proceed with - ** compilation. Instead return SQLITE_LOCKED immediately. - */ - for(i=0; inDb; i++) { - Btree *pBt = db->aDb[i].pBt; - if( pBt && sqlite3BtreeSchemaLocked(pBt) ){ - const char *zDb = db->aDb[i].zName; - sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb); - sqlite3SafetyOff(db); - return SQLITE_LOCKED; - } - } - - memset(&sParse, 0, sizeof(sParse)); - sParse.db = db; - sParse.pTsd = sqlite3ThreadData(); - sParse.pTsd->nRef++; - sqlite3RunParser(&sParse, zSql, &zErrMsg); - - if( sParse.pTsd->mallocFailed ){ - sParse.rc = SQLITE_NOMEM; - } - if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; - if( sParse.checkSchema && !schemaIsValid(db) ){ - sParse.rc = SQLITE_SCHEMA; - } - if( sParse.rc==SQLITE_SCHEMA ){ - sqlite3ResetInternalSchema(db, 0); - } - if( pzTail ) *pzTail = sParse.zTail; - rc = sParse.rc; - -#ifndef SQLITE_OMIT_EXPLAIN - if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ - if( sParse.explain==2 ){ - sqlite3VdbeSetNumCols(sParse.pVdbe, 3); - sqlite3VdbeSetColName(sParse.pVdbe, 0, "order", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 1, "from", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 2, "detail", P3_STATIC); - }else{ - sqlite3VdbeSetNumCols(sParse.pVdbe, 5); - sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC); - } - } -#endif - - if( sqlite3SafetyOff(db) ){ - rc = SQLITE_MISUSE; - } - if( rc==SQLITE_OK ){ - *ppStmt = (sqlite3_stmt*)sParse.pVdbe; - }else if( sParse.pVdbe ){ - sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); - } - - if( zErrMsg ){ - sqlite3Error(db, rc, "%s", zErrMsg); - sqliteFree(zErrMsg); - }else{ - sqlite3Error(db, rc, 0); - } - - /* We must check for malloc failure last of all, in case malloc() failed - ** inside of the sqlite3Error() call above or something. - */ - if( sParse.pTsd->mallocFailed ){ - rc = SQLITE_NOMEM; - sqlite3Error(db, rc, 0); - } - - sParse.pTsd->nRef--; - sqlite3MallocClearFailed(); - sqlite3ReleaseThreadData(); - return rc; -} - -#ifndef SQLITE_OMIT_UTF16 -/* -** Compile the UTF-16 encoded SQL statement zSql into a statement handle. -*/ -int sqlite3_prepare16( - sqlite3 *db, /* Database handle. */ - const void *zSql, /* UTF-8 encoded SQL statement. */ - int nBytes, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ - const void **pzTail /* OUT: End of parsed string */ -){ - /* This function currently works by first transforming the UTF-16 - ** encoded string to UTF-8, then invoking sqlite3_prepare(). The - ** tricky bit is figuring out the pointer to return in *pzTail. - */ - char *zSql8 = 0; - const char *zTail8 = 0; - int rc; - - if( sqlite3SafetyCheck(db) ){ - return SQLITE_MISUSE; - } - zSql8 = sqlite3utf16to8(zSql, nBytes); - if( !zSql8 ){ - sqlite3Error(db, SQLITE_NOMEM, 0); - return SQLITE_NOMEM; - } - rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8); - - if( zTail8 && pzTail ){ - /* If sqlite3_prepare returns a tail pointer, we calculate the - ** equivalent pointer into the UTF-16 string by counting the unicode - ** characters between zSql8 and zTail8, and then returning a pointer - ** the same number of characters into the UTF-16 string. - */ - int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8); - *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed); - } - sqliteFree(zSql8); - return rc; -} -#endif /* SQLITE_OMIT_UTF16 */ Index: SQLite.Interop/src/printf.c ================================================================== --- SQLite.Interop/src/printf.c +++ SQLite.Interop/src/printf.c @@ -109,25 +109,23 @@ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; static const char aPrefix[] = "-x0\000X0"; static const et_info fmtinfo[] = { { 'd', 10, 1, etRADIX, 0, 0 }, { 's', 0, 4, etSTRING, 0, 0 }, - { 'g', 0, 1, etGENERIC, 30, 0 }, { 'z', 0, 6, etDYNSTRING, 0, 0 }, { 'q', 0, 4, etSQLESCAPE, 0, 0 }, { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, { 'c', 0, 0, etCHARX, 0, 0 }, { 'o', 8, 0, etRADIX, 0, 2 }, { 'u', 10, 0, etRADIX, 0, 0 }, { 'x', 16, 0, etRADIX, 16, 1 }, { 'X', 16, 0, etRADIX, 0, 4 }, -#ifndef SQLITE_OMIT_FLOATING_POINT { 'f', 0, 1, etFLOAT, 0, 0 }, { 'e', 0, 1, etEXP, 30, 0 }, { 'E', 0, 1, etEXP, 14, 0 }, + { 'g', 0, 1, etGENERIC, 30, 0 }, { 'G', 0, 1, etGENERIC, 14, 0 }, -#endif { 'i', 10, 1, etRADIX, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, { 'T', 0, 2, etTOKEN, 0, 0 }, @@ -134,14 +132,14 @@ { 'S', 0, 2, etSRCLIST, 0, 0 }, }; #define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0])) /* -** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point +** If NOFLOATINGPOINT is defined, then none of the floating point ** conversions will work. */ -#ifndef SQLITE_OMIT_FLOATING_POINT +#ifndef etNOFLOATINGPOINT /* ** "*val" is a double such that 0.1 <= *val < 10.0 ** Return the ascii code for the leading digit of *val, then ** multiply "*val" by 10.0 to renormalize. ** @@ -161,21 +159,13 @@ d = digit; digit += '0'; *val = (*val - d)*10.0; return digit; } -#endif /* SQLITE_OMIT_FLOATING_POINT */ - -/* -** On machines with a small stack size, you can redefine the -** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for -** smaller values some %f conversions may go into an infinite loop. -*/ -#ifndef SQLITE_PRINT_BUF_SIZE -# define SQLITE_PRINT_BUF_SIZE 350 #endif -#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ + +#define etBUFSIZE 1000 /* Size of the output buffer */ /* ** The root program. All variations call this core. ** ** INPUTS: @@ -218,15 +208,13 @@ int width; /* Width of the current field */ etByte flag_leftjustify; /* True if "-" flag is present */ etByte flag_plussign; /* True if "+" flag is present */ etByte flag_blanksign; /* True if " " flag is present */ etByte flag_alternateform; /* True if "#" flag is present */ - etByte flag_altform2; /* True if "!" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ - etByte done; /* Loop termination flag */ UINT64_TYPE longvalue; /* Value for integer types */ LONGDOUBLE_TYPE realvalue; /* Value for real types */ const et_info *infop; /* Pointer to the appropriate info structure */ char buf[etBUFSIZE]; /* Conversion buffer */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ @@ -234,12 +222,12 @@ etByte xtype; /* Conversion paradigm */ char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ static const char spaces[] = " "; #define etSPACESIZE (sizeof(spaces)-1) -#ifndef SQLITE_OMIT_FLOATING_POINT - int exp, e2; /* exponent of real numbers */ +#ifndef etNOFLOATINGPOINT + int exp; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ etByte flag_exp; /* True to force display of the exponent */ int nsd; /* Number of significant digits returned */ @@ -264,23 +252,21 @@ count++; break; } /* Find out what flags are present */ flag_leftjustify = flag_plussign = flag_blanksign = - flag_alternateform = flag_altform2 = flag_zeropad = 0; - done = 0; + flag_alternateform = flag_zeropad = 0; do{ switch( c ){ - case '-': flag_leftjustify = 1; break; - case '+': flag_plussign = 1; break; - case ' ': flag_blanksign = 1; break; - case '#': flag_alternateform = 1; break; - case '!': flag_altform2 = 1; break; - case '0': flag_zeropad = 1; break; - default: done = 1; break; - } - }while( !done && (c=(*++fmt))!=0 ); + case '-': flag_leftjustify = 1; c = 0; break; + case '+': flag_plussign = 1; c = 0; break; + case ' ': flag_blanksign = 1; c = 0; break; + case '#': flag_alternateform = 1; c = 0; break; + case '0': flag_zeropad = 1; c = 0; break; + default: break; + } + }while( c==0 && (c=(*++fmt))!=0 ); /* Get the field width */ width = 0; if( c=='*' ){ width = va_arg(ap,int); if( width<0 ){ @@ -348,11 +334,10 @@ /* ** At this point, variables are initialized as follows: ** ** flag_alternateform TRUE if a '#' is present. - ** flag_altform2 TRUE if a '!' is present. ** flag_plussign TRUE if a '+' is present. ** flag_leftjustify TRUE if a '-' is present or if the ** field width was negative. ** flag_zeropad TRUE if the width began with 0. ** flag_long TRUE if the letter 'l' (ell) prefixed @@ -425,34 +410,34 @@ break; case etFLOAT: case etEXP: case etGENERIC: realvalue = va_arg(ap,double); -#ifndef SQLITE_OMIT_FLOATING_POINT +#ifndef etNOFLOATINGPOINT if( precision<0 ) precision = 6; /* Set default precision */ - if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10; + if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10; if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; }else{ if( flag_plussign ) prefix = '+'; else if( flag_blanksign ) prefix = ' '; else prefix = 0; } - if( xtype==etGENERIC && precision>0 ) precision--; + if( infop->type==etGENERIC && precision>0 ) precision--; + rounder = 0.0; #if 0 /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); #else /* It makes more sense to use 0.5 */ for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1); #endif - if( xtype==etFLOAT ) realvalue += rounder; + if( infop->type==etFLOAT ) realvalue += rounder; /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; if( realvalue>0.0 ){ - while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; } while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; } while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; } if( exp>350 || exp<-350 ){ @@ -480,71 +465,55 @@ xtype = etFLOAT; } }else{ flag_rtz = 0; } - if( xtype==etEXP ){ - e2 = 0; - }else{ - e2 = exp; - } - nsd = 0; - flag_dp = (precision>0) | flag_alternateform | flag_altform2; - /* The sign in front of the number */ - if( prefix ){ - *(bufpt++) = prefix; - } - /* Digits prior to the decimal point */ - if( e2<0 ){ - *(bufpt++) = '0'; - }else{ - for(; e2>=0; e2--){ - *(bufpt++) = et_getdigit(&realvalue,&nsd); - } - } - /* The decimal point */ - if( flag_dp ){ - *(bufpt++) = '.'; - } - /* "0" digits after the decimal point but before the first - ** significant digit of the number */ - for(e2++; e2<0 && precision>0; precision--, e2++){ - *(bufpt++) = '0'; - } - /* Significant digits after the decimal point */ - while( (precision--)>0 ){ - *(bufpt++) = et_getdigit(&realvalue,&nsd); - } - /* Remove trailing zeros and the "." if no digits follow the "." */ - if( flag_rtz && flag_dp ){ - while( bufpt[-1]=='0' ) *(--bufpt) = 0; - assert( bufpt>buf ); - if( bufpt[-1]=='.' ){ - if( flag_altform2 ){ - *(bufpt++) = '0'; - }else{ - *(--bufpt) = 0; - } - } - } - /* Add the "eNNN" suffix */ - if( flag_exp || (xtype==etEXP && exp) ){ - *(bufpt++) = aDigits[infop->charset]; - if( exp<0 ){ - *(bufpt++) = '-'; exp = -exp; - }else{ - *(bufpt++) = '+'; - } - if( exp>=100 ){ - *(bufpt++) = (exp/100)+'0'; /* 100's digit */ - exp %= 100; - } - *(bufpt++) = exp/10+'0'; /* 10's digit */ - *(bufpt++) = exp%10+'0'; /* 1's digit */ - } - *bufpt = 0; - + /* + ** The "exp+precision" test causes output to be of type etEXP if + ** the precision is too large to fit in buf[]. + */ + nsd = 0; + if( xtype==etFLOAT && exp+precision0 || flag_alternateform); + if( prefix ) *(bufpt++) = prefix; /* Sign */ + if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */ + else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd); + if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */ + for(exp++; exp<0 && precision>0; precision--, exp++){ + *(bufpt++) = '0'; + } + while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd); + *(bufpt--) = 0; /* Null terminate */ + if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ + while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; + if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; + } + bufpt++; /* point to next free slot */ + }else{ /* etEXP or etGENERIC */ + flag_dp = (precision>0 || flag_alternateform); + if( prefix ) *(bufpt++) = prefix; /* Sign */ + *(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */ + if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */ + while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd); + bufpt--; /* point to last digit */ + if( flag_rtz && flag_dp ){ /* Remove tail zeros */ + while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; + if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; + } + bufpt++; /* point to next free slot */ + if( exp || flag_exp ){ + *(bufpt++) = aDigits[infop->charset]; + if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ + else { *(bufpt++) = '+'; } + if( exp>=100 ){ + *(bufpt++) = (exp/100)+'0'; /* 100's digit */ + exp %= 100; + } + *(bufpt++) = exp/10+'0'; /* 10's digit */ + *(bufpt++) = exp%10+'0'; /* 1's digit */ + } + } /* The converted number is in buf[] and zero terminated. Output it. ** Note that the number is in the usual order, not reversed as with ** integer conversions. */ length = bufpt-buf; bufpt = buf; @@ -593,43 +562,44 @@ } length = strlen(bufpt); if( precision>=0 && precisionetBUFSIZE ){ - bufpt = zExtra = sqliteMalloc( n ); - if( bufpt==0 ) return -1; - }else{ - bufpt = buf; - } - j = 0; - if( needQuote ) bufpt[j++] = '\''; - for(i=0; (c=arg[i])!=0; i++){ - bufpt[j++] = c; - if( c=='\'' ) bufpt[j++] = c; - } - if( needQuote ) bufpt[j++] = '\''; - bufpt[j] = 0; - length = j; - if( precision>=0 && precisionetBUFSIZE ){ + bufpt = zExtra = sqliteMalloc( n ); + if( bufpt==0 ) return -1; + }else{ + bufpt = buf; + } + j = 0; + if( needQuote ) bufpt[j++] = '\''; + for(i=0; (c=arg[i])!=0; i++){ + bufpt[j++] = c; + if( c=='\'' ) bufpt[j++] = c; + } + if( needQuote ) bufpt[j++] = '\''; + bufpt[j] = 0; + length = j; + if( precision>=0 && precisionz ){ - (*func)(arg, (char*)pToken->z, pToken->n); + (*func)(arg, pToken->z, pToken->n); } length = width = 0; break; } case etSRCLIST: { @@ -726,15 +696,11 @@ pM->zText = pM->xRealloc(0, pM->nAlloc); if( pM->zText && pM->nChar ){ memcpy(pM->zText, pM->zBase, pM->nChar); } }else{ - char *zNew; - zNew = pM->xRealloc(pM->zText, pM->nAlloc); - if( zNew ){ - pM->zText = zNew; - } + pM->zText = pM->xRealloc(pM->zText, pM->nAlloc); } } } if( pM->zText ){ if( nNewChar>0 ){ @@ -768,14 +734,11 @@ sM.zText = xRealloc(0, sM.nChar+1); if( sM.zText ){ memcpy(sM.zText, sM.zBase, sM.nChar+1); } }else if( sM.nAlloc>sM.nChar+10 ){ - char *zNew = xRealloc(sM.zText, sM.nChar+1); - if( zNew ){ - sM.zText = zNew; - } + sM.zText = xRealloc(sM.zText, sM.nChar+1); } } return sM.zText; } @@ -789,11 +752,11 @@ /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. */ char *sqlite3VMPrintf(const char *zFormat, va_list ap){ - char zBase[SQLITE_PRINT_BUF_SIZE]; + char zBase[1000]; return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); } /* ** Print into memory obtained from sqliteMalloc(). Use the internal @@ -800,11 +763,11 @@ ** %-conversion extensions. */ char *sqlite3MPrintf(const char *zFormat, ...){ va_list ap; char *z; - char zBase[SQLITE_PRINT_BUF_SIZE]; + char zBase[1000]; va_start(ap, zFormat); z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); va_end(ap); return z; } Index: SQLite.Interop/src/random.c ================================================================== --- SQLite.Interop/src/random.c +++ SQLite.Interop/src/random.c @@ -13,11 +13,11 @@ ** generator (PRNG) for SQLite. ** ** Random numbers are used by some of the database backends in order ** to generate random integer keys for tables or random filenames. ** -** $Id: random.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: random.c,v 1.1 2005/03/01 16:04:34 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -24,20 +24,17 @@ /* ** Get a single 8-bit random value from the RC4 PRNG. The Mutex ** must be held while executing this routine. ** ** Why not just use a library random generator like lrand48() for this? -** Because the OP_NewRowid opcode in the VDBE depends on having a very +** Because the OP_NewRecno opcode in the VDBE depends on having a very ** good source of random numbers. The lrand48() library function may ** well be good enough. But maybe not. Or maybe lrand48() has some ** subtle problems on some systems that could cause problems. It is hard ** to know. To minimize the risk of problems due to bad lrand48() ** implementations, SQLite uses this random number generator based ** on RC4, which we know works very well. -** -** (Later): Actually, OP_NewRowid does not depend on a good source of -** randomness any more. But we will leave this code in all the same. */ static int randomByte(){ unsigned char t; /* All threads share a single random number generator. @@ -96,5 +93,8 @@ while( N-- ){ *(zBuf++) = randomByte(); } sqlite3OsLeaveMutex(); } + + + Index: SQLite.Interop/src/select.c ================================================================== --- SQLite.Interop/src/select.c +++ SQLite.Interop/src/select.c @@ -10,14 +10,14 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: select.c,v 1.1 2005/03/01 16:04:35 rmsimpson Exp $ */ #include "sqliteInt.h" - +#include "../interop.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ @@ -58,13 +58,10 @@ pNew->op = TK_SELECT; pNew->pLimit = pLimit; pNew->pOffset = pOffset; pNew->iLimit = -1; pNew->iOffset = -1; - pNew->addrOpenVirt[0] = -1; - pNew->addrOpenVirt[1] = -1; - pNew->addrOpenVirt[2] = -1; } return pNew; } /* @@ -71,11 +68,10 @@ ** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the ** type of join. Return an integer constant that expresses that type ** in terms of the following bit values: ** ** JT_INNER -** JT_CROSS ** JT_OUTER ** JT_NATURAL ** JT_LEFT ** JT_RIGHT ** @@ -87,31 +83,31 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ int jointype = 0; Token *apAll[3]; Token *p; static const struct { - const char zKeyword[8]; + const char *zKeyword; u8 nChar; u8 code; } keywords[] = { { "natural", 7, JT_NATURAL }, { "left", 4, JT_LEFT|JT_OUTER }, { "right", 5, JT_RIGHT|JT_OUTER }, { "full", 4, JT_LEFT|JT_RIGHT|JT_OUTER }, { "outer", 5, JT_OUTER }, { "inner", 5, JT_INNER }, - { "cross", 5, JT_INNER|JT_CROSS }, + { "cross", 5, JT_INNER }, }; int i, j; apAll[0] = pA; apAll[1] = pB; apAll[2] = pC; for(i=0; i<3 && apAll[i]; i++){ p = apAll[i]; for(j=0; jn==keywords[j].nChar - && sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){ + && sqlite3StrNICmp(p->z, keywords[j].zKeyword, p->n)==0 ){ jointype |= keywords[j].code; break; } } if( j>=sizeof(keywords)/sizeof(keywords[0]) ){ @@ -152,24 +148,15 @@ /* ** Set the value of a token to a '\000'-terminated string. */ static void setToken(Token *p, const char *z){ - p->z = (u8*)z; - p->n = z ? strlen(z) : 0; + p->z = z; + p->n = strlen(z); p->dyn = 0; } -/* -** Create an expression node for an identifier with the name of zName -*/ -static Expr *createIdExpr(const char *zName){ - Token dummy; - setToken(&dummy, zName); - return sqlite3Expr(TK_ID, 0, 0, &dummy); -} - /* ** Add a term to the WHERE expression in *ppExpr that requires the ** zCol column to be equal in the two tables pTab1 and pTab2. */ @@ -177,66 +164,51 @@ const char *zCol, /* Name of the column */ const Table *pTab1, /* First table */ const char *zAlias1, /* Alias for first table. May be NULL */ const Table *pTab2, /* Second table */ const char *zAlias2, /* Alias for second table. May be NULL */ - int iRightJoinTable, /* VDBE cursor for the right table */ Expr **ppExpr /* Add the equality term to this expression */ ){ + Token dummy; Expr *pE1a, *pE1b, *pE1c; Expr *pE2a, *pE2b, *pE2c; Expr *pE; - pE1a = createIdExpr(zCol); - pE2a = createIdExpr(zCol); + setToken(&dummy, zCol); + pE1a = sqlite3Expr(TK_ID, 0, 0, &dummy); + pE2a = sqlite3Expr(TK_ID, 0, 0, &dummy); if( zAlias1==0 ){ zAlias1 = pTab1->zName; } - pE1b = createIdExpr(zAlias1); + setToken(&dummy, zAlias1); + pE1b = sqlite3Expr(TK_ID, 0, 0, &dummy); if( zAlias2==0 ){ zAlias2 = pTab2->zName; } - pE2b = createIdExpr(zAlias2); + setToken(&dummy, zAlias2); + pE2b = sqlite3Expr(TK_ID, 0, 0, &dummy); pE1c = sqlite3Expr(TK_DOT, pE1b, pE1a, 0); pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0); pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0); ExprSetProperty(pE, EP_FromJoin); - pE->iRightJoinTable = iRightJoinTable; *ppExpr = sqlite3ExprAnd(*ppExpr, pE); } /* ** Set the EP_FromJoin property on all terms of the given expression. -** And set the Expr.iRightJoinTable to iTable for every term in the -** expression. ** ** The EP_FromJoin property is used on terms of an expression to tell ** the LEFT OUTER JOIN processing logic that this term is part of the ** join restriction specified in the ON or USING clause and not a part ** of the more general WHERE clause. These terms are moved over to the ** WHERE clause during join processing but we need to remember that they ** originated in the ON or USING clause. -** -** The Expr.iRightJoinTable tells the WHERE clause processing that the -** expression depends on table iRightJoinTable even if that table is not -** explicitly mentioned in the expression. That information is needed -** for cases like this: -** -** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5 -** -** The where clause needs to defer the handling of the t1.x=5 -** term until after the t2 loop of the join. In that way, a -** NULL t2 row will be inserted whenever t1.x!=5. If we do not -** defer the handling of t1.x=5, it will be processed immediately -** after the t1 loop and rows with t1.x!=5 will never appear in -** the output, which is incorrect. */ -static void setJoinExpr(Expr *p, int iTable){ +static void setJoinExpr(Expr *p){ while( p ){ ExprSetProperty(p, EP_FromJoin); - p->iRightJoinTable = iTable; - setJoinExpr(p->pLeft, iTable); + setJoinExpr(p->pLeft); p = p->pRight; } } /* @@ -279,13 +251,11 @@ } for(j=0; jnCol; j++){ char *zName = pLeftTab->aCol[j].zName; if( columnIndex(pRightTab, zName)>=0 ){ addWhereTerm(zName, pLeftTab, pLeft->zAlias, - pRightTab, pRight->zAlias, - pRight->iCursor, &p->pWhere); - + pRightTab, pRight->zAlias, &p->pWhere); } } } /* Disallow both ON and USING clauses in the same join @@ -298,11 +268,11 @@ /* Add the ON clause to the end of the WHERE clause, connected by ** an AND operator. */ if( pLeft->pOn ){ - setJoinExpr(pLeft->pOn, pRight->iCursor); + setJoinExpr(pLeft->pOn); p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn); pLeft->pOn = 0; } /* Create extra terms on the WHERE clause for each column named @@ -320,12 +290,11 @@ sqlite3ErrorMsg(pParse, "cannot join using column %s - column " "not present in both tables", zName); return 1; } addWhereTerm(zName, pLeftTab, pLeft->zAlias, - pRightTab, pRight->zAlias, - pRight->iCursor, &p->pWhere); + pRightTab, pRight->zAlias, &p->pWhere); } } } return 0; } @@ -349,83 +318,45 @@ /* ** Insert code into "v" that will push the record on the top of the ** stack into the sorter. */ -static void pushOntoSorter( - Parse *pParse, /* Parser context */ - ExprList *pOrderBy, /* The ORDER BY clause */ - Select *pSelect /* The whole SELECT statement */ -){ - Vdbe *v = pParse->pVdbe; - sqlite3ExprCodeExprList(pParse, pOrderBy); - sqlite3VdbeAddOp(v, OP_Sequence, pOrderBy->iECursor, 0); - sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr + 1, 0); - sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0); - sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0); - if( pSelect->iLimit>=0 ){ - int addr1, addr2; - addr1 = sqlite3VdbeAddOp(v, OP_IfMemZero, pSelect->iLimit+1, 0); - sqlite3VdbeAddOp(v, OP_MemIncr, -1, pSelect->iLimit+1); - addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); - sqlite3VdbeJumpHere(v, addr1); - sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0); - sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0); - sqlite3VdbeJumpHere(v, addr2); - pSelect->iLimit = -1; - } +static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){ + int i; + for(i=0; inExpr; i++){ + sqlite3ExprCode(pParse, pOrderBy->a[i].pExpr); + } + sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr, 0); + sqlite3VdbeAddOp(v, OP_SortPut, 0, 0); } /* -** Add code to implement the OFFSET +** Add code to implement the OFFSET and LIMIT */ -static void codeOffset( +static void codeLimiter( Vdbe *v, /* Generate code into this VM */ Select *p, /* The SELECT statement being coded */ int iContinue, /* Jump here to skip the current record */ + int iBreak, /* Jump here to end the loop */ int nPop /* Number of times to pop stack when jumping */ ){ - if( p->iOffset>=0 && iContinue!=0 ){ - int addr; - sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset); - addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, 0); + if( p->iOffset>=0 ){ + int addr = sqlite3VdbeCurrentAddr(v) + 3; + if( nPop>0 ) addr++; + sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, 0); + sqlite3VdbeAddOp(v, OP_IfMemPos, p->iOffset, addr); if( nPop>0 ){ sqlite3VdbeAddOp(v, OP_Pop, nPop, 0); } sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue); VdbeComment((v, "# skip OFFSET records")); - sqlite3VdbeJumpHere(v, addr); - } -} - -/* -** Add code that will check to make sure the top N elements of the -** stack are distinct. iTab is a sorting index that holds previously -** seen combinations of the N values. A new entry is made in iTab -** if the current N values are new. -** -** A jump to addrRepeat is made and the K values are popped from the -** stack if the top N elements are not distinct. -*/ -static void codeDistinct( - Vdbe *v, /* Generate code into this VM */ - int iTab, /* A sorting index used to test for distinctness */ - int addrRepeat, /* Jump to here if not distinct */ - int N, /* The top N elements of the stack must be distinct */ - int K /* Pop K elements from the stack if indistinct */ -){ -#if NULL_ALWAYS_DISTINCT - sqlite3VdbeAddOp(v, OP_IsNull, -N, sqlite3VdbeCurrentAddr(v)+6); -#endif - sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0); - sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeAddOp(v, OP_Pop, K, 0); - sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat); - VdbeComment((v, "# skip indistinct records")); - sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0); -} - + } + if( p->iLimit>=0 ){ + sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak); + VdbeComment((v, "# exit when LIMIT reached")); + } +} /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** @@ -458,11 +389,11 @@ /* If there was a LIMIT clause on the SELECT statement, then do the check ** to see if this row should be output. */ hasDistinct = distinct>=0 && pEList && pEList->nExpr>0; if( pOrderBy==0 && !hasDistinct ){ - codeOffset(v, p, iContinue, 0); + codeLimiter(v, p, iContinue, iBreak, 0); } /* Pull the requested columns. */ if( nColumn>0 ){ @@ -469,36 +400,47 @@ for(i=0; inExpr; - sqlite3ExprCodeExprList(pParse, pEList); + for(i=0; inExpr; i++){ + sqlite3ExprCode(pParse, pEList->a[i].pExpr); + } } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( hasDistinct ){ - int n = pEList->nExpr; - codeDistinct(v, distinct, iContinue, n, n+1); +#if NULL_ALWAYS_DISTINCT + sqlite3VdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqlite3VdbeCurrentAddr(v)+7); +#endif + /* Deliberately leave the affinity string off of the following + ** OP_MakeRecord */ + sqlite3VdbeAddOp(v, OP_MakeRecord, pEList->nExpr * -1, 0); + sqlite3VdbeAddOp(v, OP_Distinct, distinct, sqlite3VdbeCurrentAddr(v)+3); + sqlite3VdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0); + sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue); + VdbeComment((v, "# skip indistinct records")); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); + sqlite3VdbeAddOp(v, OP_PutStrKey, distinct, 0); if( pOrderBy==0 ){ - codeOffset(v, p, iContinue, nColumn); + codeLimiter(v, p, iContinue, iBreak, nColumn); } } switch( eDest ){ +#ifndef SQLITE_OMIT_COMPOUND_SELECT /* In this mode, write each query result to the key of the temporary ** table iParm. */ -#ifndef SQLITE_OMIT_COMPOUND_SELECT case SRT_Union: { sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT); - if( aff ){ - sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC); - } - sqlite3VdbeAddOp(v, OP_IdxInsert, iParm, 0); + sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); + sqlite3VdbeAddOp(v, OP_PutStrKey, iParm, 0); break; } /* Construct a record from the query result, but instead of ** saving that record, use it as a key to delete elements from @@ -515,18 +457,18 @@ #endif /* Store the result as data using a unique key. */ case SRT_Table: - case SRT_VirtualTab: { + case SRT_TempTable: { sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); if( pOrderBy ){ - pushOntoSorter(pParse, pOrderBy, p); + pushOntoSorter(pParse, v, pOrderBy); }else{ - sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); + sqlite3VdbeAddOp(v, OP_NewRecno, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); - sqlite3VdbeAddOp(v, OP_Insert, iParm, 0); + sqlite3VdbeAddOp(v, OP_PutIntKey, iParm, 0); } break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -541,63 +483,62 @@ assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); if( pOrderBy ){ - /* At first glance you would think we could optimize out the - ** ORDER BY in this case since the order of entries in the set - ** does not matter. But there might be a LIMIT clause, in which - ** case the order does matter */ - pushOntoSorter(pParse, pOrderBy, p); + pushOntoSorter(pParse, v, pOrderBy); }else{ char aff = (iParm>>16)&0xFF; aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff); sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1); - sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); - } - sqlite3VdbeJumpHere(v, addr2); - break; - } - - /* If any row exists in the result set, record that fact and abort. - */ - case SRT_Exists: { - sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm); - sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); - /* The LIMIT clause will terminate the loop for us */ + sqlite3VdbeAddOp(v, OP_String8, 0, 0); + sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0); + } + sqlite3VdbeChangeP2(v, addr2, sqlite3VdbeCurrentAddr(v)); break; } /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ + case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); if( pOrderBy ){ - pushOntoSorter(pParse, pOrderBy, p); + pushOntoSorter(pParse, v, pOrderBy); }else{ sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); - /* The LIMIT clause will jump out of the loop for us */ + sqlite3VdbeAddOp(v, OP_Goto, 0, iBreak); } break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ - /* Send the data to the callback function or to a subroutine. In the - ** case of a subroutine, the subroutine itself is responsible for - ** popping the data from the stack. + /* Send the data to the callback function. + */ + case SRT_Callback: + case SRT_Sorter: { + if( pOrderBy ){ + sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); + pushOntoSorter(pParse, v, pOrderBy); + }else{ + assert( eDest==SRT_Callback ); + sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0); + } + break; + } + + /* Invoke a subroutine to handle the results. The subroutine itself + ** is responsible for popping the results off of the stack. */ - case SRT_Subroutine: - case SRT_Callback: { + case SRT_Subroutine: { if( pOrderBy ){ sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); - pushOntoSorter(pParse, pOrderBy, p); - }else if( eDest==SRT_Subroutine ){ - sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm); + pushOntoSorter(pParse, v, pOrderBy); }else{ - sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0); + sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm); } break; } #if !defined(SQLITE_OMIT_TRIGGER) @@ -611,61 +552,12 @@ sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); break; } #endif } - - /* Jump to the end of the loop if the LIMIT is reached. - */ - if( p->iLimit>=0 && pOrderBy==0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); - sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak); - } return 0; } - -/* -** Given an expression list, generate a KeyInfo structure that records -** the collating sequence for each expression in that expression list. -** -** If the ExprList is an ORDER BY or GROUP BY clause then the resulting -** KeyInfo structure is appropriate for initializing a virtual index to -** implement that clause. If the ExprList is the result set of a SELECT -** then the KeyInfo structure is appropriate for initializing a virtual -** index to implement a DISTINCT test. -** -** Space to hold the KeyInfo structure is obtain from malloc. The calling -** function is responsible for seeing that this structure is eventually -** freed. Add the KeyInfo structure to the P3 field of an opcode using -** P3_KEYINFO_HANDOFF is the usual way of dealing with this. -*/ -static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){ - sqlite3 *db = pParse->db; - int nExpr; - KeyInfo *pInfo; - struct ExprList_item *pItem; - int i; - - nExpr = pList->nExpr; - pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) ); - if( pInfo ){ - pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr]; - pInfo->nField = nExpr; - pInfo->enc = ENC(db); - for(i=0, pItem=pList->a; ipExpr); - if( !pColl ){ - pColl = db->pDfltColl; - } - pInfo->aColl[i] = pColl; - pInfo->aSortOrder[i] = pItem->sortOrder; - } - } - return pInfo; -} - /* ** If the inner loop was generated using a non-null pOrderBy argument, ** then the results were placed in a sorter. After the loop is terminated ** we need to run the sorter and output the results. The following @@ -677,42 +569,63 @@ Vdbe *v, /* Generate code into this VDBE */ int nColumn, /* Number of columns of data */ int eDest, /* Write the sorted results here */ int iParm /* Optional parameter associated with eDest */ ){ - int brk = sqlite3VdbeMakeLabel(v); - int cont = sqlite3VdbeMakeLabel(v); + int end1 = sqlite3VdbeMakeLabel(v); + int end2 = sqlite3VdbeMakeLabel(v); int addr; - int iTab; - ExprList *pOrderBy = p->pOrderBy; + KeyInfo *pInfo; + ExprList *pOrderBy; + int nCol, i; + sqlite3 *db = pParse->db; - iTab = pOrderBy->iECursor; - addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk); - codeOffset(v, p, cont, 0); - sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); + if( eDest==SRT_Sorter ) return; + pOrderBy = p->pOrderBy; + nCol = pOrderBy->nExpr; + pInfo = sqliteMalloc( sizeof(*pInfo) + nCol*(sizeof(CollSeq*)+1) ); + if( pInfo==0 ) return; + pInfo->aSortOrder = (char*)&pInfo->aColl[nCol]; + pInfo->nField = nCol; + for(i=0; ia[i].zName. Otherwise, use the default + ** collation type for the expression. + */ + pInfo->aColl[i] = sqlite3ExprCollSeq(pParse, pOrderBy->a[i].pExpr); + if( !pInfo->aColl[i] ){ + pInfo->aColl[i] = db->pDfltColl; + } + pInfo->aSortOrder[i] = pOrderBy->a[i].sortOrder; + } + sqlite3VdbeOp3(v, OP_Sort, 0, 0, (char*)pInfo, P3_KEYINFO_HANDOFF); + addr = sqlite3VdbeAddOp(v, OP_SortNext, 0, end1); + codeLimiter(v, p, addr, end2, 1); switch( eDest ){ case SRT_Table: - case SRT_VirtualTab: { - sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); + case SRT_TempTable: { + sqlite3VdbeAddOp(v, OP_NewRecno, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); - sqlite3VdbeAddOp(v, OP_Insert, iParm, 0); + sqlite3VdbeAddOp(v, OP_PutIntKey, iParm, 0); break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "c", P3_STATIC); - sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); + sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "n", P3_STATIC); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); + sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0); break; } + case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); - /* The LIMIT clause will terminate the loop for us */ + sqlite3VdbeAddOp(v, OP_Goto, 0, end1); break; } #endif case SRT_Callback: case SRT_Subroutine: { @@ -733,23 +646,15 @@ default: { /* Do nothing */ break; } } - - /* Jump to the end of the loop when the LIMIT is reached - */ - if( p->iLimit>=0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); - sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, brk); - } - - /* The bottom of the loop - */ - sqlite3VdbeResolveLabel(v, cont); - sqlite3VdbeAddOp(v, OP_Next, iTab, addr); - sqlite3VdbeResolveLabel(v, brk); + sqlite3VdbeAddOp(v, OP_Goto, 0, addr); + sqlite3VdbeResolveLabel(v, end2); + sqlite3VdbeAddOp(v, OP_Pop, 1, 0); + sqlite3VdbeResolveLabel(v, end1); + sqlite3VdbeAddOp(v, OP_SortReset, 0, 0); } /* ** Return a pointer to a string containing the 'declaration type' of the ** expression pExpr. The string may be treated as static by the caller. @@ -782,24 +687,10 @@ pTab = pTabList->a[j].pTab; }else{ pNC = pNC->pNext; } } - if( pTab==0 ){ - /* FIX ME: - ** This can occurs if you have something like "SELECT new.x;" inside - ** a trigger. In other words, if you reference the special "new" - ** table in the result set of a select. We do not have a good way - ** to find the actual table type, so call it "TEXT". This is really - ** something of a bug, but I do not know how to fix it. - ** - ** This code does not produce the correct answer - it just prevents - ** a segfault. See ticket #1229. - */ - zType = "TEXT"; - break; - } assert( pTab ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zType = "INTEGER"; @@ -870,12 +761,11 @@ return; } #endif assert( v!=0 ); - if( pParse->colNamesSet || v==0 - || sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( pParse->colNamesSet || v==0 || sqlite3_malloc_failed ) return; pParse->colNamesSet = 1; fullNames = (db->flags & SQLITE_FullColNames)!=0; shortNames = (db->flags & SQLITE_ShortColNames)!=0; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; inExpr; i++){ @@ -900,24 +790,24 @@ zCol = "rowid"; }else{ zCol = pTab->aCol[iCol].zName; } if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); + sqlite3VdbeSetColName(v, i, p->span.z, p->span.n); }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ char *zName = 0; char *zTab; zTab = pTabList->a[j].zAlias; if( fullNames || zTab==0 ) zTab = pTab->zName; - sqlite3SetString(&zName, zTab, ".", zCol, (char*)0); + sqlite3SetString(&zName, zTab, ".", zCol, 0); sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC); }else{ sqlite3VdbeSetColName(v, i, zCol, strlen(zCol)); } }else if( p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); + sqlite3VdbeSetColName(v, i, p->span.z, p->span.n); /* sqlite3VdbeCompressSpace(v, addr); */ }else{ char zName[30]; assert( p->op!=TK_COLUMN || pTabList==0 ); sprintf(zName, "column%d", i+1); @@ -966,11 +856,10 @@ } pTab = sqliteMalloc( sizeof(Table) ); if( pTab==0 ){ return 0; } - pTab->nRef = 1; pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0; pEList = pSelect->pEList; pTab->nCol = pEList->nExpr; assert( pTab->nCol>0 ); pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol ); @@ -977,11 +866,10 @@ for(i=0, pCol=aCol; inCol; i++, pCol++){ Expr *p, *pR; char *zType; char *zName; char *zBasename; - CollSeq *pColl; int cnt; NameContext sNC; /* Get an appropriate name for the column */ @@ -1000,25 +888,19 @@ }else{ /* If all else fails, make up a name */ zName = sqlite3MPrintf("column%d", i+1); } sqlite3Dequote(zName); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ - sqliteFree(zName); - sqlite3DeleteTable(0, pTab); - return 0; - } /* Make sure the column name is unique. If the name is not unique, ** append a integer to the name so that it becomes unique. */ zBasename = zName; for(j=cnt=0; jzName = zName; /* Get the typename, type affinity, and collating sequence for the ** column. */ - memset(&sNC, 0, sizeof(sNC)); sNC.pSrcList = pSelect->pSrc; zType = sqliteStrDup(columnType(&sNC, p)); pCol->zType = zType; pCol->affinity = sqlite3ExprAffinity(p); - pColl = sqlite3ExprCollSeq(pParse, p); - if( pColl ){ - pCol->zColl = sqliteStrDup(pColl->zName); + pCol->pColl = sqlite3ExprCollSeq(pParse, p); + if( !pCol->pColl ){ + pCol->pColl = pParse->db->pDfltColl; } } pTab->iPKey = -1; return pTab; } @@ -1072,13 +953,11 @@ SrcList *pTabList; ExprList *pEList; Table *pTab; struct SrcList_item *pFrom; - if( p==0 || p->pSrc==0 || sqlite3ThreadDataReadOnly()->mallocFailed ){ - return 1; - } + if( p==0 || p->pSrc==0 ) return 1; pTabList = p->pSrc; pEList = p->pEList; /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. @@ -1102,11 +981,10 @@ assert( pFrom->pSelect!=0 ); if( pFrom->zAlias==0 ){ pFrom->zAlias = sqlite3MPrintf("sqlite_subquery_%p_", (void*)pFrom->pSelect); } - assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3ResultSetOfSelect(pParse, pFrom->zAlias, pFrom->pSelect); if( pTab==0 ){ return 1; } @@ -1116,17 +994,15 @@ ** part of the schema. */ pTab->isTransient = 1; #endif }else{ /* An ordinary table or view name in the FROM clause */ - assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3LocateTable(pParse,pFrom->zName,pFrom->zDatabase); if( pTab==0 ){ return 1; } - pTab->nRef++; #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ /* We reach here if the named table is a really a view */ if( sqlite3ViewGetColumnNames(pParse, pTab) ){ return 1; @@ -1171,26 +1047,18 @@ ** operators that need to be expanded. Loop through each expression ** in the result set and expand them one by one. */ struct ExprList_item *a = pEList->a; ExprList *pNew = 0; - int flags = pParse->db->flags; - int longNames = (flags & SQLITE_FullColNames)!=0 && - (flags & SQLITE_ShortColNames)==0; - for(k=0; knExpr; k++){ Expr *pE = a[k].pExpr; if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0); - if( pNew ){ - pNew->a[pNew->nExpr-1].zName = a[k].zName; - }else{ - rc = 1; - } + pNew->a[pNew->nExpr-1].zName = a[k].zName; a[k].pExpr = 0; a[k].zName = 0; }else{ /* This expression is a "*" or a "TABLE.*" and needs to be ** expanded. */ @@ -1231,11 +1099,11 @@ } } pRight = sqlite3Expr(TK_ID, 0, 0, 0); if( pRight==0 ) break; setToken(&pRight->token, zName); - if( zTabName && (longNames || pTabList->nSrc>1) ){ + if( zTabName && pTabList->nSrc>1 ){ pLeft = sqlite3Expr(TK_ID, 0, 0, 0); pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0); if( pExpr==0 ) break; setToken(&pLeft->token, zTabName); setToken(&pExpr->span, sqlite3MPrintf("%s.%s", zTabName, zName)); @@ -1245,15 +1113,11 @@ pExpr->token.dyn = 0; }else{ pExpr = pRight; pExpr->span = pExpr->token; } - if( longNames ){ - pNew = sqlite3ExprListAppend(pNew, pExpr, &pExpr->span); - }else{ - pNew = sqlite3ExprListAppend(pNew, pExpr, &pRight->token); - } + pNew = sqlite3ExprListAppend(pNew, pExpr, &pRight->token); } } if( !tableSeen ){ if( zTName ){ sqlite3ErrorMsg(pParse, "no such table: %s", zTName); @@ -1269,10 +1133,44 @@ p->pEList = pNew; } return rc; } +/* +** This routine recursively unlinks the Select.pSrc.a[].pTab pointers +** in a select structure. It just sets the pointers to NULL. This +** routine is recursive in the sense that if the Select.pSrc.a[].pSelect +** pointer is not NULL, this routine is called recursively on that pointer. +** +** This routine is called on the Select structure that defines a +** VIEW in order to undo any bindings to tables. This is necessary +** because those tables might be DROPed by a subsequent SQL command. +** If the bindings are not removed, then the Select.pSrc->a[].pTab field +** will be left pointing to a deallocated Table structure after the +** DROP and a coredump will occur the next time the VIEW is used. +*/ +#if 0 +void sqlite3SelectUnbind(Select *p){ + int i; + SrcList *pSrc = p->pSrc; + struct SrcList_item *pItem; + Table *pTab; + if( p==0 ) return; + for(i=0, pItem=pSrc->a; inSrc; i++, pItem++){ + if( (pTab = pItem->pTab)!=0 ){ + if( pTab->isTransient ){ + sqlite3DeleteTable(0, pTab); + } + pItem->pTab = 0; + if( pItem->pSelect ){ + sqlite3SelectUnbind(pItem->pSelect); + } + } + } +} +#endif + #ifndef SQLITE_OMIT_COMPOUND_SELECT /* ** This routine associates entries in an ORDER BY expression list with ** columns in a result. For each ORDER BY expression, the opcode of ** the top-level node is changed to TK_COLUMN and the iColumn value of @@ -1367,108 +1265,118 @@ v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db); } return v; } - /* ** Compute the iLimit and iOffset fields of the SELECT based on the -** pLimit and pOffset expressions. pLimit and pOffset hold the expressions +** pLimit and pOffset expressions. nLimit and nOffset hold the expressions ** that appear in the original SQL statement after the LIMIT and OFFSET ** keywords. Or NULL if those keywords are omitted. iLimit and iOffset ** are the integer memory register numbers for counters used to compute ** the limit and offset. If there is no limit and/or offset, then ** iLimit and iOffset are negative. ** -** This routine changes the values of iLimit and iOffset only if -** a limit or offset is defined by pLimit and pOffset. iLimit and +** This routine changes the values if iLimit and iOffset only if +** a limit or offset is defined by nLimit and nOffset. iLimit and ** iOffset should have been preset to appropriate default values ** (usually but not always -1) prior to calling this routine. -** Only if pLimit!=0 or pOffset!=0 do the limit registers get +** Only if nLimit>=0 or nOffset>0 do the limit registers get ** redefined. The UNION ALL operator uses this property to force ** the reuse of the same limit and offset registers across multiple ** SELECT statements. */ -static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ - Vdbe *v; - int iLimit; - int iOffset; - int addr1, addr2; - +static void computeLimitRegisters(Parse *pParse, Select *p){ /* ** "LIMIT -1" always shows all rows. There is some ** contraversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean ** no rows. */ if( p->pLimit ){ - p->iLimit = iLimit = pParse->nMem; - pParse->nMem += 2; - v = sqlite3GetVdbe(pParse); + int iMem = pParse->nMem++; + Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pLimit); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); - sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 0); + sqlite3VdbeAddOp(v, OP_Negative, 0, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); VdbeComment((v, "# LIMIT counter")); - sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak); + p->iLimit = iMem; } if( p->pOffset ){ - p->iOffset = iOffset = pParse->nMem++; - v = sqlite3GetVdbe(pParse); + int iMem = pParse->nMem++; + Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pOffset); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); - sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0); + sqlite3VdbeAddOp(v, OP_Negative, 0, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); VdbeComment((v, "# OFFSET counter")); - addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0); - sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - sqlite3VdbeAddOp(v, OP_Integer, 0, 0); - sqlite3VdbeJumpHere(v, addr1); - if( p->pLimit ){ - sqlite3VdbeAddOp(v, OP_Add, 0, 0); - } - } - if( p->pLimit ){ - addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iLimit, 0); - sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - sqlite3VdbeAddOp(v, OP_MemInt, -1, iLimit+1); - addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); - sqlite3VdbeJumpHere(v, addr1); - sqlite3VdbeAddOp(v, OP_MemStore, iLimit+1, 1); - VdbeComment((v, "# LIMIT+OFFSET")); - sqlite3VdbeJumpHere(v, addr2); - } -} - -/* -** Allocate a virtual index to use for sorting. -*/ -static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){ - if( pOrderBy ){ - int addr; - assert( pOrderBy->iECursor==0 ); - pOrderBy->iECursor = pParse->nTab++; - addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenVirtual, - pOrderBy->iECursor, pOrderBy->nExpr+1); - assert( p->addrOpenVirt[2] == -1 ); - p->addrOpenVirt[2] = addr; - } -} - -/* -** The opcode at addr is an OP_OpenVirtual that created a sorting -** index tha we ended up not needing. This routine changes that -** opcode to OP_Noop. -*/ -static void uncreateSortingIndex(Parse *pParse, int addr){ + p->iOffset = iMem; + } +} + +/* +** Generate VDBE instructions that will open a transient table that +** will be used for an index or to store keyed results for a compound +** select. In other words, open a transient table that needs a +** KeyInfo structure. The number of columns in the KeyInfo is determined +** by the result set of the SELECT statement in the second argument. +** +** Specifically, this routine is called to open an index table for +** DISTINCT, UNION, INTERSECT and EXCEPT select statements (but not +** UNION ALL). +** +** Make the new table a KeyAsData table if keyAsData is true. +** +** The value returned is the address of the OP_OpenTemp instruction. +*/ +static int openTempIndex(Parse *pParse, Select *p, int iTab, int keyAsData){ + KeyInfo *pKeyInfo; + int nColumn; + sqlite3 *db = pParse->db; + int i; Vdbe *v = pParse->pVdbe; - VdbeOp *pOp = sqlite3VdbeGetOp(v, addr); - sqlite3VdbeChangeP3(v, addr, 0, 0); - pOp->opcode = OP_Noop; - pOp->p1 = 0; - pOp->p2 = 0; + int addr; + + if( prepSelectStmt(pParse, p) ){ + return 0; + } + nColumn = p->pEList->nExpr; + pKeyInfo = sqliteMalloc( sizeof(*pKeyInfo)+nColumn*sizeof(CollSeq*) ); + if( pKeyInfo==0 ) return 0; + pKeyInfo->enc = db->enc; + pKeyInfo->nField = nColumn; + for(i=0; iaColl[i] = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr); + if( !pKeyInfo->aColl[i] ){ + pKeyInfo->aColl[i] = db->pDfltColl; + } + } + addr = sqlite3VdbeOp3(v, OP_OpenTemp, iTab, 0, + (char*)pKeyInfo, P3_KEYINFO_HANDOFF); + if( keyAsData ){ + sqlite3VdbeAddOp(v, OP_KeyAsData, iTab, 1); + } + return addr; +} + +#ifndef SQLITE_OMIT_COMPOUND_SELECT +/* +** Add the address "addr" to the set of all OpenTemp opcode addresses +** that are being accumulated in p->ppOpenTemp. +*/ +static int multiSelectOpenTempAddr(Select *p, int addr){ + IdList *pList = *p->ppOpenTemp = sqlite3IdListAppend(*p->ppOpenTemp, 0); + if( pList==0 ){ + return SQLITE_NOMEM; + } + pList->a[pList->nId-1].idx = addr; + return SQLITE_OK; } +#endif /* SQLITE_OMIT_COMPOUND_SELECT */ #ifndef SQLITE_OMIT_COMPOUND_SELECT /* ** Return the appropriate collating sequence for the iCol-th column of ** the result set for the compound-select statement "p". Return NULL if @@ -1530,25 +1438,23 @@ char *aff /* If eDest is SRT_Union, the affinity string */ ){ int rc = SQLITE_OK; /* Success code from a subroutine */ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ + IdList *pOpenTemp = 0;/* OP_OpenTemp opcodes that need a KeyInfo */ + int aAddr[5]; /* Addresses of SetNumColumns operators */ + int nAddr = 0; /* Number used */ int nCol; /* Number of columns in the result set */ - ExprList *pOrderBy; /* The ORDER BY clause on p */ - int aSetP2[2]; /* Set P2 value of these op to number of columns */ - int nSetP2 = 0; /* Number of slots in aSetP2[] used */ /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ if( p==0 || p->pPrior==0 ){ rc = 1; goto multi_select_end; } pPrior = p->pPrior; - assert( pPrior->pRightmost!=pPrior ); - assert( pPrior->pRightmost==p->pRightmost ); if( pPrior->pOrderBy ){ sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before", selectOpName(p->op)); rc = 1; goto multi_select_end; @@ -1565,51 +1471,54 @@ v = sqlite3GetVdbe(pParse); if( v==0 ){ rc = 1; goto multi_select_end; } + + /* If *p this is the right-most select statement, then initialize + ** p->ppOpenTemp to point to pOpenTemp. If *p is not the right most + ** statement then p->ppOpenTemp will have already been initialized + ** by a prior call to this same procedure. Pass along the pOpenTemp + ** pointer to pPrior, the next statement to our left. + */ + if( p->ppOpenTemp==0 ){ + p->ppOpenTemp = &pOpenTemp; + } + pPrior->ppOpenTemp = p->ppOpenTemp; /* Create the destination temporary table if necessary */ - if( eDest==SRT_VirtualTab ){ + if( eDest==SRT_TempTable ){ assert( p->pEList ); - assert( nSetP2pOrderBy; switch( p->op ){ case TK_ALL: { - if( pOrderBy==0 ){ - int addr = 0; + if( p->pOrderBy==0 ){ assert( !pPrior->pLimit ); pPrior->pLimit = p->pLimit; pPrior->pOffset = p->pOffset; rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff); - p->pLimit = 0; - p->pOffset = 0; if( rc ){ goto multi_select_end; } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; - if( p->iLimit>=0 ){ - addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0); - VdbeComment((v, "# Jump ahead if LIMIT reached")); - } + p->pLimit = 0; + p->pOffset = 0; rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff); p->pPrior = pPrior; if( rc ){ goto multi_select_end; } - if( addr ){ - sqlite3VdbeJumpHere(v, addr); - } break; } /* For UNION ALL ... ORDER BY fall through to the next case */ } case TK_EXCEPT: @@ -1616,37 +1525,39 @@ case TK_UNION: { int unionTab; /* Cursor number of the temporary table holding result */ int op = 0; /* One of the SRT_ operations to apply to self */ int priorOp; /* The SRT_ operation to apply to prior selects */ Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */ + ExprList *pOrderBy; /* The ORDER BY clause for the right SELECT */ int addr; priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union; - if( eDest==priorOp && pOrderBy==0 && !p->pLimit && !p->pOffset ){ + if( eDest==priorOp && p->pOrderBy==0 && !p->pLimit && !p->pOffset ){ /* We can reuse a temporary table generated by a SELECT to our ** right. */ unionTab = iParm; }else{ /* We will need to create our own temporary table to hold the ** intermediate results. */ unionTab = pParse->nTab++; - if( pOrderBy && matchOrderbyToColumn(pParse, p, pOrderBy, unionTab,1) ){ + if( p->pOrderBy + && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){ rc = 1; goto multi_select_end; } - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, unionTab, 0); - if( priorOp==SRT_Table ){ - assert( nSetP2addrOpenVirt[0] == -1 ); - p->addrOpenVirt[0] = addr; - p->pRightmost->usesVirt = 1; - } - createSortingIndex(pParse, p, pOrderBy); + addr = sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 0); + if( p->op!=TK_ALL ){ + rc = multiSelectOpenTempAddr(p, addr); + if( rc!=SQLITE_OK ){ + goto multi_select_end; + } + sqlite3VdbeAddOp(v, OP_KeyAsData, unionTab, 1); + } + assert( nAddrpEList ); } /* Code the SELECT statements to our left */ @@ -1662,12 +1573,12 @@ case TK_EXCEPT: op = SRT_Except; break; case TK_UNION: op = SRT_Union; break; case TK_ALL: op = SRT_Table; break; } p->pPrior = 0; + pOrderBy = p->pOrderBy; p->pOrderBy = 0; - p->disallowOrderBy = pOrderBy!=0; pLimit = p->pLimit; p->pLimit = 0; pOffset = p->pOffset; p->pOffset = 0; rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff); @@ -1692,15 +1603,15 @@ if( eDest==SRT_Callback ){ generateColumnNames(pParse, 0, p->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); - computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak); + computeLimitRegisters(pParse, p); iStart = sqlite3VdbeCurrentAddr(v); rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, - pOrderBy, -1, eDest, iParm, + p->pOrderBy, -1, eDest, iParm, iCont, iBreak, 0); if( rc ){ rc = 1; goto multi_select_end; } @@ -1721,20 +1632,23 @@ ** two temporary tables. Hence it has its own case. Begin ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; - if( pOrderBy && matchOrderbyToColumn(pParse,p,pOrderBy,tab1,1) ){ + if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){ rc = 1; goto multi_select_end; } - createSortingIndex(pParse, p, pOrderBy); - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0); - assert( p->addrOpenVirt[0] == -1 ); - p->addrOpenVirt[0] = addr; - p->pRightmost->usesVirt = 1; + addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 0); + rc = multiSelectOpenTempAddr(p, addr); + if( rc!=SQLITE_OK ){ + goto multi_select_end; + } + sqlite3VdbeAddOp(v, OP_KeyAsData, tab1, 1); + assert( nAddrpEList ); /* Code the SELECTs to our left into temporary table "tab1". */ rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff); @@ -1742,13 +1656,18 @@ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0); - assert( p->addrOpenVirt[1] == -1 ); - p->addrOpenVirt[1] = addr; + addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab2, 0); + rc = multiSelectOpenTempAddr(p, addr); + if( rc!=SQLITE_OK ){ + goto multi_select_end; + } + sqlite3VdbeAddOp(v, OP_KeyAsData, tab2, 1); + assert( nAddrpPrior = 0; pLimit = p->pLimit; p->pLimit = 0; pOffset = p->pOffset; p->pOffset = 0; @@ -1768,16 +1687,16 @@ if( eDest==SRT_Callback ){ generateColumnNames(pParse, 0, p->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); - computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak); - iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0); + computeLimitRegisters(pParse, p); + iStart = sqlite3VdbeAddOp(v, OP_FullKey, tab1, 0); sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont); rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, - pOrderBy, -1, eDest, iParm, + p->pOrderBy, -1, eDest, iParm, iCont, iBreak, 0); if( rc ){ rc = 1; goto multi_select_end; } @@ -1802,12 +1721,13 @@ } /* Set the number of columns in temporary tables */ nCol = p->pEList->nExpr; - while( nSetP2 ){ - sqlite3VdbeChangeP2(v, aSetP2[--nSetP2], nCol); + while( nAddr>0 ){ + nAddr--; + sqlite3VdbeChangeP2(v, aAddr[nAddr], nCol); } /* Compute collating sequences used by either the ORDER BY clause or ** by any temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. Invoke the @@ -1816,83 +1736,64 @@ ** This section is run by the right-most SELECT statement only. ** SELECT statements to the left always skip this part. The right-most ** SELECT might also skip this part if it has no ORDER BY clause and ** no temp tables are required. */ - if( pOrderBy || p->usesVirt ){ + if( p->pOrderBy || (pOpenTemp && pOpenTemp->nId>0) ){ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ - Select *pLoop; /* For looping through SELECT statements */ - CollSeq **apColl; - CollSeq **aCopy; - assert( p->pRightmost==p ); - pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*2*sizeof(CollSeq*) + nCol); + assert( p->ppOpenTemp == &pOpenTemp ); + pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*sizeof(CollSeq*)); if( !pKeyInfo ){ rc = SQLITE_NOMEM; goto multi_select_end; } - pKeyInfo->enc = ENC(pParse->db); + pKeyInfo->enc = pParse->db->enc; pKeyInfo->nField = nCol; - for(i=0, apColl=pKeyInfo->aColl; idb->pDfltColl; - } - } - - for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ - for(i=0; i<2; i++){ - int addr = pLoop->addrOpenVirt[i]; - if( addr<0 ){ - /* If [0] is unused then [1] is also unused. So we can - ** always safely abort as soon as the first unused slot is found */ - assert( pLoop->addrOpenVirt[1]<0 ); - break; - } - sqlite3VdbeChangeP2(v, addr, nCol); - sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO); - } - } - - if( pOrderBy ){ - struct ExprList_item *pOTerm = pOrderBy->a; - int nOrderByExpr = pOrderBy->nExpr; - int addr; - u8 *pSortOrder; - - aCopy = (CollSeq**)&pKeyInfo[1]; - pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol]; - memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*)); - apColl = pKeyInfo->aColl; - for(i=0; ipExpr; - char *zName = pOTerm->zName; - assert( pExpr->op==TK_COLUMN && pExpr->iColumniColumn]; - } - *pSortOrder = pOTerm->sortOrder; - } - assert( p->pRightmost==p ); - assert( p->addrOpenVirt[2]>=0 ); - addr = p->addrOpenVirt[2]; - sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2); - pKeyInfo->nField = nOrderByExpr; - sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); - pKeyInfo = 0; + for(i=0; iaColl[i] = multiSelectCollSeq(pParse, p, i); + if( !pKeyInfo->aColl[i] ){ + pKeyInfo->aColl[i] = pParse->db->pDfltColl; + } + } + + for(i=0; pOpenTemp && inId; i++){ + int p3type = (i==0?P3_KEYINFO_HANDOFF:P3_KEYINFO); + int addr = pOpenTemp->a[i].idx; + sqlite3VdbeChangeP3(v, addr, (char *)pKeyInfo, p3type); + } + + if( p->pOrderBy ){ + struct ExprList_item *pOrderByTerm = p->pOrderBy->a; + for(i=0; ipOrderBy->nExpr; i++, pOrderByTerm++){ + Expr *pExpr = pOrderByTerm->pExpr; + char *zName = pOrderByTerm->zName; + assert( pExpr->op==TK_COLUMN && pExpr->iColumnpColl ); */ + if( zName ){ + pExpr->pColl = sqlite3LocateCollSeq(pParse, zName, -1); + }else{ + pExpr->pColl = pKeyInfo->aColl[pExpr->iColumn]; + } + } generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm); } - sqliteFree(pKeyInfo); + if( !pOpenTemp ){ + /* This happens for UNION ALL ... ORDER BY */ + sqliteFree(pKeyInfo); + } } multi_select_end: + if( pOpenTemp ){ + sqlite3IdListDelete(pOpenTemp); + } + p->ppOpenTemp = 0; return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ #ifndef SQLITE_OMIT_VIEW @@ -2064,11 +1965,11 @@ if( pSubSrc->nSrc==0 ) return 0; if( pSub->isDistinct && (pSrc->nSrc>1 || isAgg) ){ return 0; } if( p->isDistinct && subqueryIsAgg ) return 0; - if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ) return 0; + if( p->pOrderBy && pSub->pOrderBy ) return 0; /* Restriction 3: If the subquery is a join, make sure the subquery is ** not used as the right operand of an outer join. Examples of why this ** is not allowed: ** @@ -2116,12 +2017,15 @@ */ iParent = pSubitem->iCursor; { int nSubSrc = pSubSrc->nSrc; int jointype = pSubitem->jointype; + Table *pTab = pSubitem->pTab; - sqlite3DeleteTable(0, pSubitem->pTab); + if( pTab && pTab->isTransient ){ + sqlite3DeleteTable(0, pSubitem->pTab); + } sqliteFree(pSubitem->zDatabase); sqliteFree(pSubitem->zName); sqliteFree(pSubitem->zAlias); if( nSubSrc>1 ){ int extra = nSubSrc - 1; @@ -2155,11 +2059,11 @@ substExprList(p->pEList, iParent, pSub->pEList); pList = p->pEList; for(i=0; inExpr; i++){ Expr *pExpr; if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){ - pList->a[i].zName = sqliteStrNDup((char*)pExpr->span.z, pExpr->span.n); + pList->a[i].zName = sqliteStrNDup(pExpr->span.z, pExpr->span.n); } } if( isAgg ){ substExprList(p->pGroupBy, iParent, pSub->pEList); substExpr(p->pHaving, iParent, pSub->pEList); @@ -2236,15 +2140,14 @@ Table *pTab; Index *pIdx; int base; Vdbe *v; int seekOp; + int cont; ExprList *pEList, *pList, eList; struct ExprList_item eListItem; SrcList *pSrc; - int brk; - int iDb; /* Check to see if this query is a simple min() or max() query. Return ** zero if it is not. */ if( p->pGroupBy || p->pHaving || p->pWhere ) return 0; @@ -2255,22 +2158,21 @@ pExpr = pEList->a[0].pExpr; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; pList = pExpr->pList; if( pList==0 || pList->nExpr!=1 ) return 0; if( pExpr->token.n!=3 ) return 0; - if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){ + if( sqlite3StrNICmp(pExpr->token.z,"min",3)==0 ){ seekOp = OP_Rewind; - }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){ + }else if( sqlite3StrNICmp(pExpr->token.z,"max",3)==0 ){ seekOp = OP_Last; }else{ return 0; } pExpr = pList->a[0].pExpr; if( pExpr->op!=TK_COLUMN ) return 0; iCol = pExpr->iColumn; pTab = pSrc->a[0].pTab; - /* If we get to here, it means the query is of the correct form. ** Check to make sure we have an index and make pIdx point to the ** appropriate index. If the min() or max() is on an INTEGER PRIMARY ** key column, no index is necessary so set pIdx to NULL. If no @@ -2280,14 +2182,11 @@ pIdx = 0; }else{ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nColumn>=1 ); - if( pIdx->aiColumn[0]==iCol && - 0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){ - break; - } + if( pIdx->aiColumn[0]==iCol && pIdx->keyInfo.aColl[0]==pColl ) break; } if( pIdx==0 ) return 0; } /* Identify column types if we will be using the callback. This @@ -2297,29 +2196,27 @@ v = sqlite3GetVdbe(pParse); if( v==0 ) return 0; /* If the output is destined for a temporary table, open that table. */ - if( eDest==SRT_VirtualTab ){ - sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 1); + if( eDest==SRT_TempTable ){ + sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0); + sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, 1); } /* Generating code to find the min or the max. Basically all we have ** to do is find the first or the last entry in the chosen index. If ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first ** or last entry in the main table. */ - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - assert( iDb>=0 || pTab->isTransient ); - sqlite3CodeVerifySchema(pParse, iDb); - sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + sqlite3CodeVerifySchema(pParse, pTab->iDb); base = pSrc->a[0].iCursor; - brk = sqlite3VdbeMakeLabel(v); - computeLimitRegisters(pParse, p, brk); + computeLimitRegisters(pParse, p); if( pSrc->a[0].pSelect==0 ){ - sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead); + sqlite3OpenTableForReading(v, base, pTab); } + cont = sqlite3VdbeMakeLabel(v); if( pIdx==0 ){ sqlite3VdbeAddOp(v, seekOp, base, 0); }else{ /* Even though the cursor used to open the index here is closed ** as soon as a single value has been read from it, allocate it @@ -2326,32 +2223,30 @@ ** using (pParse->nTab++) to prevent the cursor id from being ** reused. This is important for statements of the form ** "INSERT INTO x SELECT max() FROM x". */ int iIdx; - KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); iIdx = pParse->nTab++; - assert( pIdx->pSchema==pTab->pSchema ); - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum, - (char*)pKey, P3_KEYINFO_HANDOFF); + sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum, + (char*)&pIdx->keyInfo, P3_KEYINFO); if( seekOp==OP_Rewind ){ - sqlite3VdbeAddOp(v, OP_Null, 0, 0); + sqlite3VdbeAddOp(v, OP_String, 0, 0); sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0); seekOp = OP_MoveGt; } sqlite3VdbeAddOp(v, seekOp, iIdx, 0); - sqlite3VdbeAddOp(v, OP_IdxRowid, iIdx, 0); + sqlite3VdbeAddOp(v, OP_IdxRecno, iIdx, 0); sqlite3VdbeAddOp(v, OP_Close, iIdx, 0); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); } eList.nExpr = 1; memset(&eListItem, 0, sizeof(eListItem)); eList.a = &eListItem; eList.a[0].pExpr = pExpr; - selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0); - sqlite3VdbeResolveLabel(v, brk); + selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0); + sqlite3VdbeResolveLabel(v, cont); sqlite3VdbeAddOp(v, OP_Close, base, 0); return 1; } @@ -2412,11 +2307,10 @@ NameContext *pOuterNC /* The outer name context. May be NULL. */ ){ ExprList *pEList; /* Result set. */ int i; /* For-loop variable used in multiple places */ NameContext sNC; /* Local name-context */ - ExprList *pGroupBy; /* The group by clause */ /* If this routine has run before, return immediately. */ if( p->isResolved ){ assert( !pOuterNC ); return SQLITE_OK; @@ -2436,12 +2330,18 @@ } /* Resolve the expressions in the LIMIT and OFFSET clauses. These ** are not allowed to refer to any names, so pass an empty NameContext. */ - memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; + sNC.hasAgg = 0; + sNC.nErr = 0; + sNC.nRef = 0; + sNC.pEList = 0; + sNC.allowAgg = 0; + sNC.pSrcList = 0; + sNC.pNext = 0; if( sqlite3ExprResolveNames(&sNC, p->pLimit) || sqlite3ExprResolveNames(&sNC, p->pOffset) ){ return SQLITE_ERROR; } @@ -2449,10 +2349,22 @@ ** resolve the expression-list. */ sNC.allowAgg = 1; sNC.pSrcList = p->pSrc; sNC.pNext = pOuterNC; + + /* NameContext.nDepth stores the depth of recursion for this query. For + ** an outer query (e.g. SELECT * FROM sqlite_master) this is 1. For + ** a subquery it is 2. For a subquery of a subquery, 3. And so on. + ** Parse.nMaxDepth is the maximum depth for any subquery resolved so + ** far. This is used to determine the number of aggregate contexts + ** required at runtime. + */ + sNC.nDepth = (pOuterNC?pOuterNC->nDepth+1:1); + if( sNC.nDepth>pParse->nMaxDepth ){ + pParse->nMaxDepth = sNC.nDepth; + } /* Resolve names in the result set. */ pEList = p->pEList; if( !pEList ) return SQLITE_ERROR; for(i=0; inExpr; i++){ @@ -2464,20 +2376,19 @@ /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( !p->isAgg ); - pGroupBy = p->pGroupBy; - if( pGroupBy || sNC.hasAgg ){ + if( p->pGroupBy || sNC.hasAgg ){ p->isAgg = 1; }else{ sNC.allowAgg = 0; } /* If a HAVING clause is present, then there must be a GROUP BY clause. */ - if( p->pHaving && !pGroupBy ){ + if( p->pHaving && !p->pGroupBy ){ sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); return SQLITE_ERROR; } /* Add the expression list to the name-context before parsing the @@ -2490,132 +2401,53 @@ */ sNC.pEList = p->pEList; if( sqlite3ExprResolveNames(&sNC, p->pWhere) || sqlite3ExprResolveNames(&sNC, p->pHaving) || processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") || - processOrderGroupBy(&sNC, pGroupBy, "GROUP") + processOrderGroupBy(&sNC, p->pGroupBy, "GROUP") ){ return SQLITE_ERROR; } - /* Make sure the GROUP BY clause does not contain aggregate functions. - */ - if( pGroupBy ){ - struct ExprList_item *pItem; - - for(i=0, pItem=pGroupBy->a; inExpr; i++, pItem++){ - if( ExprHasProperty(pItem->pExpr, EP_Agg) ){ - sqlite3ErrorMsg(pParse, "aggregate functions are not allowed in " - "the GROUP BY clause"); - return SQLITE_ERROR; - } - } - } - return SQLITE_OK; } /* -** Reset the aggregate accumulator. -** -** The aggregate accumulator is a set of memory cells that hold -** intermediate results while calculating an aggregate. This -** routine simply stores NULLs in all of those memory cells. -*/ -static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ - Vdbe *v = pParse->pVdbe; - int i; - struct AggInfo_func *pFunc; - if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){ - return; - } - for(i=0; inColumn; i++){ - sqlite3VdbeAddOp(v, OP_MemNull, pAggInfo->aCol[i].iMem, 0); - } - for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){ - sqlite3VdbeAddOp(v, OP_MemNull, pFunc->iMem, 0); - if( pFunc->iDistinct>=0 ){ - Expr *pE = pFunc->pExpr; - if( pE->pList==0 || pE->pList->nExpr!=1 ){ - sqlite3ErrorMsg(pParse, "DISTINCT in aggregate must be followed " - "by an expression"); - pFunc->iDistinct = -1; - }else{ - KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList); - sqlite3VdbeOp3(v, OP_OpenVirtual, pFunc->iDistinct, 0, - (char*)pKeyInfo, P3_KEYINFO_HANDOFF); - } - } - } -} - -/* -** Invoke the OP_AggFinalize opcode for every aggregate function -** in the AggInfo structure. -*/ -static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ - Vdbe *v = pParse->pVdbe; - int i; - struct AggInfo_func *pF; - for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ - ExprList *pList = pF->pExpr->pList; - sqlite3VdbeOp3(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, - (void*)pF->pFunc, P3_FUNCDEF); - } -} - -/* -** Update the accumulator memory cells for an aggregate based on -** the current cursor position. -*/ -static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ - Vdbe *v = pParse->pVdbe; - int i; - struct AggInfo_func *pF; - struct AggInfo_col *pC; - - pAggInfo->directMode = 1; - for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ - int nArg; - int addrNext = 0; - ExprList *pList = pF->pExpr->pList; - if( pList ){ - nArg = pList->nExpr; - sqlite3ExprCodeExprList(pParse, pList); - }else{ - nArg = 0; - } - if( pF->iDistinct>=0 ){ - addrNext = sqlite3VdbeMakeLabel(v); - assert( nArg==1 ); - codeDistinct(v, pF->iDistinct, addrNext, 1, 2); - } - if( pF->pFunc->needCollSeq ){ - CollSeq *pColl = 0; - struct ExprList_item *pItem; - int j; - for(j=0, pItem=pList->a; !pColl && jnExpr; j++, pItem++){ - pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr); - } - if( !pColl ){ - pColl = pParse->db->pDfltColl; - } - sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); - } - sqlite3VdbeOp3(v, OP_AggStep, pF->iMem, nArg, (void*)pF->pFunc, P3_FUNCDEF); - if( addrNext ){ - sqlite3VdbeResolveLabel(v, addrNext); - } - } - for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ - sqlite3ExprCode(pParse, pC->pExpr); - sqlite3VdbeAddOp(v, OP_MemStore, pC->iMem, 1); - } - pAggInfo->directMode = 0; -} - - +** An instance of the following struct is used by sqlite3Select() +** to save aggregate related information from the Parse object +** at the start of each call and to restore it at the end. See +** saveAggregateInfo() and restoreAggregateInfo(). +*/ +struct AggregateInfo { + int nAgg; + AggExpr *aAgg; +}; +typedef struct AggregateInfo AggregateInfo; + +/* +** Copy aggregate related information from the Parse structure +** into the AggregateInfo structure. Zero the aggregate related +** values in the Parse struct. +*/ +static void saveAggregateInfo(Parse *pParse, AggregateInfo *pInfo){ + pInfo->aAgg = pParse->aAgg; + pInfo->nAgg = pParse->nAgg; + pParse->aAgg = 0; + pParse->nAgg = 0; +} + +/* +** Copy aggregate related information from the AggregateInfo struct +** back into the Parse structure. The aggregate related information +** currently stored in the Parse structure is deleted. +*/ +static void restoreAggregateInfo(Parse *pParse, AggregateInfo *pInfo){ + sqliteFree(pParse->aAgg); + pParse->aAgg = pInfo->aAgg; + pParse->nAgg = pInfo->nAgg; +} + /* ** Generate code for the given SELECT statement. ** ** The results are distributed in various ways depending on the ** value of eDest and iParm. @@ -2674,13 +2506,13 @@ Select *pParent, /* Another SELECT for which this is a sub-query */ int parentTab, /* Index in pParent->pSrc of this query */ int *pParentAgg, /* True if pParent uses aggregate functions */ char *aff /* If eDest is SRT_Union, the affinity string */ ){ - int i, j; /* Loop counters */ - WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */ - Vdbe *v; /* The virtual machine under construction */ + int i; + WhereInfo *pWInfo; + Vdbe *v; int isAgg; /* True for select lists like "count(*)" */ ExprList *pEList; /* List of columns to extract. */ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ @@ -2687,36 +2519,26 @@ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ int isDistinct; /* True if the DISTINCT keyword is present */ int distinct; /* Table to use for the distinct set */ int rc = 1; /* Value to return from this function */ - int addrSortIndex; /* Address of an OP_OpenVirtual instruction */ - AggInfo sAggInfo; /* Information used by aggregate queries */ - int iEnd; /* Address of the end of the query */ - - if( p==0 || sqlite3ThreadDataReadOnly()->mallocFailed || pParse->nErr ){ - return 1; - } - if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; - memset(&sAggInfo, 0, sizeof(sAggInfo)); + AggregateInfo sAggInfo; + + if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1; + if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; #ifndef SQLITE_OMIT_COMPOUND_SELECT /* If there is are a sequence of queries, do the earlier ones first. */ if( p->pPrior ){ - if( p->pRightmost==0 ){ - Select *pLoop; - for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ - pLoop->pRightmost = p; - } - } return multiSelect(pParse, p, eDest, iParm, aff); } #endif + saveAggregateInfo(pParse, &sAggInfo); pOrderBy = p->pOrderBy; - if( IgnorableOrderby(eDest) ){ + if( eDest==SRT_Union || eDest==SRT_Except || eDest==SRT_Discard ){ p->pOrderBy = 0; } if( sqlite3SelectResolve(pParse, p, 0) ){ goto select_end; } @@ -2740,10 +2562,11 @@ if( pParse->nErr>0 ) goto select_end; /* If writing to memory or generating a set ** only a single column may be output. */ + assert( eDest!=SRT_Exists || pEList->nExpr==1 ); #ifndef SQLITE_OMIT_SUBQUERY if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){ sqlite3ErrorMsg(pParse, "only a single result allowed for " "a SELECT that is part of an expression"); goto select_end; @@ -2750,12 +2573,18 @@ } #endif /* ORDER BY is ignored for some destinations. */ - if( IgnorableOrderby(eDest) ){ - pOrderBy = 0; + switch( eDest ){ + case SRT_Union: + case SRT_Except: + case SRT_Discard: + pOrderBy = 0; + break; + default: + break; } /* Begin generating code. */ v = sqlite3GetVdbe(pParse); @@ -2772,28 +2601,27 @@ */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; inSrc; i++){ const char *zSavedAuthContext = 0; int needRestoreContext; - struct SrcList_item *pItem = &pTabList->a[i]; - if( pItem->pSelect==0 ) continue; - if( pItem->zName!=0 ){ + if( pTabList->a[i].pSelect==0 ) continue; + if( pTabList->a[i].zName!=0 ){ zSavedAuthContext = pParse->zAuthContext; - pParse->zAuthContext = pItem->zName; + pParse->zAuthContext = pTabList->a[i].zName; needRestoreContext = 1; }else{ needRestoreContext = 0; } - sqlite3Select(pParse, pItem->pSelect, SRT_VirtualTab, - pItem->iCursor, p, i, &isAgg, 0); + sqlite3Select(pParse, pTabList->a[i].pSelect, SRT_TempTable, + pTabList->a[i].iCursor, p, i, &isAgg, 0); if( needRestoreContext ){ pParse->zAuthContext = zSavedAuthContext; } pTabList = p->pSrc; pWhere = p->pWhere; - if( !IgnorableOrderby(eDest) ){ + if( eDest!=SRT_Union && eDest!=SRT_Except && eDest!=SRT_Discard ){ pOrderBy = p->pOrderBy; } pGroupBy = p->pGroupBy; pHaving = p->pHaving; isDistinct = p->isDistinct; @@ -2818,350 +2646,203 @@ goto select_end; } #endif /* If there is an ORDER BY clause, resolve any collation sequences - ** names that have been explicitly specified and create a sorting index. - ** - ** This sorting index might end up being unused if the data can be - ** extracted in pre-sorted order. If that is the case, then the - ** OP_OpenVirtual instruction will be changed to an OP_Noop once - ** we figure out that the sorting index is not needed. The addrSortIndex - ** variable is used to facilitate that change. + ** names that have been explicitly specified. */ if( pOrderBy ){ - struct ExprList_item *pTerm; - KeyInfo *pKeyInfo; - for(i=0, pTerm=pOrderBy->a; inExpr; i++, pTerm++){ - if( pTerm->zName ){ - pTerm->pExpr->pColl = sqlite3LocateCollSeq(pParse, pTerm->zName, -1); + for(i=0; inExpr; i++){ + if( pOrderBy->a[i].zName ){ + pOrderBy->a[i].pExpr->pColl = + sqlite3LocateCollSeq(pParse, pOrderBy->a[i].zName, -1); } } if( pParse->nErr ){ goto select_end; } - pKeyInfo = keyInfoFromExprList(pParse, pOrderBy); - pOrderBy->iECursor = pParse->nTab++; - p->addrOpenVirt[2] = addrSortIndex = - sqlite3VdbeOp3(v, OP_OpenVirtual, pOrderBy->iECursor, pOrderBy->nExpr+2, - (char*)pKeyInfo, P3_KEYINFO_HANDOFF); - }else{ - addrSortIndex = -1; } /* Set the limiter. */ - iEnd = sqlite3VdbeMakeLabel(v); - computeLimitRegisters(pParse, p, iEnd); + computeLimitRegisters(pParse, p); /* If the output is destined for a temporary table, open that table. */ - if( eDest==SRT_VirtualTab ){ - sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr); - } - - /* Open a virtual index to use for the distinct set. - */ - if( isDistinct ){ - KeyInfo *pKeyInfo; - distinct = pParse->nTab++; - pKeyInfo = keyInfoFromExprList(pParse, p->pEList); - sqlite3VdbeOp3(v, OP_OpenVirtual, distinct, 0, - (char*)pKeyInfo, P3_KEYINFO_HANDOFF); - }else{ - distinct = -1; - } - - /* Aggregate and non-aggregate queries are handled differently */ - if( !isAgg && pGroupBy==0 ){ - /* This case is for non-aggregate queries - ** Begin the database scan - */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy); - if( pWInfo==0 ) goto select_end; - - /* If sorting index that was created by a prior OP_OpenVirtual - ** instruction ended up not being needed, then change the OP_OpenVirtual - ** into an OP_Noop. - */ - if( addrSortIndex>=0 && pOrderBy==0 ){ - uncreateSortingIndex(pParse, addrSortIndex); - p->addrOpenVirt[2] = -1; - } - - /* Use the standard inner loop - */ - if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, - iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){ - goto select_end; - } - - /* End the database scan loop. - */ - sqlite3WhereEnd(pWInfo); - }else{ - /* This is the processing for aggregate queries */ - NameContext sNC; /* Name context for processing aggregate information */ - int iAMem; /* First Mem address for storing current GROUP BY */ - int iBMem; /* First Mem address for previous GROUP BY */ - int iUseFlag; /* Mem address holding flag indicating that at least - ** one row of the input to the aggregator has been - ** processed */ - int iAbortFlag; /* Mem address which causes query abort if positive */ - int groupBySort; /* Rows come from source in GROUP BY order */ - - - /* The following variables hold addresses or labels for parts of the - ** virtual machine program we are putting together */ - int addrOutputRow; /* Start of subroutine that outputs a result row */ - int addrSetAbort; /* Set the abort flag and return */ - int addrInitializeLoop; /* Start of code that initializes the input loop */ - int addrTopOfLoop; /* Top of the input loop */ - int addrGroupByChange; /* Code that runs when any GROUP BY term changes */ - int addrProcessRow; /* Code to process a single input row */ - int addrEnd; /* End of all processing */ - int addrSortingIdx; /* The OP_OpenVirtual for the sorting index */ - int addrReset; /* Subroutine for resetting the accumulator */ - - addrEnd = sqlite3VdbeMakeLabel(v); - - /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in - ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the - ** SELECT statement. - */ + if( eDest==SRT_TempTable ){ + sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0); + sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr); + } + + /* Do an analysis of aggregate expressions. + */ + if( isAgg || pGroupBy ){ + NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; - sNC.pAggInfo = &sAggInfo; - sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; - sAggInfo.pGroupBy = pGroupBy; - if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){ - goto select_end; - } - if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){ - goto select_end; + + assert( pParse->nAgg==0 ); + isAgg = 1; + for(i=0; inExpr; i++){ + if( sqlite3ExprAnalyzeAggregates(&sNC, pEList->a[i].pExpr) ){ + goto select_end; + } + } + if( pGroupBy ){ + for(i=0; inExpr; i++){ + if( sqlite3ExprAnalyzeAggregates(&sNC, pGroupBy->a[i].pExpr) ){ + goto select_end; + } + } } if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){ goto select_end; } - sAggInfo.nAccumulator = sAggInfo.nColumn; - for(i=0; ipList) ){ - goto select_end; - } - } - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto select_end; - - /* Processing for aggregates with GROUP BY is very different and - ** much more complex tha aggregates without a GROUP BY. - */ - if( pGroupBy ){ - KeyInfo *pKeyInfo; /* Keying information for the group by clause */ - - /* Create labels that we will be needing - */ - - addrInitializeLoop = sqlite3VdbeMakeLabel(v); - addrGroupByChange = sqlite3VdbeMakeLabel(v); - addrProcessRow = sqlite3VdbeMakeLabel(v); - - /* If there is a GROUP BY clause we might need a sorting index to - ** implement it. Allocate that sorting index now. If it turns out - ** that we do not need it after all, the OpenVirtual instruction - ** will be converted into a Noop. - */ - sAggInfo.sortingIdx = pParse->nTab++; - pKeyInfo = keyInfoFromExprList(pParse, pGroupBy); - addrSortingIdx = - sqlite3VdbeOp3(v, OP_OpenVirtual, sAggInfo.sortingIdx, - sAggInfo.nSortingColumn, - (char*)pKeyInfo, P3_KEYINFO_HANDOFF); - - /* Initialize memory locations used by GROUP BY aggregate processing - */ - iUseFlag = pParse->nMem++; - iAbortFlag = pParse->nMem++; - iAMem = pParse->nMem; - pParse->nMem += pGroupBy->nExpr; - iBMem = pParse->nMem; - pParse->nMem += pGroupBy->nExpr; - sqlite3VdbeAddOp(v, OP_MemInt, 0, iAbortFlag); - VdbeComment((v, "# clear abort flag")); - sqlite3VdbeAddOp(v, OP_MemInt, 0, iUseFlag); - VdbeComment((v, "# indicate accumulator empty")); - sqlite3VdbeAddOp(v, OP_Goto, 0, addrInitializeLoop); - - /* Generate a subroutine that outputs a single row of the result - ** set. This subroutine first looks at the iUseFlag. If iUseFlag - ** is less than or equal to zero, the subroutine is a no-op. If - ** the processing calls for the query to abort, this subroutine - ** increments the iAbortFlag memory location before returning in - ** order to signal the caller to abort. - */ - addrSetAbort = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp(v, OP_MemInt, 1, iAbortFlag); - VdbeComment((v, "# set abort flag")); - sqlite3VdbeAddOp(v, OP_Return, 0, 0); - addrOutputRow = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp(v, OP_IfMemPos, iUseFlag, addrOutputRow+2); - VdbeComment((v, "# Groupby result generator entry point")); - sqlite3VdbeAddOp(v, OP_Return, 0, 0); - finalizeAggFunctions(pParse, &sAggInfo); - if( pHaving ){ - sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, 1); - } - rc = selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy, - distinct, eDest, iParm, - addrOutputRow+1, addrSetAbort, aff); - if( rc ){ - goto select_end; - } - sqlite3VdbeAddOp(v, OP_Return, 0, 0); - VdbeComment((v, "# end groupby result generator")); - - /* Generate a subroutine that will reset the group-by accumulator - */ - addrReset = sqlite3VdbeCurrentAddr(v); - resetAccumulator(pParse, &sAggInfo); - sqlite3VdbeAddOp(v, OP_Return, 0, 0); - - /* Begin a loop that will extract all source rows in GROUP BY order. - ** This might involve two separate loops with an OP_Sort in between, or - ** it might be a single loop that uses an index to extract information - ** in the right order to begin with. - */ - sqlite3VdbeResolveLabel(v, addrInitializeLoop); - sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy); - if( pWInfo==0 ) goto select_end; - if( pGroupBy==0 ){ - /* The optimizer is able to deliver rows in group by order so - ** we do not have to sort. The OP_OpenVirtual table will be - ** cancelled later because we still need to use the pKeyInfo - */ - pGroupBy = p->pGroupBy; - groupBySort = 0; - }else{ - /* Rows are coming out in undetermined order. We have to push - ** each row into a sorting index, terminate the first loop, - ** then loop over the sorting index in order to get the output - ** in sorted order - */ - groupBySort = 1; - sqlite3ExprCodeExprList(pParse, pGroupBy); - sqlite3VdbeAddOp(v, OP_Sequence, sAggInfo.sortingIdx, 0); - j = pGroupBy->nExpr+1; - for(i=0; iiSorterColumniColumn<0 ){ - sqlite3VdbeAddOp(v, OP_Rowid, pCol->iTable, 0); - }else{ - sqlite3VdbeAddOp(v, OP_Column, pCol->iTable, pCol->iColumn); - } - j++; - } - sqlite3VdbeAddOp(v, OP_MakeRecord, j, 0); - sqlite3VdbeAddOp(v, OP_IdxInsert, sAggInfo.sortingIdx, 0); - sqlite3WhereEnd(pWInfo); - sqlite3VdbeAddOp(v, OP_Sort, sAggInfo.sortingIdx, addrEnd); - VdbeComment((v, "# GROUP BY sort")); - sAggInfo.useSortingIdx = 1; - } - - /* Evaluate the current GROUP BY terms and store in b0, b1, b2... - ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) - ** Then compare the current GROUP BY terms against the GROUP BY terms - ** from the previous row currently stored in a0, a1, a2... - */ - addrTopOfLoop = sqlite3VdbeCurrentAddr(v); - for(j=0; jnExpr; j++){ - if( groupBySort ){ - sqlite3VdbeAddOp(v, OP_Column, sAggInfo.sortingIdx, j); - }else{ - sAggInfo.directMode = 1; - sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr); - } - sqlite3VdbeAddOp(v, OP_MemStore, iBMem+j, jnExpr-1); - } - for(j=pGroupBy->nExpr-1; j>=0; j--){ - if( jnExpr-1 ){ - sqlite3VdbeAddOp(v, OP_MemLoad, iBMem+j, 0); - } - sqlite3VdbeAddOp(v, OP_MemLoad, iAMem+j, 0); - if( j==0 ){ - sqlite3VdbeAddOp(v, OP_Eq, 0x200, addrProcessRow); - }else{ - sqlite3VdbeAddOp(v, OP_Ne, 0x200, addrGroupByChange); - } - sqlite3VdbeChangeP3(v, -1, (void*)pKeyInfo->aColl[j], P3_COLLSEQ); - } - - /* Generate code that runs whenever the GROUP BY changes. - ** Change in the GROUP BY are detected by the previous code - ** block. If there were no changes, this block is skipped. - ** - ** This code copies current group by terms in b0,b1,b2,... - ** over to a0,a1,a2. It then calls the output subroutine - ** and resets the aggregate accumulator registers in preparation - ** for the next GROUP BY batch. - */ - sqlite3VdbeResolveLabel(v, addrGroupByChange); - for(j=0; jnExpr; j++){ - sqlite3VdbeAddOp(v, OP_MemMove, iAMem+j, iBMem+j); - } - sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow); - VdbeComment((v, "# output one row")); - sqlite3VdbeAddOp(v, OP_IfMemPos, iAbortFlag, addrEnd); - VdbeComment((v, "# check abort flag")); - sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset); - VdbeComment((v, "# reset accumulator")); - - /* Update the aggregate accumulators based on the content of - ** the current row - */ - sqlite3VdbeResolveLabel(v, addrProcessRow); - updateAccumulator(pParse, &sAggInfo); - sqlite3VdbeAddOp(v, OP_MemInt, 1, iUseFlag); - VdbeComment((v, "# indicate data in accumulator")); - - /* End of the loop - */ - if( groupBySort ){ - sqlite3VdbeAddOp(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop); - }else{ - sqlite3WhereEnd(pWInfo); - uncreateSortingIndex(pParse, addrSortingIdx); - } - - /* Output the final row of result - */ - sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow); - VdbeComment((v, "# output final row")); - - } /* endif pGroupBy */ - else { - /* This case runs if the aggregate has no GROUP BY clause. The - ** processing is much simpler since there is only a single row - ** of output. - */ - resetAccumulator(pParse, &sAggInfo); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); - if( pWInfo==0 ) goto select_end; - updateAccumulator(pParse, &sAggInfo); - sqlite3WhereEnd(pWInfo); - finalizeAggFunctions(pParse, &sAggInfo); - pOrderBy = 0; - if( pHaving ){ - sqlite3ExprIfFalse(pParse, pHaving, addrEnd, 1); - } - selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1, - eDest, iParm, addrEnd, addrEnd, aff); - } - sqlite3VdbeResolveLabel(v, addrEnd); - - } /* endif aggregate query */ + if( pOrderBy ){ + for(i=0; inExpr; i++){ + if( sqlite3ExprAnalyzeAggregates(&sNC, pOrderBy->a[i].pExpr) ){ + goto select_end; + } + } + } + } + + /* Reset the aggregator + */ + if( isAgg ){ + int addr = sqlite3VdbeAddOp(v, OP_AggReset, (pGroupBy?0:1), pParse->nAgg); + for(i=0; inAgg; i++){ + FuncDef *pFunc; + if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){ + sqlite3VdbeOp3(v, OP_AggInit, 0, i, (char*)pFunc, P3_FUNCDEF); + } + } + if( pGroupBy ){ + int sz = sizeof(KeyInfo) + pGroupBy->nExpr*sizeof(CollSeq*); + KeyInfo *pKey = (KeyInfo *)sqliteMalloc(sz); + if( 0==pKey ){ + goto select_end; + } + pKey->enc = pParse->db->enc; + pKey->nField = pGroupBy->nExpr; + for(i=0; inExpr; i++){ + pKey->aColl[i] = sqlite3ExprCollSeq(pParse, pGroupBy->a[i].pExpr); + if( !pKey->aColl[i] ){ + pKey->aColl[i] = pParse->db->pDfltColl; + } + } + sqlite3VdbeChangeP3(v, addr, (char *)pKey, P3_KEYINFO_HANDOFF); + } + } + + /* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists + */ + if( eDest==SRT_Mem || eDest==SRT_Exists ){ + sqlite3VdbeAddOp(v, eDest==SRT_Mem ? OP_String8 : OP_Integer, 0, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); + } + + /* Open a temporary table to use for the distinct set. + */ + if( isDistinct ){ + distinct = pParse->nTab++; + openTempIndex(pParse, p, distinct, 0); + }else{ + distinct = -1; + } + + /* Begin the database scan + */ + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, + pGroupBy ? 0 : &pOrderBy, p->pFetch); + if( pWInfo==0 ) goto select_end; + + /* Use the standard inner loop if we are not dealing with + ** aggregates + */ + if( !isAgg ){ + if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, + iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){ + goto select_end; + } + } + + /* If we are dealing with aggregates, then do the special aggregate + ** processing. + */ + else{ + AggExpr *pAgg; + int lbl1 = 0; + pParse->fillAgg = 1; + if( pGroupBy ){ + for(i=0; inExpr; i++){ + sqlite3ExprCode(pParse, pGroupBy->a[i].pExpr); + } + /* No affinity string is attached to the following OP_MakeRecord + ** because we do not need to do any coercion of datatypes. */ + sqlite3VdbeAddOp(v, OP_MakeRecord, pGroupBy->nExpr, 0); + lbl1 = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp(v, OP_AggFocus, 0, lbl1); + } + for(i=0, pAgg=pParse->aAgg; inAgg; i++, pAgg++){ + if( pAgg->isAgg ) continue; + sqlite3ExprCode(pParse, pAgg->pExpr); + sqlite3VdbeAddOp(v, OP_AggSet, 0, i); + } + pParse->fillAgg = 0; + if( lbl1<0 ){ + sqlite3VdbeResolveLabel(v, lbl1); + } + for(i=0, pAgg=pParse->aAgg; inAgg; i++, pAgg++){ + Expr *pE; + int nExpr; + FuncDef *pDef; + if( !pAgg->isAgg ) continue; + assert( pAgg->pFunc!=0 ); + assert( pAgg->pFunc->xStep!=0 ); + pDef = pAgg->pFunc; + pE = pAgg->pExpr; + assert( pE!=0 ); + assert( pE->op==TK_AGG_FUNCTION ); + nExpr = sqlite3ExprCodeExprList(pParse, pE->pList); + sqlite3VdbeAddOp(v, OP_Integer, i, 0); + if( pDef->needCollSeq ){ + CollSeq *pColl = 0; + int j; + for(j=0; !pColl && jpList->a[j].pExpr); + } + if( !pColl ) pColl = pParse->db->pDfltColl; + sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); + } + sqlite3VdbeOp3(v, OP_AggFunc, 0, nExpr, (char*)pDef, P3_POINTER); + } + } + + /* End the database scan loop. + */ + sqlite3WhereEnd(pWInfo); + + /* If we are processing aggregates, we need to set up a second loop + ** over all of the aggregate values and process them. + */ + if( isAgg ){ + int endagg = sqlite3VdbeMakeLabel(v); + int startagg; + startagg = sqlite3VdbeAddOp(v, OP_AggNext, 0, endagg); + if( pHaving ){ + sqlite3ExprIfFalse(pParse, pHaving, startagg, 1); + } + if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, + iParm, startagg, endagg, aff) ){ + goto select_end; + } + sqlite3VdbeAddOp(v, OP_Goto, 0, startagg); + sqlite3VdbeResolveLabel(v, endagg); + sqlite3VdbeAddOp(v, OP_Noop, 0, 0); + } /* If there is an ORDER BY clause, then we need to sort the results ** and send them to the callback one by one. */ if( pOrderBy ){ @@ -3180,22 +2861,17 @@ sqlite3SelectDelete(p); pParent->pSrc->a[parentTab].pSelect = 0; } #endif - /* Jump here to skip this query - */ - sqlite3VdbeResolveLabel(v, iEnd); - /* The SELECT was successfully coded. Set the return code to 0 ** to indicate no errors. */ rc = 0; /* Control jumps to here if an error is encountered above, or upon ** successful coding of the SELECT. */ select_end: - sqliteFree(sAggInfo.aCol); - sqliteFree(sAggInfo.aFunc); + restoreAggregateInfo(pParse, &sAggInfo); return rc; } DELETED SQLite.Interop/src/server.c Index: SQLite.Interop/src/server.c ================================================================== --- SQLite.Interop/src/server.c +++ /dev/null @@ -1,485 +0,0 @@ -/* -** 2006 January 07 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains demonstration code. Nothing in this file gets compiled -** or linked into the SQLite library unless you use a non-standard option: -** -** -DSQLITE_SERVER=1 -** -** The configure script will never generate a Makefile with the option -** above. You will need to manually modify the Makefile if you want to -** include any of the code from this file in your project. Or, at your -** option, you may copy and paste the code from this file and -** thereby avoiding a recompile of SQLite. -** -** -** This source file demonstrates how to use SQLite to create an SQL database -** server thread in a multiple-threaded program. One or more client threads -** send messages to the server thread and the server thread processes those -** messages in the order received and returns the results to the client. -** -** One might ask: "Why bother? Why not just let each thread connect -** to the database directly?" There are a several of reasons to -** prefer the client/server approach. -** -** (1) Some systems (ex: Redhat9) have broken threading implementations -** that prevent SQLite database connections from being used in -** a thread different from the one where they were created. With -** the client/server approach, all database connections are created -** and used within the server thread. Client calls to the database -** can be made from multiple threads (though not at the same time!) -** -** (2) Beginning with SQLite version 3.3.0, when two or more -** connections to the same database occur within the same thread, -** they can optionally share their database cache. This reduces -** I/O and memory requirements. Cache shared is controlled using -** the sqlite3_enable_shared_cache() API. -** -** (3) Database connections on a shared cache use table-level locking -** instead of file-level locking for improved concurrency. -** -** (4) Database connections on a shared cache can by optionally -** set to READ UNCOMMITTED isolation. (The default isolation for -** SQLite is SERIALIZABLE.) When this occurs, readers will -** never be blocked by a writer and writers will not be -** blocked by readers. There can still only be a single writer -** at a time, but multiple readers can simultaneously exist with -** that writer. This is a huge increase in concurrency. -** -** To summarize the rational for using a client/server approach: prior -** to SQLite version 3.3.0 it probably was not worth the trouble. But -** with SQLite version 3.3.0 and beyond you can get significant performance -** and concurrency improvements and memory usage reductions by going -** client/server. -** -** Note: The extra features of version 3.3.0 described by points (2) -** through (4) above are only available if you compile without the -** option -DSQLITE_OMIT_SHARED_CACHE. -** -** Here is how the client/server approach works: The database server -** thread is started on this procedure: -** -** void *sqlite3_server(void *NotUsed); -** -** The sqlite_server procedure runs as long as the g.serverHalt variable -** is false. A mutex is used to make sure no more than one server runs -** at a time. The server waits for messages to arrive on a message -** queue and processes the messages in order. -** -** Two convenience routines are provided for starting and stopping the -** server thread: -** -** void sqlite3_server_start(void); -** void sqlite3_server_stop(void); -** -** Both of the convenience routines return immediately. Neither will -** ever give an error. If a server is already started or already halted, -** then the routines are effectively no-ops. -** -** Clients use the following interfaces: -** -** sqlite3_client_open -** sqlite3_client_prepare -** sqlite3_client_step -** sqlite3_client_reset -** sqlite3_client_finalize -** sqlite3_client_close -** -** These interfaces work exactly like the standard core SQLite interfaces -** having the same names without the "_client_" infix. Many other SQLite -** interfaces can be used directly without having to send messages to the -** server as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. -** The following interfaces fall into this second category: -** -** sqlite3_bind_* -** sqlite3_changes -** sqlite3_clear_bindings -** sqlite3_column_* -** sqlite3_complete -** sqlite3_create_collation -** sqlite3_create_function -** sqlite3_data_count -** sqlite3_db_handle -** sqlite3_errcode -** sqlite3_errmsg -** sqlite3_last_insert_rowid -** sqlite3_total_changes -** sqlite3_transfer_bindings -** -** A single SQLite connection (an sqlite3* object) or an SQLite statement -** (an sqlite3_stmt* object) should only be passed to a single interface -** function at a time. The connections and statements can be passed from -** any thread to any of the functions listed in the second group above as -** long as the same connection is not in use by two threads at once and -** as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. Additional -** information about the SQLITE_ENABLE_MEMORY_MANAGEMENT constraint is -** below. -** -** The busy handler for all database connections should remain turned -** off. That means that any lock contention will cause the associated -** sqlite3_client_step() call to return immediately with an SQLITE_BUSY -** error code. If a busy handler is enabled and lock contention occurs, -** then the entire server thread will block. This will cause not only -** the requesting client to block but every other database client as -** well. It is possible to enhance the code below so that lock -** contention will cause the message to be placed back on the top of -** the queue to be tried again later. But such enhanced processing is -** not included here, in order to keep the example simple. -** -** This example code assumes the use of pthreads. Pthreads -** implementations are available for windows. (See, for example -** http://sourceware.org/pthreads-win32/announcement.html.) Or, you -** can translate the locking and thread synchronization code to use -** windows primitives easily enough. The details are left as an -** exercise to the reader. -** -**** Restrictions Associated With SQLITE_ENABLE_MEMORY_MANAGEMENT **** -** -** If you compile with SQLITE_ENABLE_MEMORY_MANAGEMENT defined, then -** SQLite includes code that tracks how much memory is being used by -** each thread. These memory counts can become confused if memory -** is allocated by one thread and then freed by another. For that -** reason, when SQLITE_ENABLE_MEMORY_MANAGEMENT is used, all operations -** that might allocate or free memory should be performanced in the same -** thread that originally created the database connection. In that case, -** many of the operations that are listed above as safe to be performed -** in separate threads would need to be sent over to the server to be -** done there. If SQLITE_ENABLE_MEMORY_MANAGEMENT is defined, then -** the following functions can be used safely from different threads -** without messing up the allocation counts: -** -** sqlite3_bind_parameter_name -** sqlite3_bind_parameter_index -** sqlite3_changes -** sqlite3_column_blob -** sqlite3_column_count -** sqlite3_complete -** sqlite3_data_count -** sqlite3_db_handle -** sqlite3_errcode -** sqlite3_errmsg -** sqlite3_last_insert_rowid -** sqlite3_total_changes -** -** The remaining functions are not thread-safe when memory management -** is enabled. So one would have to define some new interface routines -** along the following lines: -** -** sqlite3_client_bind_* -** sqlite3_client_clear_bindings -** sqlite3_client_column_* -** sqlite3_client_create_collation -** sqlite3_client_create_function -** sqlite3_client_transfer_bindings -** -** The example code in this file is intended for use with memory -** management turned off. So the implementation of these additional -** client interfaces is left as an exercise to the reader. -** -** It may seem surprising to the reader that the list of safe functions -** above does not include things like sqlite3_bind_int() or -** sqlite3_column_int(). But those routines might, in fact, allocate -** or deallocate memory. In the case of sqlite3_bind_int(), if the -** parameter was previously bound to a string that string might need -** to be deallocated before the new integer value is inserted. In -** the case of sqlite3_column_int(), the value of the column might be -** a UTF-16 string which will need to be converted to UTF-8 then into -** an integer. -*/ - -/* -** Only compile the code in this file on UNIX with a THREADSAFE build -** and only if the SQLITE_SERVER macro is defined. -*/ -#ifdef SQLITE_SERVER -#if defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE - -/* -** We require only pthreads and the public interface of SQLite. -*/ -#include -#include "sqlite3.h" - -/* -** Messages are passed from client to server and back again as -** instances of the following structure. -*/ -typedef struct SqlMessage SqlMessage; -struct SqlMessage { - int op; /* Opcode for the message */ - sqlite3 *pDb; /* The SQLite connection */ - sqlite3_stmt *pStmt; /* A specific statement */ - int errCode; /* Error code returned */ - const char *zIn; /* Input filename or SQL statement */ - int nByte; /* Size of the zIn parameter for prepare() */ - const char *zOut; /* Tail of the SQL statement */ - SqlMessage *pNext; /* Next message in the queue */ - SqlMessage *pPrev; /* Previous message in the queue */ - pthread_mutex_t clientMutex; /* Hold this mutex to access the message */ - pthread_cond_t clientWakeup; /* Signal to wake up the client */ -}; - -/* -** Legal values for SqlMessage.op -*/ -#define MSG_Open 1 /* sqlite3_open(zIn, &pDb) */ -#define MSG_Prepare 2 /* sqlite3_prepare(pDb, zIn, nByte, &pStmt, &zOut) */ -#define MSG_Step 3 /* sqlite3_step(pStmt) */ -#define MSG_Reset 4 /* sqlite3_reset(pStmt) */ -#define MSG_Finalize 5 /* sqlite3_finalize(pStmt) */ -#define MSG_Close 6 /* sqlite3_close(pDb) */ -#define MSG_Done 7 /* Server has finished with this message */ - - -/* -** State information about the server is stored in a static variable -** named "g" as follows: -*/ -static struct ServerState { - pthread_mutex_t queueMutex; /* Hold this mutex to access the msg queue */ - pthread_mutex_t serverMutex; /* Held by the server while it is running */ - pthread_cond_t serverWakeup; /* Signal this condvar to wake up the server */ - volatile int serverHalt; /* Server halts itself when true */ - SqlMessage *pQueueHead; /* Head of the message queue */ - SqlMessage *pQueueTail; /* Tail of the message queue */ -} g = { - PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, - PTHREAD_COND_INITIALIZER, -}; - -/* -** Send a message to the server. Block until we get a reply. -** -** The mutex and condition variable in the message are uninitialized -** when this routine is called. This routine takes care of -** initializing them and destroying them when it has finished. -*/ -static void sendToServer(SqlMessage *pMsg){ - /* Initialize the mutex and condition variable on the message - */ - pthread_mutex_init(&pMsg->clientMutex, 0); - pthread_cond_init(&pMsg->clientWakeup, 0); - - /* Add the message to the head of the server's message queue. - */ - pthread_mutex_lock(&g.queueMutex); - pMsg->pNext = g.pQueueHead; - if( g.pQueueHead==0 ){ - g.pQueueTail = pMsg; - }else{ - g.pQueueHead->pPrev = pMsg; - } - pMsg->pPrev = 0; - g.pQueueHead = pMsg; - pthread_mutex_unlock(&g.queueMutex); - - /* Signal the server that the new message has be queued, then - ** block waiting for the server to process the message. - */ - pthread_mutex_lock(&pMsg->clientMutex); - pthread_cond_signal(&g.serverWakeup); - while( pMsg->op!=MSG_Done ){ - pthread_cond_wait(&pMsg->clientWakeup, &pMsg->clientMutex); - } - pthread_mutex_unlock(&pMsg->clientMutex); - - /* Destroy the mutex and condition variable of the message. - */ - pthread_mutex_destroy(&pMsg->clientMutex); - pthread_cond_destroy(&pMsg->clientWakeup); -} - -/* -** The following 6 routines are client-side implementations of the -** core SQLite interfaces: -** -** sqlite3_open -** sqlite3_prepare -** sqlite3_step -** sqlite3_reset -** sqlite3_finalize -** sqlite3_close -** -** Clients should use the following client-side routines instead of -** the core routines above. -** -** sqlite3_client_open -** sqlite3_client_prepare -** sqlite3_client_step -** sqlite3_client_reset -** sqlite3_client_finalize -** sqlite3_client_close -** -** Each of these routines creates a message for the desired operation, -** sends that message to the server, waits for the server to process -** then message and return a response. -*/ -int sqlite3_client_open(const char *zDatabaseName, sqlite3 **ppDb){ - SqlMessage msg; - msg.op = MSG_Open; - msg.zIn = zDatabaseName; - sendToServer(&msg); - *ppDb = msg.pDb; - return msg.errCode; -} -int sqlite3_client_prepare( - sqlite3 *pDb, - const char *zSql, - int nByte, - sqlite3_stmt **ppStmt, - const char **pzTail -){ - SqlMessage msg; - msg.op = MSG_Prepare; - msg.pDb = pDb; - msg.zIn = zSql; - msg.nByte = nByte; - sendToServer(&msg); - *ppStmt = msg.pStmt; - if( pzTail ) *pzTail = msg.zOut; - return msg.errCode; -} -int sqlite3_client_step(sqlite3_stmt *pStmt){ - SqlMessage msg; - msg.op = MSG_Step; - msg.pStmt = pStmt; - sendToServer(&msg); - return msg.errCode; -} -int sqlite3_client_reset(sqlite3_stmt *pStmt){ - SqlMessage msg; - msg.op = MSG_Reset; - msg.pStmt = pStmt; - sendToServer(&msg); - return msg.errCode; -} -int sqlite3_client_finalize(sqlite3_stmt *pStmt){ - SqlMessage msg; - msg.op = MSG_Finalize; - msg.pStmt = pStmt; - sendToServer(&msg); - return msg.errCode; -} -int sqlite3_client_close(sqlite3 *pDb){ - SqlMessage msg; - msg.op = MSG_Close; - msg.pDb = pDb; - sendToServer(&msg); - return msg.errCode; -} - -/* -** This routine implements the server. To start the server, first -** make sure g.serverHalt is false, then create a new detached thread -** on this procedure. See the sqlite3_server_start() routine below -** for an example. This procedure loops until g.serverHalt becomes -** true. -*/ -void *sqlite3_server(void *NotUsed){ - sqlite3_enable_shared_cache(1); - if( pthread_mutex_trylock(&g.serverMutex) ){ - sqlite3_enable_shared_cache(0); - return 0; /* Another server is already running */ - } - while( !g.serverHalt ){ - SqlMessage *pMsg; - - /* Remove the last message from the message queue. - */ - pthread_mutex_lock(&g.queueMutex); - while( g.pQueueTail==0 && g.serverHalt==0 ){ - pthread_cond_wait(&g.serverWakeup, &g.queueMutex); - } - pMsg = g.pQueueTail; - if( pMsg ){ - if( pMsg->pPrev ){ - pMsg->pPrev->pNext = 0; - }else{ - g.pQueueHead = 0; - } - g.pQueueTail = pMsg->pPrev; - } - pthread_mutex_unlock(&g.queueMutex); - if( pMsg==0 ) break; - - /* Process the message just removed - */ - pthread_mutex_lock(&pMsg->clientMutex); - switch( pMsg->op ){ - case MSG_Open: { - pMsg->errCode = sqlite3_open(pMsg->zIn, &pMsg->pDb); - break; - } - case MSG_Prepare: { - pMsg->errCode = sqlite3_prepare(pMsg->pDb, pMsg->zIn, pMsg->nByte, - &pMsg->pStmt, &pMsg->zOut); - break; - } - case MSG_Step: { - pMsg->errCode = sqlite3_step(pMsg->pStmt); - break; - } - case MSG_Reset: { - pMsg->errCode = sqlite3_reset(pMsg->pStmt); - break; - } - case MSG_Finalize: { - pMsg->errCode = sqlite3_finalize(pMsg->pStmt); - break; - } - case MSG_Close: { - pMsg->errCode = sqlite3_close(pMsg->pDb); - break; - } - } - - /* Signal the client that the message has been processed. - */ - pMsg->op = MSG_Done; - pthread_mutex_unlock(&pMsg->clientMutex); - pthread_cond_signal(&pMsg->clientWakeup); - } - pthread_mutex_unlock(&g.serverMutex); - sqlite3_thread_cleanup(); - return 0; -} - -/* -** Start a server thread if one is not already running. If there -** is aleady a server thread running, the new thread will quickly -** die and this routine is effectively a no-op. -*/ -void sqlite3_server_start(void){ - pthread_t x; - int rc; - g.serverHalt = 0; - rc = pthread_create(&x, 0, sqlite3_server, 0); - if( rc==0 ){ - pthread_detach(x); - } -} - -/* -** If a server thread is running, then stop it. If no server is -** running, this routine is effectively a no-op. -** -** This routine returns immediately without waiting for the server -** thread to stop. But be assured that the server will eventually stop. -*/ -void sqlite3_server_stop(void){ - g.serverHalt = 1; - pthread_cond_broadcast(&g.serverWakeup); -} - -#endif /* defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE */ -#endif /* defined(SQLITE_SERVER) */ Index: SQLite.Interop/src/shell.c ================================================================== --- SQLite.Interop/src/shell.c +++ SQLite.Interop/src/shell.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. ** -** $Id: shell.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: shell.c,v 1.1 2005/03/01 16:04:35 rmsimpson Exp $ */ #include #include #include #include @@ -79,11 +79,11 @@ /* ** Determines if a string is a number of not. */ -static int isNumber(const char *z, int *realnum){ +static int isNumber(const unsigned char *z, int *realnum){ if( *z=='-' || *z=='+' ) z++; if( !isdigit(*z) ){ return 0; } z++; @@ -311,11 +311,11 @@ fputc('n', out); }else if( c=='\r' ){ fputc('\\', out); fputc('r', out); }else if( !isprint(c) ){ - fprintf(out, "\\%03o", c&0xff); + fprintf(out, "\\%03o", c); }else{ fputc(c, out); } } fputc('"', out); @@ -654,18 +654,14 @@ if( nArg!=3 ) return 1; zTable = azArg[0]; zType = azArg[1]; zSql = azArg[2]; - if( strcmp(zTable, "sqlite_sequence")==0 ){ - fprintf(p->out, "DELETE FROM sqlite_sequence;\n"); - }else if( strcmp(zTable, "sqlite_stat1")==0 ){ - fprintf(p->out, "ANALYZE sqlite_master;\n"); - }else if( strncmp(zTable, "sqlite_", 7)==0 ){ - return 0; + if( strcasecmp(zTable,"sqlite_sequence")!=0 ){ + fprintf(p->out, "%s;\n", zSql); }else{ - fprintf(p->out, "%s;\n", zSql); + fprintf(p->out, "DELETE FROM sqlite_sequence;\n"); } if( strcmp(zType, "table")==0 ){ sqlite3_stmt *pTableInfo = 0; char *zSelect = 0; @@ -688,13 +684,12 @@ zSelect = appendText(zSelect, zTmp, '\''); } zSelect = appendText(zSelect, " || ' VALUES(' || ", 0); rc = sqlite3_step(pTableInfo); while( rc==SQLITE_ROW ){ - const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1); zSelect = appendText(zSelect, "quote(", 0); - zSelect = appendText(zSelect, zText, '"'); + zSelect = appendText(zSelect, sqlite3_column_text(pTableInfo, 1), '"'); rc = sqlite3_step(pTableInfo); if( rc==SQLITE_ROW ){ zSelect = appendText(zSelect, ") || ', ' || ", 0); }else{ zSelect = appendText(zSelect, ") ", 0); @@ -828,11 +823,11 @@ }else if( c=='t' ){ c = '\t'; }else if( c=='r' ){ c = '\r'; }else if( c>='0' && c<='7' ){ - c -= '0'; + c =- '0'; if( z[i+1]>='0' && z[i+1]<='7' ){ i++; c = (c<<3) + z[i] - '0'; if( z[i+1]>='0' && z[i+1]<='7' ){ i++; @@ -987,14 +982,14 @@ */ p->mode = MODE_Column; p->showHeader = 1; memset(p->colWidth,0,ArraySize(p->colWidth)); p->colWidth[0] = 4; - p->colWidth[1] = 14; + p->colWidth[1] = 12; p->colWidth[2] = 10; p->colWidth[3] = 10; - p->colWidth[4] = 33; + p->colWidth[4] = 35; }else if (p->explainPrev.valid) { p->explainPrev.valid = 0; p->mode = p->explainPrev.mode; p->showHeader = p->explainPrev.showHeader; memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth)); @@ -1096,11 +1091,10 @@ azCol[i] = &z[nSep]; z += nSep-1; } } } - *z = 0; if( i+1!=nCol ){ fprintf(stderr,"%s line %d: expected %d columns of data but found %d\n", zFile, lineno, nCol, i+1); zCommit = "ROLLBACK"; break; @@ -1293,11 +1287,11 @@ }else{ sqlite3_exec(p->db, "SELECT sql FROM " " (SELECT * FROM sqlite_master UNION ALL" " SELECT * FROM sqlite_temp_master) " - "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" + "WHERE type!='meta' AND sql NOTNULL " "ORDER BY substr(type,2,1), name", callback, &data, &zErrMsg ); } if( zErrMsg ){ @@ -1337,11 +1331,11 @@ char *zErrMsg; open_db(p); if( nArg==1 ){ rc = sqlite3_get_table(p->db, "SELECT name FROM sqlite_master " - "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'" + "WHERE type IN ('table','view') " "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type IN ('table','view') " "ORDER BY 1", &azResult, &nRow, 0, &zErrMsg @@ -1701,17 +1695,10 @@ if( i /* Needed for the definition of va_list */ @@ -29,11 +29,11 @@ ** The version of the SQLite library. */ #ifdef SQLITE_VERSION # undef SQLITE_VERSION #endif -#define SQLITE_VERSION "3.3.1" +#define SQLITE_VERSION "3.1.3" /* ** The format of the version string is "X.Y.Z", where ** X is the major version number, Y is the minor version number and Z ** is the release number. The trailing string is often "alpha" or "beta". @@ -46,11 +46,11 @@ ** (SQLITE_VERSION_NUMBER>=3001001). */ #ifdef SQLITE_VERSION_NUMBER # undef SQLITE_VERSION_NUMBER #endif -#define SQLITE_VERSION_NUMBER 3003001 +#define SQLITE_VERSION_NUMBER 3001003 /* ** The version string is also compiled into the library so that a program ** can check to make sure that the lib*.a file and the *.h file are from ** the same version. The sqlite3_libversion() function returns a pointer @@ -84,17 +84,10 @@ #else typedef long long int sqlite_int64; typedef unsigned long long int sqlite_uint64; #endif -/* -** If compiling for a processor that lacks floating point support, -** substitute integer for floating-point -*/ -#ifdef SQLITE_OMIT_FLOATING_POINT -# define double sqlite_int64 -#endif /* ** A function to close the database. ** ** Call this function with a pointer to a structure that was previously @@ -163,27 +156,27 @@ /* ** Return values for sqlite3_exec() and sqlite3_step() */ #define SQLITE_OK 0 /* Successful result */ #define SQLITE_ERROR 1 /* SQL error or missing database */ -#define SQLITE_INTERNAL 2 /* NOT USED. Internal logic error in SQLite */ +#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ #define SQLITE_BUSY 5 /* The database file is locked */ #define SQLITE_LOCKED 6 /* A table in the database is locked */ #define SQLITE_NOMEM 7 /* A malloc() failed */ #define SQLITE_READONLY 8 /* Attempt to write a readonly database */ #define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ #define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ #define SQLITE_CORRUPT 11 /* The database disk image is malformed */ -#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */ +#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */ #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ #define SQLITE_EMPTY 16 /* Database is empty */ #define SQLITE_SCHEMA 17 /* The database schema changed */ -#define SQLITE_TOOBIG 18 /* NOT USED. Too much data for one row */ +#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */ #define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */ #define SQLITE_MISMATCH 20 /* Data type mismatch */ #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ @@ -190,11 +183,10 @@ #define SQLITE_FORMAT 24 /* Auxiliary database format error */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ -/* end-of-return-codes */ /* ** Each entry in an SQLite table has a unique integer key. (The key is ** the value of the INTEGER PRIMARY KEY column if there is such a column, ** otherwise the key is generated at random. The unique key is always @@ -379,13 +371,12 @@ ** ** char *zText = "It's a happy day!"; ** ** We can use this text in an SQL statement as follows: ** -** char *z = sqlite3_mprintf("INSERT INTO TABLES('%q')", zText); -** sqlite3_exec(db, z, callback1, 0, 0); -** sqlite3_free(z); +** sqlite3_exec_printf(db, "INSERT INTO table VALUES('%q')", +** callback1, 0, 0, zText); ** ** Because the %q format string is used, the '\'' character in zText ** is escaped and the SQL generated is as follows: ** ** INSERT INTO table1 VALUES('It''s a happy day!') @@ -459,11 +450,10 @@ #define SQLITE_UPDATE 23 /* Table Name Column Name */ #define SQLITE_ATTACH 24 /* Filename NULL */ #define SQLITE_DETACH 25 /* Database Name NULL */ #define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ #define SQLITE_REINDEX 27 /* Index Name NULL */ -#define SQLITE_ANALYZE 28 /* Table Name NULL */ /* ** The return value of the authorization function should be one of the ** following constants: @@ -471,22 +461,15 @@ /* #define SQLITE_OK 0 // Allow access (This is actually defined above) */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ /* -** Register a function for tracing SQL command evaluation. The function -** registered by sqlite3_trace() is invoked at the first sqlite3_step() -** for the evaluation of an SQL statement. The function registered by -** sqlite3_profile() runs at the end of each SQL statement and includes -** information on how long that statement ran. -** -** The sqlite3_profile() API is currently considered experimental and -** is subject to change. +** Register a function that is called at every invocation of sqlite3_exec() +** or sqlite3_prepare(). This function can be used (for example) to generate +** a log file of all SQL executed against a database. */ void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); -void *sqlite3_profile(sqlite3*, - void(*xProfile)(void*,const char*,sqlite_uint64), void*); /* ** This routine configures a callback function - the progress callback - that ** is invoked periodically during long running calls to sqlite3_exec(), ** sqlite3_step() and sqlite3_get_table(). An example use for this API is to @@ -703,10 +686,12 @@ */ int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); /* ** Set all the parameters in the compiled SQL statement to NULL. +** +******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** */ int sqlite3_clear_bindings(sqlite3_stmt*); /* ** Return the number of columns in the result set returned by the compiled @@ -1017,13 +1002,14 @@ ** The buffer allocated is freed automatically by SQLite. */ void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); /* -** The pUserData parameter to the sqlite3_create_function() -** routine used to register user functions is available to -** the implementation of the function using this call. +** The pUserData parameter to the sqlite3_create_function() and +** sqlite3_create_aggregate() routines used to register user functions +** is available to the implementation of the function using this +** call. */ void *sqlite3_user_data(sqlite3_context*); /* ** The following two functions may be used by scalar user functions to @@ -1203,181 +1189,38 @@ ** ** If the operating system does not support sleep requests with ** milisecond time resolution, then the time will be rounded up to ** the nearest second. The number of miliseconds of sleep actually ** requested from the operating system is returned. +** +******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** */ int sqlite3_sleep(int); /* -** Return TRUE (non-zero) if the statement supplied as an argument needs +** Return TRUE (non-zero) of the statement supplied as an argument needs ** to be recompiled. A statement needs to be recompiled whenever the ** execution environment changes in a way that would alter the program ** that sqlite3_prepare() generates. For example, if new functions or ** collating sequences are registered or if an authorizer function is ** added or changed. ** +******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** */ int sqlite3_expired(sqlite3_stmt*); -/* -** Move all bindings from the first prepared statement over to the second. -** This routine is useful, for example, if the first prepared statement -** fails with an SQLITE_SCHEMA error. The same SQL can be prepared into -** the second prepared statement then all of the bindings transfered over -** to the second statement before the first statement is finalized. -*/ -int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); - /* ** If the following global variable is made to point to a ** string which is the name of a directory, then all temporary files ** created by SQLite will be placed in that directory. If this variable ** is NULL pointer, then SQLite does a search for an appropriate temporary ** file directory. ** -** Once sqlite3_open() has been called, changing this variable will invalidate -** the current temporary database, if any. +** Once sqlite3_open() has been called, changing this variable will invalidate the +** current temporary database, if any. */ extern char *sqlite3_temp_directory; -/* -** This function is called to recover from a malloc() failure that occured -** within the SQLite library. Normally, after a single malloc() fails the -** library refuses to function (all major calls return SQLITE_NOMEM). -** This function restores the library state so that it can be used again. -** -** All existing statements (sqlite3_stmt pointers) must be finalized or -** reset before this call is made. Otherwise, SQLITE_BUSY is returned. -** If any in-memory databases are in use, either as a main or TEMP -** database, SQLITE_ERROR is returned. In either of these cases, the -** library is not reset and remains unusable. -** -** This function is *not* threadsafe. Calling this from within a threaded -** application when threads other than the caller have used SQLite is -** dangerous and will almost certainly result in malfunctions. -** -** This functionality can be omitted from a build by defining the -** SQLITE_OMIT_GLOBALRECOVER at compile time. -*/ -int sqlite3_global_recover(void); - -/* -** Test to see whether or not the database connection is in autocommit -** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on -** by default. Autocommit is disabled by a BEGIN statement and reenabled -** by the next COMMIT or ROLLBACK. -*/ -int sqlite3_get_autocommit(sqlite3*); - -/* -** Return the sqlite3* database handle to which the prepared statement given -** in the argument belongs. This is the same database handle that was -** the first argument to the sqlite3_prepare() that was used to create -** the statement in the first place. -*/ -sqlite3 *sqlite3_db_handle(sqlite3_stmt*); - -/* -** Register a callback function with the database connection identified by the -** first argument to be invoked whenever a row is updated, inserted or deleted. -** Any callback set by a previous call to this function for the same -** database connection is overridden. -** -** The second argument is a pointer to the function to invoke when a -** row is updated, inserted or deleted. The first argument to the callback is -** a copy of the third argument to sqlite3_update_hook. The second callback -** argument is one of SQLITE_INSERT, SQLITE_DELETE or SQLITE_UPDATE, depending -** on the operation that caused the callback to be invoked. The third and -** fourth arguments to the callback contain pointers to the database and -** table name containing the affected row. The final callback parameter is -** the rowid of the row. In the case of an update, this is the rowid after -** the update takes place. -** -** The update hook is not invoked when internal system tables are -** modified (i.e. sqlite_master and sqlite_sequence). -** -** If another function was previously registered, its pArg value is returned. -** Otherwise NULL is returned. -*/ -void *sqlite3_update_hook( - sqlite3*, - void(*)(void *,int ,char const *,char const *,sqlite_int64), - void* -); - -/* -** Register a callback to be invoked whenever a transaction is rolled -** back. -** -** The new callback function overrides any existing rollback-hook -** callback. If there was an existing callback, then it's pArg value -** (the third argument to sqlite3_rollback_hook() when it was registered) -** is returned. Otherwise, NULL is returned. -** -** For the purposes of this API, a transaction is said to have been -** rolled back if an explicit "ROLLBACK" statement is executed, or -** an error or constraint causes an implicit rollback to occur. The -** callback is not invoked if a transaction is automatically rolled -** back because the database connection is closed. -*/ -void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); - -/* -** This function is only available if the library is compiled without -** the SQLITE_OMIT_SHARED_CACHE macro defined. It is used to enable or -** disable (if the argument is true or false, respectively) the -** "shared pager" feature. -*/ -int sqlite3_enable_shared_cache(int); - -/* -** Attempt to free N bytes of heap memory by deallocating non-essential -** memory allocations held by the database library (example: memory -** used to cache database pages to improve performance). -** -** This function is not a part of standard builds. It is only created -** if SQLite is compiled with the SQLITE_ENABLE_MEMORY_MANAGEMENT macro. -*/ -int sqlite3_release_memory(int); - -/* -** Place a "soft" limit on the amount of heap memory that may be allocated by -** SQLite within the current thread. If an internal allocation is requested -** that would exceed the specified limit, sqlite3_release_memory() is invoked -** one or more times to free up some space before the allocation is made. -** -** The limit is called "soft", because if sqlite3_release_memory() cannot free -** sufficient memory to prevent the limit from being exceeded, the memory is -** allocated anyway and the current operation proceeds. -** -** This function is only available if the library was compiled with the -** SQLITE_ENABLE_MEMORY_MANAGEMENT option set. -** memory-management has been enabled. -*/ -void sqlite3_soft_heap_limit(int); - -/* -** This routine makes sure that all thread-local storage has been -** deallocated for the current thread. -** -** This routine is not technically necessary. All thread-local storage -** will be automatically deallocated once memory-management and -** shared-cache are disabled and the soft heap limit has been set -** to zero. This routine is provided as a convenience for users who -** want to make absolutely sure they have not forgotten something -** prior to killing off a thread. -*/ -void sqlite3_thread_cleanup(void); - -/* -** Undo the hack that converts floating point types to integer for -** builds on processors without floating point support. -*/ -#ifdef SQLITE_OMIT_FLOATING_POINT -# undef double -#endif - #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif Index: SQLite.Interop/src/sqliteInt.h ================================================================== --- SQLite.Interop/src/sqliteInt.h +++ SQLite.Interop/src/sqliteInt.h @@ -9,33 +9,15 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: sqliteInt.h,v 1.1 2005/03/01 16:04:36 rmsimpson Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ -/* -** Extra interface definitions for those who need them -*/ -#ifdef SQLITE_EXTRA -# include "sqliteExtra.h" -#endif - -/* -** Many people are failing to set -DNDEBUG=1 when compiling SQLite. -** Setting NDEBUG makes the code smaller and run faster. So the following -** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1 -** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out -** feature. -*/ -#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) -# define NDEBUG 1 -#endif - /* ** These #defines should enable >2GB file support on Posix if the ** underlying operating system supports it. If the OS lacks ** large file support, or if the OS is windows, these should be no-ops. ** @@ -55,31 +37,20 @@ # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif +#include "config.h" #include "sqlite3.h" #include "hash.h" #include "parse.h" #include #include #include #include #include -/* -** If compiling for a processor that lacks floating point support, -** substitute integer for floating-point -*/ -#ifdef SQLITE_OMIT_FLOATING_POINT -# define double sqlite_int64 -# define LONGDOUBLE_TYPE sqlite_int64 -# define SQLITE_BIG_DBL (0x7fffffffffffffff) -# define SQLITE_OMIT_DATETIME_FUNCS 1 -# define SQLITE_OMIT_TRACE 1 -#endif - /* ** The maximum number of in-memory pages to use for the main database ** table and for temporary tables. Internally, the MAX_PAGES and ** TEMP_PAGES macros are used. To override the default values at ** compilation time, the SQLITE_DEFAULT_CACHE_SIZE and @@ -94,21 +65,10 @@ # define TEMP_PAGES SQLITE_DEFAULT_TEMP_CACHE_SIZE #else # define TEMP_PAGES 500 #endif -/* -** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0 -** afterward. Having this macro allows us to cause the C compiler -** to omit code used by TEMP tables without messy #ifndef statements. -*/ -#ifdef SQLITE_OMIT_TEMPDB -#define OMIT_TEMPDB 1 -#else -#define OMIT_TEMPDB 0 -#endif - /* ** If the following macro is set to 1, then NULL values are considered ** distinct for the SELECT DISTINCT statement and for UNION or EXCEPT ** compound queries. No other SQL database engine (among those tested) ** works this way except for OCELOT. But the SQL92 spec implies that @@ -146,19 +106,22 @@ ** The maximum value of a ?nnn wildcard that the parser will accept. */ #define SQLITE_MAX_VARIABLE_NUMBER 999 /* -** The "file format" number is an integer that is incremented whenever -** the VDBE-level file format changes. The following macros define the -** the default file format for new databases and the maximum file format -** that the library can read. +** When building SQLite for embedded systems where memory is scarce, +** you can define one or more of the following macros to omit extra +** features of the library and thus keep the size of the library to +** a minimum. */ -#define SQLITE_MAX_FILE_FORMAT 4 -#ifndef SQLITE_DEFAULT_FILE_FORMAT -# define SQLITE_DEFAULT_FILE_FORMAT 4 -#endif +/* #define SQLITE_OMIT_AUTHORIZATION 1 */ +/* #define SQLITE_OMIT_MEMORYDB 1 */ +/* #define SQLITE_OMIT_VACUUM 1 */ +/* #define SQLITE_OMIT_DATETIME_FUNCS 1 */ +/* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */ +/* #define SQLITE_OMIT_AUTOVACUUM */ +/* #define SQLITE_OMIT_ALTERTABLE */ /* ** Provide a default value for TEMP_STORE in case it is not specified ** on the command-line */ @@ -203,18 +166,34 @@ #ifndef INT8_TYPE # define INT8_TYPE signed char #endif #ifndef LONGDOUBLE_TYPE # define LONGDOUBLE_TYPE long double +#endif +#ifndef INTPTR_TYPE +# if SQLITE_PTR_SZ==4 +# define INTPTR_TYPE int +# else +# define INTPTR_TYPE sqlite_int64 +# endif +#endif +#ifndef UINTPTR_TYPE +# if SQLITE_PTR_SZ==4 +# define UINTPTR_TYPE unsigned int +# else +# define UINTPTR_TYPE sqlite_uint64 +# endif #endif typedef sqlite_int64 i64; /* 8-byte signed integer */ typedef UINT64_TYPE u64; /* 8-byte unsigned integer */ typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ typedef INT16_TYPE i16; /* 2-byte signed integer */ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ typedef UINT8_TYPE i8; /* 1-byte signed integer */ +typedef INTPTR_TYPE ptr; /* Big enough to hold a pointer */ +typedef UINTPTR_TYPE uptr; /* Big enough to hold a pointer */ /* ** Macros to determine whether the machine is big or little endian, ** evaluated at runtime. */ @@ -233,93 +212,71 @@ */ typedef struct BusyHandler BusyHandler; struct BusyHandler { int (*xFunc)(void *,int); /* The busy callback */ void *pArg; /* First arg to busy callback */ - int nBusy; /* Incremented with each busy call */ }; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler typedefs. */ #include "vdbe.h" #include "btree.h" -#include "pager.h" /* ** This macro casts a pointer to an integer. Useful for doing ** pointer arithmetic. */ #define Addr(X) ((uptr)X) +/* +** If memory allocation problems are found, recompile with +** +** -DSQLITE_DEBUG=1 +** +** to enable some sanity checking on malloc() and free(). To +** check for memory leaks, recompile with +** +** -DSQLITE_DEBUG=2 +** +** and a line of text will be written to standard error for +** each malloc() and free(). This output can be analyzed +** by an AWK script to determine if there are any leaks. +*/ #ifdef SQLITE_MEMDEBUG +# define sqliteMalloc(X) sqlite3Malloc_(X,1,__FILE__,__LINE__) +# define sqliteMallocRaw(X) sqlite3Malloc_(X,0,__FILE__,__LINE__) +# define sqliteFree(X) sqlite3Free_(X,__FILE__,__LINE__) +# define sqliteRealloc(X,Y) sqlite3Realloc_(X,Y,__FILE__,__LINE__) +# define sqliteStrDup(X) sqlite3StrDup_(X,__FILE__,__LINE__) +# define sqliteStrNDup(X,Y) sqlite3StrNDup_(X,Y,__FILE__,__LINE__) +#else +# define sqliteFree sqlite3FreeX +# define sqliteMalloc sqlite3Malloc +# define sqliteMallocRaw sqlite3MallocRaw +# define sqliteRealloc sqlite3Realloc +# define sqliteStrDup sqlite3StrDup +# define sqliteStrNDup sqlite3StrNDup +#endif + +/* +** This variable gets set if malloc() ever fails. After it gets set, +** the SQLite library shuts down permanently. +*/ +extern int sqlite3_malloc_failed; + /* ** The following global variables are used for testing and debugging -** only. They only work if SQLITE_MEMDEBUG is defined. +** only. They only work if SQLITE_DEBUG is defined. */ +#ifdef SQLITE_MEMDEBUG extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */ extern int sqlite3_nFree; /* Number of sqliteFree() calls */ extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */ -#define ENTER_MALLOC (\ - sqlite3ThreadData()->zFile = __FILE__, sqlite3ThreadData()->iLine = __LINE__ \ -) -#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x)) -#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x)) -#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y)) -#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x)) -#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y)) -#define sqliteReallocOrFree(x,y) (ENTER_MALLOC, sqlite3ReallocOrFree(x,y)) - -#else - -#define sqliteMalloc(x) sqlite3Malloc(x) -#define sqliteMallocRaw(x) sqlite3MallocRaw(x) -#define sqliteRealloc(x,y) sqlite3Realloc(x,y) -#define sqliteStrDup(x) sqlite3StrDup(x) -#define sqliteStrNDup(x,y) sqlite3StrNDup(x,y) -#define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y) - -#endif - -#define sqliteFree(x) sqlite3FreeX(x) -#define sqliteAllocSize(x) sqlite3AllocSize(x) - - -/* -** An instance of this structure might be allocated to store information -** specific to a single thread. -** -** To avoid a memory leak on windows, the content of this structure is -** checked at the conclusion of each API call. If it is all zero, it -** is deallocated. -*/ -struct ThreadData { - int mallocFailed; /* True after a malloc() has failed */ - int nRef; /* Number of users */ - -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - int nSoftHeapLimit; /* Suggested max mem allocation. No limit if <0 */ - int nAlloc; /* Number of bytes currently allocated */ - Pager *pPager; /* Linked list of all pagers in this thread */ -#endif - -#ifndef SQLITE_OMIT_SHARED_CACHE - u8 useSharedData; /* True if shared pagers and schemas are enabled */ - BtShared *pBtree; /* Linked list of all currently open BTrees */ -#endif - -#ifdef SQLITE_MEMDEBUG - int nMaxAlloc; /* High water mark of ThreadData.nAlloc */ - int mallocDisallowed; /* assert() in sqlite3Malloc() if set */ - int isFail; /* True if all malloc() calls should fail */ - const char *zFile; /* Filename to associate debugging info with */ - int iLine; /* Line number to associate debugging info with */ - void *pFirst; /* Pointer to linked list of allocations */ -#endif -}; +#endif /* ** Name of the master database table. The master database table ** is a special table that holds the names and attributes of all ** user tables and indices. @@ -333,11 +290,11 @@ #define MASTER_ROOT 1 /* ** The name of the schema table. */ -#define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME) +#define SCHEMA_TABLE(x) (x==1?TEMP_MASTER_NAME:MASTER_NAME) /* ** A convenience macro that returns the number of elements in ** an array. */ @@ -344,37 +301,36 @@ #define ArraySize(X) (sizeof(X)/sizeof(X[0])) /* ** Forward references to structures */ -typedef struct AggInfo AggInfo; -typedef struct AuthContext AuthContext; -typedef struct CollSeq CollSeq; typedef struct Column Column; -typedef struct Db Db; -typedef struct Schema Schema; +typedef struct Table Table; +typedef struct Index Index; +typedef struct Instruction Instruction; typedef struct Expr Expr; typedef struct ExprList ExprList; -typedef struct FKey FKey; -typedef struct FuncDef FuncDef; +typedef struct Parse Parse; +typedef struct Token Token; typedef struct IdList IdList; -typedef struct Index Index; +typedef struct SrcList SrcList; +typedef struct WhereInfo WhereInfo; +typedef struct WhereLevel WhereLevel; +typedef struct Select Select; +typedef struct AggExpr AggExpr; +typedef struct FuncDef FuncDef; +typedef struct Trigger Trigger; +typedef struct TriggerStep TriggerStep; +typedef struct TriggerStack TriggerStack; +typedef struct FKey FKey; +typedef struct Db Db; +typedef struct AuthContext AuthContext; typedef struct KeyClass KeyClass; +typedef struct CollSeq CollSeq; typedef struct KeyInfo KeyInfo; typedef struct NameContext NameContext; -typedef struct Parse Parse; -typedef struct Select Select; -typedef struct SrcList SrcList; -typedef struct ThreadData ThreadData; -typedef struct Table Table; -typedef struct TableLock TableLock; -typedef struct Token Token; -typedef struct TriggerStack TriggerStack; -typedef struct TriggerStep TriggerStep; -typedef struct Trigger Trigger; -typedef struct WhereInfo WhereInfo; -typedef struct WhereLevel WhereLevel; +typedef struct Fetch Fetch; /* ** Each database file to be accessed by the system is an instance ** of the following structure. There are normally two of these structures ** in the sqlite.aDb[] array. aDb[0] is the main database file and @@ -382,41 +338,32 @@ ** databases may be attached. */ struct Db { char *zName; /* Name of this database */ Btree *pBt; /* The B*Tree structure for this database file */ - u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ - u8 safety_level; /* How aggressive at synching data to disk */ - void *pAux; /* Auxiliary data. Usually NULL */ - void (*xFreeAux)(void*); /* Routine to free pAux */ - Schema *pSchema; /* Pointer to database schema (possibly shared) */ -}; - -/* -** An instance of the following structure stores a database schema. -*/ -struct Schema { int schema_cookie; /* Database schema version number for this file */ Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Hash aFKey; /* Foreign keys indexed by to-table */ - Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ - u8 file_format; /* Schema format version for this file */ - u8 enc; /* Text encoding used by this database */ - u16 flags; /* Flags associated with this schema */ + u16 flags; /* Flags associated with this database */ + u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ + u8 safety_level; /* How aggressive at synching data to disk */ int cache_size; /* Number of pages to use in the cache */ + Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ + void *pAux; /* Auxiliary data. Usually NULL */ + void (*xFreeAux)(void*); /* Routine to free pAux */ }; /* ** These macros can be used to test, set, or clear bits in the ** Db.flags field. */ -#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P)) -#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0) -#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P) -#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P) +#define DbHasProperty(D,I,P) (((D)->aDb[I].flags&(P))==(P)) +#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].flags&(P))!=0) +#define DbSetProperty(D,I,P) (D)->aDb[I].flags|=(P) +#define DbClearProperty(D,I,P) (D)->aDb[I].flags&=~(P) /* ** Allowed values for the DB.flags field. ** ** The DB_SchemaLoaded flag is set after the database schema has been @@ -426,11 +373,10 @@ ** have been filled out. If the schema changes, these column names might ** changes and so the view will need to be reset. */ #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */ -#define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */ #define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) /* ** Each database is an instance of the following structure. @@ -459,15 +405,20 @@ ** consistently. */ struct sqlite3 { int nDb; /* Number of backends currently in use */ Db *aDb; /* All backends */ + Db aDbStatic[2]; /* Static space for the 2 default backends */ int flags; /* Miscellanous flags. See below */ - int errCode; /* Most recent error code (SQLITE_*) */ - u8 autoCommit; /* The auto-commit flag. */ + u8 file_format; /* What file format version is this database? */ u8 temp_store; /* 1: file 2: memory 0: default */ int nTable; /* Number of tables in the database */ + BusyHandler busyHandler; /* Busy callback */ + void *pCommitArg; /* Argument to xCommitCallback() */ + int (*xCommitCallback)(void*);/* Invoked at every commit. */ + Hash aFunc; /* All functions that can be in SQL exprs */ + Hash aCollSeq; /* All collating sequences */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 priorNewRowid; /* Last randomly generated ROWID */ int magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ @@ -477,26 +428,12 @@ int newTnum; /* Rootpage of table being initialized */ u8 busy; /* TRUE if currently initializing */ } init; struct Vdbe *pVdbe; /* List of active virtual machines */ int activeVdbeCnt; /* Number of vdbes currently executing */ - void (*xTrace)(void*,const char*); /* Trace function */ - void *pTraceArg; /* Argument to the trace function */ - void (*xProfile)(void*,const char*,u64); /* Profiling function */ - void *pProfileArg; /* Argument to profile function */ - void *pCommitArg; /* Argument to xCommitCallback() */ - int (*xCommitCallback)(void*); /* Invoked at every commit. */ - void *pRollbackArg; /* Argument to xRollbackCallback() */ - void (*xRollbackCallback)(void*); /* Invoked at every commit. */ - void *pUpdateArg; - void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); - void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); - void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); - void *pCollNeededArg; - sqlite3_value *pErr; /* Most recent error message */ - char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ - char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ + void (*xTrace)(void*,const char*); /* Trace function */ + void *pTraceArg; /* Argument to the trace function */ #ifndef SQLITE_OMIT_AUTHORIZATION int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); /* Access authorization function */ void *pAuthArg; /* 1st argument to the access auth function */ #endif @@ -503,33 +440,31 @@ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif -#ifndef SQLITE_OMIT_GLOBALRECOVER - sqlite3 *pNext; /* Linked list of open db handles. */ -#endif - Hash aFunc; /* All functions that can be in SQL exprs */ - Hash aCollSeq; /* All collating sequences */ - BusyHandler busyHandler; /* Busy callback */ - int busyTimeout; /* Busy handler timeout, in msec */ - Db aDbStatic[2]; /* Static space for the 2 default backends */ -#ifdef SQLITE_SSE - sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ -#endif + int errCode; /* Most recent error code (SQLITE_*) */ + u8 enc; /* Text encoding for this database. */ + u8 autoCommit; /* The auto-commit flag. */ + void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); + void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); + void *pCollNeededArg; + sqlite3_value *pValue; /* Value used for transient conversions */ + sqlite3_value *pErr; /* Most recent error message */ + char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ + char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ }; -#define ENC(db) ((db)->aDb[0].pSchema->enc) - /* ** Possible values for the sqlite.flags and or Db.flags fields. ** ** On sqlite.flags, the SQLITE_InTrans value means that we have ** executed a BEGIN. On Db.flags, SQLITE_InTrans means a statement ** transaction is active on that particular database file. */ #define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ +#define SQLITE_Initialized 0x00000002 /* True after initialization */ #define SQLITE_Interrupt 0x00000004 /* Cancel current operation */ #define SQLITE_InTrans 0x00000008 /* True if in a transaction */ #define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */ #define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */ #define SQLITE_ShortColNames 0x00000040 /* Show short columns names */ @@ -541,13 +476,10 @@ #define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */ #define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */ #define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */ #define SQLITE_NoReadlock 0x00001000 /* Readlocks are omitted when ** accessing read-only databases */ -#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ -#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */ -#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. @@ -562,37 +494,30 @@ ** structure. A pointer to this structure is stored in the sqlite.aFunc ** hash table. When multiple functions have the same name, the hash table ** points to a linked list of these structures. */ struct FuncDef { - i16 nArg; /* Number of arguments. -1 means unlimited */ + char *zName; /* SQL name of the function */ + int nArg; /* Number of arguments. -1 means unlimited */ u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */ - u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */ - u8 flags; /* Some combination of SQLITE_FUNC_* */ void *pUserData; /* User data parameter */ FuncDef *pNext; /* Next function with same name */ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */ void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */ void (*xFinalize)(sqlite3_context*); /* Aggregate finializer */ - char zName[1]; /* SQL name of the function. MUST BE LAST */ + u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */ }; -/* -** Possible values for FuncDef.flags -*/ -#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ -#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ - /* ** information about each column of an SQL table is held in an instance ** of this structure. */ struct Column { char *zName; /* Name of this column */ Expr *pDflt; /* Default value of this column */ char *zType; /* Data type for this column */ - char *zColl; /* Collating sequence. If NULL, use the default */ + CollSeq *pColl; /* Collating sequence. If NULL, use the default */ u8 notNull; /* True if there is a NOT NULL constraint */ u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */ char affinity; /* One of the SQLITE_AFF_... values */ }; @@ -604,11 +529,11 @@ ** There may two seperate implementations of the collation function, one ** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that ** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine ** native byte order. When a collation sequence is invoked, SQLite selects ** the version that will require the least expensive encoding -** translations, if any. +** transalations, if any. ** ** The CollSeq.pUser member variable is an extra parameter that passed in ** as the first argument to the UTF-8 comparison function, xCmp. ** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function, ** xCmp16. @@ -618,50 +543,28 @@ ** collating sequence may not be read or written. */ struct CollSeq { char *zName; /* Name of the collating sequence, UTF-8 encoded */ u8 enc; /* Text encoding handled by xCmp() */ - u8 type; /* One of the SQLITE_COLL_... values below */ void *pUser; /* First argument to xCmp() */ int (*xCmp)(void*,int, const void*, int, const void*); }; -/* -** Allowed values of CollSeq flags: -*/ -#define SQLITE_COLL_BINARY 1 /* The default memcmp() collating sequence */ -#define SQLITE_COLL_NOCASE 2 /* The built-in NOCASE collating sequence */ -#define SQLITE_COLL_REVERSE 3 /* The built-in REVERSE collating sequence */ -#define SQLITE_COLL_USER 0 /* Any other user-defined collating sequence */ - /* ** A sort order can be either ASC or DESC. */ #define SQLITE_SO_ASC 0 /* Sort in ascending order */ #define SQLITE_SO_DESC 1 /* Sort in ascending order */ /* ** Column affinity types. -** -** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and -** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve -** the speed a little by number the values consecutively. -** -** But rather than start with 0 or 1, we begin with 'a'. That way, -** when multiple affinity types are concatenated into a string and -** used as the P3 operand, they will be more readable. -** -** Note also that the numeric types are grouped together so that testing -** for a numeric type is a single comparison. */ -#define SQLITE_AFF_TEXT 'a' -#define SQLITE_AFF_NONE 'b' -#define SQLITE_AFF_NUMERIC 'c' -#define SQLITE_AFF_INTEGER 'd' -#define SQLITE_AFF_REAL 'e' +#define SQLITE_AFF_INTEGER 'i' +#define SQLITE_AFF_NUMERIC 'n' +#define SQLITE_AFF_TEXT 't' +#define SQLITE_AFF_NONE 'o' -#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) /* ** Each SQL table is represented in memory by an instance of the ** following structure. ** @@ -698,26 +601,18 @@ int iPKey; /* If not less then 0, use aCol[iPKey] as the primary key */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Root BTree node for this table (see note above) */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u8 readOnly; /* True if this table should not be written by the user */ -// u8 iDb; /* Index into sqlite.aDb[] of the backend for this table */ + u8 iDb; /* Index into sqlite.aDb[] of the backend for this table */ u8 isTransient; /* True if automatically deleted when VDBE finishes */ u8 hasPrimKey; /* True if there exists a primary key */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 autoInc; /* True if the integer primary key is autoincrement */ - int nRef; /* Number of pointers to this Table */ Trigger *pTrigger; /* List of SQL triggers on this table */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ -#ifndef SQLITE_OMIT_CHECK - Expr *pCheck; /* The AND of all CHECK constraints */ -#endif -#ifndef SQLITE_OMIT_ALTERTABLE - int addColOffset; /* Offset in CREATE TABLE statement to add a new column */ -#endif - Schema *pSchema; }; /* ** Each foreign key constraint is an instance of the following structure. ** @@ -803,12 +698,11 @@ ** An instance of the following structure is passed as the first ** argument to sqlite3VdbeKeyCompare and is used to control the ** comparison of the two index keys. ** ** If the KeyInfo.incrKey value is true and the comparison would -** otherwise be equal, then return a result as if the second key -** were larger. +** otherwise be equal, then return a result as if the second key larger. */ struct KeyInfo { u8 enc; /* Text encoding - one of the TEXT_Utf* values */ u8 incrKey; /* Increase 2nd key by epsilon before comparison */ int nField; /* Number of entries in aColl[] */ @@ -844,20 +738,18 @@ */ struct Index { char *zName; /* Name of this index */ int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ - unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ int tnum; /* Page containing root of this index in database file */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ + u8 iDb; /* Index in sqlite.aDb[] of where this index is stored */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ - Schema *pSchema; /* Schema containing this index */ - u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ - char **azColl; /* Array of collation sequence names for index */ + KeyInfo keyInfo; /* Info on how to order keys. MUST BE LAST */ }; /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. @@ -870,53 +762,10 @@ const unsigned char *z; /* Text of the token. Not NULL-terminated! */ unsigned dyn : 1; /* True for malloced memory, false for static */ unsigned n : 31; /* Number of characters in this token */ }; -/* -** An instance of this structure contains information needed to generate -** code for a SELECT that contains aggregate functions. -** -** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a -** pointer to this structure. The Expr.iColumn field is the index in -** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate -** code for that node. -** -** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the -** original Select structure that describes the SELECT statement. These -** fields do not need to be freed when deallocating the AggInfo structure. -*/ -struct AggInfo { - u8 directMode; /* Direct rendering mode means take data directly - ** from source tables rather than from accumulators */ - u8 useSortingIdx; /* In direct mode, reference the sorting index rather - ** than the source table */ - int sortingIdx; /* Cursor number of the sorting index */ - ExprList *pGroupBy; /* The group by clause */ - int nSortingColumn; /* Number of columns in the sorting index */ - struct AggInfo_col { /* For each column used in source tables */ - int iTable; /* Cursor number of the source table */ - int iColumn; /* Column number within the source table */ - int iSorterColumn; /* Column number in the sorting index */ - int iMem; /* Memory location that acts as accumulator */ - Expr *pExpr; /* The original expression */ - } *aCol; - int nColumn; /* Number of used entries in aCol[] */ - int nColumnAlloc; /* Number of slots allocated for aCol[] */ - int nAccumulator; /* Number of columns that show through to the output. - ** Additional columns are used only as parameters to - ** aggregate functions */ - struct AggInfo_func { /* For each aggregate function */ - Expr *pExpr; /* Expression encoding the function */ - FuncDef *pFunc; /* The aggregate function implementation */ - int iMem; /* Memory location that acts as accumulator */ - int iDistinct; /* Virtual table used to enforce DISTINCT */ - } *aFunc; - int nFunc; /* Number of entries in aFunc[] */ - int nFuncAlloc; /* Number of slots allocated for aFunc[] */ -}; - /* ** Each node of an expression in the parse tree is an instance ** of this structure. ** ** Expr.op is the opcode. The integer parser token codes are reused @@ -954,47 +803,40 @@ ** ** The Expr.pSelect field points to a SELECT statement. The SELECT might ** be the right operand of an IN operator. Or, if a scalar SELECT appears ** in an expression the opcode is TK_SELECT and Expr.pSelect is the only ** operand. -** -** If the Expr is of type OP_Column, and the table it is selecting from -** is a disk table or the "old.*" pseudo-table, then pTab points to the -** corresponding table definition. */ struct Expr { u8 op; /* Operation performed by this node */ char affinity; /* The affinity of the column or 0 if not a column */ -//u8 iDb; /* Database referenced by this expression */ + u8 iDb; /* Database referenced by this expression */ u8 flags; /* Various flags. See below */ CollSeq *pColl; /* The collation type of the column or 0 */ Expr *pLeft, *pRight; /* Left and right subnodes */ ExprList *pList; /* A list of expressions used as function arguments ** or in " IN (aCol[] or ->aFunc[] */ - int iRightJoinTable; /* If EP_FromJoin, the right table of the join */ + int iAgg; /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull + ** result from the iAgg-th element of the aggregator */ + int iAggCtx; /* The value to pass as P1 of OP_AggGet. */ Select *pSelect; /* When the expression is a sub-select. Also the ** right side of " IN (