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