SQLiteStatement.java revision e25539fdfdf884eee55107efbcc893f44e82e00e
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.database.sqlite;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
196a353876178ca2fe4bc61f128130067d2c2574d1Brad Fitzpatrickimport android.os.SystemClock;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21cfda9f3a4756c71b3aadd1387419cb3b513dd400Brad Fitzpatrickimport dalvik.system.BlockGuard;
22cfda9f3a4756c71b3aadd1387419cb3b513dd400Brad Fitzpatrick
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A pre-compiled statement against a {@link SQLiteDatabase} that can be reused.
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The statement cannot return multiple rows, but 1x1 result sets are allowed.
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Don't use SQLiteStatement constructor directly, please use
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link SQLiteDatabase#compileStatement(String)}
28ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori *<p>
29f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * SQLiteStatement is not internally synchronized so code using a SQLiteStatement from multiple
30f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * threads should perform its own synchronization when using the SQLiteStatement.
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
322827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori@SuppressWarnings("deprecation")
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class SQLiteStatement extends SQLiteProgram
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
357501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    private static final boolean READ = true;
367501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    private static final boolean WRITE = false;
377501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori
38e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori    private SQLiteDatabase mOrigDb;
39e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Don't use SQLiteStatement constructor directly, please use
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link SQLiteDatabase#compileStatement(String)}
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param db
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param sql
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ SQLiteStatement(SQLiteDatabase db, String sql) {
472827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        super(db, sql, false /* don't compile sql statement */);
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Execute this SQL statement, if it is not a query. For example,
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * CREATE TABLE, DELTE, INSERT, etc.
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws android.database.SQLException If the SQL string is invalid for
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         some reason
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void execute() {
58e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        synchronized(this) {
59e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            long timeStart = acquireAndLock(WRITE);
60e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            try {
61e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                native_execute();
62e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                mDatabase.logTimeStat(mSql, timeStart);
63e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            } finally {
64e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                releaseAndUnlock();
65e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            }
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
705bf67247d2e299f0586de65b2d024f1f835657e0Vasu Nori     * Execute this SQL statement and return the ID of the row inserted due to this call.
715bf67247d2e299f0586de65b2d024f1f835657e0Vasu Nori     * The SQL statement should be an INSERT for this to be a useful call.
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
735bf67247d2e299f0586de65b2d024f1f835657e0Vasu Nori     * @return the row ID of the last row inserted, if this insert is successful. -1 otherwise.
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws android.database.SQLException If the SQL string is invalid for
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         some reason
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long executeInsert() {
79e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        synchronized(this) {
80e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            long timeStart = acquireAndLock(WRITE);
81e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            try {
82e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                native_execute();
83e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                mDatabase.logTimeStat(mSql, timeStart);
84e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                return (mDatabase.lastChangeCount() > 0) ? mDatabase.lastInsertRow() : -1;
85e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            } finally {
86e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                releaseAndUnlock();
87e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            }
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Execute a statement that returns a 1 by 1 table with a numeric value.
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For example, SELECT COUNT(*) FROM table;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The result of the query.
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long simpleQueryForLong() {
100e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        synchronized(this) {
101e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            long timeStart = acquireAndLock(READ);
102e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            try {
103e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                long retValue = native_1x1_long();
104e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                mDatabase.logTimeStat(mSql, timeStart);
105e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                return retValue;
106e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            } finally {
107e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                releaseAndUnlock();
108e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            }
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Execute a statement that returns a 1 by 1 table with a text value.
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For example, SELECT COUNT(*) FROM table;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The result of the query.
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String simpleQueryForString() {
121e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        synchronized(this) {
122e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            long timeStart = acquireAndLock(READ);
123e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            try {
124e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                String retValue = native_1x1_string();
125e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                mDatabase.logTimeStat(mSql, timeStart);
126e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                return retValue;
127e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            } finally {
128e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                releaseAndUnlock();
129e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            }
1307501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        }
1317501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    }
1327501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori
1337501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    /**
1347501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * Called before every method in this class before executing a SQL statement,
1357501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * this method does the following:
1367501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * <ul>
1377501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>make sure the database is open</li>
138e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori     *   <li>get a database connection from the connection pool,if possible</li>
1397501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>notifies {@link BlockGuard} of read/write</li>
1407501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>get lock on the database</li>
1417501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>acquire reference on this object</li>
1427501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>and then return the current time _before_ the database lock was acquired</li>
1437501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * </ul>
1447501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * <p>
1457501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * This method removes the duplcate code from the other public
1467501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * methods in this class.
1477501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     */
1487501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    private long acquireAndLock(boolean rwFlag) {
149e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        // use pooled database connection handles for SELECT SQL statements
150e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        mDatabase.verifyDbIsOpen();
151e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        SQLiteDatabase db = (getSqlStatementType(mSql) != SELECT_STMT) ? mDatabase
152e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                : mDatabase.getDbConnection(mSql);
153e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        // use the database connection obtained above
154e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        mOrigDb = mDatabase;
155e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        mDatabase = db;
156e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        nHandle = mDatabase.mNativeHandle;
1577501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        if (rwFlag == WRITE) {
1587501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori            BlockGuard.getThreadPolicy().onWriteToDisk();
1597501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        } else {
1607501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori            BlockGuard.getThreadPolicy().onReadFromDisk();
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1627501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        long startTime = SystemClock.uptimeMillis();
1637501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        mDatabase.lock();
1647501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        acquireReference();
1657501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        mDatabase.closePendingStatements();
166e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        compileAndbindAllArgs();
1677501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        return startTime;
1687501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    }
1697501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori
1707501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    /**
1717501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * this method releases locks and references acquired in {@link #acquireAndLock(boolean)}.
1727501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     */
1737501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    private void releaseAndUnlock() {
1747501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        releaseReference();
1757501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        mDatabase.unlock();
1762827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        clearBindings();
1772827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        // release the compiled sql statement so that the caller's SQLiteStatement no longer
1782827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        // has a hard reference to a database object that may get deallocated at any point.
1792827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        releaseCompiledSqlIfNotInCache();
180e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        // restore the database connection handle to the original value
181e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        mDatabase = mOrigDb;
182e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        nHandle = mDatabase.mNativeHandle;
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final native void native_execute();
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final native long native_1x1_long();
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final native String native_1x1_string();
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
189