<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: d-richard-hipp</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/d-richard-hipp.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2026-03-09T15:05:15+00:00</updated><author><name>Simon Willison</name></author><entry><title>Production query plans without production data</title><link href="https://simonwillison.net/2026/Mar/9/production-query-plans-without-production-data/#atom-tag" rel="alternate"/><published>2026-03-09T15:05:15+00:00</published><updated>2026-03-09T15:05:15+00:00</updated><id>https://simonwillison.net/2026/Mar/9/production-query-plans-without-production-data/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://boringsql.com/posts/portable-stats/"&gt;Production query plans without production data&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Radim Marek describes the new &lt;a href="https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADMIN-STATSMOD"&gt;&lt;code&gt;pg_restore_relation_stats()&lt;/code&gt; and &lt;code&gt;pg_restore_attribute_stats()&lt;/code&gt; functions&lt;/a&gt; that were introduced &lt;a href="https://www.postgresql.org/docs/current/release-18.html"&gt;in PostgreSQL 18&lt;/a&gt; in September 2025.&lt;/p&gt;
&lt;p&gt;The PostgreSQL query planner makes use of internal statistics to help it decide how to best execute a query. These statistics often differ between production data and development environments, which means the query plans used in production may not be replicable in development.&lt;/p&gt;
&lt;p&gt;PostgreSQL's new features now let you copy those statistics down to your development environment, allowing you to simulate the plans for production workloads without needing to copy in all of that data first.&lt;/p&gt;
&lt;p&gt;I found this illustrative example useful:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT pg_restore_attribute_stats(
    'schemaname', 'public',
    'relname', 'test_orders',
    'attname', 'status',
    'inherited', false::boolean,
    'null_frac', 0.0::real,
    'avg_width', 9::integer,
    'n_distinct', 5::real,
    'most_common_vals', '{delivered,shipped,cancelled,pending,returned}'::text,
    'most_common_freqs', '{0.95,0.015,0.015,0.015,0.005}'::real[]
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This simulates statistics for a &lt;code&gt;status&lt;/code&gt; column that is 95% &lt;code&gt;delivered&lt;/code&gt;. Based on these statistics PostgreSQL can decide to use an index for &lt;code&gt;status = 'shipped'&lt;/code&gt; but to instead perform a full table scan for &lt;code&gt;status = 'delivered'&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These statistics are pretty small. Radim says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Statistics dumps are tiny. A database with hundreds of tables and thousands of columns produces a statistics dump under 1MB. The production data might be hundreds of GB. The statistics that describe it fit in a text file.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I posted on the SQLite user forum asking if SQLite could offer a similar feature and D. Richard Hipp promptly replied &lt;a href="https://sqlite.org/forum/forumpost/480c5cb8a3898346"&gt;that it has one already&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All of the data statistics used by the query planner in SQLite are available in the &lt;a href="https://sqlite.org/fileformat.html#the_sqlite_stat1_table"&gt;sqlite_stat1 table&lt;/a&gt; (or also in the &lt;a href="https://sqlite.org/fileformat.html#the_sqlite_stat4_table"&gt;sqlite_stat4 table&lt;/a&gt; if you happen to have compiled with SQLITE_ENABLE_STAT4).  That table is writable. You can inject whatever alternative statistics you like.&lt;/p&gt;
&lt;p&gt;This approach to controlling the query planner is mentioned in the documentation:
&lt;a href="https://sqlite.org/optoverview.html#manual_control_of_query_plans_using_sqlite_stat_tables"&gt;https://sqlite.org/optoverview.html#manual_control_of_query_plans_using_sqlite_stat_tables&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See also &lt;a href="https://sqlite.org/lang_analyze.html#fixed_results_of_analyze"&gt;https://sqlite.org/lang_analyze.html#fixed_results_of_analyze&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The ".fullschema" command in the CLI outputs both the schema and the content of the sqlite_statN tables, exactly for the reasons outlined above - so that we can reproduce query problems for testing without have to load multi-terabyte database files.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/o8vbb7/production_query_plans_without"&gt;Lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sql"&gt;sql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;



</summary><category term="databases"/><category term="postgresql"/><category term="sql"/><category term="sqlite"/><category term="d-richard-hipp"/></entry><entry><title>Quoting D. Richard Hipp</title><link href="https://simonwillison.net/2025/Dec/29/d-richard-hipp/#atom-tag" rel="alternate"/><published>2025-12-29T21:51:49+00:00</published><updated>2025-12-29T21:51:49+00:00</updated><id>https://simonwillison.net/2025/Dec/29/d-richard-hipp/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://sigmodrecord.org/publications/sigmodRecord/1906/pdfs/06_Profiles_Hipp.pdf"&gt;&lt;p&gt;But once we got that and got this aviation grade testing in place, the number of bugs just dropped to a trickle. Now we still do have bugs but the aviation grade testing allows us to move fast, which is important because in this business you either move fast or you're disrupted. So, we're able to make major changes to the structure of the code that we deliver and be confident that we're not breaking things because we had these intense tests. Probably half the time we spend is actually writing new tests, we're constantly writing new tests. And over the 17-year history, we have amassed a huge suite of tests which we run constantly.&lt;/p&gt;
&lt;p&gt;Other database engines don't do this; don't have this
level of testing. But they're still high quality, I mean, I
noticed in particular, PostgreSQL is a very high-quality database engine, they don't have many bugs. I went to the PostgreSQL and ask them “how do you prevent the bugs”? We talked about this for a while. What I came away with was they've got a very elaborate peer review process, and if they've got code that has worked for 10 years they just don't mess with it, leave it alone, it
works. Whereas we change our code fearlessly, and we have a much smaller team and we don't have the peer review process.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://sigmodrecord.org/publications/sigmodRecord/1906/pdfs/06_Profiles_Hipp.pdf"&gt;D. Richard Hipp&lt;/a&gt;, ACM SIGMOD Record, June 2019 (PDF)&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;&lt;/p&gt;



</summary><category term="testing"/><category term="d-richard-hipp"/><category term="postgresql"/><category term="sqlite"/></entry><entry><title>Copyright Release for Contributions To SQLite</title><link href="https://simonwillison.net/2025/Dec/29/copyright-release/#atom-tag" rel="alternate"/><published>2025-12-29T19:58:45+00:00</published><updated>2025-12-29T19:58:45+00:00</updated><id>https://simonwillison.net/2025/Dec/29/copyright-release/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.sqlite.org/copyright-release.html"&gt;Copyright Release for Contributions To SQLite&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
D. Richard Hipp &lt;a href="https://news.ycombinator.com/item?id=46420453#46424225"&gt;called me out&lt;/a&gt; for spreading misinformation on Hacker News that SQLite refuses outside contributions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;No, Simon, we don't "refuse". We are just very selective and there is a lot of paperwork involved to confirm the contribution is in the public domain and does not contaminate the SQLite core with licensed code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I deeply regret this error! I'm linking to the copyright release document here - it looks like SQLite's public domain nature makes this kind of clause extremely important:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[...] To the best of my knowledge and belief, the changes and enhancements that I have contributed to SQLite are either originally written by me or are derived from prior works which I have verified are also in the public domain and are not subject to claims of copyright by other parties.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Out of curiosity I decided to see how many people have contributed to SQLite outside of the core team of Richard, Dan and Joe. I ran that query using Fossil, SQLite's own SQLite-based version control system, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install fossil
fossil clone https://www.sqlite.org/src sqlite.fossil
fossil sql -R sqlite.fossil "
  SELECT user, COUNT(*) as commits
  FROM event WHERE type='ci'
  GROUP BY user ORDER BY commits DESC
"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I got back 38 rows, though I think &lt;code&gt;danielk1977&lt;/code&gt; and &lt;code&gt;dan&lt;/code&gt; may be duplicates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: The SQLite team have clarified this on their &lt;a href="https://sqlite.org/copyright.html"&gt;SQLite is Public Domain&lt;/a&gt; page. It used to read "In order to keep SQLite completely free and unencumbered by copyright, the project does not accept patches." - it now reads:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In order to keep SQLite completely free and unencumbered by copyright, the project does not accept patches from random people on the internet. There is a process to get a patch accepted, but that process is involved and for smaller changes is not normally worth the effort.&lt;/p&gt;
&lt;/blockquote&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/open-source"&gt;open-source&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;



</summary><category term="open-source"/><category term="sqlite"/><category term="d-richard-hipp"/></entry><entry><title>Quoting D. Richard Hipp</title><link href="https://simonwillison.net/2024/Oct/18/d-richard-hipp/#atom-tag" rel="alternate"/><published>2024-10-18T01:21:44+00:00</published><updated>2024-10-18T01:21:44+00:00</updated><id>https://simonwillison.net/2024/Oct/18/d-richard-hipp/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://sqlite.org/forum/forumpost/3ce1ee76242cfb29"&gt;&lt;p&gt;I'm of the opinion that you should never use mmap, because if you get an I/O error of some kind, the OS raises a signal, which SQLite is unable to catch, and so the process dies. When you are not using mmap, SQLite gets back an error code from an I/O error and is able to take remedial action, or at least compose an error message.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://sqlite.org/forum/forumpost/3ce1ee76242cfb29"&gt;D. Richard Hipp&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;&lt;/p&gt;



</summary><category term="d-richard-hipp"/><category term="sqlite"/></entry><entry><title>Quoting D. Richard Hipp</title><link href="https://simonwillison.net/2024/Aug/28/d-richard-hipp/#atom-tag" rel="alternate"/><published>2024-08-28T22:30:28+00:00</published><updated>2024-08-28T22:30:28+00:00</updated><id>https://simonwillison.net/2024/Aug/28/d-richard-hipp/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://sqlite.org/forum/forumpost/2d2720461b82f2fd"&gt;&lt;p&gt;My goal is to keep SQLite relevant and viable through the year 2050. That's a long time from now. If I knew that standard SQL was not going to change any between now and then, I'd go ahead and make non-standard extensions that allowed for FROM-clause-first queries, as that seems like a useful extension. The problem is that standard SQL will &lt;em&gt;not&lt;/em&gt; remain static. Probably some future version of "standard SQL" will support some kind of FROM-clause-first query format. I need to ensure that whatever SQLite supports will be compatible with the standard, whenever it drops. And the only way to do that is to support nothing until after the standard appears.&lt;/p&gt;
&lt;p&gt;When will that happen? A month? A year? Ten years? Who knows.&lt;/p&gt;
&lt;p&gt;I'll probably take my cue from PostgreSQL. If PostgreSQL adds support for FROM-clause-first queries, then I'll do the same with SQLite, copying the PostgreSQL syntax. Until then, I'm afraid you are stuck with only traditional SELECT-first queries in SQLite.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://sqlite.org/forum/forumpost/2d2720461b82f2fd"&gt;D. Richard Hipp&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sql"&gt;sql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;&lt;/p&gt;



</summary><category term="d-richard-hipp"/><category term="sql"/><category term="postgresql"/><category term="sqlite"/></entry><entry><title>Datasette 0.64.7</title><link href="https://simonwillison.net/2024/Jun/12/datasette-0647/#atom-tag" rel="alternate"/><published>2024-06-12T22:55:00+00:00</published><updated>2024-06-12T22:55:00+00:00</updated><id>https://simonwillison.net/2024/Jun/12/datasette-0647/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://docs.datasette.io/en/stable/changelog.html#v0-64-7"&gt;Datasette 0.64.7&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
A very minor dot-fix release for Datasette stable, addressing &lt;a href="https://github.com/simonw/datasette/issues/2353"&gt;this bug&lt;/a&gt; where Datasette running against the latest version of SQLite - 3.46.0 - threw an error on canned queries that included &lt;code&gt;:named&lt;/code&gt; parameters in their SQL.&lt;/p&gt;
&lt;p&gt;The root cause was Datasette using &lt;a href="https://github.com/simonw/datasette/blob/7437d40e5dd4d614bb769e16c0c1b96c6c19647f/datasette/utils/__init__.py#L1137-L1150"&gt;a now invalid clever trick&lt;/a&gt; I came up with against the undocumented and unstable opcodes returned by a SQLite &lt;code&gt;EXPLAIN&lt;/code&gt; query.&lt;/p&gt;
&lt;p&gt;I asked on the SQLite forum and learned that the feature I was using was removed in &lt;a href="https://sqlite.org/src/info/dd5977c9a8a418be"&gt;this commit to SQLite&lt;/a&gt;. D. Richard Hipp &lt;a href="https://sqlite.org/forum/forumpost/1cafc721009cef7f"&gt;explains&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The P4 parameter to OP_Variable was not being used for anything. By omitting it, we make the prepared statement slightly smaller, reduce the size of the SQLite library by a few bytes, and help sqlite3_prepare() and similar run slightly faster.&lt;/p&gt;
&lt;/blockquote&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/annotated-release-notes"&gt;annotated-release-notes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;



</summary><category term="projects"/><category term="sqlite"/><category term="datasette"/><category term="annotated-release-notes"/><category term="d-richard-hipp"/></entry><entry><title>Quoting D. Richard Hipp</title><link href="https://simonwillison.net/2024/May/22/d-richard-hipp/#atom-tag" rel="alternate"/><published>2024-05-22T04:21:12+00:00</published><updated>2024-05-22T04:21:12+00:00</updated><id>https://simonwillison.net/2024/May/22/d-richard-hipp/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://github.com/sqlite/sqlite/commit/fd288f3549a1ab9a309a9e120d46319d42adea29#diff-d7c6125271929f399b173406a7151cd2734ceca66f1045b77f1795a37dc8c5da"&gt;&lt;p&gt;The default prefix used to be "sqlite_".  But then Mcafee started using SQLite in their anti-virus product and it started putting files with the "sqlite" name in the c:/temp folder. This annoyed many windows users.  Those users would then do a  Google search for "sqlite", find the telephone numbers of the developers and call to wake them up at night and complain. For this reason, the default name prefix is changed to be "sqlite"  spelled backwards.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://github.com/sqlite/sqlite/commit/fd288f3549a1ab9a309a9e120d46319d42adea29#diff-d7c6125271929f399b173406a7151cd2734ceca66f1045b77f1795a37dc8c5da"&gt;D. Richard Hipp&lt;/a&gt;, 18 years ago&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;&lt;/p&gt;



</summary><category term="d-richard-hipp"/><category term="sqlite"/></entry><entry><title>Quoting D. Richard Hipp</title><link href="https://simonwillison.net/2024/Apr/30/d-richard-hipp/#atom-tag" rel="alternate"/><published>2024-04-30T13:59:50+00:00</published><updated>2024-04-30T13:59:50+00:00</updated><id>https://simonwillison.net/2024/Apr/30/d-richard-hipp/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://news.ycombinator.com/item?id=40206752#40209833"&gt;&lt;p&gt;Performance analysis indicates that SQLite spends very little time doing bytecode decoding and dispatch. Most CPU cycles are consumed in walking B-Trees, doing value comparisons, and decoding records - all of which happens in compiled C code. Bytecode dispatch is using less than 3% of the total CPU time, according to my measurements.&lt;/p&gt;
&lt;p&gt;So at least in the case of SQLite, compiling all the way down to machine code might provide a performance boost 3% or less. That's not very much, considering the size, complexity, and portability costs involved.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://news.ycombinator.com/item?id=40206752#40209833"&gt;D. Richard Hipp&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;&lt;/p&gt;



</summary><category term="d-richard-hipp"/><category term="performance"/><category term="sqlite"/></entry><entry><title>Why SQLite Uses Bytecode</title><link href="https://simonwillison.net/2024/Apr/30/why-sqlite-uses-bytecode/#atom-tag" rel="alternate"/><published>2024-04-30T05:32:54+00:00</published><updated>2024-04-30T05:32:54+00:00</updated><id>https://simonwillison.net/2024/Apr/30/why-sqlite-uses-bytecode/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://sqlite.org/draft/whybytecode.html"&gt;Why SQLite Uses Bytecode&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Brand new SQLite architecture documentation by D. Richard Hipp explaining the trade-offs between a bytecode based query plan and a tree of objects.&lt;/p&gt;

&lt;p&gt;SQLite uses the bytecode approach, which provides an important characteristic that SQLite can very easily execute queries incrementally—stopping after each row, for example. This is more useful for a local library database than for a network server where the assumption is that the entire query will be executed before results are returned over the wire.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/DRichardHipp/status/1785037995101290772"&gt;@DRichardHipp&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sql"&gt;sql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;



</summary><category term="databases"/><category term="sql"/><category term="sqlite"/><category term="d-richard-hipp"/></entry><entry><title>Quoting D. Richard Hipp</title><link href="https://simonwillison.net/2023/Sep/18/d-richard-hipp/#atom-tag" rel="alternate"/><published>2023-09-18T18:02:37+00:00</published><updated>2023-09-18T18:02:37+00:00</updated><id>https://simonwillison.net/2023/Sep/18/d-richard-hipp/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://news.ycombinator.com/item?id=37558809"&gt;&lt;p&gt;Note that there have been no breaking changes since the [SQLite] file format was designed in 2004. The changes shows in the version history above have all be one of (1) typo fixes, (2) clarifications, or (3) filling in the "reserved for future extensions" bits with descriptions of those extensions as they occurred.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://news.ycombinator.com/item?id=37558809"&gt;D. Richard Hipp&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;&lt;/p&gt;



</summary><category term="d-richard-hipp"/><category term="sqlite"/></entry><entry><title>Quoting D. Richard Hipp</title><link href="https://simonwillison.net/2023/Feb/8/d-richard-hipp/#atom-tag" rel="alternate"/><published>2023-02-08T18:07:06+00:00</published><updated>2023-02-08T18:07:06+00:00</updated><id>https://simonwillison.net/2023/Feb/8/d-richard-hipp/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://news.ycombinator.com/item?id=34480732"&gt;&lt;p&gt;Many people, and even a few companies, have contributed code to SQLite over the years. I have legal documentation for all such contributions in the firesafe in my office. We are able to track every byte of the SQLite source code back to its original creator. The project has been and continues to be open to outside contributions, as long as those contributions meet high standards of provenance and maintainability.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://news.ycombinator.com/item?id=34480732"&gt;D. Richard Hipp&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/open-source"&gt;open-source&lt;/a&gt;&lt;/p&gt;



</summary><category term="d-richard-hipp"/><category term="sqlite"/><category term="open-source"/></entry><entry><title>Notes on the SQLite DuckDB paper</title><link href="https://simonwillison.net/2022/Sep/1/sqlite-duckdb-paper/#atom-tag" rel="alternate"/><published>2022-09-01T17:33:14+00:00</published><updated>2022-09-01T17:33:14+00:00</updated><id>https://simonwillison.net/2022/Sep/1/sqlite-duckdb-paper/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;a href="https://vldb.org/pvldb/volumes/15/paper/SQLite%3A%20Past%2C%20Present%2C%20and%20Future"&gt;SQLite: Past, Present, and Future&lt;/a&gt; is a newly published paper authored by Kevin P. Gaffney, Martin Prammer and Jignesh M. Patel from the University of Wisconsin-Madison and D. Richard Hipp, Larry Brasfield and Dan Kennedy from the core SQLite engineering team.&lt;/p&gt;
&lt;p&gt;The paper compares &lt;a href="https://www.sqlite.org/"&gt;SQLite&lt;/a&gt; and &lt;a href="https://duckdb.org/"&gt;DuckDB&lt;/a&gt;, and describes some optimization work to make SQLite perform better for analytical queries.&lt;/p&gt;
&lt;p&gt;DuckDB is a relatively new project which is frequently nicknamed (including by this paper) "SQLite for analytics". It shares many of the characteristics of SQLite: an embedded database implemented as a header file and implementation file (using C++ as opposed to SQLite's C) with databases that are theselves single binary files.&lt;/p&gt;
&lt;p&gt;The primary difference is that DuckDB is optimized for analytical queries: queries that apply aggregate calculations across large numbers of rows, rather than being optimized for fast scanning and lookup of individual rows of data.&lt;/p&gt;
&lt;p&gt;I've been &lt;a href="https://simonwillison.net/tags/duckdb/"&gt;tracking DuckDB for a while&lt;/a&gt; - it's a very exciting project. If I ever introduce alternative database backends to &lt;a href="https://datasette.io/"&gt;Datasette&lt;/a&gt; it's top of my list of things to try.&lt;/p&gt;
&lt;p&gt;The paper spends quite a bit of time on benchmark comparisons. To very loosely summarize those:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQLite out-performs DuckDB on a write transactions benchmark by 10x-500x on a powerful cloud server and 2x-60x on a Raspberry Pi, for small to large databases.&lt;/li&gt;
&lt;li&gt;For analytical benchmarks using the SSB (&lt;a href="https://www.cs.umb.edu/~poneil/StarSchemaB.PDF"&gt;Star Schema Benchmark&lt;/a&gt;) DuckDB out-performs SQLite by 30-50x at the highest margin and 3-8x at the lowest.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Neither of these are particularly surprising: DuckDB isn't optimized for write transactions and SQLite isn't optimized for analytical queries.&lt;/p&gt;
&lt;p&gt;Next, the paper explores optimizations that can be applied to SQLite to improve its analytical query performance.&lt;/p&gt;
&lt;p&gt;One of these has already shipped! In February 2022 the &lt;a href="https://www.sqlite.org/releaselog/3_38_0.html"&gt;SQLite 3.38.0&lt;/a&gt; release notes included this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use a Bloom filter to speed up large analytic queries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had wondered at the time what the deal with this was - the paper explains it in some detail:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A key change is made to the join processing, which is to probe the Bloom filters before carrying out the rest of the join. Applying the Bloom filters early in the join pipeline dramatically reduces the number of tuples that flow through the join pipeline, and thus improves performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This had a pretty big impact on the benchmark:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The performance impact of our optimizations is shown in Figure 6. On the Raspberry Pi, SQLite is now 4.2X faster on SSB. Our optimizations are particularly effective for query flight 2, resulting in 10X speedup. On the cloud server, we observed an overall speedup of 2.7X and individual query speedups up to 7X&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I decided to quote in full the first part of section 5, "future development", because it does a great job of describing some of the key features of the culture of SQLite itself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;5 FUTURE DEVELOPMENT&lt;/h4&gt;
&lt;p&gt;The developers intend to provide support for SQLite through the year 2050, and design decisions are made accordingly. SQLite’s code and database file format are fully cross-platform, ensuring that SQLite can run on any current or future platform with an 8-bit byte, two’s complement 32-bit and 64-bit integers, and a C compiler. Every machine-code branch in the SQLite library is tested with multiple platforms and compilers, which makes the code robust for future migrations. SQLite is also extensively documented and commented, which helps new developers quickly understand SQLite’s architecture. Finally, the developers work hard to evaluate new programming trends based on merit rather than popularity.&lt;/p&gt;
&lt;p&gt;While the performance gap has narrowed as a result of this work, DuckDB is still considerably faster than SQLite on SSB. This is somewhat expected; SQLite is a general-purpose database engine, whereas DuckDB is designed from the ground up for efficient OLAP. Although SQLite’s OLAP performance could be further improved in future work, there are several constraints that potential modifications to SQLite must satisfy.&lt;/p&gt;
&lt;p&gt;First, modifications should cause no significant performance regression across the broad range of workloads served by SQLite. Second, the benefit of an optimization must be weighed against its impact on the size of the source code and the compiled library. Finally, modifications should not break SQLite’s backwards compatibility with previous versions and cross-compatibility with different machine architectures&lt;/p&gt;
&lt;p&gt;Although SQLite’s performance is a key priority, it must be balanced with these (sometimes competing) goals. We considered several means of improving value extraction in SQLite, but no single solution satisfied all the constraints above. For example, changing the data format from row-oriented to column-oriented would streamline value extraction, but it would also likely increase overhead for OLTP workloads. Moreover, drastic changes to the data format are at odds with SQLite’s goal of stability for the database file format&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That section continues with this intriguing detail:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An alternative approach to improving SQLite’s OLAP performance is a separate, yet tightly connected query engine that evaluates analytical queries on its own copy of the data, while SQLite continues to serve transactional requests, ensuring that the analytical engine stays up to date with the freshest data. If the extra space overhead is acceptable, the specialized analytical engine can provide substantial OLAP performance gains.&lt;/p&gt;
&lt;p&gt;This design has been successfully implemented in SQLite3/HE [46], a query acceleration path for analytics in SQLite. SQLite3/HE achieves speedups of over 100X on SSB with no degradation in OLTP performance. However, the current implementation of SQLite3/HE does not persist columnar data to storage and is designed to be used in a single process. Future work may explore similar approaches without these limitations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the first I had heard of SQLite3/HE. It's described in this paper: &lt;a href="https://www.cidrdb.org/cidr2022/papers/p56-prammer.pdf"&gt;Introducing a Query Acceleration Path for Analytics in SQLite3&lt;/a&gt; - by Martin Prammer, Suryadev Sahadevan Rajesh, Junda Chen, Jignesh M. Patel from the University of Wisconsin-Madison. Martin and Jignesh are both credited as authors on the SQLite/DuckDB paper.&lt;/p&gt;

&lt;p&gt;It's also the subject of this &lt;a href="https://www.youtube.com/watch?v=c9bQyzm6JRU"&gt;12 minute video&lt;/a&gt; from the CIDR DB conference.&lt;/p&gt;

&lt;p&gt;It's not clear to me if the code for this has been made available yet. I'd be fascinated to learn more about this project.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/duckdb"&gt;duckdb&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/paper-review"&gt;paper-review&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="databases"/><category term="sqlite"/><category term="duckdb"/><category term="d-richard-hipp"/><category term="paper-review"/></entry><entry><title>The Untold Story of SQLite With Richard Hipp</title><link href="https://simonwillison.net/2021/Jul/16/the-untold-story-of-sqlite/#atom-tag" rel="alternate"/><published>2021-07-16T20:12:29+00:00</published><updated>2021-07-16T20:12:29+00:00</updated><id>https://simonwillison.net/2021/Jul/16/the-untold-story-of-sqlite/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://corecursive.com/066-sqlite-with-richard-hipp/"&gt;The Untold Story of SQLite With Richard Hipp&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
This is a really interesting interview with SQLite creator D. Richard Hipp—it covers all sorts of aspects of the SQLite story I hadn’t heard before, from its inspiration by a software challenge on a battleship to the first income from clients such as AOL and Symbian to the formation of the SQLite Consortium (based on advice from Mozilla’s Mitchell Baker) and more.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/podcasts"&gt;podcasts&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;



</summary><category term="podcasts"/><category term="sqlite"/><category term="d-richard-hipp"/></entry><entry><title>Datasette 0.58: The annotated release notes</title><link href="https://simonwillison.net/2021/Jul/16/datasette-058/#atom-tag" rel="alternate"/><published>2021-07-16T02:21:11+00:00</published><updated>2021-07-16T02:21:11+00:00</updated><id>https://simonwillison.net/2021/Jul/16/datasette-058/#atom-tag</id><summary type="html">
    &lt;p&gt;I released &lt;a href="https://docs.datasette.io/en/stable/changelog.html#v0-58"&gt;Datasette 0.58&lt;/a&gt; last night, with new plugin hooks, Unix domain socket support, a major faceting performance fix and a few other improvements. Here are the &lt;a href="https://simonwillison.net/series/datasette-release-notes/"&gt;annotated release notes&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Faceting performance improvement&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://docs.datasette.io/en/stable/facets.html"&gt;Facets&lt;/a&gt; remains my favourite feature in Datasette: it turns out a simple group by / count against a column is one of the most productive ways I know of to start understanding new data.&lt;/p&gt;
&lt;p&gt;Yesterday I stumbled across &lt;a href="https://github.com/simonw/datasette/commit/a6c8e7fa4cffdeff84e9e755dcff4788fd6154b8"&gt;a tiny tweak&lt;/a&gt; (details in &lt;a href="https://github.com/simonw/datasette/issues/1394"&gt;this issue&lt;/a&gt;) that gave me a 10x performance boost on facet queries! Short version: given the following example query:&lt;/p&gt;
&lt;div class="highlight highlight-source-sql"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;select&lt;/span&gt;
  country_long,
  &lt;span class="pl-c1"&gt;count&lt;/span&gt;(&lt;span class="pl-k"&gt;*&lt;/span&gt;)
&lt;span class="pl-k"&gt;from&lt;/span&gt; (
  &lt;span class="pl-k"&gt;select&lt;/span&gt; &lt;span class="pl-k"&gt;*&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; [global&lt;span class="pl-k"&gt;-&lt;/span&gt;power&lt;span class="pl-k"&gt;-&lt;/span&gt;plants]
  &lt;span class="pl-k"&gt;order by&lt;/span&gt; rowid
)
&lt;span class="pl-k"&gt;where&lt;/span&gt;
  country_long &lt;span class="pl-k"&gt;is not null&lt;/span&gt;
&lt;span class="pl-k"&gt;group by&lt;/span&gt;
  country_long
&lt;span class="pl-k"&gt;order by&lt;/span&gt;
  &lt;span class="pl-c1"&gt;count&lt;/span&gt;(&lt;span class="pl-k"&gt;*&lt;/span&gt;) &lt;span class="pl-k"&gt;desc&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Removing the unnecessary &lt;code&gt;order by rowid&lt;/code&gt; from that inner query knocked the time down from 53ms to 7.2ms (and makes even more of a difference on larger tables).&lt;/p&gt;
&lt;p&gt;I was surprised SQLite didn't perform that optimization automatically - so I &lt;a href="https://sqlite.org/forum/forumpost/2d76f2bcf65d256a"&gt;started a thread&lt;/a&gt; on the SQLite forum and SQLite author D. Richard Hipp &lt;a href="https://sqlite.org/src/timeline?r=omit-subquery-order-by"&gt;figured out a patch&lt;/a&gt;! It's not yet certain that it will land in a SQLite release but I'm excited to have found an issue interesting enough to be worth looking into. (UPDATE: it &lt;a href="https://sqlite.org/forum/forumpost/878ca7a9be0862af?t=h"&gt;landed on trunk&lt;/a&gt;).&lt;/p&gt;
&lt;h4&gt;The get_metadata() plugin hook&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;New plugin hook: &lt;a href="https://docs.datasette.io/en/stable/plugin_hooks.html#plugin-hook-get-metadata"&gt;get_metadata(datasette, key, database, table)&lt;/a&gt;, for returning custom metadata for an instance, database or table. Thanks, Brandon Roberts! (&lt;a href="https://github.com/simonw/datasette/issues/1384"&gt;#1384&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Brandon Roberts contributed this hook as part of work he's been doing with &lt;a href="https://next.newsday.com/"&gt;Newsday nextLI&lt;/a&gt; - always exciting to see Datasette used by another news organization. Brandon has &lt;a href="https://datasette-live.bxroberts.org/"&gt;a live demo&lt;/a&gt; of the plugins he has been building: &lt;a href="https://github.com/next-LI/datasette-live-config"&gt;datasette-live-config&lt;/a&gt;, &lt;a href="https://github.com/next-LI/datasette-live-permissions"&gt;datasette-live-permissions&lt;/a&gt;, &lt;a href="https://github.com/next-LI/datasette-csv-importer"&gt;datasette-csv-importer&lt;/a&gt; and &lt;a href="https://github.com/next-LI/datasette-surveys"&gt;datasette-surveys&lt;/a&gt;. He also has a &lt;a href="https://drive.google.com/file/d/1SShy_C6-CSUlSaqyQSIlUDIa4WA9YzTr/view"&gt;6 minute demo video&lt;/a&gt; explaining the project so far.&lt;/p&gt;
&lt;p&gt;The new hook allows plugins to customize the &lt;a href="https://docs.datasette.io/en/stable/metadata.html#metadata"&gt;metadata&lt;/a&gt; displayed for different databases and tables within the Datasette interface.&lt;/p&gt;
&lt;p&gt;There is one catch at the moment: the plugin doesn't yet allow for async calls (including &lt;code&gt;await db.execute(sql)&lt;/code&gt;) because Datasette's own internals currently treat access to metadata as a sync rather than async feature.&lt;/p&gt;
&lt;p&gt;There are workarounds for this. Brandon's &lt;code&gt;datasette-live-config&lt;/code&gt; plugin &lt;a href="https://github.com/next-LI/datasette-live-config/blob/d7e39db50f33b78ec0ef3f404ba421c4a47a5844/datasette_live_config/__init__.py"&gt;opens an additional, synchronous connection&lt;/a&gt; to the DB which is completely fine for fast queries. Another option would be to keep metadata in an in-memory Python dictionary which is updated by SQL queries that run in an async background task.&lt;/p&gt;
&lt;p&gt;In the longer run though I'd like to redesign Datasette's internals to support asynchronous metadata access - ideally before Datasette 1.0.&lt;/p&gt;
&lt;h4 id="skip-csrf-plugin-hook"&gt;The skip_csrf() plugin hook&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;New plugin hook: &lt;a href="https://docs.datasette.io/en/stable/plugin_hooks.html#plugin-hook-skip-csrf"&gt;skip_csrf(datasette, scope)&lt;/a&gt;, for opting out of CSRF protection based on the incoming request. (&lt;a href="https://github.com/simonw/datasette/issues/1377"&gt;#1377&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I wanted to write a plugin that supported an HTTP POST to a Datasette form that wasn't protected by Datasette's &lt;a href="https://docs.datasette.io/en/stable/internals.html?highlight=csrf#csrf-protection"&gt;CSRF protection&lt;/a&gt;. This proved surprisingly difficult! I ended up shipping &lt;a href="https://github.com/simonw/asgi-csrf/releases/tag/0.9"&gt;asgi-csrf 0.9&lt;/a&gt; with a new mechanism for custom opting-out of CSRF protection based on the ASGI scope, then exposing that mechanism in a new plugin hook in Datasette.&lt;/p&gt;
&lt;p&gt;CSRF is such a frustrating security issue to write code against, because in modern browsers the SameSite cookie attribute more-or-less solves the problem for you... but that attribute only has &lt;a href="https://caniuse.com/same-site-cookie-attribute"&gt;90% global usage according to caniuse.com&lt;/a&gt; - not quite enough for me to forget about it entirely.&lt;/p&gt;
&lt;p&gt;There also remains &lt;a href="https://twitter.com/simonw/status/1413484080226717708"&gt;one obscure edge-case&lt;/a&gt; in which SameSite won't help you: the definition of "same site" includes other subdomains of your domain (provided it's not on the &lt;a href="https://github.com/publicsuffix/list"&gt;Public Suffix List&lt;/a&gt;). This means that for SameSite CSRF protection to work you need to be confident that no subdomains of your domain will suffer an XSS - and in my experience its common for subdomains to be pointed at third-party applications that may not have the same stringent XSS protection as your main code.&lt;/p&gt;
&lt;p&gt;So I continue to care about CSRF protection in Datasette.&lt;/p&gt;
&lt;h4&gt;Unix domain socket support&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;New &lt;code&gt;datasette --uds /tmp/datasette.sock&lt;/code&gt; option for binding Datasette to a Unix domain socket, see &lt;a href="https://docs.datasette.io/en/stable/deploying.html#deploying-proxy"&gt;proxy documentation&lt;/a&gt;. (&lt;a href="https://github.com/simonw/datasette/issues/1388"&gt;#1388&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I wrote about this &lt;a href="https://simonwillison.net/2021/Jul/13/unix-domain-sockets/"&gt;in my weeknotes&lt;/a&gt; - this is a great way to run Datasette if you have it behind a proxy such as Apache or nginx and don't want to have the Datasette server listening on a high port.&lt;/p&gt;
&lt;h4&gt;"searchmode": "raw" in table metadata&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;"searchmode": "raw"&lt;/code&gt; table metadata option for defaulting a table to executing SQLite full-text search syntax without first escaping it, see &lt;a href="https://docs.datasette.io/en/stable/full_text_search.html#full-text-search-advanced-queries"&gt;Advanced SQLite search queries&lt;/a&gt;. (&lt;a href="https://github.com/simonw/datasette/issues/1389"&gt;#1389&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SQLite's built in full-text search feature includes support &lt;a href="https://www.sqlite.org/fts5.html#full_text_query_syntax"&gt;for advanced operators&lt;/a&gt;: you can use operators like AND, OR and NEAR and you can add column specifiers like &lt;code&gt;name:Simon&lt;/code&gt; to restrict searches to individual columns.&lt;/p&gt;
&lt;p&gt;This is something of a two-edged sword: I've found innocent looking queries that raise errors due to unexpected interactions with the query language.&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://github.com/simonw/datasette/issues/651"&gt;issue 651&lt;/a&gt; I switched to escaping all queries by default to prevent these errors from happening, with a &lt;code&gt;?_searchmode=raw&lt;/code&gt; query string option for opting back into the default functionality.&lt;/p&gt;
&lt;p&gt;I've since had a few requests for a mechanism to enable this by default - hence the new &lt;code&gt;"searchmode": "raw"&lt;/code&gt; option in table metadata.&lt;/p&gt;
&lt;h4&gt;Link plugin hooks now take a request&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;a href="https://docs.datasette.io/en/stable/plugin_hooks.html#plugin-hook-menu-links"&gt;menu_links()&lt;/a&gt;, &lt;a href="https://docs.datasette.io/en/stable/plugin_hooks.html#plugin-hook-table-actions"&gt;table_actions()&lt;/a&gt; and &lt;a href="https://docs.datasette.io/en/stable/plugin_hooks.html#plugin-hook-database-actions"&gt;database_actions()&lt;/a&gt; plugin hooks all gained a new optional &lt;code&gt;request&lt;/code&gt; argument providing access to the current request. (&lt;a href="https://github.com/simonw/datasette/issues/1371"&gt;#1371&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have a plugin which needs to add links to different places depending on the subdomain that the Datasette instance is running on. Adding &lt;code&gt;request&lt;/code&gt; to these plugin hooks proved to be the easiest way to achieve this.&lt;/p&gt;
&lt;p&gt;This is a really nice thing about how &lt;a href="https://pluggy.readthedocs.io/"&gt;Pluggy&lt;/a&gt; (the plugin library used by Datasette) works: adding new named parameters to hooks can be done without breaking backwards compatibility with existing plugins.&lt;/p&gt;
&lt;h4&gt;And the rest&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Improved documentation for &lt;a href="https://docs.datasette.io/en/stable/deploying.html#deploying-proxy"&gt;Running Datasette behind a proxy&lt;/a&gt; to recommend using &lt;code&gt;ProxyPreservehost On&lt;/code&gt; with Apache. (&lt;a href="https://github.com/simonw/datasette/issues/1387"&gt;#1387&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST&lt;/code&gt; requests to endpoints that do not support that HTTP verb now return a 405 error.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db.path&lt;/code&gt; can now be provided as a &lt;code&gt;pathlib.Path&lt;/code&gt; object, useful when writing unit tests for plugins. Thanks, Chris Amico. (&lt;a href="https://github.com/simonw/datasette/issues/1365"&gt;#1365&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/csrf"&gt;csrf&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/releasenotes"&gt;releasenotes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/annotated-release-notes"&gt;annotated-release-notes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/samesite"&gt;samesite&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="csrf"/><category term="releasenotes"/><category term="sqlite"/><category term="datasette"/><category term="annotated-release-notes"/><category term="d-richard-hipp"/><category term="samesite"/></entry><entry><title>Pikchr</title><link href="https://simonwillison.net/2020/Oct/21/pikchr/#atom-tag" rel="alternate"/><published>2020-10-21T16:02:48+00:00</published><updated>2020-10-21T16:02:48+00:00</updated><id>https://simonwillison.net/2020/Oct/21/pikchr/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://pikchr.org"&gt;Pikchr&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Interesting new project from SQLite creator D. Richard Hipp. Pikchr is a new mini language for describing visual diagrams, designed to be embedded in Markdown documentation. It’s already enabled for the SQLite forum. Implementation is a no-dependencies C library and output is SVG.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/svg"&gt;svg&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/markdown"&gt;markdown&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="sqlite"/><category term="svg"/><category term="markdown"/><category term="d-richard-hipp"/></entry><entry><title>Quoting D. Richard Hipp</title><link href="https://simonwillison.net/2018/May/10/d-richard-hipp/#atom-tag" rel="alternate"/><published>2018-05-10T05:15:49+00:00</published><updated>2018-05-10T05:15:49+00:00</updated><id>https://simonwillison.net/2018/May/10/d-richard-hipp/#atom-tag</id><summary type="html">
    &lt;blockquote cite="http://sqlite.1065341.n5.nabble.com/50-faster-than-3-7-17-td78082.html"&gt;&lt;p&gt;The latest SQLite 3.8.7 alpha version is 50% faster than the 3.7.17 release from 16 months ago.  That is to say, it does 50% more work using the same number of CPU cycles. [...] The 50% faster number above is not about better query plans.  This is 50% faster at the low-level grunt work of moving bits on and off disk and search b-trees.  We have achieved this by incorporating hundreds of micro-optimizations.  Each micro-optimization might improve the performance by as little as 0.05%.  If we get one that improves performance by 0.25%, that is considered a huge win.  Each of these optimizations is unmeasurable on a real-world system (we have to use cachegrind to get repeatable run-times) but if you do enough of them, they add up.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="http://sqlite.1065341.n5.nabble.com/50-faster-than-3-7-17-td78082.html"&gt;D. Richard Hipp&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;



</summary><category term="sqlite"/><category term="performance"/><category term="d-richard-hipp"/></entry><entry><title>SQLite Keynote</title><link href="https://simonwillison.net/2006/Oct/21/sqlite/#atom-tag" rel="alternate"/><published>2006-10-21T23:44:28+00:00</published><updated>2006-10-21T23:44:28+00:00</updated><id>https://simonwillison.net/2006/Oct/21/sqlite/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://blog.cleverly.com/permalinks/247.html"&gt;SQLite Keynote&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
SQLite 3.3.8 has full text indexing!


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/full-text-search"&gt;full-text-search&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;



</summary><category term="full-text-search"/><category term="sqlite"/><category term="d-richard-hipp"/></entry><entry><title>More lightweight software: SQLite</title><link href="https://simonwillison.net/2003/Mar/12/moreLightweightSoftware/#atom-tag" rel="alternate"/><published>2003-03-12T23:47:16+00:00</published><updated>2003-03-12T23:47:16+00:00</updated><id>https://simonwillison.net/2003/Mar/12/moreLightweightSoftware/#atom-tag</id><summary type="html">
    &lt;p&gt;The other toy I've been playing with recently is &lt;a href="http://www.sqlite.org/"&gt;SQLite&lt;/a&gt;. SQLite is an embeddable &lt;acronym title="Structured Query Language"&gt;SQL&lt;/acronym&gt; database engine written in just under 25,000 lines of (heavily commented) C. Don't let the size fool you - it's phenomenally powerful and is released under a no-holds-barred public domain license that practically begs you to include it in your applications, commercial or not.&lt;/p&gt;

&lt;p&gt;The feature list is pretty awesome - it's &lt;a href="http://www.sqlite.org/speed.html"&gt;two times faster&lt;/a&gt; than both mySQL and Postgres on simple operations, implements &lt;a href="http://www.sqlite.org/lang.html" title="SQL As Understood By SQLite"&gt;an impressive amount&lt;/a&gt; of the SQL92 standard (including transaction support) and has bindings for &lt;a href="http://www.sqlite.org/tclsqlite.html" title="The Tcl interface to the SQLite library"&gt;Tcl&lt;/a&gt;, &lt;a href="http://sourceforge.net/projects/sqlite-php/" title="SourceForge Project: SQLite-PHP"&gt;PHP&lt;/a&gt;, &lt;a href="http://search.cpan.org/author/MSERGEANT/DBD-SQLite-0.25/lib/DBD/SQLite.pm" title="DBD::SQLite"&gt;Perl&lt;/a&gt;, &lt;a href="http://pysqlite.sourceforge.net/" title="PySQLite"&gt;Python&lt;/a&gt; and &lt;a href="http://www.ch-werner.de/javasqlite/" title="SQLite Java Wrapper/JDBC Driver"&gt;Java&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That said, the lack of a security model (databases are stored in a single file with no user authentication / permissions system) and the fact that it's very much meant for embedding rather than featuring a client-server model mean it isn't really suitable for web applications. Where it would shine (and where the author D. Richard Hipp intended it to be used) is in applications that would benefit from an ultra fast relational database but don't need the overhead of embedding a large system such as mySQL. The no-strings license makes it a tempting prospect for that kind of work as well.&lt;/p&gt;

&lt;p&gt;Definitely one for the tool box.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/software"&gt;software&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/d-richard-hipp"&gt;d-richard-hipp&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="c"/><category term="software"/><category term="sqlite"/><category term="d-richard-hipp"/></entry></feed>