android_database_SQLiteCommon.cpp revision ca309f212d560673276aec0f4168a6c56131260c
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
21namespace android {
22
23/* throw a SQLiteException with a message appropriate for the error in handle */
24void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
25    throw_sqlite3_exception(env, handle, NULL);
26}
27
28/* throw a SQLiteException with the given message */
29void 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 */
36void 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 */
54void 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 */
61void 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