Postgres wire compatible SQLite proxy
github.com
github.com
https://twitter.com/benbjohnson/status/1508927916561743872
It's a recurring theme with SQLite. Many developers are on-board with using it as a database but when you tell them that they also have to SSH in and use a CLI exclusively then they are turned off. Postlite is meant to alleviate that pain.
I wrote a PgBouncer alternative awhile back using that library, and in the span of only about 1200 SLoC, I had a fully functional alternative that...
- benchmarked better than PgBouncer for me
- avoided the need for the annoying session, transaction, statement modes by just Doing The Right Thing. If you prepare an anonymous statement, it holds that connection for you until you execute the prepared statement. If you open a transaction, it holds that connection for you until you commit or rollback that transaction.
- offered control over whether to set application_name for the DB connection whenever one is acquired by a client connection, and whether to also clear application_name or not when the connection is released.
It's relatively straightforward to detect when a SELECT query comes through, so I had planned to add transparent read replica support to route SELECT queries to read replicas if you aren't in a transaction. I also never got around to implementing TLS support, but... that should be trivial in Go.
Longer term, I also thought it would be cool to implement some extensions to the Postgres wire protocol, like end to end compression with zstd. You might have an application in one datacenter querying a Postgres database in another, and depending on the size of datasets that you're getting back from the database, compression could make a huge difference. You could also imagine implementing a "double proxy" where a proxy is running both locally and in the remote datacenter, and it would implement the non-standard postgres extensions behind the scenes, presenting a purely standard wire protocol to any client that connects.
Since this was just a fun side project that was never proven in production, I've never gotten around to open sourcing it. I also wish it actually had some tests... but those haven't happened yet. I don't want to mislead people into thinking I consider this side project to be production ready, but I don't remember any obvious problems. If people were actually interested, I could open up the repo, but this comment is less about self-promotion and more about how impressed I've been with that particular wire protocol library, but I admittedly do also enjoy talking about side projects. If anyone needs to do something with Postgres's protocol, I would highly recommend it.
[1]: https://github.com/benbjohnson/postlite/blob/main/server.go
Do not worry about it being buggy, or even it being bad (design, or code). Let others do that work for you :-)
It took a few minutes since I had to add a license and README, plus I did a quick test of it locally to make sure it still worked, which helped me discover that SASL authentication needed to be implemented, so I added that.
I agree other people could be interested in contributing, I'm just not sure how much interest there actually is for a PgBouncer alternative.
Do you know of a package/application/library that can be used to validate just the FEBE protocal of Postgres, and possibly stress/performance test it, as well. Such a test-suite would be great to independently test the various implementations of Postgres wire-compatible projects and products, including your roundabout.
A pair of programs. One to emulate Postgres server, another to emulate a Postgres client. These two programs would assume they are just talking to each other, and know exactly what to expect from the other side.
Then we can inject a protocol implementer (the system under test, or SUT) between these two programs and see if the SUT can make both these programs believe that they are still talking just with each other. This way we can validate the level of protocol support by the SUT. And if we can run this whole setup, multiple clients, a server, and the SUT, under controlled conditions, we can also evaluate the performance of each such protocol implementation.
The Postgres client emulator would send a predefined set of commands, and would know exactly what the response should be. The Postgres server emulator would know exactly what commands to expect, and the hard-coded responses to send for each incoming command.
The client emulator's knowledge of the responses would make it easy to catch any errors/bugs introduced by the SUT.
The Postgres server emulator would _not_ implement any server-side logic (command parsing, planning, etc.), to ensure the peak performance for each command it processes.
I was thinking of implementing such a Postgres server emulator back in around 2014, but for a different reason. IIRC, I was thinking of calling it Black Hole Postgres, to test the performance of my TPC-C implementation, DBYardstick [1].
The Django ORM has provided the ability to test against SQLite and deploy against PostgreSQL with the same code base (and the same tests) for years - and while it works incredibly well, I still won't use that in any system that I build. How your database behaves is such a crucial component of your application!
These days I find spinning up a real PostgreSQL database to run the tests is so easy there's essentially no reason not to do it. I use GitHub Actions for my PostgreSQL testing insurance, and it ends up just being a few extra lines in the YAML file.
You could also run SQLite in production. Then you don't have to test against a different database locally. :)
Works well if you are not trying to watch real time processes as they write to the db.
You can do basically anything you would need to do to a database with it, and it’s very performant and cross platform.
The implication is that "if you can do it in postgres, you can do it in X". But the reality is, of course, different.
If you are using databases properly, not just as a blackbox dumping ground, then if you use postgres on the wire, its because you are talking to postgres and using postgres specific features (like you should).
Unless you have feature parity, don't tell me I can connect to another database using my postgres libraries. Its pointless. Its meaningless. Why would I want to do that if I can't use the features ?
Rant over. ;-)
I'm not saying it's what I would've done (I have little use for GUI database tooling), but I can see why someone else might.
> Supports all popular databases: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Apache Hive, Phoenix, Presto, etc.
> Postlite is a network proxy to allow access to remote SQLite databases over the Postgres wire protocol. This allows GUI tools to be used on remote SQLite databases which can make administration easier.
The readme does not seem to advertise this software as being a drop-in replacement for Postgres by any means, although I can understand your frustration with database vendors that market their software as such. I suspect they used Postgres as the wire format because otherwise they would need to invent one from scratch, and then work with existing tools to integrate. Leveraging the Postgres wire form means they can integrate with existing GUI tools on day one, and seems to be a very pragmatic choice.
SQL itself is only a vague standard these days, as almost every single database has its own dialect. The only ones that are the same are MariaDB and MySQL... and that doesn't count. [1] And I don't see this situation changing in the medium term, or ever, really.
[1] ... because the first is the fork of the second.
I think the comparison is more like "is having an ad-hoc semi-standard wire protocol built around the postgres one better than having none at all?" and I think the answer is yes.
But it's not like there's an authority making this choice for everyone. If you think something else is better then use it in your tools and push for it. Postgres is ancient, open source, widely used and adapted for many different use cases. I think those all make it hard to beat in just a practical "worse is better" type way, but I also think people saying "no. we can do better" is good too, esp when they demonstrate it.
https://www.postgresql.org/docs/current/libpq-pipeline-mode....
So are SQLite drivers (and MySQL and all the other top-10/top-20 databases).
Why add un-necessary abstraction ?
Why add an un-necessary layer with bugs and edge-cases that you will subsequently waste hours of your life debugging ?
Plus, if we are talking about drivers, then surely if you're going to be using SQLite, you should be using SQLite drivers because they will be inherently simpler and smaller than the Postgres ones because of the much reduced feature-set of SQLite.
> What SQLite3 driver out there allows you to talk over a network connection to a remote database?
(Replied here because I can't reply to your point below)
Maybe that's because, as per the SQLite website[1], SQLite was never intended to be used as a client/server database !!!
I would argue that by attempting to "square peg round hole" SQLite into being a network database, you are only opening yourself up for unknown troubles down the road.
There are many excellent client/server databases out there (including the postgres referred to here). If you need that functionality you should be using the right tool for the job, there's no need to shoehorn SQLite into it.
What SQLite3 driver out there allows you to talk over a network connection to a remote database? Not any one that I've ever used.
It depends a lot on what you're using the remote connectivity for.
I think I have a pretty good understanding of SQLite's strengths+capabilities, enough to understand when it can replace a traditional RDBMS for a back-end service. I wouldn't build a solution where multiple clients are connecting to the DB remotely - but sometimes I want the convenience of connecting to the DB remotely for observability/troubleshooting. This is something that's trivial with traditional RDBMSs, and a bit painful with SQLite.
Exposing the SQLite DB over the network for occasional interactive use seems quite useful to me.
You can even move the abstraction down a level with non-relational databases like Cassandra and Elastic offering SQL interfaces. They don't offer relational features, but let you express queries using a relational language.
Also, sqlite doesn't support INTERVAL which I personally use heavily in postgres.
Curious how the author plans to deal with this since they mentioned they're interested in supporting BI tools that presumably wouldn't issue sqlite queries if they think they're talking to postgres.
I don't have any plans for query translation except for some basic client startup query handling (e.g. SET, SHOW). Postlite is really just meant as a thin shim to allow GUI tools to work remotely on SQLite databases.
> Postlite is a network proxy to allow access to remote SQLite databases over the Postgres wire protocol. This allows GUI tools to be used on remote SQLite databases which can make administration easier.
This is about using SQLite with existing tools that don't have support for it. It's very common since it's easier to support multiple remote database servers (MySQL, Postgres) vs adding the in-process model for SQLite only.
Also you need to take the context into account - Fly.io has SQLite databases distributed across their nodes (see their post about replacing Consul [1]) and most likely want to be able to manage those remotely. Since SQLite doesn't have a server protocol, tools that have bindings for it only support working with local databases.
Unlikely. A lot of such tools are mainly for displaying the data that's present; they might have support for displaying e.g. GIS types but they're not going to need to write GIS data into the database, and certainly not to the point where you can't run them at all if that's not possible.
So the idea is very nice, but any existing tool for PostgreSQL will not work. You need to either work with the psql terminal application or write a new client.
> Many Postgres clients also inspect the pg_catalog to determine system information so Postlite mirrors this catalog by using an attached in-memory database with virtual tables.
I guess these days the best approach for connecting arbitrary data sources to existing drivers, at least for OLAP, is Apache Calcite (https://calcite.apache.org/). Unfortunately that feels a little more involved.
ODBC > Bridging configurations: https://en.wikipedia.org/wiki/Open_Database_Connectivity#Bri...
awesome-graphql > tools: security: https://github.com/chentsulin/awesome-graphql#tools---securi...
... W3C SOLID > Authorization and Access Control: https://github.com/solid/solid-spec#authorization-and-access...
"Hosting SQLite Databases on GitHub Pages" (2021) re: sql.js-httpvfs, DuckDB https://news.ycombinator.com/item?id=28021766
[edit] TIL the MS ODBC 4.0 spec is MIT Licensed, on GitHub , and supports ~challenge/response token auth: "3.2.2 Web-based Authentication Flow with SQLBrowseConnect" https://github.com/microsoft/ODBC-Specification/blob/master/...
> Applications that are unable to allow drivers to pop up dialogs can call SQLBrowseConnect to connect to the service.
> SQLBrowseConnect provides an iterative dialog between the driver and the application where the application passes in an initial input connection string. If the connection string contains sufficient information to connect, the driver responds with SQL_SUCCESS and an output connection string containing the complete set of connection attributes used.
> If the initial input connection string does not contain sufficient information to connect to the source, the driver responds with SQL_NEED_DATA and an output connection string specifying informational attributes for the application (such as the authorization url) as well as required attributes to be specified in a subsequent call to SQLBrowseConnect. Attribute names returned by SQLBrowseConnect may include a colon followed by a localized identifier, and the value of the requested attribute is either a single question mark or a comma-separated list of valid values (optionally including localized identifiers) enclosed in curly braces. Optional attributes are returned preceded with an asterix (*).
> In a Web-based authentication scenario, if SQLBrowseConnect is called with an input connection string containing an access token that has not expired, along with any other required properties, no additional information should be required. If the access token has expired and the connection string contains a refresh token, the driver attempts to refresh the connection using the supplied refresh token.
Also TIL ODBC 4.0 supports: https://github.com/microsoft/ODBC-Specification :
> Semi-structured data – Tables whose schema may not be defined or may change on a row-by-row basis
> Hierarchical Data – Data with nested structure (structured fields, lists)
> Web Authentication model
If there were you could basically query and write to a SQLite database entirely through http.
You could then use that plus the above network proxy to move a Sqlite3 database off of the local system to a remote system, without having to change the existing codebase.
This would also give you multiple remote clients as well.
Thanks for this, it never occurred to me that I could improve on ssh + sqlite3 on the cli, but here it is.
Great for those times when I want to check some data but don’t want to ssh in