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