Home | History | Annotate | Download | only in sqlite
      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     /** 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 = SystemClock.uptimeMillis();
     61         mDatabase.lock();
     62         mDatabase.logTimeStat(mSql, timeStart, SQLiteDatabase.GET_LOCK_LOG_PREFIX);
     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