Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "android_database_SQLiteCommon.h"
     18 
     19 #include <utils/String8.h>
     20 
     21 #include <map>
     22 
     23 namespace android {
     24 
     25 static const std::map<int, std::string> sErrorCodesMap = {
     26     // Primary Result Code List
     27     {4,     "SQLITE_ABORT"},
     28     {23,    "SQLITE_AUTH"},
     29     {5,     "SQLITE_BUSY"},
     30     {14,    "SQLITE_CANTOPEN"},
     31     {19,    "SQLITE_CONSTRAINT"},
     32     {11,    "SQLITE_CORRUPT"},
     33     {101,   "SQLITE_DONE"},
     34     {16,    "SQLITE_EMPTY"},
     35     {1,     "SQLITE_ERROR"},
     36     {24,    "SQLITE_FORMAT"},
     37     {13,    "SQLITE_FULL"},
     38     {2,     "SQLITE_INTERNAL"},
     39     {9,     "SQLITE_INTERRUPT"},
     40     {10,    "SQLITE_IOERR"},
     41     {6,     "SQLITE_LOCKED"},
     42     {20,    "SQLITE_MISMATCH"},
     43     {21,    "SQLITE_MISUSE"},
     44     {22,    "SQLITE_NOLFS"},
     45     {7,     "SQLITE_NOMEM"},
     46     {26,    "SQLITE_NOTADB"},
     47     {12,    "SQLITE_NOTFOUND"},
     48     {27,    "SQLITE_NOTICE"},
     49     {0,     "SQLITE_OK"},
     50     {3,     "SQLITE_PERM"},
     51     {15,    "SQLITE_PROTOCOL"},
     52     {25,    "SQLITE_RANGE"},
     53     {8,     "SQLITE_READONLY"},
     54     {100,   "SQLITE_ROW"},
     55     {17,    "SQLITE_SCHEMA"},
     56     {18,    "SQLITE_TOOBIG"},
     57     {28,    "SQLITE_WARNING"},
     58     // Extended Result Code List
     59     {516,   "SQLITE_ABORT_ROLLBACK"},
     60     {261,   "SQLITE_BUSY_RECOVERY"},
     61     {517,   "SQLITE_BUSY_SNAPSHOT"},
     62     {1038,  "SQLITE_CANTOPEN_CONVPATH"},
     63     {782,   "SQLITE_CANTOPEN_FULLPATH"},
     64     {526,   "SQLITE_CANTOPEN_ISDIR"},
     65     {270,   "SQLITE_CANTOPEN_NOTEMPDIR"},
     66     {275,   "SQLITE_CONSTRAINT_CHECK"},
     67     {531,   "SQLITE_CONSTRAINT_COMMITHOOK"},
     68     {787,   "SQLITE_CONSTRAINT_FOREIGNKEY"},
     69     {1043,  "SQLITE_CONSTRAINT_FUNCTION"},
     70     {1299,  "SQLITE_CONSTRAINT_NOTNULL"},
     71     {1555,  "SQLITE_CONSTRAINT_PRIMARYKEY"},
     72     {2579,  "SQLITE_CONSTRAINT_ROWID"},
     73     {1811,  "SQLITE_CONSTRAINT_TRIGGER"},
     74     {2067,  "SQLITE_CONSTRAINT_UNIQUE"},
     75     {2323,  "SQLITE_CONSTRAINT_VTAB"},
     76     {267,   "SQLITE_CORRUPT_VTAB"},
     77     {3338,  "SQLITE_IOERR_ACCESS"},
     78     {2826,  "SQLITE_IOERR_BLOCKED"},
     79     {3594,  "SQLITE_IOERR_CHECKRESERVEDLOCK"},
     80     {4106,  "SQLITE_IOERR_CLOSE"},
     81     {6666,  "SQLITE_IOERR_CONVPATH"},
     82     {2570,  "SQLITE_IOERR_DELETE"},
     83     {5898,  "SQLITE_IOERR_DELETE_NOENT"},
     84     {4362,  "SQLITE_IOERR_DIR_CLOSE"},
     85     {1290,  "SQLITE_IOERR_DIR_FSYNC"},
     86     {1802,  "SQLITE_IOERR_FSTAT"},
     87     {1034,  "SQLITE_IOERR_FSYNC"},
     88     {6410,  "SQLITE_IOERR_GETTEMPPATH"},
     89     {3850,  "SQLITE_IOERR_LOCK"},
     90     {6154,  "SQLITE_IOERR_MMAP"},
     91     {3082,  "SQLITE_IOERR_NOMEM"},
     92     {2314,  "SQLITE_IOERR_RDLOCK"},
     93     {266,   "SQLITE_IOERR_READ"},
     94     {5642,  "SQLITE_IOERR_SEEK"},
     95     {5130,  "SQLITE_IOERR_SHMLOCK"},
     96     {5386,  "SQLITE_IOERR_SHMMAP"},
     97     {4618,  "SQLITE_IOERR_SHMOPEN"},
     98     {4874,  "SQLITE_IOERR_SHMSIZE"},
     99     {522,   "SQLITE_IOERR_SHORT_READ"},
    100     {1546,  "SQLITE_IOERR_TRUNCATE"},
    101     {2058,  "SQLITE_IOERR_UNLOCK"},
    102     {778,   "SQLITE_IOERR_WRITE"},
    103     {262,   "SQLITE_LOCKED_SHAREDCACHE"},
    104     {539,   "SQLITE_NOTICE_RECOVER_ROLLBACK"},
    105     {283,   "SQLITE_NOTICE_RECOVER_WAL"},
    106     {256,   "SQLITE_OK_LOAD_PERMANENTLY"},
    107     {520,   "SQLITE_READONLY_CANTLOCK"},
    108     {1032,  "SQLITE_READONLY_DBMOVED"},
    109     {264,   "SQLITE_READONLY_RECOVERY"},
    110     {776,   "SQLITE_READONLY_ROLLBACK"},
    111     {284,   "SQLITE_WARNING_AUTOINDEX"},
    112 };
    113 
    114 static std::string sqlite3_error_code_to_msg(int errcode) {
    115     auto it = sErrorCodesMap.find(errcode);
    116     if (it != sErrorCodesMap.end()) {
    117         return std::to_string(errcode) + " " + it->second;
    118     } else {
    119         return std::to_string(errcode);
    120     }
    121 }
    122 
    123 /* throw a SQLiteException with a message appropriate for the error in handle */
    124 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
    125     throw_sqlite3_exception(env, handle, NULL);
    126 }
    127 
    128 /* throw a SQLiteException with the given message */
    129 void throw_sqlite3_exception(JNIEnv* env, const char* message) {
    130     throw_sqlite3_exception(env, NULL, message);
    131 }
    132 
    133 /* throw a SQLiteException with a message appropriate for the error in handle
    134    concatenated with the given message
    135  */
    136 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) {
    137     if (handle) {
    138         // get the error code and message from the SQLite connection
    139         // the error message may contain more information than the error code
    140         // because it is based on the extended error code rather than the simplified
    141         // error code that SQLite normally returns.
    142         throw_sqlite3_exception(env, sqlite3_extended_errcode(handle),
    143                 sqlite3_errmsg(handle), message);
    144     } else {
    145         // we use SQLITE_OK so that a generic SQLiteException is thrown;
    146         // any code not specified in the switch statement below would do.
    147         throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message);
    148     }
    149 }
    150 
    151 /* throw a SQLiteException for a given error code
    152  * should only be used when the database connection is not available because the
    153  * error information will not be quite as rich */
    154 void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) {
    155     throw_sqlite3_exception(env, errcode, "unknown error", message);
    156 }
    157 
    158 /* throw a SQLiteException for a given error code, sqlite3message, and
    159    user message
    160  */
    161 void throw_sqlite3_exception(JNIEnv* env, int errcode,
    162                              const char* sqlite3Message, const char* message) {
    163     const char* exceptionClass;
    164     switch (errcode & 0xff) { /* mask off extended error code */
    165         case SQLITE_IOERR:
    166             exceptionClass = "android/database/sqlite/SQLiteDiskIOException";
    167             break;
    168         case SQLITE_CORRUPT:
    169         case SQLITE_NOTADB: // treat "unsupported file format" error as corruption also
    170             exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException";
    171             break;
    172         case SQLITE_CONSTRAINT:
    173             exceptionClass = "android/database/sqlite/SQLiteConstraintException";
    174             break;
    175         case SQLITE_ABORT:
    176             exceptionClass = "android/database/sqlite/SQLiteAbortException";
    177             break;
    178         case SQLITE_DONE:
    179             exceptionClass = "android/database/sqlite/SQLiteDoneException";
    180             sqlite3Message = NULL; // SQLite error message is irrelevant in this case
    181             break;
    182         case SQLITE_FULL:
    183             exceptionClass = "android/database/sqlite/SQLiteFullException";
    184             break;
    185         case SQLITE_MISUSE:
    186             exceptionClass = "android/database/sqlite/SQLiteMisuseException";
    187             break;
    188         case SQLITE_PERM:
    189             exceptionClass = "android/database/sqlite/SQLiteAccessPermException";
    190             break;
    191         case SQLITE_BUSY:
    192             exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException";
    193             break;
    194         case SQLITE_LOCKED:
    195             exceptionClass = "android/database/sqlite/SQLiteTableLockedException";
    196             break;
    197         case SQLITE_READONLY:
    198             exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException";
    199             break;
    200         case SQLITE_CANTOPEN:
    201             exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException";
    202             break;
    203         case SQLITE_TOOBIG:
    204             exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException";
    205             break;
    206         case SQLITE_RANGE:
    207             exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
    208             break;
    209         case SQLITE_NOMEM:
    210             exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException";
    211             break;
    212         case SQLITE_MISMATCH:
    213             exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
    214             break;
    215         case SQLITE_INTERRUPT:
    216             exceptionClass = "android/os/OperationCanceledException";
    217             break;
    218         default:
    219             exceptionClass = "android/database/sqlite/SQLiteException";
    220             break;
    221     }
    222 
    223     if (sqlite3Message) {
    224         String8 fullMessage;
    225         fullMessage.append(sqlite3Message);
    226         std::string errcode_msg = sqlite3_error_code_to_msg(errcode);
    227         fullMessage.appendFormat(" (code %s)", errcode_msg.c_str()); // print extended error code
    228         if (message) {
    229             fullMessage.append(": ");
    230             fullMessage.append(message);
    231         }
    232         jniThrowException(env, exceptionClass, fullMessage.string());
    233     } else {
    234         jniThrowException(env, exceptionClass, message);
    235     }
    236 }
    237 
    238 
    239 } // namespace android
    240