SQLiteStatement.java revision fb16cbd9b2e86d6878d4bff820422bc09c8938de
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    /**
51fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     * Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example
52fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     * CREATE / DROP table, view, trigger, index 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() {
58fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori        executeUpdateDelete();
59fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori    }
60fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori
61fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori    /**
62fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     * Execute this SQL statement, if the the number of rows affected by exection of this SQL
63fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     * statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
64fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     *
65fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     * @return the number of rows affected by this SQL statement execution.
66fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     * @throws android.database.SQLException If the SQL string is invalid for
67fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     *         some reason
68fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori     */
69fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori    public int executeUpdateDelete() {
70e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        synchronized(this) {
71e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            long timeStart = acquireAndLock(WRITE);
72e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            try {
73fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori                int numChanges = native_execute();
74e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                mDatabase.logTimeStat(mSql, timeStart);
75fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori                return numChanges;
76e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            } finally {
77e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                releaseAndUnlock();
78e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
835bf67247d2e299f0586de65b2d024f1f835657e0Vasu Nori     * Execute this SQL statement and return the ID of the row inserted due to this call.
845bf67247d2e299f0586de65b2d024f1f835657e0Vasu Nori     * The SQL statement should be an INSERT for this to be a useful call.
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
865bf67247d2e299f0586de65b2d024f1f835657e0Vasu Nori     * @return the row ID of the last row inserted, if this insert is successful. -1 otherwise.
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws android.database.SQLException If the SQL string is invalid for
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         some reason
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long executeInsert() {
92e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        synchronized(this) {
93e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            long timeStart = acquireAndLock(WRITE);
94e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            try {
95fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori                long lastInsertedRowId = native_executeInsert();
96e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                mDatabase.logTimeStat(mSql, timeStart);
97fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori                return lastInsertedRowId;
98e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            } finally {
99e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                releaseAndUnlock();
100e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            }
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Execute a statement that returns a 1 by 1 table with a numeric value.
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For example, SELECT COUNT(*) FROM table;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The result of the query.
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long simpleQueryForLong() {
113e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        synchronized(this) {
114e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            long timeStart = acquireAndLock(READ);
115e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            try {
116e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                long retValue = native_1x1_long();
117e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                mDatabase.logTimeStat(mSql, timeStart);
118e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                return retValue;
119e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            } finally {
120e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                releaseAndUnlock();
121e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            }
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Execute a statement that returns a 1 by 1 table with a text value.
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For example, SELECT COUNT(*) FROM table;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The result of the query.
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String simpleQueryForString() {
134e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        synchronized(this) {
135e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            long timeStart = acquireAndLock(READ);
136e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            try {
137e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                String retValue = native_1x1_string();
138e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                mDatabase.logTimeStat(mSql, timeStart);
139e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                return retValue;
140e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            } finally {
141e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                releaseAndUnlock();
142e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori            }
1437501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        }
1447501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    }
1457501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori
1467501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    /**
1477501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * Called before every method in this class before executing a SQL statement,
1487501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * this method does the following:
1497501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * <ul>
1507501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>make sure the database is open</li>
151e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori     *   <li>get a database connection from the connection pool,if possible</li>
1527501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>notifies {@link BlockGuard} of read/write</li>
1537501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>get lock on the database</li>
1547501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>acquire reference on this object</li>
1557501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     *   <li>and then return the current time _before_ the database lock was acquired</li>
1567501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * </ul>
1577501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * <p>
1587501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * This method removes the duplcate code from the other public
1597501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * methods in this class.
1607501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     */
1617501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    private long acquireAndLock(boolean rwFlag) {
162e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        // use pooled database connection handles for SELECT SQL statements
163e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        mDatabase.verifyDbIsOpen();
164e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        SQLiteDatabase db = (getSqlStatementType(mSql) != SELECT_STMT) ? mDatabase
165e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori                : mDatabase.getDbConnection(mSql);
166e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        // use the database connection obtained above
167e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        mOrigDb = mDatabase;
168e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        mDatabase = db;
169e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        nHandle = mDatabase.mNativeHandle;
1707501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        if (rwFlag == WRITE) {
1717501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori            BlockGuard.getThreadPolicy().onWriteToDisk();
1727501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        } else {
1737501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori            BlockGuard.getThreadPolicy().onReadFromDisk();
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1757501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        long startTime = SystemClock.uptimeMillis();
1767501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        mDatabase.lock();
1777501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        acquireReference();
1787501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        mDatabase.closePendingStatements();
179e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        compileAndbindAllArgs();
1807501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        return startTime;
1817501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    }
1827501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori
1837501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    /**
1847501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     * this method releases locks and references acquired in {@link #acquireAndLock(boolean)}.
1857501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori     */
1867501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori    private void releaseAndUnlock() {
1877501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        releaseReference();
1887501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori        mDatabase.unlock();
1892827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        clearBindings();
1902827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        // release the compiled sql statement so that the caller's SQLiteStatement no longer
1912827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        // has a hard reference to a database object that may get deallocated at any point.
1922827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori        releaseCompiledSqlIfNotInCache();
193e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        // restore the database connection handle to the original value
194e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        mDatabase = mOrigDb;
195e25539fdfdf884eee55107efbcc893f44e82e00eVasu Nori        nHandle = mDatabase.mNativeHandle;
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
198fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori    private final native int native_execute();
199fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori    private final native long native_executeInsert();
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final native long native_1x1_long();
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final native String native_1x1_string();
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
203