static jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jlong windowPtr,
        jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);

    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
    if (!fieldSlot) {
        throwExceptionWithRowCol(env, row, column);
        return NULL;
    }

    int32_t type = window->getFieldSlotType(fieldSlot);
    if (type == CursorWindow::FIELD_TYPE_BLOB || type == CursorWindow::FIELD_TYPE_STRING) {
        size_t size;
        const void* value = window->getFieldSlotValueBlob(fieldSlot, &size);
        jbyteArray byteArray = env->NewByteArray(size);
        if (!byteArray) {
            env->ExceptionClear();
            throw_sqlite3_exception(env, "Native could not create new byte[]");
            return NULL;
        }
        env->SetByteArrayRegion(byteArray, 0, size, static_cast<const jbyte*>(value));
        return byteArray;
    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
        throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob ");
    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
        throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob ");
    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
        // do nothing
    } else {
        throwUnknownTypeException(env, type);
    }
    return NULL;
}
static jboolean putBlob_native(JNIEnv * env, jobject object, jbyteArray value, jint row, jint col)
{
    CursorWindow * window = GET_WINDOW(env, object);
    if (!value) {
        LOG_WINDOW("How did a null value send to here");
        return false;
    }
    field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col);
    if (fieldSlot == NULL) {
        LOG_WINDOW(" getFieldSlotWithCheck error ");
        return false;
    }

    jint len = env->GetArrayLength(value);
    int offset = window->alloc(len);
    if (!offset) {
        LOG_WINDOW("Failed allocating %u bytes", len);
        return false;
    }
    jbyte * bytes = env->GetByteArrayElements(value, NULL);
    window->copyIn(offset, (uint8_t const *)bytes, len);

    // This must be updated after the call to alloc(), since that
    // may move the field around in the window
    fieldSlot->type = FIELD_TYPE_BLOB;
    fieldSlot->data.buffer.offset = offset;
    fieldSlot->data.buffer.size = len;
    env->ReleaseByteArrayElements(value, bytes, JNI_ABORT);
    LOG_WINDOW("%d,%d is BLOB with %u bytes @ %d", row, col, len, offset);
    return true;
}
static jbyteArray getBlob_native(JNIEnv* env, jobject object, jint row, jint column)
{
    int32_t err;
    CursorWindow * window = GET_WINDOW(env, object);
LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);

    field_slot_t field;
    err = window->read_field_slot(row, column, &field);
    if (err != 0) {
        throwExceptionWithRowCol(env, row, column);
        return NULL;
    }

    uint8_t type = field.type;
    if (type == FIELD_TYPE_BLOB || type == FIELD_TYPE_STRING) {
        jbyteArray byteArray = env->NewByteArray(field.data.buffer.size);
        LOG_ASSERT(byteArray, "Native could not create new byte[]");
        env->SetByteArrayRegion(byteArray, 0, field.data.buffer.size,
            (const jbyte*)window->offsetToPtr(field.data.buffer.offset));
        return byteArray;
    } else if (type == FIELD_TYPE_INTEGER) {
        throw_sqlite3_exception(env, "INTEGER data in getBlob_native ");
    } else if (type == FIELD_TYPE_FLOAT) {
        throw_sqlite3_exception(env, "FLOAT data in getBlob_native ");
    } else if (type == FIELD_TYPE_NULL) {
        // do nothing
    } else {
        throwUnknowTypeException(env, type);
    }
    return NULL;
}
static void nativeClear(JNIEnv * env, jclass clazz, jlong windowPtr) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    LOG_WINDOW("Clearing window %p", window);
    status_t status = window->clear();
    if (status) {
        LOG_WINDOW("Could not clear window. error=%d", status);
    }
}
static void native_clear(JNIEnv * env, jobject object)
{
    CursorWindow * window = GET_WINDOW(env, object);
LOG_WINDOW("Clearing window %p", window);
    if (window == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "clear() called after close()");
        return;
    }
    window->clear();
}
static jboolean putString_native(JNIEnv * env, jobject object, jstring value, jint row, jint col)
{
    CursorWindow * window = GET_WINDOW(env, object);
    if (!value) {
        LOG_WINDOW("How did a null value send to here");
        return false;
    }
    field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col);
    if (fieldSlot == NULL) {
        LOG_WINDOW(" getFieldSlotWithCheck error ");
        return false;
    }

#if WINDOW_STORAGE_UTF8
    int len = env->GetStringUTFLength(value) + 1;
    char const * valStr = env->GetStringUTFChars(value, NULL);
#else
    int len = env->GetStringLength(value);
    // GetStringLength return number of chars and one char takes 2 bytes
    len *= 2;
    const jchar* valStr = env->GetStringChars(value, NULL);
#endif
    if (!valStr) {
        LOG_WINDOW("value can't be transfer to UTFChars");
        return false;
    }

    int offset = window->alloc(len);
    if (!offset) {
        LOG_WINDOW("Failed allocating %u bytes", len);
#if WINDOW_STORAGE_UTF8
        env->ReleaseStringUTFChars(value, valStr);
#else
        env->ReleaseStringChars(value, valStr);
#endif
        return false;
    }

    window->copyIn(offset, (uint8_t const *)valStr, len);

    // This must be updated after the call to alloc(), since that
    // may move the field around in the window
    fieldSlot->type = FIELD_TYPE_STRING;
    fieldSlot->data.buffer.offset = offset;
    fieldSlot->data.buffer.size = len;

    LOG_WINDOW("%d,%d is TEXT with %u bytes @ %d", row, col, len, offset);
#if WINDOW_STORAGE_UTF8
    env->ReleaseStringUTFChars(value, valStr);
#else
    env->ReleaseStringChars(value, valStr);
#endif

    return true;
}
static jint nativeGetType(JNIEnv* env, jclass clazz, jlong windowPtr,
        jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);

    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
    if (!fieldSlot) {
        return CursorWindow::FIELD_TYPE_NULL;
    }
    return window->getFieldSlotType(fieldSlot);
}
static jboolean putNull_native(JNIEnv * env, jobject object, jint row, jint col)
{
    CursorWindow * window = GET_WINDOW(env, object);
    if (!window->putNull(row, col)) {
        LOG_WINDOW(" getFieldSlotWithCheck error ");
        return false;
    }

    LOG_WINDOW("%d,%d is NULL", row, col);

    return true;
}
static jobject native_getBinder(JNIEnv * env, jobject object)
{
    CursorWindow * window = GET_WINDOW(env, object);
    if (window) {
        sp<IMemory> memory = window->getMemory();
        if (memory != NULL) {
            sp<IBinder> binder = memory->asBinder();
            return javaObjectForIBinder(env, binder);
        }
    }
    return NULL;
}
static void nativeWriteToParcel(JNIEnv * env, jclass clazz, jlong windowPtr,
        jobject parcelObj) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    Parcel* parcel = parcelForJavaObject(env, parcelObj);

    status_t status = window->writeToParcel(parcel);
    if (status) {
        String8 msg;
        msg.appendFormat("Could not write CursorWindow to Parcel due to error %d.", status);
        jniThrowRuntimeException(env, msg.string());
    }
}
static jboolean putDouble_native(JNIEnv * env, jobject object, jdouble value, jint row, jint col)
{
    CursorWindow * window = GET_WINDOW(env, object);
    if (!window->putDouble(row, col, value)) {
        LOG_WINDOW(" getFieldSlotWithCheck error ");
        return false;
    }

    LOG_WINDOW("%d,%d is FLOAT %lf", row, col, value);

    return true;
}
static void nativeWriteToParcel(JNIEnv * env, jclass clazz, jint windowPtr,
        jobject parcelObj) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    Parcel* parcel = parcelForJavaObject(env, parcelObj);

    status_t status = window->writeToParcel(parcel);
    if (status) {
    	char buf[100];
		snprintf(buf, sizeof(buf), "Could not write CursorWindow to Parcel due to error %d.", status);
		jniThrowException(env, "java/lang/IllegalStateException", buf);
    }
}
static jboolean putLong_native(JNIEnv * env, jobject object, jlong value, jint row, jint col)
{
    CursorWindow * window = GET_WINDOW(env, object);
    if (!window->putLong(row, col, value)) {
        LOG_WINDOW(" getFieldSlotWithCheck error ");
        return false;
    }

    LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, col, value);

    return true;
}
static jboolean nativePutDouble(JNIEnv* env, jclass clazz, jlong windowPtr,
        jdouble value, jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    status_t status = window->putDouble(row, column, value);

    if (status) {
        LOG_WINDOW("Failed to put double. error=%d", status);
        return false;
    }

    LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value);
    return true;
}
static jboolean nativePutLong(JNIEnv* env, jclass clazz, jlong windowPtr,
        jlong value, jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    status_t status = window->putLong(row, column, value);

    if (status) {
        LOG_WINDOW("Failed to put long. error=%d", status);
        return false;
    }

    LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value);
    return true;
}
static jboolean nativePutNull(JNIEnv* env, jclass clazz, jlong windowPtr,
        jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    status_t status = window->putNull(row, column);

    if (status) {
        LOG_WINDOW("Failed to put null. error=%d", status);
        return false;
    }

    LOG_WINDOW("%d,%d is NULL", row, column);
    return true;
}
static jboolean isNull_native(JNIEnv* env, jobject object, jint row, jint column)
{
    CursorWindow * window = GET_WINDOW(env, object);
LOG_WINDOW("Checking for NULL at %d,%d from %p", row, column, window);

    bool isNull;
    if (window->getNull(row, column, &isNull)) {
        return isNull;
    }

    //TODO throw execption?
    return true;
}
static jint nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
    Parcel* parcel = parcelForJavaObject(env, parcelObj);

    CursorWindow* window;
    status_t status = CursorWindow::createFromParcel(parcel, &window);
    if (status || !window) {
        LOGE("Could not create CursorWindow from Parcel due to error %d.", status);
        return 0;
    }

    LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p",
            window->getNumRows(), window->getNumColumns(), window);
    return reinterpret_cast<jint>(window);
}
static jint nativeGetType(JNIEnv* env, jclass clazz, jlong windowPtr,
        jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);

    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
    if (!fieldSlot) {
        // FIXME: This is really broken but we have CTS tests that depend
        // on this legacy behavior.
        //throwExceptionWithRowCol(env, row, column);
        return CursorWindow::FIELD_TYPE_NULL;
    }
    return window->getFieldSlotType(fieldSlot);
}
static jdouble getDouble_native(JNIEnv* env, jobject object, jint row, jint column)
{
    int32_t err;
    CursorWindow * window = GET_WINDOW(env, object);
LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);

    field_slot_t field;
    err = window->read_field_slot(row, column, &field);
    if (err != 0) {
        throwExceptionWithRowCol(env, row, column);
        return 0.0;
    }

    uint8_t type = field.type;
    if (type == FIELD_TYPE_FLOAT) {
        double value;
        if (window->getDouble(row, column, &value)) {
            return value;
        }
        return 0.0;
    } else if (type == FIELD_TYPE_STRING) {
        uint32_t size = field.data.buffer.size;
        if (size > 0) {
          double result;
          jstring data = env->NewString((const jchar*)window->offsetToPtr(field.data.buffer.offset), (jsize)size);
          const char* utf8data = env->GetStringUTFChars(data, NULL);
          result = strtod(utf8data, NULL);
          if(utf8data) env->ReleaseStringUTFChars(data, utf8data);
          if(data) env->DeleteLocalRef(data);
          return result;
        } else {
            return 0.0;
        }
    } else if (type == FIELD_TYPE_INTEGER) {
        int64_t value;
        if (window->getLong(row, column, &value)) {
            return (double) value;
        }
        return 0.0;
    } else if (type == FIELD_TYPE_NULL) {
        return 0.0;
    } else if (type == FIELD_TYPE_BLOB) {
        throw_sqlite3_exception(env, "Unable to convert BLOB to double");
        return 0.0;
    } else {
        throwUnknowTypeException(env, type);
        return 0.0;
    }
}
static jint getType_native(JNIEnv* env, jobject object, jint row, jint column)
{
    int32_t err;
    CursorWindow * window = GET_WINDOW(env, object);
LOG_WINDOW("Getting type for %d,%d from %p", row, column, window);

    field_slot_t field;
    err = window->read_field_slot(row, column, &field);
    if (err != 0) {
        throwExceptionWithRowCol(env, row, column);
        return NULL;
    }

    return field.type;
}
static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column)
{
    int32_t err;
    CursorWindow * window = GET_WINDOW(env, object);
LOG_WINDOW("Checking if column is a float for %d,%d from %p", row, column, window);

    field_slot_t field;
    err = window->read_field_slot(row, column, &field);
    if (err != 0) {
        throwExceptionWithRowCol(env, row, column);
        return NULL;
    }

    return field.type == FIELD_TYPE_FLOAT;
}
static jboolean nativePutBlob(JNIEnv* env, jclass clazz, jlong windowPtr,
        jbyteArray valueObj, jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    jsize len = env->GetArrayLength(valueObj);

    void* value = env->GetPrimitiveArrayCritical(valueObj, NULL);
    status_t status = window->putBlob(row, column, value, len);
    env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT);

    if (status) {
        LOG_WINDOW("Failed to put blob. error=%d", status);
        return false;
    }

    LOG_WINDOW("%d,%d is BLOB with %u bytes", row, column, len);
    return true;
}
Пример #24
0
status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
    String8 ashmemName("CursorWindow: ");
    ashmemName.append(name);

    status_t result;
    int ashmemFd = ashmem_create_region(ashmemName.string(), size);
    if (ashmemFd < 0) {
    	ALOG(LOG_ERROR,LOG_TAG,"CursorWindow::create, ashmem_create_region return errno = %d",errno);
        result = -errno;
    } else {
        result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
        if (result >= 0) {
            void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
            if (data == MAP_FAILED) {
            	ALOG(LOG_ERROR,LOG_TAG,"CursorWindow::create, mmap return errno = %d",errno);
                result = -errno;
            } else {
                result = ashmem_set_prot_region(ashmemFd, PROT_READ);
                if (result >= 0) {
                    CursorWindow* window = new CursorWindow(name, ashmemFd,
                            data, size, false /*readOnly*/);
                    result = window->clear();
                    if (!result) {
                        LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
                                "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                                window->mHeader->freeOffset,
                                window->mHeader->numRows,
                                window->mHeader->numColumns,
                                window->mSize, window->mData);
                        *outCursorWindow = window;
                        return OK;
                    }
                    ALOG(LOG_ERROR,LOG_TAG,"CursorWindow::create, window->clear return errno = %d",errno);
                    delete window;
                } else {
                    ALOG(LOG_ERROR,LOG_TAG,"CursorWindow::create, ashmeme_set_prot_region return errno = %d",errno);	
                }
            }
            ::munmap(data, size);
        }
        ::close(ashmemFd);
    }
    *outCursorWindow = NULL;
    return result;
}
static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column)
{
  int i;
    int32_t err;
    CursorWindow * window = GET_WINDOW(env, object);
    LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
    field_slot_t field;
    err = window->read_field_slot(row, column, &field);
    if (err != 0) {
        throwExceptionWithRowCol(env, row, column);
        return NULL;
    }
    uint8_t type = field.type;
    jint size = (jint)field.data.buffer.size;
    if (type == FIELD_TYPE_NULL) {
         return NULL;
    } else if (type == FIELD_TYPE_BLOB) {
        throw_sqlite3_exception(env, "Unable to convert BLOB to string");
        return NULL;
    } else if (type == FIELD_TYPE_STRING) {
      jchar * buf = (jchar *)window->offsetToPtr(field.data.buffer.offset);
      jclass strClass = env->FindClass("java/lang/String"); 
      jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V"); 
      jstring encoding = env->NewStringUTF("UTF-16LE");
      jbyteArray bytes = env->NewByteArray(size); 
      env->SetByteArrayRegion(bytes, 0, size, (jbyte*)buf);
      return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
    } else if (type == FIELD_TYPE_INTEGER) {
        int64_t value;
        if (window->getLong(row, column, &value)) {
          char buf[32];
          snprintf(buf, sizeof(buf), "%lld", value);
          return env->NewStringUTF((const char*)buf);
        }
        return NULL;
    } else if (type == FIELD_TYPE_FLOAT) {
        double value;
        if (window->getDouble(row, column, &value)) {
            char buf[32];
            snprintf(buf, sizeof(buf), "%g", value);
            return env->NewStringUTF(buf);
        }
        return NULL;
    }
}
static jboolean nativePutString(JNIEnv* env, jclass clazz, jlong windowPtr,
        jstring valueObj, jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);

    size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1;
    const char* valueStr = env->GetStringUTFChars(valueObj, NULL);
    if (!valueStr) {
        LOG_WINDOW("value can't be transferred to UTFChars");
        return false;
    }
    status_t status = window->putString(row, column, valueStr, sizeIncludingNull);
    env->ReleaseStringUTFChars(valueObj, valueStr);

    if (status) {
        LOG_WINDOW("Failed to put string. error=%d", status);
        return false;
    }

    LOG_WINDOW("%d,%d is TEXT with %u bytes", row, column, sizeIncludingNull);
    return true;
}
static void native_init_empty(JNIEnv * env, jobject object, jboolean localOnly)
{
    uint8_t * data;
    size_t size;
    CursorWindow * window;

    window = new CursorWindow(MAX_WINDOW_SIZE);
    if (!window) {
        jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object");
        return;
    }

    if (!window->initBuffer(localOnly)) {
        jniThrowException(env, "java/lang/IllegalStateException", "Couldn't init cursor window");
        delete window;
        return;
    }

LOG_WINDOW("native_init_empty: window = %p", window);
    SET_WINDOW(env, object, window);
}
static jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jlong windowPtr,
        jint row, jint column) {
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);

    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
    if (!fieldSlot) {
        throwExceptionWithRowCol(env, row, column);
        return 0.0;
    }

    int32_t type = window->getFieldSlotType(fieldSlot);
    if (type == CursorWindow::FIELD_TYPE_FLOAT) {
        return window->getFieldSlotValueDouble(fieldSlot);
    } else if (type == CursorWindow::FIELD_TYPE_STRING) {
        size_t sizeIncludingNull;
        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
        return sizeIncludingNull > 1 ? strtod(value, NULL) : 0.0;
    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
        return jdouble(window->getFieldSlotValueLong(fieldSlot));
    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
        return 0.0;
    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
        throw_sqlite3_exception(env, "Unable to convert BLOB to double");
        return 0.0;
    } else {
        throwUnknownTypeException(env, type);
        return 0.0;
    }
}
static void native_init_memory(JNIEnv * env, jobject object, jobject memObj)
{
    sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, memObj));
    if (memory == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "Couldn't get native binder");
        return;
    }

    CursorWindow * window = new CursorWindow();
    if (!window) {
        jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object");
        return;
    }
    if (!window->setMemory(memory)) {
        jniThrowException(env, "java/lang/RuntimeException", "No memory in memObj");
        delete window;
        return;
    }

LOG_WINDOW("native_init_memory: numRows = %d, numColumns = %d, window = %p", window->getNumRows(), window->getNumColumns(), window);
    SET_WINDOW(env, object, window);
}
static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column)
{
    int32_t err;
    CursorWindow * window = GET_WINDOW(env, object);
LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);

    field_slot_t field;
    err = window->read_field_slot(row, column, &field);
    if (err != 0) {
        throwExceptionWithRowCol(env, row, column);
        return NULL;
    }

    uint8_t type = field.type;
    if (type == FIELD_TYPE_STRING) {
        uint32_t size = field.data.buffer.size;
        if (size > 0) {
#if WINDOW_STORAGE_UTF8
            // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string
            String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1);
            return env->NewString((jchar const *)utf16.string(), utf16.size());
#else
            return env->NewString((jchar const *)window->offsetToPtr(field.data.buffer.offset), size / 2);
#endif
        } else {
            return env->NewStringUTF("");
        }
    } else if (type == FIELD_TYPE_INTEGER) {
        int64_t value;
        if (window->getLong(row, column, &value)) {
            char buf[32];
            snprintf(buf, sizeof(buf), "%lld", value);
            return env->NewStringUTF(buf);
        }
        return NULL;
    } else if (type == FIELD_TYPE_FLOAT) {
        double value;
        if (window->getDouble(row, column, &value)) {
            char buf[32];
            //selete the print way by code to impove the precision
            if (((value > 0.0001) && (value < 1000000)) || ((value < -0.0001) && (value > -1000000)))
                snprintf(buf, sizeof(buf), "%lf", value);
            else
                snprintf(buf, sizeof(buf), "%e", value);

            return env->NewStringUTF(buf);
        }
        return NULL;
    } else if (type == FIELD_TYPE_NULL) {
        return NULL;
    } else if (type == FIELD_TYPE_BLOB) {
        throw_sqlite3_exception(env, "Unable to convert BLOB to string");
        return NULL;
    } else {
        throwUnknowTypeException(env, type);
        return NULL;
    }
}