diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:28:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:28:19 +0000 |
commit | 18657a960e125336f704ea058e25c27bd3900dcb (patch) | |
tree | 17b438b680ed45a996d7b59951e6aa34023783f2 /www/34to35.html | |
parent | Initial commit. (diff) | |
download | sqlite3-upstream.tar.xz sqlite3-upstream.zip |
Adding upstream version 3.40.1.upstream/3.40.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'www/34to35.html')
-rw-r--r-- | www/34to35.html | 945 |
1 files changed, 945 insertions, 0 deletions
diff --git a/www/34to35.html b/www/34to35.html new file mode 100644 index 0000000..e7b3596 --- /dev/null +++ b/www/34to35.html @@ -0,0 +1,945 @@ +<!DOCTYPE html> +<html><head> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<link href="sqlite.css" rel="stylesheet"> +<title>SQLite Changes From Version 3.4.2 To 3.5.0</title> +<!-- path= --> +</head> +<body> +<div class=nosearch> +<a href="index.html"> +<img class="logo" src="images/sqlite370_banner.gif" alt="SQLite" border="0"> +</a> +<div><!-- IE hack to prevent disappearing logo --></div> +<div class="tagline desktoponly"> +Small. Fast. Reliable.<br>Choose any three. +</div> +<div class="menu mainmenu"> +<ul> +<li><a href="index.html">Home</a> +<li class='mobileonly'><a href="javascript:void(0)" onclick='toggle_div("submenu")'>Menu</a> +<li class='wideonly'><a href='about.html'>About</a> +<li class='desktoponly'><a href="docs.html">Documentation</a> +<li class='desktoponly'><a href="download.html">Download</a> +<li class='wideonly'><a href='copyright.html'>License</a> +<li class='desktoponly'><a href="support.html">Support</a> +<li class='desktoponly'><a href="prosupport.html">Purchase</a> +<li class='search' id='search_menubutton'> +<a href="javascript:void(0)" onclick='toggle_search()'>Search</a> +</ul> +</div> +<div class="menu submenu" id="submenu"> +<ul> +<li><a href='about.html'>About</a> +<li><a href='docs.html'>Documentation</a> +<li><a href='download.html'>Download</a> +<li><a href='support.html'>Support</a> +<li><a href='prosupport.html'>Purchase</a> +</ul> +</div> +<div class="searchmenu" id="searchmenu"> +<form method="GET" action="search"> +<select name="s" id="searchtype"> +<option value="d">Search Documentation</option> +<option value="c">Search Changelog</option> +</select> +<input type="text" name="q" id="searchbox" value=""> +<input type="submit" value="Go"> +</form> +</div> +</div> +<script> +function toggle_div(nm) { +var w = document.getElementById(nm); +if( w.style.display=="block" ){ +w.style.display = "none"; +}else{ +w.style.display = "block"; +} +} +function toggle_search() { +var w = document.getElementById("searchmenu"); +if( w.style.display=="block" ){ +w.style.display = "none"; +} else { +w.style.display = "block"; +setTimeout(function(){ +document.getElementById("searchbox").focus() +}, 30); +} +} +function div_off(nm){document.getElementById(nm).style.display="none";} +window.onbeforeunload = function(e){div_off("submenu");} +/* Disable the Search feature if we are not operating from CGI, since */ +/* Search is accomplished using CGI and will not work without it. */ +if( !location.origin || !location.origin.match || !location.origin.match(/http/) ){ +document.getElementById("search_menubutton").style.display = "none"; +} +/* Used by the Hide/Show button beside syntax diagrams, to toggle the */ +function hideorshow(btn,obj){ +var x = document.getElementById(obj); +var b = document.getElementById(btn); +if( x.style.display!='none' ){ +x.style.display = 'none'; +b.innerHTML='show'; +}else{ +x.style.display = ''; +b.innerHTML='hide'; +} +return false; +} +var antiRobot = 0; +function antiRobotGo(){ +if( antiRobot!=3 ) return; +antiRobot = 7; +var j = document.getElementById("mtimelink"); +if(j && j.hasAttribute("data-href")) j.href=j.getAttribute("data-href"); +} +function antiRobotDefense(){ +document.body.onmousedown=function(){ +antiRobot |= 2; +antiRobotGo(); +document.body.onmousedown=null; +} +document.body.onmousemove=function(){ +antiRobot |= 2; +antiRobotGo(); +document.body.onmousemove=null; +} +setTimeout(function(){ +antiRobot |= 1; +antiRobotGo(); +}, 100) +antiRobotGo(); +} +antiRobotDefense(); +</script> +<?xml version="1.0" encoding="Windows-1252"?> + +<h1> Moving From SQLite 3.4.2 to 3.5.0</h1><p> + SQLite version 3.5.0 (2007-09-04) introduces a new OS interface layer that + is incompatible with all prior versions of SQLite. In addition, + a few existing interfaces have been generalized to work across all + database connections within a process rather than just all + connections within a thread. The purpose of this article + is to describe the changes to 3.5.0 in detail so that users + of prior versions of SQLite can judge what, if any, effort will + be required to upgrade to newer versions. +</p> +<h2>1.0 Overview Of Changes</h2><p> + A quick enumeration of the changes in SQLite version 3.5.0 + is provided here. Subsequent sections will describe these + changes in more detail. +</p> +<p> + <ol> + <li>The OS interface layer has been completely reworked: + <ol type="a"> + <li>The undocumented <b>sqlite3_os_switch()</b> interface has + been removed.</li> + <li>The <b>SQLITE_ENABLE_REDEF_IO</b> compile-time flag no longer functions. + I/O procedures are now always redefinable.</li> + <li>Three new objects are defined for specifying I/O procedures: + <a href="c3ref/vfs.html">sqlite3_vfs</a>, <a href="c3ref/file.html">sqlite3_file</a>, and <a href="c3ref/io_methods.html">sqlite3_io_methods</a>.</li> + <li>Three new interfaces are used to create alternative OS interfaces: + <a href="c3ref/vfs_find.html">sqlite3_vfs_register()</a>, <a href="c3ref/vfs_find.html">sqlite3_vfs_unregister()</a>, and + <a href="c3ref/vfs_find.html">sqlite3_vfs_find()</a>.</li> + <li>A new interface has been added to provided additional control over + the creation of new database connections: <a href="c3ref/open.html">sqlite3_open_v2()</a>. + The legacy interfaces of <a href="c3ref/open.html">sqlite3_open()</a> and + <a href="c3ref/open.html">sqlite3_open16()</a> continue to be fully supported.</li> + </ol></li> + <li>The optional shared cache and memory management features that + were introduced in version 3.3.0 can now be used across multiple + threads within the same process. Formerly, these extensions only + applied to database connections operating within a single thread. + <ol type="a"> + <li>The <a href="c3ref/enable_shared_cache.html">sqlite3_enable_shared_cache()</a> interface now applies to all + threads within a process, not to just the one thread in which it + was run.</li> + <li>The <a href="c3ref/soft_heap_limit.html">sqlite3_soft_heap_limit()</a> interface now applies to all threads + within a process, not to just the one thread in which it was run.</li> + <li>The <a href="c3ref/release_memory.html">sqlite3_release_memory()</a> interface will now attempt to reduce + the memory usages across all database connections in all threads, not + just connections in the thread where the interface is called.</li> + <li>The <a href="c3ref/aggregate_count.html">sqlite3_thread_cleanup()</a> interface has become a no-op.</li> + </ol></li> + <li>Restrictions on the use of the same database connection by multiple + threads have been dropped. It is now safe for + multiple threads to use the same database connection at the same + time.</li> + <li>There is now a compile-time option that allows an application to + define alternative malloc()/free() implementations without having + to modify any core SQLite code.</li> + <li>There is now a compile-time option that allows an application to + define alternative mutex implementations without having + to modify any core SQLite code.</li> + </ol> +</p> +<p> + Of these changes, only 1a and 2a through 2c are incompatibilities + in any formal sense. + But users who have previously made custom modifications to the + SQLite source (for example to add a custom OS layer for embedded + hardware) might find that these changes have a larger impact. + On the other hand, an important goal of these changes is to make + it much easier to customize SQLite for use on different operating + systems. +</p> +<h2>2.0 The OS Interface Layer</h2><p> + If your system defines a custom OS interface for SQLite or if you + were using the undocumented <b>sqlite3_os_switch()</b> + interface, then you will need to make modifications in order to + upgrade to SQLite version 3.5.0. This may seem painful at first + glance. But as you look more closely, you will probably discover + that your changes are made smaller and easier to understand and manage + by the new SQLite interface. It is likely that your changes will + now also work seamlessly with the SQLite amalgamation. You will + no longer need to make any changes to the code SQLite source code. + All of your changes can be effected by application code and you can + link against a standard, unmodified version of the SQLite amalgamation. + Furthermore, the OS interface layer, which was formerly undocumented, + is now an officially support interface for SQLite. So you have + some assurance that this will be a one-time change and that your + new backend will continue to work in future versions of SQLite. +</p> +<h3>2.1 The Virtual File System Object</h3><p> + The new OS interface for SQLite is built around an object named + <a href="c3ref/vfs.html">sqlite3_vfs</a>. The "vfs" stands for "Virtual File System". + The sqlite3_vfs object is basically a structure containing pointers + to functions that implement the primitive disk I/O operations that + SQLite needs to perform in order to read and write databases. + In this article, we will often refer to an sqlite3_vfs objects as a "VFS". +</p> +<p> + SQLite is able to use multiple VFSes at the same time. Each + individual database connection is associated with just one VFS. + But if you have multiple database connections, each connection + can be associated with a different VFS. +</p> +<p> + There is always a default VFS. + The legacy interfaces <a href="c3ref/open.html">sqlite3_open()</a> and <a href="c3ref/open.html">sqlite3_open16()</a> always + use the default VFS. + The new interface for creating database connections, + <a href="c3ref/open.html">sqlite3_open_v2()</a>, allows you to specify which VFS you want to + use by name. +</p> +<h4>2.1.1 Registering New VFS Objects</h4><p> + Standard builds of SQLite for Unix or Windows come with a single + VFS named "unix" or "win32", as appropriate. This one VFS is also + the default. So if you are using the legacy open functions, everything + will continue to operate as it has before. The change is that an application + now has the flexibility of adding new VFS modules to implement a + customized OS layer. The <a href="c3ref/vfs_find.html">sqlite3_vfs_register()</a> API can be used + to tell SQLite about one or more application-defined VFS modules: +</p> +<blockquote><pre> +int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); +</pre></blockquote><p> + Applications can call sqlite3_vfs_register() at any time, though of course + a VFS needs to be registered before it can be used. The first argument + is a pointer to a customized VFS object that the application has prepared. + The second argument is true to make the new VFS the default VFS so that + it will be used by the legacy <a href="c3ref/open.html">sqlite3_open()</a> and <a href="c3ref/open.html">sqlite3_open16()</a> APIs. + If the new VFS is not the default, then you will probably have to use + the new <a href="c3ref/open.html">sqlite3_open_v2()</a> API to use it. Note, however, that if + a new VFS is the only VFS known to SQLite (if SQLite was compiled without + its usual default VFS or if the precompiled default VFS was removed + using <a href="c3ref/vfs_find.html">sqlite3_vfs_unregister()</a>) then the new VFS automatically becomes the + default VFS regardless of the makeDflt argument to <a href="c3ref/vfs_find.html">sqlite3_vfs_register()</a>. +</p> +<p> + Standard builds include the default "unix" or "win32" VFSes. + But if you use the -DOS_OTHER=1 compile-time option, then SQLite is + built without a default VFS. In that case, the application must + register at least one VFS prior to calling <a href="c3ref/open.html">sqlite3_open()</a>. + This is the approach that embedded applications should use. + Rather than modifying the SQLite source to insert an alternative + OS layer as was done in prior releases of SQLite, instead compile + an unmodified SQLite source file (preferably the amalgamation) + with the -DOS_OTHER=1 option, then invoke <a href="c3ref/vfs_find.html">sqlite3_vfs_register()</a> + to define the interface to the underlying filesystem prior to + creating any database connections. +</p> +<h4>2.1.2 Additional Control Over VFS Objects</h4><p> + The <a href="c3ref/vfs_find.html">sqlite3_vfs_unregister()</a> API is used to remove an existing + VFS from the system. +</p> +<blockquote><pre> +int sqlite3_vfs_unregister(sqlite3_vfs*); +</pre></blockquote><p> + The <a href="c3ref/vfs_find.html">sqlite3_vfs_find()</a> API is used to locate a particular VFS + by name. Its prototype is as follows: +</p> +<blockquote><pre> +sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); +</pre></blockquote><p> + The argument is the symbolic name for the desired VFS. If the + argument is a NULL pointer, then the default VFS is returned. + The function returns a pointer to the <a href="c3ref/vfs.html">sqlite3_vfs</a> object that + implements the VFS. Or it returns a NULL pointer if no object + could be found that matched the search criteria. +</p> +<h4>2.1.3 Modifications Of Existing VFSes</h4><p> + Once a VFS has been registered, it should never be modified. If + a change in behavior is required, a new VFS should be registered. + The application could, perhaps, use <a href="c3ref/vfs_find.html">sqlite3_vfs_find()</a> to locate + the old VFS, make a copy of the old VFS into a new <a href="c3ref/vfs.html">sqlite3_vfs</a> + object, make the desired modifications to the new VFS, unregister + the old VFS, then register the new VFS in its place. Existing + database connections would continue to use the old VFS even after + it is unregistered, but new database connections would use the + new VFS. +</p> +<h4>2.1.4 The VFS Object</h4><p> + A VFS object is an instance of the following structure: +</p> +<blockquote><pre> +typedef struct sqlite3_vfs sqlite3_vfs; +struct sqlite3_vfs { + int iVersion; /* Structure version number */ + int szOsFile; /* Size of subclassed sqlite3_file */ + int mxPathname; /* Maximum file pathname length */ + sqlite3_vfs *pNext; /* Next registered VFS */ + const char *zName; /* Name of this virtual file system */ + void *pAppData; /* Pointer to application-specific data */ + int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, + int flags, int *pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char *zName, int flags); + int (*xGetTempName)(sqlite3_vfs*, char *zOut); + int (*xFullPathname)(sqlite3_vfs*, const char *zName, char *zOut); + void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); + void *(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + /* New fields may be appended in figure versions. The iVersion + ** value will increment whenever this happens. */ +}; +</pre></blockquote><p> + To create a new VFS, an application fills in an instance of this + structure with appropriate values and then calls <a href="c3ref/vfs_find.html">sqlite3_vfs_register()</a>. +</p> +<p> + The iVersion field of <a href="c3ref/vfs.html">sqlite3_vfs</a> should be 1 for SQLite version 3.5.0. + This number may increase in future versions of SQLite if we have to + modify the VFS object in some way. We hope that this never happens, + but the provision is made in case it does. +</p> +<p> + The szOsFile field is the size in bytes of the structure that defines + an open file: the <a href="c3ref/file.html">sqlite3_file</a> object. This object will be described + more fully below. The point here is that each VFS implementation can + define its own <a href="c3ref/file.html">sqlite3_file</a> object containing whatever information + the VFS implementation needs to store about an open file. SQLite needs + to know how big this object is, however, in order to preallocate enough + space to hold it. +</p> +<p> + The mxPathname field is the maximum length of a file pathname that + this VFS can use. SQLite sometimes has to preallocate buffers of + this size, so it should be as small as reasonably possible. Some + filesystems permit huge pathnames, but in practice pathnames rarely + extend beyond 100 bytes or so. You do not have to put the longest + pathname that the underlying filesystem can handle here. You only + have to put the longest pathname that you want SQLite to be able to + handle. A few hundred is a good value in most cases. +</p> +<p> + The pNext field is used internally by SQLite. Specifically, SQLite + uses this field to form a linked list of registered VFSes. +</p> +<p> + The zName field is the symbolic name of the VFS. This is the name + that the <a href="c3ref/vfs_find.html">sqlite3_vfs_find()</a> compares against when it is looking for + a VFS. +</p> +<p> + The pAppData pointer is unused by the SQLite core. The pointer is + available to store auxiliary information that a VFS information might + want to carry around. +</p> +<p> + The remaining fields of the <a href="c3ref/vfs.html">sqlite3_vfs</a> object all store pointers + to functions that implement primitive operations. We call these + "methods". The first method, xOpen, is used to open files on + the underlying storage media. The result is an <a href="c3ref/file.html">sqlite3_file</a> + object. There are additional methods, defined by the <a href="c3ref/file.html">sqlite3_file</a> + object itself that are used to read and write and close the file. + The additional methods are detailed below. The filename is in UTF-8. + SQLite will guarantee that the zFilename string passed to + xOpen() is a full pathname as generated by xFullPathname() and + that the string will be valid and unchanged until xClose() is + called. So the <a href="c3ref/file.html">sqlite3_file</a> can store a pointer to the + filename if it needs to remember the filename for some reason. + The flags argument to xOpen() is a copy of the flags argument + to sqlite3_open_v2(). If sqlite3_open() or sqlite3_open16() + is used, then flags is <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_READWRITE</a> | <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_CREATE</a>. + If xOpen() opens a file read-only then it sets *pOutFlags to + include <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_READONLY</a>. Other bits in *pOutFlags may be + set. + SQLite will also add one of the following flags to the xOpen() + call, depending on the object being opened: + <ul> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_MAIN_DB</a> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_MAIN_JOURNAL</a> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_TEMP_DB</a> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_TEMP_JOURNAL</a> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_TRANSIENT_DB</a> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_SUBJOURNAL</a> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_SUPER_JOURNAL</a> + </ul> + The file I/O implementation can use the object type flags to + changes the way it deals with files. For example, an application + that does not care about crash recovery or rollback, might make + the open of a journal file a no-op. Writes to this journal are + also a no-op. Any attempt to read the journal returns <a href="rescode.html#ioerr">SQLITE_IOERR</a>. + Or the implementation might recognize the a database file will + be doing page-aligned sector reads and writes in a random order + and set up its I/O subsystem accordingly. + SQLite might also add one of the following flags to the xOpen + method: + <ul> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_DELETEONCLOSE</a> + <li> <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_EXCLUSIVE</a> + </ul> + The <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_DELETEONCLOSE</a> flag means the file should be + deleted when it is closed. This will always be set for TEMP + databases and journals and for subjournals. The + <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_EXCLUSIVE</a> flag means the file should be opened + for exclusive access. This flag is set for all files except + for the main database file. + The <a href="c3ref/file.html">sqlite3_file</a> structure passed as the third argument to + xOpen is allocated by the caller. xOpen just fills it in. The + caller allocates a minimum of szOsFile bytes for the <a href="c3ref/file.html">sqlite3_file</a> + structure. +</p> +<p> + The differences between an <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_TEMP_DB</a> database and an + <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_TRANSIENT_DB</a> database is this: The <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_TEMP_DB</a> + is used for explicitly declared and named TEMP tables (using the + CREATE TEMP TABLE syntax) or for named tables in a temporary database + that is created by opening a database with a filename that is an empty + string. An <a href="c3ref/c_open_autoproxy.html">SQLITE_OPEN_TRANSIENT_DB</a> holds a database table that + SQLite creates automatically in order to evaluate a subquery or + ORDER BY or GROUP BY clause. Both TEMP_DB and TRANSIENT_DB databases + are private and are deleted automatically. TEMP_DB databases last + for the duration of the database connection. TRANSIENT_DB databases + last only for the duration of a single SQL statement. +</p> +<p> + The xDelete method is used to delete a file. The name of the file is + given in the second parameter. The filename will be in UTF-8. + The VFS must convert the filename into whatever character representation + the underlying operating system expects. If the syncDir parameter is + true, then the xDelete method should not return until the change + to the directory contents for the directory containing the + deleted file have been synced to disk in order to ensure that the + file does not "reappear" if a power failure occurs soon after. +</p> +<p> + The xAccess method is used to check for access permissions on a file. + The filename will be UTF-8 encoded. The flags argument will be + <a href="c3ref/c_access_exists.html">SQLITE_ACCESS_EXISTS</a> to check for the existence of the file, + <a href="c3ref/c_access_exists.html">SQLITE_ACCESS_READWRITE</a> to check to see if the file is both readable + and writable, or <a href="c3ref/c_access_exists.html">SQLITE_ACCESS_READ</a> to check to see if the file is + at least readable. The "file" named by the second parameter might + be a directory or folder name. +</p> +<p> + The xGetTempName method computes the name of a temporary file that + SQLite can use. The name should be written into the buffer given + by the second parameter. SQLite will size that buffer to hold + at least mxPathname bytes. The generated filename should be in UTF-8. + To avoid security problems, the generated temporary filename should + contain enough randomness to prevent an attacker from guessing the + temporary filename in advance. +</p> +<p> + The xFullPathname method is used to convert a relative pathname + into a full pathname. The resulting full pathname is written into + the buffer provided by the third parameter. SQLite will size the + output buffer to at least mxPathname bytes. Both the input and + output names should be in UTF-8. +</p> +<p> + The xDlOpen, xDlError, xDlSym, and xDlClose methods are all used for + accessing shared libraries at run-time. These methods may be omitted + (and their pointers set to zero) if the library is compiled with + <a href="compile.html#omit_load_extension">SQLITE_OMIT_LOAD_EXTENSION</a> or if the <a href="c3ref/enable_load_extension.html">sqlite3_enable_load_extension()</a> + interface is never used to enable dynamic extension loading. The + xDlOpen method opens a shared library or DLL and returns a pointer to + a handle. NULL is returned if the open fails. If the open fails, + the xDlError method can be used to obtain a text error message. + The message is written into the zErrMsg buffer of the third parameter + which is at least nByte bytes in length. The xDlSym returns a pointer + to a symbol in the shared library. The name of the symbol is given + by the second parameter. UTF-8 encoding is assumed. If the symbol + is not found a NULL pointer is returned. The xDlClose routine closes + the shared library. +</p> +<p> + The xRandomness method is used exactly once to initialize the + pseudo-random number generator (PRNG) inside of SQLite. Only + the xRandomness method on the default VFS is used. The xRandomness + methods on other VFSes are never accessed by SQLite. + The xRandomness routine requests that nByte bytes of randomness + be written into zOut. The routine returns the actual number of + bytes of randomness obtained. The quality of the randomness so obtained + will determine the quality of the randomness generated by built-in + SQLite functions such as random() and randomblob(). SQLite also + uses its PRNG to generate temporary file names. On some platforms + (ex: Windows) SQLite assumes that temporary file names are unique + without actually testing for collisions, so it is important to have + good-quality randomness even if the random() and randomblob() + functions are never used. +</p> +<p> + The xSleep method is used to suspend the calling thread for at + least the number of microseconds given. This method is used to + implement the <a href="c3ref/sleep.html">sqlite3_sleep()</a> and <a href="c3ref/busy_timeout.html">sqlite3_busy_timeout()</a> APIs. + In the case of <a href="c3ref/sleep.html">sqlite3_sleep()</a> the xSleep method of the default + VFS is always used. If the underlying system does not have a + microsecond resolution sleep capability, then the sleep time should + be rounded up. xSleep returns this rounded-up value. +</p> +<p> + The xCurrentTime method finds the current time and date and writes + the result as a double-precision floating point value into pointer + provided by the second parameter. The time and date is in + coordinated universal time (UTC) and is a fractional Julian day number. +</p> +<h4>2.1.5 The Open File Object</h4><p> + The result of opening a file is an instance of an <a href="c3ref/file.html">sqlite3_file</a> object. + The <a href="c3ref/file.html">sqlite3_file</a> object is an abstract base class defined as follows: +</p> +<blockquote><pre> +typedef struct sqlite3_file sqlite3_file; +struct sqlite3_file { + const struct sqlite3_io_methods *pMethods; +}; +</pre></blockquote><p> + Each VFS implementation will subclass the <a href="c3ref/file.html">sqlite3_file</a> by adding + additional fields at the end to hold whatever information the VFS + needs to know about an open file. It does not matter what information + is stored as long as the total size of the structure does not exceed + the szOsFile value recorded in the <a href="c3ref/vfs.html">sqlite3_vfs</a> object. +</p> +<p> + The <a href="c3ref/io_methods.html">sqlite3_io_methods</a> object is a structure that contains pointers + to methods for reading, writing, and otherwise dealing with files. + This object is defined as follows: +</p> +<blockquote><pre> +typedef struct sqlite3_io_methods sqlite3_io_methods; +struct sqlite3_io_methods { + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*); + int (*xFileControl)(sqlite3_file*, int op, void *pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + /* Additional methods may be added in future releases */ +}; +</pre></blockquote><p> + The iVersion field of <a href="c3ref/io_methods.html">sqlite3_io_methods</a> is provided as insurance + against future enhancements. The iVersion value should always be + 1 for SQLite version 3.5. +</p> +<p> + The xClose method closes the file. The space for the <a href="c3ref/file.html">sqlite3_file</a> + structure is deallocated by the caller. But if the <a href="c3ref/file.html">sqlite3_file</a> + contains pointers to other allocated memory or resources, those + allocations should be released by the xClose method. +</p> +<p> + The xRead method reads iAmt bytes from the file beginning at a byte + offset to iOfst. The data read is stored in the pointer of the + second parameter. xRead returns the <a href="rescode.html#ok">SQLITE_OK</a> on success, + <a href="rescode.html#ioerr_short_read">SQLITE_IOERR_SHORT_READ</a> if it was not able to read the full number + of bytes because it reached end-of-file, or <a href="rescode.html#ioerr_read">SQLITE_IOERR_READ</a> for + any other error. +</p> +<p> + The xWrite method writes iAmt bytes of data from the second parameter + into the file beginning at an offset of iOfst bytes. If the size of + the file is less than iOfst bytes prior to the write, then xWrite should + ensure that the file is extended with zeros up to iOfst bytes prior + to beginning its write. xWrite continues to extends the file as + necessary so that the size of the file is at least iAmt+iOfst bytes + at the conclusion of the xWrite call. The xWrite method returns + <a href="rescode.html#ok">SQLITE_OK</a> on success. If the write cannot complete because the + underlying storage medium is full, then <a href="rescode.html#full">SQLITE_FULL</a> is returned. + <a href="rescode.html#ioerr_write">SQLITE_IOERR_WRITE</a> should be returned for any other error. +</p> +<p> + The xTruncate method truncates a file to be nByte bytes in length. + If the file is already nByte bytes or less in length then this + method is a no-op. The xTruncate method returns <a href="rescode.html#ok">SQLITE_OK</a> on + success and <a href="rescode.html#ioerr_truncate">SQLITE_IOERR_TRUNCATE</a> if anything goes wrong. +</p> +<p> + The xSync method is used to force previously written data out of + operating system cache and into non-volatile memory. The second + parameter is usually <a href="c3ref/c_sync_dataonly.html">SQLITE_SYNC_NORMAL</a>. If the second parameter + is <a href="c3ref/c_sync_dataonly.html">SQLITE_SYNC_FULL</a> then the xSync method should make sure that + data has also been flushed through the disk controllers cache. + The <a href="c3ref/c_sync_dataonly.html">SQLITE_SYNC_FULL</a> parameter is the equivalent of the F_FULLSYNC + ioctl() on Mac OS X. The xSync method returns + <a href="rescode.html#ok">SQLITE_OK</a> on success and <a href="rescode.html#ioerr_fsync">SQLITE_IOERR_FSYNC</a> if anything goes wrong. +</p> +<p> + The xFileSize() method determines the current size of the file + in bytes and writes that value into *pSize. It returns <a href="rescode.html#ok">SQLITE_OK</a> + on success and <a href="rescode.html#ioerr_fstat">SQLITE_IOERR_FSTAT</a> if something goes wrong. +</p> +<p> + The xLock and xUnlock methods are used to set and clear file locks. + SQLite supports five levels of file locks, in order: + <ul> + <li> <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_NONE</a> + <li> <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_SHARED</a> + <li> <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_RESERVED</a> + <li> <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_PENDING</a> + <li> <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_EXCLUSIVE</a> + </ul> + The underlying implementation can support some subset of these locking + levels as long as it meets the other requirements of this paragraph. + The locking level is specified as the second argument to both xLock + and xUnlock. The xLock method increases the locking level to the + specified locking level or higher. The xUnlock method decreases the + locking level to no lower than the level specified. + <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_NONE</a> means that the file is unlocked. <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_SHARED</a> + gives permission to read the file. Multiple database connections can + hold <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_SHARED</a> at the same time. + <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_RESERVED</a> is like <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_SHARED</a> in that it is permission + to read the file. But only a single connection can hold a reserved lock + at any point in time. The <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_PENDING</a> is also permission to + read the file. Other connections can continue to read the file as well, + but no other connection is allowed to escalate a lock from none to shared. + <a href="c3ref/c_lock_exclusive.html">SQLITE_LOCK_EXCLUSIVE</a> is permission to write on the file. Only a single + connection can hold an exclusive lock and no other connection can hold + any lock (other than "none") while one connection holds an exclusive + lock. The xLock returns <a href="rescode.html#ok">SQLITE_OK</a> on success, <a href="rescode.html#busy">SQLITE_BUSY</a> if it + is unable to obtain the lock, or <a href="rescode.html#ioerr_rdlock">SQLITE_IOERR_RDLOCK</a> if something else + goes wrong. The xUnlock method returns <a href="rescode.html#ok">SQLITE_OK</a> on success and + <a href="rescode.html#ioerr_unlock">SQLITE_IOERR_UNLOCK</a> for problems. +</p> +<p> + The xCheckReservedLock() method checks to see if another connection or + another process is currently holding a reserved, pending, or exclusive + lock on the file. It returns true or false. +</p> +<p> + The xFileControl() method is a generic interface that allows custom + VFS implementations to directly control an open file using the + (new and experimental) + <a href="c3ref/file_control.html">sqlite3_file_control()</a> interface. The second "op" argument + is an integer opcode. The third + argument is a generic pointer which is intended to be a pointer + to a structure that may contain arguments or space in which to + write return values. Potential uses for xFileControl() might be + functions to enable blocking locks with timeouts, to change the + locking strategy (for example to use dot-file locks), to inquire + about the status of a lock, or to break stale locks. The SQLite + core reserves opcodes less than 100 for its own use. + A <a href="c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntllockstate">list of opcodes</a> less than 100 is available. + Applications that define a custom xFileControl method should use opcodes + greater than 100 to avoid conflicts. +</p> +<p> + The xSectorSize returns the "sector size" of the underlying + non-volatile media. A "sector" is defined as the smallest unit of + storage that can be written without disturbing adjacent storage. + On a disk drive the "sector size" has until recently been 512 bytes, + though there is a push to increase this value to 4KiB. SQLite needs + to know the sector size so that it can write a full sector at a + time, and thus avoid corrupting adjacent storage space if a power + loss occurs in the middle of a write. +</p> +<p> + The xDeviceCharacteristics method returns an integer bit vector that + defines any special properties that the underlying storage medium might + have that SQLite can use to increase performance. The allowed return + is the bit-wise OR of the following values: + <ul> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC512</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC1K</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC2K</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC4K</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC8K</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC16K</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC32K</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC64K</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_SAFE_APPEND</a> + <li> <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_SEQUENTIAL</a> + </ul> + The <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC</a> bit means that all writes to this device are + atomic in the sense that either the entire write occurs or none of it + occurs. The other + <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_ATOMIC<i>nnn</i></a> values indicate that + writes of aligned blocks of the indicated size are atomic. + <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_SAFE_APPEND</a> means that when extending a file with new + data, the new data is written first and then the file size is updated. + So if a power failure occurs, there is no chance that the file might have + been extended with randomness. The <a href="c3ref/c_iocap_atomic.html">SQLITE_IOCAP_SEQUENTIAL</a> bit means + that all writes occur in the order that they are issued and are not + reordered by the underlying file system. +</p> +<h4>2.1.6 Checklist For Constructing A New VFS</h4><p> + The preceding paragraphs contain a lot of information. + To ease the task of constructing + a new VFS for SQLite we offer the following implementation checklist: +</p> +<p> + <ol> + <li> Define an appropriate subclass of the <a href="c3ref/file.html">sqlite3_file</a> object. + <li> Implement the methods required by the <a href="c3ref/io_methods.html">sqlite3_io_methods</a> object. + <li> Create a static and + constant <a href="c3ref/io_methods.html">sqlite3_io_methods</a> object containing pointers + to the methods from the previous step. + <li> Implement the xOpen method that opens a file and populates an + <a href="c3ref/file.html">sqlite3_file</a> object, including setting pMethods to + point to the <a href="c3ref/io_methods.html">sqlite3_io_methods</a> object from the previous step. + <li> Implement the other methods required by <a href="c3ref/vfs.html">sqlite3_vfs</a>. + <li> Define a static (but not constant) <a href="c3ref/vfs.html">sqlite3_vfs</a> structure that + contains pointers to the xOpen method and the other methods and + which contains the appropriate values for iVersion, szOsFile, + mxPathname, zName, and pAppData. + <li> Implement a procedure that calls <a href="c3ref/vfs_find.html">sqlite3_vfs_register()</a> and + passes it a pointer to the <a href="c3ref/vfs.html">sqlite3_vfs</a> structure from the previous + step. This procedure is probably the only exported symbol in the + source file that implements your VFS. + </ol> +</p> +<p> + Within your application, call the procedure implemented in the last + step above as part of your initialization process before any + database connections are opened. +</p> +<h2>3.0 The Memory Allocation Subsystem</h2><p> + Beginning with version 3.5, SQLite obtains all of the heap memory it + needs using the routines <a href="c3ref/free.html">sqlite3_malloc()</a>, <a href="c3ref/free.html">sqlite3_free()</a>, and + <a href="c3ref/free.html">sqlite3_realloc()</a>. These routines have existed in prior versions + of SQLite, but SQLite has previously bypassed these routines and used + its own memory allocator. This all changes in version 3.5.0. +</p> +<p> + The SQLite source tree actually contains multiple versions of the + memory allocator. The default high-speed version found in the + "mem1.c" source file is used for most builds. But if the SQLITE_MEMDEBUG + flag is enabled, a separate memory allocator the "mem2.c" source file + is used instead. The mem2.c allocator implements lots of hooks to + do error checking and to simulate memory allocation failures for testing + purposes. Both of these allocators use the malloc()/free() implementation + in the standard C library. +</p> +<p> + Applications are not required to use either of these standard memory + allocators. If SQLite is compiled with <a href="compile.html#omitfeatures">SQLITE_OMIT_MEMORY_ALLOCATION</a> + then no implementation for the <a href="c3ref/free.html">sqlite3_malloc()</a>, <a href="c3ref/free.html">sqlite3_realloc()</a>, + and <a href="c3ref/free.html">sqlite3_free()</a> functions is provided. Instead, the application + that links against SQLite must provide its own implementation of these + functions. The application provided memory allocator is not required + to use the malloc()/free() implementation in the standard C library. + An embedded application might provide an alternative memory allocator + that uses memory for a fixed memory pool set aside for the exclusive + use of SQLite, for example. +</p> +<p> + Applications that implement their own memory allocator must provide + implementation for the usual three allocation functions + <a href="c3ref/free.html">sqlite3_malloc()</a>, <a href="c3ref/free.html">sqlite3_realloc()</a>, and <a href="c3ref/free.html">sqlite3_free()</a>. + And they must also implement a fourth function: +</p> +<blockquote><pre> +int sqlite3_memory_alarm( + void(*xCallback)(void *pArg, sqlite3_int64 used, int N), + void *pArg, + sqlite3_int64 iThreshold +); +</pre></blockquote><p> + The <a href="c3ref/aggregate_count.html">sqlite3_memory_alarm</a> routine is used to register + a callback on memory allocation events. + This routine registers or clears a callback that fires when + the amount of memory allocated exceeds iThreshold. Only + a single callback can be registered at a time. Each call + to <a href="c3ref/aggregate_count.html">sqlite3_memory_alarm()</a> overwrites the previous callback. + The callback is disabled by setting xCallback to a NULL + pointer. +</p> +<p> + The parameters to the callback are the pArg value, the + amount of memory currently in use, and the size of the + allocation that provoked the callback. The callback will + presumably invoke <a href="c3ref/free.html">sqlite3_free()</a> to free up memory space. + The callback may invoke <a href="c3ref/free.html">sqlite3_malloc()</a> or <a href="c3ref/free.html">sqlite3_realloc()</a> + but if it does, no additional callbacks will be invoked by + the recursive calls. +</p> +<p> + The <a href="c3ref/soft_heap_limit.html">sqlite3_soft_heap_limit()</a> interface works by registering + a memory alarm at the soft heap limit and invoking + <a href="c3ref/release_memory.html">sqlite3_release_memory()</a> in the alarm callback. Application + programs should not attempt to use the <a href="c3ref/aggregate_count.html">sqlite3_memory_alarm()</a> + interface because doing so will interfere with the + <a href="c3ref/soft_heap_limit.html">sqlite3_soft_heap_limit()</a> module. This interface is exposed + only so that applications can provide their own + alternative implementation when the SQLite core is + compiled with <a href="compile.html#omitfeatures">SQLITE_OMIT_MEMORY_ALLOCATION</a>. +</p> +<p> + The built-in memory allocators in SQLite also provide the following + additional interfaces: +</p> +<blockquote><pre> +sqlite3_int64 sqlite3_memory_used(void); +sqlite3_int64 sqlite3_memory_highwater(int resetFlag); +</pre></blockquote><p> + These interfaces can be used by an application to monitor how + much memory SQLite is using. The <a href="c3ref/memory_highwater.html">sqlite3_memory_used()</a> routine + returns the number of bytes of memory currently in use and the + <a href="c3ref/memory_highwater.html">sqlite3_memory_highwater()</a> returns the maximum instantaneous + memory usage. Neither routine includes the overhead associated + with the memory allocator. These routines are provided for use + by the application. SQLite never invokes them itself. So if + the application is providing its own memory allocation subsystem, + it can omit these interfaces if desired. +</p> +<h2>4.0 The Mutex Subsystem</h2><p> + SQLite has always been threadsafe in the sense that it is safe to + use different SQLite database connections in different threads at the + same time. The constraint was that the same database connection + could not be used in two separate threads at once. SQLite version 3.5.0 + relaxes this constraint. +</p> +<p> + In order to allow multiple threads to use the same database connection + at the same time, SQLite must make extensive use of mutexes. And for + this reason a new mutex subsystem as been added. The mutex subsystem + as the following interface: +</p> +<blockquote><pre> +sqlite3_mutex *sqlite3_mutex_alloc(int); +void sqlite3_mutex_free(sqlite3_mutex*); +void sqlite3_mutex_enter(sqlite3_mutex*); +int sqlite3_mutex_try(sqlite3_mutex*); +void sqlite3_mutex_leave(sqlite3_mutex*); +</pre></blockquote><p> + Though these routines exist for the use of the SQLite core, + application code is free to use these routines as well, if desired. + A mutex is an <a href="c3ref/mutex.html">sqlite3_mutex</a> object. The <a href="c3ref/mutex_alloc.html">sqlite3_mutex_alloc()</a> + routine allocates a new mutex object and returns a pointer to it. + The argument to <a href="c3ref/mutex_alloc.html">sqlite3_mutex_alloc()</a> should be + <a href="c3ref/c_mutex_fast.html">SQLITE_MUTEX_FAST</a> or <a href="c3ref/c_mutex_fast.html">SQLITE_MUTEX_RECURSIVE</a> for non-recursive + and recursive mutexes, respectively. If the underlying system does + not provide non-recursive mutexes, then a recursive mutex can be + substituted in that case. The argument to <a href="c3ref/mutex_alloc.html">sqlite3_mutex_alloc()</a> + can also be a constant designating one of several static mutexes: + <ul> + <li> <a href="c3ref/c_mutex_fast.html">SQLITE_MUTEX_STATIC_MAIN</a> + <li> <a href="c3ref/c_mutex_fast.html">SQLITE_MUTEX_STATIC_MEM</a> + <li> <a href="c3ref/c_mutex_fast.html">SQLITE_MUTEX_STATIC_MEM2</a> + <li> <a href="c3ref/c_mutex_fast.html">SQLITE_MUTEX_STATIC_PRNG</a> + <li> <a href="c3ref/c_mutex_fast.html">SQLITE_MUTEX_STATIC_LRU</a> + </ul> + These static mutexes are reserved for use internally by SQLite + and should not be used by the application. The static mutexes + are all non-recursive. +</p> +<p> + The <a href="c3ref/mutex_alloc.html">sqlite3_mutex_free()</a> routine should be used to deallocate + a non-static mutex. If a static mutex is passed to this routine + then the behavior is undefined. +</p> +<p> + The <a href="c3ref/mutex_alloc.html">sqlite3_mutex_enter()</a> attempts to enter the mutex and blocks + if another threads is already there. <a href="c3ref/mutex_alloc.html">sqlite3_mutex_try()</a> attempts + to enter and returns <a href="rescode.html#ok">SQLITE_OK</a> on success or <a href="rescode.html#busy">SQLITE_BUSY</a> if another + thread is already there. <a href="c3ref/mutex_alloc.html">sqlite3_mutex_leave()</a> exits a mutex. + The mutex is held until the number of exits matches the number of + entrances. If <a href="c3ref/mutex_alloc.html">sqlite3_mutex_leave()</a> is called on a mutex that + the thread is not currently holding, then the behavior is undefined. + If any routine is called for a deallocated mutex, then the behavior + is undefined. +</p> +<p> + The SQLite source code provides multiple implementations of these + APIs, suitable for varying environments. If SQLite is compiled with + the SQLITE_THREADSAFE=0 flag then a no-op mutex implementation that + is fast but does no real mutual exclusion is provided. That + implementation is suitable for use in single-threaded applications + or applications that only use SQLite in a single thread. Other + real mutex implementations are provided based on the underlying + operating system. +</p> +<p> + Embedded applications may wish to provide their own mutex implementation. + If SQLite is compiled with the -DSQLITE_MUTEX_APPDEF=1 compile-time flag + then the SQLite core provides no mutex subsystem and a mutex subsystem + that matches the interface described above must be provided by the + application that links against SQLite. +</p> +<h2>5.0 Other Interface Changes</h2><p> + Version 3.5.0 of SQLite changes the behavior of a few APIs in ways + that are technically incompatible. However, these APIs are seldom + used and even when they are used it is difficult to imagine a + scenario where the change might break something. The changes + actually makes these interface much more useful and powerful. +</p> +<p> + Prior to version 3.5.0, the <a href="c3ref/enable_shared_cache.html">sqlite3_enable_shared_cache()</a> API + would enable and disable the shared cache feature for all connections + within a single thread - the same thread from which the + sqlite3_enable_shared_cache() routine was called. Database connections + that used the shared cache were restricted to running in the same + thread in which they were opened. Beginning with version 3.5.0, + the sqlite3_enable_shared_cache() applies to all database connections + in all threads within the process. Now database connections running + in separate threads can share a cache. And database connections that + use shared cache can migrate from one thread to another. +</p> +<p> + Prior to version 3.5.0 the <a href="c3ref/soft_heap_limit.html">sqlite3_soft_heap_limit()</a> set an upper + bound on heap memory usage for all database connections within a + single thread. Each thread could have its own heap limit. Beginning + in version 3.5.0, there is a single heap limit for the entire process. + This seems more restrictive (one limit as opposed to many) but in + practice it is what most users want. +</p> +<p> + Prior to version 3.5.0 the <a href="c3ref/release_memory.html">sqlite3_release_memory()</a> function would + try to reclaim memory from all database connections in the same thread + as the sqlite3_release_memory() call. Beginning with version 3.5.0, + the sqlite3_release_memory() function will attempt to reclaim memory + from all database connections in all threads. +</p> +<h2>6.0 Summary</h2><p> + The transition from SQLite version 3.4.2 to 3.5.0 is a major change. + Every source code file in the SQLite core had to be modified, some + extensively. And the change introduced some minor incompatibilities + in the C interface. But we feel that the benefits of the transition + from 3.4.2 to 3.5.0 far outweigh the pain of porting. The new + VFS layer is now well-defined and stable and should simplify future + customizations. The VFS layer, and the separable memory allocator + and mutex subsystems allow a standard SQLite source code amalgamation + to be used in an embedded project without change, greatly simplifying + configuration management. And the resulting system is much more + tolerant of highly threaded designs. +</p> + +<p align="center"><small><i>This page last modified on <a href="https://sqlite.org/docsrc/honeypot" id="mtimelink" data-href="https://sqlite.org/docsrc/finfo/pages/34to35.in?m=ea67967bbd60713dd">2020-06-18 21:18:56</a> UTC </small></i></p> + |