• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 public class SQLiteQuery extends SQLiteProgram {
28     private static final String TAG = "Cursor";
29 
30     /** The index of the unbound OFFSET parameter */
31     private int mOffsetIndex;
32 
33     /** The SQL used to create this query */
34     private String mQuery;
35 
36     /** Args to bind on requery */
37     private String[] mBindArgs;
38 
39     private boolean mClosed = false;
40 
41     /**
42      * Create a persistent query object.
43      *
44      * @param db The database that this query object is associated with
45      * @param query The SQL string for this query.
46      * @param offsetIndex The 1-based index to the OFFSET parameter,
47      */
SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs)48     /* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) {
49         super(db, query);
50 
51         mOffsetIndex = offsetIndex;
52         mQuery = query;
53         mBindArgs = bindArgs;
54     }
55 
56     /**
57      * Reads rows into a buffer. This method acquires the database lock.
58      *
59      * @param window The window to fill into
60      * @return number of total rows in the query
61      */
fillWindow(CursorWindow window, int maxRead, int lastPos)62     /* package */ int fillWindow(CursorWindow window,
63             int maxRead, int lastPos) {
64         mDatabase.lock();
65 
66         boolean logStats = mDatabase.mLogStats;
67         long startTime = logStats ? SystemClock.elapsedRealtime() : 0;
68         try {
69             acquireReference();
70             try {
71                 window.acquireReference();
72                 // if the start pos is not equal to 0, then most likely window is
73                 // too small for the data set, loading by another thread
74                 // is not safe in this situation. the native code will ignore maxRead
75                 int numRows = native_fill_window(window, window.getStartPosition(), mOffsetIndex,
76                         maxRead, lastPos);
77 
78                 // Logging
79                 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
80                     Log.d(TAG, "fillWindow(): " + mQuery);
81                 }
82                 if (logStats) {
83                     mDatabase.logTimeStat(true /* read */, startTime,
84                             SystemClock.elapsedRealtime());
85                 }
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             } finally {
94                 window.releaseReference();
95             }
96         } finally {
97             releaseReference();
98             mDatabase.unlock();
99         }
100     }
101 
102     /**
103      * Get the column count for the statement. Only valid on query based
104      * statements. The database must be locked
105      * when calling this method.
106      *
107      * @return The number of column in the statement's result set.
108      */
columnCountLocked()109     /* package */ int columnCountLocked() {
110         acquireReference();
111         try {
112             return native_column_count();
113         } finally {
114             releaseReference();
115         }
116     }
117 
118     /**
119      * Retrieves the column name for the given column index. The database must be locked
120      * when calling this method.
121      *
122      * @param columnIndex the index of the column to get the name for
123      * @return The requested column's name
124      */
columnNameLocked(int columnIndex)125     /* package */ String columnNameLocked(int columnIndex) {
126         acquireReference();
127         try {
128             return native_column_name(columnIndex);
129         } finally {
130             releaseReference();
131         }
132     }
133 
134     @Override
toString()135     public String toString() {
136         return "SQLiteQuery: " + mQuery;
137     }
138 
139     @Override
close()140     public void close() {
141         super.close();
142         mClosed = true;
143     }
144 
145     /**
146      * Called by SQLiteCursor when it is requeried.
147      */
requery()148     /* package */ void requery() {
149         if (mBindArgs != null) {
150             int len = mBindArgs.length;
151             try {
152                 for (int i = 0; i < len; i++) {
153                     super.bindString(i + 1, mBindArgs[i]);
154                 }
155             } catch (SQLiteMisuseException e) {
156                 StringBuilder errMsg = new StringBuilder("mQuery " + mQuery);
157                 for (int i = 0; i < len; i++) {
158                     errMsg.append(" ");
159                     errMsg.append(mBindArgs[i]);
160                 }
161                 errMsg.append(" ");
162                 IllegalStateException leakProgram = new IllegalStateException(
163                         errMsg.toString(), e);
164                 throw leakProgram;
165             }
166         }
167     }
168 
169     @Override
bindNull(int index)170     public void bindNull(int index) {
171         mBindArgs[index - 1] = null;
172         if (!mClosed) super.bindNull(index);
173     }
174 
175     @Override
bindLong(int index, long value)176     public void bindLong(int index, long value) {
177         mBindArgs[index - 1] = Long.toString(value);
178         if (!mClosed) super.bindLong(index, value);
179     }
180 
181     @Override
bindDouble(int index, double value)182     public void bindDouble(int index, double value) {
183         mBindArgs[index - 1] = Double.toString(value);
184         if (!mClosed) super.bindDouble(index, value);
185     }
186 
187     @Override
bindString(int index, String value)188     public void bindString(int index, String value) {
189         mBindArgs[index - 1] = value;
190         if (!mClosed) super.bindString(index, value);
191     }
192 
native_fill_window(CursorWindow window, int startPos, int offsetParam, int maxRead, int lastPos)193     private final native int native_fill_window(CursorWindow window,
194             int startPos, int offsetParam, int maxRead, int lastPos);
195 
native_column_count()196     private final native int native_column_count();
197 
native_column_name(int columnIndex)198     private final native String native_column_name(int columnIndex);
199 }
200