JSONB has landed
sqlite.org
sqlite.org
To your application, using JSONB looks very similar to the JSON datatype. You still read and write JSON strings—Your application will never see the raw JSONB content. The same SQL functions are available, with a different prefix (jsonb_). Very little changes from the application's view.
The difference is that the JSON datatype is stored to disk as JSON, whereas the JSONB is stored in a special binary format. With the JSON datatype, the JSON must be parsed in full to perform any operation against the column. With the JSONB datatype, operations can be performed directly against the on-disk format, skipping the parsing step entirely.
If you're just using SQLite to write and read full JSON blobs, the JSON datatype will be the best pick. If you're querying or manipulating the data using SQL, JSONB will be the best pick.
"An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array."
Defined yes, but still arbitrary and may not be consistent between JSON values of the same schema, as per the document you linked to:
> in ascending chronological order of property creation
Also, while JSON came from JS sort-of, it is, for better or worse (better than XML!) a standard apart from JS with its own definitions and used in many other contexts. JSON as specified does not have a prescribed order for properties, so it is not safe to assume one. JS may generally impose a particular order, but other things may not when [re]creating a JSON string from their internal format (JSONB in this case), so by assuming a particular order will be preserved you would be relying on a behaviour that is undefined in the context of JSON.
Because it is idiomatic in that language, and you often don't need the higher overhead of tracking insertion order.
Before Python 3.7, json.loads used dict (undefined order) and you needed to explicitly need to override the load calls with the kwarg `object_pairs_hook=collections.OrderedDict` to accept ordered dictionaries.
Since Python 3.7 all `dict`s are effectively `collections.OrderedDict` because people now expect this kind of inefficient default behavior everywhere. ¯\_(ツ)_/¯
ON part of JSON doesn't know about objects. When serialized, object entries are just an array of key-value pairs with a weird syntax and a well-defined order. That's true for any serialization format actually.
It's the JS part of JSON that imposes non-duplicate keys with undefined order constraint.
You are the engineer, you can decide how you use your tools depending on your use case. Unless eg. you need interop with the rest of the world, it's your JSON, (mis)treat it to your heart's content.
The text I quoted is from the RFC. json.org and ECMA-404 both agree. You are welcome to do whatever you want, but then it isn't JSON anymore.
JSON formatted data remains JSON no matter if you use it incorrectly.
This happens all the time in the real world - applications unknowingly rely on undefined (but generally true) behavior. If you e.g. need to integrate with a legacy application where you're not completely sure how it handles JSON, then it's likely better to use plain text JSON.
You may take the risk as well, but then good luck explaining that those devs 10 years out of the company are responsible for the breakage happening after you've converted JSON to JSONB.
In some cases, insisting on ignoring the key order is too expensive luxury, since it basically forces you to parse the whole document first and only then process it. In case you have huge documents, you have to stream-read and this often implies relying on a particular key order (which isn't a problem since those same huge documents will likely be stream-written with a particular order too).
> The JSON syntax does not impose any restrictions on the strings used as names, does not require that name strings be unique, and does not assign any significance to the ordering of name/value pairs. These are all semantic considerations that may be defined by JSON processors or in specifications defining specific uses of JSON for data interchange.
If you work in environments that respect JSON key order (like browser and I think also Python) then unordered behavior of JSONB would be the exception not the rule.
Actually since ES2015 the iteration order of object properties is fully defined: first integer keys, then string keys in insertion order, finally symbols in insertion order. (Of course, symbols cannot be represented in JSON.)
And duplicate properties in JSON are guaranteed to be treated the same way they are in object literals: a duplicate overwrites the previous value but doesn't change the order of the key.
Concretely that means if you write:
Object.entries(JSON.parse('{"a":10, "1":20, "b":30, "a":40}'))
This is guaranteed to evaluate to: [['1', 20], ['a', 40], ['b', 30]]
(Note that '1' was moved to front, and 'a' comes before 'b' even though the associated value comes from the final entry in the JSON code.)Python made a similar change in version 3.6 (officially since 3.7), both with regards to insertion order and later values overwriting earlier ones while preserving order. I think the only difference at this point is that Python doesn't move integer-like keys to the front, because unlike JavaScript, Python properly distinguishes between different key types.
Read JSON from TEXT column.
Parse JSON into Internal Binary Format.
Run json_*() function on this format, which will Serialize Internal Binary Format to JSON as output.
To:
Read JSONB from BLOB column.
Run json_*() function on Internal Binary Format, which will serialize the Internal Binary Format to JSON as output.
Because:
The json_* and jsonb_* all accept _either_ JSON or JSONB as their input. The difference is jsonb_* functions also produces it as output. So even in the above case, if your function output is just being used to feed back into another table as a BLOB, then you can use the jsonb_* version of the function and skip the serialization step entirely.
I don’t think that’s always correct (it is within this thread, which stated (way up) “if you’re always reading/writing the full blob”, but I think this discussion is more general by now). Firstly, it need not convert the full jsonb blob (example: jsonb_extract(field,'$.a.b.c.d.e'))
Secondly, it need not convert to text at all, for example when calling a jsonb_* function that returns jsonb.
(Technically, whether any implementation is that smart is an implementation detail, but the article claims this is
“a rewrite of the SQLite JSON functions that, depending on usage patterns, could be several times faster than the original JSON functions”
so it can’t be completely dumb.
The "built-in validation mechanism" is invoking json_valid(X) [1] call within the CHECK [2] condition on a column.
[1] https://www.sqlite.org/json1.html#jvalid
[2] also assumes you didn't disable CHECKs with PRAGMA ignore_check_constraints https://www.sqlite.org/pragma.html#pragma_ignore_check_const...
There'll also be a conversion cost if you ultimately want it back in JSON form.
> JSONB is also slightly smaller than text JSON in most cases (about 5% or 10% smaller) so you might also see a modest reduction in your database size if you use a lot of JSON.
Jsonb_extract(jsonb(foo), '€')
likely- will remove/change white space in ‘foo’,
- does not guarantee to keep field order
- will fail if a dictionary in the ‘foo’ string has duplicate fields
- will fail if ‘foo’ doesn’t contain a valid json string
It seems that the JSON type is even able to contain JSONB. So why even use these functions, if the normal ones don't care?
There are some other minor advantages of having exact representation of the original - e.g. hashing, signatures, equality comparison is much simpler on the JSON string (you need a strict key order, which is again undefined by the spec, but happens in the real world anyway).
If you're modifying something "in-place" then `jsonb_` functions would be better since they avoid conversion.
I don't know how the driver is written, but this is misleading if sqlite provides an api to read the jsonb data with a in-memory copy, an app can surely benefit from skipping the json string parsing.
That's not exactly right, as the jsonb_* functions return JSONB if you choose to use them.
There is no json data type ! If you are just storing json blobs, then the BLOB or TEXT data types will be the best picks.
Why not? I feel like a database should allow for a JSON data type that stores only valid JSON or throws an exception. It would also be nice to be able to access subfields of the JSON.
SELECT userid, username, some_json_field["some_subfield"][0] FROM users where ...
Not sure where to give feature suggestions so I'm just leaving this here for future devs to find
create table foo(my_json json);
insert into foo values ('{"a":{"b":{"c":"d"}}}' FORMAT JSON);
select (my_json)."a"."b"."c" from foo; -- where the () around the field is mandatory
https://h2database.com/html/grammar.html#field_referenceNot that it's not _useful_ sometimes, but it amuses me that this is a huge violation of 1NF and people are often ok with it. It really depends on whether you're treating the JSON object as an atomic unit on its own, regardless of contents, or using the JSON to store more fine-grained information.
I guess the same argument can be made for XML data types, and everyone's OK with it too.
They are successful beyond anything that I can imagine people expecting when creating them. But they are not that complete silver bullet that solves every problem humanity will ever need solved.
You can access subfields using `json_` and `jsonb_` functions.
If i just need the messages between certain temperatures i can speed this up by adding an index on the 'temperature' field in json.
create or replace view bme680_v(ts, message, temperature, humidity, pressure, gas, iaq) as
SELECT mqtt_raw.created_at AS ts
, mqtt_raw.message
, (mqtt_raw.message::jsonb ->> 'temperature'::text)::numeric AS temperature
, (mqtt_raw.message::jsonb ->> 'humidity'::text)::numeric AS humidity
, (mqtt_raw.message::jsonb ->> 'pressure'::text)::numeric AS pressure
, (mqtt_raw.message::jsonb ->> 'gas_resistance'::text)::numeric AS gas
, (mqtt_raw.message::jsonb ->> 'IAQ'::text)::numeric AS iaq
FROM mqtt_raw
WHERE mqtt_raw.topic::text = 'pi/bme680'::text
ORDER BY mqtt_raw.created_at DESC;Rule of thumb: if you are not sure, or do not have time for the nuances, just use JSONB.
So use it for writes:
UPDATE t SET col = jsonb_*(?)
Also use it for filters if applicable (although this seems like a niche use case, I can't actually think of an example).But if returning values you probably want to use `json_*` functions
SELECT json_extract(col1, '$.myProp') FROM t
Otherwise you will end up receiving the binary format.This may be desired - it makes two effectively-equal objects have the same representation at rest!
But if you are storing human-written JSON - say, configs from an internal interface, where one might collocate a “__foo_comments” key above “foo” - their layout will be lost, and this may lead to someone visually seeing their changes scrambled on save.
When keys are not unique, their order can matter again, and can matter differently to different parsers.
Additionally, Javascript environments (formalized in ES2015), your text editor, and your filesystem all guarantee that they'll preserve object key order when JSON is evaluated. It's not unreasonable that someone would expect this of their database!
Yes, but only for non-integer keys.
> JSON.stringify({'one': 1, '3': 3, 'two': 2, '2': 2, 'three': 3, '1': 1})
'{"1":1,"2":2,"3":3,"one":1,"two":2,"three":3}'If you use the database's JSON type(s) and/or functions, then yes, your database is a JSON processor.
And, yes, your database is not a dumb store, not if it's an RDBMS. The whole point of it is that it's not a dumb store.
For example, JavaScript JSON.stringify and JSON.parse have well-defined behaviour:
> Properties are visited using the same algorithm as Object.keys(), which has a well-defined order and is stable across implementations
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
> The traversal order, as of modern ECMAScript specification, is well-defined and consistent across implementations. Within each component of the prototype chain, all non-negative integer keys (those that can be array indices) will be traversed first in ascending order by value, then other string keys in ascending chronological order of property creation.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Similarly, Python json module guarantees that "encoders and decoders preserve input and output order by default. Order is only lost if the underlying containers are unordered." Since 3.7 dict maintains insertion order.
https://docs.python.org/3/library/json.html
https://docs.python.org/3/library/stdtypes.html#dict
Yes, JS and Python behaviour are not the same for all cases, however, non-integer keys do maintain order across Python and JavaScript.
For any one implementation. But there's a very large number of implementations. You just can't count on object key order being preserved, so don't.
I also gave an example of two implementations that are compatible for a useful subset of keys. By the way, SQLite JSONB keeps object keys in insertion order, similar to Python: https://news.ycombinator.com/item?id=38547254
You might have to just normalize every time you want to edit that.
UPDATE: I think SQLite JSONB does maintain order. For example:
select json(jsonb('{"a": 1, "b": 2, "c": 3, "d": 4}'));"
-- {"a":1,"b":2,"c":3,"d":4}
And it does maintain order when adding new keys: select json(jsonb_insert(jsonb('{"a": 1, "b": 2, "c": 3, "d": 4}'), '$.e', 99));
-- {"a":1,"b":2,"c":3,"d":4,"e":99}
(tested on https://codapi.org/sqlite/)JSON never guarantees any ordering. From json.org:
> An object is an unordered set of name/value pairs.
If you depend on a given implementation doing so, you're depending on a quirk of that implementation, not on a JSON-defined behavior.
Fair enough when considering only the string value. My ill-expressed point was more about JSON as a data exchange format - it may pass through any number of JSON parser/storage implementations, any of which may use an arbitrary order for the keys.
Originally JSONB used only offsets, but that made it incompressible. That held up a PostgreSQL release for some time while they figured out what to do about it.
> The "JSONB" name is inspired by PostgreSQL, but the on-disk format for SQLite's JSONB is not the same as PostgreSQL's. The two formats have the same name, but they have wildly different internal representations and are not in any way binary compatible.
> The "JSONB" name is inspired by PostgreSQL, but the on-disk format for SQLite's JSONB is not the same as PostgreSQL's. The two formats have the same name, but they have wildly different internal representations and are not in any way binary compatible.
Definitely is not: Hipp states
> JSONB is also slightly smaller than text JSON in most cases (about 5% or 10% smaller)
Whereas in Postgres jsonb commonly takes 10~20% more space than json.
EDIT: https://sqlite.org/draft/jsonb.html does say that they are different.
Sqlite's JSONB keeps numbers as strings, which is slower but preserves your weird JSON (since there's no such thing as standard JSON). I'm not sure about duplicate keys.
I-JSON is the most sensible JSON profile I know of: https://datatracker.ietf.org/doc/html/rfc7493. It says: UTF-8 only, prefer not to use numbers beyond IEEE 754-2008 binary64 precision, no duplicate keys, and a couple more things.
You would probably be string quoting your numbers in your data/model if this matters to you so sounds like the right call from PG implementation.
If key order has to be preserved then a blob type would be a better fit, then you're guaranteed to get back what you wrote.
For example, SQLite says it stores JSON as regular text but MySQL converts it to an internal representation[2], so if you migrate you might be in trouble.
[1]: https://ecma-international.org/publications-and-standards/st...
>An object is an unordered set of name/value pairs.
# select '{ "id": "\u0000" }'::json;
-> { "id": "\u0000" }
# select '{ "id": "\u0000" }'::jsonb;
-> ERROR: unsupported Unicode escape sequence
Once you accept this then it stops being a problem.
I get full type support by serializing and deserializing protobuf messages from a db column and not making this column JSONB means i can filter this column too, instead of having to flatten the searchable data to other columns.
You just have to be vigilant about correctly migrating existing data to the current shape if you ever make breaking changes to types.
For now i use sqlite to deal with transactions and only make backward compatible updates to structs. Brittle, but it is a toy app anyways.
(Normally use django to deal with models and migrations, but wanted to do something different)
I gave it a good go to use mongo and firestore for a few projects, but after a year or two of experimenting I'll be sticking to SQL based DBs unless there are super clear and obvious benefits to using a document based model.
* meaning, when there's enough code that depends on it that changing it would require some planning
Though most of the time, in that situation, I would pull it out.
But I tend to just use Django. Every time I try piecing together the parts (ex FastAPI, Pydantic, Alembic, etc) I reach a point where I realize I’m recreating a half baked Django, and kick myself for not starting with Django in the first place.
I don't use SQLite directly much, but I'd be keen to use this in Cloudflare's D1 & Fly.io. Having said that though, I'm not sure they publicise sqlite version (or even that it isn't customised) - double-checking now they currently only talk about importing SQLite3 dumps or compatible .sql files, not actually that it is SQLite.
So API changes like this actually break that promise don't they? Even though you wouldn't normally think of an addition (of `jsonb_*` functions) as being a major change (and I know it isn't semver anyway) they are for Cloudflare's promise of being able to import SQLite-compatible dumps/query files, which wouldn't previously have but henceforth might contain those functions.
So does sqlite's. An implementation detail, even a necessarily stable one, does not a format make.
That was the previous step. Binary BLOBs have been supported in SQLite for some time.
CREATE TABLE data(id, name, age);
WITH ins AS (
SELECT c1.value, c2.value, c3.value
FROM json_each('["some", "uuid", "key"]') c1
INNER JOIN json_each('["joe", "sam", "phil"]') c2 USING (id)
INNER JOIN json_each('[10, 20, 30]') c3 USING (id)
)
INSERT INTO data (id, name, age)
SELECT * FROM ins
Each json_each could accept a bind parameter with JSONB BLOB from an app.I typically do bulk inserts using a single JSON argument like this:
WITH ins AS (SELECT e.value ->> 'id', e.value ->> 'name', e.value ->> 'age' FROM json_each(?) e)
INSERT INTO data (id, name, age)
SELECT * FROM ins
The same approach can be used for bulk updates and deletes as well. WITH ins AS (
SELECT value ->> 0, value ->> 1, value ->> 2
FROM json_each('[["some", "joe", 10], ["uuid", "sam", 20], ["key", "phil", 30]]')
)
INSERT INTO data (id, name, value)
SELECT * FROM insEdit: Sorry, just saw the comment below by o11c,
> Sqlite's JSONB keeps numbers as strings
which means the answer to my question is basically "no".
select jsonb_extract('{"foo": {"bar": 42}}', '$.foo');
┌────────────────────────────────────────────────┐
│ jsonb_extract('{"foo": {"bar": 42}}', '$.foo') │
├────────────────────────────────────────────────┤
│ |7bar#42 │
└────────────────────────────────────────────────┘Why not add this size indication to JSON specification. Would reduce memory requirements for JSON processing.
1997: https://cr.yp.to/proto/netstrings.txt
NB. This header may be the "central idea" behind JSONB but JSONB has other differences from JSON. This comment refers only to the size indication not the other features.
I encourage you to view this talk from PGConf NYC 2021 - Understanding of Jsonb Performance by Oleg Bartunov [1]
Looking forward to a similar talk from the SQLite community on JSONB performance in the future.
This way it can efficiently store numbers , dates, uuids or raw binary etc. and should really have some sort of key interning to efficiently store repeating key names.
Then just have functions to convert to/from json if thats what you want
So is SQLite3 though.
I do wish that SQLite3 could get a CREATE TYPE command so that one could get a measure of static typing. Under the covers there would still be only the types that SQLite3 has now, so a CREATE TYPE would have to specify which one of those types underlies the user-defined type. I think this should be doable.
It feels like it would be better to use a known binary encoding. I thought the MessagePack data model corresponded pretty much exactly to JSON ?
Edit: someone else mentioned BSON - https://bsonspec.org/
To be honest the wins (in this draft) don't seem that compelling
The advantage of JSONB over ordinary text RFC 8259 JSON is that JSONB is both slightly smaller (by between 5% and 10% in most cases) and can be processed in less than half the number of CPU cycles.
JSON has been optimized to death; it seems like you could get the 2x gain and avoid a new format with normal optimization, or perhaps compile-time options for SIMD JSON techniques
---
And this seems likely to confuse:
The "JSONB" name is inspired by PostgreSQL, but the on-disk format for SQLite's JSONB is not the same as PostgreSQL's. The two formats have the same name, but they have wildly different internal representations and are not in any way binary compatible.
---
Any time data is serialized, SOMEBODY is going to read it. With something as popular as sqlite, that's true 10x over.
So to me, this seems suboptimal on 2 fronts.
> The JSONB format is not intended as an interchange format. Nevertheless, JSONB is stored in database files which are intended to be readable and writable for many decades into the future. To that end, the JSONB format is well-defined and stable. The separate SQLite JSONB format document provides details of the JSONB format for the curious reader.
And indeed the functions jsonb() and json() will let you convert to and from jsonb.
> Any time data is serialized, SOMEBODY is going to read it. With something as popular as sqlite, that's true 10x over.
And this statement is equally true for the SQLite format itself. That doesn't mean that the SQLite format should be replaced with something more standard, of course.
Either I'm experiencing a reading comprehension mishap or this is self contradictory. Where is a "2x gain" supposed to come from through "normal optimization" from after something has already been optimized "to death?"
> SIMD JSON techniques
Which are infeasible in key SQLite use cases.
The comment you are replying to cites a statement saying explicitly that they are not adopting the Postgres JSONB binary format, only the name and the abstract concept. The API is not compatible with Postgres either.
Points off for a.) inventing yet another binary JSON and/or b.) using the same name as an existing binary JSON.
> JSONB is not intended as an external format to be used by applications. JSONB is designed for internal use by SQLite only. Programmers do not need to understand the JSONB format in order to use it effectively. Applications should access JSONB only through the JSON SQL functions, not by looking at individual bytes of the BLOB.
> However, JSONB is intended to be portable and backwards compatible for all future versions of SQLite. In other words, you should not have to export and reimport your SQLite database files when you upgrade to a newer SQLite version. For that reason, the JSONB format needs to be well-defined.
If SQLite intends to own the format forever, I can believe that their requirements are such that leaning on an existing implementation is not worth the savings to implement.
It looks like they're aware of that ... it's probably fine -- not ideal, but fine
If users didn't care about what the blob format was, there wouldn't be JSON support in the first place! You would have started with something like JSONB
What's the advantage of re-using a format?
Ecosystem? That won't help SQLite here, who don't have dependencies.
Keep in mind that anyone trying to write a parser for this is also writing a parser for the entire SQLite file format (the only way to access bytes). And it's a spec simple enough to fit on one monitor.
Design?
BSON (and others?) seem to have different goals.
SQLite's format seems to minimise conversion/parsing (eg. it has multiple TEXT types depending on how much escaping is needed; BSON has one fully-parsed UTF-8 string type). BSON is more complex: includes many types not supported by json (dates, regexs, uuids...) and has a bunch of deprecated features already.
SQLite's on disk-format is something they intend to support "forever", and as with the rest of SQLite, they enjoy pragmatic simplicity.
Not the JSON format.
> [..] it seems like you could get the 2x gain and avoid a new format with normal optimization, or perhaps compile-time options for SIMD JSON techniques
SIMD isn't always appropriate, and there are still no SIMD incremental JSON parsers either. There are things that can't easily be done with SIMD and JSON.
TCL.
The C integration API to Sqlite is very simple and small, so a) almost all languages will have bindings, and b) any bindings that exist will be reasonable.
https://modernc.org/sqlite https://github.com/ncruces/go-sqlite3
There's.. no need to interop with PG's JSONB encoding, I think. If so then SQLite3's could differ from PG's.
Anyways, it'd be nice if TFA was clearer on this point.
EDIT: https://sqlite.org/draft/jsonb.html does refer to PG's JSONB, and says that they are different.
- json is used a lot by sql.js users to interact with JavaScript.
- to generate more sophisticated web pages in SQLPage, json is crucial
I can't wait for the next release !
Those bags of data are usually called "documents". And a lot of systems need a way to store them along relational data.
If you're just storing and retrieving those documents, without any query, you don't need JSONB, a simple blob is enough.
If you sometimes need to do some queries, especially free queries (you want all component whose configuration has some property), then JSONB is suitable as it lets you do the filtering in the database.
This feels like a slippery slope into a denormalised mess though. Before you know it your whole client record is a document and you’re using Postgres as a NoSQL database
Such use cases may not be quite as optimized as relational usecases, but they should be possible. If you are doing that then perhaps a different database would be nicer or faster for that scenario, but again not PostgreSQL's concern.
If the PostgreSQL devs were relational purists they would never have added special support for querying JSON.
An application may be better served with a properly normalized schema, or it might not. That is a choice for the application developers to make.
In practice competent developers should quickly realize if they went too nosql when a relational approach would provide benefits (Like if multiple "documents" need to reference consistent shared data, or if json query performance is not good enough) and normalize as needed to get those advantages.
So long as the application does not contain random sql queries scattered everywhere (and doesnt treat its database as a sort of API for external access) then database refactoring is not impossible. Indeed the difficulty is often overestimated. It is seldom fun work, and tends to be a bit of a slog, and require more extensive testing before pushing to prod, but that happens.
Performance, when records are complex and usually not accessed.
Ease, avoiding/postponing table design decisions.
Flexibility, for one of many corner-cases (since sqlite is a very broad tool).
Incremental enhancement, e.g. when starting with sqlite as replacement to an ndjson-file and incrementally taking advantage of transactions and indexes on fields [1,2,3].
For example, several of these could apply when doing structured logging to a sqlite database.
[1]: https://www.sqlite.org/expridx.html
[2]: https://www.sqlite.org/gencol.html
[3]: https://antonz.org/json-virtual-columns/
See also: https://www.sqlite.org/json1.html[1]: https://www.sqlite.org/expridx.html
[2]: https://www.sqlite.org/gencol.html
[3]: https://antonz.org/json-virtual-columns/
See also: https://www.sqlite.org/json1.html
When you format links as code, they don't become links.
And it just keeps getting better and better and better, and faster and faster and faster.
I don't know how these guys manage to succeed where almost all other projects fail, but I hope they keep going.
Just wondering how they will transition once the original few people at the top of the hierarchy need to retire, eventually it will happen.
I guess they need to find younger trusted committers with the same dedication and spirit. That's not necessarily easy. But for a piece of software as important as SQLite, I have a feeling they will find those.
I had always viewed this as a "future worry", and then Bram Moolenaar passed away :(
- They draft behind others, and I mean this in a good way. They seem to eschew trailblazing new features, but keep a close eye on alternatives (esp. Postgres) and how use cases are emerging. When a sufficiently interesting concept has stabilized, they bring it to SQLite.
- Closely related to this, they seem to stay clear of technical and community distractions. They have their plans and execute.
- I don't know if D. Richard Hipp is considered a BDFL, but that's my impression and he seems good at it.
Go get a pro subscription with each of your competitors :)
"I suggest SQLite because the source code is superb (seriously, some of the most readable, most logically organized and best commented C code you'll ever see)" https://news.ycombinator.com/item?id=12559301
"it never hurts to look at a good open-source codebase written in C, for example the SQLite code is worth looking at (if a bit overwhelming)" https://news.ycombinator.com/item?id=33132772
They have a proprietary (not open source) test suite with 100% branch coverage. That makes it impossible to have credible forks of SQLite3. And it makes the gatekeepers valuable because SQLite3 is the most widely used piece of software ever built. So there's a SQLite Consortium, and all the big tech players that depend on SQLite3 are members, and that's how the SQLite team pays the bills.
This is a problem with WAFs, not databases. Postgres and SQL Server both provide prepared statements as an alternative to string concatenation, which addresses SQL injection. (Though some people may be stuck with legacy or vendor-contolled systems that they can't fix, and so WAFs are their only option.)