| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "android_database_SQLiteCommon.h" |
| |
| #include <utils/String8.h> |
| |
| #include <map> |
| |
| namespace android { |
| |
| static const std::map<int, std::string> sErrorCodesMap = { |
| // Primary Result Code List |
| {4, "SQLITE_ABORT"}, |
| {23, "SQLITE_AUTH"}, |
| {5, "SQLITE_BUSY"}, |
| {14, "SQLITE_CANTOPEN"}, |
| {19, "SQLITE_CONSTRAINT"}, |
| {11, "SQLITE_CORRUPT"}, |
| {101, "SQLITE_DONE"}, |
| {16, "SQLITE_EMPTY"}, |
| {1, "SQLITE_ERROR"}, |
| {24, "SQLITE_FORMAT"}, |
| {13, "SQLITE_FULL"}, |
| {2, "SQLITE_INTERNAL"}, |
| {9, "SQLITE_INTERRUPT"}, |
| {10, "SQLITE_IOERR"}, |
| {6, "SQLITE_LOCKED"}, |
| {20, "SQLITE_MISMATCH"}, |
| {21, "SQLITE_MISUSE"}, |
| {22, "SQLITE_NOLFS"}, |
| {7, "SQLITE_NOMEM"}, |
| {26, "SQLITE_NOTADB"}, |
| {12, "SQLITE_NOTFOUND"}, |
| {27, "SQLITE_NOTICE"}, |
| {0, "SQLITE_OK"}, |
| {3, "SQLITE_PERM"}, |
| {15, "SQLITE_PROTOCOL"}, |
| {25, "SQLITE_RANGE"}, |
| {8, "SQLITE_READONLY"}, |
| {100, "SQLITE_ROW"}, |
| {17, "SQLITE_SCHEMA"}, |
| {18, "SQLITE_TOOBIG"}, |
| {28, "SQLITE_WARNING"}, |
| // Extended Result Code List |
| {516, "SQLITE_ABORT_ROLLBACK"}, |
| {261, "SQLITE_BUSY_RECOVERY"}, |
| {517, "SQLITE_BUSY_SNAPSHOT"}, |
| {1038, "SQLITE_CANTOPEN_CONVPATH"}, |
| {782, "SQLITE_CANTOPEN_FULLPATH"}, |
| {526, "SQLITE_CANTOPEN_ISDIR"}, |
| {270, "SQLITE_CANTOPEN_NOTEMPDIR"}, |
| {275, "SQLITE_CONSTRAINT_CHECK"}, |
| {531, "SQLITE_CONSTRAINT_COMMITHOOK"}, |
| {787, "SQLITE_CONSTRAINT_FOREIGNKEY"}, |
| {1043, "SQLITE_CONSTRAINT_FUNCTION"}, |
| {1299, "SQLITE_CONSTRAINT_NOTNULL"}, |
| {1555, "SQLITE_CONSTRAINT_PRIMARYKEY"}, |
| {2579, "SQLITE_CONSTRAINT_ROWID"}, |
| {1811, "SQLITE_CONSTRAINT_TRIGGER"}, |
| {2067, "SQLITE_CONSTRAINT_UNIQUE"}, |
| {2323, "SQLITE_CONSTRAINT_VTAB"}, |
| {267, "SQLITE_CORRUPT_VTAB"}, |
| {3338, "SQLITE_IOERR_ACCESS"}, |
| {2826, "SQLITE_IOERR_BLOCKED"}, |
| {3594, "SQLITE_IOERR_CHECKRESERVEDLOCK"}, |
| {4106, "SQLITE_IOERR_CLOSE"}, |
| {6666, "SQLITE_IOERR_CONVPATH"}, |
| {2570, "SQLITE_IOERR_DELETE"}, |
| {5898, "SQLITE_IOERR_DELETE_NOENT"}, |
| {4362, "SQLITE_IOERR_DIR_CLOSE"}, |
| {1290, "SQLITE_IOERR_DIR_FSYNC"}, |
| {1802, "SQLITE_IOERR_FSTAT"}, |
| {1034, "SQLITE_IOERR_FSYNC"}, |
| {6410, "SQLITE_IOERR_GETTEMPPATH"}, |
| {3850, "SQLITE_IOERR_LOCK"}, |
| {6154, "SQLITE_IOERR_MMAP"}, |
| {3082, "SQLITE_IOERR_NOMEM"}, |
| {2314, "SQLITE_IOERR_RDLOCK"}, |
| {266, "SQLITE_IOERR_READ"}, |
| {5642, "SQLITE_IOERR_SEEK"}, |
| {5130, "SQLITE_IOERR_SHMLOCK"}, |
| {5386, "SQLITE_IOERR_SHMMAP"}, |
| {4618, "SQLITE_IOERR_SHMOPEN"}, |
| {4874, "SQLITE_IOERR_SHMSIZE"}, |
| {522, "SQLITE_IOERR_SHORT_READ"}, |
| {1546, "SQLITE_IOERR_TRUNCATE"}, |
| {2058, "SQLITE_IOERR_UNLOCK"}, |
| {778, "SQLITE_IOERR_WRITE"}, |
| {262, "SQLITE_LOCKED_SHAREDCACHE"}, |
| {539, "SQLITE_NOTICE_RECOVER_ROLLBACK"}, |
| {283, "SQLITE_NOTICE_RECOVER_WAL"}, |
| {256, "SQLITE_OK_LOAD_PERMANENTLY"}, |
| {520, "SQLITE_READONLY_CANTLOCK"}, |
| {1032, "SQLITE_READONLY_DBMOVED"}, |
| {264, "SQLITE_READONLY_RECOVERY"}, |
| {776, "SQLITE_READONLY_ROLLBACK"}, |
| {284, "SQLITE_WARNING_AUTOINDEX"}, |
| }; |
| |
| static std::string sqlite3_error_code_to_msg(int errcode) { |
| auto it = sErrorCodesMap.find(errcode); |
| if (it != sErrorCodesMap.end()) { |
| return std::to_string(errcode) + " " + it->second; |
| } else { |
| return std::to_string(errcode); |
| } |
| } |
| |
| /* throw a SQLiteException with a message appropriate for the error in handle */ |
| void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) { |
| throw_sqlite3_exception(env, handle, NULL); |
| } |
| |
| /* throw a SQLiteException with the given message */ |
| void throw_sqlite3_exception(JNIEnv* env, const char* message) { |
| throw_sqlite3_exception(env, NULL, message); |
| } |
| |
| /* throw a SQLiteException with a message appropriate for the error in handle |
| concatenated with the given message |
| */ |
| void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) { |
| if (handle) { |
| // get the error code and message from the SQLite connection |
| // the error message may contain more information than the error code |
| // because it is based on the extended error code rather than the simplified |
| // error code that SQLite normally returns. |
| throw_sqlite3_exception(env, sqlite3_extended_errcode(handle), |
| sqlite3_errmsg(handle), message); |
| } else { |
| // we use SQLITE_OK so that a generic SQLiteException is thrown; |
| // any code not specified in the switch statement below would do. |
| throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message); |
| } |
| } |
| |
| /* throw a SQLiteException for a given error code |
| * should only be used when the database connection is not available because the |
| * error information will not be quite as rich */ |
| void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) { |
| throw_sqlite3_exception(env, errcode, "unknown error", message); |
| } |
| |
| /* throw a SQLiteException for a given error code, sqlite3message, and |
| user message |
| */ |
| void throw_sqlite3_exception(JNIEnv* env, int errcode, |
| const char* sqlite3Message, const char* message) { |
| const char* exceptionClass; |
| switch (errcode & 0xff) { /* mask off extended error code */ |
| case SQLITE_IOERR: |
| exceptionClass = "android/database/sqlite/SQLiteDiskIOException"; |
| break; |
| case SQLITE_CORRUPT: |
| case SQLITE_NOTADB: // treat "unsupported file format" error as corruption also |
| exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException"; |
| break; |
| case SQLITE_CONSTRAINT: |
| exceptionClass = "android/database/sqlite/SQLiteConstraintException"; |
| break; |
| case SQLITE_ABORT: |
| exceptionClass = "android/database/sqlite/SQLiteAbortException"; |
| break; |
| case SQLITE_DONE: |
| exceptionClass = "android/database/sqlite/SQLiteDoneException"; |
| sqlite3Message = NULL; // SQLite error message is irrelevant in this case |
| break; |
| case SQLITE_FULL: |
| exceptionClass = "android/database/sqlite/SQLiteFullException"; |
| break; |
| case SQLITE_MISUSE: |
| exceptionClass = "android/database/sqlite/SQLiteMisuseException"; |
| break; |
| case SQLITE_PERM: |
| exceptionClass = "android/database/sqlite/SQLiteAccessPermException"; |
| break; |
| case SQLITE_BUSY: |
| exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException"; |
| break; |
| case SQLITE_LOCKED: |
| exceptionClass = "android/database/sqlite/SQLiteTableLockedException"; |
| break; |
| case SQLITE_READONLY: |
| exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException"; |
| break; |
| case SQLITE_CANTOPEN: |
| exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException"; |
| break; |
| case SQLITE_TOOBIG: |
| exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException"; |
| break; |
| case SQLITE_RANGE: |
| exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException"; |
| break; |
| case SQLITE_NOMEM: |
| exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException"; |
| break; |
| case SQLITE_MISMATCH: |
| exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException"; |
| break; |
| case SQLITE_INTERRUPT: |
| exceptionClass = "android/os/OperationCanceledException"; |
| break; |
| default: |
| exceptionClass = "android/database/sqlite/SQLiteException"; |
| break; |
| } |
| |
| if (sqlite3Message) { |
| String8 fullMessage; |
| fullMessage.append(sqlite3Message); |
| std::string errcode_msg = sqlite3_error_code_to_msg(errcode); |
| fullMessage.appendFormat(" (code %s)", errcode_msg.c_str()); // print extended error code |
| if (message) { |
| fullMessage.append(": "); |
| fullMessage.append(message); |
| } |
| jniThrowException(env, exceptionClass, fullMessage.string()); |
| } else { |
| jniThrowException(env, exceptionClass, message); |
| } |
| } |
| |
| |
| } // namespace android |