blob: 56dd0076a5c6f09df8fc1d4e33a4d2a95309d4b1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.database.sqlite;
18
19import android.database.CursorWindow;
Brad Fitzpatrick6a353872010-02-11 18:04:49 -080020import android.os.SystemClock;
Jeff Brown89101cd92011-10-27 21:24:54 -070021import android.text.TextUtils;
Vasu Norib18f27d2010-08-12 18:16:35 -070022import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
24/**
25 * A SQLite program that represents a query that reads the resulting rows into a CursorWindow.
26 * This class is used by SQLiteCursor and isn't useful itself.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -070027 *
28 * SQLiteQuery is not internally synchronized so code using a SQLiteQuery from multiple
29 * threads should perform its own synchronization when using the SQLiteQuery.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030 */
31public class SQLiteQuery extends SQLiteProgram {
Vasu Nori0732f792010-07-29 17:24:12 -070032 private static final String TAG = "SQLiteQuery";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
Jeff Brown650de3d2011-10-27 14:52:28 -070034 private static native long nativeFillWindow(int databasePtr, int statementPtr, int windowPtr,
35 int offsetParam, int startPos, int requiredPos, boolean countAllRows);
Jeff Brown89101cd92011-10-27 21:24:54 -070036
Jeff Brown7ce74522011-10-07 13:29:37 -070037 private static native int nativeColumnCount(int statementPtr);
38 private static native String nativeColumnName(int statementPtr, int columnIndex);
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 /** The index of the unbound OFFSET parameter */
Vasu Nori0732f792010-07-29 17:24:12 -070041 private int mOffsetIndex = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
43 private boolean mClosed = false;
44
45 /**
46 * Create a persistent query object.
Vasu Nori0732f792010-07-29 17:24:12 -070047 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048 * @param db The database that this query object is associated with
49 * @param query The SQL string for this query.
50 * @param offsetIndex The 1-based index to the OFFSET parameter,
51 */
52 /* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) {
53 super(db, query);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 mOffsetIndex = offsetIndex;
Vasu Nori0732f792010-07-29 17:24:12 -070055 bindAllArgsAsStrings(bindArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 }
57
58 /**
Vasu Nori65a88832010-07-16 15:14:08 -070059 * Constructor used to create new instance to replace a given instance of this class.
60 * This constructor is used when the current Query object is now associated with a different
61 * {@link SQLiteDatabase} object.
62 *
63 * @param db The database that this query object is associated with
64 * @param query the instance of {@link SQLiteQuery} to be replaced
65 */
66 /* package */ SQLiteQuery(SQLiteDatabase db, SQLiteQuery query) {
Vasu Nori0732f792010-07-29 17:24:12 -070067 super(db, query.mSql);
68 this.mBindArgs = query.mBindArgs;
Vasu Norib18f27d2010-08-12 18:16:35 -070069 this.mOffsetIndex = query.mOffsetIndex;
Vasu Nori65a88832010-07-16 15:14:08 -070070 }
71
72 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 * Reads rows into a buffer. This method acquires the database lock.
Brad Fitzpatrick722802e2010-03-23 22:22:16 -070074 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 * @param window The window to fill into
Jeff Brown650de3d2011-10-27 14:52:28 -070076 * @param startPos The start position for filling the window.
77 * @param requiredPos The position of a row that MUST be in the window.
78 * If it won't fit, then the query should discard part of what it filled.
79 * @param countAllRows True to count all rows that the query would
80 * return regardless of whether they fit in the window.
81 * @return Number of rows that were enumerated. Might not be all rows
82 * unless countAllRows is true.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 */
Jeff Brown650de3d2011-10-27 14:52:28 -070084 /* package */ int fillWindow(CursorWindow window,
85 int startPos, int requiredPos, boolean countAllRows) {
Vasu Nori16057fa2011-03-18 11:40:37 -070086 mDatabase.lock(mSql);
Brad Fitzpatrick6a353872010-02-11 18:04:49 -080087 long timeStart = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 try {
89 acquireReference();
90 try {
91 window.acquireReference();
Jeff Brown650de3d2011-10-27 14:52:28 -070092 long result = nativeFillWindow(nHandle, nStatement, window.mWindowPtr,
93 mOffsetIndex, startPos, requiredPos, countAllRows);
94 int actualPos = (int)(result >> 32);
95 int countedRows = (int)result;
96 window.setStartPosition(actualPos);
Jeff Brown89101cd92011-10-27 21:24:54 -070097 if (SQLiteDebug.DEBUG_LOG_SLOW_QUERIES) {
98 long elapsed = SystemClock.uptimeMillis() - timeStart;
99 if (SQLiteDebug.shouldLogSlowQuery(elapsed)) {
100 Log.d(TAG, "fillWindow took " + elapsed
101 + " ms: window=\"" + window
102 + "\", startPos=" + startPos
Jeff Brownfa59cfb2011-10-31 15:10:10 -0700103 + ", requiredPos=" + requiredPos
Jeff Brown89101cd92011-10-27 21:24:54 -0700104 + ", offset=" + mOffsetIndex
Jeff Brownfa59cfb2011-10-31 15:10:10 -0700105 + ", actualPos=" + actualPos
Jeff Brown89101cd92011-10-27 21:24:54 -0700106 + ", filledRows=" + window.getNumRows()
Jeff Brownfa59cfb2011-10-31 15:10:10 -0700107 + ", countedRows=" + countedRows
Jeff Brown89101cd92011-10-27 21:24:54 -0700108 + ", query=\"" + mSql + "\""
109 + ", args=[" + (mBindArgs != null ?
110 TextUtils.join(", ", mBindArgs.values()) : "")
111 + "]");
112 }
Jeff Brown650de3d2011-10-27 14:52:28 -0700113 }
Dan Egnor12311952009-11-23 14:47:45 -0800114 mDatabase.logTimeStat(mSql, timeStart);
Jeff Brown650de3d2011-10-27 14:52:28 -0700115 return countedRows;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 } catch (IllegalStateException e){
117 // simply ignore it
118 return 0;
119 } catch (SQLiteDatabaseCorruptException e) {
120 mDatabase.onCorruption();
121 throw e;
Vasu Norib18f27d2010-08-12 18:16:35 -0700122 } catch (SQLiteException e) {
123 Log.e(TAG, "exception: " + e.getMessage() + "; query: " + mSql);
124 throw e;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 } finally {
Brad Fitzpatrick722802e2010-03-23 22:22:16 -0700126 window.releaseReference();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 }
128 } finally {
129 releaseReference();
130 mDatabase.unlock();
131 }
132 }
133
134 /**
135 * Get the column count for the statement. Only valid on query based
136 * statements. The database must be locked
137 * when calling this method.
138 *
139 * @return The number of column in the statement's result set.
140 */
141 /* package */ int columnCountLocked() {
142 acquireReference();
143 try {
Jeff Brown7ce74522011-10-07 13:29:37 -0700144 return nativeColumnCount(nStatement);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 } finally {
146 releaseReference();
147 }
148 }
149
150 /**
151 * Retrieves the column name for the given column index. The database must be locked
152 * when calling this method.
153 *
154 * @param columnIndex the index of the column to get the name for
155 * @return The requested column's name
156 */
157 /* package */ String columnNameLocked(int columnIndex) {
158 acquireReference();
159 try {
Jeff Brown7ce74522011-10-07 13:29:37 -0700160 return nativeColumnName(nStatement, columnIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 } finally {
162 releaseReference();
163 }
164 }
Jeff Brown7ce74522011-10-07 13:29:37 -0700165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 @Override
167 public String toString() {
Vasu Nori5a03f362009-10-20 15:16:35 -0700168 return "SQLiteQuery: " + mSql;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 }
Jeff Brown7ce74522011-10-07 13:29:37 -0700170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 @Override
172 public void close() {
173 super.close();
174 mClosed = true;
175 }
176
177 /**
178 * Called by SQLiteCursor when it is requeried.
179 */
180 /* package */ void requery() {
Vasu Nori0732f792010-07-29 17:24:12 -0700181 if (mClosed) {
182 throw new IllegalStateException("requerying a closed cursor");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 }
Vasu Nori0732f792010-07-29 17:24:12 -0700184 compileAndbindAllArgs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186}