The SQLite library contains a number of utility functions that are useful for both application developers, and those working on SQLite extensions. Most of these are not required for basic database tasks, but if your code is strongly tied to SQLite, you may find these particularly useful.
There are several functions available to query the version of the SQLite
library. Each API call has a corresponding #define
macro that declares the same value.
SQLITE_VERSION_NUMBER
int sqlite3_libversion_number( )
Returns the SQLite library version as an integer.
The format is MNNNPPP
,
where M
is the major
version (3, in this case),
N
is the minor number,
and P
is the point
release. This format allows for releases up to
3.999.999. If a sub-point release is made, it will
not be indicated in this version number.
If you’re building your own application, you can
use the
#define
macros and the function
calls to verify that you’re using the correct header for the available
library. The #define
values come
from the header file, and are set when your application is compiled.
The function calls return the same values that were baked into the
library when it was compiled.
If you’re using a dynamic library of some sort, you can use these macros and functions to prevent your application from linking with a library version other than the one it was originally compiled against. This might not be a good thing, however, as it will also prevent upgrades. If you need to lock in a specific version, you should probably be using a static library.
If you want to check the validity of a dynamic library, it might be better to do something like this:
if ( SQLITE_VERSION_NUMBER > sqlite3_libversion_number( ) ) { /* library too old; report error and exit. */ }
Remember that the macro will hold the version used when your code was compiled, while the function call will return the version of the SQLite library. In this case, we report an error if the library is older (smaller version) than the one used to compile and build the application code.
When SQLite needs to dynamically allocate memory, it normally calls the default memory handler of the underlying operating system. This causes SQLite to allocate its memory from the application heap. However, SQLite can also be configured to do its own internal memory management (see sqlite3_config() in Appendix G). This is especially important on embedded and hand-held devices where memory is limited and overallocation may lead to stability problems.
Regardless, you can access whatever memory manager SQLite is using with these SQLite memory management functions:
void* sqlite3_malloc( int numBytes )
Allocates and returns a buffer of the size specified. If the memory cannot be allocated, a NULL pointer is returned. Memory will always be 8-byte (64-bit) aligned.
This is a replacement for the
standard C library malloc()
function.
void* sqlite3_realloc( void *buffer, int numBytes )
Used to resize a memory allocation. Buffers can be made
larger or smaller. Given a buffer previously
returned by sqlite3_malloc()
and a byte count,
*_realloc()
will allocate a new buffer of the specified size and
copy as much of the old buffer as will fit into the
new buffer. It will then free the old buffer and
return the new buffer. If the new buffer cannot be
allocated, a NULL is returned and the original
buffer is not freed.
If the buffer pointer is NULL,
the call is equivalent to a call to sqlite3_malloc()
. If the
numBytes
parameter is zero or negative, the call is
equivalent to a call to sqlite3_free()
.
This is a replacement for the
standard C library realloc()
function.
void sqlite3_free( void *buffer )
Releases a memory buffer previously allocated by
sqlite3_malloc()
or sqlite3_realloc()
. Also
used to free the results or buffers of a number of
SQLite API functions that call sqlite3_malloc()
internally.
This is a replacement for the
standard C library free()
function.
While a number of SQLite calls require the use of
sqlite3_free()
, application
code is free to use whatever memory management is most appropriate.
Where these functions become extremely useful is in writing custom
functions, virtual tables, or any type of loadable module. Since this
type of code is meant to operate in any SQLite environment, you will
likely want to use these memory management functions to ensure the
maximum portability for your code.