[go: nahoru, domu]

blob: 4999388d9c60675db47b07dfb2fd87a1d90ec235 [file] [log] [blame]
Avi Drissman69b874f2022-09-15 19:11:141// Copyright 2012 The Chromium Authors
pkotwicz@chromium.org0d04ede2012-10-18 04:31:532// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "sql/error_delegate_util.h"
6
Victor Costan293c8c62022-03-14 16:31:107#include <ostream> // Needed to compile NOTREACHED() with operator <<.
8#include <string>
9
10#include "base/files/file_path.h"
11#include "base/notreached.h"
pkotwicz@chromium.org0d04ede2012-10-18 04:31:5312#include "third_party/sqlite/sqlite3.h"
13
14namespace sql {
15
Victor Costan293c8c62022-03-14 16:31:1016bool IsErrorCatastrophic(int sqlite_error_code) {
17 // SQLite result codes are documented at https://www.sqlite.org/rescode.html
18 int primary_error_code = sqlite_error_code & 0xff;
pkotwicz@chromium.org0d04ede2012-10-18 04:31:5319
Victor Costan293c8c62022-03-14 16:31:1020 // Within each group, error codes are sorted by their numerical values. This
21 // matches the order used by the SQLite documentation describing them.
22 switch (primary_error_code) {
23 // Group of error codes that should never be returned by SQLite.
24 //
25 // If we do get these, our database schema / query pattern / data managed to
26 // trigger a bug in SQLite. In development, we DCHECK to flag this SQLite
27 // bug. In production, we [[fallback]] to corruption handling, because the
28 // bug may be persistent, and corruption recovery will get the user unstuck.
29 case SQLITE_INTERNAL: // Bug in SQLite.
30 case SQLITE_EMPTY: // Marked for SQLite internal use.
31 case SQLITE_FORMAT: // Not currently used, according to SQLite docs.
32 case SQLITE_NOTICE: // Only used as an argument to sqlite3_log().
33 case SQLITE_WARNING: // Only used as an argument to sqlite3_log().
34 NOTREACHED() << "SQLite returned result code marked for internal use: "
35 << sqlite_error_code;
36 [[fallthrough]];
37
38 // Group of error codes that may only be returned by SQLite (given Chrome's
39 // usage patterns) if a database is corrupted. DCHECK would not be
40 // appropriate, since these can occur in production. Silently [[fallback]]
41 // to corruption handling.
42 case SQLITE_ERROR:
43 // Generic/fallback error code.
44 //
Tommy C. Li8ee3d2632022-11-05 00:30:0145 // In production, database corruption leads our SQL statements being
46 // flagged as invalid. For example, a SQL statement may reference a table
47 // or column whose name got corrupted.
Victor Costan293c8c62022-03-14 16:31:1048 //
Tommy C. Li8ee3d2632022-11-05 00:30:0149 // In development, this error code shows up most often when passing
50 // invalid SQL statements to SQLite. We have DCHECKs in sql::Statement and
51 // sql::Database::Execute() that catch obvious SQL syntax errors. We can't
52 // DCHECK when a SQL statement uses incorrect table/index/row names,
53 // because that can legitimately happen in production, due to corruption.
Tommy C. Li596190c2022-06-30 19:55:3454 //
Tommy C. Li8ee3d2632022-11-05 00:30:0155 // In 2022 we considered these errors as non-catastrophic, and we didn't
56 // find ANY invalid SQL statements, and only found failed transactions
57 // and schemas that didn't match the reported schema version, which both
58 // suggest corruption. See https://crbug.com/1321483 for context.
59 [[fallthrough]];
Victor Costan293c8c62022-03-14 16:31:1060 case SQLITE_PERM:
61 // Failed to get the requested access mode for a newly created database.
62 // The database was just created, so error recovery will not cause data
63 // loss. Error recovery steps, such as re-creating database files, may
64 // fix the permission problems.
65 [[fallthrough]];
pkotwicz@chromium.org0d04ede2012-10-18 04:31:5366 case SQLITE_CORRUPT:
Victor Costan293c8c62022-03-14 16:31:1067 // Some form of database corruption was detected. The sql::Recovery code
68 // may be able to recover some of the data.
69 [[fallthrough]];
70 case SQLITE_CANTOPEN:
71 // Failed to open the database, for a variety of reasons. All the reasons
72 // come down to some form of corruption. Here are some known reasons:
73 // * One of the file names (database, journal, WAL, etc.) points to a
74 // directory, not a file. This indicates filesystem corruption. Most
75 // likely, some app messed with the user's Chrome file. It's also
76 // possible that the inode was corrupted and the is_dir bit flipped.
77 // * One of the file names is a symlink, and SQLite was instructed not to
78 // follow symlinks. This should not occur in Chrome, we let SQLite use
79 // its default symlink handling.
80 // * The WAL file has a format version that SQLite can't understand. This
81 // should not occur in Chrome, as we don't use WAL yet.
82 [[fallthrough]];
83 case SQLITE_MISMATCH:
84 // SQLite was forced to perform an operation that involves incompatible
85 // data types. An example is attempting to store a non-integer value in a
86 // ROWID primary key.
87 //
88 // In production, database corruption can lead to this. For example, it's
89 // possible that a schema is corrupted in such a way that the ROWID
90 // primary key column's name is swapped with another column's name.
91 [[fallthrough]];
92 case SQLITE_NOLFS:
93 // The database failed to grow past the filesystem size limit. This is
94 // unlikely to happen in Chrome, but it is theoretically possible.
95 [[fallthrough]];
pkotwicz@chromium.org0d04ede2012-10-18 04:31:5396 case SQLITE_NOTADB:
Victor Costan293c8c62022-03-14 16:31:1097 // The database header is corrupted. The sql::Recovery code will not be
98 // able to recovery any data, as SQLite will refuse to open the database.
pkotwicz@chromium.org0d04ede2012-10-18 04:31:5399 return true;
100
Victor Costan293c8c62022-03-14 16:31:10101 // Group of result codes that are not error codes. These should never make
102 // it to error handling code. In development, we DCHECK to flag this Chrome
103 // bug. In production, we hope this is a transient error, such as a race
104 // condition.
105 case SQLITE_OK: // Most used success code.
106 case SQLITE_ROW: // The statement produced a row of output.
107 case SQLITE_DONE: // A step has completed in a multi-step operation.
108 NOTREACHED() << "Called with non-error result code " << sqlite_error_code;
109 [[fallthrough]];
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53110
Victor Costan293c8c62022-03-14 16:31:10111 // Group of error codes that should not be returned by SQLite given Chrome's
112 // usage patterns, even if the database gets corrupted. In development, we
113 // DCHECK to flag this Chrome bug. In production, we hope the errors have
114 // transient causes, such as race conditions.
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53115 case SQLITE_LOCKED:
Victor Costan293c8c62022-03-14 16:31:10116 // Conflict between two concurrently executing statements in the same
117 // database connection.
118 //
119 // In theory, SQLITE_LOCKED could also signal a conflict between different
120 // connections (in the same process) sharing a page cache, but Chrome only
121 // uses private page caches.
122 NOTREACHED() << "Conflict between concurrently executing SQL statements";
123 [[fallthrough]];
124 case SQLITE_NOMEM:
125 // Out of memory. This is most likely a transient error.
126 //
127 // There's a small chance that the error is caused by trying to exchange
128 // too much data with SQLite. Most such errors result in SQLITE_TOOBIG.
129 NOTREACHED() << "SQLite reported out-of-memory: " << sqlite_error_code;
130 [[fallthrough]];
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53131 case SQLITE_INTERRUPT:
Victor Costan293c8c62022-03-14 16:31:10132 // Chrome features don't use sqlite3_interrupt().
133 NOTREACHED() << "SQLite returned INTERRUPT code: " << sqlite_error_code;
134 [[fallthrough]];
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53135 case SQLITE_NOTFOUND:
Victor Costan293c8c62022-03-14 16:31:10136 // Unknown opcode in sqlite3_file_control(). Chrome's features only use a
137 // few built-in opcodes.
138 NOTREACHED() << "SQLite returned NOTFOUND code: " << sqlite_error_code;
139 [[fallthrough]];
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53140 case SQLITE_MISUSE:
Victor Costan293c8c62022-03-14 16:31:10141 // SQLite API misuse, such as trying to use a prepared statement after it
142 // was finalized. In development, we DCHECK to flag this Chrome bug. In
143 // production, we hope this is a race condition, and therefore transient.
144 NOTREACHED() << "SQLite returned MISUSE code: " << sqlite_error_code;
145 [[fallthrough]];
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53146 case SQLITE_AUTH:
Victor Costan293c8c62022-03-14 16:31:10147 // Chrome features don't install an authorizer callback. Only WebSQL does.
148 NOTREACHED() << "SQLite returned AUTH code: " << sqlite_error_code;
149 [[fallthrough]];
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53150 case SQLITE_RANGE:
Victor Costan293c8c62022-03-14 16:31:10151 // Chrome uses DCHECKs to ensure the validity of column indexes passed to
152 // sqlite3_bind() and sqlite3_column().
153 NOTREACHED() << "SQLite returned RANGE code: " << sqlite_error_code;
154 [[fallthrough]];
155
156 // Group of error codes that should may be returned by SQLite given Chrome's
157 // usage patterns, even without database corruption. In development, we
158 // DCHECK to flag this Chrome bug. In production, we hope the errors have
159 // transient causes, such as race conditions.
160 case SQLITE_ABORT:
161 // SQLITE_ABORT may be returned when a ROLLBACK statement is executed
162 // concurrently with a pending read or write, and Chrome features are
163 // allowed to execute concurrent statements in the same transaction, under
164 // some conditions.
165 //
166 // It may be worth noting that Chrome features don't use callback routines
167 // that may abort SQL statements, such as passing a callback to
168 // sqlite3_exec().
169 [[fallthrough]];
170 case SQLITE_BUSY:
171 // Failed to grab a lock on the database. Another database connection
172 // (most likely in another process) is holding the database lock. This
173 // should not be a problem for exclusive databases, which are strongly
174 // recommended for Chrome features.
175 [[fallthrough]];
176 case SQLITE_READONLY:
177 // SQLite either failed to write to the database file or its associated
178 // files (journal, WAL, etc.), or considers it unsafe to do so.
179 //
180 // Most error codes (SQLITE_READONLY_DIRECTORY, SQLITE_READONLY_RECOVERY,
181 // SQLITE_READONLY_ROLLBACK, SQLITE_READONLY_CANTLOCK) mean that SQLite
182 // failed to write to some file, or to create a file (which entails
183 // writing to the directory containing the database).
184 //
185 // SQLITE_READONLY_CANTLOCK should never happen in Chrome, because we will
186 // only allow enabling WAL on databases that use exclusive locking.
187 //
188 // Unlike all other codes, SQLITE_READONLY_DBMOVED signals that a file was
189 // deleted or renamed. It is returned when SQLite realizes that the
190 // database file was moved or unlinked from the filesystem after it was
191 // opened, so the associated files (journal, WAL, etc.) would not be found
192 // by another SQLite instance in the event of a crash. This was observed
193 // on the iOS try bots.
194 [[fallthrough]];
195 case SQLITE_IOERR:
196 // Catch-all for many errors reported by the VFS. Some of the errors
197 // indicate media failure (SQLITE_IOERR_READ), while others indicate
198 // transient problems (SQLITE_IOERR_LOCK). In the future, we may invest in
199 // distinguishing between them. For now, since all the codes are bundled
200 // up, we must assume that the error is transient.
201 [[fallthrough]];
202 case SQLITE_FULL:
203 // The disk is full. This is definitely a transient error, and does not
204 // indicate any database corruption. While it's true that the user will be
205 // stuck in this state until some action is taken, we're unlikely to help
206 // the user if we run our recovery code or delete our databases.
207 [[fallthrough]];
208 case SQLITE_PROTOCOL:
Victor Costanbc4ad0a52022-03-14 22:18:44209 // Gave up while attempting to grab a lock on a WAL database at the
210 // beginning of a transaction. In theory, this should not be a problem in
211 // Chrome, because we'll only allow enabling WAL on databases with
212 // exclusive locking. However, other software on the user's system may
213 // lock our databases in a way that triggers this error.
Victor Costan293c8c62022-03-14 16:31:10214 [[fallthrough]];
215 case SQLITE_SCHEMA:
216 // The database schema was changed between the time when a prepared
217 // statement was compiled, and when it was executing.
218 //
219 // This can happen in production. Databases that don't use exclusive
220 // locking (recommended but not yet required for Chrome features) may be
221 // changed from another process via legitimate use of SQLite APIs.
222 // Databases that do use exclusive locks may still be mutated on-disk, on
223 // operating systems where exclusive locks are only enforced via advisory
224 // locking.
225 //
226 // When we mandate exclusive locks for all features in Chrome, we may
227 // classify this error as database corruption, because it is an indicator
228 // that another process is interfering with Chrome's schemas.
229 [[fallthrough]];
230 case SQLITE_TOOBIG:
231 // SQLite encountered a string or blob whose length exceeds
232 // SQLITE_MAX_LENGTH, or it was asked to execute a SQL statement whose
233 // length exceeds SQLITE_MAX_SQL_LENGTH or SQLITE_LIMIT_SQL_LENGTH.
234 //
235 // A corrupted database could cause this in the following ways:
236 // * SQLite could encounter an overly large string or blob because its
237 // size field got corrupted.
238 // * SQLite could attempt to execute an overly large SQL statement while
239 // operating on a corrupted schema. (Some of SQLite's DDL statements
240 // involve executing SQL that includes schema content.)
241 //
242 // However, this could also occur due to a Chrome bug where we ask SQLite
243 // to bind an overly large string or blob. So, we currently don't classify
244 // this as definitely induced by corruption.
245 [[fallthrough]];
246 case SQLITE_CONSTRAINT:
247 // This can happen in production, when executing SQL statements with the
248 // semantics of "create a record if it doesn't exist, otherwise do
249 // nothing".
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53250 return false;
251 }
Victor Costan293c8c62022-03-14 16:31:10252
253 NOTREACHED() << "SQLite returned unknown result code: " << sqlite_error_code;
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53254 return false;
255}
256
afakhry7c9abe72016-08-05 17:33:19257std::string GetCorruptFileDiagnosticsInfo(
258 const base::FilePath& corrupted_file_path) {
259 std::string corrupted_file_info("Corrupted file: ");
260 corrupted_file_info +=
261 corrupted_file_path.DirName().BaseName().AsUTF8Unsafe() + "/" +
262 corrupted_file_path.BaseName().AsUTF8Unsafe() + "\n";
263 return corrupted_file_info;
264}
265
pkotwicz@chromium.org0d04ede2012-10-18 04:31:53266} // namespace sql