sqlite_result_code.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "sql/sqlite_result_code.h"
  5. #include <ostream> // Needed to compile NOTREACHED() with operator <<.
  6. #include <set>
  7. #include <utility>
  8. #include "base/check_op.h"
  9. #include "base/metrics/histogram_functions.h"
  10. #include "base/notreached.h"
  11. #include "base/ranges/algorithm.h"
  12. #include "base/strings/string_piece.h"
  13. #include "sql/sqlite_result_code_values.h"
  14. #include "third_party/sqlite/sqlite3.h"
  15. namespace sql {
  16. namespace {
  17. // The highly packed representation minimizes binary size and memory usage.
  18. struct SqliteResultCodeMappingEntry {
  19. unsigned result_code : 16;
  20. unsigned logged_code : 8;
  21. // The remaining bits will be used to encode the result values of helpers that
  22. // indicate corruption handling.
  23. };
  24. constexpr SqliteResultCodeMappingEntry kResultCodeMapping[] = {
  25. // Entries are ordered by SQLite result code value. This should match the
  26. // ordering in https://www.sqlite.org/rescode.html.
  27. {SQLITE_OK, static_cast<int>(SqliteLoggedResultCode::kNoError)},
  28. {SQLITE_ERROR, static_cast<int>(SqliteLoggedResultCode::kGeneric)},
  29. {SQLITE_INTERNAL, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  30. {SQLITE_PERM, static_cast<int>(SqliteLoggedResultCode::kPermission)},
  31. {SQLITE_ABORT, static_cast<int>(SqliteLoggedResultCode::kAbort)},
  32. {SQLITE_BUSY, static_cast<int>(SqliteLoggedResultCode::kBusy)},
  33. // Chrome features shouldn't execute conflicting statements concurrently.
  34. {SQLITE_LOCKED, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  35. // Chrome should crash on OOM.
  36. {SQLITE_NOMEM, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  37. {SQLITE_READONLY, static_cast<int>(SqliteLoggedResultCode::kReadOnly)},
  38. // Chrome doesn't use sqlite3_interrupt().
  39. {SQLITE_INTERRUPT, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  40. {SQLITE_IOERR, static_cast<int>(SqliteLoggedResultCode::kIo)},
  41. {SQLITE_CORRUPT, static_cast<int>(SqliteLoggedResultCode::kCorrupt)},
  42. // Chrome only passes a few known-good opcodes to sqlite3_file_control().
  43. {SQLITE_NOTFOUND, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  44. {SQLITE_FULL, static_cast<int>(SqliteLoggedResultCode::kFullDisk)},
  45. {SQLITE_CANTOPEN, static_cast<int>(SqliteLoggedResultCode::kCantOpen)},
  46. {SQLITE_PROTOCOL,
  47. static_cast<int>(SqliteLoggedResultCode::kLockingProtocol)},
  48. {SQLITE_EMPTY, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  49. {SQLITE_SCHEMA, static_cast<int>(SqliteLoggedResultCode::kSchemaChanged)},
  50. {SQLITE_TOOBIG, static_cast<int>(SqliteLoggedResultCode::kTooBig)},
  51. {SQLITE_CONSTRAINT, static_cast<int>(SqliteLoggedResultCode::kConstraint)},
  52. {SQLITE_MISMATCH, static_cast<int>(SqliteLoggedResultCode::kTypeMismatch)},
  53. // Chrome should not misuse SQLite's API.
  54. {SQLITE_MISUSE, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  55. {SQLITE_NOLFS,
  56. static_cast<int>(SqliteLoggedResultCode::kNoLargeFileSupport)},
  57. // Chrome does not set an authorizer callback.
  58. {SQLITE_AUTH, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  59. {SQLITE_FORMAT, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  60. // Chrome should not use invalid column indexes in sqlite3_{bind,column}*().
  61. {SQLITE_RANGE, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  62. {SQLITE_NOTADB, static_cast<int>(SqliteLoggedResultCode::kNotADatabase)},
  63. {SQLITE_NOTICE, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  64. {SQLITE_WARNING, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  65. {SQLITE_ROW, static_cast<int>(SqliteLoggedResultCode::kNoError)},
  66. {SQLITE_DONE, static_cast<int>(SqliteLoggedResultCode::kNoError)},
  67. {SQLITE_OK_LOAD_PERMANENTLY,
  68. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  69. // Chrome should not use collating sequence names in SQL statements.
  70. {SQLITE_ERROR_MISSING_COLLSEQ,
  71. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  72. {SQLITE_BUSY_RECOVERY,
  73. static_cast<int>(SqliteLoggedResultCode::kBusyRecovery)},
  74. // Chrome does not use a shared page cache.
  75. {SQLITE_LOCKED_SHAREDCACHE,
  76. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  77. {SQLITE_READONLY_RECOVERY,
  78. static_cast<int>(SqliteLoggedResultCode::kReadOnlyRecovery)},
  79. {SQLITE_IOERR_READ, static_cast<int>(SqliteLoggedResultCode::kIoRead)},
  80. // Chrome does not use a virtual table that signals corruption. We only use
  81. // a
  82. // virtual table code for recovery. That code does not use this error.
  83. {SQLITE_CORRUPT_VTAB,
  84. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  85. {SQLITE_CANTOPEN_NOTEMPDIR,
  86. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  87. {SQLITE_CONSTRAINT_CHECK,
  88. static_cast<int>(SqliteLoggedResultCode::kConstraintCheck)},
  89. // Chrome does not set an authorizer callback.
  90. {SQLITE_AUTH_USER, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  91. {SQLITE_NOTICE_RECOVER_WAL,
  92. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  93. {SQLITE_WARNING_AUTOINDEX,
  94. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  95. {SQLITE_ERROR_RETRY,
  96. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  97. {SQLITE_ABORT_ROLLBACK,
  98. static_cast<int>(SqliteLoggedResultCode::kAbortRollback)},
  99. {SQLITE_BUSY_SNAPSHOT,
  100. static_cast<int>(SqliteLoggedResultCode::kBusySnapshot)},
  101. // Chrome does not use a virtual table that signals conflicts. We only use a
  102. // virtual table code for recovery. That code does not use this error.
  103. {SQLITE_LOCKED_VTAB,
  104. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  105. {SQLITE_READONLY_CANTLOCK,
  106. static_cast<int>(SqliteLoggedResultCode::kReadOnlyCantLock)},
  107. {SQLITE_IOERR_SHORT_READ,
  108. static_cast<int>(SqliteLoggedResultCode::kIoShortRead)},
  109. {SQLITE_CORRUPT_SEQUENCE,
  110. static_cast<int>(SqliteLoggedResultCode::kCorruptSequence)},
  111. {SQLITE_CANTOPEN_ISDIR,
  112. static_cast<int>(SqliteLoggedResultCode::kCantOpenIsDir)},
  113. // Chrome does not use commit hook callbacks.
  114. {SQLITE_CONSTRAINT_COMMITHOOK,
  115. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  116. {SQLITE_NOTICE_RECOVER_ROLLBACK,
  117. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  118. // Chrome does not use sqlite3_snapshot_open().
  119. {SQLITE_ERROR_SNAPSHOT,
  120. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  121. #ifdef SQLITE_ENABLE_SNAPSHOT
  122. #error "This code assumes that Chrome does not use sqlite3_snapshot_open()"
  123. #endif
  124. // Chrome does not use blocking Posix advisory file lock requests.
  125. {SQLITE_BUSY_TIMEOUT,
  126. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  127. #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  128. #error "This code assumes that Chrome does not use
  129. #endif
  130. {SQLITE_READONLY_ROLLBACK,
  131. static_cast<int>(SqliteLoggedResultCode::kReadOnlyRollback)},
  132. {SQLITE_IOERR_WRITE, static_cast<int>(SqliteLoggedResultCode::kIoWrite)},
  133. {SQLITE_CORRUPT_INDEX,
  134. static_cast<int>(SqliteLoggedResultCode::kCorruptIndex)},
  135. // Chrome should always pass full paths to SQLite.
  136. {SQLITE_CANTOPEN_FULLPATH,
  137. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  138. {SQLITE_CONSTRAINT_FOREIGNKEY,
  139. static_cast<int>(SqliteLoggedResultCode::kConstraintForeignKey)},
  140. {SQLITE_READONLY_DBMOVED,
  141. static_cast<int>(SqliteLoggedResultCode::kReadOnlyDbMoved)},
  142. {SQLITE_IOERR_FSYNC, static_cast<int>(SqliteLoggedResultCode::kIoFsync)},
  143. // Chrome does not support Cygwin and does not use its VFS.
  144. {SQLITE_CANTOPEN_CONVPATH,
  145. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  146. // Chrome does not use extension functions.
  147. {SQLITE_CONSTRAINT_FUNCTION,
  148. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  149. {SQLITE_READONLY_CANTINIT,
  150. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  151. {SQLITE_IOERR_DIR_FSYNC,
  152. static_cast<int>(SqliteLoggedResultCode::kIoDirFsync)},
  153. {SQLITE_CANTOPEN_DIRTYWAL,
  154. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  155. {SQLITE_CONSTRAINT_NOTNULL,
  156. static_cast<int>(SqliteLoggedResultCode::kConstraintNotNull)},
  157. {SQLITE_READONLY_DIRECTORY,
  158. static_cast<int>(SqliteLoggedResultCode::kReadOnlyDirectory)},
  159. {SQLITE_IOERR_TRUNCATE,
  160. static_cast<int>(SqliteLoggedResultCode::kIoTruncate)},
  161. // Chrome does not use the SQLITE_OPEN_NOFOLLOW flag.
  162. {SQLITE_CANTOPEN_SYMLINK,
  163. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  164. {SQLITE_CONSTRAINT_PRIMARYKEY,
  165. static_cast<int>(SqliteLoggedResultCode::kConstraintPrimaryKey)},
  166. {SQLITE_IOERR_FSTAT, static_cast<int>(SqliteLoggedResultCode::kIoFstat)},
  167. // Chrome unconditionally disables database triggers via
  168. // sqlite3_db_config(SQLITE_DBCONFIG_ENABLE_TRIGGER).
  169. {SQLITE_CONSTRAINT_TRIGGER,
  170. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  171. {SQLITE_IOERR_UNLOCK, static_cast<int>(SqliteLoggedResultCode::kIoUnlock)},
  172. {SQLITE_CONSTRAINT_UNIQUE,
  173. static_cast<int>(SqliteLoggedResultCode::kConstraintUnique)},
  174. {SQLITE_IOERR_RDLOCK,
  175. static_cast<int>(SqliteLoggedResultCode::kIoReadLock)},
  176. // Chrome does not use a virtual table that signals constraints. We only use
  177. // a virtual table code for recovery. That code does not use this error.
  178. {SQLITE_CONSTRAINT_VTAB,
  179. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  180. {SQLITE_IOERR_DELETE, static_cast<int>(SqliteLoggedResultCode::kIoDelete)},
  181. {SQLITE_CONSTRAINT_ROWID,
  182. static_cast<int>(SqliteLoggedResultCode::kConstraintRowId)},
  183. {SQLITE_IOERR_BLOCKED,
  184. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  185. // Chrome unconditionally disables database triggers via
  186. // sqlite3_db_config(SQLITE_DBCONFIG_ENABLE_TRIGGER).
  187. {SQLITE_CONSTRAINT_PINNED,
  188. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  189. // The SQLite docus claim that this error code is "normally" converted to
  190. // SQLITE_NOMEM. This doesn't seem 100% categorical, so we're flagging this
  191. // as "unused in Chrome" per the same rationale as SQLITE_NOMEM.
  192. {SQLITE_IOERR_NOMEM,
  193. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  194. {SQLITE_CONSTRAINT_DATATYPE,
  195. static_cast<int>(SqliteLoggedResultCode::kConstraintDataType)},
  196. {SQLITE_IOERR_ACCESS, static_cast<int>(SqliteLoggedResultCode::kIoAccess)},
  197. {SQLITE_IOERR_CHECKRESERVEDLOCK,
  198. static_cast<int>(SqliteLoggedResultCode::kIoCheckReservedLock)},
  199. {SQLITE_IOERR_LOCK, static_cast<int>(SqliteLoggedResultCode::kIoLock)},
  200. {SQLITE_IOERR_CLOSE, static_cast<int>(SqliteLoggedResultCode::kIoClose)},
  201. {SQLITE_IOERR_DIR_CLOSE,
  202. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  203. // Chrome will only allow enabling WAL on databases with exclusive locking.
  204. {SQLITE_IOERR_SHMOPEN,
  205. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  206. // Chrome will only allow enabling WAL on databases with exclusive locking.
  207. {SQLITE_IOERR_SHMSIZE,
  208. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  209. {SQLITE_IOERR_SHMLOCK,
  210. static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
  211. // Chrome will only allow enabling WAL on databases with exclusive locking.
  212. {SQLITE_IOERR_SHMMAP,
  213. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  214. {SQLITE_IOERR_SEEK, static_cast<int>(SqliteLoggedResultCode::kIoSeek)},
  215. {SQLITE_IOERR_DELETE_NOENT,
  216. static_cast<int>(SqliteLoggedResultCode::kIoDeleteNoEntry)},
  217. {SQLITE_IOERR_MMAP,
  218. static_cast<int>(SqliteLoggedResultCode::kIoMemoryMapping)},
  219. {SQLITE_IOERR_GETTEMPPATH,
  220. static_cast<int>(SqliteLoggedResultCode::kIoGetTemporaryPath)},
  221. // Chrome does not support Cygwin and does not use its VFS.
  222. {SQLITE_IOERR_CONVPATH,
  223. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  224. // Chrome does not use SQLite extensions.
  225. {SQLITE_IOERR_VNODE,
  226. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  227. // Chrome does not use SQLite extensions.
  228. {SQLITE_IOERR_AUTH,
  229. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  230. {SQLITE_IOERR_BEGIN_ATOMIC,
  231. static_cast<int>(SqliteLoggedResultCode::kIoBeginAtomic)},
  232. {SQLITE_IOERR_COMMIT_ATOMIC,
  233. static_cast<int>(SqliteLoggedResultCode::kIoCommitAtomic)},
  234. {SQLITE_IOERR_ROLLBACK_ATOMIC,
  235. static_cast<int>(SqliteLoggedResultCode::kIoRollbackAtomic)},
  236. // Chrome does not use the checksum VFS shim.
  237. {SQLITE_IOERR_DATA,
  238. static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
  239. {SQLITE_IOERR_CORRUPTFS,
  240. static_cast<int>(SqliteLoggedResultCode::kIoCorruptFileSystem)},
  241. };
  242. // Describes the handling of unknown SQLite error codes.
  243. constexpr SqliteResultCodeMappingEntry kUnknownResultCodeMappingEntry = {
  244. 0, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)};
  245. // Looks up a `sqlite_result_code` in the mapping tables.
  246. //
  247. // Returns an entry in kResultCodeMapping or kUnknownResultCodeMappingEntry.
  248. // DCHECKs if the `sqlite_result_code` is not in the mapping table.
  249. SqliteResultCodeMappingEntry FindResultCode(int sqlite_result_code) {
  250. const auto* mapping_it = base::ranges::find_if(
  251. kResultCodeMapping,
  252. [&sqlite_result_code](SqliteResultCodeMappingEntry rhs) {
  253. return sqlite_result_code == rhs.result_code;
  254. });
  255. if (mapping_it == base::ranges::end(kResultCodeMapping)) {
  256. NOTREACHED() << "Unsupported SQLite result code: " << sqlite_result_code;
  257. return kUnknownResultCodeMappingEntry;
  258. }
  259. return *mapping_it;
  260. }
  261. } // namespace
  262. #if DCHECK_IS_ON()
  263. SqliteResultCode ToSqliteResultCode(int sqlite_result_code) {
  264. SqliteLoggedResultCode logged_code = static_cast<SqliteLoggedResultCode>(
  265. FindResultCode(sqlite_result_code).logged_code);
  266. DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedSqlite)
  267. << "SQLite reported code marked for internal use: " << sqlite_result_code;
  268. DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedChrome)
  269. << "SQLite reported code that should never show up in Chrome: "
  270. << sqlite_result_code;
  271. return static_cast<SqliteResultCode>(sqlite_result_code);
  272. }
  273. SqliteErrorCode ToSqliteErrorCode(SqliteResultCode sqlite_error_code) {
  274. SqliteLoggedResultCode logged_code = static_cast<SqliteLoggedResultCode>(
  275. FindResultCode(static_cast<int>(sqlite_error_code)).logged_code);
  276. DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedSqlite)
  277. << "SQLite reported code marked for internal use: " << sqlite_error_code;
  278. DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedChrome)
  279. << "SQLite reported code that should never show up in Chrome: "
  280. << sqlite_error_code;
  281. DCHECK_NE(logged_code, SqliteLoggedResultCode::kNoError)
  282. << __func__
  283. << " called with non-error result code: " << sqlite_error_code;
  284. return static_cast<SqliteErrorCode>(sqlite_error_code);
  285. }
  286. #endif // DCHECK_IS_ON()
  287. bool IsSqliteSuccessCode(SqliteResultCode sqlite_result_code) {
  288. // https://www.sqlite.org/rescode.html lists the result codes that are not
  289. // errors.
  290. bool is_success = (sqlite_result_code == SqliteResultCode::kOk) ||
  291. (sqlite_result_code == SqliteResultCode::kRow) ||
  292. (sqlite_result_code == SqliteResultCode::kDone);
  293. #if DCHECK_IS_ON()
  294. SqliteLoggedResultCode logged_code = static_cast<SqliteLoggedResultCode>(
  295. FindResultCode(static_cast<int>(sqlite_result_code)).logged_code);
  296. DCHECK_EQ(is_success, logged_code == SqliteLoggedResultCode::kNoError)
  297. << __func__ << " logic disagrees with the code mapping for "
  298. << sqlite_result_code;
  299. DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedSqlite)
  300. << "SQLite reported code marked for internal use: " << sqlite_result_code;
  301. DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedChrome)
  302. << "SQLite reported code that should never show up in Chrome: "
  303. << sqlite_result_code;
  304. #endif // DCHECK_IS_ON()
  305. return is_success;
  306. }
  307. SqliteLoggedResultCode ToSqliteLoggedResultCode(int sqlite_result_code) {
  308. SqliteLoggedResultCode logged_code = static_cast<SqliteLoggedResultCode>(
  309. FindResultCode(sqlite_result_code).logged_code);
  310. DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedSqlite)
  311. << "SQLite reported code marked for internal use: " << sqlite_result_code;
  312. DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedChrome)
  313. << "SQLite reported code that should never show up in Chrome: "
  314. << sqlite_result_code;
  315. return logged_code;
  316. }
  317. void UmaHistogramSqliteResult(const char* histogram_name,
  318. int sqlite_result_code) {
  319. auto logged_code = ToSqliteLoggedResultCode(sqlite_result_code);
  320. base::UmaHistogramEnumeration(histogram_name, logged_code);
  321. }
  322. std::ostream& operator<<(std::ostream& os,
  323. SqliteResultCode sqlite_result_code) {
  324. return os << static_cast<int>(sqlite_result_code);
  325. }
  326. std::ostream& operator<<(std::ostream& os, SqliteErrorCode sqlite_error_code) {
  327. return os << static_cast<SqliteResultCode>(sqlite_error_code);
  328. }
  329. void CheckSqliteLoggedResultCodeForTesting() {
  330. // Ensure that error codes are alphabetical.
  331. const auto* unordered_it = base::ranges::adjacent_find(
  332. kResultCodeMapping,
  333. [](SqliteResultCodeMappingEntry lhs, SqliteResultCodeMappingEntry rhs) {
  334. return lhs.result_code >= rhs.result_code;
  335. });
  336. DCHECK_EQ(unordered_it, base::ranges::end(kResultCodeMapping))
  337. << "Mapping ordering broken at {" << unordered_it->result_code << ", "
  338. << static_cast<int>(unordered_it->logged_code) << "}";
  339. std::set<int> sqlite_result_codes;
  340. for (auto& mapping_entry : kResultCodeMapping)
  341. sqlite_result_codes.insert(mapping_entry.result_code);
  342. // SQLite doesn't have special messages for extended errors.
  343. // At the time of this writing, sqlite3_errstr() has a string table for
  344. // primary result codes, and uses it for extended error codes as well.
  345. //
  346. // So, we can only use sqlite3_errstr() to check for holes in the primary
  347. // message table.
  348. for (int result_code = 0; result_code <= 256; ++result_code) {
  349. if (sqlite_result_codes.count(result_code) != 0)
  350. continue;
  351. const char* error_message = sqlite3_errstr(result_code);
  352. static constexpr base::StringPiece kUnknownErrorMessage("unknown error");
  353. DCHECK_EQ(kUnknownErrorMessage.compare(error_message), 0)
  354. << "Unmapped SQLite result code: " << result_code
  355. << " SQLite message: " << error_message;
  356. }
  357. // Number of #defines in https://www.sqlite.org/c3ref/c_abort.html
  358. //
  359. // This number is also stated at
  360. // https://www.sqlite.org/rescode.html#primary_result_code_list
  361. static constexpr int kPrimaryResultCodes = 31;
  362. // Number of #defines in https://www.sqlite.org/c3ref/c_abort_rollback.html
  363. //
  364. // This number is also stated at
  365. // https://www.sqlite.org/rescode.html#extended_result_code_list
  366. static constexpr int kExtendedResultCodes = 74;
  367. DCHECK_EQ(std::size(kResultCodeMapping),
  368. size_t{kPrimaryResultCodes + kExtendedResultCodes})
  369. << "Mapping table has incorrect number of entries";
  370. }
  371. } // namespace sql