blob: 579d6ad858abb25e1496452d4753061a63d4c377 [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"
19
20#include <jni.h>
21#include <JNIHelp.h>
22#include <android_runtime/AndroidRuntime.h>
23
24#include <utils/Log.h>
25#include <utils/String8.h>
26#include <utils/String16.h>
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070027#include <utils/Unicode.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
29#include <stdio.h>
30#include <string.h>
31#include <unistd.h>
32
Mathias Agopian49d2b182012-02-27 18:11:20 -080033#include <androidfw/CursorWindow.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034#include "android_util_Binder.h"
Jeff Browne5360fb2011-10-31 17:48:13 -070035#include "android_database_SQLiteCommon.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037namespace android {
38
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070039static struct {
40 jfieldID data;
41 jfieldID sizeCopied;
42} gCharArrayBufferClassInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070044static jstring gEmptyString;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070046static void throwExceptionWithRowCol(JNIEnv* env, jint row, jint column) {
47 String8 msg;
48 msg.appendFormat("Couldn't read row %d, col %d from CursorWindow. "
49 "Make sure the Cursor is initialized correctly before accessing data from it.",
50 row, column);
51 jniThrowException(env, "java/lang/IllegalStateException", msg.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052}
53
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070054static void throwUnknownTypeException(JNIEnv * env, jint type) {
55 String8 msg;
56 msg.appendFormat("UNKNOWN type %d", type);
57 jniThrowException(env, "java/lang/IllegalStateException", msg.string());
58}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
Jeff Brown5e5d6d82011-10-12 15:41:34 -070060static jint nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
Jeff Brown0cde89f2011-10-10 14:50:10 -070061 String8 name;
Jeff Brown5a05c232012-01-12 12:04:22 -080062 const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
63 name.setTo(nameStr);
64 env->ReleaseStringUTFChars(nameObj, nameStr);
Jeff Brown0cde89f2011-10-10 14:50:10 -070065
66 CursorWindow* window;
Jeff Brown5e5d6d82011-10-12 15:41:34 -070067 status_t status = CursorWindow::create(name, cursorWindowSize, &window);
Jeff Brown0cde89f2011-10-10 14:50:10 -070068 if (status || !window) {
Steve Block3762c312012-01-06 19:20:56 +000069 ALOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
Jeff Brown0cde89f2011-10-10 14:50:10 -070070 name.string(), cursorWindowSize, status);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070071 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 }
73
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070074 LOG_WINDOW("nativeInitializeEmpty: window = %p", window);
75 return reinterpret_cast<jint>(window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076}
77
Jeff Brown0cde89f2011-10-10 14:50:10 -070078static jint nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
79 Parcel* parcel = parcelForJavaObject(env, parcelObj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
Jeff Brown0cde89f2011-10-10 14:50:10 -070081 CursorWindow* window;
82 status_t status = CursorWindow::createFromParcel(parcel, &window);
83 if (status || !window) {
Steve Block3762c312012-01-06 19:20:56 +000084 ALOGE("Could not create CursorWindow from Parcel due to error %d.", status);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070085 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 }
87
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070088 LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p",
89 window->getNumRows(), window->getNumColumns(), window);
90 return reinterpret_cast<jint>(window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091}
92
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070093static void nativeDispose(JNIEnv* env, jclass clazz, jint windowPtr) {
94 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
95 if (window) {
96 LOG_WINDOW("Closing window %p", window);
97 delete window;
98 }
99}
100
Jeff Brown650de3d2011-10-27 14:52:28 -0700101static jstring nativeGetName(JNIEnv* env, jclass clazz, jint windowPtr) {
102 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
103 return env->NewStringUTF(window->name().string());
104}
105
Jeff Brown0cde89f2011-10-10 14:50:10 -0700106static void nativeWriteToParcel(JNIEnv * env, jclass clazz, jint windowPtr,
107 jobject parcelObj) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700108 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700109 Parcel* parcel = parcelForJavaObject(env, parcelObj);
110
111 status_t status = window->writeToParcel(parcel);
112 if (status) {
113 String8 msg;
114 msg.appendFormat("Could not write CursorWindow to Parcel due to error %d.", status);
115 jniThrowRuntimeException(env, msg.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117}
118
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700119static void nativeClear(JNIEnv * env, jclass clazz, jint windowPtr) {
120 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
121 LOG_WINDOW("Clearing window %p", window);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700122 status_t status = window->clear();
123 if (status) {
124 LOG_WINDOW("Could not clear window. error=%d", status);
125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126}
127
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700128static jint nativeGetNumRows(JNIEnv* env, jclass clazz, jint windowPtr) {
129 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
130 return window->getNumRows();
131}
132
133static jboolean nativeSetNumColumns(JNIEnv* env, jclass clazz, jint windowPtr,
134 jint columnNum) {
135 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700136 status_t status = window->setNumColumns(columnNum);
137 return status == OK;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700138}
139
140static jboolean nativeAllocRow(JNIEnv* env, jclass clazz, jint windowPtr) {
141 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700142 status_t status = window->allocRow();
143 return status == OK;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700144}
145
146static void nativeFreeLastRow(JNIEnv* env, jclass clazz, jint windowPtr) {
147 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
148 window->freeLastRow();
149}
150
151static jint nativeGetType(JNIEnv* env, jclass clazz, jint windowPtr,
152 jint row, jint column) {
153 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
154 LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
155
Jeff Brown0cde89f2011-10-10 14:50:10 -0700156 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700157 if (!fieldSlot) {
Jeff Brownaa32c302011-10-07 13:15:59 -0700158 // FIXME: This is really broken but we have CTS tests that depend
159 // on this legacy behavior.
160 //throwExceptionWithRowCol(env, row, column);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700161 return CursorWindow::FIELD_TYPE_NULL;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700162 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700163 return window->getFieldSlotType(fieldSlot);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700164}
165
166static jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jint windowPtr,
167 jint row, jint column) {
168 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
169 LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);
170
Jeff Brown0cde89f2011-10-10 14:50:10 -0700171 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700172 if (!fieldSlot) {
173 throwExceptionWithRowCol(env, row, column);
174 return NULL;
175 }
176
Jeff Brown0cde89f2011-10-10 14:50:10 -0700177 int32_t type = window->getFieldSlotType(fieldSlot);
178 if (type == CursorWindow::FIELD_TYPE_BLOB || type == CursorWindow::FIELD_TYPE_STRING) {
179 size_t size;
180 const void* value = window->getFieldSlotValueBlob(fieldSlot, &size);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700181 jbyteArray byteArray = env->NewByteArray(size);
182 if (!byteArray) {
183 env->ExceptionClear();
184 throw_sqlite3_exception(env, "Native could not create new byte[]");
185 return NULL;
186 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700187 env->SetByteArrayRegion(byteArray, 0, size, static_cast<const jbyte*>(value));
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700188 return byteArray;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700189 } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700190 throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob ");
Jeff Brown0cde89f2011-10-10 14:50:10 -0700191 } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700192 throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob ");
Jeff Brown0cde89f2011-10-10 14:50:10 -0700193 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700194 // do nothing
195 } else {
196 throwUnknownTypeException(env, type);
197 }
198 return NULL;
199}
200
201static jstring nativeGetString(JNIEnv* env, jclass clazz, jint windowPtr,
202 jint row, jint column) {
203 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
204 LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
205
Jeff Brown0cde89f2011-10-10 14:50:10 -0700206 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700207 if (!fieldSlot) {
208 throwExceptionWithRowCol(env, row, column);
209 return NULL;
210 }
211
Jeff Brown0cde89f2011-10-10 14:50:10 -0700212 int32_t type = window->getFieldSlotType(fieldSlot);
213 if (type == CursorWindow::FIELD_TYPE_STRING) {
214 size_t sizeIncludingNull;
215 const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
216 if (sizeIncludingNull <= 1) {
Jeff Brown715311f2011-10-07 14:17:09 -0700217 return gEmptyString;
218 }
219 // Convert to UTF-16 here instead of calling NewStringUTF. NewStringUTF
220 // doesn't like UTF-8 strings with high codepoints. It actually expects
221 // Modified UTF-8 with encoded surrogate pairs.
Jeff Brown0cde89f2011-10-10 14:50:10 -0700222 String16 utf16(value, sizeIncludingNull - 1);
Jeff Brown715311f2011-10-07 14:17:09 -0700223 return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size());
Jeff Brown0cde89f2011-10-10 14:50:10 -0700224 } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700225 int64_t value = window->getFieldSlotValueLong(fieldSlot);
226 char buf[32];
227 snprintf(buf, sizeof(buf), "%lld", value);
228 return env->NewStringUTF(buf);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700229 } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700230 double value = window->getFieldSlotValueDouble(fieldSlot);
231 char buf[32];
232 snprintf(buf, sizeof(buf), "%g", value);
233 return env->NewStringUTF(buf);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700234 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700235 return NULL;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700236 } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700237 throw_sqlite3_exception(env, "Unable to convert BLOB to string");
238 return NULL;
239 } else {
240 throwUnknownTypeException(env, type);
241 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 }
243}
244
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700245static jcharArray allocCharArrayBuffer(JNIEnv* env, jobject bufferObj, size_t size) {
246 jcharArray dataObj = jcharArray(env->GetObjectField(bufferObj,
247 gCharArrayBufferClassInfo.data));
248 if (dataObj && size) {
249 jsize capacity = env->GetArrayLength(dataObj);
250 if (size_t(capacity) < size) {
251 env->DeleteLocalRef(dataObj);
252 dataObj = NULL;
253 }
254 }
255 if (!dataObj) {
256 jsize capacity = size;
257 if (capacity < 64) {
258 capacity = 64;
259 }
260 dataObj = env->NewCharArray(capacity); // might throw OOM
261 if (dataObj) {
262 env->SetObjectField(bufferObj, gCharArrayBufferClassInfo.data, dataObj);
263 }
264 }
265 return dataObj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266}
267
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700268static void fillCharArrayBufferUTF(JNIEnv* env, jobject bufferObj,
269 const char* str, size_t len) {
270 ssize_t size = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str), len);
271 if (size < 0) {
272 size = 0; // invalid UTF8 string
273 }
274 jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, size);
275 if (dataObj) {
276 if (size) {
277 jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL));
Jeff Brownd0ff68d2011-10-07 13:28:18 -0700278 utf8_to_utf16_no_null_terminator(reinterpret_cast<const uint8_t*>(str), len,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700279 reinterpret_cast<char16_t*>(data));
280 env->ReleasePrimitiveArrayCritical(dataObj, data, 0);
281 }
282 env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, size);
283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284}
285
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700286static void clearCharArrayBuffer(JNIEnv* env, jobject bufferObj) {
287 jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, 0);
288 if (dataObj) {
289 env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, 0);
290 }
291}
292
293static void nativeCopyStringToBuffer(JNIEnv* env, jclass clazz, jint windowPtr,
294 jint row, jint column, jobject bufferObj) {
295 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
296 LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
297
Jeff Brown0cde89f2011-10-10 14:50:10 -0700298 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700299 if (!fieldSlot) {
300 throwExceptionWithRowCol(env, row, column);
301 return;
302 }
303
Jeff Brown0cde89f2011-10-10 14:50:10 -0700304 int32_t type = window->getFieldSlotType(fieldSlot);
305 if (type == CursorWindow::FIELD_TYPE_STRING) {
306 size_t sizeIncludingNull;
307 const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
308 if (sizeIncludingNull > 1) {
309 fillCharArrayBufferUTF(env, bufferObj, value, sizeIncludingNull - 1);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700310 } else {
311 clearCharArrayBuffer(env, bufferObj);
312 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700313 } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700314 int64_t value = window->getFieldSlotValueLong(fieldSlot);
315 char buf[32];
316 snprintf(buf, sizeof(buf), "%lld", value);
317 fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700318 } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700319 double value = window->getFieldSlotValueDouble(fieldSlot);
320 char buf[32];
321 snprintf(buf, sizeof(buf), "%g", value);
322 fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700323 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700324 clearCharArrayBuffer(env, bufferObj);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700325 } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700326 throw_sqlite3_exception(env, "Unable to convert BLOB to string");
327 } else {
328 throwUnknownTypeException(env, type);
329 }
330}
331
332static jlong nativeGetLong(JNIEnv* env, jclass clazz, jint windowPtr,
333 jint row, jint column) {
334 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
335 LOG_WINDOW("Getting long for %d,%d from %p", row, column, window);
336
Jeff Brown0cde89f2011-10-10 14:50:10 -0700337 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700338 if (!fieldSlot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 throwExceptionWithRowCol(env, row, column);
340 return 0;
341 }
342
Jeff Brown0cde89f2011-10-10 14:50:10 -0700343 int32_t type = window->getFieldSlotType(fieldSlot);
344 if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700345 return window->getFieldSlotValueLong(fieldSlot);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700346 } else if (type == CursorWindow::FIELD_TYPE_STRING) {
347 size_t sizeIncludingNull;
348 const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
349 return sizeIncludingNull > 1 ? strtoll(value, NULL, 0) : 0L;
350 } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700351 return jlong(window->getFieldSlotValueDouble(fieldSlot));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700352 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 return 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700354 } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 throw_sqlite3_exception(env, "Unable to convert BLOB to long");
356 return 0;
357 } else {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700358 throwUnknownTypeException(env, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 return 0;
360 }
361}
362
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700363static jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jint windowPtr,
364 jint row, jint column) {
365 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
366 LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367
Jeff Brown0cde89f2011-10-10 14:50:10 -0700368 CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700369 if (!fieldSlot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 throwExceptionWithRowCol(env, row, column);
371 return 0.0;
372 }
373
Jeff Brown0cde89f2011-10-10 14:50:10 -0700374 int32_t type = window->getFieldSlotType(fieldSlot);
375 if (type == CursorWindow::FIELD_TYPE_FLOAT) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700376 return window->getFieldSlotValueDouble(fieldSlot);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700377 } else if (type == CursorWindow::FIELD_TYPE_STRING) {
378 size_t sizeIncludingNull;
379 const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
380 return sizeIncludingNull > 1 ? strtod(value, NULL) : 0.0;
381 } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700382 return jdouble(window->getFieldSlotValueLong(fieldSlot));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700383 } else if (type == CursorWindow::FIELD_TYPE_NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 return 0.0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700385 } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 throw_sqlite3_exception(env, "Unable to convert BLOB to double");
387 return 0.0;
388 } else {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700389 throwUnknownTypeException(env, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 return 0.0;
391 }
392}
393
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700394static jboolean nativePutBlob(JNIEnv* env, jclass clazz, jint windowPtr,
395 jbyteArray valueObj, jint row, jint column) {
396 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700397 jsize len = env->GetArrayLength(valueObj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700399 void* value = env->GetPrimitiveArrayCritical(valueObj, NULL);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700400 status_t status = window->putBlob(row, column, value, len);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700401 env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT);
402
Jeff Brown0cde89f2011-10-10 14:50:10 -0700403 if (status) {
404 LOG_WINDOW("Failed to put blob. error=%d", status);
405 return false;
406 }
407
408 LOG_WINDOW("%d,%d is BLOB with %u bytes", row, column, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 return true;
410}
411
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700412static jboolean nativePutString(JNIEnv* env, jclass clazz, jint windowPtr,
413 jstring valueObj, jint row, jint column) {
414 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415
Jeff Brown0cde89f2011-10-10 14:50:10 -0700416 size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700417 const char* valueStr = env->GetStringUTFChars(valueObj, NULL);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700418 if (!valueStr) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700419 LOG_WINDOW("value can't be transferred to UTFChars");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 return false;
421 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700422 status_t status = window->putString(row, column, valueStr, sizeIncludingNull);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700423 env->ReleaseStringUTFChars(valueObj, valueStr);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700424
Jeff Brown0cde89f2011-10-10 14:50:10 -0700425 if (status) {
426 LOG_WINDOW("Failed to put string. error=%d", status);
427 return false;
428 }
429
430 LOG_WINDOW("%d,%d is TEXT with %u bytes", row, column, sizeIncludingNull);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 return true;
432}
433
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700434static jboolean nativePutLong(JNIEnv* env, jclass clazz, jint windowPtr,
435 jlong value, jint row, jint column) {
436 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700437 status_t status = window->putLong(row, column, value);
438
439 if (status) {
440 LOG_WINDOW("Failed to put long. error=%d", status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 return false;
442 }
443
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700444 LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 return true;
446}
447
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700448static jboolean nativePutDouble(JNIEnv* env, jclass clazz, jint windowPtr,
449 jdouble value, jint row, jint column) {
450 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700451 status_t status = window->putDouble(row, column, value);
452
453 if (status) {
454 LOG_WINDOW("Failed to put double. error=%d", status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 return false;
456 }
457
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700458 LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 return true;
460}
461
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700462static jboolean nativePutNull(JNIEnv* env, jclass clazz, jint windowPtr,
463 jint row, jint column) {
464 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700465 status_t status = window->putNull(row, column);
466
467 if (status) {
468 LOG_WINDOW("Failed to put null. error=%d", status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 return false;
470 }
471
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700472 LOG_WINDOW("%d,%d is NULL", row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 return true;
474}
475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476static JNINativeMethod sMethods[] =
477{
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700478 /* name, signature, funcPtr */
Jeff Brown5e5d6d82011-10-12 15:41:34 -0700479 { "nativeCreate", "(Ljava/lang/String;I)I",
Jeff Brown0cde89f2011-10-10 14:50:10 -0700480 (void*)nativeCreate },
481 { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I",
482 (void*)nativeCreateFromParcel },
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700483 { "nativeDispose", "(I)V",
484 (void*)nativeDispose },
Jeff Brown0cde89f2011-10-10 14:50:10 -0700485 { "nativeWriteToParcel", "(ILandroid/os/Parcel;)V",
486 (void*)nativeWriteToParcel },
Jeff Brown650de3d2011-10-27 14:52:28 -0700487 { "nativeGetName", "(I)Ljava/lang/String;",
488 (void*)nativeGetName },
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700489 { "nativeClear", "(I)V",
490 (void*)nativeClear },
491 { "nativeGetNumRows", "(I)I",
492 (void*)nativeGetNumRows },
493 { "nativeSetNumColumns", "(II)Z",
494 (void*)nativeSetNumColumns },
495 { "nativeAllocRow", "(I)Z",
496 (void*)nativeAllocRow },
497 { "nativeFreeLastRow", "(I)V",
498 (void*)nativeFreeLastRow },
499 { "nativeGetType", "(III)I",
500 (void*)nativeGetType },
501 { "nativeGetBlob", "(III)[B",
502 (void*)nativeGetBlob },
503 { "nativeGetString", "(III)Ljava/lang/String;",
504 (void*)nativeGetString },
505 { "nativeGetLong", "(III)J",
506 (void*)nativeGetLong },
507 { "nativeGetDouble", "(III)D",
508 (void*)nativeGetDouble },
509 { "nativeCopyStringToBuffer", "(IIILandroid/database/CharArrayBuffer;)V",
510 (void*)nativeCopyStringToBuffer },
511 { "nativePutBlob", "(I[BII)Z",
512 (void*)nativePutBlob },
513 { "nativePutString", "(ILjava/lang/String;II)Z",
514 (void*)nativePutString },
515 { "nativePutLong", "(IJII)Z",
516 (void*)nativePutLong },
517 { "nativePutDouble", "(IDII)Z",
518 (void*)nativePutDouble },
519 { "nativePutNull", "(III)Z",
520 (void*)nativePutNull },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521};
522
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700523#define FIND_CLASS(var, className) \
524 var = env->FindClass(className); \
525 LOG_FATAL_IF(! var, "Unable to find class " className);
526
527#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
528 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
529 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531int register_android_database_CursorWindow(JNIEnv * env)
532{
533 jclass clazz;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700534 FIND_CLASS(clazz, "android/database/CharArrayBuffer");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700536 GET_FIELD_ID(gCharArrayBufferClassInfo.data, clazz,
537 "data", "[C");
538 GET_FIELD_ID(gCharArrayBufferClassInfo.sizeCopied, clazz,
539 "sizeCopied", "I");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700541 gEmptyString = jstring(env->NewGlobalRef(env->NewStringUTF("")));
542 LOG_FATAL_IF(!gEmptyString, "Unable to create empty string");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543
544 return AndroidRuntime::registerNativeMethods(env, "android/database/CursorWindow",
545 sMethods, NELEM(sMethods));
546}
547
548} // namespace android