Home | History | Annotate | Download | only in jni
      1 /* //device/libs/android_runtime/android_database_SQLiteCursor.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #undef LOG_TAG
     19 #define LOG_TAG "SQLiteStatementCpp"
     20 
     21 #include "android_util_Binder.h"
     22 
     23 #include <jni.h>
     24 #include <JNIHelp.h>
     25 #include <android_runtime/AndroidRuntime.h>
     26 
     27 #include <sqlite3.h>
     28 
     29 #include <cutils/ashmem.h>
     30 #include <utils/Log.h>
     31 
     32 #include <fcntl.h>
     33 #include <stdio.h>
     34 #include <string.h>
     35 #include <unistd.h>
     36 #include <sys/mman.h>
     37 #include <sys/types.h>
     38 #include <sys/stat.h>
     39 
     40 #include "sqlite3_exception.h"
     41 
     42 namespace android {
     43 
     44 
     45 sqlite3_stmt * compile(JNIEnv* env, jobject object,
     46                        sqlite3 * handle, jstring sqlString);
     47 
     48 static jfieldID gHandleField;
     49 static jfieldID gStatementField;
     50 
     51 
     52 #define GET_STATEMENT(env, object) \
     53         (sqlite3_stmt *)env->GetIntField(object, gStatementField)
     54 #define GET_HANDLE(env, object) \
     55         (sqlite3 *)env->GetIntField(object, gHandleField)
     56 
     57 
     58 static jint native_execute(JNIEnv* env, jobject object)
     59 {
     60     int err;
     61     sqlite3 * handle = GET_HANDLE(env, object);
     62     sqlite3_stmt * statement = GET_STATEMENT(env, object);
     63     int numChanges = -1;
     64 
     65     // Execute the statement
     66     err = sqlite3_step(statement);
     67 
     68     // Throw an exception if an error occurred
     69     if (err == SQLITE_ROW) {
     70         throw_sqlite3_exception(env,
     71                 "Queries can be performed using SQLiteDatabase query or rawQuery methods only.");
     72     } else if (err != SQLITE_DONE) {
     73         throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
     74     } else {
     75         numChanges = sqlite3_changes(handle);
     76     }
     77 
     78     // Reset the statement so it's ready to use again
     79     sqlite3_reset(statement);
     80     return numChanges;
     81 }
     82 
     83 static jlong native_executeInsert(JNIEnv* env, jobject object)
     84 {
     85     sqlite3 * handle = GET_HANDLE(env, object);
     86     jint numChanges = native_execute(env, object);
     87     if (numChanges > 0) {
     88         return sqlite3_last_insert_rowid(handle);
     89     } else {
     90         return -1;
     91     }
     92 }
     93 
     94 static jlong native_1x1_long(JNIEnv* env, jobject object)
     95 {
     96     int err;
     97     sqlite3 * handle = GET_HANDLE(env, object);
     98     sqlite3_stmt * statement = GET_STATEMENT(env, object);
     99     jlong value = -1;
    100 
    101     // Execute the statement
    102     err = sqlite3_step(statement);
    103 
    104     // Handle the result
    105     if (err == SQLITE_ROW) {
    106         // No errors, read the data and return it
    107         value = sqlite3_column_int64(statement, 0);
    108     } else {
    109         throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
    110     }
    111 
    112     // Reset the statment so it's ready to use again
    113     sqlite3_reset(statement);
    114 
    115     return value;
    116 }
    117 
    118 static jstring native_1x1_string(JNIEnv* env, jobject object)
    119 {
    120     int err;
    121     sqlite3 * handle = GET_HANDLE(env, object);
    122     sqlite3_stmt * statement = GET_STATEMENT(env, object);
    123     jstring value = NULL;
    124 
    125     // Execute the statement
    126     err = sqlite3_step(statement);
    127 
    128     // Handle the result
    129     if (err == SQLITE_ROW) {
    130         // No errors, read the data and return it
    131         char const * text = (char const *)sqlite3_column_text(statement, 0);
    132         value = env->NewStringUTF(text);
    133     } else {
    134         throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
    135     }
    136 
    137     // Reset the statment so it's ready to use again
    138     sqlite3_reset(statement);
    139 
    140     return value;
    141 }
    142 
    143 static jobject createParcelFileDescriptor(JNIEnv * env, int fd)
    144 {
    145     // Create FileDescriptor object
    146     jobject fileDesc = jniCreateFileDescriptor(env, fd);
    147     if (fileDesc == NULL) {
    148         // FileDescriptor constructor has thrown an exception
    149         close(fd);
    150         return NULL;
    151     }
    152 
    153     // Wrap it in a ParcelFileDescriptor
    154     jobject parcelFileDesc = newParcelFileDescriptor(env, fileDesc);
    155     if (parcelFileDesc == NULL) {
    156         // ParcelFileDescriptor constructor has thrown an exception
    157         close(fd);
    158         return NULL;
    159     }
    160 
    161     return parcelFileDesc;
    162 }
    163 
    164 // Creates an ashmem area, copies some data into it, and returns
    165 // a ParcelFileDescriptor for the ashmem area.
    166 static jobject create_ashmem_region_with_data(JNIEnv * env,
    167                                               const void * data, int length)
    168 {
    169     // Create ashmem area
    170     int fd = ashmem_create_region(NULL, length);
    171     if (fd < 0) {
    172         LOGE("ashmem_create_region failed: %s", strerror(errno));
    173         jniThrowIOException(env, errno);
    174         return NULL;
    175     }
    176 
    177     if (length > 0) {
    178         // mmap the ashmem area
    179         void * ashmem_ptr =
    180                 mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    181         if (ashmem_ptr == MAP_FAILED) {
    182             LOGE("mmap failed: %s", strerror(errno));
    183             jniThrowIOException(env, errno);
    184             close(fd);
    185             return NULL;
    186         }
    187 
    188         // Copy data to ashmem area
    189         memcpy(ashmem_ptr, data, length);
    190 
    191         // munmap ashmem area
    192         if (munmap(ashmem_ptr, length) < 0) {
    193             LOGE("munmap failed: %s", strerror(errno));
    194             jniThrowIOException(env, errno);
    195             close(fd);
    196             return NULL;
    197         }
    198     }
    199 
    200     // Make ashmem area read-only
    201     if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
    202         LOGE("ashmem_set_prot_region failed: %s", strerror(errno));
    203         jniThrowIOException(env, errno);
    204         close(fd);
    205         return NULL;
    206     }
    207 
    208     // Wrap it in a ParcelFileDescriptor
    209     return createParcelFileDescriptor(env, fd);
    210 }
    211 
    212 static jobject native_1x1_blob_ashmem(JNIEnv* env, jobject object)
    213 {
    214     int err;
    215     sqlite3 * handle = GET_HANDLE(env, object);
    216     sqlite3_stmt * statement = GET_STATEMENT(env, object);
    217     jobject value = NULL;
    218 
    219     // Execute the statement
    220     err = sqlite3_step(statement);
    221 
    222     // Handle the result
    223     if (err == SQLITE_ROW) {
    224         // No errors, read the data and return it
    225         const void * blob = sqlite3_column_blob(statement, 0);
    226         if (blob != NULL) {
    227             int len = sqlite3_column_bytes(statement, 0);
    228             if (len >= 0) {
    229                 value = create_ashmem_region_with_data(env, blob, len);
    230             }
    231         }
    232     } else {
    233         throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
    234     }
    235 
    236     // Reset the statment so it's ready to use again
    237     sqlite3_reset(statement);
    238 
    239     return value;
    240 }
    241 
    242 static void native_executeSql(JNIEnv* env, jobject object, jstring sql)
    243 {
    244     char const* sqlString = env->GetStringUTFChars(sql, NULL);
    245     sqlite3 * handle = GET_HANDLE(env, object);
    246     int err = sqlite3_exec(handle, sqlString, NULL, NULL, NULL);
    247     if (err != SQLITE_OK) {
    248         throw_sqlite3_exception(env, handle);
    249     }
    250     env->ReleaseStringUTFChars(sql, sqlString);
    251 }
    252 
    253 static JNINativeMethod sMethods[] =
    254 {
    255      /* name, signature, funcPtr */
    256     {"native_execute", "()I", (void *)native_execute},
    257     {"native_executeInsert", "()J", (void *)native_executeInsert},
    258     {"native_1x1_long", "()J", (void *)native_1x1_long},
    259     {"native_1x1_string", "()Ljava/lang/String;", (void *)native_1x1_string},
    260     {"native_1x1_blob_ashmem", "()Landroid/os/ParcelFileDescriptor;", (void *)native_1x1_blob_ashmem},
    261     {"native_executeSql", "(Ljava/lang/String;)V", (void *)native_executeSql},
    262 };
    263 
    264 int register_android_database_SQLiteStatement(JNIEnv * env)
    265 {
    266     jclass clazz;
    267 
    268     clazz = env->FindClass("android/database/sqlite/SQLiteStatement");
    269     if (clazz == NULL) {
    270         LOGE("Can't find android/database/sqlite/SQLiteStatement");
    271         return -1;
    272     }
    273 
    274     gHandleField = env->GetFieldID(clazz, "nHandle", "I");
    275     gStatementField = env->GetFieldID(clazz, "nStatement", "I");
    276 
    277     if (gHandleField == NULL || gStatementField == NULL) {
    278         LOGE("Error locating fields");
    279         return -1;
    280     }
    281 
    282     return AndroidRuntime::registerNativeMethods(env,
    283         "android/database/sqlite/SQLiteStatement", sMethods, NELEM(sMethods));
    284 }
    285 
    286 } // namespace android
    287