19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#undef LOG_TAG
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "Cursor"
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <jni.h>
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <JNIHelp.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h>
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sqlite3.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdio.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <unistd.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "CursorWindow.h"
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "sqlite3_exception.h"
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectsqlite3_stmt * compile(JNIEnv* env, jobject object,
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                       sqlite3 * handle, jstring sqlString);
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// From android_database_CursorWindow.cpp
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectCursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow);
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jfieldID gHandleField;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jfieldID gStatementField;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define GET_STATEMENT(env, object) \
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        (sqlite3_stmt *)env->GetIntField(object, gStatementField)
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define GET_HANDLE(env, object) \
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        (sqlite3 *)env->GetIntField(object, gHandleField)
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int skip_rows(sqlite3_stmt *statement, int maxRows) {
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int retryCount = 0;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i = 0; i < maxRows; i++) {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int err = sqlite3_step(statement);
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err == SQLITE_ROW){
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // do nothing
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (err == SQLITE_DONE) {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return i;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The table is locked, retry
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG_WINDOW("Database locked, retrying");
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           if (retryCount > 50) {
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LOGE("Bailing on database busy rety");
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Sleep to give the thread holding the lock a chance to finish
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            usleep(1000);
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retryCount++;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOGD("skip_rows row %d", maxRows);
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return maxRows;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int finish_program_and_get_row_count(sqlite3_stmt *statement) {
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int numRows = 0;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int retryCount = 0;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (true) {
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int err = sqlite3_step(statement);
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err == SQLITE_ROW){
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            numRows++;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The table is locked, retry
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG_WINDOW("Database locked, retrying");
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (retryCount > 50) {
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LOGE("Bailing on database busy rety");
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Sleep to give the thread holding the lock a chance to finish
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            usleep(1000);
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retryCount++;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // no need to throw exception
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_reset(statement);
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOGD("finish_program_and_get_row_count row %d", numRows);
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return numRows;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                               jint startPos, jint offsetParam, jint maxRead, jint lastPos)
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_stmt * statement = GET_STATEMENT(env, object);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int numRows = lastPos;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    maxRead += lastPos;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int numColumns;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int retryCount;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int boundParams;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CursorWindow * window;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (statement == NULL) {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Invalid statement in fillWindow()");
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException",
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "Attempting to access a deactivated, closed, or empty cursor");
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Only do the binding if there is a valid offsetParam. If no binding needs to be done
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // offsetParam will be set to 0, an invliad value.
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if(offsetParam > 0) {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Bind the offset parameter, telling the program which row to start with
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        err = sqlite3_bind_int(statement, offsetParam, startPos);
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != SQLITE_OK) {
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("Unable to bind offset position, offsetParam = %d", offsetParam);
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jniThrowException(env, "java/lang/IllegalArgumentException",
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              sqlite3_errmsg(GET_HANDLE(env, object)));
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG_WINDOW("Bound to startPos %d", startPos);
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG_WINDOW("Not binding to startPos %d", startPos);
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Get the native window
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    window = get_window_from_object(env, javaWindow);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!window) {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Invalid CursorWindow");
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalArgumentException",
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "Bad CursorWindow");
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOG_WINDOW("Window: numRows = %d, size = %d, freeSpace = %d", window->getNumRows(), window->size(), window->freeSpace());
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    numColumns = sqlite3_column_count(statement);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!window->setNumColumns(numColumns)) {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Failed to change column count from %d to %d", window->getNumColumns(), numColumns);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException", "numColumns mismatch");
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    retryCount = 0;
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (startPos > 0) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int num = skip_rows(statement, startPos);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (num < 0) {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw_sqlite3_exception(env, GET_HANDLE(env, object));
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (num < startPos) {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("startPos %d > actual rows %d", startPos, num);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return num;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while(startPos != 0 || numRows < maxRead) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        err = sqlite3_step(statement);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err == SQLITE_ROW) {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG_WINDOW("\nStepped statement %p to row %d", statement, startPos + numRows);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retryCount = 0;
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Allocate a new field directory for the row. This pointer is not reused
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // since it mey be possible for it to be relocated on a call to alloc() when
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // the field data is being allocated.
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                field_slot_t * fieldDir = window->allocRow();
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!fieldDir) {
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LOGE("Failed allocating fieldDir at startPos %d row %d", startPos, numRows);
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Pack the row into the window
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < numColumns; i++) {
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int type = sqlite3_column_type(statement, i);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type == SQLITE_TEXT) {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // TEXT data
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if WINDOW_STORAGE_UTF8
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    uint8_t const * text = (uint8_t const *)sqlite3_column_text(statement, i);
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // SQLite does not include the NULL terminator in size, but does
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // ensure all strings are NULL terminated, so increase size by
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // one to make sure we store the terminator.
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    size_t size = sqlite3_column_bytes(statement, i) + 1;
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#else
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    uint8_t const * text = (uint8_t const *)sqlite3_column_text16(statement, i);
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    size_t size = sqlite3_column_bytes16(statement, i);
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int offset = window->alloc(size);
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!offset) {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        window->freeLastRow();
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        LOGE("Failed allocating %u bytes for text/blob at %d,%d", size,
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   startPos + numRows, i);
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    window->copyIn(offset, text, size);
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // This must be updated after the call to alloc(), since that
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // may move the field around in the window
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    field_slot_t * fieldSlot = window->getFieldSlot(numRows, i);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldSlot->type = FIELD_TYPE_STRING;
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldSlot->data.buffer.offset = offset;
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldSlot->data.buffer.size = size;
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LOG_WINDOW("%d,%d is TEXT with %u bytes", startPos + numRows, i, size);
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (type == SQLITE_INTEGER) {
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // INTEGER data
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int64_t value = sqlite3_column_int64(statement, i);
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!window->putLong(numRows, i, value)) {
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        window->freeLastRow();
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        LOGE("Failed allocating space for a long in column %d", i);
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + numRows, i, value);
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (type == SQLITE_FLOAT) {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // FLOAT data
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    double value = sqlite3_column_double(statement, i);
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!window->putDouble(numRows, i, value)) {
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        window->freeLastRow();
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        LOGE("Failed allocating space for a double in column %d", i);
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LOG_WINDOW("%d,%d is FLOAT %lf", startPos + numRows, i, value);
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (type == SQLITE_BLOB) {
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // BLOB data
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    uint8_t const * blob = (uint8_t const *)sqlite3_column_blob(statement, i);
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    size_t size = sqlite3_column_bytes16(statement, i);
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int offset = window->alloc(size);
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!offset) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        window->freeLastRow();
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        LOGE("Failed allocating %u bytes for blob at %d,%d", size,
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   startPos + numRows, i);
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    window->copyIn(offset, blob, size);
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // This must be updated after the call to alloc(), since that
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // may move the field around in the window
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    field_slot_t * fieldSlot = window->getFieldSlot(numRows, i);
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldSlot->type = FIELD_TYPE_BLOB;
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldSlot->data.buffer.offset = offset;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldSlot->data.buffer.size = size;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LOG_WINDOW("%d,%d is Blob with %u bytes @ %d", startPos + numRows, i, size, offset);
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (type == SQLITE_NULL) {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // NULL field
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    window->putNull(numRows, i);
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LOG_WINDOW("%d,%d is NULL", startPos + numRows, i);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Unknown data
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LOGE("Unknown column type when filling database window");
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw_sqlite3_exception(env, "Unknown column type when filling window");
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (i < numColumns) {
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Not all the fields fit in the window
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Unknown data error happened
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Mark the row as complete in the window
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            numRows++;
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (err == SQLITE_DONE) {
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // All rows processed, bail
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG_WINDOW("Processed all rows");
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The table is locked, retry
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG_WINDOW("Database locked, retrying");
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (retryCount > 50) {
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LOGE("Bailing on database busy rety");
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Sleep to give the thread holding the lock a chance to finish
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            usleep(1000);
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retryCount++;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw_sqlite3_exception(env, GET_HANDLE(env, object));
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOG_WINDOW("Resetting statement %p after fetching %d rows in %d bytes\n\n\n\n", statement,
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            numRows, window->size() - window->freeSpace());
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//    LOGI("Filled window with %d rows in %d bytes", numRows, window->size() - window->freeSpace());
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err == SQLITE_ROW) {
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sqlite3_reset(statement);
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return startPos + numRows;
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint native_column_count(JNIEnv* env, jobject object)
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_stmt * statement = GET_STATEMENT(env, object);
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return sqlite3_column_count(statement);
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jstring native_column_name(JNIEnv* env, jobject object, jint columnIndex)
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_stmt * statement = GET_STATEMENT(env, object);
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char const * name;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    name = sqlite3_column_name(statement, columnIndex);
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return env->NewStringUTF(name);
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod sMethods[] =
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     /* name, signature, funcPtr */
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_fill_window", "(Landroid/database/CursorWindow;IIII)I", (void *)native_fill_window},
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_column_count", "()I", (void*)native_column_count},
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_column_name", "(I)Ljava/lang/String;", (void *)native_column_name},
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_database_SQLiteQuery(JNIEnv * env)
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jclass clazz;
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    clazz = env->FindClass("android/database/sqlite/SQLiteQuery");
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (clazz == NULL) {
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Can't find android/database/sqlite/SQLiteQuery");
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    gHandleField = env->GetFieldID(clazz, "nHandle", "I");
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    gStatementField = env->GetFieldID(clazz, "nStatement", "I");
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (gHandleField == NULL || gStatementField == NULL) {
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Error locating fields");
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return AndroidRuntime::registerNativeMethods(env,
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "android/database/sqlite/SQLiteQuery", sMethods, NELEM(sMethods));
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} // namespace android
367