SQLiteDatabase.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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.content.ContentValues;
20import android.database.Cursor;
21import android.database.DatabaseUtils;
22import android.database.SQLException;
23import android.os.Debug;
24import android.os.SystemClock;
25import android.text.TextUtils;
26import android.util.Config;
27import android.util.Log;
28import android.util.EventLog;
29
30import java.io.File;
31import java.util.HashMap;
32import java.util.Iterator;
33import java.util.Locale;
34import java.util.Map;
35import java.util.Set;
36import java.util.WeakHashMap;
37import java.util.concurrent.locks.ReentrantLock;
38
39/**
40 * Exposes methods to manage a SQLite database.
41 * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and
42 * perform other common database management tasks.
43 * <p>See the Notepad sample application in the SDK for an example of creating
44 * and managing a database.
45 * <p> Database names must be unique within an application, not across all
46 * applications.
47 *
48 * <h3>Localized Collation - ORDER BY</h3>
49 * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies
50 * two more, <code>LOCALIZED</code>, which changes with the system's current locale
51 * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which
52 * is the Unicode Collation Algorithm and not tailored to the current locale.
53 */
54public class SQLiteDatabase extends SQLiteClosable {
55    private static final String TAG = "Database";
56    private static final int DB_OPERATION_EVENT = 52000;
57
58    /**
59     * Algorithms used in ON CONFLICT clause
60     * http://www.sqlite.org/lang_conflict.html
61     * @hide
62     */
63    public enum ConflictAlgorithm {
64        /**
65         *  When a constraint violation occurs, an immediate ROLLBACK occurs,
66         * thus ending the current transaction, and the command aborts with a
67         * return code of SQLITE_CONSTRAINT. If no transaction is active
68         * (other than the implied transaction that is created on every command)
69         *  then this algorithm works the same as ABORT.
70         */
71        ROLLBACK("ROLLBACK"),
72
73        /**
74         * When a constraint violation occurs,no ROLLBACK is executed
75         * so changes from prior commands within the same transaction
76         * are preserved. This is the default behavior.
77         */
78        ABORT("ABORT"),
79
80        /**
81         * When a constraint violation occurs, the command aborts with a return
82         * code SQLITE_CONSTRAINT. But any changes to the database that
83         * the command made prior to encountering the constraint violation
84         * are preserved and are not backed out.
85         */
86        FAIL("FAIL"),
87
88        /**
89         * When a constraint violation occurs, the one row that contains
90         * the constraint violation is not inserted or changed.
91         * But the command continues executing normally. Other rows before and
92         * after the row that contained the constraint violation continue to be
93         * inserted or updated normally. No error is returned.
94         */
95        IGNORE("IGNORE"),
96
97        /**
98         * When a UNIQUE constraint violation occurs, the pre-existing rows that
99         * are causing the constraint violation are removed prior to inserting
100         * or updating the current row. Thus the insert or update always occurs.
101         * The command continues executing normally. No error is returned.
102         * If a NOT NULL constraint violation occurs, the NULL value is replaced
103         * by the default value for that column. If the column has no default
104         * value, then the ABORT algorithm is used. If a CHECK constraint
105         * violation occurs then the IGNORE algorithm is used. When this conflict
106         * resolution strategy deletes rows in order to satisfy a constraint,
107         * it does not invoke delete triggers on those rows.
108         *  This behavior might change in a future release.
109         */
110        REPLACE("REPLACE");
111
112        private final String mValue;
113        ConflictAlgorithm(String value) {
114            mValue = value;
115        }
116        public String value() {
117            return mValue;
118        }
119    }
120
121    /**
122     * Maximum Length Of A LIKE Or GLOB Pattern
123     * The pattern matching algorithm used in the default LIKE and GLOB implementation
124     * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
125     * the pattern) for certain pathological cases. To avoid denial-of-service attacks
126     * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes.
127     * The default value of this limit is 50000. A modern workstation can evaluate
128     * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
129     * The denial of service problem only comes into play when the pattern length gets
130     * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
131     * are at most a few dozen bytes in length, paranoid application developers may
132     * want to reduce this parameter to something in the range of a few hundred
133     * if they know that external users are able to generate arbitrary patterns.
134     */
135    public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
136
137    /**
138     * Flag for {@link #openDatabase} to open the database for reading and writing.
139     * If the disk is full, this may fail even before you actually write anything.
140     *
141     * {@more} Note that the value of this flag is 0, so it is the default.
142     */
143    public static final int OPEN_READWRITE = 0x00000000;          // update native code if changing
144
145    /**
146     * Flag for {@link #openDatabase} to open the database for reading only.
147     * This is the only reliable way to open a database if the disk may be full.
148     */
149    public static final int OPEN_READONLY = 0x00000001;           // update native code if changing
150
151    private static final int OPEN_READ_MASK = 0x00000001;         // update native code if changing
152
153    /**
154     * Flag for {@link #openDatabase} to open the database without support for localized collators.
155     *
156     * {@more} This causes the collator <code>LOCALIZED</code> not to be created.
157     * You must be consistent when using this flag to use the setting the database was
158     * created with.  If this is set, {@link #setLocale} will do nothing.
159     */
160    public static final int NO_LOCALIZED_COLLATORS = 0x00000010;  // update native code if changing
161
162    /**
163     * Flag for {@link #openDatabase} to create the database file if it does not already exist.
164     */
165    public static final int CREATE_IF_NECESSARY = 0x10000000;     // update native code if changing
166
167    /**
168     * Indicates whether the most-recently started transaction has been marked as successful.
169     */
170    private boolean mInnerTransactionIsSuccessful;
171
172    /**
173     * Valid during the life of a transaction, and indicates whether the entire transaction (the
174     * outer one and all of the inner ones) so far has been successful.
175     */
176    private boolean mTransactionIsSuccessful;
177
178    /** Synchronize on this when accessing the database */
179    private final ReentrantLock mLock = new ReentrantLock(true);
180
181    private long mLockAcquiredWallTime = 0L;
182    private long mLockAcquiredThreadTime = 0L;
183
184    // limit the frequency of complaints about each database to one within 20 sec
185    // unless run command adb shell setprop log.tag.Database VERBOSE
186    private static final int LOCK_WARNING_WINDOW_IN_MS = 20000;
187    /** If the lock is held this long then a warning will be printed when it is released. */
188    private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300;
189    private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100;
190    private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000;
191
192    private long mLastLockMessageTime = 0L;
193
194    /** Used by native code, do not rename */
195    /* package */ int mNativeHandle = 0;
196
197    /** Used to make temp table names unique */
198    /* package */ int mTempTableSequence = 0;
199
200    /** The path for the database file */
201    private String mPath;
202
203    /** The flags passed to open/create */
204    private int mFlags;
205
206    /** The optional factory to use when creating new Cursors */
207    private CursorFactory mFactory;
208
209    private WeakHashMap<SQLiteClosable, Object> mPrograms;
210
211    private final RuntimeException mLeakedException;
212
213    // package visible, since callers will access directly to minimize overhead in the case
214    // that logging is not enabled.
215    /* package */ final boolean mLogStats;
216
217    /**
218     * @param closable
219     */
220    void addSQLiteClosable(SQLiteClosable closable) {
221        lock();
222        try {
223            mPrograms.put(closable, null);
224        } finally {
225            unlock();
226        }
227    }
228
229    void removeSQLiteClosable(SQLiteClosable closable) {
230        lock();
231        try {
232            mPrograms.remove(closable);
233        } finally {
234            unlock();
235        }
236    }
237
238    @Override
239    protected void onAllReferencesReleased() {
240        if (isOpen()) {
241            dbclose();
242        }
243    }
244
245    /**
246     * Attempts to release memory that SQLite holds but does not require to
247     * operate properly. Typically this memory will come from the page cache.
248     *
249     * @return the number of bytes actually released
250     */
251    static public native int releaseMemory();
252
253    /**
254     * Control whether or not the SQLiteDatabase is made thread-safe by using locks
255     * around critical sections. This is pretty expensive, so if you know that your
256     * DB will only be used by a single thread then you should set this to false.
257     * The default is true.
258     * @param lockingEnabled set to true to enable locks, false otherwise
259     */
260    public void setLockingEnabled(boolean lockingEnabled) {
261        mLockingEnabled = lockingEnabled;
262    }
263
264    /**
265     * If set then the SQLiteDatabase is made thread-safe by using locks
266     * around critical sections
267     */
268    private boolean mLockingEnabled = true;
269
270    /* package */ void onCorruption() {
271        try {
272            // Close the database (if we can), which will cause subsequent operations to fail.
273            close();
274        } finally {
275            Log.e(TAG, "Removing corrupt database: " + mPath);
276            // Delete the corrupt file.  Don't re-create it now -- that would just confuse people
277            // -- but the next time someone tries to open it, they can set it up from scratch.
278            new File(mPath).delete();
279        }
280    }
281
282    /**
283     * Locks the database for exclusive access. The database lock must be held when
284     * touch the native sqlite3* object since it is single threaded and uses
285     * a polling lock contention algorithm. The lock is recursive, and may be acquired
286     * multiple times by the same thread. This is a no-op if mLockingEnabled is false.
287     *
288     * @see #unlock()
289     */
290    /* package */ void lock() {
291        if (!mLockingEnabled) return;
292        mLock.lock();
293        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
294            if (mLock.getHoldCount() == 1) {
295                // Use elapsed real-time since the CPU may sleep when waiting for IO
296                mLockAcquiredWallTime = SystemClock.elapsedRealtime();
297                mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
298            }
299        }
300    }
301
302    /**
303     * Locks the database for exclusive access. The database lock must be held when
304     * touch the native sqlite3* object since it is single threaded and uses
305     * a polling lock contention algorithm. The lock is recursive, and may be acquired
306     * multiple times by the same thread.
307     *
308     * @see #unlockForced()
309     */
310    private void lockForced() {
311        mLock.lock();
312        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
313            if (mLock.getHoldCount() == 1) {
314                // Use elapsed real-time since the CPU may sleep when waiting for IO
315                mLockAcquiredWallTime = SystemClock.elapsedRealtime();
316                mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
317            }
318        }
319    }
320
321    /**
322     * Releases the database lock. This is a no-op if mLockingEnabled is false.
323     *
324     * @see #unlock()
325     */
326    /* package */ void unlock() {
327        if (!mLockingEnabled) return;
328        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
329            if (mLock.getHoldCount() == 1) {
330                checkLockHoldTime();
331            }
332        }
333        mLock.unlock();
334    }
335
336    /**
337     * Releases the database lock.
338     *
339     * @see #unlockForced()
340     */
341    private void unlockForced() {
342        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
343            if (mLock.getHoldCount() == 1) {
344                checkLockHoldTime();
345            }
346        }
347        mLock.unlock();
348    }
349
350    private void checkLockHoldTime() {
351        // Use elapsed real-time since the CPU may sleep when waiting for IO
352        long elapsedTime = SystemClock.elapsedRealtime();
353        long lockedTime = elapsedTime - mLockAcquiredWallTime;
354        if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT &&
355                !Log.isLoggable(TAG, Log.VERBOSE) &&
356                (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) {
357            return;
358        }
359        if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) {
360            int threadTime = (int)
361                    ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000);
362            if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS ||
363                    lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) {
364                mLastLockMessageTime = elapsedTime;
365                String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was "
366                        + threadTime + "ms";
367                if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) {
368                    Log.d(TAG, msg, new Exception());
369                } else {
370                    Log.d(TAG, msg);
371                }
372            }
373        }
374    }
375
376    /**
377     * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
378     * the work done in that transaction and all of the nested transactions will be committed or
379     * rolled back. The changes will be rolled back if any transaction is ended without being
380     * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
381     *
382     * <p>Here is the standard idiom for transactions:
383     *
384     * <pre>
385     *   db.beginTransaction();
386     *   try {
387     *     ...
388     *     db.setTransactionSuccessful();
389     *   } finally {
390     *     db.endTransaction();
391     *   }
392     * </pre>
393     */
394    public void beginTransaction() {
395        lockForced();
396        boolean ok = false;
397        try {
398            // If this thread already had the lock then get out
399            if (mLock.getHoldCount() > 1) {
400                if (mInnerTransactionIsSuccessful) {
401                    String msg = "Cannot call beginTransaction between "
402                            + "calling setTransactionSuccessful and endTransaction";
403                    IllegalStateException e = new IllegalStateException(msg);
404                    Log.e(TAG, "beginTransaction() failed", e);
405                    throw e;
406                }
407                ok = true;
408                return;
409            }
410
411            // This thread didn't already have the lock, so begin a database
412            // transaction now.
413            execSQL("BEGIN EXCLUSIVE;");
414            mTransactionIsSuccessful = true;
415            mInnerTransactionIsSuccessful = false;
416            ok = true;
417        } finally {
418            if (!ok) {
419                // beginTransaction is called before the try block so we must release the lock in
420                // the case of failure.
421                unlockForced();
422            }
423        }
424    }
425
426    /**
427     * End a transaction. See beginTransaction for notes about how to use this and when transactions
428     * are committed and rolled back.
429     */
430    public void endTransaction() {
431        if (!mLock.isHeldByCurrentThread()) {
432            throw new IllegalStateException("no transaction pending");
433        }
434        try {
435            if (mInnerTransactionIsSuccessful) {
436                mInnerTransactionIsSuccessful = false;
437            } else {
438                mTransactionIsSuccessful = false;
439            }
440            if (mLock.getHoldCount() != 1) {
441                return;
442            }
443            if (mTransactionIsSuccessful) {
444                execSQL("COMMIT;");
445            } else {
446                try {
447                    execSQL("ROLLBACK;");
448                } catch (SQLException e) {
449                    if (Config.LOGD) {
450                        Log.d(TAG, "exception during rollback, maybe the DB previously "
451                                + "performed an auto-rollback");
452                    }
453                }
454            }
455        } finally {
456            unlockForced();
457            if (Config.LOGV) {
458                Log.v(TAG, "unlocked " + Thread.currentThread()
459                        + ", holdCount is " + mLock.getHoldCount());
460            }
461        }
462    }
463
464    /**
465     * Marks the current transaction as successful. Do not do any more database work between
466     * calling this and calling endTransaction. Do as little non-database work as possible in that
467     * situation too. If any errors are encountered between this and endTransaction the transaction
468     * will still be committed.
469     *
470     * @throws IllegalStateException if the current thread is not in a transaction or the
471     * transaction is already marked as successful.
472     */
473    public void setTransactionSuccessful() {
474        if (!mLock.isHeldByCurrentThread()) {
475            throw new IllegalStateException("no transaction pending");
476        }
477        if (mInnerTransactionIsSuccessful) {
478            throw new IllegalStateException(
479                    "setTransactionSuccessful may only be called once per call to beginTransaction");
480        }
481        mInnerTransactionIsSuccessful = true;
482    }
483
484    /**
485     * return true if there is a transaction pending
486     */
487    public boolean inTransaction() {
488        return mLock.getHoldCount() > 0;
489    }
490
491    /**
492     * Checks if the database lock is held by this thread.
493     *
494     * @return true, if this thread is holding the database lock.
495     */
496    public boolean isDbLockedByCurrentThread() {
497        return mLock.isHeldByCurrentThread();
498    }
499
500    /**
501     * Checks if the database is locked by another thread. This is
502     * just an estimate, since this status can change at any time,
503     * including after the call is made but before the result has
504     * been acted upon.
505     *
506     * @return true, if the database is locked by another thread
507     */
508    public boolean isDbLockedByOtherThreads() {
509        return !mLock.isHeldByCurrentThread() && mLock.isLocked();
510    }
511
512    /**
513     * Temporarily end the transaction to let other threads run. The transaction is assumed to be
514     * successful so far. Do not call setTransactionSuccessful before calling this. When this
515     * returns a new transaction will have been created but not marked as successful.
516     * @return true if the transaction was yielded
517     * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
518     *   will not be yielded. Use yieldIfContendedSafely instead.
519     */
520    public boolean yieldIfContended() {
521        return yieldIfContendedHelper(false /* do not check yielding */);
522    }
523
524    /**
525     * Temporarily end the transaction to let other threads run. The transaction is assumed to be
526     * successful so far. Do not call setTransactionSuccessful before calling this. When this
527     * returns a new transaction will have been created but not marked as successful. This assumes
528     * that there are no nested transactions (beginTransaction has only been called once) and will
529     * through an exception if that is not the case.
530     * @return true if the transaction was yielded
531     */
532    public boolean yieldIfContendedSafely() {
533        return yieldIfContendedHelper(true /* check yielding */);
534    }
535
536    private boolean yieldIfContendedHelper(boolean checkFullyYielded) {
537        if (mLock.getQueueLength() == 0) {
538            // Reset the lock acquire time since we know that the thread was willing to yield
539            // the lock at this time.
540            mLockAcquiredWallTime = SystemClock.elapsedRealtime();
541            mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
542            return false;
543        }
544        setTransactionSuccessful();
545        endTransaction();
546        if (checkFullyYielded) {
547            if (this.isDbLockedByCurrentThread()) {
548                throw new IllegalStateException(
549                        "Db locked more than once. yielfIfContended cannot yield");
550            }
551        }
552        beginTransaction();
553        return true;
554    }
555
556    /** Maps table names to info about what to which _sync_time column to set
557     * to NULL on an update. This is used to support syncing. */
558    private final Map<String, SyncUpdateInfo> mSyncUpdateInfo =
559            new HashMap<String, SyncUpdateInfo>();
560
561    public Map<String, String> getSyncedTables() {
562        synchronized(mSyncUpdateInfo) {
563            HashMap<String, String> tables = new HashMap<String, String>();
564            for (String table : mSyncUpdateInfo.keySet()) {
565                SyncUpdateInfo info = mSyncUpdateInfo.get(table);
566                if (info.deletedTable != null) {
567                    tables.put(table, info.deletedTable);
568                }
569            }
570            return tables;
571        }
572    }
573
574    /**
575     * Internal class used to keep track what needs to be marked as changed
576     * when an update occurs. This is used for syncing, so the sync engine
577     * knows what data has been updated locally.
578     */
579    static private class SyncUpdateInfo {
580        /**
581         * Creates the SyncUpdateInfo class.
582         *
583         * @param masterTable The table to set _sync_time to NULL in
584         * @param deletedTable The deleted table that corresponds to the
585         *          master table
586         * @param foreignKey The key that refers to the primary key in table
587         */
588        SyncUpdateInfo(String masterTable, String deletedTable,
589                String foreignKey) {
590            this.masterTable = masterTable;
591            this.deletedTable = deletedTable;
592            this.foreignKey = foreignKey;
593        }
594
595        /** The table containing the _sync_time column */
596        String masterTable;
597
598        /** The deleted table that corresponds to the master table */
599        String deletedTable;
600
601        /** The key in the local table the row in table. It may be _id, if table
602         * is the local table. */
603        String foreignKey;
604    }
605
606    /**
607     * Used to allow returning sub-classes of {@link Cursor} when calling query.
608     */
609    public interface CursorFactory {
610        /**
611         * See
612         * {@link SQLiteCursor#SQLiteCursor(SQLiteDatabase, SQLiteCursorDriver,
613         * String, SQLiteQuery)}.
614         */
615        public Cursor newCursor(SQLiteDatabase db,
616                SQLiteCursorDriver masterQuery, String editTable,
617                SQLiteQuery query);
618    }
619
620    /**
621     * Open the database according to the flags {@link #OPEN_READWRITE}
622     * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
623     *
624     * <p>Sets the locale of the database to the  the system's current locale.
625     * Call {@link #setLocale} if you would like something else.</p>
626     *
627     * @param path to database file to open and/or create
628     * @param factory an optional factory class that is called to instantiate a
629     *            cursor when query is called, or null for default
630     * @param flags to control database access mode
631     * @return the newly opened database
632     * @throws SQLiteException if the database cannot be opened
633     */
634    public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
635        SQLiteDatabase db = null;
636        try {
637            // Open the database.
638            return new SQLiteDatabase(path, factory, flags);
639        } catch (SQLiteDatabaseCorruptException e) {
640            // Try to recover from this, if we can.
641            // TODO: should we do this for other open failures?
642            Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
643            new File(path).delete();
644            return new SQLiteDatabase(path, factory, flags);
645        }
646    }
647
648    /**
649     * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
650     */
651    public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
652        return openOrCreateDatabase(file.getPath(), factory);
653    }
654
655    /**
656     * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
657     */
658    public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
659        return openDatabase(path, factory, CREATE_IF_NECESSARY);
660    }
661
662    /**
663     * Create a memory backed SQLite database.  Its contents will be destroyed
664     * when the database is closed.
665     *
666     * <p>Sets the locale of the database to the  the system's current locale.
667     * Call {@link #setLocale} if you would like something else.</p>
668     *
669     * @param factory an optional factory class that is called to instantiate a
670     *            cursor when query is called
671     * @return a SQLiteDatabase object, or null if the database can't be created
672     */
673    public static SQLiteDatabase create(CursorFactory factory) {
674        // This is a magic string with special meaning for SQLite.
675        return openDatabase(":memory:", factory, CREATE_IF_NECESSARY);
676    }
677
678    /**
679     * Close the database.
680     */
681    public void close() {
682        lock();
683        try {
684            closeClosable();
685            releaseReference();
686        } finally {
687            unlock();
688        }
689    }
690
691    private void closeClosable() {
692        Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
693        while (iter.hasNext()) {
694            Map.Entry<SQLiteClosable, Object> entry = iter.next();
695            SQLiteClosable program = entry.getKey();
696            if (program != null) {
697                program.onAllReferencesReleasedFromContainer();
698            }
699        }
700    }
701
702    /**
703     * Native call to close the database.
704     */
705    private native void dbclose();
706
707    /**
708     * Gets the database version.
709     *
710     * @return the database version
711     */
712    public int getVersion() {
713        SQLiteStatement prog = null;
714        lock();
715        try {
716            prog = new SQLiteStatement(this, "PRAGMA user_version;");
717            long version = prog.simpleQueryForLong();
718            return (int) version;
719        } finally {
720            if (prog != null) prog.close();
721            unlock();
722        }
723    }
724
725    /**
726     * Sets the database version.
727     *
728     * @param version the new database version
729     */
730    public void setVersion(int version) {
731        execSQL("PRAGMA user_version = " + version);
732    }
733
734    /**
735     * Returns the maximum size the database may grow to.
736     *
737     * @return the new maximum database size
738     */
739    public long getMaximumSize() {
740        SQLiteStatement prog = null;
741        lock();
742        try {
743            prog = new SQLiteStatement(this,
744                    "PRAGMA max_page_count;");
745            long pageCount = prog.simpleQueryForLong();
746            return pageCount * getPageSize();
747        } finally {
748            if (prog != null) prog.close();
749            unlock();
750        }
751    }
752
753    /**
754     * Sets the maximum size the database will grow to. The maximum size cannot
755     * be set below the current size.
756     *
757     * @param numBytes the maximum database size, in bytes
758     * @return the new maximum database size
759     */
760    public long setMaximumSize(long numBytes) {
761        SQLiteStatement prog = null;
762        lock();
763        try {
764            long pageSize = getPageSize();
765            long numPages = numBytes / pageSize;
766            // If numBytes isn't a multiple of pageSize, bump up a page
767            if ((numBytes % pageSize) != 0) {
768                numPages++;
769            }
770            prog = new SQLiteStatement(this,
771                    "PRAGMA max_page_count = " + numPages);
772            long newPageCount = prog.simpleQueryForLong();
773            return newPageCount * pageSize;
774        } finally {
775            if (prog != null) prog.close();
776            unlock();
777        }
778    }
779
780    /**
781     * Returns the current database page size, in bytes.
782     *
783     * @return the database page size, in bytes
784     */
785    public long getPageSize() {
786        SQLiteStatement prog = null;
787        lock();
788        try {
789            prog = new SQLiteStatement(this,
790                    "PRAGMA page_size;");
791            long size = prog.simpleQueryForLong();
792            return size;
793        } finally {
794            if (prog != null) prog.close();
795            unlock();
796        }
797    }
798
799    /**
800     * Sets the database page size. The page size must be a power of two. This
801     * method does not work if any data has been written to the database file,
802     * and must be called right after the database has been created.
803     *
804     * @param numBytes the database page size, in bytes
805     */
806    public void setPageSize(long numBytes) {
807        execSQL("PRAGMA page_size = " + numBytes);
808    }
809
810    /**
811     * Mark this table as syncable. When an update occurs in this table the
812     * _sync_dirty field will be set to ensure proper syncing operation.
813     *
814     * @param table the table to mark as syncable
815     * @param deletedTable The deleted table that corresponds to the
816     *          syncable table
817     */
818    public void markTableSyncable(String table, String deletedTable) {
819        markTableSyncable(table, "_id", table, deletedTable);
820    }
821
822    /**
823     * Mark this table as syncable, with the _sync_dirty residing in another
824     * table. When an update occurs in this table the _sync_dirty field of the
825     * row in updateTable with the _id in foreignKey will be set to
826     * ensure proper syncing operation.
827     *
828     * @param table an update on this table will trigger a sync time removal
829     * @param foreignKey this is the column in table whose value is an _id in
830     *          updateTable
831     * @param updateTable this is the table that will have its _sync_dirty
832     */
833    public void markTableSyncable(String table, String foreignKey,
834            String updateTable) {
835        markTableSyncable(table, foreignKey, updateTable, null);
836    }
837
838    /**
839     * Mark this table as syncable, with the _sync_dirty residing in another
840     * table. When an update occurs in this table the _sync_dirty field of the
841     * row in updateTable with the _id in foreignKey will be set to
842     * ensure proper syncing operation.
843     *
844     * @param table an update on this table will trigger a sync time removal
845     * @param foreignKey this is the column in table whose value is an _id in
846     *          updateTable
847     * @param updateTable this is the table that will have its _sync_dirty
848     * @param deletedTable The deleted table that corresponds to the
849     *          updateTable
850     */
851    private void markTableSyncable(String table, String foreignKey,
852            String updateTable, String deletedTable) {
853        lock();
854        try {
855            native_execSQL("SELECT _sync_dirty FROM " + updateTable
856                    + " LIMIT 0");
857            native_execSQL("SELECT " + foreignKey + " FROM " + table
858                    + " LIMIT 0");
859        } finally {
860            unlock();
861        }
862
863        SyncUpdateInfo info = new SyncUpdateInfo(updateTable, deletedTable,
864                foreignKey);
865        synchronized (mSyncUpdateInfo) {
866            mSyncUpdateInfo.put(table, info);
867        }
868    }
869
870    /**
871     * Call for each row that is updated in a cursor.
872     *
873     * @param table the table the row is in
874     * @param rowId the row ID of the updated row
875     */
876    /* package */ void rowUpdated(String table, long rowId) {
877        SyncUpdateInfo info;
878        synchronized (mSyncUpdateInfo) {
879            info = mSyncUpdateInfo.get(table);
880        }
881        if (info != null) {
882            execSQL("UPDATE " + info.masterTable
883                    + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey
884                    + " FROM " + table + " WHERE _id=" + rowId + ")");
885        }
886    }
887
888    /**
889     * Finds the name of the first table, which is editable.
890     *
891     * @param tables a list of tables
892     * @return the first table listed
893     */
894    public static String findEditTable(String tables) {
895        if (!TextUtils.isEmpty(tables)) {
896            // find the first word terminated by either a space or a comma
897            int spacepos = tables.indexOf(' ');
898            int commapos = tables.indexOf(',');
899
900            if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
901                return tables.substring(0, spacepos);
902            } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
903                return tables.substring(0, commapos);
904            }
905            return tables;
906        } else {
907            throw new IllegalStateException("Invalid tables");
908        }
909    }
910
911    /**
912     * Compiles an SQL statement into a reusable pre-compiled statement object.
913     * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
914     * statement and fill in those values with {@link SQLiteProgram#bindString}
915     * and {@link SQLiteProgram#bindLong} each time you want to run the
916     * statement. Statements may not return result sets larger than 1x1.
917     *
918     * @param sql The raw SQL statement, may contain ? for unknown values to be
919     *            bound later.
920     * @return a pre-compiled statement object.
921     */
922    public SQLiteStatement compileStatement(String sql) throws SQLException {
923        lock();
924        try {
925            return new SQLiteStatement(this, sql);
926        } finally {
927            unlock();
928        }
929    }
930
931    /**
932     * Query the given URL, returning a {@link Cursor} over the result set.
933     *
934     * @param distinct true if you want each row to be unique, false otherwise.
935     * @param table The table name to compile the query against.
936     * @param columns A list of which columns to return. Passing null will
937     *            return all columns, which is discouraged to prevent reading
938     *            data from storage that isn't going to be used.
939     * @param selection A filter declaring which rows to return, formatted as an
940     *            SQL WHERE clause (excluding the WHERE itself). Passing null
941     *            will return all rows for the given table.
942     * @param selectionArgs You may include ?s in selection, which will be
943     *         replaced by the values from selectionArgs, in order that they
944     *         appear in the selection. The values will be bound as Strings.
945     * @param groupBy A filter declaring how to group rows, formatted as an SQL
946     *            GROUP BY clause (excluding the GROUP BY itself). Passing null
947     *            will cause the rows to not be grouped.
948     * @param having A filter declare which row groups to include in the cursor,
949     *            if row grouping is being used, formatted as an SQL HAVING
950     *            clause (excluding the HAVING itself). Passing null will cause
951     *            all row groups to be included, and is required when row
952     *            grouping is not being used.
953     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
954     *            (excluding the ORDER BY itself). Passing null will use the
955     *            default sort order, which may be unordered.
956     * @param limit Limits the number of rows returned by the query,
957     *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
958     * @return A Cursor object, which is positioned before the first entry
959     * @see Cursor
960     */
961    public Cursor query(boolean distinct, String table, String[] columns,
962            String selection, String[] selectionArgs, String groupBy,
963            String having, String orderBy, String limit) {
964        return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
965                groupBy, having, orderBy, limit);
966    }
967
968    /**
969     * Query the given URL, returning a {@link Cursor} over the result set.
970     *
971     * @param cursorFactory the cursor factory to use, or null for the default factory
972     * @param distinct true if you want each row to be unique, false otherwise.
973     * @param table The table name to compile the query against.
974     * @param columns A list of which columns to return. Passing null will
975     *            return all columns, which is discouraged to prevent reading
976     *            data from storage that isn't going to be used.
977     * @param selection A filter declaring which rows to return, formatted as an
978     *            SQL WHERE clause (excluding the WHERE itself). Passing null
979     *            will return all rows for the given table.
980     * @param selectionArgs You may include ?s in selection, which will be
981     *         replaced by the values from selectionArgs, in order that they
982     *         appear in the selection. The values will be bound as Strings.
983     * @param groupBy A filter declaring how to group rows, formatted as an SQL
984     *            GROUP BY clause (excluding the GROUP BY itself). Passing null
985     *            will cause the rows to not be grouped.
986     * @param having A filter declare which row groups to include in the cursor,
987     *            if row grouping is being used, formatted as an SQL HAVING
988     *            clause (excluding the HAVING itself). Passing null will cause
989     *            all row groups to be included, and is required when row
990     *            grouping is not being used.
991     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
992     *            (excluding the ORDER BY itself). Passing null will use the
993     *            default sort order, which may be unordered.
994     * @param limit Limits the number of rows returned by the query,
995     *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
996     * @return A Cursor object, which is positioned before the first entry
997     * @see Cursor
998     */
999    public Cursor queryWithFactory(CursorFactory cursorFactory,
1000            boolean distinct, String table, String[] columns,
1001            String selection, String[] selectionArgs, String groupBy,
1002            String having, String orderBy, String limit) {
1003        String sql = SQLiteQueryBuilder.buildQueryString(
1004                distinct, table, columns, selection, groupBy, having, orderBy, limit);
1005
1006        return rawQueryWithFactory(
1007                cursorFactory, sql, selectionArgs, findEditTable(table));
1008    }
1009
1010    /**
1011     * Query the given table, returning a {@link Cursor} over the result set.
1012     *
1013     * @param table The table name to compile the query against.
1014     * @param columns A list of which columns to return. Passing null will
1015     *            return all columns, which is discouraged to prevent reading
1016     *            data from storage that isn't going to be used.
1017     * @param selection A filter declaring which rows to return, formatted as an
1018     *            SQL WHERE clause (excluding the WHERE itself). Passing null
1019     *            will return all rows for the given table.
1020     * @param selectionArgs You may include ?s in selection, which will be
1021     *         replaced by the values from selectionArgs, in order that they
1022     *         appear in the selection. The values will be bound as Strings.
1023     * @param groupBy A filter declaring how to group rows, formatted as an SQL
1024     *            GROUP BY clause (excluding the GROUP BY itself). Passing null
1025     *            will cause the rows to not be grouped.
1026     * @param having A filter declare which row groups to include in the cursor,
1027     *            if row grouping is being used, formatted as an SQL HAVING
1028     *            clause (excluding the HAVING itself). Passing null will cause
1029     *            all row groups to be included, and is required when row
1030     *            grouping is not being used.
1031     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1032     *            (excluding the ORDER BY itself). Passing null will use the
1033     *            default sort order, which may be unordered.
1034     * @return A {@link Cursor} object, which is positioned before the first entry
1035     * @see Cursor
1036     */
1037    public Cursor query(String table, String[] columns, String selection,
1038            String[] selectionArgs, String groupBy, String having,
1039            String orderBy) {
1040
1041        return query(false, table, columns, selection, selectionArgs, groupBy,
1042                having, orderBy, null /* limit */);
1043    }
1044
1045    /**
1046     * Query the given table, returning a {@link Cursor} over the result set.
1047     *
1048     * @param table The table name to compile the query against.
1049     * @param columns A list of which columns to return. Passing null will
1050     *            return all columns, which is discouraged to prevent reading
1051     *            data from storage that isn't going to be used.
1052     * @param selection A filter declaring which rows to return, formatted as an
1053     *            SQL WHERE clause (excluding the WHERE itself). Passing null
1054     *            will return all rows for the given table.
1055     * @param selectionArgs You may include ?s in selection, which will be
1056     *         replaced by the values from selectionArgs, in order that they
1057     *         appear in the selection. The values will be bound as Strings.
1058     * @param groupBy A filter declaring how to group rows, formatted as an SQL
1059     *            GROUP BY clause (excluding the GROUP BY itself). Passing null
1060     *            will cause the rows to not be grouped.
1061     * @param having A filter declare which row groups to include in the cursor,
1062     *            if row grouping is being used, formatted as an SQL HAVING
1063     *            clause (excluding the HAVING itself). Passing null will cause
1064     *            all row groups to be included, and is required when row
1065     *            grouping is not being used.
1066     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1067     *            (excluding the ORDER BY itself). Passing null will use the
1068     *            default sort order, which may be unordered.
1069     * @param limit Limits the number of rows returned by the query,
1070     *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1071     * @return A {@link Cursor} object, which is positioned before the first entry
1072     * @see Cursor
1073     */
1074    public Cursor query(String table, String[] columns, String selection,
1075            String[] selectionArgs, String groupBy, String having,
1076            String orderBy, String limit) {
1077
1078        return query(false, table, columns, selection, selectionArgs, groupBy,
1079                having, orderBy, limit);
1080    }
1081
1082    /**
1083     * Runs the provided SQL and returns a {@link Cursor} over the result set.
1084     *
1085     * @param sql the SQL query. The SQL string must not be ; terminated
1086     * @param selectionArgs You may include ?s in where clause in the query,
1087     *     which will be replaced by the values from selectionArgs. The
1088     *     values will be bound as Strings.
1089     * @return A {@link Cursor} object, which is positioned before the first entry
1090     */
1091    public Cursor rawQuery(String sql, String[] selectionArgs) {
1092        return rawQueryWithFactory(null, sql, selectionArgs, null);
1093    }
1094
1095    /**
1096     * Runs the provided SQL and returns a cursor over the result set.
1097     *
1098     * @param cursorFactory the cursor factory to use, or null for the default factory
1099     * @param sql the SQL query. The SQL string must not be ; terminated
1100     * @param selectionArgs You may include ?s in where clause in the query,
1101     *     which will be replaced by the values from selectionArgs. The
1102     *     values will be bound as Strings.
1103     * @param editTable the name of the first table, which is editable
1104     * @return A {@link Cursor} object, which is positioned before the first entry
1105     */
1106    public Cursor rawQueryWithFactory(
1107            CursorFactory cursorFactory, String sql, String[] selectionArgs,
1108            String editTable) {
1109        long timeStart = 0;
1110
1111        if (Config.LOGV) {
1112            timeStart = System.currentTimeMillis();
1113        }
1114
1115        SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
1116
1117        try {
1118            return driver.query(
1119                    cursorFactory != null ? cursorFactory : mFactory,
1120                    selectionArgs);
1121        } finally {
1122            if (Config.LOGV) {
1123                long duration = System.currentTimeMillis() - timeStart;
1124
1125                Log.v(SQLiteCursor.TAG,
1126                      "query (" + duration + " ms): " + driver.toString() + ", args are "
1127                              + (selectionArgs != null
1128                              ? TextUtils.join(",", selectionArgs)
1129                              : "<null>"));
1130            }
1131        }
1132    }
1133
1134    /**
1135     * Runs the provided SQL and returns a cursor over the result set.
1136     * The cursor will read an initial set of rows and the return to the caller.
1137     * It will continue to read in batches and send data changed notifications
1138     * when the later batches are ready.
1139     * @param sql the SQL query. The SQL string must not be ; terminated
1140     * @param selectionArgs You may include ?s in where clause in the query,
1141     *     which will be replaced by the values from selectionArgs. The
1142     *     values will be bound as Strings.
1143     * @param initialRead set the initial count of items to read from the cursor
1144     * @param maxRead set the count of items to read on each iteration after the first
1145     * @return A {@link Cursor} object, which is positioned before the first entry
1146     * @hide pending API council approval
1147     */
1148    public Cursor rawQuery(String sql, String[] selectionArgs,
1149            int initialRead, int maxRead) {
1150        SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
1151                null, sql, selectionArgs, null);
1152        c.setLoadStyle(initialRead, maxRead);
1153        return c;
1154    }
1155
1156    /**
1157     * Convenience method for inserting a row into the database.
1158     *
1159     * @param table the table to insert the row into
1160     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1161     *            so if initialValues is empty this column will explicitly be
1162     *            assigned a NULL value
1163     * @param values this map contains the initial column values for the
1164     *            row. The keys should be the column names and the values the
1165     *            column values
1166     * @return the row ID of the newly inserted row, or -1 if an error occurred
1167     */
1168    public long insert(String table, String nullColumnHack, ContentValues values) {
1169        try {
1170            return insertWithOnConflict(table, nullColumnHack, values, null);
1171        } catch (SQLException e) {
1172            Log.e(TAG, "Error inserting " + values, e);
1173            return -1;
1174        }
1175    }
1176
1177    /**
1178     * Convenience method for inserting a row into the database.
1179     *
1180     * @param table the table to insert the row into
1181     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1182     *            so if initialValues is empty this column will explicitly be
1183     *            assigned a NULL value
1184     * @param values this map contains the initial column values for the
1185     *            row. The keys should be the column names and the values the
1186     *            column values
1187     * @throws SQLException
1188     * @return the row ID of the newly inserted row, or -1 if an error occurred
1189     */
1190    public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1191            throws SQLException {
1192        return insertWithOnConflict(table, nullColumnHack, values, null);
1193    }
1194
1195    /**
1196     * Convenience method for replacing a row in the database.
1197     *
1198     * @param table the table in which to replace the row
1199     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1200     *            so if initialValues is empty this row will explicitly be
1201     *            assigned a NULL value
1202     * @param initialValues this map contains the initial column values for
1203     *   the row. The key
1204     * @return the row ID of the newly inserted row, or -1 if an error occurred
1205     */
1206    public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1207        try {
1208            return insertWithOnConflict(table, nullColumnHack, initialValues,
1209                    ConflictAlgorithm.REPLACE);
1210        } catch (SQLException e) {
1211            Log.e(TAG, "Error inserting " + initialValues, e);
1212            return -1;
1213        }
1214    }
1215
1216    /**
1217     * Convenience method for replacing a row in the database.
1218     *
1219     * @param table the table in which to replace the row
1220     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1221     *            so if initialValues is empty this row will explicitly be
1222     *            assigned a NULL value
1223     * @param initialValues this map contains the initial column values for
1224     *   the row. The key
1225     * @throws SQLException
1226     * @return the row ID of the newly inserted row, or -1 if an error occurred
1227     */
1228    public long replaceOrThrow(String table, String nullColumnHack,
1229            ContentValues initialValues) throws SQLException {
1230        return insertWithOnConflict(table, nullColumnHack, initialValues,
1231                ConflictAlgorithm.REPLACE);
1232    }
1233
1234    /**
1235     * General method for inserting a row into the database.
1236     *
1237     * @param table the table to insert the row into
1238     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1239     *            so if initialValues is empty this column will explicitly be
1240     *            assigned a NULL value
1241     * @param initialValues this map contains the initial column values for the
1242     *            row. The keys should be the column names and the values the
1243     *            column values
1244     * @param algorithm  {@link ConflictAlgorithm} for insert conflict resolver
1245     * @return the row ID of the newly inserted row, or -1 if an error occurred
1246     * @hide
1247     */
1248    public long insertWithOnConflict(String table, String nullColumnHack,
1249            ContentValues initialValues, ConflictAlgorithm algorithm) {
1250        if (!isOpen()) {
1251            throw new IllegalStateException("database not open");
1252        }
1253
1254        // Measurements show most sql lengths <= 152
1255        StringBuilder sql = new StringBuilder(152);
1256        sql.append("INSERT");
1257        if (algorithm != null) {
1258            sql.append(" OR ");
1259            sql.append(algorithm.value());
1260        }
1261        sql.append(" INTO ");
1262        sql.append(table);
1263        // Measurements show most values lengths < 40
1264        StringBuilder values = new StringBuilder(40);
1265
1266        Set<Map.Entry<String, Object>> entrySet = null;
1267        if (initialValues != null && initialValues.size() > 0) {
1268            entrySet = initialValues.valueSet();
1269            Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1270            sql.append('(');
1271
1272            boolean needSeparator = false;
1273            while (entriesIter.hasNext()) {
1274                if (needSeparator) {
1275                    sql.append(", ");
1276                    values.append(", ");
1277                }
1278                needSeparator = true;
1279                Map.Entry<String, Object> entry = entriesIter.next();
1280                sql.append(entry.getKey());
1281                values.append('?');
1282            }
1283
1284            sql.append(')');
1285        } else {
1286            sql.append("(" + nullColumnHack + ") ");
1287            values.append("NULL");
1288        }
1289
1290        sql.append(" VALUES(");
1291        sql.append(values);
1292        sql.append(");");
1293
1294        lock();
1295        SQLiteStatement statement = null;
1296        try {
1297            statement = compileStatement(sql.toString());
1298
1299            // Bind the values
1300            if (entrySet != null) {
1301                int size = entrySet.size();
1302                Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1303                for (int i = 0; i < size; i++) {
1304                    Map.Entry<String, Object> entry = entriesIter.next();
1305                    DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue());
1306                }
1307            }
1308
1309            // Run the program and then cleanup
1310            statement.execute();
1311
1312            long insertedRowId = lastInsertRow();
1313            if (insertedRowId == -1) {
1314                Log.e(TAG, "Error inserting " + initialValues + " using " + sql);
1315            } else {
1316                if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1317                    Log.v(TAG, "Inserting row " + insertedRowId + " from "
1318                            + initialValues + " using " + sql);
1319                }
1320            }
1321            return insertedRowId;
1322        } catch (SQLiteDatabaseCorruptException e) {
1323            onCorruption();
1324            throw e;
1325        } finally {
1326            if (statement != null) {
1327                statement.close();
1328            }
1329            unlock();
1330        }
1331    }
1332
1333    /**
1334     * Convenience method for deleting rows in the database.
1335     *
1336     * @param table the table to delete from
1337     * @param whereClause the optional WHERE clause to apply when deleting.
1338     *            Passing null will delete all rows.
1339     * @return the number of rows affected if a whereClause is passed in, 0
1340     *         otherwise. To remove all rows and get a count pass "1" as the
1341     *         whereClause.
1342     */
1343    public int delete(String table, String whereClause, String[] whereArgs) {
1344        if (!isOpen()) {
1345            throw new IllegalStateException("database not open");
1346        }
1347        lock();
1348        SQLiteStatement statement = null;
1349        try {
1350            statement = compileStatement("DELETE FROM " + table
1351                    + (!TextUtils.isEmpty(whereClause)
1352                    ? " WHERE " + whereClause : ""));
1353            if (whereArgs != null) {
1354                int numArgs = whereArgs.length;
1355                for (int i = 0; i < numArgs; i++) {
1356                    DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]);
1357                }
1358            }
1359            statement.execute();
1360            statement.close();
1361            return lastChangeCount();
1362        } catch (SQLiteDatabaseCorruptException e) {
1363            onCorruption();
1364            throw e;
1365        } finally {
1366            if (statement != null) {
1367                statement.close();
1368            }
1369            unlock();
1370        }
1371    }
1372
1373    /**
1374     * Convenience method for updating rows in the database.
1375     *
1376     * @param table the table to update in
1377     * @param values a map from column names to new column values. null is a
1378     *            valid value that will be translated to NULL.
1379     * @param whereClause the optional WHERE clause to apply when updating.
1380     *            Passing null will update all rows.
1381     * @return the number of rows affected
1382     */
1383    public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
1384        return updateWithOnConflict(table, values, whereClause, whereArgs, null);
1385    }
1386
1387    /**
1388     * Convenience method for updating rows in the database.
1389     *
1390     * @param table the table to update in
1391     * @param values a map from column names to new column values. null is a
1392     *            valid value that will be translated to NULL.
1393     * @param whereClause the optional WHERE clause to apply when updating.
1394     *            Passing null will update all rows.
1395     * @param algorithm  {@link ConflictAlgorithm} for update conflict resolver
1396     * @return the number of rows affected
1397     * @hide
1398     */
1399    public int updateWithOnConflict(String table, ContentValues values,
1400            String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) {
1401        if (!isOpen()) {
1402            throw new IllegalStateException("database not open");
1403        }
1404
1405        if (values == null || values.size() == 0) {
1406            throw new IllegalArgumentException("Empty values");
1407        }
1408
1409        StringBuilder sql = new StringBuilder(120);
1410        sql.append("UPDATE ");
1411        if (algorithm != null) {
1412            sql.append(" OR ");
1413            sql.append(algorithm.value());
1414        }
1415
1416        sql.append(table);
1417        sql.append(" SET ");
1418
1419        Set<Map.Entry<String, Object>> entrySet = values.valueSet();
1420        Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1421
1422        while (entriesIter.hasNext()) {
1423            Map.Entry<String, Object> entry = entriesIter.next();
1424            sql.append(entry.getKey());
1425            sql.append("=?");
1426            if (entriesIter.hasNext()) {
1427                sql.append(", ");
1428            }
1429        }
1430
1431        if (!TextUtils.isEmpty(whereClause)) {
1432            sql.append(" WHERE ");
1433            sql.append(whereClause);
1434        }
1435
1436        lock();
1437        SQLiteStatement statement = null;
1438        try {
1439            statement = compileStatement(sql.toString());
1440
1441            // Bind the values
1442            int size = entrySet.size();
1443            entriesIter = entrySet.iterator();
1444            int bindArg = 1;
1445            for (int i = 0; i < size; i++) {
1446                Map.Entry<String, Object> entry = entriesIter.next();
1447                DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue());
1448                bindArg++;
1449            }
1450
1451            if (whereArgs != null) {
1452                size = whereArgs.length;
1453                for (int i = 0; i < size; i++) {
1454                    statement.bindString(bindArg, whereArgs[i]);
1455                    bindArg++;
1456                }
1457            }
1458
1459            // Run the program and then cleanup
1460            statement.execute();
1461            statement.close();
1462            int numChangedRows = lastChangeCount();
1463            if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1464                Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql);
1465            }
1466            return numChangedRows;
1467        } catch (SQLiteDatabaseCorruptException e) {
1468            onCorruption();
1469            throw e;
1470        } catch (SQLException e) {
1471            Log.e(TAG, "Error updating " + values + " using " + sql);
1472            throw e;
1473        } finally {
1474            if (statement != null) {
1475                statement.close();
1476            }
1477            unlock();
1478        }
1479    }
1480
1481    /**
1482     * Execute a single SQL statement that is not a query. For example, CREATE
1483     * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1484     * supported. it takes a write lock
1485     *
1486     * @throws SQLException If the SQL string is invalid for some reason
1487     */
1488    public void execSQL(String sql) throws SQLException {
1489        boolean logStats = mLogStats;
1490        long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
1491        lock();
1492        try {
1493            native_execSQL(sql);
1494        } catch (SQLiteDatabaseCorruptException e) {
1495            onCorruption();
1496            throw e;
1497        } finally {
1498            unlock();
1499        }
1500        if (logStats) {
1501            logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
1502        }
1503    }
1504
1505    /**
1506     * Execute a single SQL statement that is not a query. For example, CREATE
1507     * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1508     * supported. it takes a write lock,
1509     *
1510     * @param sql
1511     * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
1512     * @throws SQLException If the SQL string is invalid for some reason
1513     */
1514    public void execSQL(String sql, Object[] bindArgs) throws SQLException {
1515        if (bindArgs == null) {
1516            throw new IllegalArgumentException("Empty bindArgs");
1517        }
1518
1519        boolean logStats = mLogStats;
1520        long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
1521        lock();
1522        SQLiteStatement statement = null;
1523        try {
1524            statement = compileStatement(sql);
1525            if (bindArgs != null) {
1526                int numArgs = bindArgs.length;
1527                for (int i = 0; i < numArgs; i++) {
1528                    DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]);
1529                }
1530            }
1531            statement.execute();
1532        } catch (SQLiteDatabaseCorruptException e) {
1533            onCorruption();
1534            throw e;
1535        } finally {
1536            if (statement != null) {
1537                statement.close();
1538            }
1539            unlock();
1540        }
1541        if (logStats) {
1542            logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
1543        }
1544    }
1545
1546    @Override
1547    protected void finalize() {
1548        if (isOpen()) {
1549            if (mPrograms.isEmpty()) {
1550                Log.e(TAG, "Leak found", mLeakedException);
1551            } else {
1552                IllegalStateException leakProgram = new IllegalStateException(
1553                        "mPrograms size " + mPrograms.size(), mLeakedException);
1554                Log.e(TAG, "Leak found", leakProgram);
1555            }
1556            closeClosable();
1557            onAllReferencesReleased();
1558        }
1559    }
1560
1561    /**
1562     * Private constructor. See {@link #create} and {@link #openDatabase}.
1563     *
1564     * @param path The full path to the database
1565     * @param factory The factory to use when creating cursors, may be NULL.
1566     * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}.  If the database file already
1567     *              exists, mFlags will be updated appropriately.
1568     */
1569    private SQLiteDatabase(String path, CursorFactory factory, int flags) {
1570        if (path == null) {
1571            throw new IllegalArgumentException("path should not be null");
1572        }
1573        mFlags = flags;
1574        mPath = path;
1575        mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
1576
1577        mLeakedException = new IllegalStateException(path +
1578            " SQLiteDatabase created and never closed");
1579        mFactory = factory;
1580        dbopen(mPath, mFlags);
1581        mPrograms = new WeakHashMap<SQLiteClosable,Object>();
1582        try {
1583            setLocale(Locale.getDefault());
1584        } catch (RuntimeException e) {
1585            Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
1586            dbclose();
1587            throw e;
1588        }
1589    }
1590
1591    /**
1592     * return whether the DB is opened as read only.
1593     * @return true if DB is opened as read only
1594     */
1595    public boolean isReadOnly() {
1596        return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
1597    }
1598
1599    /**
1600     * @return true if the DB is currently open (has not been closed)
1601     */
1602    public boolean isOpen() {
1603        return mNativeHandle != 0;
1604    }
1605
1606    public boolean needUpgrade(int newVersion) {
1607        return newVersion > getVersion();
1608    }
1609
1610    /**
1611     * Getter for the path to the database file.
1612     *
1613     * @return the path to our database file.
1614     */
1615    public final String getPath() {
1616        return mPath;
1617    }
1618
1619    /* package */ void logTimeStat(boolean read, long begin, long end) {
1620        EventLog.writeEvent(DB_OPERATION_EVENT, mPath, read ? 0 : 1, end - begin);
1621    }
1622
1623    /**
1624     * Sets the locale for this database.  Does nothing if this database has
1625     * the NO_LOCALIZED_COLLATORS flag set or was opened read only.
1626     * @throws SQLException if the locale could not be set.  The most common reason
1627     * for this is that there is no collator available for the locale you requested.
1628     * In this case the database remains unchanged.
1629     */
1630    public void setLocale(Locale locale) {
1631        lock();
1632        try {
1633            native_setLocale(locale.toString(), mFlags);
1634        } finally {
1635            unlock();
1636        }
1637    }
1638
1639    /**
1640     * Native call to open the database.
1641     *
1642     * @param path The full path to the database
1643     */
1644    private native void dbopen(String path, int flags);
1645
1646    /**
1647     * Native call to execute a raw SQL statement. {@link #lock} must be held
1648     * when calling this method.
1649     *
1650     * @param sql The raw SQL string
1651     * @throws SQLException
1652     */
1653    /* package */ native void native_execSQL(String sql) throws SQLException;
1654
1655    /**
1656     * Native call to set the locale.  {@link #lock} must be held when calling
1657     * this method.
1658     * @throws SQLException
1659     */
1660    /* package */ native void native_setLocale(String loc, int flags);
1661
1662    /**
1663     * Returns the row ID of the last row inserted into the database.
1664     *
1665     * @return the row ID of the last row inserted into the database.
1666     */
1667    /* package */ native long lastInsertRow();
1668
1669    /**
1670     * Returns the number of changes made in the last statement executed.
1671     *
1672     * @return the number of changes made in the last statement executed.
1673     */
1674    /* package */ native int lastChangeCount();
1675}
1676