SQLiteDatabase.java revision f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75
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     *
1147     * This work is incomplete and not fully tested or reviewed, so currently
1148     * hidden.
1149     * @hide
1150     */
1151    public Cursor rawQuery(String sql, String[] selectionArgs,
1152            int initialRead, int maxRead) {
1153        SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
1154                null, sql, selectionArgs, null);
1155        c.setLoadStyle(initialRead, maxRead);
1156        return c;
1157    }
1158
1159    /**
1160     * Convenience method for inserting a row into the database.
1161     *
1162     * @param table the table to insert the row into
1163     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1164     *            so if initialValues is empty this column will explicitly be
1165     *            assigned a NULL value
1166     * @param values this map contains the initial column values for the
1167     *            row. The keys should be the column names and the values the
1168     *            column values
1169     * @return the row ID of the newly inserted row, or -1 if an error occurred
1170     */
1171    public long insert(String table, String nullColumnHack, ContentValues values) {
1172        try {
1173            return insertWithOnConflict(table, nullColumnHack, values, null);
1174        } catch (SQLException e) {
1175            Log.e(TAG, "Error inserting " + values, e);
1176            return -1;
1177        }
1178    }
1179
1180    /**
1181     * Convenience method for inserting a row into the database.
1182     *
1183     * @param table the table to insert the row into
1184     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1185     *            so if initialValues is empty this column will explicitly be
1186     *            assigned a NULL value
1187     * @param values this map contains the initial column values for the
1188     *            row. The keys should be the column names and the values the
1189     *            column values
1190     * @throws SQLException
1191     * @return the row ID of the newly inserted row, or -1 if an error occurred
1192     */
1193    public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1194            throws SQLException {
1195        return insertWithOnConflict(table, nullColumnHack, values, null);
1196    }
1197
1198    /**
1199     * Convenience method for replacing a row in the database.
1200     *
1201     * @param table the table in which to replace the row
1202     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1203     *            so if initialValues is empty this row will explicitly be
1204     *            assigned a NULL value
1205     * @param initialValues this map contains the initial column values for
1206     *   the row. The key
1207     * @return the row ID of the newly inserted row, or -1 if an error occurred
1208     */
1209    public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1210        try {
1211            return insertWithOnConflict(table, nullColumnHack, initialValues,
1212                    ConflictAlgorithm.REPLACE);
1213        } catch (SQLException e) {
1214            Log.e(TAG, "Error inserting " + initialValues, e);
1215            return -1;
1216        }
1217    }
1218
1219    /**
1220     * Convenience method for replacing a row in the database.
1221     *
1222     * @param table the table in which to replace the row
1223     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1224     *            so if initialValues is empty this row will explicitly be
1225     *            assigned a NULL value
1226     * @param initialValues this map contains the initial column values for
1227     *   the row. The key
1228     * @throws SQLException
1229     * @return the row ID of the newly inserted row, or -1 if an error occurred
1230     */
1231    public long replaceOrThrow(String table, String nullColumnHack,
1232            ContentValues initialValues) throws SQLException {
1233        return insertWithOnConflict(table, nullColumnHack, initialValues,
1234                ConflictAlgorithm.REPLACE);
1235    }
1236
1237    /**
1238     * General method for inserting a row into the database.
1239     *
1240     * @param table the table to insert the row into
1241     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1242     *            so if initialValues is empty this column will explicitly be
1243     *            assigned a NULL value
1244     * @param initialValues this map contains the initial column values for the
1245     *            row. The keys should be the column names and the values the
1246     *            column values
1247     * @param algorithm  {@link ConflictAlgorithm} for insert conflict resolver
1248     * @return the row ID of the newly inserted row, or -1 if an error occurred
1249     * @hide
1250     */
1251    public long insertWithOnConflict(String table, String nullColumnHack,
1252            ContentValues initialValues, ConflictAlgorithm algorithm) {
1253        if (!isOpen()) {
1254            throw new IllegalStateException("database not open");
1255        }
1256
1257        // Measurements show most sql lengths <= 152
1258        StringBuilder sql = new StringBuilder(152);
1259        sql.append("INSERT");
1260        if (algorithm != null) {
1261            sql.append(" OR ");
1262            sql.append(algorithm.value());
1263        }
1264        sql.append(" INTO ");
1265        sql.append(table);
1266        // Measurements show most values lengths < 40
1267        StringBuilder values = new StringBuilder(40);
1268
1269        Set<Map.Entry<String, Object>> entrySet = null;
1270        if (initialValues != null && initialValues.size() > 0) {
1271            entrySet = initialValues.valueSet();
1272            Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1273            sql.append('(');
1274
1275            boolean needSeparator = false;
1276            while (entriesIter.hasNext()) {
1277                if (needSeparator) {
1278                    sql.append(", ");
1279                    values.append(", ");
1280                }
1281                needSeparator = true;
1282                Map.Entry<String, Object> entry = entriesIter.next();
1283                sql.append(entry.getKey());
1284                values.append('?');
1285            }
1286
1287            sql.append(')');
1288        } else {
1289            sql.append("(" + nullColumnHack + ") ");
1290            values.append("NULL");
1291        }
1292
1293        sql.append(" VALUES(");
1294        sql.append(values);
1295        sql.append(");");
1296
1297        lock();
1298        SQLiteStatement statement = null;
1299        try {
1300            statement = compileStatement(sql.toString());
1301
1302            // Bind the values
1303            if (entrySet != null) {
1304                int size = entrySet.size();
1305                Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1306                for (int i = 0; i < size; i++) {
1307                    Map.Entry<String, Object> entry = entriesIter.next();
1308                    DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue());
1309                }
1310            }
1311
1312            // Run the program and then cleanup
1313            statement.execute();
1314
1315            long insertedRowId = lastInsertRow();
1316            if (insertedRowId == -1) {
1317                Log.e(TAG, "Error inserting " + initialValues + " using " + sql);
1318            } else {
1319                if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1320                    Log.v(TAG, "Inserting row " + insertedRowId + " from "
1321                            + initialValues + " using " + sql);
1322                }
1323            }
1324            return insertedRowId;
1325        } catch (SQLiteDatabaseCorruptException e) {
1326            onCorruption();
1327            throw e;
1328        } finally {
1329            if (statement != null) {
1330                statement.close();
1331            }
1332            unlock();
1333        }
1334    }
1335
1336    /**
1337     * Convenience method for deleting rows in the database.
1338     *
1339     * @param table the table to delete from
1340     * @param whereClause the optional WHERE clause to apply when deleting.
1341     *            Passing null will delete all rows.
1342     * @return the number of rows affected if a whereClause is passed in, 0
1343     *         otherwise. To remove all rows and get a count pass "1" as the
1344     *         whereClause.
1345     */
1346    public int delete(String table, String whereClause, String[] whereArgs) {
1347        if (!isOpen()) {
1348            throw new IllegalStateException("database not open");
1349        }
1350        lock();
1351        SQLiteStatement statement = null;
1352        try {
1353            statement = compileStatement("DELETE FROM " + table
1354                    + (!TextUtils.isEmpty(whereClause)
1355                    ? " WHERE " + whereClause : ""));
1356            if (whereArgs != null) {
1357                int numArgs = whereArgs.length;
1358                for (int i = 0; i < numArgs; i++) {
1359                    DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]);
1360                }
1361            }
1362            statement.execute();
1363            statement.close();
1364            return lastChangeCount();
1365        } catch (SQLiteDatabaseCorruptException e) {
1366            onCorruption();
1367            throw e;
1368        } finally {
1369            if (statement != null) {
1370                statement.close();
1371            }
1372            unlock();
1373        }
1374    }
1375
1376    /**
1377     * Convenience method for updating rows in the database.
1378     *
1379     * @param table the table to update in
1380     * @param values a map from column names to new column values. null is a
1381     *            valid value that will be translated to NULL.
1382     * @param whereClause the optional WHERE clause to apply when updating.
1383     *            Passing null will update all rows.
1384     * @return the number of rows affected
1385     */
1386    public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
1387        return updateWithOnConflict(table, values, whereClause, whereArgs, null);
1388    }
1389
1390    /**
1391     * Convenience method for updating rows in the database.
1392     *
1393     * @param table the table to update in
1394     * @param values a map from column names to new column values. null is a
1395     *            valid value that will be translated to NULL.
1396     * @param whereClause the optional WHERE clause to apply when updating.
1397     *            Passing null will update all rows.
1398     * @param algorithm  {@link ConflictAlgorithm} for update conflict resolver
1399     * @return the number of rows affected
1400     * @hide
1401     */
1402    public int updateWithOnConflict(String table, ContentValues values,
1403            String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) {
1404        if (!isOpen()) {
1405            throw new IllegalStateException("database not open");
1406        }
1407
1408        if (values == null || values.size() == 0) {
1409            throw new IllegalArgumentException("Empty values");
1410        }
1411
1412        StringBuilder sql = new StringBuilder(120);
1413        sql.append("UPDATE ");
1414        if (algorithm != null) {
1415            sql.append(" OR ");
1416            sql.append(algorithm.value());
1417        }
1418
1419        sql.append(table);
1420        sql.append(" SET ");
1421
1422        Set<Map.Entry<String, Object>> entrySet = values.valueSet();
1423        Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1424
1425        while (entriesIter.hasNext()) {
1426            Map.Entry<String, Object> entry = entriesIter.next();
1427            sql.append(entry.getKey());
1428            sql.append("=?");
1429            if (entriesIter.hasNext()) {
1430                sql.append(", ");
1431            }
1432        }
1433
1434        if (!TextUtils.isEmpty(whereClause)) {
1435            sql.append(" WHERE ");
1436            sql.append(whereClause);
1437        }
1438
1439        lock();
1440        SQLiteStatement statement = null;
1441        try {
1442            statement = compileStatement(sql.toString());
1443
1444            // Bind the values
1445            int size = entrySet.size();
1446            entriesIter = entrySet.iterator();
1447            int bindArg = 1;
1448            for (int i = 0; i < size; i++) {
1449                Map.Entry<String, Object> entry = entriesIter.next();
1450                DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue());
1451                bindArg++;
1452            }
1453
1454            if (whereArgs != null) {
1455                size = whereArgs.length;
1456                for (int i = 0; i < size; i++) {
1457                    statement.bindString(bindArg, whereArgs[i]);
1458                    bindArg++;
1459                }
1460            }
1461
1462            // Run the program and then cleanup
1463            statement.execute();
1464            statement.close();
1465            int numChangedRows = lastChangeCount();
1466            if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1467                Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql);
1468            }
1469            return numChangedRows;
1470        } catch (SQLiteDatabaseCorruptException e) {
1471            onCorruption();
1472            throw e;
1473        } catch (SQLException e) {
1474            Log.e(TAG, "Error updating " + values + " using " + sql);
1475            throw e;
1476        } finally {
1477            if (statement != null) {
1478                statement.close();
1479            }
1480            unlock();
1481        }
1482    }
1483
1484    /**
1485     * Execute a single SQL statement that is not a query. For example, CREATE
1486     * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1487     * supported. it takes a write lock
1488     *
1489     * @throws SQLException If the SQL string is invalid for some reason
1490     */
1491    public void execSQL(String sql) throws SQLException {
1492        boolean logStats = mLogStats;
1493        long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
1494        lock();
1495        try {
1496            native_execSQL(sql);
1497        } catch (SQLiteDatabaseCorruptException e) {
1498            onCorruption();
1499            throw e;
1500        } finally {
1501            unlock();
1502        }
1503        if (logStats) {
1504            logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
1505        }
1506    }
1507
1508    /**
1509     * Execute a single SQL statement that is not a query. For example, CREATE
1510     * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1511     * supported. it takes a write lock,
1512     *
1513     * @param sql
1514     * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
1515     * @throws SQLException If the SQL string is invalid for some reason
1516     */
1517    public void execSQL(String sql, Object[] bindArgs) throws SQLException {
1518        if (bindArgs == null) {
1519            throw new IllegalArgumentException("Empty bindArgs");
1520        }
1521
1522        boolean logStats = mLogStats;
1523        long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
1524        lock();
1525        SQLiteStatement statement = null;
1526        try {
1527            statement = compileStatement(sql);
1528            if (bindArgs != null) {
1529                int numArgs = bindArgs.length;
1530                for (int i = 0; i < numArgs; i++) {
1531                    DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]);
1532                }
1533            }
1534            statement.execute();
1535        } catch (SQLiteDatabaseCorruptException e) {
1536            onCorruption();
1537            throw e;
1538        } finally {
1539            if (statement != null) {
1540                statement.close();
1541            }
1542            unlock();
1543        }
1544        if (logStats) {
1545            logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
1546        }
1547    }
1548
1549    @Override
1550    protected void finalize() {
1551        if (isOpen()) {
1552            if (mPrograms.isEmpty()) {
1553                Log.e(TAG, "Leak found", mLeakedException);
1554            } else {
1555                IllegalStateException leakProgram = new IllegalStateException(
1556                        "mPrograms size " + mPrograms.size(), mLeakedException);
1557                Log.e(TAG, "Leak found", leakProgram);
1558            }
1559            closeClosable();
1560            onAllReferencesReleased();
1561        }
1562    }
1563
1564    /**
1565     * Private constructor. See {@link #create} and {@link #openDatabase}.
1566     *
1567     * @param path The full path to the database
1568     * @param factory The factory to use when creating cursors, may be NULL.
1569     * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}.  If the database file already
1570     *              exists, mFlags will be updated appropriately.
1571     */
1572    private SQLiteDatabase(String path, CursorFactory factory, int flags) {
1573        if (path == null) {
1574            throw new IllegalArgumentException("path should not be null");
1575        }
1576        mFlags = flags;
1577        mPath = path;
1578        mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
1579
1580        mLeakedException = new IllegalStateException(path +
1581            " SQLiteDatabase created and never closed");
1582        mFactory = factory;
1583        dbopen(mPath, mFlags);
1584        mPrograms = new WeakHashMap<SQLiteClosable,Object>();
1585        try {
1586            setLocale(Locale.getDefault());
1587        } catch (RuntimeException e) {
1588            Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
1589            dbclose();
1590            throw e;
1591        }
1592    }
1593
1594    /**
1595     * return whether the DB is opened as read only.
1596     * @return true if DB is opened as read only
1597     */
1598    public boolean isReadOnly() {
1599        return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
1600    }
1601
1602    /**
1603     * @return true if the DB is currently open (has not been closed)
1604     */
1605    public boolean isOpen() {
1606        return mNativeHandle != 0;
1607    }
1608
1609    public boolean needUpgrade(int newVersion) {
1610        return newVersion > getVersion();
1611    }
1612
1613    /**
1614     * Getter for the path to the database file.
1615     *
1616     * @return the path to our database file.
1617     */
1618    public final String getPath() {
1619        return mPath;
1620    }
1621
1622    /* package */ void logTimeStat(boolean read, long begin, long end) {
1623        EventLog.writeEvent(DB_OPERATION_EVENT, mPath, read ? 0 : 1, end - begin);
1624    }
1625
1626    /**
1627     * Sets the locale for this database.  Does nothing if this database has
1628     * the NO_LOCALIZED_COLLATORS flag set or was opened read only.
1629     * @throws SQLException if the locale could not be set.  The most common reason
1630     * for this is that there is no collator available for the locale you requested.
1631     * In this case the database remains unchanged.
1632     */
1633    public void setLocale(Locale locale) {
1634        lock();
1635        try {
1636            native_setLocale(locale.toString(), mFlags);
1637        } finally {
1638            unlock();
1639        }
1640    }
1641
1642    /**
1643     * Native call to open the database.
1644     *
1645     * @param path The full path to the database
1646     */
1647    private native void dbopen(String path, int flags);
1648
1649    /**
1650     * Native call to execute a raw SQL statement. {@link #lock} must be held
1651     * when calling this method.
1652     *
1653     * @param sql The raw SQL string
1654     * @throws SQLException
1655     */
1656    /* package */ native void native_execSQL(String sql) throws SQLException;
1657
1658    /**
1659     * Native call to set the locale.  {@link #lock} must be held when calling
1660     * this method.
1661     * @throws SQLException
1662     */
1663    /* package */ native void native_setLocale(String loc, int flags);
1664
1665    /**
1666     * Returns the row ID of the last row inserted into the database.
1667     *
1668     * @return the row ID of the last row inserted into the database.
1669     */
1670    /* package */ native long lastInsertRow();
1671
1672    /**
1673     * Returns the number of changes made in the last statement executed.
1674     *
1675     * @return the number of changes made in the last statement executed.
1676     */
1677    /* package */ native int lastChangeCount();
1678}
1679