1e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/*
2e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Copyright (C) 2011 The Android Open Source Project
3e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
4e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * you may not use this file except in compliance with the License.
6e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * You may obtain a copy of the License at
7e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
8e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
10e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Unless required by applicable law or agreed to in writing, software
11e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * See the License for the specific language governing permissions and
14e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * limitations under the License.
15e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */
16e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
17e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include "android_database_SQLiteCommon.h"
18e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
19ca309f212d560673276aec0f4168a6c56131260cJeff Brown#include <utils/String8.h>
20ca309f212d560673276aec0f4168a6c56131260cJeff Brown
21e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownnamespace android {
22e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
23e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/* throw a SQLiteException with a message appropriate for the error in handle */
24e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownvoid throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
25e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    throw_sqlite3_exception(env, handle, NULL);
26e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
27e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
28e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/* throw a SQLiteException with the given message */
29e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownvoid throw_sqlite3_exception(JNIEnv* env, const char* message) {
30e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    throw_sqlite3_exception(env, NULL, message);
31e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
32e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
33e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/* throw a SQLiteException with a message appropriate for the error in handle
34e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown   concatenated with the given message
35e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */
36e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownvoid throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) {
37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (handle) {
389d25fa67a9291d469fa4006b2a373c8429132536Jeff Brown        // get the error code and message from the SQLite connection
399d25fa67a9291d469fa4006b2a373c8429132536Jeff Brown        // the error message may contain more information than the error code
409d25fa67a9291d469fa4006b2a373c8429132536Jeff Brown        // because it is based on the extended error code rather than the simplified
419d25fa67a9291d469fa4006b2a373c8429132536Jeff Brown        // error code that SQLite normally returns.
42ca309f212d560673276aec0f4168a6c56131260cJeff Brown        throw_sqlite3_exception(env, sqlite3_extended_errcode(handle),
43ca309f212d560673276aec0f4168a6c56131260cJeff Brown                sqlite3_errmsg(handle), message);
44e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    } else {
45e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // we use SQLITE_OK so that a generic SQLiteException is thrown;
46e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // any code not specified in the switch statement below would do.
47e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message);
48e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
49e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
50e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
519d25fa67a9291d469fa4006b2a373c8429132536Jeff Brown/* throw a SQLiteException for a given error code
529d25fa67a9291d469fa4006b2a373c8429132536Jeff Brown * should only be used when the database connection is not available because the
539d25fa67a9291d469fa4006b2a373c8429132536Jeff Brown * error information will not be quite as rich */
54e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownvoid throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) {
55ca309f212d560673276aec0f4168a6c56131260cJeff Brown    throw_sqlite3_exception(env, errcode, "unknown error", message);
56e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
57e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
58e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/* throw a SQLiteException for a given error code, sqlite3message, and
59e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown   user message
60e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */
61e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownvoid throw_sqlite3_exception(JNIEnv* env, int errcode,
62e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                             const char* sqlite3Message, const char* message) {
63e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const char* exceptionClass;
64ca309f212d560673276aec0f4168a6c56131260cJeff Brown    switch (errcode & 0xff) { /* mask off extended error code */
65e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_IOERR:
66e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            exceptionClass = "android/database/sqlite/SQLiteDiskIOException";
67e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            break;
68e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_CORRUPT:
69e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_NOTADB: // treat "unsupported file format" error as corruption also
70e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException";
71e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            break;
72e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_CONSTRAINT:
7375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteConstraintException";
7475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
75e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_ABORT:
7675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteAbortException";
7775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
78e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_DONE:
7975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteDoneException";
809d25fa67a9291d469fa4006b2a373c8429132536Jeff Brown            sqlite3Message = NULL; // SQLite error message is irrelevant in this case
8175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
82e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_FULL:
8375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteFullException";
8475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
85e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_MISUSE:
8675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteMisuseException";
8775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
88e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_PERM:
8975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteAccessPermException";
9075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
91e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_BUSY:
9275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException";
9375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
94e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_LOCKED:
9575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteTableLockedException";
9675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
97e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_READONLY:
9875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException";
9975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
100e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_CANTOPEN:
10175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException";
10275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_TOOBIG:
10475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException";
10575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
106e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_RANGE:
10775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
10875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
109e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_NOMEM:
11075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException";
11175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
112e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        case SQLITE_MISMATCH:
11375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
11475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
11575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        case SQLITE_INTERRUPT:
11625c934533fb81aa08e379ffe60e390dbbd12440cJeff Brown            exceptionClass = "android/os/OperationCanceledException";
11775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
118e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        default:
11975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            exceptionClass = "android/database/sqlite/SQLiteException";
12075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            break;
121e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
123ca309f212d560673276aec0f4168a6c56131260cJeff Brown    if (sqlite3Message) {
124ca309f212d560673276aec0f4168a6c56131260cJeff Brown        String8 fullMessage;
125ca309f212d560673276aec0f4168a6c56131260cJeff Brown        fullMessage.append(sqlite3Message);
126ca309f212d560673276aec0f4168a6c56131260cJeff Brown        fullMessage.appendFormat(" (code %d)", errcode); // print extended error code
127ca309f212d560673276aec0f4168a6c56131260cJeff Brown        if (message) {
128ca309f212d560673276aec0f4168a6c56131260cJeff Brown            fullMessage.append(": ");
129ca309f212d560673276aec0f4168a6c56131260cJeff Brown            fullMessage.append(message);
130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
131ca309f212d560673276aec0f4168a6c56131260cJeff Brown        jniThrowException(env, exceptionClass, fullMessage.string());
132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    } else {
133e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jniThrowException(env, exceptionClass, message);
134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
137e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown} // namespace android
139