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 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;
    }
}
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) {
#if WINDOW_STORAGE_UTF8
            return strtod((char const *)window->offsetToPtr(field.data.buffer.offset), NULL);
#else
            String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2);
            char const * str = ascii.string();
            return strtod(str, NULL);
#endif
        } 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 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;
    }
}