惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
云风的 BLOG
云风的 BLOG
aimingoo的专栏
aimingoo的专栏
Vercel News
Vercel News
T
The Blog of Author Tim Ferriss
F
Full Disclosure
A
About on SuperTechFans
C
Check Point Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
Know Your Adversary
Know Your Adversary
K
Kaspersky official blog
L
LINUX DO - 热门话题
Recorded Future
Recorded Future
C
Cisco Blogs
M
MIT News - Artificial intelligence
T
Tenable Blog
G
GRAHAM CLULEY
月光博客
月光博客
Recent Announcements
Recent Announcements
V
Visual Studio Blog
IT之家
IT之家
T
The Exploit Database - CXSecurity.com
The GitHub Blog
The GitHub Blog
T
Threat Research - Cisco Blogs
D
DataBreaches.Net
P
Privacy International News Feed
P
Proofpoint News Feed
I
Intezer
博客园 - 叶小钗
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Hacker News
The Hacker News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - Franky
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
P
Palo Alto Networks Blog
Last Week in AI
Last Week in AI
小众软件
小众软件
Hacker News - Newest:
Hacker News - Newest: "LLM"
O
OpenAI News
N
News and Events Feed by Topic
Microsoft Security Blog
Microsoft Security Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
N
News and Events Feed by Topic
The Cloudflare Blog
Spread Privacy
Spread Privacy
酷 壳 – CoolShell
酷 壳 – CoolShell
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
B
Blog RSS Feed

alexwlchan’s notes

A single command to test all my changed Go packages Disable the new message animations in WhatsApp Finding high-churn folders that bother Backblaze Always-on SSH agent forwarding with my Git pushes Managing the caption of a photo with AppleScript (but not PhotoKit) Goodhart’s and Campbell’s Law are different Notes from The Cornishman No. 176 (Spring 2026) Notes from The Cornishman No. 176 (Spring 2026) GitUp can’t diff text files larger than 8MB Home Testing the width of a page on a mobile device using Playwright Disable AirPods charging notifications Start a Caddy server in a subprocess during a Python session Filter a list of JSON object based on a list of tags HOME_GET_ME_HOME is a Citymapper Shortcuts action The FileExistsError exception exposes a filename attribute The red-lined bubble snail Why can’t Python connect to example.com? Useful type hints for Python How to truncate the middle of long command output AirPlay Receiver can interfere with Flask apps The file(1) command can read SQLite databases My randline project is tested by Crater Drawing an image with Liquid Glass using SwiftUI Previews Road signs in the Soviet union don’t have circular heads Setting up golink in my personal tailnet Create a file atomically in Go Get a map of IP addresses for devices in my tailnet The SQLite command line shell will count your unclosed parentheses Use SQL triggers to prevent overwriting a value Testing date formatting with date-fns-tz and different timezones The “strangler” pattern is named after a tree, not an act of violence Place with the same name, but different etymology
What’s the main prefix in SQLite queries?
2026-03-18 · via alexwlchan’s notes

SQLite uses schema prefixes like main and temp to disambiguate between attached databases and connection-specific temporary tables.

I was reading the SQLite database queries in the Tailscale source code today, and tables are referred to inconsistently: the schema creates tables like CREATE TABLE main.TKAChonk, but then queries may use TKAChonk or main.TKAChonk. What’s the difference?

I asked about it in Slack, and Michael and Brad explained what’s going on: it’s possible to attach multiple databases in SQLite, and the main prefix tells SQLite to look in the main database. We only attach one database so the two references are equivalent, but in the past there used to be separate databases and it was useful to disambiguate.

Here’s the relevant part of the SQLite docs:

In SQLite, a database object (a table, index, trigger or view) is identified by the name of the object and the name of the database that it resides in. […]

If no database is specified as part of the object reference, then SQLite searches the main, temp and all attached databases for an object with a matching name. The temp database is searched first, followed by the main database, followed by all attached databases in the order that they were attached. […]

If a schema name is specified as part of an object reference, it must be either “main”, or “temp” or the schema-name of an attached database.

The temp database referred to here is a set of tables created using CREATE TEMP TABLE which are only visible to the database connection that created them.

Example

  1. Create two databases which both have an IntID table, and store a different value in each:

    $ sqlite3 db1.sqlite 'CREATE TABLE IntID (id INTEGER);
                          INSERT INTO IntID (id) VALUES (100);'
    
    $ sqlite3 db2.sqlite 'CREATE TABLE IntID (id INTEGER);
                          INSERT INTO IntID (id) VALUES (200);'
  2. Open one of the databases, attach the other, and then look up the identically-named tables:

    sqlite> ATTACH DATABASE 'db2.sqlite' as db2;
    sqlite> SELECT id FROM IntID;
    100
    sqlite> SELECT id FROM main.IntID;
    100
    sqlite> SELECT id FROM db2.IntID;
    200

    Observe that when I query a bare IntID, SQLite chooses the table from the main database.

  3. Create a temporary table, insert a value, and query IntID again:

    sqlite> CREATE TEMP TABLE IntID (id INTEGER);
    sqlite> INSERT INTO temp.IntID VALUES (300);
    sqlite> SELECT id FROM IntID;
    300
    sqlite> SELECT id FROM main.IntID;
    100
    sqlite> SELECT id FROM temp.IntID;
    300
  4. Try to read the temporary table from a different database connection, and observe that it fails:

    $ sqlite3 db1.sqlite 'SELECT id FROM temp.IntID;'
    Error: in prepare, no such table: temp.IntID
  5. Create a table in the attached database, and observe it can be queried by the bare name, but doesn’t exist in the main database:

    sqlite> CREATE TABLE db2.NewID (id INTEGER);
    sqlite> INSERT INTO db2.NewID (id) VALUES (500);
    sqlite> SELECT id FROM NewID;
    500
    sqlite> SELECT id FROM main.NewID;
    Parse error: no such table: main.NewID
    sqlite> SELECT id FROM db2.NewID;
    500