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
sqlite3_error_code_to_msg(int errcode)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 */
throw_sqlite3_exception(JNIEnv * env,sqlite3 * 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 */
throw_sqlite3_exception(JNIEnv * env,const char * 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 */
throw_sqlite3_exception(JNIEnv * env,sqlite3 * handle,const char * message)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 */
throw_sqlite3_exception_errcode(JNIEnv * env,int errcode,const char * message)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 */
throw_sqlite3_exception(JNIEnv * env,int errcode,const char * sqlite3Message,const char * message)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