blob: e96613b7d45b96b29e746b805586594d02220f13 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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#undef LOG_TAG
18#define LOG_TAG "CursorWindow"
Amith Yamasani0903ec52016-08-26 09:22:36 -070019#define LOG_NDEBUG 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020
Mark Salyzyn85394032014-04-16 10:28:37 -070021#include <inttypes.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022#include <jni.h>
23#include <JNIHelp.h>
24#include <android_runtime/AndroidRuntime.h>
25
26#include <utils/Log.h>
27#include <utils/String8.h>
28#include <utils/String16.h>
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070029#include <utils/Unicode.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
31#include <stdio.h>
32#include <string.h>
33#include <unistd.h>
Amith Yamasani0903ec52016-08-26 09:22:36 -070034#include <sys/types.h>
35#include <dirent.h>
36
37#undef LOG_NDEBUG
38#define LOG_NDEBUG 1
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
Mathias Agopian49d2b182012-02-27 18:11:20 -080040#include <androidfw/CursorWindow.h>
Jeff Sharkeyd84e1ce2012-03-06 18:26:19 -080041#include "android_os_Parcel.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042#include "android_util_Binder.h"
Jeff Browne5360fb2011-10-31 17:48:13 -070043#include "android_database_SQLiteCommon.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
Andreas Gampe987f79f2014-11-18 17:29:46 -080045#include "core_jni_helpers.h"
46
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047namespace android {
48
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070049static struct {
50 jfieldID data;
51 jfieldID sizeCopied;
52} gCharArrayBufferClassInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070054static jstring gEmptyString;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070056static void throwExceptionWithRowCol(JNIEnv* env, jint row, jint column) {
57 String8 msg;
58 msg.appendFormat("Couldn't read row %d, col %d from CursorWindow. "
59 "Make sure the Cursor is initialized correctly before accessing data from it.",
60 row, column);
61 jniThrowException(env, "java/lang/IllegalStateException", msg.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062}
63
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070064static void throwUnknownTypeException(JNIEnv * env, jint type) {
65 String8 msg;
66 msg.appendFormat("UNKNOWN type %d", type);
67 jniThrowException(env, "java/lang/IllegalStateException", msg.string());
68}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
Amith Yamasani0903ec52016-08-26 09:22:36 -070070static int getFdCount() {
71 char fdpath[PATH_MAX];
72 int count = 0;
73 snprintf(fdpath, PATH_MAX, "/proc/%d/fd", getpid());
74 DIR *dir = opendir(fdpath);
75 if (dir != NULL) {
76 struct dirent *dirent;
77 while ((dirent = readdir(dir))) {
78 count++;
79 }
80 count -= 2; // discount "." and ".."
81 closedir(dir);
82 }
83 return count;
84}
85
Ashok Bhat738702d2014-01-02 13:42:56 +000086static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
Jeff Brown0cde89f2011-10-10 14:50:10 -070087 String8 name;
Jeff Brown5a05c232012-01-12 12:04:22 -080088 const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
89 name.setTo(nameStr);
90 env->ReleaseStringUTFChars(nameObj, nameStr);
Jeff Brown0cde89f2011-10-10 14:50:10 -070091
92 CursorWindow* window;
Jeff Brown5e5d6d82011-10-12 15:41:34 -070093 status_t status = CursorWindow::create(name, cursorWindowSize, &window);
Jeff Brown0cde89f2011-10-10 14:50:10 -070094 if (status || !window) {
Steve Block3762c312012-01-06 19:20:56 +000095 ALOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
Jeff Brown0cde89f2011-10-10 14:50:10 -070096 name.string(), cursorWindowSize, status);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070097 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 }
99
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700100 LOG_WINDOW("nativeInitializeEmpty: window = %p", window);
Ashok Bhat738702d2014-01-02 13:42:56 +0000101 return reinterpret_cast<jlong>(window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102}
103
Ashok Bhat738702d2014-01-02 13:42:56 +0000104static jlong nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700105 Parcel* parcel = parcelForJavaObject(env, parcelObj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Jeff Brown0cde89f2011-10-10 14:50:10 -0700107 CursorWindow* window;
108 status_t status = CursorWindow::createFromParcel(parcel, &window);
109 if (status || !window) {
Amith Yamasani0903ec52016-08-26 09:22:36 -0700110 ALOGE("Could not create CursorWindow from Parcel due to error %d, process fd count=%d",
111 status, getFdCount());
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700112 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 }
114
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700115 LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p",
116 window->getNumRows(), window->getNumColumns(), window);
Ashok Bhat738702d2014-01-02 13:42:56 +0000117 return reinterpret_cast<jlong>(window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118}
119
Ashok Bhat738702d2014-01-02 13:42:56 +0000120static void nativeDispose(JNIEnv* env, jclass clazz, jlong windowPtr) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700121 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
122 if (window) {
123 LOG_WINDOW("Closing window %p", window);
124 delete window;
125 }
126}
127
Ashok Bhat738702d2014-01-02 13:42:56 +0000128static jstring nativeGetName(JNIEnv* env, jclass clazz, jlong windowPtr) {
Jeff Brown650de3d2011-10-27 14:52:28 -0700129 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
130 return env->NewStringUTF(window->name().string());
131}
132
Ashok Bhat738702d2014-01-02 13:42:56 +0000133static void nativeWriteToParcel(JNIEnv * env, jclass clazz, jlong windowPtr,
Jeff Brown0cde89f2011-10-10 14:50:10 -0700134 jobject parcelObj) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700135 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700136 Parcel* parcel = parcelForJavaObject(env, parcelObj);
137
138 status_t status = window->writeToParcel(parcel);
139 if (status) {
140 String8 msg;
141 msg.appendFormat("Could not write CursorWindow to Parcel due to error %d.", status);
142 jniThrowRuntimeException(env, msg.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144}
145
Ashok Bhat738702d2014-01-02 13:42:56 +0000146static void nativeClear(JNIEnv * env, jclass clazz, jlong windowPtr) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700147 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
148 LOG_WINDOW("Clearing window %p", window);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700149 status_t status = window->clear();
150 if (status) {
151 LOG_WINDOW("Could not clear window. error=%d", status);
152 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153}
154
Ashok Bhat738702d2014-01-02 13:42:56 +0000155static jint nativeGetNumRows(JNIEnv* env, jclass clazz, jlong windowPtr) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700156 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
157 return window->getNumRows();
158}
159
Ashok Bhat738702d2014-01-02 13:42:56 +0000160static jboolean nativeSetNumColumns(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700161 jint columnNum) {
162 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700163 status_t status = window->setNumColumns(columnNum);
164 return status == OK;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700165}
166
Ashok Bhat738702d2014-01-02 13:42:56 +0000167static jboolean nativeAllocRow(JNIEnv* env, jclass clazz, jlong windowPtr) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700168 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700169 status_t status = window->allocRow();
170 return status == OK;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700171}
172
Ashok Bhat738702d2014-01-02 13:42:56 +0000173static void nativeFreeLastRow(JNIEnv* env, jclass clazz, jlong windowPtr) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700174 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
175 window->freeLastRow();
176}
177
Ashok Bhat738702d2014-01-02 13:42:56 +0000178static jint nativeGetType(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700179 jint row, jint column) {
180 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
181 LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
182
Jeff Brown0cde89f2011-10-10 14:50:10 -0700183 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700184 if (!fieldSlot) {
Jeff Brownaa32c302011-10-07 13:15:59 -0700185 // FIXME: This is really broken but we have CTS tests that depend
186 // on this legacy behavior.
187 //throwExceptionWithRowCol(env, row, column);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700188 return CursorWindow::FIELD_TYPE_NULL;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700189 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700190 return window->getFieldSlotType(fieldSlot);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700191}
192
Ashok Bhat738702d2014-01-02 13:42:56 +0000193static jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700194 jint row, jint column) {
195 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
196 LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);
197
Jeff Brown0cde89f2011-10-10 14:50:10 -0700198 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700199 if (!fieldSlot) {
200 throwExceptionWithRowCol(env, row, column);
201 return NULL;
202 }
203
Jeff Brown0cde89f2011-10-10 14:50:10 -0700204 int32_t type = window->getFieldSlotType(fieldSlot);
205 if (type == CursorWindow::FIELD_TYPE_BLOB || type == CursorWindow::FIELD_TYPE_STRING) {
206 size_t size;
207 const void* value = window->getFieldSlotValueBlob(fieldSlot, &size);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700208 jbyteArray byteArray = env->NewByteArray(size);
209 if (!byteArray) {
210 env->ExceptionClear();
211 throw_sqlite3_exception(env, "Native could not create new byte[]");
212 return NULL;
213 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700214 env->SetByteArrayRegion(byteArray, 0, size, static_cast<const jbyte*>(value));
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700215 return byteArray;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700216 } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700217 throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob ");
Jeff Brown0cde89f2011-10-10 14:50:10 -0700218 } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700219 throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob ");
Jeff Brown0cde89f2011-10-10 14:50:10 -0700220 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700221 // do nothing
222 } else {
223 throwUnknownTypeException(env, type);
224 }
225 return NULL;
226}
227
Ashok Bhat738702d2014-01-02 13:42:56 +0000228static jstring nativeGetString(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700229 jint row, jint column) {
230 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
231 LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
232
Jeff Brown0cde89f2011-10-10 14:50:10 -0700233 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700234 if (!fieldSlot) {
235 throwExceptionWithRowCol(env, row, column);
236 return NULL;
237 }
238
Jeff Brown0cde89f2011-10-10 14:50:10 -0700239 int32_t type = window->getFieldSlotType(fieldSlot);
240 if (type == CursorWindow::FIELD_TYPE_STRING) {
241 size_t sizeIncludingNull;
242 const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
243 if (sizeIncludingNull <= 1) {
Jeff Brown715311f2011-10-07 14:17:09 -0700244 return gEmptyString;
245 }
246 // Convert to UTF-16 here instead of calling NewStringUTF. NewStringUTF
247 // doesn't like UTF-8 strings with high codepoints. It actually expects
248 // Modified UTF-8 with encoded surrogate pairs.
Jeff Brown0cde89f2011-10-10 14:50:10 -0700249 String16 utf16(value, sizeIncludingNull - 1);
Jeff Brown715311f2011-10-07 14:17:09 -0700250 return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size());
Jeff Brown0cde89f2011-10-10 14:50:10 -0700251 } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700252 int64_t value = window->getFieldSlotValueLong(fieldSlot);
253 char buf[32];
Mark Salyzyn85394032014-04-16 10:28:37 -0700254 snprintf(buf, sizeof(buf), "%" PRId64, value);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700255 return env->NewStringUTF(buf);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700256 } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700257 double value = window->getFieldSlotValueDouble(fieldSlot);
258 char buf[32];
259 snprintf(buf, sizeof(buf), "%g", value);
260 return env->NewStringUTF(buf);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700261 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700262 return NULL;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700263 } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700264 throw_sqlite3_exception(env, "Unable to convert BLOB to string");
265 return NULL;
266 } else {
267 throwUnknownTypeException(env, type);
268 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 }
270}
271
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700272static jcharArray allocCharArrayBuffer(JNIEnv* env, jobject bufferObj, size_t size) {
273 jcharArray dataObj = jcharArray(env->GetObjectField(bufferObj,
274 gCharArrayBufferClassInfo.data));
275 if (dataObj && size) {
276 jsize capacity = env->GetArrayLength(dataObj);
277 if (size_t(capacity) < size) {
278 env->DeleteLocalRef(dataObj);
279 dataObj = NULL;
280 }
281 }
282 if (!dataObj) {
283 jsize capacity = size;
284 if (capacity < 64) {
285 capacity = 64;
286 }
287 dataObj = env->NewCharArray(capacity); // might throw OOM
288 if (dataObj) {
289 env->SetObjectField(bufferObj, gCharArrayBufferClassInfo.data, dataObj);
290 }
291 }
292 return dataObj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293}
294
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700295static void fillCharArrayBufferUTF(JNIEnv* env, jobject bufferObj,
296 const char* str, size_t len) {
297 ssize_t size = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str), len);
298 if (size < 0) {
299 size = 0; // invalid UTF8 string
300 }
301 jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, size);
302 if (dataObj) {
303 if (size) {
304 jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL));
Jeff Brownd0ff68d2011-10-07 13:28:18 -0700305 utf8_to_utf16_no_null_terminator(reinterpret_cast<const uint8_t*>(str), len,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700306 reinterpret_cast<char16_t*>(data));
307 env->ReleasePrimitiveArrayCritical(dataObj, data, 0);
308 }
309 env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, size);
310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311}
312
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700313static void clearCharArrayBuffer(JNIEnv* env, jobject bufferObj) {
314 jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, 0);
315 if (dataObj) {
316 env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, 0);
317 }
318}
319
Ashok Bhat738702d2014-01-02 13:42:56 +0000320static void nativeCopyStringToBuffer(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700321 jint row, jint column, jobject bufferObj) {
322 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
323 LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
324
Jeff Brown0cde89f2011-10-10 14:50:10 -0700325 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700326 if (!fieldSlot) {
327 throwExceptionWithRowCol(env, row, column);
328 return;
329 }
330
Jeff Brown0cde89f2011-10-10 14:50:10 -0700331 int32_t type = window->getFieldSlotType(fieldSlot);
332 if (type == CursorWindow::FIELD_TYPE_STRING) {
333 size_t sizeIncludingNull;
334 const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
335 if (sizeIncludingNull > 1) {
336 fillCharArrayBufferUTF(env, bufferObj, value, sizeIncludingNull - 1);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700337 } else {
338 clearCharArrayBuffer(env, bufferObj);
339 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700340 } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700341 int64_t value = window->getFieldSlotValueLong(fieldSlot);
342 char buf[32];
Mark Salyzyn85394032014-04-16 10:28:37 -0700343 snprintf(buf, sizeof(buf), "%" PRId64, value);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700344 fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700345 } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700346 double value = window->getFieldSlotValueDouble(fieldSlot);
347 char buf[32];
348 snprintf(buf, sizeof(buf), "%g", value);
349 fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700350 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700351 clearCharArrayBuffer(env, bufferObj);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700352 } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700353 throw_sqlite3_exception(env, "Unable to convert BLOB to string");
354 } else {
355 throwUnknownTypeException(env, type);
356 }
357}
358
Ashok Bhat738702d2014-01-02 13:42:56 +0000359static jlong nativeGetLong(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700360 jint row, jint column) {
361 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
362 LOG_WINDOW("Getting long for %d,%d from %p", row, column, window);
363
Jeff Brown0cde89f2011-10-10 14:50:10 -0700364 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700365 if (!fieldSlot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 throwExceptionWithRowCol(env, row, column);
367 return 0;
368 }
369
Jeff Brown0cde89f2011-10-10 14:50:10 -0700370 int32_t type = window->getFieldSlotType(fieldSlot);
371 if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700372 return window->getFieldSlotValueLong(fieldSlot);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700373 } else if (type == CursorWindow::FIELD_TYPE_STRING) {
374 size_t sizeIncludingNull;
375 const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
376 return sizeIncludingNull > 1 ? strtoll(value, NULL, 0) : 0L;
377 } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700378 return jlong(window->getFieldSlotValueDouble(fieldSlot));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700379 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 return 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700381 } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 throw_sqlite3_exception(env, "Unable to convert BLOB to long");
383 return 0;
384 } else {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700385 throwUnknownTypeException(env, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 return 0;
387 }
388}
389
Ashok Bhat738702d2014-01-02 13:42:56 +0000390static jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700391 jint row, jint column) {
392 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
393 LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394
Jeff Brown0cde89f2011-10-10 14:50:10 -0700395 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700396 if (!fieldSlot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 throwExceptionWithRowCol(env, row, column);
398 return 0.0;
399 }
400
Jeff Brown0cde89f2011-10-10 14:50:10 -0700401 int32_t type = window->getFieldSlotType(fieldSlot);
402 if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700403 return window->getFieldSlotValueDouble(fieldSlot);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700404 } else if (type == CursorWindow::FIELD_TYPE_STRING) {
405 size_t sizeIncludingNull;
406 const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
407 return sizeIncludingNull > 1 ? strtod(value, NULL) : 0.0;
408 } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700409 return jdouble(window->getFieldSlotValueLong(fieldSlot));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700410 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 return 0.0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700412 } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 throw_sqlite3_exception(env, "Unable to convert BLOB to double");
414 return 0.0;
415 } else {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700416 throwUnknownTypeException(env, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 return 0.0;
418 }
419}
420
Ashok Bhat738702d2014-01-02 13:42:56 +0000421static jboolean nativePutBlob(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700422 jbyteArray valueObj, jint row, jint column) {
423 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700424 jsize len = env->GetArrayLength(valueObj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700426 void* value = env->GetPrimitiveArrayCritical(valueObj, NULL);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700427 status_t status = window->putBlob(row, column, value, len);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700428 env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT);
429
Jeff Brown0cde89f2011-10-10 14:50:10 -0700430 if (status) {
431 LOG_WINDOW("Failed to put blob. error=%d", status);
432 return false;
433 }
434
435 LOG_WINDOW("%d,%d is BLOB with %u bytes", row, column, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 return true;
437}
438
Ashok Bhat738702d2014-01-02 13:42:56 +0000439static jboolean nativePutString(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700440 jstring valueObj, jint row, jint column) {
441 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442
Jeff Brown0cde89f2011-10-10 14:50:10 -0700443 size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700444 const char* valueStr = env->GetStringUTFChars(valueObj, NULL);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700445 if (!valueStr) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700446 LOG_WINDOW("value can't be transferred to UTFChars");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 return false;
448 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700449 status_t status = window->putString(row, column, valueStr, sizeIncludingNull);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700450 env->ReleaseStringUTFChars(valueObj, valueStr);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700451
Jeff Brown0cde89f2011-10-10 14:50:10 -0700452 if (status) {
453 LOG_WINDOW("Failed to put string. error=%d", status);
454 return false;
455 }
456
457 LOG_WINDOW("%d,%d is TEXT with %u bytes", row, column, sizeIncludingNull);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 return true;
459}
460
Ashok Bhat738702d2014-01-02 13:42:56 +0000461static jboolean nativePutLong(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700462 jlong value, jint row, jint column) {
463 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700464 status_t status = window->putLong(row, column, value);
465
466 if (status) {
467 LOG_WINDOW("Failed to put long. error=%d", status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 return false;
469 }
470
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700471 LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 return true;
473}
474
Ashok Bhat738702d2014-01-02 13:42:56 +0000475static jboolean nativePutDouble(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700476 jdouble value, jint row, jint column) {
477 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700478 status_t status = window->putDouble(row, column, value);
479
480 if (status) {
481 LOG_WINDOW("Failed to put double. error=%d", status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 return false;
483 }
484
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700485 LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 return true;
487}
488
Ashok Bhat738702d2014-01-02 13:42:56 +0000489static jboolean nativePutNull(JNIEnv* env, jclass clazz, jlong windowPtr,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700490 jint row, jint column) {
491 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700492 status_t status = window->putNull(row, column);
493
494 if (status) {
495 LOG_WINDOW("Failed to put null. error=%d", status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 return false;
497 }
498
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700499 LOG_WINDOW("%d,%d is NULL", row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 return true;
501}
502
Daniel Micay76f6a862015-09-19 17:31:01 -0400503static const JNINativeMethod sMethods[] =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504{
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700505 /* name, signature, funcPtr */
Ashok Bhat738702d2014-01-02 13:42:56 +0000506 { "nativeCreate", "(Ljava/lang/String;I)J",
Jeff Brown0cde89f2011-10-10 14:50:10 -0700507 (void*)nativeCreate },
Ashok Bhat738702d2014-01-02 13:42:56 +0000508 { "nativeCreateFromParcel", "(Landroid/os/Parcel;)J",
Jeff Brown0cde89f2011-10-10 14:50:10 -0700509 (void*)nativeCreateFromParcel },
Ashok Bhat738702d2014-01-02 13:42:56 +0000510 { "nativeDispose", "(J)V",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700511 (void*)nativeDispose },
Ashok Bhat738702d2014-01-02 13:42:56 +0000512 { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
Jeff Brown0cde89f2011-10-10 14:50:10 -0700513 (void*)nativeWriteToParcel },
Ashok Bhat738702d2014-01-02 13:42:56 +0000514 { "nativeGetName", "(J)Ljava/lang/String;",
Jeff Brown650de3d2011-10-27 14:52:28 -0700515 (void*)nativeGetName },
Ashok Bhat738702d2014-01-02 13:42:56 +0000516 { "nativeClear", "(J)V",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700517 (void*)nativeClear },
Ashok Bhat738702d2014-01-02 13:42:56 +0000518 { "nativeGetNumRows", "(J)I",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700519 (void*)nativeGetNumRows },
Ashok Bhat738702d2014-01-02 13:42:56 +0000520 { "nativeSetNumColumns", "(JI)Z",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700521 (void*)nativeSetNumColumns },
Ashok Bhat738702d2014-01-02 13:42:56 +0000522 { "nativeAllocRow", "(J)Z",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700523 (void*)nativeAllocRow },
Ashok Bhat738702d2014-01-02 13:42:56 +0000524 { "nativeFreeLastRow", "(J)V",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700525 (void*)nativeFreeLastRow },
Ashok Bhat738702d2014-01-02 13:42:56 +0000526 { "nativeGetType", "(JII)I",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700527 (void*)nativeGetType },
Ashok Bhat738702d2014-01-02 13:42:56 +0000528 { "nativeGetBlob", "(JII)[B",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700529 (void*)nativeGetBlob },
Ashok Bhat738702d2014-01-02 13:42:56 +0000530 { "nativeGetString", "(JII)Ljava/lang/String;",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700531 (void*)nativeGetString },
Ashok Bhat738702d2014-01-02 13:42:56 +0000532 { "nativeGetLong", "(JII)J",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700533 (void*)nativeGetLong },
Ashok Bhat738702d2014-01-02 13:42:56 +0000534 { "nativeGetDouble", "(JII)D",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700535 (void*)nativeGetDouble },
Ashok Bhat738702d2014-01-02 13:42:56 +0000536 { "nativeCopyStringToBuffer", "(JIILandroid/database/CharArrayBuffer;)V",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700537 (void*)nativeCopyStringToBuffer },
Ashok Bhat738702d2014-01-02 13:42:56 +0000538 { "nativePutBlob", "(J[BII)Z",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700539 (void*)nativePutBlob },
Ashok Bhat738702d2014-01-02 13:42:56 +0000540 { "nativePutString", "(JLjava/lang/String;II)Z",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700541 (void*)nativePutString },
Ashok Bhat738702d2014-01-02 13:42:56 +0000542 { "nativePutLong", "(JJII)Z",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700543 (void*)nativePutLong },
Ashok Bhat738702d2014-01-02 13:42:56 +0000544 { "nativePutDouble", "(JDII)Z",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700545 (void*)nativePutDouble },
Ashok Bhat738702d2014-01-02 13:42:56 +0000546 { "nativePutNull", "(JII)Z",
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700547 (void*)nativePutNull },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548};
549
Andreas Gampe987f79f2014-11-18 17:29:46 -0800550int register_android_database_CursorWindow(JNIEnv* env)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551{
Andreas Gampe987f79f2014-11-18 17:29:46 -0800552 jclass clazz = FindClassOrDie(env, "android/database/CharArrayBuffer");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553
Andreas Gampe987f79f2014-11-18 17:29:46 -0800554 gCharArrayBufferClassInfo.data = GetFieldIDOrDie(env, clazz, "data", "[C");
555 gCharArrayBufferClassInfo.sizeCopied = GetFieldIDOrDie(env, clazz, "sizeCopied", "I");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556
Andreas Gampe987f79f2014-11-18 17:29:46 -0800557 gEmptyString = MakeGlobalRefOrDie(env, env->NewStringUTF(""));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558
Andreas Gampe987f79f2014-11-18 17:29:46 -0800559 return RegisterMethodsOrDie(env, "android/database/CursorWindow", sMethods, NELEM(sMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560}
561
562} // namespace android