1 /* 2 * Copyright (C) 2006 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 package android.database.sqlite; 18 19 import android.database.CursorWindow; 20 import android.os.SystemClock; 21 import android.util.Log; 22 23 /** 24 * A SQLite program that represents a query that reads the resulting rows into a CursorWindow. 25 * This class is used by SQLiteCursor and isn't useful itself. 26 * 27 * SQLiteQuery is not internally synchronized so code using a SQLiteQuery from multiple 28 * threads should perform its own synchronization when using the SQLiteQuery. 29 */ 30 public class SQLiteQuery extends SQLiteProgram { 31 private static final String TAG = "SQLiteQuery"; 32 nativeFillWindow(int databasePtr, int statementPtr, int windowPtr, int startPos, int offsetParam)33 private static native int nativeFillWindow(int databasePtr, int statementPtr, int windowPtr, 34 int startPos, int offsetParam); nativeColumnCount(int statementPtr)35 private static native int nativeColumnCount(int statementPtr); nativeColumnName(int statementPtr, int columnIndex)36 private static native String nativeColumnName(int statementPtr, int columnIndex); 37 38 /** The index of the unbound OFFSET parameter */ 39 private int mOffsetIndex = 0; 40 41 private boolean mClosed = false; 42 43 /** 44 * Create a persistent query object. 45 * 46 * @param db The database that this query object is associated with 47 * @param query The SQL string for this query. 48 * @param offsetIndex The 1-based index to the OFFSET parameter, 49 */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs)50 /* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) { 51 super(db, query); 52 mOffsetIndex = offsetIndex; 53 bindAllArgsAsStrings(bindArgs); 54 } 55 56 /** 57 * Constructor used to create new instance to replace a given instance of this class. 58 * This constructor is used when the current Query object is now associated with a different 59 * {@link SQLiteDatabase} object. 60 * 61 * @param db The database that this query object is associated with 62 * @param query the instance of {@link SQLiteQuery} to be replaced 63 */ SQLiteQuery(SQLiteDatabase db, SQLiteQuery query)64 /* package */ SQLiteQuery(SQLiteDatabase db, SQLiteQuery query) { 65 super(db, query.mSql); 66 this.mBindArgs = query.mBindArgs; 67 this.mOffsetIndex = query.mOffsetIndex; 68 } 69 70 /** 71 * Reads rows into a buffer. This method acquires the database lock. 72 * 73 * @param window The window to fill into 74 * @return number of total rows in the query 75 */ fillWindow(CursorWindow window)76 /* package */ int fillWindow(CursorWindow window) { 77 mDatabase.lock(mSql); 78 long timeStart = SystemClock.uptimeMillis(); 79 try { 80 acquireReference(); 81 try { 82 window.acquireReference(); 83 int numRows = nativeFillWindow(nHandle, nStatement, window.mWindowPtr, 84 window.getStartPosition(), mOffsetIndex); 85 mDatabase.logTimeStat(mSql, timeStart); 86 return numRows; 87 } catch (IllegalStateException e){ 88 // simply ignore it 89 return 0; 90 } catch (SQLiteDatabaseCorruptException e) { 91 mDatabase.onCorruption(); 92 throw e; 93 } catch (SQLiteException e) { 94 Log.e(TAG, "exception: " + e.getMessage() + "; query: " + mSql); 95 throw e; 96 } finally { 97 window.releaseReference(); 98 } 99 } finally { 100 releaseReference(); 101 mDatabase.unlock(); 102 } 103 } 104 105 /** 106 * Get the column count for the statement. Only valid on query based 107 * statements. The database must be locked 108 * when calling this method. 109 * 110 * @return The number of column in the statement's result set. 111 */ columnCountLocked()112 /* package */ int columnCountLocked() { 113 acquireReference(); 114 try { 115 return nativeColumnCount(nStatement); 116 } finally { 117 releaseReference(); 118 } 119 } 120 121 /** 122 * Retrieves the column name for the given column index. The database must be locked 123 * when calling this method. 124 * 125 * @param columnIndex the index of the column to get the name for 126 * @return The requested column's name 127 */ columnNameLocked(int columnIndex)128 /* package */ String columnNameLocked(int columnIndex) { 129 acquireReference(); 130 try { 131 return nativeColumnName(nStatement, columnIndex); 132 } finally { 133 releaseReference(); 134 } 135 } 136 137 @Override toString()138 public String toString() { 139 return "SQLiteQuery: " + mSql; 140 } 141 142 @Override close()143 public void close() { 144 super.close(); 145 mClosed = true; 146 } 147 148 /** 149 * Called by SQLiteCursor when it is requeried. 150 */ requery()151 /* package */ void requery() { 152 if (mClosed) { 153 throw new IllegalStateException("requerying a closed cursor"); 154 } 155 compileAndbindAllArgs(); 156 } 157 } 158