Avi Drissman | 69b874f | 2022-09-15 19:11:14 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 5 | #ifndef SQL_DATABASE_H_ |
| 6 | #define SQL_DATABASE_H_ |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 7 | |
avi | 0b51920 | 2015-12-21 07:25:19 | [diff] [blame] | 8 | #include<stddef.h> |
tfarina | 720d4f3 | 2015-05-11 22:31:26 | [diff] [blame] | 9 | #include<stdint.h> |
Victor Costan | ab7a245 | 2022-03-21 23:06:08 | [diff] [blame] | 10 | |
mostynb | d82cd995 | 2016-04-11 20:05:34 | [diff] [blame] | 11 | #include<memory> |
Arthur Sonzogni | 5bc3326c | 2024-02-29 19:39:05 | [diff] [blame] | 12 | #include<optional> |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 13 | #include<set> |
mark@chromium.org | 7d6aee4e | 2009-09-12 01:12:33 | [diff] [blame] | 14 | #include<string> |
Md Hasibul Hasan | 52ffeca6 | 2024-03-26 18:23:18 | [diff] [blame] | 15 | #include<string_view> |
Victor Costan | 87cf8c7 | 2018-07-19 19:36:04 | [diff] [blame] | 16 | #include<utility> |
shess@chromium.org | 80abf15 | 2013-05-22 12:42:42 | [diff] [blame] | 17 | #include<vector> |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 18 | |
Dan McArdle | b52665c | 2024-05-23 20:24:31 | [diff] [blame] | 19 | #include"base/check.h" |
| 20 | #include"base/check_op.h" |
Victor Costan | e56cc68 | 2018-12-27 01:53:46 | [diff] [blame] | 21 | #include"base/component_export.h" |
Dmitry Skiba | a9ad8fe4 | 2017-08-16 21:02:48 | [diff] [blame] | 22 | #include"base/containers/flat_map.h" |
Austin Sullivan | 0593ef9 | 2023-05-17 20:46:30 | [diff] [blame] | 23 | #include"base/files/file_path.h" |
Avi Drissman | 2e85357a | 2023-01-12 21:57:32 | [diff] [blame] | 24 | #include"base/functional/callback.h" |
shess | c8cd2a16 | 2015-10-22 20:30:46 | [diff] [blame] | 25 | #include"base/gtest_prod_util.h" |
Dan McArdle | b52665c | 2024-05-23 20:24:31 | [diff] [blame] | 26 | #include"base/location.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 27 | #include"base/memory/raw_ptr.h" |
levin@chromium.org | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame] | 28 | #include"base/memory/ref_counted.h" |
Evan Stade | 9728e5a | 2025-06-05 18:51:27 | [diff] [blame] | 29 | #include"base/memory/ref_counted_memory.h" |
Dan McArdle | b52665c | 2024-05-23 20:24:31 | [diff] [blame] | 30 | #include"base/memory/scoped_refptr.h" |
Dan McArdle | 49be9b0 | 2024-02-06 23:15:33 | [diff] [blame] | 31 | #include"base/memory/weak_ptr.h" |
Anthony Vallée-Dubois | dd2d901 | 2024-12-18 23:25:28 | [diff] [blame] | 32 | #include"base/notreached.h" |
Victor Costan | 12daa3ac9 | 2018-07-19 01:05:58 | [diff] [blame] | 33 | #include"base/sequence_checker.h" |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 34 | #include"base/strings/cstring_view.h" |
Etienne Pierre-Doray | 0400dfb6 | 2018-12-03 19:12:25 | [diff] [blame] | 35 | #include"base/threading/scoped_blocking_call.h" |
Dan McArdle | b52665c | 2024-05-23 20:24:31 | [diff] [blame] | 36 | #include"base/time/time.h" |
Victor Costan | bc4285f | 2021-09-20 21:29:28 | [diff] [blame] | 37 | #include"base/types/pass_key.h" |
Victor Costan | 7f6abbbe | 2018-07-29 02:57:27 | [diff] [blame] | 38 | #include"sql/internal_api_token.h" |
Anthony Vallée-Dubois | dd2d901 | 2024-12-18 23:25:28 | [diff] [blame] | 39 | #include"sql/sql_name_variants.h" |
Victor Costan | ab7a245 | 2022-03-21 23:06:08 | [diff] [blame] | 40 | #include"sql/sqlite_result_code.h" |
| 41 | #include"sql/sqlite_result_code_values.h" |
Victor Costan | 12daa3ac9 | 2018-07-19 01:05:58 | [diff] [blame] | 42 | #include"sql/statement_id.h" |
Evan Stade | 416f46f1 | 2025-06-18 15:42:39 | [diff] [blame] | 43 | #include"sql/streaming_blob_handle.h" |
Dan McArdle | b52665c | 2024-05-23 20:24:31 | [diff] [blame] | 44 | #include"third_party/perfetto/include/perfetto/tracing/traced_proto.h" |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 45 | |
Victor Costan | ab7a245 | 2022-03-21 23:06:08 | [diff] [blame] | 46 | // Forward declaration for SQLite structures. Headers in the public sql:: API |
| 47 | // must NOT include sqlite3.h. |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 48 | struct sqlite3; |
Victor Costan | dc72e8d | 2022-03-14 18:14:51 | [diff] [blame] | 49 | struct sqlite3_file; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 50 | struct sqlite3_stmt; |
| 51 | |
Austin Sullivan | 0593ef9 | 2023-05-17 20:46:30 | [diff] [blame] | 52 | namespacebase::trace_event{ |
ssid | 1f4e536 | 2016-12-08 20:41:38 | [diff] [blame] | 53 | classProcessMemoryDump; |
Austin Sullivan | 0593ef9 | 2023-05-17 20:46:30 | [diff] [blame] | 54 | }// namespace base::trace_event |
brettw@chromium.org | a3ef483 | 2013-02-02 05:12:33 | [diff] [blame] | 55 | |
Hans Wennborg | 5fcd6b87 | 2025-04-14 21:53:01 | [diff] [blame] | 56 | namespace perfetto{ |
| 57 | classNamedTrack; |
| 58 | } |
| 59 | |
Tommy C. Li | 7803636c | 2022-07-27 21:47:22 | [diff] [blame] | 60 | namespace perfetto::protos::pbzero{ |
| 61 | classChromeSqlDiagnostics; |
| 62 | } |
| 63 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 64 | namespace sql{ |
| 65 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 66 | classDatabaseMemoryDumpProvider; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 67 | classStatement; |
| 68 | |
shess | 58b8df8 | 2015-06-03 00:19:32 | [diff] [blame] | 69 | namespace test{ |
shess | 97681440 | 2016-06-21 06:56:25 | [diff] [blame] | 70 | classScopedErrorExpecter; |
Victor Costan | 87cf8c7 | 2018-07-19 19:36:04 | [diff] [blame] | 71 | }// namespace test |
shess | 58b8df8 | 2015-06-03 00:19:32 | [diff] [blame] | 72 | |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 73 | struct COMPONENT_EXPORT(SQL)DatabaseOptions{ |
| 74 | // Default page size for newly created databases. |
| 75 | // |
| 76 | // Guaranteed to match SQLITE_DEFAULT_PAGE_SIZE. |
| 77 | staticconstexprint kDefaultPageSize=4096; |
| 78 | |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 79 | DatabaseOptions(); |
Etienne Bergeron | 9635e20f | 2025-02-11 17:52:38 | [diff] [blame] | 80 | DatabaseOptions(constDatabaseOptions&); |
| 81 | DatabaseOptions(DatabaseOptions&&); |
| 82 | DatabaseOptions&operator=(constDatabaseOptions&); |
| 83 | DatabaseOptions&operator=(DatabaseOptions&&); |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 84 | ~DatabaseOptions(); |
| 85 | |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 86 | // If true, the database can only be opened by one process at a time. |
| 87 | // |
Shubham Aggarwal | b30a0cee | 2021-01-28 15:11:23 | [diff] [blame] | 88 | // SQLite supports a locking protocol that allows multiple processes to safely |
| 89 | // operate on the same database at the same time. The locking protocol is used |
| 90 | // on every transaction, and comes with a small performance penalty. |
| 91 | // |
| 92 | // Setting this to true causes the locking protocol to be used once, when the |
Will Harris | 711a5ec | 2023-04-04 21:43:37 | [diff] [blame] | 93 | // database is opened. No other SQLite process will be able to access the |
| 94 | // database at the same time. Note that this uses OS-level |
| 95 | // advisory/cooperative locking, so this does not protect the database file |
| 96 | // from uncooperative processes. |
Shubham Aggarwal | b30a0cee | 2021-01-28 15:11:23 | [diff] [blame] | 97 | // |
| 98 | // More details at https://www.sqlite.org/pragma.html#pragma_locking_mode |
| 99 | // |
| 100 | // SQLite's locking protocol is summarized at |
| 101 | // https://www.sqlite.org/c3ref/io_methods.html |
| 102 | // |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 103 | // Exclusive mode is strongly recommended. It reduces the I/O cost of setting |
| 104 | // up a transaction. It also removes the need of handling transaction failures |
| 105 | // due to lock contention. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 106 | DatabaseOptions& set_exclusive_locking(bool exclusive_locking){ |
| 107 | exclusive_locking_= exclusive_locking; |
| 108 | return*this; |
| 109 | } |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 110 | |
Will Harris | 711a5ec | 2023-04-04 21:43:37 | [diff] [blame] | 111 | // If true, enables exclusive=true vfs URI parameter on the database file. |
| 112 | // This is only supported on Windows. |
| 113 | // |
| 114 | // If this option is true then the database file cannot be opened by any |
| 115 | // processes on the system until the database has been closed. Note, this is |
| 116 | // not the same as `exclusive_locking` above, which refers to |
| 117 | // advisory/cooperative locks. This option sets file handle sharing attributes |
| 118 | // to prevent the database files from being opened from any process including |
| 119 | // being opened a second time by the hosting process. |
| 120 | // |
Will Harris | 711a5ec | 2023-04-04 21:43:37 | [diff] [blame] | 121 | // This option is experimental and will be merged into the `exclusive_locking` |
| 122 | // option above if proven to cause no OS compatibility issues. |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 123 | // TODO(crbug.com/40262539): Merge into above option, if possible. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 124 | DatabaseOptions& set_exclusive_database_file_lock( |
| 125 | bool exclusive_database_file_lock){ |
| 126 | exclusive_database_file_lock_= exclusive_database_file_lock; |
| 127 | return*this; |
| 128 | } |
Will Harris | 711a5ec | 2023-04-04 21:43:37 | [diff] [blame] | 129 | |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 130 | // If true, enables SQLite's Write-Ahead Logging (WAL). |
| 131 | // |
| 132 | // WAL integration is under development, and should not be used in shipping |
Evan Stade | 4c7d6b3 | 2024-03-12 16:50:27 | [diff] [blame] | 133 | // Chrome features yet. |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 134 | // |
Shubham Aggarwal | b30a0cee | 2021-01-28 15:11:23 | [diff] [blame] | 135 | // WAL mode is currently not fully supported on FuchsiaOS. It will only be |
| 136 | // turned on if the database is also using exclusive locking mode. |
| 137 | // (https://crbug.com/1082059) |
| 138 | // |
| 139 | // Note: Changing page size is not supported when in WAL mode. So running |
| 140 | // 'PRAGMA page_size = <new-size>' will result in no-ops. |
| 141 | // |
Olivier Li | 0408c8c1 | 2025-04-30 14:29:35 | [diff] [blame] | 142 | // Note: This option is not supported in read-only mode. |
| 143 | // |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 144 | // More details at https://www.sqlite.org/wal.html |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 145 | DatabaseOptions& set_wal_mode(bool wal_mode){ |
| 146 | wal_mode_= wal_mode; |
| 147 | return*this; |
| 148 | } |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 149 | |
Etienne Bergeron | 9635e20f | 2025-02-11 17:52:38 | [diff] [blame] | 150 | // If true, enables preloading the database before opening it. |
| 151 | // |
| 152 | // Hints the file system that the database will be accessed soon. |
| 153 | // |
| 154 | // This method should be called on databases that are on the critical path to |
| 155 | // Chrome startup. Informing the filesystem about our expected access pattern |
| 156 | // early on reduces the likelihood that we'll be blocked on disk I/O. This has |
| 157 | // a high impact on startup time. |
| 158 | DatabaseOptions& set_preload(bool preload){ |
| 159 | preload_= preload; |
| 160 | return*this; |
| 161 | } |
| 162 | |
Victor Costan | f2ed41f7 | 2022-03-16 04:04:38 | [diff] [blame] | 163 | // If true, transaction commit waits for data to reach persistent media. |
| 164 | // |
| 165 | // This is currently only meaningful on macOS. All other operating systems |
| 166 | // only support flushing directly to disk. |
| 167 | // |
| 168 | // If both `flush_to_media` and `wal_mode` are false, power loss can lead to |
| 169 | // database corruption. |
| 170 | // |
| 171 | // By default, SQLite considers that transactions commit when they reach the |
| 172 | // disk controller's memory. This guarantees durability in the event of |
| 173 | // software crashes, up to and including the operating system. In the event of |
| 174 | // power loss, SQLite may lose data. If `wal_mode` is false (SQLite uses a |
| 175 | // rollback journal), power loss can lead to database corruption. |
| 176 | // |
| 177 | // When this option is enabled, committing a transaction causes SQLite to wait |
| 178 | // until the data is written to the persistent media. This guarantees |
| 179 | // durability in the event of power loss, which is needed to guarantee the |
| 180 | // integrity of non-WAL databases. |
Olivier Li | 0408c8c1 | 2025-04-30 14:29:35 | [diff] [blame] | 181 | // |
| 182 | // Note: This option is not supported in read-only mode. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 183 | DatabaseOptions& set_flush_to_media(bool flush_to_media){ |
| 184 | flush_to_media_= flush_to_media; |
| 185 | return*this; |
| 186 | } |
Victor Costan | f2ed41f7 | 2022-03-16 04:04:38 | [diff] [blame] | 187 | |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 188 | // Database page size. |
| 189 | // |
Victor Costan | 9d1c8754b | 2021-07-13 02:53:29 | [diff] [blame] | 190 | // The value in this option is only applied to newly created databases. In |
| 191 | // other words, changing the value doesn't impact the databases that have |
| 192 | // already been created on the users' devices. So, changing the value in the |
| 193 | // code without a lot of work (re-creating existing databases) will result in |
| 194 | // inconsistent page sizes across the fleet of user devices, which will make |
| 195 | // it (even) more difficult to reason about database performance. |
| 196 | // |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 197 | // Larger page sizes result in shallower B-trees, because they allow an inner |
| 198 | // page to hold more keys. On the flip side, larger page sizes may result in |
| 199 | // more I/O when making small changes to existing records. |
Shubham Aggarwal | b30a0cee | 2021-01-28 15:11:23 | [diff] [blame] | 200 | // |
| 201 | // Must be a power of two between 512 and 65536 inclusive. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 202 | DatabaseOptions& set_page_size(int page_size){ |
| 203 | page_size_= page_size; |
| 204 | return*this; |
| 205 | } |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 206 | |
| 207 | // The size of in-memory cache, in pages. |
| 208 | // |
| 209 | // SQLite's database cache will take up at most (`page_size` * `cache_size`) |
| 210 | // bytes of RAM. |
| 211 | // |
| 212 | // 0 invokes SQLite's default, which is currently to size up the cache to use |
| 213 | // exactly 2,048,000 bytes of RAM. |
Olivier Li | 0408c8c1 | 2025-04-30 14:29:35 | [diff] [blame] | 214 | // |
| 215 | // Note: This option is not supported in read-only mode. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 216 | DatabaseOptions& set_cache_size(int cache_size){ |
| 217 | cache_size_= cache_size; |
| 218 | return*this; |
| 219 | } |
Victor Costan | 8ec18ee4 | 2021-07-13 19:45:32 | [diff] [blame] | 220 | |
| 221 | // Stores mmap failures in the SQL schema, instead of the meta table. |
| 222 | // |
| 223 | // This option is strongly discouraged for new databases, and will eventually |
| 224 | // be removed. |
| 225 | // |
| 226 | // If this option is true, the mmap status is stored in the database schema. |
| 227 | // Like any other schema change, changing the mmap status invalidates all |
| 228 | // pre-compiled SQL statements. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 229 | DatabaseOptions& set_mmap_alt_status_discouraged( |
| 230 | bool mmap_alt_status_discouraged){ |
| 231 | mmap_alt_status_discouraged_= mmap_alt_status_discouraged; |
| 232 | return*this; |
| 233 | } |
Victor Costan | 04fc909 | 2021-07-17 00:09:34 | [diff] [blame] | 234 | |
Victor Costan | fe078f9 | 2021-07-19 20:02:59 | [diff] [blame] | 235 | // If true, enables SQL views (a discouraged feature) for this database. |
Victor Costan | 04fc909 | 2021-07-17 00:09:34 | [diff] [blame] | 236 | // |
| 237 | // The use of views is discouraged for Chrome code. See README.md for details |
| 238 | // and recommended replacements. |
| 239 | // |
Victor Costan | fe078f9 | 2021-07-19 20:02:59 | [diff] [blame] | 240 | // If this option is false, CREATE VIEW and DROP VIEW succeed, but SELECT |
| 241 | // statements targeting views fail. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 242 | DatabaseOptions& set_enable_views_discouraged(bool enable_views_discouraged){ |
| 243 | enable_views_discouraged_= enable_views_discouraged; |
| 244 | return*this; |
| 245 | } |
Olivier Li Shing Tat-Dupuis | e8a59fb1 | 2024-12-03 19:38:42 | [diff] [blame] | 246 | |
Evan Stade | ff25d2d | 2025-06-24 19:03:44 | [diff] [blame] | 247 | // If true, enables SQL triggers for this database. |
| 248 | // |
| 249 | // The use of triggers should be thoughtful. See README.md for details. |
| 250 | // |
| 251 | // If this option is false, CREATE TRIGGER and DROP TRIGGER succeed, but the |
| 252 | // triggers won't fire. |
| 253 | DatabaseOptions& set_enable_triggers(bool enable_triggers){ |
| 254 | enable_triggers_= enable_triggers; |
| 255 | return*this; |
| 256 | } |
| 257 | |
Olivier Li Shing Tat-Dupuis | e8a59fb1 | 2024-12-03 19:38:42 | [diff] [blame] | 258 | // If non-null, specifies the vfs implementation for the database to look for. |
| 259 | // Most use-cases do not require the use of a |
| 260 | // VFS(https://www.sqlite.org/vfs.html). This option should only be used when |
| 261 | // there is a clear need for it. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 262 | DatabaseOptions& set_vfs_name_discouraged(constchar* vfs_name_discouraged){ |
| 263 | vfs_name_discouraged_= vfs_name_discouraged; |
| 264 | return*this; |
| 265 | } |
| 266 | |
Olivier Li | 3b4ef07 | 2025-02-12 19:37:00 | [diff] [blame] | 267 | // If true database attempts using memory mapped files. True by default. Only |
| 268 | // set to false when a condition is known that prevents the use of memory |
| 269 | // mapped files. See https://www.sqlite.org/mmap.html. |
| 270 | DatabaseOptions& set_mmap_enabled(bool mmap_enabled){ |
| 271 | mmap_enabled_= mmap_enabled; |
| 272 | return*this; |
| 273 | } |
| 274 | |
Olivier Li | 0408c8c1 | 2025-04-30 14:29:35 | [diff] [blame] | 275 | // If true, the database is opened in read-only mode. All operations requiring |
| 276 | // write access will fail, including insert statements and some pragmas. |
| 277 | // Queries on the database will fail in the presence of a hot journal since |
| 278 | // the database file can't be modified to apply it. This must be used in the |
| 279 | // VFS returns read-only file descriptors, but not otherwise. |
| 280 | DatabaseOptions& set_read_only(bool read_only){ |
| 281 | read_only_= read_only; |
| 282 | return*this; |
| 283 | } |
| 284 | |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 285 | private: |
| 286 | friendclassDatabase; |
| 287 | FRIEND_TEST_ALL_PREFIXES(DatabaseOptionsTest, |
| 288 | EnableViewsDiscouraged_FalseByDefault); |
| 289 | FRIEND_TEST_ALL_PREFIXES(DatabaseOptionsTest,FlushToDisk_FalseByDefault); |
| 290 | FRIEND_TEST_ALL_PREFIXES(SQLDatabaseTest,ReOpenWithDifferentJournalMode); |
| 291 | |
| 292 | bool exclusive_locking_=true; |
| 293 | bool exclusive_database_file_lock_=false; |
Etienne Bergeron | e211c3d | 2025-05-01 13:12:43 | [diff] [blame] | 294 | bool wal_mode_=false; |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 295 | bool flush_to_media_=false; |
| 296 | int page_size_= kDefaultPageSize; |
| 297 | int cache_size_=0; |
Etienne Bergeron | 9635e20f | 2025-02-11 17:52:38 | [diff] [blame] | 298 | bool preload_=false; |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 299 | bool mmap_alt_status_discouraged_=false; |
| 300 | bool enable_views_discouraged_=false; |
| 301 | constchar* vfs_name_discouraged_=nullptr; |
Olivier Li | 3b4ef07 | 2025-02-12 19:37:00 | [diff] [blame] | 302 | bool mmap_enabled_=true; |
Olivier Li | 0408c8c1 | 2025-04-30 14:29:35 | [diff] [blame] | 303 | bool read_only_=false; |
Evan Stade | ff25d2d | 2025-06-24 19:03:44 | [diff] [blame] | 304 | bool enable_triggers_=false; |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 305 | }; |
| 306 | |
Tommy C. Li | 7803636c | 2022-07-27 21:47:22 | [diff] [blame] | 307 | // Holds database diagnostics in a structured format. |
| 308 | struct COMPONENT_EXPORT(SQL)DatabaseDiagnostics{ |
| 309 | DatabaseDiagnostics(); |
| 310 | ~DatabaseDiagnostics(); |
| 311 | |
| 312 | usingTraceProto= perfetto::protos::pbzero::ChromeSqlDiagnostics; |
| 313 | // Write a representation of this object into tracing proto. |
| 314 | voidWriteIntoTrace(perfetto::TracedProto<TraceProto> context)const; |
| 315 | |
| 316 | // This was the original error code that triggered the error callback. Should |
| 317 | // generally match `error_code`, but this isn't guaranteed by the code. |
| 318 | int reported_sqlite_error_code=0; |
| 319 | |
| 320 | // Corresponds to `Database::GetErrorCode()`. |
| 321 | int error_code=0; |
| 322 | |
| 323 | // Corresponds to `Database::GetLastErrno()`. |
| 324 | int last_errno=0; |
| 325 | |
| 326 | // Corresponds to `Statement::GetSQLStatement()` of the problematic statement. |
| 327 | // This doesn't include the bound values, and therefore is free of any PII. |
| 328 | std::string sql_statement; |
| 329 | |
| 330 | // The 'version' value stored in the user database's meta table, if it can be |
| 331 | // read. If we fail to read the version of the user database, it's left as 0. |
| 332 | int version=0; |
| 333 | |
| 334 | // Most rows in 'sql_schema' have a non-NULL 'sql' column. Those rows' 'sql' |
| 335 | // contents are logged here, one element per row. |
| 336 | std::vector<std::string> schema_sql_rows; |
| 337 | |
| 338 | // Some rows of 'sql_schema' have a NULL 'sql' column. They are typically |
| 339 | // autogenerated indices, like "sqlite_autoindex_downloads_slices_1". These |
| 340 | // are also logged here by their 'name' column, one element per row. |
| 341 | std::vector<std::string> schema_other_row_names; |
| 342 | |
| 343 | // Sanity checks used for all errors. |
| 344 | bool has_valid_header=false; |
| 345 | bool has_valid_schema=false; |
Tommy C. Li | 400c0f1 | 2022-09-13 22:39:28 | [diff] [blame] | 346 | |
| 347 | // Corresponds to `Database::GetErrorMessage()`. |
| 348 | std::string error_message; |
Tommy C. Li | 7803636c | 2022-07-27 21:47:22 | [diff] [blame] | 349 | }; |
| 350 | |
Victor Costan | 87cf8c7 | 2018-07-19 19:36:04 | [diff] [blame] | 351 | // Handle to an open SQLite database. |
| 352 | // |
Dan McArdle | 44d62a1 | 2024-02-29 17:08:14 | [diff] [blame] | 353 | // Instances of this class are not thread-safe. With few exceptions, Database |
| 354 | // instances should only be accessed from one sequence. Database instances may |
| 355 | // be constructed on one sequence and safely used/destroyed on another. Callers |
| 356 | // may explicitly use `DetachFromSequence()` before moving to another sequence. |
Victor Costan | 9d1c8754b | 2021-07-13 02:53:29 | [diff] [blame] | 357 | // |
| 358 | // When a Database instance goes out of scope, any uncommitted transactions are |
| 359 | // rolled back. |
Victor Costan | e56cc68 | 2018-12-27 01:53:46 | [diff] [blame] | 360 | class COMPONENT_EXPORT(SQL)Database{ |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 361 | private: |
| 362 | classStatementRef;// Forward declaration, see real one below. |
| 363 | |
| 364 | public: |
Anthony Vallée-Dubois | dd2d901 | 2024-12-18 23:25:28 | [diff] [blame] | 365 | // A convenience struct to |
| 366 | // 1. Convert (often implicitly) a static const char* string to a database tag |
| 367 | // to pass to the Database constructors |
| 368 | // 2. Check that the tag is in the DatabaseTag histogram variant list, at |
| 369 | // compile time. |
| 370 | // |
| 371 | // There is nothing special to do to use this struct. For example, the |
| 372 | // following works out of the box: |
| 373 | // |
| 374 | // Database db(DatabaseOptions{}, "TagName"); |
| 375 | // |
| 376 | // However, if the database is a unique_ptr created with make_unique, |
| 377 | // explicitly invoking the constructor is necessary: |
| 378 | // |
| 379 | // auto db = std::make_unique<Database>( |
| 380 | // DatabaseOptions{}, |
| 381 | // Database::Tag("TagName")); |
| 382 | structTag{ |
| 383 | // Purposely not explicit to avoid requiring callers to wrap their tag |
| 384 | // string. |
| 385 | constevalTag(constchar* tag_value): value(tag_value){ |
| 386 | if(!sql_metrics::IsValidDatabaseTag(tag_value)){ |
| 387 | // This will never actually invoke what's under NOTREACHED(), but |
| 388 | // NOTREACHED() is invalid in a consteval context so compilation will |
| 389 | // fail iff the string is invalid. |
| 390 | NOTREACHED()<<"Invalid database tag. Did you add it to the " |
Anthony Vallée-Dubois | eb60f1b | 2024-12-20 16:37:12 | [diff] [blame] | 391 | "DatabaseTag variant in sql/histograms.xml?"; |
Anthony Vallée-Dubois | dd2d901 | 2024-12-18 23:25:28 | [diff] [blame] | 392 | } |
| 393 | } |
| 394 | |
| 395 | std::string_view value; |
| 396 | }; |
| 397 | |
Victor Costan | 9d1c8754b | 2021-07-13 02:53:29 | [diff] [blame] | 398 | // Creates an instance that can receive Open() / OpenInMemory() calls. |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 399 | // |
Victor Costan | 9d1c8754b | 2021-07-13 02:53:29 | [diff] [blame] | 400 | // Some `options` members are only applied to newly created databases. |
| 401 | // |
| 402 | // Most operations on the new instance will fail until Open() / OpenInMemory() |
| 403 | // is called. |
Anthony Vallée-Dubois | e3c9491 | 2024-12-12 16:47:47 | [diff] [blame] | 404 | // |
| 405 | // `tag` is a string uniquely identifying this database for metrics. This |
| 406 | // class automatically uses `tag` to determine which histogram to record to |
| 407 | // for timing and error histograms. Tests that don't care about those |
| 408 | // histograms values can use `sql::test::kTestTag` from |
| 409 | // sql/test/test_helpers.h. |
Anthony Vallée-Dubois | dd2d901 | 2024-12-18 23:25:28 | [diff] [blame] | 410 | Database(DatabaseOptions options,Tag tag); |
Victor Costan | 9d1c8754b | 2021-07-13 02:53:29 | [diff] [blame] | 411 | |
Anthony Vallée-Dubois | 5508a34 | 2024-11-29 16:35:25 | [diff] [blame] | 412 | // Convenience constructor for callers that use default options. |
Anthony Vallée-Dubois | dd2d901 | 2024-12-18 23:25:28 | [diff] [blame] | 413 | explicitDatabase(Tag tag); |
Victor Costan | 9d1c8754b | 2021-07-13 02:53:29 | [diff] [blame] | 414 | |
Victor Costan | 00c7643 | 2021-07-07 16:55:58 | [diff] [blame] | 415 | Database(constDatabase&)=delete; |
| 416 | Database&operator=(constDatabase&)=delete; |
Andrew Paseltiner | 7d512ddd | 2022-09-16 13:36:52 | [diff] [blame] | 417 | Database(Database&&)=delete; |
| 418 | Database&operator=(Database&&)=delete; |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 419 | ~Database(); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 420 | |
| 421 | // Pre-init configuration ---------------------------------------------------- |
| 422 | |
Victor Costan | 7f6abbbe | 2018-07-29 02:57:27 | [diff] [blame] | 423 | // The page size that will be used when creating a new database. |
Anthony Vallée-Dubois | 9adf0bb | 2025-02-03 17:01:41 | [diff] [blame] | 424 | int page_size()const{return options_.page_size_;} |
Victor Costan | 7f6abbbe | 2018-07-29 02:57:27 | [diff] [blame] | 425 | |
Shubham Aggarwal | be4f97ce | 2020-06-19 15:58:57 | [diff] [blame] | 426 | // Returns whether a database will be opened in WAL mode. |
| 427 | boolUseWALMode()const; |
| 428 | |
Victor Costan | 87cf8c7 | 2018-07-19 19:36:04 | [diff] [blame] | 429 | // Opt out of memory-mapped file I/O. |
shess | 7dbd4dee | 2015-10-06 17:39:16 | [diff] [blame] | 430 | void set_mmap_disabled(){ mmap_disabled_=true;} |
| 431 | |
shess@chromium.org | c3881b37 | 2013-05-17 08:39:46 | [diff] [blame] | 432 | // Set an error-handling callback. On errors, the error number (and |
| 433 | // statement, if available) will be passed to the callback. |
| 434 | // |
Victor Costan | ce406da2 | 2021-09-20 21:01:38 | [diff] [blame] | 435 | // If no callback is set, the default error-handling behavior is invoked. The |
| 436 | // default behavior is to LOGs the error and propagate the failure. |
| 437 | // |
| 438 | // In DCHECK-enabled builds, the default error-handling behavior currently |
| 439 | // DCHECKs on errors. This is not correct, because DCHECKs are supposed to |
| 440 | // cover invariants and never fail, whereas SQLite errors can surface even on |
| 441 | // correct usage, due to I/O errors and data corruption. At some point in the |
| 442 | // future, errors will not result in DCHECKs. |
| 443 | // |
| 444 | // The callback will be called on the sequence used for database operations. |
| 445 | // The callback will never be called after the Database instance is destroyed. |
Victor Costan | c7e7f2e | 2018-07-18 20:07:55 | [diff] [blame] | 446 | usingErrorCallback=base::RepeatingCallback<void(int,Statement*)>; |
Victor Costan | d09770c | 2022-03-08 23:14:46 | [diff] [blame] | 447 | void set_error_callback(ErrorCallback callback){ |
Victor Costan | 7d0b01a | 2022-03-15 19:56:49 | [diff] [blame] | 448 | DCHECK(!callback.is_null())<<"Use reset_error_callback() explicitly"; |
| 449 | DCHECK(error_callback_.is_null()) |
Victor Costan | d09770c | 2022-03-08 23:14:46 | [diff] [blame] | 450 | <<"Overwriting previously set error callback"; |
| 451 | error_callback_= std::move(callback); |
shess@chromium.org | c3881b37 | 2013-05-17 08:39:46 | [diff] [blame] | 452 | } |
Victor Costan | 87cf8c7 | 2018-07-19 19:36:04 | [diff] [blame] | 453 | void reset_error_callback(){ error_callback_.Reset();} |
Austin Sullivan | 2fbe496e | 2023-05-18 19:48:52 | [diff] [blame] | 454 | bool has_error_callback()const{return!error_callback_.is_null();} |
shess@chromium.org | c3881b37 | 2013-05-17 08:39:46 | [diff] [blame] | 455 | |
Etienne Bergeron | f969727a | 2023-12-15 19:40:34 | [diff] [blame] | 456 | const std::string& histogram_tag()const{return histogram_tag_;} |
shess@chromium.org | c088e3a3 | 2013-01-03 23:59:14 | [diff] [blame] | 457 | |
Victor Costan | 8c3a992 | 2022-02-26 03:50:52 | [diff] [blame] | 458 | // Asks SQLite to perform a full integrity check on the database. |
| 459 | // |
| 460 | // Returns true if the integrity check was completed successfully. Success |
| 461 | // does not necessarily entail that the database is healthy. Finding |
| 462 | // corruption and reporting it in `messages` counts as success. |
| 463 | // |
| 464 | // If the method returns true, `messages` is populated with a list of |
| 465 | // diagnostic messages. If the integrity check finds no errors, `messages` |
| 466 | // will contain exactly one "ok" string. This unusual API design is explained |
| 467 | // by the fact that SQLite exposes integrity check functionality as a PRAGMA, |
| 468 | // and the PRAGMA returns "ok" in case of success. |
michaeln@chromium.org | 579446c | 2013-12-16 18:36:52 | [diff] [blame] | 469 | boolFullIntegrityCheck(std::vector<std::string>* messages); |
| 470 | |
afakhry | 7c9abe7 | 2016-08-05 17:33:19 | [diff] [blame] | 471 | // Meant to be called from a client error callback so that it's able to |
Tommy C. Li | 7803636c | 2022-07-27 21:47:22 | [diff] [blame] | 472 | // get diagnostic information about the database. `diagnostics` is an optional |
| 473 | // out parameter. If `diagnostics` is defined, this method populates all of |
| 474 | // its fields. |
| 475 | std::stringGetDiagnosticInfo(int extended_error, |
| 476 | Statement* statement, |
| 477 | DatabaseDiagnostics* diagnostics=nullptr); |
afakhry | 7c9abe7 | 2016-08-05 17:33:19 | [diff] [blame] | 478 | |
ssid | 1f4e536 | 2016-12-08 20:41:38 | [diff] [blame] | 479 | // Reports memory usage into provided memory dump with the given name. |
| 480 | boolReportMemoryUsage(base::trace_event::ProcessMemoryDump* pmd, |
| 481 | const std::string& dump_name); |
dskiba | b4199f8 | 2016-11-21 20:16:13 | [diff] [blame] | 482 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 483 | // Initialization ------------------------------------------------------------ |
| 484 | |
Victor Costan | 6de11461f | 2022-03-13 06:47:19 | [diff] [blame] | 485 | // Opens or creates a database on disk. |
| 486 | // |
| 487 | // `db_file_path` points to the file storing database pages. Other files |
| 488 | // associated with the database (rollback journal, write-ahead log, |
| 489 | // shared-memory file) may be created. |
| 490 | // |
Dan McArdle | 4feabeb5 | 2024-01-03 15:17:13 | [diff] [blame] | 491 | // Returns true in case of success, false in case of failure. If an error |
| 492 | // occurs, this function will invoke the error callback if it is present and |
| 493 | // then may attempt to open the database a second time. If the second attempt |
| 494 | // succeeds, it will return true. |
Victor Costan | 6de11461f | 2022-03-13 06:47:19 | [diff] [blame] | 495 | [[nodiscard]]boolOpen(constbase::FilePath& db_file_path); |
brettw@chromium.org | 765b4450 | 2009-10-02 05:01:42 | [diff] [blame] | 496 | |
Victor Costan | 6de11461f | 2022-03-13 06:47:19 | [diff] [blame] | 497 | // Alternative to Open() that creates an in-memory database. |
| 498 | // |
| 499 | // Returns true in case of success, false in case of failure. |
| 500 | // |
| 501 | // The memory associated with the database will be released when the database |
| 502 | // is closed. |
Daniel Cheng | 1ac0cad | 2022-01-14 00:19:53 | [diff] [blame] | 503 | [[nodiscard]]boolOpenInMemory(); |
brettw@chromium.org | 765b4450 | 2009-10-02 05:01:42 | [diff] [blame] | 504 | |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 505 | // Returns true if the database has been successfully opened. |
Austin Sullivan | 6c6faa5 | 2023-08-16 18:32:37 | [diff] [blame] | 506 | bool is_open()const; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 507 | |
Dan McArdle | 44d62a1 | 2024-02-29 17:08:14 | [diff] [blame] | 508 | // Detach from the currently-attached sequence. If already attached to a |
| 509 | // sequence, this method must be called from that sequence. |
| 510 | voidDetachFromSequence(); |
| 511 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 512 | // Closes the database. This is automatically performed on destruction for |
| 513 | // you, but this allows you to close the database early. You must not call |
| 514 | // any other functions after closing it. It is permissable to call Close on |
| 515 | // an uninitialized or already-closed database. |
| 516 | voidClose(); |
| 517 | |
Victor Costan | 52bef81 | 2018-12-05 07:41:49 | [diff] [blame] | 518 | // Release all non-essential memory associated with this database connection. |
| 519 | voidTrimMemory(); |
rmcilroy@chromium.org | be7995f1 | 2013-07-18 18:49:14 | [diff] [blame] | 520 | |
shess@chromium.org | 8e0c0128 | 2012-04-06 19:36:49 | [diff] [blame] | 521 | // Raze the database to the ground. This approximates creating a |
| 522 | // fresh database from scratch, within the constraints of SQLite's |
| 523 | // locking protocol (locks and open handles can make doing this with |
| 524 | // filesystem operations problematic). Returns true if the database |
| 525 | // was razed. |
| 526 | // |
| 527 | // false is returned if the database is locked by some other |
Carlos Knippschild | 46800c9f | 2017-09-02 02:21:43 | [diff] [blame] | 528 | // process. |
shess@chromium.org | 8e0c0128 | 2012-04-06 19:36:49 | [diff] [blame] | 529 | // |
| 530 | // NOTE(shess): Raze() will DCHECK in the following situations: |
| 531 | // - database is not open. |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 532 | // - the database has a transaction open. |
shess@chromium.org | 8e0c0128 | 2012-04-06 19:36:49 | [diff] [blame] | 533 | // - a SQLite issue occurs which is structural in nature (like the |
| 534 | // statements used are broken). |
| 535 | // Since Raze() is expected to be called in unexpected situations, |
| 536 | // these all return false, since it is unlikely that the caller |
| 537 | // could fix them. |
shess@chromium.org | 6d42f15 | 2012-11-10 00:38:24 | [diff] [blame] | 538 | // |
Shubham Aggarwal | 7b60fe6e | 2020-10-15 06:00:28 | [diff] [blame] | 539 | // The database's page size is taken from |options_.page_size|. The |
shess@chromium.org | 6d42f15 | 2012-11-10 00:38:24 | [diff] [blame] | 540 | // existing database's |auto_vacuum| setting is lost (the |
| 541 | // possibility of corruption makes it unreliable to pull it from the |
| 542 | // existing database). To re-enable on the empty database requires |
| 543 | // running "PRAGMA auto_vacuum = 1;" then "VACUUM". |
| 544 | // |
| 545 | // NOTE(shess): For Android, SQLITE_DEFAULT_AUTOVACUUM is set to 1, |
| 546 | // so Raze() sets auto_vacuum to 1. |
| 547 | // |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 548 | // TODO(shess): Raze() needs a database so cannot clear SQLITE_NOTADB. |
| 549 | // TODO(shess): Bake auto_vacuum into Database's API so it can |
shess@chromium.org | 6d42f15 | 2012-11-10 00:38:24 | [diff] [blame] | 550 | // just pick up the default. |
shess@chromium.org | 8e0c0128 | 2012-04-06 19:36:49 | [diff] [blame] | 551 | boolRaze(); |
shess@chromium.org | 8e0c0128 | 2012-04-06 19:36:49 | [diff] [blame] | 552 | |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 553 | // Breaks all outstanding transactions (as initiated by |
shess@chromium.org | 8d40941 | 2013-07-19 18:25:30 | [diff] [blame] | 554 | // BeginTransaction()), closes the SQLite database, and poisons the |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 555 | // object so that all future operations against the Database (or |
shess@chromium.org | 8d40941 | 2013-07-19 18:25:30 | [diff] [blame] | 556 | // its Statements) fail safely, without side effects. |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 557 | // |
shess@chromium.org | 8d40941 | 2013-07-19 18:25:30 | [diff] [blame] | 558 | // This is intended as an alternative to Close() in error callbacks. |
| 559 | // Close() should still be called at some point. |
| 560 | voidPoison(); |
| 561 | |
Andrew Paseltiner | b03bebe6 | 2023-03-27 13:08:24 | [diff] [blame] | 562 | // `Raze()` the database and `Poison()` the handle. Returns the return |
| 563 | // value from `Raze()`. |
| 564 | boolRazeAndPoison(); |
| 565 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 566 | // Delete the underlying database files associated with |path|. This should be |
| 567 | // used on a database which is not opened by any Database instance. Open |
| 568 | // Database instances pointing to the database can cause odd results or |
| 569 | // corruption (for instance if a hot journal is deleted but the associated |
| 570 | // database is not). |
shess@chromium.org | 8d2e39e | 2013-06-24 05:55:08 | [diff] [blame] | 571 | // |
| 572 | // Returns true if the database file and associated journals no |
| 573 | // longer exist, false otherwise. If the database has never |
| 574 | // existed, this will return true. |
| 575 | staticboolDelete(constbase::FilePath& path); |
| 576 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 577 | // Transactions -------------------------------------------------------------- |
| 578 | |
| 579 | // Transaction management. We maintain a virtual transaction stack to emulate |
| 580 | // nested transactions since sqlite can't do nested transactions. The |
| 581 | // limitation is you can't roll back a sub transaction: if any transaction |
| 582 | // fails, all transactions open will also be rolled back. Any nested |
| 583 | // transactions after one has rolled back will return fail for Begin(). If |
| 584 | // Begin() fails, you must not call Commit or Rollback(). |
| 585 | // |
| 586 | // Normally you should use sql::Transaction to manage a transaction, which |
| 587 | // will scope it to a C++ context. |
Andrew Paseltiner | cbb1448 | 2024-05-20 13:24:06 | [diff] [blame] | 588 | [[nodiscard]]boolBeginTransaction(InternalApiToken); |
| 589 | voidRollbackTransaction(InternalApiToken); |
| 590 | [[nodiscard]]boolCommitTransaction(InternalApiToken); |
| 591 | |
| 592 | // These methods are deprecated and will be removed in the future: The |
| 593 | // `Transaction` class should be used instead. |
| 594 | boolBeginTransactionDeprecated(); |
| 595 | voidRollbackTransactionDeprecated(); |
| 596 | boolCommitTransactionDeprecated(); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 597 | |
shess@chromium.org | 8d40941 | 2013-07-19 18:25:30 | [diff] [blame] | 598 | // Rollback all outstanding transactions. Use with care, there may |
| 599 | // be scoped transactions on the stack. |
| 600 | voidRollbackAllTransactions(); |
| 601 | |
Victor Costan | 628afca | 2021-09-21 02:36:09 | [diff] [blame] | 602 | boolHasActiveTransactions()const{ |
| 603 | DCHECK_GE(transaction_nesting_,0); |
Dan McArdle | 89348ed | 2024-02-26 20:50:08 | [diff] [blame] | 604 | return is_open()&& transaction_nesting_>0; |
Victor Costan | 628afca | 2021-09-21 02:36:09 | [diff] [blame] | 605 | } |
| 606 | |
| 607 | // Deprecated in favor of HasActiveTransactions(). |
| 608 | // |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 609 | // Returns the current transaction nesting, which will be 0 if there are |
| 610 | // no open transactions. |
| 611 | int transaction_nesting()const{return transaction_nesting_;} |
| 612 | |
shess@chromium.org | 8d40941 | 2013-07-19 18:25:30 | [diff] [blame] | 613 | // Attached databases--------------------------------------------------------- |
| 614 | |
Victor Costan | 169ef03 | 2021-07-14 08:45:49 | [diff] [blame] | 615 | // Attaches an existing database to this connection. |
shess@chromium.org | 8d40941 | 2013-07-19 18:25:30 | [diff] [blame] | 616 | // |
Victor Costan | 169ef03 | 2021-07-14 08:45:49 | [diff] [blame] | 617 | // `attachment_point` must only contain lowercase letters. |
| 618 | // |
Evan Stade | 1d80896e | 2024-02-28 18:40:26 | [diff] [blame] | 619 | // Use is generally discouraged in production code. The README has more |
| 620 | // details. |
Victor Costan | 8a87f7e5 | 2017-11-10 01:29:30 | [diff] [blame] | 621 | // |
| 622 | // On the SQLite version shipped with Chrome (3.21+, Oct 2017), databases can |
| 623 | // be attached while a transaction is opened. However, these databases cannot |
Victor Costan | 70bedf2 | 2018-07-18 21:21:14 | [diff] [blame] | 624 | // be detached until the transaction is committed or aborted. |
shess@chromium.org | 8d40941 | 2013-07-19 18:25:30 | [diff] [blame] | 625 | boolAttachDatabase(constbase::FilePath& other_db_path, |
Md Hasibul Hasan | 52ffeca6 | 2024-03-26 18:23:18 | [diff] [blame] | 626 | std::string_view attachment_point); |
Victor Costan | 169ef03 | 2021-07-14 08:45:49 | [diff] [blame] | 627 | |
| 628 | // Detaches a database that was previously attached with AttachDatabase(). |
| 629 | // |
| 630 | // `attachment_point` must match the argument of a previously successsful |
| 631 | // AttachDatabase() call. |
| 632 | // |
| 633 | // Attachment APIs are only exposed for use in recovery. General use is |
| 634 | // discouraged in Chrome. The README has more details. |
Md Hasibul Hasan | 52ffeca6 | 2024-03-26 18:23:18 | [diff] [blame] | 635 | boolDetachDatabase(std::string_view attachment_point); |
shess@chromium.org | 8d40941 | 2013-07-19 18:25:30 | [diff] [blame] | 636 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 637 | // Statements ---------------------------------------------------------------- |
| 638 | |
Victor Costan | 205b96dc | 2021-07-21 20:27:46 | [diff] [blame] | 639 | // Executes a SQL statement. Returns true for success, and false for failure. |
shess@chromium.org | 9fe3755 | 2011-12-23 17:07:20 | [diff] [blame] | 640 | // |
Victor Costan | 205b96dc | 2021-07-21 20:27:46 | [diff] [blame] | 641 | // `sql` should be a single SQL statement. Production code should not execute |
Victor Costan | 289f2c8b | 2021-07-22 06:33:47 | [diff] [blame] | 642 | // multiple SQL statements at once, to facilitate crash debugging. Test code |
| 643 | // should use ExecuteScriptForTesting(). |
Victor Costan | 205b96dc | 2021-07-21 20:27:46 | [diff] [blame] | 644 | // |
| 645 | // `sql` cannot have parameters. Statements with parameters can be handled by |
| 646 | // sql::Statement. See GetCachedStatement() and GetUniqueStatement(). |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 647 | [[nodiscard]]boolExecute(base::cstring_view sql); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 648 | |
Victor Costan | 289f2c8b | 2021-07-22 06:33:47 | [diff] [blame] | 649 | // Executes a sequence of SQL statements. |
| 650 | // |
| 651 | // Returns true if all statements execute successfully. If a statement fails, |
| 652 | // stops and returns false. Calls should be wrapped in ASSERT_TRUE(). |
| 653 | // |
| 654 | // The database's error handler is not invoked when errors occur. This method |
| 655 | // is a convenience for setting up a complex on-disk database state, such as |
| 656 | // an old schema version with test contents. |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 657 | [[nodiscard]]boolExecuteScriptForTesting(base::cstring_view sql_script); |
Victor Costan | 289f2c8b | 2021-07-22 06:33:47 | [diff] [blame] | 658 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 659 | // Returns a statement for the given SQL using the statement cache. It can |
| 660 | // take a nontrivial amount of work to parse and compile a statement, so |
| 661 | // keeping commonly-used ones around for future use is important for |
| 662 | // performance. |
| 663 | // |
Victor Costan | 613b430 | 2018-11-20 05:32:43 | [diff] [blame] | 664 | // The SQL_FROM_HERE macro is the recommended way of generating a StatementID. |
| 665 | // Code that generates custom IDs must ensure that a StatementID is never used |
| 666 | // for different SQL statements. Failing to meet this requirement results in |
| 667 | // incorrect behavior, and should be caught by a DCHECK. |
| 668 | // |
| 669 | // The SQL statement passed in |sql| must match the SQL statement reported |
| 670 | // back by SQLite. Mismatches are caught by a DCHECK, so any code that has |
| 671 | // automated test coverage or that was manually tested on a DCHECK build will |
| 672 | // not exhibit this problem. Mismatches generally imply that the statement |
| 673 | // passed in has extra whitespace or comments surrounding it, which waste |
| 674 | // storage and CPU cycles. |
| 675 | // |
shess@chromium.org | eff1fa52 | 2011-12-12 23:50:59 | [diff] [blame] | 676 | // If the |sql| has an error, an invalid, inert StatementRef is returned (and |
| 677 | // the code will crash in debug). The caller must deal with this eventuality, |
| 678 | // either by checking validity of the |sql| before calling, by correctly |
| 679 | // handling the return of an inert statement, or both. |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 680 | // |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 681 | // Example: |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 682 | // sql::Statement stmt(database_.GetCachedStatement( |
nick@chromium.org | 3273dce | 2010-01-27 16:08:08 | [diff] [blame] | 683 | // SQL_FROM_HERE, "SELECT * FROM foo")); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 684 | // if (!stmt) |
| 685 | // return false; // Error creating statement. |
Victor Costan | 12daa3ac9 | 2018-07-19 01:05:58 | [diff] [blame] | 686 | scoped_refptr<StatementRef>GetCachedStatement(StatementID id, |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 687 | base::cstring_view sql); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 688 | |
shess@chromium.org | eff1fa52 | 2011-12-12 23:50:59 | [diff] [blame] | 689 | // Used to check a |sql| statement for syntactic validity. If the statement is |
| 690 | // valid SQL, returns true. |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 691 | boolIsSQLValid(base::cstring_view sql); |
shess@chromium.org | eff1fa52 | 2011-12-12 23:50:59 | [diff] [blame] | 692 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 693 | // Returns a non-cached statement for the given SQL. Use this for SQL that |
| 694 | // is only executed once or only rarely (there is overhead associated with |
| 695 | // keeping a statement cached). |
| 696 | // |
| 697 | // See GetCachedStatement above for examples and error information. |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 698 | scoped_refptr<StatementRef>GetUniqueStatement(base::cstring_view sql); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 699 | |
ssid | 583f55e | 2022-04-21 19:59:00 | [diff] [blame] | 700 | // Returns a non-cached statement same as `GetUniqueStatement()`, except |
| 701 | // returns an invalid statement if the statement makes direct changes to the |
| 702 | // database file. This readonly check does not include changes made by |
| 703 | // application-defined functions. See more at: |
| 704 | // https://www.sqlite.org/c3ref/stmt_readonly.html. |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 705 | scoped_refptr<Database::StatementRef>GetReadonlyStatement( |
| 706 | base::cstring_view sql); |
ssid | 583f55e | 2022-04-21 19:59:00 | [diff] [blame] | 707 | |
Evan Stade | 416f46f1 | 2025-06-18 15:42:39 | [diff] [blame] | 708 | // Opens a blob for streaming. Returns nullopt on failure. Note that this |
| 709 | // should only be called if the given table, column, and row is known to |
| 710 | // exist --- everything else is an error. For a list of failure modes, see |
| 711 | // https://www.sqlite.org/c3ref/blob_open.html |
| 712 | // |
| 713 | // See `StreamingBlobHandle` docs for notes on lifetime. |
| 714 | std::optional<StreamingBlobHandle>GetStreamingBlob(base::cstring_view table, |
| 715 | base::cstring_view column, |
| 716 | int64_t row_id, |
| 717 | boolreadonly); |
| 718 | |
Shubham Aggarwal | be4f97ce | 2020-06-19 15:58:57 | [diff] [blame] | 719 | // Performs a passive checkpoint on the main attached database if it is in |
| 720 | // WAL mode. Returns true if the checkpoint was successful and false in case |
| 721 | // of an error. It is a no-op if the database is not in WAL mode. |
| 722 | // |
| 723 | // Note: Checkpointing is a very slow operation and will block any writes |
| 724 | // until it is finished. Please use with care. |
| 725 | boolCheckpointDatabase(); |
| 726 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 727 | // Info querying ------------------------------------------------------------- |
| 728 | |
shess | a62504d | 2016-11-07 19:26:12 | [diff] [blame] | 729 | // Returns true if the given structure exists. Instead of test-then-create, |
| 730 | // callers should almost always prefer the "IF NOT EXISTS" version of the |
| 731 | // CREATE statement. |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 732 | // TODO(https://crbug.com/341639215): these should take a `base::cstring`. |
Md Hasibul Hasan | 52ffeca6 | 2024-03-26 18:23:18 | [diff] [blame] | 733 | boolDoesIndexExist(std::string_view index_name); |
| 734 | boolDoesTableExist(std::string_view table_name); |
| 735 | boolDoesViewExist(std::string_view table_name); |
michaeln@google.com | e2cadec8 | 2011-12-13 02:00:53 | [diff] [blame] | 736 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 737 | // Returns true if a column with the given name exists in the given table. |
Victor Costan | 1ff47e9 | 2018-12-07 11:10:43 | [diff] [blame] | 738 | // |
| 739 | // Calling this method on a VIEW returns an unspecified result. |
| 740 | // |
| 741 | // This should only be used by migration code for legacy features that do not |
| 742 | // use MetaTable, and need an alternative way of figuring out the database's |
| 743 | // current version. |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 744 | boolDoesColumnExist(base::cstring_view table_name, |
| 745 | base::cstring_view column_name); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 746 | |
| 747 | // Returns sqlite's internal ID for the last inserted row. Valid only |
| 748 | // immediately after an insert. |
tfarina | 720d4f3 | 2015-05-11 22:31:26 | [diff] [blame] | 749 | int64_tGetLastInsertRowId()const; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 750 | |
brettw@chromium.org | 1ed78a3 | 2009-09-15 20:24:17 | [diff] [blame] | 751 | // Returns sqlite's count of the number of rows modified by the last |
| 752 | // statement executed. Will be 0 if no statement has executed or the database |
| 753 | // is closed. |
Victor Costan | d4dfb4f | 2022-02-24 00:01:12 | [diff] [blame] | 754 | int64_tGetLastChangeCount(); |
brettw@chromium.org | 1ed78a3 | 2009-09-15 20:24:17 | [diff] [blame] | 755 | |
Victor Costan | d6e7325 | 2020-10-14 21:11:25 | [diff] [blame] | 756 | // Approximates the amount of memory used by SQLite for this database. |
| 757 | // |
| 758 | // This measures the memory used for the page cache (most likely the biggest |
| 759 | // consumer), database schema, and prepared statements. |
| 760 | // |
| 761 | // The memory used by the page cache can be recovered by calling TrimMemory(), |
| 762 | // which will cause SQLite to drop the page cache. |
| 763 | intGetMemoryUsage(); |
| 764 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 765 | // Errors -------------------------------------------------------------------- |
| 766 | |
| 767 | // Returns the error code associated with the last sqlite operation. |
| 768 | intGetErrorCode()const; |
| 769 | |
Vikram Pasupathy | 73c60391 | 2024-04-02 20:51:31 | [diff] [blame] | 770 | // Returns the errno associated with GetErrorCode(). See <errno.h>. |
shess@chromium.org | 767718e5 | 2010-09-21 23:18:49 | [diff] [blame] | 771 | intGetLastErrno()const; |
| 772 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 773 | // Returns a pointer to a statically allocated string associated with the |
| 774 | // last sqlite operation. |
| 775 | constchar*GetErrorMessage()const; |
| 776 | |
shess@chromium.org | 92cd00a | 2013-08-16 11:09:58 | [diff] [blame] | 777 | // Return a reproducible representation of the schema equivalent to |
| 778 | // running the following statement at a sqlite3 command-line: |
John Delaney | 86dbec6 | 2021-08-24 15:05:21 | [diff] [blame] | 779 | // SELECT type, name, tbl_name, sql FROM sqlite_schema ORDER BY 1, 2, 3, 4; |
Victor Costan | 106e5007 | 2021-07-17 00:04:49 | [diff] [blame] | 780 | std::stringGetSchema(); |
shess@chromium.org | 92cd00a | 2013-08-16 11:09:58 | [diff] [blame] | 781 | |
shess | 97681440 | 2016-06-21 06:56:25 | [diff] [blame] | 782 | // Returns |true| if there is an error expecter (see SetErrorExpecter), and |
| 783 | // that expecter returns |true| when passed |error|. Clients which provide an |
| 784 | // |error_callback| should use IsExpectedSqliteError() to check for unexpected |
Peter Boström | 29c76179 | 2024-01-18 23:05:29 | [diff] [blame] | 785 | // errors; if one is detected, DLOG(FATAL) is generally appropriate (see |
shess | 97681440 | 2016-06-21 06:56:25 | [diff] [blame] | 786 | // OnSqliteError implementation). |
Victor Costan | edf48be | 2022-03-14 21:40:12 | [diff] [blame] | 787 | staticboolIsExpectedSqliteError(int sqlite_error_code); |
shess@chromium.org | 74cdede | 2013-09-25 05:39:57 | [diff] [blame] | 788 | |
Victor Costan | ce678e7 | 2018-07-24 10:25:00 | [diff] [blame] | 789 | // Computes the path of a database's rollback journal. |
| 790 | // |
| 791 | // The journal file is created at the beginning of the database's first |
| 792 | // transaction. The file may be removed and re-created between transactions, |
| 793 | // depending on whether the database is opened in exclusive mode, and on |
| 794 | // configuration options. The journal file does not exist when the database |
| 795 | // operates in WAL mode. |
| 796 | // |
| 797 | // This is intended for internal use and tests. To preserve our ability to |
| 798 | // iterate on our SQLite configuration, features must avoid relying on |
| 799 | // the existence of specific files. |
| 800 | staticbase::FilePathJournalPath(constbase::FilePath& db_path); |
| 801 | |
| 802 | // Computes the path of a database's write-ahead log (WAL). |
| 803 | // |
| 804 | // The WAL file exists while a database is opened in WAL mode. |
| 805 | // |
| 806 | // This is intended for internal use and tests. To preserve our ability to |
| 807 | // iterate on our SQLite configuration, features must avoid relying on |
| 808 | // the existence of specific files. |
| 809 | staticbase::FilePathWriteAheadLogPath(constbase::FilePath& db_path); |
| 810 | |
| 811 | // Computes the path of a database's shared memory (SHM) file. |
| 812 | // |
| 813 | // The SHM file is used to coordinate between multiple processes using the |
| 814 | // same database in WAL mode. Thus, this file only exists for databases using |
| 815 | // WAL and not opened in exclusive mode. |
| 816 | // |
| 817 | // This is intended for internal use and tests. To preserve our ability to |
| 818 | // iterate on our SQLite configuration, features must avoid relying on |
| 819 | // the existence of specific files. |
| 820 | staticbase::FilePathSharedMemoryFilePath(constbase::FilePath& db_path); |
| 821 | |
Victor Costan | 7f6abbbe | 2018-07-29 02:57:27 | [diff] [blame] | 822 | // Internal state accessed by other classes in //sql. |
Dan McArdle | 44d62a1 | 2024-02-29 17:08:14 | [diff] [blame] | 823 | base::WeakPtr<Database>GetWeakPtr(InternalApiToken); |
Victor Costan | 7f6abbbe | 2018-07-29 02:57:27 | [diff] [blame] | 824 | sqlite3* db(InternalApiToken)const{return db_;} |
| 825 | bool poisoned(InternalApiToken)const{return poisoned_;} |
Austin Sullivan | 0593ef9 | 2023-05-17 20:46:30 | [diff] [blame] | 826 | base::FilePathDbPath(InternalApiToken)const{returnDbPath();} |
Victor Costan | 7f6abbbe | 2018-07-29 02:57:27 | [diff] [blame] | 827 | |
Victor Costan | bc4285f | 2021-09-20 21:29:28 | [diff] [blame] | 828 | // Interface with sql::test::ScopedErrorExpecter. |
| 829 | usingScopedErrorExpecterCallback=base::RepeatingCallback<bool(int)>; |
| 830 | staticvoidSetScopedErrorExpecter(ScopedErrorExpecterCallback* expecter, |
| 831 | base::PassKey<test::ScopedErrorExpecter>); |
| 832 | staticvoidResetScopedErrorExpecter( |
| 833 | base::PassKey<test::ScopedErrorExpecter>); |
shess@chromium.org | 4350e32 | 2013-06-18 22:18:10 | [diff] [blame] | 834 | |
Victor Costan | bc4285f | 2021-09-20 21:29:28 | [diff] [blame] | 835 | private: |
shess@chromium.org | eff1fa52 | 2011-12-12 23:50:59 | [diff] [blame] | 836 | // Statement accesses StatementRef which we don't want to expose to everybody |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 837 | // (they should go through Statement). |
| 838 | friendclassStatement; |
| 839 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 840 | FRIEND_TEST_ALL_PREFIXES(SQLDatabaseTest,CachedStatement); |
| 841 | FRIEND_TEST_ALL_PREFIXES(SQLDatabaseTest,CollectDiagnosticInfo); |
Victor Costan | dc72e8d | 2022-03-14 18:14:51 | [diff] [blame] | 842 | FRIEND_TEST_ALL_PREFIXES(SQLDatabaseTest,ComputeMmapSizeForOpen); |
| 843 | FRIEND_TEST_ALL_PREFIXES(SQLDatabaseTest,ComputeMmapSizeForOpenAltStatus); |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 844 | FRIEND_TEST_ALL_PREFIXES(SQLDatabaseTest,OnMemoryDump); |
Etienne Bergeron | 1ee05fe | 2025-05-23 14:37:36 | [diff] [blame] | 845 | FRIEND_TEST_ALL_PREFIXES(SQLDatabaseTest, |
| 846 | RazeAndPoison_ComputeMmapSizeForOpen); |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 847 | FRIEND_TEST_ALL_PREFIXES(SQLDatabaseTest,RegisterIntentToUpload); |
shess | f7fcc45 | 2017-04-19 22:10:41 | [diff] [blame] | 848 | FRIEND_TEST_ALL_PREFIXES(SQLiteFeaturesTest,WALNoClose); |
a20.singh | b0ca112 | 2022-05-26 03:32:45 | [diff] [blame] | 849 | FRIEND_TEST_ALL_PREFIXES(SQLEmptyPathDatabaseTest,EmptyPathTest); |
Evan Stade | 416f46f1 | 2025-06-18 15:42:39 | [diff] [blame] | 850 | FRIEND_TEST_ALL_PREFIXES(StreamingBlobHandleTest,Basic); |
shess | c8cd2a16 | 2015-10-22 20:30:46 | [diff] [blame] | 851 | |
Anthony Vallée-Dubois | de3720258 | 2024-12-04 18:52:30 | [diff] [blame] | 852 | // A scoped utility to setup error reporting during the `Open()` operation |
| 853 | classScopedOpenErrorReporter{ |
| 854 | public: |
| 855 | // db: the database to instrument. Must outlive `this` |
| 856 | // histogram: the histogram to record the error code into. Will |
| 857 | // automatically be suffixed with `Database::histogram_tag()` if it's |
| 858 | // specified, "NoTag" otherwise. |
| 859 | ScopedOpenErrorReporter(Database* db, std::string_view histogram); |
| 860 | ~ScopedOpenErrorReporter(); |
| 861 | |
| 862 | private: |
| 863 | // The callback that will be invoked by the database in case of an error. |
| 864 | voidOnErrorDuringOpen(SqliteResultCode code); |
| 865 | |
| 866 | raw_ptr<Database> db_; |
| 867 | std::string_view histogram_; |
| 868 | }; |
| 869 | |
| 870 | // Invoke `open_error_reporting_callback_` if it's set. |
| 871 | voidMaybeReportErrorDuringOpen(SqliteResultCode code); |
| 872 | |
Evan Stade | 4c7d6b3 | 2024-03-12 16:50:27 | [diff] [blame] | 873 | // Implements Open(), OpenInMemory(). |
shess@chromium.org | fed734a | 2013-07-17 04:45:13 | [diff] [blame] | 874 | // |
Evan Stade | 4c7d6b3 | 2024-03-12 16:50:27 | [diff] [blame] | 875 | // `db_file_path` is a UTF-8 path to the file storing the database pages. If |
| 876 | // `file_name` is the SQLite magic memory path :memory:, the database will be |
| 877 | // opened in-memory. |
| 878 | boolOpenInternal(const std::string& file_name); |
brettw@chromium.org | 765b4450 | 2009-10-02 05:01:42 | [diff] [blame] | 879 | |
Etienne Bergeron | 9635e20f | 2025-02-11 17:52:38 | [diff] [blame] | 880 | // Requests the operating system to preload the pages on disk into memory. |
| 881 | voidPreloadInternal(constbase::FilePath& path); |
| 882 | |
Victor Costan | f9832e3 | 2022-03-12 18:33:59 | [diff] [blame] | 883 | // Configures the underlying sqlite3* object via sqlite3_db_config(). |
| 884 | // |
| 885 | // To minimize the number of possible SQLite code paths executed in Chrome, |
| 886 | // this method must be called right after the underlying sqlite3* object is |
| 887 | // obtained from sqlite3_open*(), before any other sqlite3_*() methods are |
| 888 | // called on the object. |
| 889 | voidConfigureSqliteDatabaseObject(); |
| 890 | |
Andrew Paseltiner | d309fec | 2023-03-28 16:59:55 | [diff] [blame] | 891 | // Internal close function used by Close() and RazeAndPoison(). |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 892 | // |forced| indicates that orderly-shutdown checks should not apply. |
| 893 | voidCloseInternal(bool forced); |
| 894 | |
Evan Stade | 416f46f1 | 2025-06-18 15:42:39 | [diff] [blame] | 895 | // Called when a blob opened with `GetStreamingBlob()` is closed. `result` may |
| 896 | // or may not be an error; if it is, `error_source` identifies which sqlite3 |
| 897 | // call caused the error. |
| 898 | voidOnStreamingBlobClosed(SqliteResultCode result,constchar* error_source); |
| 899 | |
Etienne Pierre-Doray | a71d7af | 2019-02-07 02:07:54 | [diff] [blame] | 900 | // Construct a ScopedBlockingCall to annotate IO calls, but only if |
Etienne Bergeron | e7681c7 | 2020-01-17 00:51:20 | [diff] [blame] | 901 | // database wasn't open in memory. ScopedBlockingCall uses |from_here| to |
| 902 | // declare its blocking execution scope (see https://www.crbug/934302). |
Etienne Pierre-Doray | a71d7af | 2019-02-07 02:07:54 | [diff] [blame] | 903 | voidInitScopedBlockingCall( |
Etienne Bergeron | e7681c7 | 2020-01-17 00:51:20 | [diff] [blame] | 904 | constbase::Location& from_here, |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 905 | std::optional<base::ScopedBlockingCall>* scoped_blocking_call)const{ |
shess@chromium.org | 35f7e539 | 2012-07-27 19:54:50 | [diff] [blame] | 906 | if(!in_memory_) |
Etienne Bergeron | e7681c7 | 2020-01-17 00:51:20 | [diff] [blame] | 907 | scoped_blocking_call->emplace(from_here,base::BlockingType::MAY_BLOCK); |
shess@chromium.org | 35f7e539 | 2012-07-27 19:54:50 | [diff] [blame] | 908 | } |
| 909 | |
shess | a62504d | 2016-11-07 19:26:12 | [diff] [blame] | 910 | // Internal helper for Does*Exist() functions. |
Md Hasibul Hasan | 52ffeca6 | 2024-03-26 18:23:18 | [diff] [blame] | 911 | boolDoesSchemaItemExist(std::string_view name, std::string_view type); |
michaeln@google.com | e2cadec8 | 2011-12-13 02:00:53 | [diff] [blame] | 912 | |
Victor Costan | bc4285f | 2021-09-20 21:29:28 | [diff] [blame] | 913 | // Used to implement the interface with sql::test::ScopedErrorExpecter. |
| 914 | staticScopedErrorExpecterCallback* current_expecter_cb_; |
shess@chromium.org | 4350e32 | 2013-06-18 22:18:10 | [diff] [blame] | 915 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 916 | // A StatementRef is a refcounted wrapper around a sqlite statement pointer. |
| 917 | // Refcounting allows us to give these statements out to sql::Statement |
| 918 | // objects while also optionally maintaining a cache of compiled statements |
| 919 | // by just keeping a refptr to these objects. |
| 920 | // |
| 921 | // A statement ref can be valid, in which case it can be used, or invalid to |
| 922 | // indicate that the statement hasn't been created yet, has an error, or has |
| 923 | // been destroyed. |
| 924 | // |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 925 | // The Database may revoke a StatementRef in some error cases, so callers |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 926 | // should always check validity before using. |
Victor Costan | e56cc68 | 2018-12-27 01:53:46 | [diff] [blame] | 927 | class COMPONENT_EXPORT(SQL)StatementRef |
| 928 | :publicbase::RefCounted<StatementRef>{ |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 929 | public: |
Victor Costan | 3b02cdf | 2018-07-18 00:39:56 | [diff] [blame] | 930 | REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); |
| 931 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 932 | // |database| is the sql::Database instance associated with |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 933 | // the statement, and is used for tracking outstanding statements |
Victor Costan | 106e5007 | 2021-07-17 00:04:49 | [diff] [blame] | 934 | // and for error handling. Set to nullptr for invalid refs. |
| 935 | // |stmt| is the actual statement, and should only be null |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 936 | // to create an invalid ref. |was_valid| indicates whether the |
Etienne Bergeron | 95a01c2a | 2019-02-26 21:32:50 | [diff] [blame] | 937 | // statement should be considered valid for diagnostic purposes. |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 938 | // |was_valid| can be true for a null |stmt| if the Database has |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 939 | // been forcibly closed by an error handler. |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 940 | StatementRef(Database* database, sqlite3_stmt* stmt,bool was_valid); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 941 | |
Victor Costan | 00c7643 | 2021-07-07 16:55:58 | [diff] [blame] | 942 | StatementRef(constStatementRef&)=delete; |
| 943 | StatementRef&operator=(constStatementRef&)=delete; |
Andrew Paseltiner | 7d512ddd | 2022-09-16 13:36:52 | [diff] [blame] | 944 | StatementRef(StatementRef&&)=delete; |
| 945 | StatementRef&operator=(StatementRef&&)=delete; |
Victor Costan | 00c7643 | 2021-07-07 16:55:58 | [diff] [blame] | 946 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 947 | // When true, the statement can be used. |
| 948 | bool is_valid()const{return!!stmt_;} |
| 949 | |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 950 | // When true, the statement is either currently valid, or was |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 951 | // previously valid but the database was forcibly closed. Used |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 952 | // for diagnostic checks. |
| 953 | bool was_valid()const{return was_valid_;} |
| 954 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 955 | // If we've not been linked to a database, this will be null. |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 956 | Database* database()const{return database_;} |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 957 | |
| 958 | // Returns the sqlite statement if any. If the statement is not active, |
Victor Costan | bd62311 | 2018-07-18 04:17:27 | [diff] [blame] | 959 | // this will return nullptr. |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 960 | sqlite3_stmt* stmt()const{return stmt_;} |
| 961 | |
Evan Stade | 9728e5a | 2025-06-05 18:51:27 | [diff] [blame] | 962 | // Assumes ownership of `blob`. |
| 963 | // |
| 964 | // To be called BEFORE the data in `blob` will be bound to a SQLite |
| 965 | // statement SQLite. SQLite assumes the pointer will remain valid until the |
| 966 | // statement is finalized or the parameter is unbound. |
| 967 | // |
| 968 | // A span pointing to the newly owned memory is returned --- this is the |
| 969 | // pointer that should be passed to sqlite3 functions. |
| 970 | base::span<constuint8_t>TakeBlobMemory( |
| 971 | int index, |
| 972 | scoped_refptr<base::RefCountedMemory> blob); |
| 973 | |
| 974 | // Releases memory passed by `TakeBlobMemory()`, if any. The caller should |
| 975 | // also tell SQLite to unbind or rebind the parameter (i.e. update the |
| 976 | // binding that was previously set with TakeBlobMemory's output). |
| 977 | voidClearBlobMemory(int index); |
| 978 | |
| 979 | // Resets the statement and, if `clear_bound_variables` is true, drops |
| 980 | // parameter bindings, including dropping `bound_blobs_`. |
| 981 | voidReset(bool clear_bound_variables); |
| 982 | |
Victor Costan | bd62311 | 2018-07-18 04:17:27 | [diff] [blame] | 983 | // Destroys the compiled statement and sets it to nullptr. The statement |
| 984 | // will no longer be active. |forced| is used to indicate if |
Andrew Paseltiner | d309fec | 2023-03-28 16:59:55 | [diff] [blame] | 985 | // orderly-shutdown checks should apply (see Database::RazeAndPoison()). |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 986 | voidClose(bool forced); |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 987 | |
Etienne Pierre-Doray | a71d7af | 2019-02-07 02:07:54 | [diff] [blame] | 988 | // Construct a ScopedBlockingCall to annotate IO calls, but only if |
Etienne Bergeron | e7681c7 | 2020-01-17 00:51:20 | [diff] [blame] | 989 | // database wasn't open in memory. ScopedBlockingCall uses |from_here| to |
| 990 | // declare its blocking execution scope (see https://www.crbug/934302). |
Etienne Pierre-Doray | a71d7af | 2019-02-07 02:07:54 | [diff] [blame] | 991 | voidInitScopedBlockingCall( |
Etienne Bergeron | e7681c7 | 2020-01-17 00:51:20 | [diff] [blame] | 992 | constbase::Location& from_here, |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 993 | std::optional<base::ScopedBlockingCall>* scoped_blocking_call)const{ |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 994 | if(database_) |
Etienne Bergeron | e7681c7 | 2020-01-17 00:51:20 | [diff] [blame] | 995 | database_->InitScopedBlockingCall(from_here, scoped_blocking_call); |
Victor Costan | c7e7f2e | 2018-07-18 20:07:55 | [diff] [blame] | 996 | } |
shess@chromium.org | 35f7e539 | 2012-07-27 19:54:50 | [diff] [blame] | 997 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 998 | private: |
jam@chromium.org | 877d55d | 2009-11-05 21:53:08 | [diff] [blame] | 999 | friendclassbase::RefCounted<StatementRef>; |
| 1000 | |
| 1001 | ~StatementRef(); |
| 1002 | |
Evan Stade | 9728e5a | 2025-06-05 18:51:27 | [diff] [blame] | 1003 | // Holds onto memory that is to be used by the statement. These blobs have |
| 1004 | // been bound with `SQLITE_STATIC`, see |
| 1005 | // https://www.sqlite.org/c3ref/bind_blob.html for docs. |
| 1006 | // Note that value pointer stability is important, and that's granted by |
| 1007 | // scoped_refptr. |
| 1008 | base::flat_map<int, scoped_refptr<base::RefCountedMemory>> bound_blobs_; |
| 1009 | |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 1010 | raw_ptr<Database> database_; |
| 1011 | raw_ptr<sqlite3_stmt> stmt_; |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 1012 | bool was_valid_; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1013 | }; |
| 1014 | friendclassStatementRef; |
| 1015 | |
| 1016 | // Executes a rollback statement, ignoring all transaction state. Used |
| 1017 | // internally in the transaction management code. |
| 1018 | voidDoRollback(); |
| 1019 | |
| 1020 | // Called by a StatementRef when it's being created or destroyed. See |
| 1021 | // open_statements_ below. |
| 1022 | voidStatementRefCreated(StatementRef*ref); |
| 1023 | voidStatementRefDeleted(StatementRef*ref); |
| 1024 | |
Victor Costan | b9faa62 | 2022-03-10 16:08:29 | [diff] [blame] | 1025 | // Used by sql:: internals to report a SQLite error related to this database. |
| 1026 | // |
| 1027 | // `sqlite_error_code` contains the error code reported by SQLite. Possible |
| 1028 | // values are documented at https://www.sqlite.org/rescode.html |
| 1029 | // |
| 1030 | // `statement` is non-null if the error is associated with a sql::Statement. |
| 1031 | // Otherwise, `sql_statement` will be a non-null string pointing to a |
| 1032 | // statically-allocated (valid for the entire duration of the process) buffer |
| 1033 | // pointing to either a SQL statement or a SQL comment (starting with "-- ") |
| 1034 | // pointing to a "sqlite3_" function name. |
Victor Costan | ab7a245 | 2022-03-21 23:06:08 | [diff] [blame] | 1035 | voidOnSqliteError(SqliteErrorCode sqlite_error_code, |
Victor Costan | 378d984 | 2022-03-10 22:08:25 | [diff] [blame] | 1036 | Statement* statement, |
| 1037 | constchar* sql_statement); |
cpu@chromium.org | faa604e | 2009-09-25 22:38:59 | [diff] [blame] | 1038 | |
Etienne Bergeron | c3475949 | 2025-06-16 15:45:17 | [diff] [blame] | 1039 | // Raze the database to the ground. This is the internal version called by |
| 1040 | // Raze(...). |
| 1041 | boolRazeInternal(); |
| 1042 | |
Victor Costan | edf48be | 2022-03-14 21:40:12 | [diff] [blame] | 1043 | // Like Execute(), but returns a SQLite result code. |
Victor Costan | 205b96dc | 2021-07-21 20:27:46 | [diff] [blame] | 1044 | // |
Victor Costan | ab7a245 | 2022-03-21 23:06:08 | [diff] [blame] | 1045 | // This method returns SqliteResultCode::kOk or a SQLite error code. In other |
| 1046 | // words, it never returns SqliteResultCode::{kDone, kRow}. |
Victor Costan | edf48be | 2022-03-14 21:40:12 | [diff] [blame] | 1047 | // |
| 1048 | // This method is only exposed to the Database implementation. Code that uses |
| 1049 | // sql::Database should not be concerned with SQLite result codes. |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 1050 | [[nodiscard]]SqliteResultCodeExecuteAndReturnResultCode( |
| 1051 | base::cstring_view sql); |
Victor Costan | 205b96dc | 2021-07-21 20:27:46 | [diff] [blame] | 1052 | |
shess@chromium.org | 5b96f377 | 2010-09-28 16:30:57 | [diff] [blame] | 1053 | // Like |Execute()|, but retries if the database is locked. |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 1054 | [[nodiscard]]boolExecuteWithTimeout(base::cstring_view sql, |
Daniel Cheng | 1ac0cad | 2022-01-14 00:19:53 | [diff] [blame] | 1055 | base::TimeDelta ms_timeout); |
shess@chromium.org | 5b96f377 | 2010-09-28 16:30:57 | [diff] [blame] | 1056 | |
Victor Costan | 106e5007 | 2021-07-17 00:04:49 | [diff] [blame] | 1057 | // Implementation helper for GetUniqueStatement() and GetCachedStatement(). |
Evan Stade | e63b834 | 2024-06-07 15:55:23 | [diff] [blame] | 1058 | scoped_refptr<StatementRef>GetStatementImpl(base::cstring_view sql, |
ssid | 583f55e | 2022-04-21 19:59:00 | [diff] [blame] | 1059 | bool is_readonly); |
shess@chromium.org | 2eec0a2 | 2012-07-24 01:59:58 | [diff] [blame] | 1060 | |
shess | 7dbd4dee | 2015-10-06 17:39:16 | [diff] [blame] | 1061 | // Release page-cache memory if memory-mapped I/O is enabled and the database |
| 1062 | // was changed. Passing true for |implicit_change_performed| allows |
| 1063 | // overriding the change detection for cases like DDL (CREATE, DROP, etc), |
| 1064 | // which do not participate in the total-rows-changed tracking. |
| 1065 | voidReleaseCacheMemoryIfNeeded(bool implicit_change_performed); |
| 1066 | |
shess | c8cd2a16 | 2015-10-22 20:30:46 | [diff] [blame] | 1067 | // Returns the results of sqlite3_db_filename(), which should match the path |
| 1068 | // passed to Open(). |
| 1069 | base::FilePathDbPath()const; |
| 1070 | |
shess | c8cd2a16 | 2015-10-22 20:30:46 | [diff] [blame] | 1071 | // Helper to collect diagnostic info for a corrupt database. |
| 1072 | std::stringCollectCorruptionInfo(); |
| 1073 | |
Tommy C. Li | 7803636c | 2022-07-27 21:47:22 | [diff] [blame] | 1074 | // Helper to collect diagnostic info for errors. `diagnostics` is an optional |
| 1075 | // out parameter. If `diagnostics` is defined, this method populates SOME of |
| 1076 | // its fields. Some of the fields are left unmodified for the caller. |
| 1077 | std::stringCollectErrorInfo(int sqlite_error_code, |
| 1078 | Statement* stmt, |
| 1079 | DatabaseDiagnostics* diagnostics)const; |
shess | c8cd2a16 | 2015-10-22 20:30:46 | [diff] [blame] | 1080 | |
Victor Costan | dc72e8d | 2022-03-14 18:14:51 | [diff] [blame] | 1081 | // The size of the memory mapping that SQLite should use for this database. |
shess | d90aeea8 | 2015-11-13 02:24:31 | [diff] [blame] | 1082 | // |
Victor Costan | dc72e8d | 2022-03-14 18:14:51 | [diff] [blame] | 1083 | // The return value follows the semantics of "PRAGMA mmap_size". In |
| 1084 | // particular, zero (0) means memory-mapping should be disabled, and the value |
| 1085 | // is capped by SQLITE_MAX_MMAP_SIZE. More details at |
| 1086 | // https://www.sqlite.org/pragma.html#pragma_mmap_size |
| 1087 | // |
| 1088 | // "Memory-mapped access" is usually shortened to "mmap", which is the name of |
| 1089 | // the POSIX system call used to implement. The same principles apply on |
| 1090 | // Windows, but its more-descriptive API names don't make for good shorthands. |
| 1091 | // |
| 1092 | // When mmap is enabled, SQLite attempts to use the memory-mapped area (by |
| 1093 | // calling xFetch() in the VFS file API) instead of requesting a database page |
| 1094 | // buffer from the pager and reading (via xRead() in the VFS API) into it. |
| 1095 | // When this works out, the database page cache ends up only storing pages |
| 1096 | // whose contents has been modified. More details at |
| 1097 | // https://sqlite.org/mmap.html |
| 1098 | // |
| 1099 | // I/O errors on memory-mapped files result in crashes in Chrome. POSIX |
| 1100 | // systems signal SIGSEGV or SIGBUS on I/O errors in mmap-ed files. Windows |
| 1101 | // raises the EXECUTE_IN_PAGE_ERROR strucuted exception in this case. Chrome |
| 1102 | // does not catch signals or structured exceptions. |
| 1103 | // |
| 1104 | // In order to avoid crashes, this method attempts to read the file using |
| 1105 | // regular I/O, and returns 0 (no mmap) if it encounters any error. |
| 1106 | size_tComputeMmapSizeForOpen(); |
shess | d90aeea8 | 2015-11-13 02:24:31 | [diff] [blame] | 1107 | |
Victor Costan | dc72e8d | 2022-03-14 18:14:51 | [diff] [blame] | 1108 | // Helpers for ComputeMmapSizeForOpen(). |
shess | a62504d | 2016-11-07 19:26:12 | [diff] [blame] | 1109 | boolGetMmapAltStatus(int64_t* status); |
| 1110 | boolSetMmapAltStatus(int64_t status); |
| 1111 | |
Victor Costan | dc72e8d | 2022-03-14 18:14:51 | [diff] [blame] | 1112 | // Returns a SQLite VFS interface pointer to the file storing database pages. |
| 1113 | // |
| 1114 | // Returns null if the database is not backed by a VFS file. This is always |
Evan Stade | 4c7d6b3 | 2024-03-12 16:50:27 | [diff] [blame] | 1115 | // the case for in-memory databases. |
Victor Costan | dc72e8d | 2022-03-14 18:14:51 | [diff] [blame] | 1116 | // |
| 1117 | // This method must only be called while the database is successfully opened. |
| 1118 | sqlite3_file*GetSqliteVfsFile(); |
| 1119 | |
Anthony Vallée-Dubois | 4b297791 | 2024-11-22 16:28:51 | [diff] [blame] | 1120 | // Records a histogram named `name_prefix` suffixed with this database's |
Etienne Bergeron | 98f446ed | 2025-01-24 16:16:22 | [diff] [blame] | 1121 | // histogram tag. For instance, `RecordTimingHistogram("Foo.", ...)` called on |
| 1122 | // a database with the tag "Bar" will record into "Foo.Bar". This function |
| 1123 | // chooses reasonable bucketing parameters for typical database operations |
| 1124 | // timing and reports in microseconds. |
Anthony Vallée-Dubois | 4b297791 | 2024-11-22 16:28:51 | [diff] [blame] | 1125 | voidRecordTimingHistogram(std::string_view name_prefix, |
| 1126 | base::TimeDelta timing)const; |
| 1127 | |
| 1128 | // Returns the name of the track in which to record this database's events |
| 1129 | // based on its histogram tag. |
| 1130 | perfetto::NamedTrackGetTracingNamedTrack()const; |
| 1131 | |
Victor Costan | 554f11e | 2022-03-16 17:00:09 | [diff] [blame] | 1132 | // Will eventually be checked on all methods. See https://crbug.com/1306694 |
| 1133 | SEQUENCE_CHECKER(sequence_checker_); |
| 1134 | |
Victor Costan | bd62311 | 2018-07-18 04:17:27 | [diff] [blame] | 1135 | // The actual sqlite database. Will be null before Init has been called or if |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1136 | // Init resulted in an error. |
Evan Stade | ae04e197 | 2024-02-01 17:35:53 | [diff] [blame] | 1137 | raw_ptr<sqlite3> db_=nullptr; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1138 | |
Etienne Bergeron | 5cada0b | 2025-01-22 15:45:01 | [diff] [blame] | 1139 | // Immutable options for the database. |
| 1140 | constDatabaseOptions options_; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1141 | |
Victor Costan | c7e7f2e | 2018-07-18 20:07:55 | [diff] [blame] | 1142 | // Holds references to all cached statements so they remain active. |
| 1143 | // |
| 1144 | // flat_map is appropriate here because the codebase has ~400 cached |
| 1145 | // statements, and each statement is at most one insertion in the map |
| 1146 | // throughout a process' lifetime. |
| 1147 | base::flat_map<StatementID, scoped_refptr<StatementRef>> statement_cache_; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1148 | |
| 1149 | // A list of all StatementRefs we've given out. Each ref must register with |
| 1150 | // us when it's created or destroyed. This allows us to potentially close |
| 1151 | // any open statements when we encounter an error. |
Arthur Sonzogni | 6839939 | 2024-07-09 20:36:56 | [diff] [blame] | 1152 | std::set<raw_ptr<StatementRef>> open_statements_; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1153 | |
Evan Stade | 416f46f1 | 2025-06-18 15:42:39 | [diff] [blame] | 1154 | // The number of blobs open for streaming, tracked for debugging purposes. |
| 1155 | size_t outstanding_blob_count_=0; |
| 1156 | |
| 1157 | // When non-zero, indicates that `this` is inside `OnSqliteError()`. |
| 1158 | size_t handling_error_nesting_=0; |
| 1159 | |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1160 | // Number of currently-nested transactions. |
Shubham Aggarwal | e2d6b60d | 2020-10-22 04:41:48 | [diff] [blame] | 1161 | int transaction_nesting_=0; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1162 | |
| 1163 | // True if any of the currently nested transactions have been rolled back. |
| 1164 | // When we get to the outermost transaction, this will determine if we do |
| 1165 | // a rollback instead of a commit. |
Shubham Aggarwal | e2d6b60d | 2020-10-22 04:41:48 | [diff] [blame] | 1166 | bool needs_rollback_=false; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1167 | |
shess@chromium.org | 35f7e539 | 2012-07-27 19:54:50 | [diff] [blame] | 1168 | // True if database is open with OpenInMemory(), False if database is open |
| 1169 | // with Open(). |
Shubham Aggarwal | e2d6b60d | 2020-10-22 04:41:48 | [diff] [blame] | 1170 | bool in_memory_=false; |
shess@chromium.org | 35f7e539 | 2012-07-27 19:54:50 | [diff] [blame] | 1171 | |
Andrew Paseltiner | d309fec | 2023-03-28 16:59:55 | [diff] [blame] | 1172 | // |true| if the Database was closed using RazeAndPoison(). Used |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 1173 | // to enable diagnostics to distinguish calls to never-opened |
| 1174 | // databases (incorrect use of the API) from calls to once-valid |
| 1175 | // databases. |
Shubham Aggarwal | e2d6b60d | 2020-10-22 04:41:48 | [diff] [blame] | 1176 | bool poisoned_=false; |
shess@chromium.org | 41a97c81 | 2013-02-07 02:35:38 | [diff] [blame] | 1177 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 1178 | // |true| if SQLite memory-mapped I/O is not desired for this database. |
shess | 7dbd4dee | 2015-10-06 17:39:16 | [diff] [blame] | 1179 | bool mmap_disabled_; |
| 1180 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 1181 | // |true| if SQLite memory-mapped I/O was enabled for this database. |
shess | 7dbd4dee | 2015-10-06 17:39:16 | [diff] [blame] | 1182 | // Used by ReleaseCacheMemoryIfNeeded(). |
Shubham Aggarwal | e2d6b60d | 2020-10-22 04:41:48 | [diff] [blame] | 1183 | bool mmap_enabled_=false; |
shess | 7dbd4dee | 2015-10-06 17:39:16 | [diff] [blame] | 1184 | |
| 1185 | // Used by ReleaseCacheMemoryIfNeeded() to track if new changes have happened |
| 1186 | // since memory was last released. |
Victor Costan | 3657e04 | 2022-03-12 18:47:30 | [diff] [blame] | 1187 | int64_t total_changes_at_last_release_=0; |
shess | 7dbd4dee | 2015-10-06 17:39:16 | [diff] [blame] | 1188 | |
Victor Costan | ce406da2 | 2021-09-20 21:01:38 | [diff] [blame] | 1189 | // Called when a SQLite error occurs. |
| 1190 | // |
| 1191 | // This callback may be null, in which case errors are handled using a default |
| 1192 | // behavior. |
| 1193 | // |
| 1194 | // This callback must never be exposed outside this Database instance. This is |
| 1195 | // a straight-forward way to guarantee that this callback will not be called |
| 1196 | // after the Database instance goes out of scope. set_error_callback() makes |
| 1197 | // this guarantee. |
shess@chromium.org | c3881b37 | 2013-05-17 08:39:46 | [diff] [blame] | 1198 | ErrorCallback error_callback_; |
| 1199 | |
Victor Costan | 90dae26 | 2021-06-01 21:01:08 | [diff] [blame] | 1200 | // Developer-friendly database ID used in logging output and memory dumps. |
shess@chromium.org | 210ce0af | 2013-05-15 09:10:39 | [diff] [blame] | 1201 | std::string histogram_tag_; |
shess@chromium.org | c088e3a3 | 2013-01-03 23:59:14 | [diff] [blame] | 1202 | |
Anthony Vallée-Dubois | 4b297791 | 2024-11-22 16:28:51 | [diff] [blame] | 1203 | // Persist the track name as a member since perfetto needs the original string |
| 1204 | // for the name to remain alive (without taking ownership of it). |
| 1205 | std::string tracing_track_name_; |
| 1206 | |
ssid | 3be5b1ec | 2016-01-13 14:21:57 | [diff] [blame] | 1207 | // Stores the dump provider object when db is open. |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 1208 | std::unique_ptr<DatabaseMemoryDumpProvider> memory_dump_provider_; |
Dan McArdle | 49be9b0 | 2024-02-06 23:15:33 | [diff] [blame] | 1209 | |
Anthony Vallée-Dubois | de3720258 | 2024-12-04 18:52:30 | [diff] [blame] | 1210 | // If set, this callback will be invoked when an sqlite error is triggered |
| 1211 | // during `OpenInternal` or `Execute`s triggered from `Open`. |
| 1212 | base::RepeatingCallback<void(SqliteResultCode)> |
| 1213 | open_error_reporting_callback_; |
| 1214 | |
Evan Stade | 416f46f1 | 2025-06-18 15:42:39 | [diff] [blame] | 1215 | // Weak factory for tracking lifetime of `this` (as opposed to |
| 1216 | // `weak_factory_`, which will also invalidate pointers if the database is |
| 1217 | // closed). |
| 1218 | base::WeakPtrFactory<Database> weak_factory_lifetime_tracker_{this}; |
| 1219 | |
Dan McArdle | 49be9b0 | 2024-02-06 23:15:33 | [diff] [blame] | 1220 | // Vends WeakPtr<Database> for internal scoping helpers. |
| 1221 | base::WeakPtrFactory<Database> weak_factory_{this}; |
brettw@chromium.org | e5ffd0e4 | 2009-09-11 21:30:56 | [diff] [blame] | 1222 | }; |
| 1223 | |
| 1224 | }// namespace sql |
| 1225 | |
Victor Costan | cfbfa60 | 2018-08-01 23:24:46 | [diff] [blame] | 1226 | #endif// SQL_DATABASE_H_ |