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