19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.database.sqlite;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
2074f170f9468d3cf6d7d0ef453320141a3e63571bVasu Noriimport android.database.DatabaseErrorHandler;
2174f170f9468d3cf6d7d0ef453320141a3e63571bVasu Noriimport android.database.DefaultDatabaseErrorHandler;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase.CursorFactory;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A helper class to manage database creation and version management.
276fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor *
286fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor * <p>You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * optionally {@link #onOpen}, and this class takes care of opening the database
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if it exists, creating it if it does not, and upgrading it as necessary.
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Transactions are used to make sure the database is always in a sensible state.
326fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor *
336fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor * <p>This class makes it easy for {@link android.content.ContentProvider}
346fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor * implementations to defer opening and upgrading the database until first use,
356fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor * to avoid blocking application startup with long-running database upgrades.
366fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor *
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>For an example, see the NotePadProvider class in the NotePad sample application,
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in the <em>samples/</em> directory of the SDK.</p>
3944dc76a8a702d6a919fcea1c2d19ba3792687c85Brad Fitzpatrick *
4044dc76a8a702d6a919fcea1c2d19ba3792687c85Brad Fitzpatrick * <p class="note"><strong>Note:</strong> this class assumes
41a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold * monotonically increasing version numbers for upgrades.</p>
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class SQLiteOpenHelper {
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
46559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // When true, getReadableDatabase returns a read-only database if it is just being opened.
47559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // The database handle is reopened in read/write mode when getWritableDatabase is called.
48559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // We leave this behavior disabled in production because it is inefficient and breaks
49559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // many applications.  For debugging purposes it can be useful to turn on strict
50559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // read-only semantics to catch applications that call getReadableDatabase when they really
51559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // wanted getWritableDatabase.
52559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private static final boolean DEBUG_STRICT_READONLY = false;
53559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final String mName;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final CursorFactory mFactory;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mNewVersion;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
59559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private SQLiteDatabase mDatabase;
60559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private boolean mIsInitializing;
6147847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown    private boolean mEnableWriteAheadLogging;
6274f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori    private final DatabaseErrorHandler mErrorHandler;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a helper object to create, open, and/or manage a database.
666fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * This method always returns very quickly.  The database is not actually
676fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * created or opened until one of {@link #getWritableDatabase} or
686fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * {@link #getReadableDatabase} is called.
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context to use to open or create the database
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param name of the database file, or null for an in-memory database
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param factory to use for creating cursor objects, or null for the default
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param version number of the database (starting at 1); if the database is older,
74a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     *     {@link #onUpgrade} will be used to upgrade the database; if the database is
75a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     *     newer, {@link #onDowngrade} will be used to downgrade the database
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
7847847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown        this(context, name, factory, version, null);
7974f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori    }
8074f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori
8174f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori    /**
8274f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * Create a helper object to create, open, and/or manage a database.
8374f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * The database is not actually created or opened until one of
8474f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.
8574f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     *
8674f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
8774f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * used to handle corruption when sqlite reports database corruption.</p>
8874f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     *
8974f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * @param context to use to open or create the database
9074f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * @param name of the database file, or null for an in-memory database
9174f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * @param factory to use for creating cursor objects, or null for the default
9274f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * @param version number of the database (starting at 1); if the database is older,
931c423b81deda88cffdf27c4b0aafc0f4daf3ac8fPin Ting     *     {@link #onUpgrade} will be used to upgrade the database; if the database is
941c423b81deda88cffdf27c4b0aafc0f4daf3ac8fPin Ting     *     newer, {@link #onDowngrade} will be used to downgrade the database
9574f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
9647847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     * corruption, or null to use the default error handler.
9774f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori     */
9874f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
9974f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori            DatabaseErrorHandler errorHandler) {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mName = name;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFactory = factory;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNewVersion = version;
10674f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori        mErrorHandler = errorHandler;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1101c423b81deda88cffdf27c4b0aafc0f4daf3ac8fPin Ting     * Return the name of the SQLite database being opened, as given to
111661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn     * the constructor.
112661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn     */
113661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    public String getDatabaseName() {
114661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn        return mName;
115661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    }
116661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn
117661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    /**
11847847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     * Enables or disables the use of write-ahead logging for the database.
11947847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     *
12047847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     * Write-ahead logging cannot be used with read-only databases so the value of
12147847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     * this flag is ignored if the database is opened read-only.
12247847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     *
12347847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     * @param enabled True if write-ahead logging should be enabled, false if it
12447847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     * should be disabled.
12547847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     *
12647847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     * @see SQLiteDatabase#enableWriteAheadLogging()
12747847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown     */
12847847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown    public void setWriteAheadLoggingEnabled(boolean enabled) {
12947847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown        synchronized (this) {
13047847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown            if (mEnableWriteAheadLogging != enabled) {
13147847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
13247847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                    if (enabled) {
13347847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                        mDatabase.enableWriteAheadLogging();
13447847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                    } else {
13547847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                        mDatabase.disableWriteAheadLogging();
13647847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                    }
13747847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                }
13847847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                mEnableWriteAheadLogging = enabled;
13947847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown            }
14047847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown        }
14147847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown    }
14247847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown
14347847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown    /**
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create and/or open a database that will be used for reading and writing.
1456fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * The first time this is called, the database will be opened and
1466fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
1476fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * called.
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1496fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * <p>Once opened successfully, the database is cached, so you can
1506fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * call this method every time you need to write to the database.
1516fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * (Make sure to call {@link #close} when you no longer need the database.)
1526fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * Errors such as bad permissions or a full disk may cause this method
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to fail, but future attempts may succeed if the problem is fixed.</p>
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1556fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * <p class="caution">Database upgrade may take a long time, you
1566fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * should not call this method from the application main thread, including
1576fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
1586fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     *
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws SQLiteException if the database cannot be opened for writing
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a read/write database object valid until {@link #close} is called
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
162559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    public SQLiteDatabase getWritableDatabase() {
163559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        synchronized (this) {
164559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            return getDatabaseLocked(true);
165559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        }
166559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    }
167559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
168559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    /**
169559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * Create and/or open a database.  This will be the same object returned by
170559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * {@link #getWritableDatabase} unless some problem, such as a full disk,
171559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * requires the database to be opened read-only.  In that case, a read-only
172559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * database object will be returned.  If the problem is fixed, a future call
173559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * to {@link #getWritableDatabase} may succeed, in which case the read-only
174559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * database object will be closed and the read/write object will be returned
175559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * in the future.
176559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     *
177559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * <p class="caution">Like {@link #getWritableDatabase}, this method may
178559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * take a long time to return, so you should not call it from the
179559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * application main thread, including from
180559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
181559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     *
182559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * @throws SQLiteException if the database cannot be opened
183559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     * @return a database object valid until {@link #getWritableDatabase}
184559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     *     or {@link #close} is called.
185559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown     */
186559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    public SQLiteDatabase getReadableDatabase() {
187559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        synchronized (this) {
188559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            return getDatabaseLocked(false);
189559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        }
190559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    }
191559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
192559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private SQLiteDatabase getDatabaseLocked(boolean writable) {
193cc6f54910d2431e31af176163f61b34d50a33647Vasu Nori        if (mDatabase != null) {
194cc6f54910d2431e31af176163f61b34d50a33647Vasu Nori            if (!mDatabase.isOpen()) {
195559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                // Darn!  The user closed the database by calling mDatabase.close().
196cc6f54910d2431e31af176163f61b34d50a33647Vasu Nori                mDatabase = null;
197559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            } else if (!writable || !mDatabase.isReadOnly()) {
198559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                // The database is already open for business.
199559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                return mDatabase;
200cc6f54910d2431e31af176163f61b34d50a33647Vasu Nori            }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsInitializing) {
204559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            throw new IllegalStateException("getDatabase called recursively");
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
207559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        SQLiteDatabase db = mDatabase;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIsInitializing = true;
210559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
211559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            if (db != null) {
212559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                if (writable && db.isReadOnly()) {
213559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    db.reopenReadWrite();
214559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                }
215559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            } else if (mName == null) {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                db = SQLiteDatabase.create(null);
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
218559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                try {
219559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    if (DEBUG_STRICT_READONLY && !writable) {
220559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                        final String path = mContext.getDatabasePath(mName).getPath();
221559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                        db = SQLiteDatabase.openDatabase(path, mFactory,
222559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                                SQLiteDatabase.OPEN_READONLY, mErrorHandler);
223559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    } else {
22447847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                        db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
22547847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                                Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
22647847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown                                mFactory, mErrorHandler);
227559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    }
228559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                } catch (SQLiteException ex) {
229559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    if (writable) {
230559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                        throw ex;
231559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    }
232559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    Log.e(TAG, "Couldn't open " + mName
233559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                            + " for writing (will try read-only):", ex);
234559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    final String path = mContext.getDatabasePath(mName).getPath();
235559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    db = SQLiteDatabase.openDatabase(path, mFactory,
236559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                            SQLiteDatabase.OPEN_READONLY, mErrorHandler);
237559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                }
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24096496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown            onConfigure(db);
24196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown
242559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            final int version = db.getVersion();
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (version != mNewVersion) {
244559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                if (db.isReadOnly()) {
245559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    throw new SQLiteException("Can't upgrade read-only database from version " +
246559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                            db.getVersion() + " to " + mNewVersion + ": " + mName);
247559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                }
248559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                db.beginTransaction();
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (version == 0) {
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        onCreate(db);
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
25444dc76a8a702d6a919fcea1c2d19ba3792687c85Brad Fitzpatrick                        if (version > mNewVersion) {
255a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold                            onDowngrade(db, version, mNewVersion);
256a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold                        } else {
257a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold                            onUpgrade(db, version, mNewVersion);
25844dc76a8a702d6a919fcea1c2d19ba3792687c85Brad Fitzpatrick                        }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    db.setVersion(mNewVersion);
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    db.setTransactionSuccessful();
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } finally {
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    db.endTransaction();
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            onOpen(db);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            if (db.isReadOnly()) {
270559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                Log.w(TAG, "Opened " + mName + " in read-only mode");
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDatabase = db;
274559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            return db;
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIsInitializing = false;
277559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            if (db != null && db != mDatabase) {
278559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                db.close();
279559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Close any open database object.
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized void close() {
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsInitializing) throw new IllegalStateException("Closed during initialization");
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDatabase != null && mDatabase.isOpen()) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDatabase.close();
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDatabase = null;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
29696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * Called when the database connection is being configured, to enable features
29796496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * such as write-ahead logging or foreign key support.
29896496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * <p>
29996496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * This method is called before {@link #onCreate}, {@link #onUpgrade},
30096496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * {@link #onDowngrade}, or {@link #onOpen} are called.  It should not modify
30196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * the database except to configure the database connection as required.
30296496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * </p><p>
30396496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * This method should only call methods that configure the parameters of the
30496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * database connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
30596496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * {@link SQLiteDatabase#setForeignKeyConstraintsEnabled},
30696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * {@link SQLiteDatabase#setLocale}, {@link SQLiteDatabase#setMaximumSize},
30796496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * or executing PRAGMA statements.
30896496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * </p>
30996496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     *
31096496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * @param db The database.
31196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     */
31296496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown    public void onConfigure(SQLiteDatabase db) {}
31396496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown
31496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown    /**
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called when the database is created for the first time. This is where the
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * creation of tables and the initial population of the tables should happen.
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param db The database.
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract void onCreate(SQLiteDatabase db);
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called when the database needs to be upgraded. The implementation
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * should use this method to drop tables, add tables, or do anything else it
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * needs to upgrade to the new schema version.
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
32796496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * <p>
32896496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * The SQLite ALTER TABLE documentation can be found
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * you can use ALTER TABLE to rename the old table, then create the new table and then
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * populate the new table with the contents of the old table.
33396496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * </p><p>
33496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * This method executes within a transaction.  If an exception is thrown, all changes
33596496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * will automatically be rolled back.
33696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * </p>
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param db The database.
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param oldVersion The old database version.
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newVersion The new database version.
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3451c423b81deda88cffdf27c4b0aafc0f4daf3ac8fPin Ting     * Called when the database needs to be downgraded. This is strictly similar to
34696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * {@link #onUpgrade} method, but is called whenever current version is newer than requested one.
347a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     * However, this method is not abstract, so it is not mandatory for a customer to
348a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     * implement it. If not overridden, default implementation will reject downgrade and
349a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     * throws SQLiteException
350a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     *
35196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * <p>
35296496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * This method executes within a transaction.  If an exception is thrown, all changes
35396496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * will automatically be rolled back.
35496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * </p>
35596496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     *
356a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     * @param db The database.
357a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     * @param oldVersion The old database version.
358a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     * @param newVersion The new database version.
359a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold     */
360a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
361a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold        throw new SQLiteException("Can't downgrade database from version " +
362a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold                oldVersion + " to " + newVersion);
363a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold    }
364a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold
365a5af5d6b122b5d7337e6640deabf7886689679ebEric Hassold    /**
3666fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * Called when the database has been opened.  The implementation
3676fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * should check {@link SQLiteDatabase#isReadOnly} before updating the
3686fcc0f073d8583cf1f485b9548cde41336a422beDan Egnor     * database.
36996496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * <p>
37096496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * This method is called after the database connection has been configured
37196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * and after the database schema has been created, upgraded or downgraded as necessary.
37296496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * If the database connection must be configured in some way before the schema
37396496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * is created, upgraded, or downgraded, do it in {@link #onConfigure} instead.
37496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown     * </p>
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param db The database.
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onOpen(SQLiteDatabase db) {}
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
380