SQLite is really easy to compile into your application. However Linux and BSD maintainers prefer to have a single centralized shared library and have all platform provided programs use that. You can see a (very long) list of platforms and their SQLite version here.
SQLite can be compiled with many options such as full text search which almost all seem to enable, even though it defaults off. That got me curious to see what they all do different than the default.
I went off and investigated, with the per platform details at the end.
Commentary
It was noticeable just how arbitrary each platform seemed. With the exception of OpenBSD, every platform had several configuration settings to their defaults. This does not result in any warnings of errors. It is generally the result of things like JSON which used to be off by default, and had to be explicitly enabled, but is now on by default. I don't know of any reasonable way for maintainers to find out that they are redundantly setting things to their default values.
COLUMN_METADATA
Column metadata is enabled by everyone. I did see some comments saying that Firefox needs it (and UNLOCK_NOTIFY), but it is enabled even by platforms that don't ship Firefox.
My own experience with Python developers has been that many also use COLUMN_METADATA, and I suspect many other dynamic languages like Ruby, Perl, and Lua do too. The problem is you can't map the text of a SQL query back to named columns because SQL queries are too difficult to parse and manipulate. Other databases provide the column and table names for query results, so code out there expects it. Even the Python database spec (DBAPI aka PEP249) requires it.
Best practice is to explicitly name the result columns (using AS) and this works without requiring COLUMN_METADATA.
SELECT name AS name, SUM(abc) AS abc_count, two.name AS two_name
FROM contacts, two;
Extensions
FTS3 and FTS4 are enabled by default, but FTS5 is not. There is a good description of the differences. I measured how big extensions compiled on my system are, as a percentage of the SQLite library with all extensions enabled (1.6MB)
Extension | Size | Percent |
---|---|---|
FTS3 & 4 | 93kb | 6% |
FTS5 | 200kb | 13% |
JSON | 50kb | 3% |
Session | 53kb | 3% |
Soundex | 813 bytes | 0% |
MAX_VARIABLE_NUMBER
This I can't make any sense of. You can use numbered bindings, that start at 1.
SELECT name, email FROM contacts WHERE name = ? AND age < ?;
When programmatically executing this, you would supply bindings number 1 and 2. It is also possible to explicitly number them, so in this example you'd provide 97 of them although only 73 and 97 are used.
SELECT ?73, ?97;
You can also provide bindings by name using :, $, or @ like this, providing the bindings as a hash/dictionary type object to the API:
SELECT :foo, $bar, @bam;
The default limit on numbered bindings is 32,767. I cannot think of any scenario under which you would want there to be a quarter or half a million of them, yet that happens!
USE_URI
URI filenames let you easily provide extra parameters when opening a database. You can programmatically turn on URI filenames, but unfortunately that has to be done very first thing after loading SQLite but before using it which is hard to arrange. You can also use SQLITE_OPEN_URI when calling sqlite3_open_v2 added in 2007.
I'm guessing this default was added to some platforms years ago and never changed.
Security
SECURE_DELETE ensures deleted data is overwritten with zeroes. Without it, old data can still be visible to anyone examining the database file contents. It can also be controlled by a pragma. There is a good case to be made for it to be on by default to avoid unintentionally leaking data, for example when databases are backed up, or shared with other people.
API_ARMOR helps defend against programming errors, which are especially easy to make in C. As a maintainer I would enable it, because a more complex program using SQLite often uses lots of libraries, and all it takes is a bug in any one of them to cause problems. Every few months an issue comes up in the SQLite forums where that has happened.
STRICT_SUBTYPE is off by default, with threats in the SQLite code that it may be turned on by default in the future. Maintainers should probably turn this on.
LIKE_DOESNT_MATCH_BLOBS should be on by default, because using LIKE doesn't make sense against blobs. For example what encoding should be used?
DQS isn't set by anyone, but really should be. The default setting allows developers to accidentally use double quotes for strings when they should be used for identifiers (column and table names etc) only. This is a frequent cause of bugs on the SQLite forums, because programming languages use double quotes, and it is easy to assume SQL does too. It doesn't.
Miscellaneous
STAT4 should get you better queries with multi-column indices.
I can't imagine why offset would be needed.
MAX_SCHEMA_RETRY defaults to 50, so I don't know why half that amount would make any difference.
Summary
Other than COLUMN_METADATA, there isn't much consistency between the platforms. SQLite is trying to serve many users, from tiny devices with trivial amounts of memory and storage, to gigantic servers with terabytes of databases, and corresponding amounts of CPU and RAM. Heck the default cache size is 2MB which is wrong for everyone.
So far platform maintainers are making decisions about what to configure for their platform, but that does result in redundancy, duplicated effort, and some amount of guessing.
SQLite doesn't tend to change things because there is an implicit guarantee that if you have a working program using SQLite, and you upgrade the SQLite library, then your program will continue to work.
There are recommended options which are appropriate when compiling SQLite for your own application, but not usable when providing SQLite for a platform used by many applications.
Details
Each entry shows what looked different to me as I did this by visual inspection looking at the default build rules for each platform. You can get more information by looking at https://www.sqlite.org/compile.html and I've left off SQLITE, ENABLE etc from the names. The most recent version of the platform is what I looked at,
You can use pragma compile_options on your own platform to see what is in use. SQLite can have different defaults between the plain library and the cli making this a little more confusing.
Platform | Configuration difference |
---|---|
MacOS | CKPTFULLFSYNC
JOURNAL_SIZE_LIMIT=32768
LOOKASIDE=1200,102
COLUMN_METADATA
FTS5
LOCKING_STYLE=1
NORMALIZE
PREUPDATE_HOOK
SESSION
SNAPSHOT
SQLLOG
STMT_SCANSTATUS
UPDATE_DELETE_LIMIT
HAS_CODEC_RESTRICTED
MAX_VARIABLE_NUMBER=500000
THREADSAFE=2
USE_URI
|
Debian | SECURE_DELETE
COLUMN_METADATA
SOUNDEX
UNLOCK_NOTIFY
ALLOW_ROWID_IN_VIEW
UPDATE_DELETE_LIMIT
LOAD_EXTENSION
LIKE_DOESNT_MATCH_BLOBS
USE_URI
MAX_SCHEMA_RETRY=25
PREUPDATE_HOOK
SESSION
STRICT_SUBTYPE
MAX_VARIABLE_NUMBER=250000
|
Fedora | COLUMN_METADATA
DISABLE_DIRSYNC
SECURE_DELETE
UNLOCK_NOTIFY
|
Gentoo | LOAD_EXTENSION
API_ARMOR
COLUMN_METADATA
EXPLAIN_COMMENTS
HIDDEN_COLUMNS
MEMSYS5
NORMALIZE
OFFSET_SQL_FUNC
PREUPDATE_HOOK
GEOPOLY
SESSION
STMT_SCANSTATUS
UNLOCK_NOTIFY
UPDATE_DELETE_LIMIT
SOUNDEX
USE_URI
|
Arch | COLUMN_METADATA
UNLOCK_NOTIFY
SECURE_DELETE
STAT4
MAX_VARIABLE_NUMBER=250000
MAX_EXPR_DEPTH=10000
FTS5
|
Termux | COLUMN_METADATA
UPDATE_DELETE_LIMIT
|
FreeBSD | DEFAULT_FILE_PERMISSIONS
DIRECT_READ
LOAD_EXTENSION
FTS5
COLUMN_METADATA
SECURE_DELETE
UNLOCK_NOTIFY
USE_URI
|
OpenBSD | FTS5
UNLOCK_NOTIFY
COLUMN_METADATA
|
Brew (homebrew) | API_ARMOR
COLUMN_METADATA
FTS5
MEMORY_MANAGEMENT
STAT4
UNLOCK_NOTIFY
MAX_VARIABLE_NUMBER=250000
USE_URI
PREUPDATE_HOOK
SESSION
|
Macports | DISABLE_INTRINSIC
COLUMN_METADATA
FTS5
SECURE_DELETE
STAT4
UNLOCK_NOTIFY
SOUNDEX
|
Nix | COLUMN_METADATA
FTS5
STMT_SCANSTATUS
UNLOCK_NOTIFY
SOUNDEX
SECURE_DELETE
MAX_VARIABLE_NUMBER=250000
MAX_EXPR_DEPTH=10000
|
Haikuports | COLUMN_METADATA
UNLOCK_NOTIFY
SECURE_DELETE
FTS5
|
msys2 | COLUMN_METADATA
DISABLE_DIRSYNC
SOUNDEX
PREUPDATE_HOOK
SESSION
(They also configure --enable-all)
|