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 namespace android {
22 
23 /* throw a SQLiteException with a message appropriate for the error in handle */
throw_sqlite3_exception(JNIEnv * env,sqlite3 * handle)24 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
25     throw_sqlite3_exception(env, handle, NULL);
26 }
27 
28 /* throw a SQLiteException with the given message */
throw_sqlite3_exception(JNIEnv * env,const char * message)29 void throw_sqlite3_exception(JNIEnv* env, const char* message) {
30     throw_sqlite3_exception(env, NULL, message);
31 }
32 
33 /* throw a SQLiteException with a message appropriate for the error in handle
34    concatenated with the given message
35  */
throw_sqlite3_exception(JNIEnv * env,sqlite3 * handle,const char * message)36 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) {
37     if (handle) {
38         // get the error code and message from the SQLite connection
39         // the error message may contain more information than the error code
40         // because it is based on the extended error code rather than the simplified
41         // error code that SQLite normally returns.
42         throw_sqlite3_exception(env, sqlite3_extended_errcode(handle),
43                 sqlite3_errmsg(handle), message);
44     } else {
45         // we use SQLITE_OK so that a generic SQLiteException is thrown;
46         // any code not specified in the switch statement below would do.
47         throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message);
48     }
49 }
50 
51 /* throw a SQLiteException for a given error code
52  * should only be used when the database connection is not available because the
53  * error information will not be quite as rich */
throw_sqlite3_exception_errcode(JNIEnv * env,int errcode,const char * message)54 void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) {
55     throw_sqlite3_exception(env, errcode, "unknown error", message);
56 }
57 
58 /* throw a SQLiteException for a given error code, sqlite3message, and
59    user message
60  */
throw_sqlite3_exception(JNIEnv * env,int errcode,const char * sqlite3Message,const char * message)61 void throw_sqlite3_exception(JNIEnv* env, int errcode,
62                              const char* sqlite3Message, const char* message) {
63     const char* exceptionClass;
64     switch (errcode & 0xff) { /* mask off extended error code */
65         case SQLITE_IOERR:
66             exceptionClass = "android/database/sqlite/SQLiteDiskIOException";
67             break;
68         case SQLITE_CORRUPT:
69         case SQLITE_NOTADB: // treat "unsupported file format" error as corruption also
70             exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException";
71             break;
72         case SQLITE_CONSTRAINT:
73             exceptionClass = "android/database/sqlite/SQLiteConstraintException";
74             break;
75         case SQLITE_ABORT:
76             exceptionClass = "android/database/sqlite/SQLiteAbortException";
77             break;
78         case SQLITE_DONE:
79             exceptionClass = "android/database/sqlite/SQLiteDoneException";
80             sqlite3Message = NULL; // SQLite error message is irrelevant in this case
81             break;
82         case SQLITE_FULL:
83             exceptionClass = "android/database/sqlite/SQLiteFullException";
84             break;
85         case SQLITE_MISUSE:
86             exceptionClass = "android/database/sqlite/SQLiteMisuseException";
87             break;
88         case SQLITE_PERM:
89             exceptionClass = "android/database/sqlite/SQLiteAccessPermException";
90             break;
91         case SQLITE_BUSY:
92             exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException";
93             break;
94         case SQLITE_LOCKED:
95             exceptionClass = "android/database/sqlite/SQLiteTableLockedException";
96             break;
97         case SQLITE_READONLY:
98             exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException";
99             break;
100         case SQLITE_CANTOPEN:
101             exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException";
102             break;
103         case SQLITE_TOOBIG:
104             exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException";
105             break;
106         case SQLITE_RANGE:
107             exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
108             break;
109         case SQLITE_NOMEM:
110             exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException";
111             break;
112         case SQLITE_MISMATCH:
113             exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
114             break;
115         case SQLITE_INTERRUPT:
116             exceptionClass = "android/os/OperationCanceledException";
117             break;
118         default:
119             exceptionClass = "android/database/sqlite/SQLiteException";
120             break;
121     }
122 
123     if (sqlite3Message) {
124         String8 fullMessage;
125         fullMessage.append(sqlite3Message);
126         fullMessage.appendFormat(" (code %d)", errcode); // print extended error code
127         if (message) {
128             fullMessage.append(": ");
129             fullMessage.append(message);
130         }
131         jniThrowException(env, exceptionClass, fullMessage.string());
132     } else {
133         jniThrowException(env, exceptionClass, message);
134     }
135 }
136 
137 
138 } // namespace android
139