blob: 27f5227b229f81862d771aa95c23c0f2db64a57d [file] [log] [blame] [view]
Victor Costan841e5b72021-04-20 06:14:321# SQLite abstraction layer
2
Victor Costanf265dd7f2021-05-26 17:47:483[TOC]
Victor Costan841e5b72021-04-20 06:14:324
5## SQLite for system designers
6
7[SQLite](https://www.sqlite.org/) is a
8[relational database management system (RDBMS)](https://en.wikipedia.org/wiki/Relational_database#RDBMS)
9that [supports most of SQL](https://www.sqlite.org/lang.html).
10
11SQLite is architected as a library that can be embedded in another application,
12such as Chrome. SQLite runs in the application's process, and shares its memory
13and other resources. This is similar to embedded databases like
14[LevelDB](https://github.com/google/leveldb) and
15[BerkeleyDB](https://en.wikipedia.org/wiki/Berkeley_DB). By contrast, most
16popular RDMBSes, like [PostgreSQL](https://www.postgresql.org/) and
17[MySQL](https://www.mysql.com/), are structured as standalone server processes
18that accept queries from client processes.
19
20TODO: Explain the process model and locking
21
22TODO: Explain Chrome decisions -- exclusive locking, full per-feature isolation
23(separate databases and page caches)
24
25
26## SQLite for database designers
27
28The section summarizes aspects of SQLite that are relevant to schema and
29query design, and may be surprising to readers with prior experience in other
30popular SQL database systems, such as
31[PostgreSQL](https://www.postgresql.org/) and [MySQL](https://www.mysql.com/).
32
33
Victor Costand9f80b52021-09-23 23:50:2334### Data storage model {#storage-model}
Victor Costan841e5b72021-04-20 06:14:3235
Victor Costand9f80b52021-09-23 23:50:2336The main bottleneck in SQLite database performance is usually disk I/O. So,
37designing schemas that perform well requires understanding how SQLite stores
38data on disk.
39
40At a very high level, a SQLite database is a forest of
41[B-trees](https://en.wikipedia.org/wiki/B-tree), some of which are
42[B+-trees](https://en.wikipedia.org/wiki/B%2B_tree). The database file is an
43array of fixed-size pages, where each page stores a B-tree node. The page size
44can only be set when a database file is created, and impacts both SQL statement
45execution speed, and memory consumption.
46
47The data in each table (usually called *rows*, *records*, or *tuples*) is stored
48in a separate B-tree. The data in each index (called *entries*, *records* or
49*tuples*) is also stored in a separate B-tree. So, each B-tree is associated
50with exactly one table. The [*Indexing* section](#indexing-model) goes into
51further details.
52
53Each B-tree node stores multiple tuples of values. The values and their
54encodings are described in the [*Value types* section](#data-types).
55
56Tying everything together: The performance of a SQL statement is roughly the
57number of database pages touched (read / written) by the statement. These pages
58are nodes belonging to the B-trees associated with the tables mentioned in the
59statement. The number of pages touched when accessing a B-tree depends on the
60B-tree's depth. Each B-tree's depth depends on its record count (number of
61records stored in it), and on its node width (how many records fit in a node).
62
63
64#### Value types {#data-types}
65
66SQLite stores values using
67[5 major types](https://www.sqlite.org/datatype3.html), which are summarized
68below.
Victor Costan841e5b72021-04-20 06:14:3269
701. NULL is a special type for the `NULL` value.
71
722. INTEGER represents big-endian twos-complement integers. Boolean values
73 (`TRUE` and `FALSE`) are represented as the integer values 1 and 0.
74
753. REAL represents IEEE 754-2008 64-bit floating point numbers.
76
774. TEXT represents strings (sequences of characters) encoded using a
78 [supported SQLite encoding](https://www.sqlite.org/c3ref/c_any.html). These
79 values are
80 [sorted](https://www.sqlite.org/datatype3.html#sort_order) according to
81 [a collating sequence](https://www.sqlite.org/datatype3.html#collation) or
82 [a collating function](https://www.sqlite.org/c3ref/create_collation.html).
83
845. BLOB represents sequences of bytes that are opaque to SQLite. These values are
85 sorted using the bitwise binary comparison offered by
86 [memcmp](https://en.cppreference.com/w/cpp/string/byte/memcmp).
87
88SQLite stores index keys and row values (records / tuples) using
89[a tightly packed format](https://sqlite.org/fileformat2.html#record_format)
90that makes heavy use of [varints](https://sqlite.org/fileformat2.html#varint)
91and variable-length fields. The column types have almost no influence on the
92encoding of values. This has the following consequences.
93
94* All SQL integer types, such as `TINYINT` and `BIGINT`, are treated as aliases
95 for `INTEGER`.
96* All SQL non-integer numeric types, such as `DECIMAL`, `FLOAT`, and
97 `DOUBLE PRECISION` are treated as aliases for `REAL`.
98* Numeric precision and scale specifiers, such as `DECIMAL(5,2)` are ignored.
99* All string types, such as `CHAR`, `CHARACTER VARYING`, `VARCHAR`, and `CLOB`,
100 are treated as aliases for `TEXT`.
101* Maximum string length specifiers, such as `CHAR(255)` are ignored.
102
103SQLite uses clever heuristics, called
104[type affinity](https://www.sqlite.org/datatype3.html#type_affinity),
105to map SQL column types such as `VARCHAR` to the major types above.
106
107Chrome database schemas should avoid type affinity, and should not include any
108information ignored by SQLite.
109
110
Victor Costand9f80b52021-09-23 23:50:23111#### Indexing {#indexing-model}
Victor Costan841e5b72021-04-20 06:14:32112
113SQLite [uses B-trees](https://www.sqlite.org/fileformat2.html#pages) to store
114both table and index data.
115
116The exclusive use of B-trees reduces the amount of schema design decisions.
117Notable examples:
118
119* There is no equivalent to
120 [PostgreSQL's index types](https://www.postgresql.org/docs/13/indexes-types.html).
121 In particular, since there are no hashed indexes, the design does not need to
122 consider whether the index only needs to support equality queries, as opposed
123 to greater/smaller than comparisons.
124
125* There is no equivalent to
126 [PostgreSQL's table access methods](https://www.postgresql.org/docs/13/tableam.html).
127 Each table is clustered by a primary key index, which is implicitly stored in
128 the table's B-tree.
129
130By default, table rows (records / tuples) are stored in a B-tree keyed by
131[rowid](https://sqlite.org/lang_createtable.html#rowid), an automatically
132assigned 64-bit integer key. Effectively, these tables are clustered by rowid,
133which acts as an implicit primary key. Opting out of this SQLite-specific
134default requires appending
135[`WITHOUT ROWID`](https://sqlite.org/withoutrowid.html) to the `CREATE TABLE`
136instruction.
137
138SQLite's [B-tree page format](https://sqlite.org/fileformat2.html#b_tree_pages)
139has optimized special cases for tables clustered by rowid. This makes rowid the
140most efficient [surrogate key](https://en.wikipedia.org/wiki/Surrogate_key)
141implementation in SQLite. To make this optimization easier to use, any column
142that is a primary key and has an `INTEGER` type is considered an alias for
143rowid.
144
Victor Costanc44ad3c2021-06-02 18:43:03145Each SQLite index
146[is stored in a B-tree](https://sqlite.org/fileformat2.html#representation_of_sql_indices).
147Each index entry is stored as a B-tree node whose key is made up of the record's
148index key column values, followed by the record's primary key column values.
149
150`WITHOUT ROWID` table indexes can include primary key columns without additional
151storage costs. This is because indexes for `WITHOUT ROWID` tables enjoy
152[a space optimization](https://sqlite.org/fileformat2.html#representation_of_sql_indices)
153where columns in both the primary key and the index key are not stored twice in
Andrew Paseltiner839fc232023-02-21 19:10:40154B-tree nodes. Note that data in such tables cannot be recovered by `sql::Recovery`.
Victor Costanc44ad3c2021-06-02 18:43:03155
Victor Costan841e5b72021-04-20 06:14:32156
Victor Costand9f80b52021-09-23 23:50:23157### Statement execution model {#query-model}
Victor Costan841e5b72021-04-20 06:14:32158
Victor Costand9f80b52021-09-23 23:50:23159At [a very high level](https://www.sqlite.org/arch.html), SQLite compiles SQL
160statements (often called *queries*) into bytecode executed by a virtual machine
161called the VDBE, or [the bytecode engine](https://www.sqlite.org/opcode.html).
162A compiled statement can be executed multiple times, amortizing the costs of
163query parsing and planning. Chrome's SQLite abstraction layer makes it easy to
164use compiled queries.
Victor Costan841e5b72021-04-20 06:14:32165
Victor Costand9f80b52021-09-23 23:50:23166Assuming effective use of cached statements, the performance of a SQL statement
167comes down to the *query plan* that SQLite generates for the statement. The
168query plan is the sequence of B-tree accesses used to execute the statement,
169which determines the number of B-tree pages touched.
170
171The rest of this section summarizes the following SQLite documentation pages.
Victor Costan841e5b72021-04-20 06:14:32172
1731. [query planner overview](https://www.sqlite.org/queryplanner.html)
1742. [query optimizer overview](https://www.sqlite.org/optoverview.html)
1753. [`EXPLAIN QUERY PLAN` output description](https://www.sqlite.org/eqp.html)
176
Victor Costand9f80b52021-09-23 23:50:23177At a high level, a SQLite query plan is a sequence of **nested** loops, where
178each loop iterates over the data in a B-tree. Each loop can use the current
179record of the outer loops.
180
181TODO: Complete this section. Cover joins, sorting, etc.
182
183#### Getting SQLite's query plans
184
185Ideally, the SQL schemas and statements used by Chrome features would be simple
186enough that the query plans would be obvious to the reader.
187
188When this isn't the case, the fastest way to get the query plan is to load the
189schema in [the SQLite shell](https://sqlite.org/cli.html), and use
190[`EXPLAIN QUERY PLAN`](https://www.sqlite.org/eqp.html).
191
192The following command builds a SQLite shell that uses Chrome's build of SQLite,
193and supports the `EXPLAIN QUERY PLAN` command.
194
195```sh
196autoninja -C out/Default sqlite_dev_shell
197```
198
199Inside the SQLite shell, the `.eqp on` directive automatically shows the results
200of `EXPLAIN QUERY PLAN` for every SQL statement executed in the shell.
201
202
203#### Query steps {#query-step-types}
204
205Query steps are the building blocks of SQLite query plans. Each query step is
206essentially a loop that iterates over the records in a B-tree. These loops
207differ in terms of how many B-tree pages they touch, and how many records they
208produce. This sub-section lists the types of steps implemented by SQLite.
209
210##### Scans
211
212Scans visit an entire (table or index) B-tree. For this reason, scans are almost
213never acceptable in Chrome. Most of our features don't have limits on the amount
214of stored data, so scans can result in an unbounded amount of I/O.
215
216A *table scan* visits the entire table's B-tree.
217
218A *covering index scan* visits an entire index B-tree, but doesn't access the
219associated table B-tree.
220
221SQLite doesn't have any special optimization for `COUNT(*)` queries. In other
222words, SQLite does not track subtree sizes in its B-tree nodes.
223
224Reviewers sometimes emphasize performance issues by calling the scans *full*
225table scans and *full* index scans, where "full" references the fact that the
226number of B-tree pages accessed is proportional to the entire data set stored on
227disk.
228
229TODO: Complete this section. Add examples in a way that doesn't make the section
230overly long.
231
232##### Searches
233
234Searches access a subset of a (table or index) B-tree nodes. Searches limit the
235amount of nodes they need to access based on query restrictions, such as terms
236in the `WHERE` clause. Seeing a `SEARCH` in a query plan is not a guarantee of
237performance. Searches can vary wildly in the amount of B-tree pages they need to
238access.
239
240One of the fastest possible searches is a *table search* that performs exactly
241one B-tree lookup, and produces at most one record.
242
243The other fastest possible search is a *covering index search* that also
244performs one lookup, and produces at most one record.
245
246TODO: Complete this section. Add examples in a way that doesn't make the section
247overly long.
Victor Costan841e5b72021-04-20 06:14:32248
249
250## General advice
251
252The following pieces of advice usually come up in code reviews.
253
Victor Costanf265dd7f2021-05-26 17:47:48254
255### Quickly iterating on SQL statements
256
257[The SQLite shell](https://sqlite.org/cli.html) offers quick feedback for
258converging on valid SQL statement syntax, and avoiding SQLite features that are
259disabled in Chrome. In addition, the
260[`EXPLAIN`](https://www.sqlite.org/lang_explain.html) and
261[`EXPLAIN QUERY PLAN`](https://www.sqlite.org/eqp.html) statements show the
262results of SQLite's query planner and optimizer, which are very helpful for
Victor Costan54f8955a2021-07-09 04:29:08263reasoning about the performance of complex queries. The SQLite shell directive
264`.eqp on` automatically issues `EXPLAIN QUERY PLAN` for all future commands.
265
Victor Costanf265dd7f2021-05-26 17:47:48266
267The following commands set up SQLite shells using Chrome's build of SQLite.
268
269```sh
270autoninja -C out/Default sqlite_shell sqlite_dev_shell
271```
272
273* `sqlite_shell` runs the SQLite build that we ship in Chrome. It offers the
274 ground truth on whether a SQL statement can be used in Chrome code or not.
275* `sqlite_dev_shell` enables the `EXPLAIN` and `EXPLAIN QUERY PLAN` statements,
276 as well as a few features used by [Perfetto](https://perfetto.dev/)'s analysis
277 tools.
278
279
Victor Costan841e5b72021-04-20 06:14:32280### SQL style
281
282SQLite queries are usually embedded as string literals in C++ code. The
283advice here has the following goals.
284
2851. Easy to read queries. The best defense against subtle bugs is making the
286 queries very easy to read, so that any bugs become obvious at code review
287 time. SQL string literals don't benefit from our code analysis
288 infrastructure, so the only lines of defense against bugs are testing and
289 code review.
290
2912. Simplify crash debugging. We will always have a low volume of non-actionable
292 crash reports, because Chrome runs on billions of devices, some of which have
293 faulty RAM or processors.
294
2953. No unnecessary performance overheads. The C++ optimizer doesn't understand
296 SQL query literals, so the queries end up as written in the Chrome binary.
297 Extra characters cost binary size, as well as CPU time (which turns into
298 battery usage) during query parsing.
299
3004. Match the embedding language (C++) style guide. This reduces the mental
301 context switch overhead for folks who write and/or review C++ code that
302 contains SQL.
303
304Format statements like so.
305
306```cc
307 static constexpr char kOriginInfoSql[] =
308 // clang-format off
309 "CREATE TABLE origin_infos("
Victor Costan768987502021-09-17 22:29:34310 "origin TEXT NOT NULL,"
311 "last_modified INTEGER NOT NULL,"
312 "secure INTEGER NOT NULL)";
313 // clang-format on
Victor Costan841e5b72021-04-20 06:14:32314
315 static constexpr char kInsertSql[] =
Victor Costan768987502021-09-17 22:29:34316 // clang-format off
317 "INSERT INTO infos(origin,last_modified,secure) "
318 "VALUES(?,?,?)";
319 // clang-format on
Victor Costanfd24d8a2021-04-23 20:23:21320
321 static constexpr char kSelectSql[] =
Victor Costan768987502021-09-17 22:29:34322 // clang-format off
323 "SELECT origin,last_modified,secure FROM origins "
324 "WHERE last_modified>? "
325 "ORDER BY last_modified";
326 // clang-format on
Victor Costan841e5b72021-04-20 06:14:32327```
328
Victor Costanc44ad3c2021-06-02 18:43:03329* [SQLite keywords](https://sqlite.org/lang_keywords.html) should use ALL CAPS.
330 This makes SQL query literals easier to distinguish and search for.
Victor Costan841e5b72021-04-20 06:14:32331
332* Identifiers, such as table and row names, should use snake_case.
333
334* Identifiers, keywords, and parameter placeholders (`?`) should be separated by
335 exactly one character. Separators may be spaces (` `), commas (`,`), or
336 parentheses (`(`, `)`).
337
338* Statement-ending semicolons (`;`) are omitted.
339
340* SQL statements are stored in variables typed `static constexpr char[]`, or in
341 string literals passed directly to methods.
342
343* [`INSERT` statements](https://sqlite.org/lang_insert.html) should list all the
344 table columns by name, in the same order as the corresponding `CREATE TABLE`
345 statements.
346
Victor Costanfd24d8a2021-04-23 20:23:21347* [`SELECT` statements](https://sqlite.org/lang_select.html) should list the
348 desired table columns by name, in the same order as the corresponding
349 `CREATE TABLE` statements. `SELECT *` is strongly discouraged, at least until
350 we have schema checks on database opens.
351
352* [`SELECT` statements](https://sqlite.org/lang_select.html) that retrieve more
353 than one row should include an
354 [`ORDER BY` clause](https://sqlite.org/lang_select.html#the_order_by_clause)
355 to clarify the implicit ordering.
356 * SELECTs whose outer loop is a table search or table scan implicitly order
357 results by [rowid](https://sqlite.org/lang_createtable.html#rowid) or, in
358 the case of [`WITHOUT ROWID`](https://sqlite.org/withoutrowid.html) tables,
359 by the table's primary key.
360 * SELECTs whose outer loop is an index scan or index search order results
361 according to that index.
362
363* [`CREATE INDEX` statements](https://sqlite.org/lang_createindex.html) should
364 immediately follow the
365 [`CREATE TABLE` statement](https://sqlite.org/lang_createtable.html) for the
366 indexed table.
367
368* Explicit `CREATE UNIQUE INDEX` statements should be preferred to
369 [`UNIQUE` constraints on `CREATE TABLE`](https://sqlite.org/lang_createtable.html#unique_constraints).
370
Victor Costan841e5b72021-04-20 06:14:32371* Values must either be embedded in the SQL statement string literal, or bound
372 using [parameters](https://www.sqlite.org/lang_expr.html#varparam).
373
374* Parameter placeholders should always use the `?` syntax. Alternative syntaxes,
375 such as `?NNN` or `:AAAA`, have few benefits in a codebase where the `Bind`
376 statements are right next to the queries, and are less known to readers.
377
Victor Costan6c962e52022-02-14 19:10:49378* SQL statements should be embedded in C++ as string literals. The `char[]` type
379 makes it possible for us to compute query length at compile time in the
380 future. The `static` and `constexpr` qualifiers both ensure optimal code
381 generation.
382
Victor Costan841e5b72021-04-20 06:14:32383* Do not execute multiple SQL statements (e.g., by calling `Step()` or `Run()`
384 on `sql::Statement`) on the same C++ line. It's difficult to get more than
385 line numbers from crash reports' stack traces.
386
387
388### Schema style
389
Victor Costanc44ad3c2021-06-02 18:43:03390Identifiers (table / index / column names and aliases) must not be
391[current SQLite keywords](https://sqlite.org/lang_keywords.html). Identifiers
392may not start with the `sqlite_` prefix, to avoid conflicting with the name of a
393[SQLite internal schema object](https://www.sqlite.org/fileformat2.html#storage_of_the_sql_database_schema).
394
Victor Costan841e5b72021-04-20 06:14:32395Column types should only be one of the the SQLite storage types (`INTEGER`,
396`REAL`, `TEXT`, `BLOB`), so readers can avoid reasoning about SQLite's type
397affinity.
398
399Columns that will store boolean values should have the `INTEGER` type.
400
401Columns that will store `base::Time` values should have the `INTEGER` type.
402Values should be serialized using `sql::Statement::BindTime()` and deserialized
403using `sql::Statement::ColumnTime()`.
404
405Column types should not include information ignored by SQLite, such as numeric
406precision or scale specifiers, or string length specifiers.
407
Victor Costan01664122021-05-26 19:11:38408Columns should have
409[`NOT NULL` constraints](https://sqlite.org/lang_createtable.html#not_null_constraints)
410whenever possible. This saves maintainers from having to reason about the less
411intuitive cases of [`NULL` handling](https://sqlite.org/nulls.html).
Victor Costan841e5b72021-04-20 06:14:32412
Victor Costan01664122021-05-26 19:11:38413`NOT NULL` constraints must be explicitly stated in column definitions that
414include `PRIMARY KEY` specifiers. For historical reasons, SQLite
415[allows NULL primary keys](https://sqlite.org/lang_createtable.html#the_primary_key)
416in most cases. When a table's primary key is composed of multiple columns,
417each column's definition should have a `NOT NULL` constraint.
418
419Columns should avoid `DEFAULT` values. Columns that have `NOT NULL` constraints
420and lack a `DEFAULT` value are easier to review and maintain, as SQLite takes
421over the burden of checking that `INSERT` statements aren't missing these
422columns.
Victor Costan841e5b72021-04-20 06:14:32423
424Surrogate primary keys should use the column type `INTEGER PRIMARY KEY`, to take
425advantage of SQLite's rowid optimizations.
426[`AUTOINCREMENT`](https://www.sqlite.org/autoinc.html) should only be used where
427primary key reuse would be unacceptable.
428
429
Evan Stadeff25d2d2025-06-24 19:03:44430### Sophisticated features
Victor Costan841e5b72021-04-20 06:14:32431
Evan Stadeff25d2d2025-06-24 19:03:44432SQLite exposes a vast array of functionality via SQL statements, many of which
433are not a good match for average Chrome feature code. Use them with care and if
434you know what you're doing.
Victor Costan9e480bc12021-05-21 17:50:46435
Victor Costanbad4d6e22021-07-13 01:09:45436#### PRAGMA statements {#no-pragmas}
Victor Costanfd24d8a2021-04-23 20:23:21437
Victor Costan841e5b72021-04-20 06:14:32438[`PRAGMA` statements](https://www.sqlite.org/pragma.html) should never be used
439directly. Chrome's SQLite abstraction layer should be modified to support the
440desired effects instead.
441
442Direct `PRAGMA` use limits our ability to customize and secure our SQLite build.
443`PRAGMA` statements may turn on code paths with less testing / fuzzing coverage.
444Furthermore, some `PRAGMA` statements invalidate previously compiled queries,
445reducing the efficiency of Chrome's compiled query cache.
446
Victor Costanbad4d6e22021-07-13 01:09:45447#### Foreign key constraints {#no-foreign-keys}
Victor Costanfd24d8a2021-04-23 20:23:21448
Victor Costan841e5b72021-04-20 06:14:32449[SQL foreign key constraints](https://sqlite.org/foreignkeys.html) should not be
450used. All data validation should be performed using explicit `SELECT` statements
451(generally wrapped as helper methods) inside transactions. Cascading deletions
452should be performed using explicit `DELETE` statements inside transactions.
453
454Chrome features cannot rely on foreign key enforcement, due to the
455possibility of data corruption. Furthermore, foreign key constraints make it
456more difficult to reason about system behavior (Chrome feature code + SQLite)
457when the database gets corrupted. Foreign key constraints also make it more
458difficult to reason about query performance.
459
Will Harris563a50c42023-03-29 21:40:35460As a result, foreign key constraints are not enforced on SQLite databases
461opened with Chrome's `sql::Database` infrastructure.
Victor Costan54d71382022-03-21 21:47:18462
Victor Costan841e5b72021-04-20 06:14:32463After
464[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan
465to disable SQLite's foreign key support using
466[SQLITE_OMIT_FOREIGN_KEY](https://sqlite.org/compile.html#omit_foreign_key).
467
Victor Costanbad4d6e22021-07-13 01:09:45468#### CHECK constraints {#no-checks}
Victor Costanfd24d8a2021-04-23 20:23:21469
470[SQL CHECK constraints](https://sqlite.org/lang_createtable.html#check_constraints)
471should not be used, for the same reasons as foreign key constraints. The
472equivalent checks should be performed in C++, typically using `DCHECK`.
473
Andrew Paseltinerb181d0d2025-04-04 14:22:58474After
475[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan
476to disable SQLite's CHECK constraint support using
Victor Costanfd24d8a2021-04-23 20:23:21477[SQLITE_OMIT_CHECK](https://sqlite.org/compile.html#omit_check).
478
Evan Stadeff25d2d2025-06-24 19:03:44479#### Triggers {#triggers}
Victor Costanfd24d8a2021-04-23 20:23:21480
Evan Stadeff25d2d2025-06-24 19:03:44481[SQL triggers](https://sqlite.org/lang_createtrigger.html) should be used
482thoughtfully.
Victor Costan841e5b72021-04-20 06:14:32483
Evan Stadeff25d2d2025-06-24 19:03:44484Use triggers only if they *increase* legibility and *reduce* query complexity.
485The vast majority of Chrome features should not need triggers as their SQL
486queries are typically very simple, and triggers can obfuscate behavior by
487introducing an easy-to-miss side effect to certain queries. It's generally
488preferred to "manually" execute a second query with the desired effect.
Victor Costan841e5b72021-04-20 06:14:32489
Evan Stadeff25d2d2025-06-24 19:03:44490There are exceptions to this rule, such as when the follow-up query would itself
491be much more complex than the trigger, and/or a single trigger can take the
492place of multiple queries.
Victor Costan7c234822021-07-13 03:03:02493
Evan Stadeff25d2d2025-06-24 19:03:44494Triggers are disabled by default, with hopes that this will encourage feature
495authors to carefully weigh their use against the alternatives, but can be
496enabled via `DatabaseOptions::set_triggers_enabled()`.
Victor Costan841e5b72021-04-20 06:14:32497
Victor Costanbad4d6e22021-07-13 01:09:45498#### Common Table Expressions {#no-ctes}
Victor Costanfd24d8a2021-04-23 20:23:21499
500[SQL Common Table Expressions (CTEs)](https://sqlite.org/lang_with.html) should
501not be used. Chrome's SQL schemas and queries should be simple enough that
502the factoring afforded by
503[ordinary CTEs](https://sqlite.org/lang_with.html#ordinary_common_table_expressions)
504is not necessary.
505[Recursive CTEs](https://sqlite.org/lang_with.html#recursive_common_table_expressions)
506should be implemented in C++.
507
508Common Table Expressions do not open up any query optimizations that would not
509be available otherwise, and make it more difficult to review / analyze queries.
510
Victor Costanbad4d6e22021-07-13 01:09:45511#### Views {#no-views}
Victor Costanfd24d8a2021-04-23 20:23:21512
513SQL views, managed by the
514[`CREATE VIEW` statement](https://www.sqlite.org/lang_createview.html) and the
515[`DROP VIEW` statement](https://www.sqlite.org/lang_dropview.html), should not
516be used. Chrome's SQL schemas and queries should be simple enough that the
517factoring afforded by views is not necessary.
518
519Views are syntactic sugar, and do not open up any new SQL capabilities. SQL
520statements on views are more difficult to understand and maintain, because of
521the extra layer of indirection.
522
Victor Costanfe078f92021-07-19 20:02:59523Access to views is disabled by default for SQLite databases opened with Chrome's
524`sql::Database` infrastructure. This is intended to steer feature developers
525away from the discouraged feature.
526
Victor Costanfd24d8a2021-04-23 20:23:21527After
528[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan
529to disable SQLite's VIEW support using
530[SQLITE_OMIT_VIEW](https://www.sqlite.org/compile.html#omit_view).
531
Victor Costan5c2e85512021-07-17 00:11:53532#### Double-quoted string literals {#no-double-quoted-strings}
533
534String literals should always be single-quoted. That being said, string literals
535should be rare in Chrome code, because any user input must be injected using
536statement parameters and the `Statement::Bind*()` methods.
537
538Double-quoted string literals are non-standard SQL syntax. The SQLite authors
539[currently consider this be a misfeature](https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted).
540
Victor Costan4e442d02021-07-20 17:43:13541SQLite support for double-quoted string literals is disabled for databases
Andrew Paseltiner986a13ba2025-04-02 18:46:29542opened with Chrome's `sql::Database` infrastructure.
Victor Costan5c2e85512021-07-17 00:11:53543
Victor Costanbad4d6e22021-07-13 01:09:45544#### Compound SELECT statements {#no-compound-queries}
Victor Costanfd24d8a2021-04-23 20:23:21545
546[Compound SELECT statements](https://www.sqlite.org/lang_select.html#compound_select_statements)
547should not be used. Such statements should be broken down into
548[simple SELECT statements](https://www.sqlite.org/lang_select.html#simple_select_processing),
549and the operators `UNION`, `UNION ALL`, `INTERSECT` and `EXCEPT` should be
550implemented in C++.
551
552A single compound SELECT statement is more difficult to review and properly
553unit-test than the equivalent collection of simple SELECT statements.
Victor Costan9e480bc12021-05-21 17:50:46554Furthermore, the compound SELECT statement operators can be implemented more
555efficiently in C++ than in SQLite's bytecode interpreter (VDBE).
Victor Costanfd24d8a2021-04-23 20:23:21556
557After
558[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan
559to disable SQLite's compound SELECT support using
560[SQLITE_OMIT_COMPOUND_SELECT](https://www.sqlite.org/compile.html#omit_compound_select).
561
Victor Costanbad4d6e22021-07-13 01:09:45562#### Built-in functions {#no-builtin-functions}
Victor Costan9e480bc12021-05-21 17:50:46563
564SQLite's [built-in functions](https://sqlite.org/lang_corefunc.html) should be
565only be used in SQL statements where they unlock significant performance
566improvements. Chrome features should store data in a format that leaves the most
567room for query optimizations, and perform any necessary transformations after
568reading / before writing the data.
569
570* [Aggregation functions](https://sqlite.org/lang_aggfunc.html) are best
571 replaced with C++ code that iterates over rows and computes the desired
572 results.
573* [Date and time functions](https://sqlite.org/lang_datefunc.html) are best
574 replaced by `base::Time` functionality.
575* String-processing functions, such as
576 [`printf()`](https://sqlite.org/printf.html) and `trim()` are best replaced
577 by C++ code that uses the helpers in `//base/strings/`.
578* Wrappers for [SQLite's C API](https://sqlite.org/c3ref/funclist.html), such as
579 `changes()`, `last_insert_rowid()`, and `total_changes()`, are best replaced
580 by functionality in `sql::Database` and `sql::Statement`.
581* SQLite-specific functions, such as `sqlite_source_id()` and
582 `sqlite_version()` should not be necessary in Chrome code, and may suggest a
583 problem in the feature's design.
584
585[Math functions](https://sqlite.org/lang_mathfunc.html) and
586[Window functions](https://sqlite.org/windowfunctions.html#biwinfunc) are
587disabled in Chrome's SQLite build.
588
Evan Stade1d80896e2024-02-28 18:40:26589#### ATTACH DATABASE statements
Victor Costanfd24d8a2021-04-23 20:23:21590
Victor Costan841e5b72021-04-20 06:14:32591[`ATTACH DATABASE` statements](https://www.sqlite.org/lang_attach.html) should
Evan Stade1d80896e2024-02-28 18:40:26592be used thoughtfully. Each Chrome feature should store its data in a single database.
Victor Costan841e5b72021-04-20 06:14:32593Chrome code should not assume that transactions across multiple databases are
594atomic.
595
Victor Costan31dfb7e72022-02-28 21:14:24596### Disabled features
597
598We aim to disable SQLite features that should not be used in Chrome, subject to
599the constraint of keeping WebSQL's feature set stable. We currently disable all
600new SQLite features, to avoid expanding the attack surface exposed to WebSQL.
601This stance may change once WebSQL is removed from Chrome.
602
603The following SQLite features have been disabled in Chrome.
604
605#### JSON
606
607Chrome features should prefer
608[procotol buffers](https://developers.google.com/protocol-buffers) to JSON for
609on-disk (persistent) serialization of extensible structured data.
610
611Chrome features should store the values used by indexes directly in their own
612columns, instead of relying on
613[SQLite's JSON support](https://www.sqlite.org/json1.html).
614
615#### UPSERT
616
617[SQLite's UPSERT implementation](https://www.sqlite.org/lang_UPSERT.html) has
618been disabled in order to avoid increasing WebSQL's attack surface. UPSERT is
619disabled using the `SQLITE_OMIT_UPSERT` macro, which is not currently included
620in [the SQLite compile-time option list](https://www.sqlite.org/compile.html),
621but exists in the source code.
622
623We currently think that the new UPSERT functionality is not essential to
624implementing Chrome features efficiently. An example where UPSERT is necessary
625for the success of a Chrome feature would likely get UPSERT enabled.
626
627#### Window functions
628
629[Window functions](https://sqlite.org/windowfunctions.html#biwinfunc) have been
630disabled primarily because they cause a significant binary size increase, which
631leads to a corresponding large increase in the attack surface exposed to WebSQL.
632
633Window functions increase the difficulty of reviewing and maintaining the Chrome
634features that use them, because window functions add complexity to the mental
635model of query performance.
636
637We currently think that this maintenance overhead of window functions exceeds
638any convenience and performance benefits (compared to simpler queries
639coordinated in C++).
Andrew Paseltinerab20e8b92024-05-15 19:29:45640
641#### Virtual tables {#no-virtual-tables}
642
643[`CREATE VIRTUAL TABLE` statements](https://www.sqlite.org/vtab.html) are
644disabled. The desired functionality should be implemented in C++, and access
645storage using standard SQL statements.
646
647Virtual tables are [SQLite's module system](https://www.sqlite.org/vtab.html).
648SQL statements on virtual tables are essentially running arbitrary code, which
649makes them very difficult to reason about and maintain. Furthermore, the virtual
650table implementations don't receive the same level of fuzzing coverage as the
651SQLite core.
652
653Chrome's SQLite build has virtual table functionality reduced to the minimum
654needed to support an internal feature.
655[SQLite's run-time loading mechanism](https://www.sqlite.org/loadext.html) is
656disabled, and most
657[built-in virtual tables](https://www.sqlite.org/vtablist.html) are disabled as
658well.
659
660Ideally we would disable SQLite's virtual table support using
661[SQLITE_OMIT_VIRTUALTABLE](https://sqlite.org/compile.html#omit_virtualtable)
662now that [WebSQL](https://www.w3.org/TR/webdatabase/) has been removed from
663Chrome, but virtual table support is required to use SQLite's
664[built-in corruption recovery module](https://www.sqlite.org/recovery.html). The
665[SQLITE_DBPAGE virtual table](https://www.sqlite.org/dbpage.html) is also
666enabled only for corruption recovery and should not be used in Chrome.