123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- // Copyright 2022 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "sql/sqlite_result_code.h"
- #include <ostream> // Needed to compile NOTREACHED() with operator <<.
- #include <set>
- #include <utility>
- #include "base/check_op.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/notreached.h"
- #include "base/ranges/algorithm.h"
- #include "base/strings/string_piece.h"
- #include "sql/sqlite_result_code_values.h"
- #include "third_party/sqlite/sqlite3.h"
- namespace sql {
- namespace {
- // The highly packed representation minimizes binary size and memory usage.
- struct SqliteResultCodeMappingEntry {
- unsigned result_code : 16;
- unsigned logged_code : 8;
- // The remaining bits will be used to encode the result values of helpers that
- // indicate corruption handling.
- };
- constexpr SqliteResultCodeMappingEntry kResultCodeMapping[] = {
- // Entries are ordered by SQLite result code value. This should match the
- // ordering in https://www.sqlite.org/rescode.html.
- {SQLITE_OK, static_cast<int>(SqliteLoggedResultCode::kNoError)},
- {SQLITE_ERROR, static_cast<int>(SqliteLoggedResultCode::kGeneric)},
- {SQLITE_INTERNAL, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_PERM, static_cast<int>(SqliteLoggedResultCode::kPermission)},
- {SQLITE_ABORT, static_cast<int>(SqliteLoggedResultCode::kAbort)},
- {SQLITE_BUSY, static_cast<int>(SqliteLoggedResultCode::kBusy)},
- // Chrome features shouldn't execute conflicting statements concurrently.
- {SQLITE_LOCKED, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- // Chrome should crash on OOM.
- {SQLITE_NOMEM, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_READONLY, static_cast<int>(SqliteLoggedResultCode::kReadOnly)},
- // Chrome doesn't use sqlite3_interrupt().
- {SQLITE_INTERRUPT, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_IOERR, static_cast<int>(SqliteLoggedResultCode::kIo)},
- {SQLITE_CORRUPT, static_cast<int>(SqliteLoggedResultCode::kCorrupt)},
- // Chrome only passes a few known-good opcodes to sqlite3_file_control().
- {SQLITE_NOTFOUND, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_FULL, static_cast<int>(SqliteLoggedResultCode::kFullDisk)},
- {SQLITE_CANTOPEN, static_cast<int>(SqliteLoggedResultCode::kCantOpen)},
- {SQLITE_PROTOCOL,
- static_cast<int>(SqliteLoggedResultCode::kLockingProtocol)},
- {SQLITE_EMPTY, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_SCHEMA, static_cast<int>(SqliteLoggedResultCode::kSchemaChanged)},
- {SQLITE_TOOBIG, static_cast<int>(SqliteLoggedResultCode::kTooBig)},
- {SQLITE_CONSTRAINT, static_cast<int>(SqliteLoggedResultCode::kConstraint)},
- {SQLITE_MISMATCH, static_cast<int>(SqliteLoggedResultCode::kTypeMismatch)},
- // Chrome should not misuse SQLite's API.
- {SQLITE_MISUSE, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_NOLFS,
- static_cast<int>(SqliteLoggedResultCode::kNoLargeFileSupport)},
- // Chrome does not set an authorizer callback.
- {SQLITE_AUTH, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_FORMAT, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- // Chrome should not use invalid column indexes in sqlite3_{bind,column}*().
- {SQLITE_RANGE, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_NOTADB, static_cast<int>(SqliteLoggedResultCode::kNotADatabase)},
- {SQLITE_NOTICE, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_WARNING, static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_ROW, static_cast<int>(SqliteLoggedResultCode::kNoError)},
- {SQLITE_DONE, static_cast<int>(SqliteLoggedResultCode::kNoError)},
- {SQLITE_OK_LOAD_PERMANENTLY,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- // Chrome should not use collating sequence names in SQL statements.
- {SQLITE_ERROR_MISSING_COLLSEQ,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_BUSY_RECOVERY,
- static_cast<int>(SqliteLoggedResultCode::kBusyRecovery)},
- // Chrome does not use a shared page cache.
- {SQLITE_LOCKED_SHAREDCACHE,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_READONLY_RECOVERY,
- static_cast<int>(SqliteLoggedResultCode::kReadOnlyRecovery)},
- {SQLITE_IOERR_READ, static_cast<int>(SqliteLoggedResultCode::kIoRead)},
- // Chrome does not use a virtual table that signals corruption. We only use
- // a
- // virtual table code for recovery. That code does not use this error.
- {SQLITE_CORRUPT_VTAB,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_CANTOPEN_NOTEMPDIR,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_CONSTRAINT_CHECK,
- static_cast<int>(SqliteLoggedResultCode::kConstraintCheck)},
- // Chrome does not set an authorizer callback.
- {SQLITE_AUTH_USER, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_NOTICE_RECOVER_WAL,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_WARNING_AUTOINDEX,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_ERROR_RETRY,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_ABORT_ROLLBACK,
- static_cast<int>(SqliteLoggedResultCode::kAbortRollback)},
- {SQLITE_BUSY_SNAPSHOT,
- static_cast<int>(SqliteLoggedResultCode::kBusySnapshot)},
- // Chrome does not use a virtual table that signals conflicts. We only use a
- // virtual table code for recovery. That code does not use this error.
- {SQLITE_LOCKED_VTAB,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_READONLY_CANTLOCK,
- static_cast<int>(SqliteLoggedResultCode::kReadOnlyCantLock)},
- {SQLITE_IOERR_SHORT_READ,
- static_cast<int>(SqliteLoggedResultCode::kIoShortRead)},
- {SQLITE_CORRUPT_SEQUENCE,
- static_cast<int>(SqliteLoggedResultCode::kCorruptSequence)},
- {SQLITE_CANTOPEN_ISDIR,
- static_cast<int>(SqliteLoggedResultCode::kCantOpenIsDir)},
- // Chrome does not use commit hook callbacks.
- {SQLITE_CONSTRAINT_COMMITHOOK,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_NOTICE_RECOVER_ROLLBACK,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- // Chrome does not use sqlite3_snapshot_open().
- {SQLITE_ERROR_SNAPSHOT,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- #ifdef SQLITE_ENABLE_SNAPSHOT
- #error "This code assumes that Chrome does not use sqlite3_snapshot_open()"
- #endif
- // Chrome does not use blocking Posix advisory file lock requests.
- {SQLITE_BUSY_TIMEOUT,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- #error "This code assumes that Chrome does not use
- #endif
- {SQLITE_READONLY_ROLLBACK,
- static_cast<int>(SqliteLoggedResultCode::kReadOnlyRollback)},
- {SQLITE_IOERR_WRITE, static_cast<int>(SqliteLoggedResultCode::kIoWrite)},
- {SQLITE_CORRUPT_INDEX,
- static_cast<int>(SqliteLoggedResultCode::kCorruptIndex)},
- // Chrome should always pass full paths to SQLite.
- {SQLITE_CANTOPEN_FULLPATH,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_CONSTRAINT_FOREIGNKEY,
- static_cast<int>(SqliteLoggedResultCode::kConstraintForeignKey)},
- {SQLITE_READONLY_DBMOVED,
- static_cast<int>(SqliteLoggedResultCode::kReadOnlyDbMoved)},
- {SQLITE_IOERR_FSYNC, static_cast<int>(SqliteLoggedResultCode::kIoFsync)},
- // Chrome does not support Cygwin and does not use its VFS.
- {SQLITE_CANTOPEN_CONVPATH,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- // Chrome does not use extension functions.
- {SQLITE_CONSTRAINT_FUNCTION,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_READONLY_CANTINIT,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_IOERR_DIR_FSYNC,
- static_cast<int>(SqliteLoggedResultCode::kIoDirFsync)},
- {SQLITE_CANTOPEN_DIRTYWAL,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- {SQLITE_CONSTRAINT_NOTNULL,
- static_cast<int>(SqliteLoggedResultCode::kConstraintNotNull)},
- {SQLITE_READONLY_DIRECTORY,
- static_cast<int>(SqliteLoggedResultCode::kReadOnlyDirectory)},
- {SQLITE_IOERR_TRUNCATE,
- static_cast<int>(SqliteLoggedResultCode::kIoTruncate)},
- // Chrome does not use the SQLITE_OPEN_NOFOLLOW flag.
- {SQLITE_CANTOPEN_SYMLINK,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_CONSTRAINT_PRIMARYKEY,
- static_cast<int>(SqliteLoggedResultCode::kConstraintPrimaryKey)},
- {SQLITE_IOERR_FSTAT, static_cast<int>(SqliteLoggedResultCode::kIoFstat)},
- // Chrome unconditionally disables database triggers via
- // sqlite3_db_config(SQLITE_DBCONFIG_ENABLE_TRIGGER).
- {SQLITE_CONSTRAINT_TRIGGER,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_IOERR_UNLOCK, static_cast<int>(SqliteLoggedResultCode::kIoUnlock)},
- {SQLITE_CONSTRAINT_UNIQUE,
- static_cast<int>(SqliteLoggedResultCode::kConstraintUnique)},
- {SQLITE_IOERR_RDLOCK,
- static_cast<int>(SqliteLoggedResultCode::kIoReadLock)},
- // Chrome does not use a virtual table that signals constraints. We only use
- // a virtual table code for recovery. That code does not use this error.
- {SQLITE_CONSTRAINT_VTAB,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_IOERR_DELETE, static_cast<int>(SqliteLoggedResultCode::kIoDelete)},
- {SQLITE_CONSTRAINT_ROWID,
- static_cast<int>(SqliteLoggedResultCode::kConstraintRowId)},
- {SQLITE_IOERR_BLOCKED,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- // Chrome unconditionally disables database triggers via
- // sqlite3_db_config(SQLITE_DBCONFIG_ENABLE_TRIGGER).
- {SQLITE_CONSTRAINT_PINNED,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- // The SQLite docus claim that this error code is "normally" converted to
- // SQLITE_NOMEM. This doesn't seem 100% categorical, so we're flagging this
- // as "unused in Chrome" per the same rationale as SQLITE_NOMEM.
- {SQLITE_IOERR_NOMEM,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_CONSTRAINT_DATATYPE,
- static_cast<int>(SqliteLoggedResultCode::kConstraintDataType)},
- {SQLITE_IOERR_ACCESS, static_cast<int>(SqliteLoggedResultCode::kIoAccess)},
- {SQLITE_IOERR_CHECKRESERVEDLOCK,
- static_cast<int>(SqliteLoggedResultCode::kIoCheckReservedLock)},
- {SQLITE_IOERR_LOCK, static_cast<int>(SqliteLoggedResultCode::kIoLock)},
- {SQLITE_IOERR_CLOSE, static_cast<int>(SqliteLoggedResultCode::kIoClose)},
- {SQLITE_IOERR_DIR_CLOSE,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- // Chrome will only allow enabling WAL on databases with exclusive locking.
- {SQLITE_IOERR_SHMOPEN,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- // Chrome will only allow enabling WAL on databases with exclusive locking.
- {SQLITE_IOERR_SHMSIZE,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_IOERR_SHMLOCK,
- static_cast<int>(SqliteLoggedResultCode::kUnusedSqlite)},
- // Chrome will only allow enabling WAL on databases with exclusive locking.
- {SQLITE_IOERR_SHMMAP,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_IOERR_SEEK, static_cast<int>(SqliteLoggedResultCode::kIoSeek)},
- {SQLITE_IOERR_DELETE_NOENT,
- static_cast<int>(SqliteLoggedResultCode::kIoDeleteNoEntry)},
- {SQLITE_IOERR_MMAP,
- static_cast<int>(SqliteLoggedResultCode::kIoMemoryMapping)},
- {SQLITE_IOERR_GETTEMPPATH,
- static_cast<int>(SqliteLoggedResultCode::kIoGetTemporaryPath)},
- // Chrome does not support Cygwin and does not use its VFS.
- {SQLITE_IOERR_CONVPATH,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- // Chrome does not use SQLite extensions.
- {SQLITE_IOERR_VNODE,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- // Chrome does not use SQLite extensions.
- {SQLITE_IOERR_AUTH,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_IOERR_BEGIN_ATOMIC,
- static_cast<int>(SqliteLoggedResultCode::kIoBeginAtomic)},
- {SQLITE_IOERR_COMMIT_ATOMIC,
- static_cast<int>(SqliteLoggedResultCode::kIoCommitAtomic)},
- {SQLITE_IOERR_ROLLBACK_ATOMIC,
- static_cast<int>(SqliteLoggedResultCode::kIoRollbackAtomic)},
- // Chrome does not use the checksum VFS shim.
- {SQLITE_IOERR_DATA,
- static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)},
- {SQLITE_IOERR_CORRUPTFS,
- static_cast<int>(SqliteLoggedResultCode::kIoCorruptFileSystem)},
- };
- // Describes the handling of unknown SQLite error codes.
- constexpr SqliteResultCodeMappingEntry kUnknownResultCodeMappingEntry = {
- 0, static_cast<int>(SqliteLoggedResultCode::kUnusedChrome)};
- // Looks up a `sqlite_result_code` in the mapping tables.
- //
- // Returns an entry in kResultCodeMapping or kUnknownResultCodeMappingEntry.
- // DCHECKs if the `sqlite_result_code` is not in the mapping table.
- SqliteResultCodeMappingEntry FindResultCode(int sqlite_result_code) {
- const auto* mapping_it = base::ranges::find_if(
- kResultCodeMapping,
- [&sqlite_result_code](SqliteResultCodeMappingEntry rhs) {
- return sqlite_result_code == rhs.result_code;
- });
- if (mapping_it == base::ranges::end(kResultCodeMapping)) {
- NOTREACHED() << "Unsupported SQLite result code: " << sqlite_result_code;
- return kUnknownResultCodeMappingEntry;
- }
- return *mapping_it;
- }
- } // namespace
- #if DCHECK_IS_ON()
- SqliteResultCode ToSqliteResultCode(int sqlite_result_code) {
- SqliteLoggedResultCode logged_code = static_cast<SqliteLoggedResultCode>(
- FindResultCode(sqlite_result_code).logged_code);
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedSqlite)
- << "SQLite reported code marked for internal use: " << sqlite_result_code;
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedChrome)
- << "SQLite reported code that should never show up in Chrome: "
- << sqlite_result_code;
- return static_cast<SqliteResultCode>(sqlite_result_code);
- }
- SqliteErrorCode ToSqliteErrorCode(SqliteResultCode sqlite_error_code) {
- SqliteLoggedResultCode logged_code = static_cast<SqliteLoggedResultCode>(
- FindResultCode(static_cast<int>(sqlite_error_code)).logged_code);
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedSqlite)
- << "SQLite reported code marked for internal use: " << sqlite_error_code;
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedChrome)
- << "SQLite reported code that should never show up in Chrome: "
- << sqlite_error_code;
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kNoError)
- << __func__
- << " called with non-error result code: " << sqlite_error_code;
- return static_cast<SqliteErrorCode>(sqlite_error_code);
- }
- #endif // DCHECK_IS_ON()
- bool IsSqliteSuccessCode(SqliteResultCode sqlite_result_code) {
- // https://www.sqlite.org/rescode.html lists the result codes that are not
- // errors.
- bool is_success = (sqlite_result_code == SqliteResultCode::kOk) ||
- (sqlite_result_code == SqliteResultCode::kRow) ||
- (sqlite_result_code == SqliteResultCode::kDone);
- #if DCHECK_IS_ON()
- SqliteLoggedResultCode logged_code = static_cast<SqliteLoggedResultCode>(
- FindResultCode(static_cast<int>(sqlite_result_code)).logged_code);
- DCHECK_EQ(is_success, logged_code == SqliteLoggedResultCode::kNoError)
- << __func__ << " logic disagrees with the code mapping for "
- << sqlite_result_code;
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedSqlite)
- << "SQLite reported code marked for internal use: " << sqlite_result_code;
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedChrome)
- << "SQLite reported code that should never show up in Chrome: "
- << sqlite_result_code;
- #endif // DCHECK_IS_ON()
- return is_success;
- }
- SqliteLoggedResultCode ToSqliteLoggedResultCode(int sqlite_result_code) {
- SqliteLoggedResultCode logged_code = static_cast<SqliteLoggedResultCode>(
- FindResultCode(sqlite_result_code).logged_code);
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedSqlite)
- << "SQLite reported code marked for internal use: " << sqlite_result_code;
- DCHECK_NE(logged_code, SqliteLoggedResultCode::kUnusedChrome)
- << "SQLite reported code that should never show up in Chrome: "
- << sqlite_result_code;
- return logged_code;
- }
- void UmaHistogramSqliteResult(const char* histogram_name,
- int sqlite_result_code) {
- auto logged_code = ToSqliteLoggedResultCode(sqlite_result_code);
- base::UmaHistogramEnumeration(histogram_name, logged_code);
- }
- std::ostream& operator<<(std::ostream& os,
- SqliteResultCode sqlite_result_code) {
- return os << static_cast<int>(sqlite_result_code);
- }
- std::ostream& operator<<(std::ostream& os, SqliteErrorCode sqlite_error_code) {
- return os << static_cast<SqliteResultCode>(sqlite_error_code);
- }
- void CheckSqliteLoggedResultCodeForTesting() {
- // Ensure that error codes are alphabetical.
- const auto* unordered_it = base::ranges::adjacent_find(
- kResultCodeMapping,
- [](SqliteResultCodeMappingEntry lhs, SqliteResultCodeMappingEntry rhs) {
- return lhs.result_code >= rhs.result_code;
- });
- DCHECK_EQ(unordered_it, base::ranges::end(kResultCodeMapping))
- << "Mapping ordering broken at {" << unordered_it->result_code << ", "
- << static_cast<int>(unordered_it->logged_code) << "}";
- std::set<int> sqlite_result_codes;
- for (auto& mapping_entry : kResultCodeMapping)
- sqlite_result_codes.insert(mapping_entry.result_code);
- // SQLite doesn't have special messages for extended errors.
- // At the time of this writing, sqlite3_errstr() has a string table for
- // primary result codes, and uses it for extended error codes as well.
- //
- // So, we can only use sqlite3_errstr() to check for holes in the primary
- // message table.
- for (int result_code = 0; result_code <= 256; ++result_code) {
- if (sqlite_result_codes.count(result_code) != 0)
- continue;
- const char* error_message = sqlite3_errstr(result_code);
- static constexpr base::StringPiece kUnknownErrorMessage("unknown error");
- DCHECK_EQ(kUnknownErrorMessage.compare(error_message), 0)
- << "Unmapped SQLite result code: " << result_code
- << " SQLite message: " << error_message;
- }
- // Number of #defines in https://www.sqlite.org/c3ref/c_abort.html
- //
- // This number is also stated at
- // https://www.sqlite.org/rescode.html#primary_result_code_list
- static constexpr int kPrimaryResultCodes = 31;
- // Number of #defines in https://www.sqlite.org/c3ref/c_abort_rollback.html
- //
- // This number is also stated at
- // https://www.sqlite.org/rescode.html#extended_result_code_list
- static constexpr int kExtendedResultCodes = 74;
- DCHECK_EQ(std::size(kResultCodeMapping),
- size_t{kPrimaryResultCodes + kExtendedResultCodes})
- << "Mapping table has incorrect number of entries";
- }
- } // namespace sql
|