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
18b18f27dbf43ee9028a11cafbca23d3fa318e278bVasu Nori#define LOG_TAG "SqliteCursor.cpp"
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
322807df89af680e46cb35ee0035bb10b42d3136a2Mike Lockwood#include "binder/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
387ce745248d4de0e6543a559c93423df899832100Jeff Brownstatic jint nativeFillWindow(JNIEnv* env, jclass clazz, jint databasePtr,
397ce745248d4de0e6543a559c93423df899832100Jeff Brown        jint statementPtr, jint windowPtr, jint startPos, jint offsetParam) {
407ce745248d4de0e6543a559c93423df899832100Jeff Brown    sqlite3* database = reinterpret_cast<sqlite3*>(databasePtr);
417ce745248d4de0e6543a559c93423df899832100Jeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
427ce745248d4de0e6543a559c93423df899832100Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Only do the binding if there is a valid offsetParam. If no binding needs to be done
457ce745248d4de0e6543a559c93423df899832100Jeff Brown    // offsetParam will be set to 0, an invalid value.
467ce745248d4de0e6543a559c93423df899832100Jeff Brown    if (offsetParam > 0) {
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Bind the offset parameter, telling the program which row to start with
487ce745248d4de0e6543a559c93423df899832100Jeff Brown        int err = sqlite3_bind_int(statement, offsetParam, startPos);
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != SQLITE_OK) {
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("Unable to bind offset position, offsetParam = %d", offsetParam);
517ce745248d4de0e6543a559c93423df899832100Jeff Brown            throw_sqlite3_exception(env, database);
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG_WINDOW("Bound to startPos %d", startPos);
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG_WINDOW("Not binding to startPos %d", startPos);
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
597ce745248d4de0e6543a559c93423df899832100Jeff Brown    // We assume numRows is initially 0.
607ce745248d4de0e6543a559c93423df899832100Jeff Brown    LOG_WINDOW("Window: numRows = %d, size = %d, freeSpace = %d",
617ce745248d4de0e6543a559c93423df899832100Jeff Brown            window->getNumRows(), window->size(), window->freeSpace());
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
637ce745248d4de0e6543a559c93423df899832100Jeff Brown    int numColumns = sqlite3_column_count(statement);
640cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->setNumColumns(numColumns);
650cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Failed to change column count from %d to %d", window->getNumColumns(), numColumns);
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException", "numColumns mismatch");
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
717ce745248d4de0e6543a559c93423df899832100Jeff Brown    int retryCount = 0;
727ce745248d4de0e6543a559c93423df899832100Jeff Brown    int totalRows = 0;
737ce745248d4de0e6543a559c93423df899832100Jeff Brown    int addedRows = 0;
747ce745248d4de0e6543a559c93423df899832100Jeff Brown    bool windowFull = false;
757ce745248d4de0e6543a559c93423df899832100Jeff Brown    bool gotException = false;
767ce745248d4de0e6543a559c93423df899832100Jeff Brown    const bool countAllRows = (startPos == 0); // when startPos is 0, we count all rows
777ce745248d4de0e6543a559c93423df899832100Jeff Brown    while (!gotException && (!windowFull || countAllRows)) {
787ce745248d4de0e6543a559c93423df899832100Jeff Brown        int err = sqlite3_step(statement);
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err == SQLITE_ROW) {
807ce745248d4de0e6543a559c93423df899832100Jeff Brown            LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retryCount = 0;
827ce745248d4de0e6543a559c93423df899832100Jeff Brown            totalRows += 1;
837ce745248d4de0e6543a559c93423df899832100Jeff Brown
847ce745248d4de0e6543a559c93423df899832100Jeff Brown            // Skip the row if the window is full or we haven't reached the start position yet.
857ce745248d4de0e6543a559c93423df899832100Jeff Brown            if (startPos >= totalRows || windowFull) {
867ce745248d4de0e6543a559c93423df899832100Jeff Brown                continue;
877ce745248d4de0e6543a559c93423df899832100Jeff Brown            }
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Allocate a new field directory for the row. This pointer is not reused
907ce745248d4de0e6543a559c93423df899832100Jeff Brown            // since it may be possible for it to be relocated on a call to alloc() when
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // the field data is being allocated.
920cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            status = window->allocRow();
930cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            if (status) {
940cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
950cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                        startPos, addedRows, status);
967ce745248d4de0e6543a559c93423df899832100Jeff Brown                windowFull = true;
977ce745248d4de0e6543a559c93423df899832100Jeff Brown                continue;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1007ce745248d4de0e6543a559c93423df899832100Jeff Brown            // Pack the row into the window.
1017ce745248d4de0e6543a559c93423df899832100Jeff Brown            for (int i = 0; i < numColumns; i++) {
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int type = sqlite3_column_type(statement, i);
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type == SQLITE_TEXT) {
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // TEXT data
1050cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    const char* text = reinterpret_cast<const char*>(
1067ce745248d4de0e6543a559c93423df899832100Jeff Brown                            sqlite3_column_text(statement, i));
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // SQLite does not include the NULL terminator in size, but does
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // ensure all strings are NULL terminated, so increase size by
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // one to make sure we store the terminator.
1100cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
1110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    status = window->putString(addedRows, i, text, sizeIncludingNull);
1120cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    if (status) {
1130cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                        LOG_WINDOW("Failed allocating %u bytes for text at %d,%d, error=%d",
1140cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                                sizeIncludingNull, startPos + addedRows, i, status);
1157ce745248d4de0e6543a559c93423df899832100Jeff Brown                        windowFull = true;
1167ce745248d4de0e6543a559c93423df899832100Jeff Brown                        break;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1180cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    LOG_WINDOW("%d,%d is TEXT with %u bytes",
1190cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                            startPos + addedRows, i, sizeIncludingNull);
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (type == SQLITE_INTEGER) {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // INTEGER data
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int64_t value = sqlite3_column_int64(statement, i);
1230cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    status = window->putLong(addedRows, i, value);
1240cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    if (status) {
1250cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                        LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
1260cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                                i, status);
1277ce745248d4de0e6543a559c93423df899832100Jeff Brown                        windowFull = true;
1287ce745248d4de0e6543a559c93423df899832100Jeff Brown                        break;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1307ce745248d4de0e6543a559c93423df899832100Jeff Brown                    LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + addedRows, i, value);
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (type == SQLITE_FLOAT) {
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // FLOAT data
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    double value = sqlite3_column_double(statement, i);
1340cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    status = window->putDouble(addedRows, i, value);
1350cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    if (status) {
1360cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                        LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
1370cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                                i, status);
1387ce745248d4de0e6543a559c93423df899832100Jeff Brown                        windowFull = true;
1397ce745248d4de0e6543a559c93423df899832100Jeff Brown                        break;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1417ce745248d4de0e6543a559c93423df899832100Jeff Brown                    LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (type == SQLITE_BLOB) {
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // BLOB data
1440cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    const void* blob = sqlite3_column_blob(statement, i);
1450cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    size_t size = sqlite3_column_bytes(statement, i);
1460cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    status = window->putBlob(addedRows, i, blob, size);
1470cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    if (status) {
1480cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                        LOG_WINDOW("Failed allocating %u bytes for blob at %d,%d, error=%d",
1490cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                                size, startPos + addedRows, i, status);
1507ce745248d4de0e6543a559c93423df899832100Jeff Brown                        windowFull = true;
1517ce745248d4de0e6543a559c93423df899832100Jeff Brown                        break;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1530cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    LOG_WINDOW("%d,%d is Blob with %u bytes",
1540cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                            startPos + addedRows, i, size);
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (type == SQLITE_NULL) {
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // NULL field
1570cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    status = window->putNull(addedRows, i);
1580cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                    if (status) {
1590cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                        LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
1600cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                                i, status);
1617ce745248d4de0e6543a559c93423df899832100Jeff Brown                        windowFull = true;
1627ce745248d4de0e6543a559c93423df899832100Jeff Brown                        break;
1637ce745248d4de0e6543a559c93423df899832100Jeff Brown                    }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1657ce745248d4de0e6543a559c93423df899832100Jeff Brown                    LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Unknown data
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LOGE("Unknown column type when filling database window");
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw_sqlite3_exception(env, "Unknown column type when filling window");
17077267fc68f2c05ca7cdd1f6b6a9d9b2d4479f8bbVasu Nori                    gotException = true;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1757ce745248d4de0e6543a559c93423df899832100Jeff Brown            // Update the final row tally.
1767ce745248d4de0e6543a559c93423df899832100Jeff Brown            if (windowFull || gotException) {
1777ce745248d4de0e6543a559c93423df899832100Jeff Brown                window->freeLastRow();
1787ce745248d4de0e6543a559c93423df899832100Jeff Brown            } else {
1797ce745248d4de0e6543a559c93423df899832100Jeff Brown                addedRows += 1;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (err == SQLITE_DONE) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // All rows processed, bail
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG_WINDOW("Processed all rows");
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The table is locked, retry
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG_WINDOW("Database locked, retrying");
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (retryCount > 50) {
1897ce745248d4de0e6543a559c93423df899832100Jeff Brown                LOGE("Bailing on database busy retry");
1907ce745248d4de0e6543a559c93423df899832100Jeff Brown                throw_sqlite3_exception(env, database, "retrycount exceeded");
19177267fc68f2c05ca7cdd1f6b6a9d9b2d4479f8bbVasu Nori                gotException = true;
1927ce745248d4de0e6543a559c93423df899832100Jeff Brown            } else {
1937ce745248d4de0e6543a559c93423df899832100Jeff Brown                // Sleep to give the thread holding the lock a chance to finish
1947ce745248d4de0e6543a559c93423df899832100Jeff Brown                usleep(1000);
1957ce745248d4de0e6543a559c93423df899832100Jeff Brown                retryCount++;
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1987ce745248d4de0e6543a559c93423df899832100Jeff Brown            throw_sqlite3_exception(env, database);
19977267fc68f2c05ca7cdd1f6b6a9d9b2d4479f8bbVasu Nori            gotException = true;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2037ce745248d4de0e6543a559c93423df899832100Jeff Brown    LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows"
2047ce745248d4de0e6543a559c93423df899832100Jeff Brown            "to the window in %d bytes",
2057ce745248d4de0e6543a559c93423df899832100Jeff Brown            statement, totalRows, addedRows, window->size() - window->freeSpace());
2067ce745248d4de0e6543a559c93423df899832100Jeff Brown    sqlite3_reset(statement);
2077ce745248d4de0e6543a559c93423df899832100Jeff Brown
2087ce745248d4de0e6543a559c93423df899832100Jeff Brown    // Report the total number of rows on request.
2097ce745248d4de0e6543a559c93423df899832100Jeff Brown    if (startPos > totalRows) {
2107ce745248d4de0e6543a559c93423df899832100Jeff Brown        LOGE("startPos %d > actual rows %d", startPos, totalRows);
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2127ce745248d4de0e6543a559c93423df899832100Jeff Brown    return countAllRows ? totalRows : 0;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2157ce745248d4de0e6543a559c93423df899832100Jeff Brownstatic jint nativeColumnCount(JNIEnv* env, jclass clazz, jint statementPtr) {
2167ce745248d4de0e6543a559c93423df899832100Jeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return sqlite3_column_count(statement);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2207ce745248d4de0e6543a559c93423df899832100Jeff Brownstatic jstring nativeColumnName(JNIEnv* env, jclass clazz, jint statementPtr,
2217ce745248d4de0e6543a559c93423df899832100Jeff Brown        jint columnIndex) {
2227ce745248d4de0e6543a559c93423df899832100Jeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
2237ce745248d4de0e6543a559c93423df899832100Jeff Brown    const char* name = sqlite3_column_name(statement, columnIndex);
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return env->NewStringUTF(name);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod sMethods[] =
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     /* name, signature, funcPtr */
2317ce745248d4de0e6543a559c93423df899832100Jeff Brown    { "nativeFillWindow", "(IIIII)I",
2327ce745248d4de0e6543a559c93423df899832100Jeff Brown            (void*)nativeFillWindow },
2337ce745248d4de0e6543a559c93423df899832100Jeff Brown    { "nativeColumnCount", "(I)I",
2347ce745248d4de0e6543a559c93423df899832100Jeff Brown            (void*)nativeColumnCount},
2357ce745248d4de0e6543a559c93423df899832100Jeff Brown    { "nativeColumnName", "(II)Ljava/lang/String;",
2367ce745248d4de0e6543a559c93423df899832100Jeff Brown            (void*)nativeColumnName},
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_database_SQLiteQuery(JNIEnv * env)
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return AndroidRuntime::registerNativeMethods(env,
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "android/database/sqlite/SQLiteQuery", sMethods, NELEM(sMethods));
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} // namespace android
246