FileDocCategorySizeDatePackage
SQLiteDatabase.javaAPI DocAndroid 1.5 API66389Wed May 06 22:41:54 BST 2009android.database.sqlite

SQLiteDatabase

public class SQLiteDatabase extends SQLiteClosable
Exposes methods to manage a SQLite database.

SQLiteDatabase has methods to create, delete, execute SQL commands, and perform other common database management tasks.

See the Notepad sample application in the SDK for an example of creating and managing a database.

Database names must be unique within an application, not across all applications.

Localized Collation - ORDER BY

In addition to SQLite's default BINARY collator, Android supplies two more, LOCALIZED, which changes with the system's current locale if you wire it up correctly (XXX a link needed!), and UNICODE, which is the Unicode Collation Algorithm and not tailored to the current locale.

Fields Summary
private static final String
TAG
private static final int
DB_OPERATION_EVENT
public static final int
SQLITE_MAX_LIKE_PATTERN_LENGTH
Maximum Length Of A LIKE Or GLOB Pattern The pattern matching algorithm used in the default LIKE and GLOB implementation of SQLite can exhibit O(N^2) performance (where N is the number of characters in the pattern) for certain pathological cases. To avoid denial-of-service attacks the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes. The default value of this limit is 50000. A modern workstation can evaluate even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly. The denial of service problem only comes into play when the pattern length gets into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns are at most a few dozen bytes in length, paranoid application developers may want to reduce this parameter to something in the range of a few hundred if they know that external users are able to generate arbitrary patterns.
public static final int
OPEN_READWRITE
Flag for {@link #openDatabase} to open the database for reading and writing. If the disk is full, this may fail even before you actually write anything. {@more} Note that the value of this flag is 0, so it is the default.
public static final int
OPEN_READONLY
Flag for {@link #openDatabase} to open the database for reading only. This is the only reliable way to open a database if the disk may be full.
private static final int
OPEN_READ_MASK
public static final int
NO_LOCALIZED_COLLATORS
Flag for {@link #openDatabase} to open the database without support for localized collators. {@more} This causes the collator LOCALIZED not to be created. You must be consistent when using this flag to use the setting the database was created with. If this is set, {@link #setLocale} will do nothing.
public static final int
CREATE_IF_NECESSARY
Flag for {@link #openDatabase} to create the database file if it does not already exist.
private boolean
mInnerTransactionIsSuccessful
Indicates whether the most-recently started transaction has been marked as successful.
private boolean
mTransactionIsSuccessful
Valid during the life of a transaction, and indicates whether the entire transaction (the outer one and all of the inner ones) so far has been successful.
private final ReentrantLock
mLock
Synchronize on this when accessing the database
private long
mLockAcquiredWallTime
private long
mLockAcquiredThreadTime
private static final int
LOCK_WARNING_WINDOW_IN_MS
private static final int
LOCK_ACQUIRED_WARNING_TIME_IN_MS
If the lock is held this long then a warning will be printed when it is released.
private static final int
LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS
private static final int
LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT
private long
mLastLockMessageTime
int
mNativeHandle
Used by native code, do not rename
int
mTempTableSequence
Used to make temp table names unique
private String
mPath
The path for the database file
private int
mFlags
The flags passed to open/create
private CursorFactory
mFactory
The optional factory to use when creating new Cursors
private WeakHashMap
mPrograms
private final RuntimeException
mLeakedException
final boolean
mLogStats
private boolean
mLockingEnabled
If set then the SQLiteDatabase is made thread-safe by using locks around critical sections
private final Map
mSyncUpdateInfo
Maps table names to info about what to which _sync_time column to set to NULL on an update. This is used to support syncing.
Constructors Summary
private SQLiteDatabase(String path, CursorFactory factory, int flags)
Private constructor. See {@link #create} and {@link #openDatabase}.

param
path The full path to the database
param
factory The factory to use when creating cursors, may be NULL.
param
flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already exists, mFlags will be updated appropriately.

        if (path == null) {
            throw new IllegalArgumentException("path should not be null");
        }
        mFlags = flags;
        mPath = path;
        mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
        
        mLeakedException = new IllegalStateException(path +
            " SQLiteDatabase created and never closed");
        mFactory = factory;
        dbopen(mPath, mFlags);
        mPrograms = new WeakHashMap<SQLiteClosable,Object>();
        try {
            setLocale(Locale.getDefault());
        } catch (RuntimeException e) {
            Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
            dbclose();
            throw e;
        }
    
Methods Summary
voidaddSQLiteClosable(SQLiteClosable closable)

param
closable

    
           
       
        lock();
        try {
            mPrograms.put(closable, null);
        } finally {
            unlock();
        }
    
public voidbeginTransaction()
Begins a transaction. Transactions can be nested. When the outer transaction is ended all of the work done in that transaction and all of the nested transactions will be committed or rolled back. The changes will be rolled back if any transaction is ended without being marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.

Here is the standard idiom for transactions:

db.beginTransaction();
try {
...
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

        lockForced();
        boolean ok = false;
        try {
            // If this thread already had the lock then get out
            if (mLock.getHoldCount() > 1) {
                if (mInnerTransactionIsSuccessful) {
                    String msg = "Cannot call beginTransaction between "
                            + "calling setTransactionSuccessful and endTransaction";
                    IllegalStateException e = new IllegalStateException(msg);
                    Log.e(TAG, "beginTransaction() failed", e);
                    throw e;
                }
                ok = true;
                return;
            }

            // This thread didn't already have the lock, so begin a database
            // transaction now.
            execSQL("BEGIN EXCLUSIVE;");
            mTransactionIsSuccessful = true;
            mInnerTransactionIsSuccessful = false;
            ok = true;
        } finally {
            if (!ok) {
                // beginTransaction is called before the try block so we must release the lock in
                // the case of failure.
                unlockForced();
            }
        }
    
private voidcheckLockHoldTime()

        // Use elapsed real-time since the CPU may sleep when waiting for IO
        long elapsedTime = SystemClock.elapsedRealtime();
        long lockedTime = elapsedTime - mLockAcquiredWallTime;                
        if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT &&
                !Log.isLoggable(TAG, Log.VERBOSE) &&
                (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) {
            return;
        }
        if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) {
            int threadTime = (int)
                    ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000);
            if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS ||
                    lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) {
                mLastLockMessageTime = elapsedTime;
                String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was "
                        + threadTime + "ms";
                if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) {
                    Log.d(TAG, msg, new Exception());
                } else {
                    Log.d(TAG, msg);
                }
            }
        }
    
public voidclose()
Close the database.

        lock();
        try {
            closeClosable();
            releaseReference();
        } finally {
            unlock();
        }
    
private voidcloseClosable()

        Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<SQLiteClosable, Object> entry = iter.next();
            SQLiteClosable program = entry.getKey();
            if (program != null) {
                program.onAllReferencesReleasedFromContainer();
            }
        }        
    
public SQLiteStatementcompileStatement(java.lang.String sql)
Compiles an SQL statement into a reusable pre-compiled statement object. The parameters are identical to {@link #execSQL(String)}. You may put ?s in the statement and fill in those values with {@link SQLiteProgram#bindString} and {@link SQLiteProgram#bindLong} each time you want to run the statement. Statements may not return result sets larger than 1x1.

param
sql The raw SQL statement, may contain ? for unknown values to be bound later.
return
a pre-compiled statement object.

        lock();
        try {
            return new SQLiteStatement(this, sql);
        } finally {
            unlock();
        }
    
public static android.database.sqlite.SQLiteDatabasecreate(android.database.sqlite.SQLiteDatabase$CursorFactory factory)
Create a memory backed SQLite database. Its contents will be destroyed when the database is closed.

Sets the locale of the database to the the system's current locale. Call {@link #setLocale} if you would like something else.

param
factory an optional factory class that is called to instantiate a cursor when query is called
return
a SQLiteDatabase object, or null if the database can't be created

        // This is a magic string with special meaning for SQLite.
        return openDatabase(":memory:", factory, CREATE_IF_NECESSARY);
    
private native voiddbclose()
Native call to close the database.

private native voiddbopen(java.lang.String path, int flags)
Native call to open the database.

param
path The full path to the database

public intdelete(java.lang.String table, java.lang.String whereClause, java.lang.String[] whereArgs)
Convenience method for deleting rows in the database.

param
table the table to delete from
param
whereClause the optional WHERE clause to apply when deleting. Passing null will delete all rows.
return
the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all rows and get a count pass "1" as the whereClause.

        if (!isOpen()) {
            throw new IllegalStateException("database not open");
        }
        lock();
        SQLiteStatement statement = null;
        try {
            statement = compileStatement("DELETE FROM " + table
                    + (!TextUtils.isEmpty(whereClause)
                    ? " WHERE " + whereClause : ""));
            if (whereArgs != null) {
                int numArgs = whereArgs.length;
                for (int i = 0; i < numArgs; i++) {
                    DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]);
                }
            }
            statement.execute();
            statement.close();
            return lastChangeCount();
        } catch (SQLiteDatabaseCorruptException e) {
            onCorruption();
            throw e;
        } finally {
            if (statement != null) {
                statement.close();
            }
            unlock();
        }
    
public voidendTransaction()
End a transaction. See beginTransaction for notes about how to use this and when transactions are committed and rolled back.

        if (!mLock.isHeldByCurrentThread()) {
            throw new IllegalStateException("no transaction pending");
        }
        try {
            if (mInnerTransactionIsSuccessful) {
                mInnerTransactionIsSuccessful = false;
            } else {
                mTransactionIsSuccessful = false;
            }
            if (mLock.getHoldCount() != 1) {
                return;
            }
            if (mTransactionIsSuccessful) {
                execSQL("COMMIT;");
            } else {
                try {
                    execSQL("ROLLBACK;");
                } catch (SQLException e) {
                    if (Config.LOGD) {
                        Log.d(TAG, "exception during rollback, maybe the DB previously "
                                + "performed an auto-rollback");
                    }
                }
            }
        } finally {
            unlockForced();
            if (Config.LOGV) {
                Log.v(TAG, "unlocked " + Thread.currentThread()
                        + ", holdCount is " + mLock.getHoldCount());
            }
        }
    
public voidexecSQL(java.lang.String sql)
Execute a single SQL statement that is not a query. For example, CREATE TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not supported. it takes a write lock

throws
SQLException If the SQL string is invalid for some reason

        boolean logStats = mLogStats;
        long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
        lock();
        try {
            native_execSQL(sql);
        } catch (SQLiteDatabaseCorruptException e) {
            onCorruption();
            throw e;
        } finally {
            unlock();
        }
        if (logStats) {
            logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
        }
    
public voidexecSQL(java.lang.String sql, java.lang.Object[] bindArgs)
Execute a single SQL statement that is not a query. For example, CREATE TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not supported. it takes a write lock,

param
sql
param
bindArgs only byte[], String, Long and Double are supported in bindArgs.
throws
SQLException If the SQL string is invalid for some reason

        if (bindArgs == null) {
            throw new IllegalArgumentException("Empty bindArgs");
        }

        boolean logStats = mLogStats;
        long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
        lock();
        SQLiteStatement statement = null;
        try {
            statement = compileStatement(sql);
            if (bindArgs != null) {
                int numArgs = bindArgs.length;
                for (int i = 0; i < numArgs; i++) {
                    DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]);
                }
            }
            statement.execute();
        } catch (SQLiteDatabaseCorruptException e) {
            onCorruption();
            throw e;
        } finally {
            if (statement != null) {
                statement.close();
            }
            unlock();
        }
        if (logStats) {
            logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
        }
    
protected voidfinalize()

        if (isOpen()) {
            if (mPrograms.isEmpty()) {
                Log.e(TAG, "Leak found", mLeakedException);
            } else {
                IllegalStateException leakProgram = new IllegalStateException(
                        "mPrograms size " + mPrograms.size(), mLeakedException);
                Log.e(TAG, "Leak found", leakProgram);
            }
            closeClosable();
            onAllReferencesReleased();
        }
    
public static java.lang.StringfindEditTable(java.lang.String tables)
Finds the name of the first table, which is editable.

param
tables a list of tables
return
the first table listed

        if (!TextUtils.isEmpty(tables)) {
            // find the first word terminated by either a space or a comma
            int spacepos = tables.indexOf(' ");
            int commapos = tables.indexOf(',");

            if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
                return tables.substring(0, spacepos);
            } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
                return tables.substring(0, commapos);
            }
            return tables;
        } else {
            throw new IllegalStateException("Invalid tables");
        }
    
public longgetMaximumSize()
Returns the maximum size the database may grow to.

return
the new maximum database size

        SQLiteStatement prog = null;
        lock();
        try {
            prog = new SQLiteStatement(this,
                    "PRAGMA max_page_count;");
            long pageCount = prog.simpleQueryForLong();
            return pageCount * getPageSize();
        } finally {
            if (prog != null) prog.close();
            unlock();
        }
    
public longgetPageSize()
Returns the current database page size, in bytes.

return
the database page size, in bytes

        SQLiteStatement prog = null;
        lock();
        try {
            prog = new SQLiteStatement(this,
                    "PRAGMA page_size;");
            long size = prog.simpleQueryForLong();
            return size;
        } finally {
            if (prog != null) prog.close();
            unlock();
        }
    
public final java.lang.StringgetPath()
Getter for the path to the database file.

return
the path to our database file.

        return mPath;
    
public java.util.MapgetSyncedTables()


        
        synchronized(mSyncUpdateInfo) {
            HashMap<String, String> tables = new HashMap<String, String>();
            for (String table : mSyncUpdateInfo.keySet()) {
                SyncUpdateInfo info = mSyncUpdateInfo.get(table);
                if (info.deletedTable != null) {
                    tables.put(table, info.deletedTable);
                }
            }
            return tables;
        }
    
public intgetVersion()
Gets the database version.

return
the database version

        SQLiteStatement prog = null;
        lock();
        try {
            prog = new SQLiteStatement(this, "PRAGMA user_version;");
            long version = prog.simpleQueryForLong();
            return (int) version;
        } finally {
            if (prog != null) prog.close();
            unlock();
        }
    
public booleaninTransaction()
return true if there is a transaction pending

        return mLock.getHoldCount() > 0;
    
public longinsert(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues values)
Convenience method for inserting a row into the database.

param
table the table to insert the row into
param
nullColumnHack SQL doesn't allow inserting a completely empty row, so if initialValues is empty this column will explicitly be assigned a NULL value
param
values this map contains the initial column values for the row. The keys should be the column names and the values the column values
return
the row ID of the newly inserted row, or -1 if an error occurred

        try {
            return insertWithOnConflict(table, nullColumnHack, values, null);
        } catch (SQLException e) {
            Log.e(TAG, "Error inserting " + values, e);
            return -1;
        }
    
public longinsertOrThrow(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues values)
Convenience method for inserting a row into the database.

param
table the table to insert the row into
param
nullColumnHack SQL doesn't allow inserting a completely empty row, so if initialValues is empty this column will explicitly be assigned a NULL value
param
values this map contains the initial column values for the row. The keys should be the column names and the values the column values
throws
SQLException
return
the row ID of the newly inserted row, or -1 if an error occurred

        return insertWithOnConflict(table, nullColumnHack, values, null);
    
public longinsertWithOnConflict(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues initialValues, android.database.sqlite.SQLiteDatabase$ConflictAlgorithm algorithm)
General method for inserting a row into the database.

param
table the table to insert the row into
param
nullColumnHack SQL doesn't allow inserting a completely empty row, so if initialValues is empty this column will explicitly be assigned a NULL value
param
initialValues this map contains the initial column values for the row. The keys should be the column names and the values the column values
param
algorithm {@link ConflictAlgorithm} for insert conflict resolver
return
the row ID of the newly inserted row, or -1 if an error occurred
hide

        if (!isOpen()) {
            throw new IllegalStateException("database not open");
        }

        // Measurements show most sql lengths <= 152
        StringBuilder sql = new StringBuilder(152);
        sql.append("INSERT");
        if (algorithm != null) {
            sql.append(" OR ");
            sql.append(algorithm.value());
        }
        sql.append(" INTO ");
        sql.append(table);
        // Measurements show most values lengths < 40
        StringBuilder values = new StringBuilder(40);

        Set<Map.Entry<String, Object>> entrySet = null;
        if (initialValues != null && initialValues.size() > 0) {
            entrySet = initialValues.valueSet();
            Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
            sql.append('(");

            boolean needSeparator = false;
            while (entriesIter.hasNext()) {
                if (needSeparator) {
                    sql.append(", ");
                    values.append(", ");
                }
                needSeparator = true;
                Map.Entry<String, Object> entry = entriesIter.next();
                sql.append(entry.getKey());
                values.append('?");
            }

            sql.append(')");
        } else {
            sql.append("(" + nullColumnHack + ") ");
            values.append("NULL");
        }

        sql.append(" VALUES(");
        sql.append(values);
        sql.append(");");

        lock();
        SQLiteStatement statement = null;
        try {
            statement = compileStatement(sql.toString());

            // Bind the values
            if (entrySet != null) {
                int size = entrySet.size();
                Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
                for (int i = 0; i < size; i++) {
                    Map.Entry<String, Object> entry = entriesIter.next();
                    DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue());
                }
            }

            // Run the program and then cleanup
            statement.execute();

            long insertedRowId = lastInsertRow();
            if (insertedRowId == -1) {
                Log.e(TAG, "Error inserting " + initialValues + " using " + sql);
            } else {
                if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "Inserting row " + insertedRowId + " from "
                            + initialValues + " using " + sql);
                }
            }
            return insertedRowId;
        } catch (SQLiteDatabaseCorruptException e) {
            onCorruption();
            throw e;
        } finally {
            if (statement != null) {
                statement.close();
            }
            unlock();
        }
    
public booleanisDbLockedByCurrentThread()
Checks if the database lock is held by this thread.

return
true, if this thread is holding the database lock.

        return mLock.isHeldByCurrentThread();
    
public booleanisDbLockedByOtherThreads()
Checks if the database is locked by another thread. This is just an estimate, since this status can change at any time, including after the call is made but before the result has been acted upon.

return
true, if the database is locked by another thread

        return !mLock.isHeldByCurrentThread() && mLock.isLocked();
    
public booleanisOpen()

return
true if the DB is currently open (has not been closed)

        return mNativeHandle != 0;
    
public booleanisReadOnly()
return whether the DB is opened as read only.

return
true if DB is opened as read only

        return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
    
native intlastChangeCount()
Returns the number of changes made in the last statement executed.

return
the number of changes made in the last statement executed.

native longlastInsertRow()
Returns the row ID of the last row inserted into the database.

return
the row ID of the last row inserted into the database.

voidlock()
Locks the database for exclusive access. The database lock must be held when touch the native sqlite3* object since it is single threaded and uses a polling lock contention algorithm. The lock is recursive, and may be acquired multiple times by the same thread. This is a no-op if mLockingEnabled is false.

see
#unlock()

        if (!mLockingEnabled) return;
        mLock.lock();
        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
            if (mLock.getHoldCount() == 1) {
                // Use elapsed real-time since the CPU may sleep when waiting for IO
                mLockAcquiredWallTime = SystemClock.elapsedRealtime();
                mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
            }
        }
    
private voidlockForced()
Locks the database for exclusive access. The database lock must be held when touch the native sqlite3* object since it is single threaded and uses a polling lock contention algorithm. The lock is recursive, and may be acquired multiple times by the same thread.

see
#unlockForced()

        mLock.lock();
        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
            if (mLock.getHoldCount() == 1) {
                // Use elapsed real-time since the CPU may sleep when waiting for IO
                mLockAcquiredWallTime = SystemClock.elapsedRealtime();
                mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
            }
        }
    
voidlogTimeStat(boolean read, long begin, long end)

        EventLog.writeEvent(DB_OPERATION_EVENT, mPath, read ? 0 : 1, end - begin);
    
public voidmarkTableSyncable(java.lang.String table, java.lang.String deletedTable)
Mark this table as syncable. When an update occurs in this table the _sync_dirty field will be set to ensure proper syncing operation.

param
table the table to mark as syncable
param
deletedTable The deleted table that corresponds to the syncable table

        markTableSyncable(table, "_id", table, deletedTable);
    
public voidmarkTableSyncable(java.lang.String table, java.lang.String foreignKey, java.lang.String updateTable)
Mark this table as syncable, with the _sync_dirty residing in another table. When an update occurs in this table the _sync_dirty field of the row in updateTable with the _id in foreignKey will be set to ensure proper syncing operation.

param
table an update on this table will trigger a sync time removal
param
foreignKey this is the column in table whose value is an _id in updateTable
param
updateTable this is the table that will have its _sync_dirty

        markTableSyncable(table, foreignKey, updateTable, null);
    
private voidmarkTableSyncable(java.lang.String table, java.lang.String foreignKey, java.lang.String updateTable, java.lang.String deletedTable)
Mark this table as syncable, with the _sync_dirty residing in another table. When an update occurs in this table the _sync_dirty field of the row in updateTable with the _id in foreignKey will be set to ensure proper syncing operation.

param
table an update on this table will trigger a sync time removal
param
foreignKey this is the column in table whose value is an _id in updateTable
param
updateTable this is the table that will have its _sync_dirty
param
deletedTable The deleted table that corresponds to the updateTable

        lock();
        try {
            native_execSQL("SELECT _sync_dirty FROM " + updateTable
                    + " LIMIT 0");
            native_execSQL("SELECT " + foreignKey + " FROM " + table
                    + " LIMIT 0");
        } finally {
            unlock();
        }

        SyncUpdateInfo info = new SyncUpdateInfo(updateTable, deletedTable,
                foreignKey);
        synchronized (mSyncUpdateInfo) {
            mSyncUpdateInfo.put(table, info);
        }
    
native voidnative_execSQL(java.lang.String sql)
Native call to execute a raw SQL statement. {@link #lock} must be held when calling this method.

param
sql The raw SQL string
throws
SQLException

native voidnative_setLocale(java.lang.String loc, int flags)
Native call to set the locale. {@link #lock} must be held when calling this method.

throws
SQLException

public booleanneedUpgrade(int newVersion)

        return newVersion > getVersion();
    
protected voidonAllReferencesReleased()

        if (isOpen()) {
            dbclose();
        }
    
voidonCorruption()


    /* package */   
        try {
            // Close the database (if we can), which will cause subsequent operations to fail.
            close();
        } finally {
            Log.e(TAG, "Removing corrupt database: " + mPath);
            // Delete the corrupt file.  Don't re-create it now -- that would just confuse people
            // -- but the next time someone tries to open it, they can set it up from scratch.
            new File(mPath).delete();
        }
    
public static android.database.sqlite.SQLiteDatabaseopenDatabase(java.lang.String path, android.database.sqlite.SQLiteDatabase$CursorFactory factory, int flags)
Open the database according to the flags {@link #OPEN_READWRITE} {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.

Sets the locale of the database to the the system's current locale. Call {@link #setLocale} if you would like something else.

param
path to database file to open and/or create
param
factory an optional factory class that is called to instantiate a cursor when query is called, or null for default
param
flags to control database access mode
return
the newly opened database
throws
SQLiteException if the database cannot be opened

        SQLiteDatabase db = null;
        try {
            // Open the database.
            return new SQLiteDatabase(path, factory, flags);
        } catch (SQLiteDatabaseCorruptException e) {
            // Try to recover from this, if we can.
            // TODO: should we do this for other open failures?
            Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
            new File(path).delete();
            return new SQLiteDatabase(path, factory, flags);
        }
    
public static android.database.sqlite.SQLiteDatabaseopenOrCreateDatabase(java.io.File file, android.database.sqlite.SQLiteDatabase$CursorFactory factory)
Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).

        return openOrCreateDatabase(file.getPath(), factory);
    
public static android.database.sqlite.SQLiteDatabaseopenOrCreateDatabase(java.lang.String path, android.database.sqlite.SQLiteDatabase$CursorFactory factory)
Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).

        return openDatabase(path, factory, CREATE_IF_NECESSARY);
    
public android.database.Cursorquery(boolean distinct, java.lang.String table, java.lang.String[] columns, java.lang.String selection, java.lang.String[] selectionArgs, java.lang.String groupBy, java.lang.String having, java.lang.String orderBy, java.lang.String limit)
Query the given URL, returning a {@link Cursor} over the result set.

param
distinct true if you want each row to be unique, false otherwise.
param
table The table name to compile the query against.
param
columns A list of which columns to return. Passing null will return all columns, which is discouraged to prevent reading data from storage that isn't going to be used.
param
selection A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given table.
param
selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
param
groupBy A filter declaring how to group rows, formatted as an SQL GROUP BY clause (excluding the GROUP BY itself). Passing null will cause the rows to not be grouped.
param
having A filter declare which row groups to include in the cursor, if row grouping is being used, formatted as an SQL HAVING clause (excluding the HAVING itself). Passing null will cause all row groups to be included, and is required when row grouping is not being used.
param
orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.
param
limit Limits the number of rows returned by the query, formatted as LIMIT clause. Passing null denotes no LIMIT clause.
return
A Cursor object, which is positioned before the first entry
see
Cursor

        return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
                groupBy, having, orderBy, limit);
    
public android.database.Cursorquery(java.lang.String table, java.lang.String[] columns, java.lang.String selection, java.lang.String[] selectionArgs, java.lang.String groupBy, java.lang.String having, java.lang.String orderBy)
Query the given table, returning a {@link Cursor} over the result set.

param
table The table name to compile the query against.
param
columns A list of which columns to return. Passing null will return all columns, which is discouraged to prevent reading data from storage that isn't going to be used.
param
selection A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given table.
param
selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
param
groupBy A filter declaring how to group rows, formatted as an SQL GROUP BY clause (excluding the GROUP BY itself). Passing null will cause the rows to not be grouped.
param
having A filter declare which row groups to include in the cursor, if row grouping is being used, formatted as an SQL HAVING clause (excluding the HAVING itself). Passing null will cause all row groups to be included, and is required when row grouping is not being used.
param
orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.
return
A {@link Cursor} object, which is positioned before the first entry
see
Cursor


        return query(false, table, columns, selection, selectionArgs, groupBy,
                having, orderBy, null /* limit */);
    
public android.database.Cursorquery(java.lang.String table, java.lang.String[] columns, java.lang.String selection, java.lang.String[] selectionArgs, java.lang.String groupBy, java.lang.String having, java.lang.String orderBy, java.lang.String limit)
Query the given table, returning a {@link Cursor} over the result set.

param
table The table name to compile the query against.
param
columns A list of which columns to return. Passing null will return all columns, which is discouraged to prevent reading data from storage that isn't going to be used.
param
selection A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given table.
param
selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
param
groupBy A filter declaring how to group rows, formatted as an SQL GROUP BY clause (excluding the GROUP BY itself). Passing null will cause the rows to not be grouped.
param
having A filter declare which row groups to include in the cursor, if row grouping is being used, formatted as an SQL HAVING clause (excluding the HAVING itself). Passing null will cause all row groups to be included, and is required when row grouping is not being used.
param
orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.
param
limit Limits the number of rows returned by the query, formatted as LIMIT clause. Passing null denotes no LIMIT clause.
return
A {@link Cursor} object, which is positioned before the first entry
see
Cursor


        return query(false, table, columns, selection, selectionArgs, groupBy,
                having, orderBy, limit);
    
public android.database.CursorqueryWithFactory(android.database.sqlite.SQLiteDatabase$CursorFactory cursorFactory, boolean distinct, java.lang.String table, java.lang.String[] columns, java.lang.String selection, java.lang.String[] selectionArgs, java.lang.String groupBy, java.lang.String having, java.lang.String orderBy, java.lang.String limit)
Query the given URL, returning a {@link Cursor} over the result set.

param
cursorFactory the cursor factory to use, or null for the default factory
param
distinct true if you want each row to be unique, false otherwise.
param
table The table name to compile the query against.
param
columns A list of which columns to return. Passing null will return all columns, which is discouraged to prevent reading data from storage that isn't going to be used.
param
selection A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given table.
param
selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
param
groupBy A filter declaring how to group rows, formatted as an SQL GROUP BY clause (excluding the GROUP BY itself). Passing null will cause the rows to not be grouped.
param
having A filter declare which row groups to include in the cursor, if row grouping is being used, formatted as an SQL HAVING clause (excluding the HAVING itself). Passing null will cause all row groups to be included, and is required when row grouping is not being used.
param
orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.
param
limit Limits the number of rows returned by the query, formatted as LIMIT clause. Passing null denotes no LIMIT clause.
return
A Cursor object, which is positioned before the first entry
see
Cursor

        String sql = SQLiteQueryBuilder.buildQueryString(
                distinct, table, columns, selection, groupBy, having, orderBy, limit);

        return rawQueryWithFactory(
                cursorFactory, sql, selectionArgs, findEditTable(table));
    
public android.database.CursorrawQuery(java.lang.String sql, java.lang.String[] selectionArgs)
Runs the provided SQL and returns a {@link Cursor} over the result set.

param
sql the SQL query. The SQL string must not be ; terminated
param
selectionArgs You may include ?s in where clause in the query, which will be replaced by the values from selectionArgs. The values will be bound as Strings.
return
A {@link Cursor} object, which is positioned before the first entry

        return rawQueryWithFactory(null, sql, selectionArgs, null);
    
public android.database.CursorrawQuery(java.lang.String sql, java.lang.String[] selectionArgs, int initialRead, int maxRead)
Runs the provided SQL and returns a cursor over the result set. The cursor will read an initial set of rows and the return to the caller. It will continue to read in batches and send data changed notifications when the later batches are ready.

param
sql the SQL query. The SQL string must not be ; terminated
param
selectionArgs You may include ?s in where clause in the query, which will be replaced by the values from selectionArgs. The values will be bound as Strings.
param
initialRead set the initial count of items to read from the cursor
param
maxRead set the count of items to read on each iteration after the first
return
A {@link Cursor} object, which is positioned before the first entry This work is incomplete and not fully tested or reviewed, so currently hidden.
hide

        SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
                null, sql, selectionArgs, null);
        c.setLoadStyle(initialRead, maxRead);
        return c;
    
public android.database.CursorrawQueryWithFactory(android.database.sqlite.SQLiteDatabase$CursorFactory cursorFactory, java.lang.String sql, java.lang.String[] selectionArgs, java.lang.String editTable)
Runs the provided SQL and returns a cursor over the result set.

param
cursorFactory the cursor factory to use, or null for the default factory
param
sql the SQL query. The SQL string must not be ; terminated
param
selectionArgs You may include ?s in where clause in the query, which will be replaced by the values from selectionArgs. The values will be bound as Strings.
param
editTable the name of the first table, which is editable
return
A {@link Cursor} object, which is positioned before the first entry

        long timeStart = 0;

        if (Config.LOGV) {
            timeStart = System.currentTimeMillis();
        }

        SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);

        try {
            return driver.query(
                    cursorFactory != null ? cursorFactory : mFactory,
                    selectionArgs);
        } finally {
            if (Config.LOGV) {
                long duration = System.currentTimeMillis() - timeStart;

                Log.v(SQLiteCursor.TAG,
                      "query (" + duration + " ms): " + driver.toString() + ", args are "
                              + (selectionArgs != null
                              ? TextUtils.join(",", selectionArgs)
                              : "<null>"));
            }
        }
    
public static native intreleaseMemory()
Attempts to release memory that SQLite holds but does not require to operate properly. Typically this memory will come from the page cache.

return
the number of bytes actually released

voidremoveSQLiteClosable(SQLiteClosable closable)

        lock();
        try {
            mPrograms.remove(closable);
        } finally {
            unlock();
        }
    
public longreplace(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues initialValues)
Convenience method for replacing a row in the database.

param
table the table in which to replace the row
param
nullColumnHack SQL doesn't allow inserting a completely empty row, so if initialValues is empty this row will explicitly be assigned a NULL value
param
initialValues this map contains the initial column values for the row. The key
return
the row ID of the newly inserted row, or -1 if an error occurred

        try {
            return insertWithOnConflict(table, nullColumnHack, initialValues, 
                    ConflictAlgorithm.REPLACE);
        } catch (SQLException e) {
            Log.e(TAG, "Error inserting " + initialValues, e);
            return -1;
        }
    
public longreplaceOrThrow(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues initialValues)
Convenience method for replacing a row in the database.

param
table the table in which to replace the row
param
nullColumnHack SQL doesn't allow inserting a completely empty row, so if initialValues is empty this row will explicitly be assigned a NULL value
param
initialValues this map contains the initial column values for the row. The key
throws
SQLException
return
the row ID of the newly inserted row, or -1 if an error occurred

        return insertWithOnConflict(table, nullColumnHack, initialValues, 
                ConflictAlgorithm.REPLACE);
    
voidrowUpdated(java.lang.String table, long rowId)
Call for each row that is updated in a cursor.

param
table the table the row is in
param
rowId the row ID of the updated row

        SyncUpdateInfo info;
        synchronized (mSyncUpdateInfo) {
            info = mSyncUpdateInfo.get(table);
        }
        if (info != null) {
            execSQL("UPDATE " + info.masterTable
                    + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey
                    + " FROM " + table + " WHERE _id=" + rowId + ")");
        }
    
public voidsetLocale(java.util.Locale locale)
Sets the locale for this database. Does nothing if this database has the NO_LOCALIZED_COLLATORS flag set or was opened read only.

throws
SQLException if the locale could not be set. The most common reason for this is that there is no collator available for the locale you requested. In this case the database remains unchanged.

        lock();
        try {
            native_setLocale(locale.toString(), mFlags);
        } finally {
            unlock();
        }
    
public voidsetLockingEnabled(boolean lockingEnabled)
Control whether or not the SQLiteDatabase is made thread-safe by using locks around critical sections. This is pretty expensive, so if you know that your DB will only be used by a single thread then you should set this to false. The default is true.

param
lockingEnabled set to true to enable locks, false otherwise

        mLockingEnabled = lockingEnabled;
    
public longsetMaximumSize(long numBytes)
Sets the maximum size the database will grow to. The maximum size cannot be set below the current size.

param
numBytes the maximum database size, in bytes
return
the new maximum database size

        SQLiteStatement prog = null;
        lock();
        try {
            long pageSize = getPageSize();
            long numPages = numBytes / pageSize;
            // If numBytes isn't a multiple of pageSize, bump up a page
            if ((numBytes % pageSize) != 0) {
                numPages++;
            }
            prog = new SQLiteStatement(this,
                    "PRAGMA max_page_count = " + numPages);
            long newPageCount = prog.simpleQueryForLong();
            return newPageCount * pageSize;
        } finally {
            if (prog != null) prog.close();
            unlock();
        }
    
public voidsetPageSize(long numBytes)
Sets the database page size. The page size must be a power of two. This method does not work if any data has been written to the database file, and must be called right after the database has been created.

param
numBytes the database page size, in bytes

        execSQL("PRAGMA page_size = " + numBytes);
    
public voidsetTransactionSuccessful()
Marks the current transaction as successful. Do not do any more database work between calling this and calling endTransaction. Do as little non-database work as possible in that situation too. If any errors are encountered between this and endTransaction the transaction will still be committed.

throws
IllegalStateException if the current thread is not in a transaction or the transaction is already marked as successful.

        if (!mLock.isHeldByCurrentThread()) {
            throw new IllegalStateException("no transaction pending");
        }
        if (mInnerTransactionIsSuccessful) {
            throw new IllegalStateException(
                    "setTransactionSuccessful may only be called once per call to beginTransaction");
        }
        mInnerTransactionIsSuccessful = true;
    
public voidsetVersion(int version)
Sets the database version.

param
version the new database version

        execSQL("PRAGMA user_version = " + version);
    
voidunlock()
Releases the database lock. This is a no-op if mLockingEnabled is false.

see
#unlock()

        if (!mLockingEnabled) return;
        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
            if (mLock.getHoldCount() == 1) {
                checkLockHoldTime();
            }
        }
        mLock.unlock();
    
private voidunlockForced()
Releases the database lock.

see
#unlockForced()

        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
            if (mLock.getHoldCount() == 1) {
                checkLockHoldTime();
            }
        }
        mLock.unlock();
    
public intupdate(java.lang.String table, android.content.ContentValues values, java.lang.String whereClause, java.lang.String[] whereArgs)
Convenience method for updating rows in the database.

param
table the table to update in
param
values a map from column names to new column values. null is a valid value that will be translated to NULL.
param
whereClause the optional WHERE clause to apply when updating. Passing null will update all rows.
return
the number of rows affected

        return updateWithOnConflict(table, values, whereClause, whereArgs, null);
    
public intupdateWithOnConflict(java.lang.String table, android.content.ContentValues values, java.lang.String whereClause, java.lang.String[] whereArgs, android.database.sqlite.SQLiteDatabase$ConflictAlgorithm algorithm)
Convenience method for updating rows in the database.

param
table the table to update in
param
values a map from column names to new column values. null is a valid value that will be translated to NULL.
param
whereClause the optional WHERE clause to apply when updating. Passing null will update all rows.
param
algorithm {@link ConflictAlgorithm} for update conflict resolver
return
the number of rows affected
hide

        if (!isOpen()) {
            throw new IllegalStateException("database not open");
        }

        if (values == null || values.size() == 0) {
            throw new IllegalArgumentException("Empty values");
        }

        StringBuilder sql = new StringBuilder(120);
        sql.append("UPDATE ");
        if (algorithm != null) {
            sql.append(" OR ");
            sql.append(algorithm.value());
        }
        
        sql.append(table);
        sql.append(" SET ");

        Set<Map.Entry<String, Object>> entrySet = values.valueSet();
        Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();

        while (entriesIter.hasNext()) {
            Map.Entry<String, Object> entry = entriesIter.next();
            sql.append(entry.getKey());
            sql.append("=?");
            if (entriesIter.hasNext()) {
                sql.append(", ");
            }
        }

        if (!TextUtils.isEmpty(whereClause)) {
            sql.append(" WHERE ");
            sql.append(whereClause);
        }

        lock();
        SQLiteStatement statement = null;
        try {
            statement = compileStatement(sql.toString());

            // Bind the values
            int size = entrySet.size();
            entriesIter = entrySet.iterator();
            int bindArg = 1;
            for (int i = 0; i < size; i++) {
                Map.Entry<String, Object> entry = entriesIter.next();
                DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue());
                bindArg++;
            }

            if (whereArgs != null) {
                size = whereArgs.length;
                for (int i = 0; i < size; i++) {
                    statement.bindString(bindArg, whereArgs[i]);
                    bindArg++;
                }
            }

            // Run the program and then cleanup
            statement.execute();
            statement.close();
            int numChangedRows = lastChangeCount();
            if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql);
            }
            return numChangedRows;
        } catch (SQLiteDatabaseCorruptException e) {
            onCorruption();
            throw e;
        } catch (SQLException e) {
            Log.e(TAG, "Error updating " + values + " using " + sql);
            throw e;
        } finally {
            if (statement != null) {
                statement.close();
            }
            unlock();
        }
    
public booleanyieldIfContended()
Temporarily end the transaction to let other threads run. The transaction is assumed to be successful so far. Do not call setTransactionSuccessful before calling this. When this returns a new transaction will have been created but not marked as successful.

return
true if the transaction was yielded
deprecated
if the db is locked more than once (becuase of nested transactions) then the lock will not be yielded. Use yieldIfContendedSafely instead.

        return yieldIfContendedHelper(false /* do not check yielding */);
    
private booleanyieldIfContendedHelper(boolean checkFullyYielded)

        if (mLock.getQueueLength() == 0) {
            // Reset the lock acquire time since we know that the thread was willing to yield
            // the lock at this time.
            mLockAcquiredWallTime = SystemClock.elapsedRealtime();
            mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
            return false;
        }
        setTransactionSuccessful();
        endTransaction();
        if (checkFullyYielded) {
            if (this.isDbLockedByCurrentThread()) {
                throw new IllegalStateException(
                        "Db locked more than once. yielfIfContended cannot yield");
            }
        }
        beginTransaction();
        return true;
    
public booleanyieldIfContendedSafely()
Temporarily end the transaction to let other threads run. The transaction is assumed to be successful so far. Do not call setTransactionSuccessful before calling this. When this returns a new transaction will have been created but not marked as successful. This assumes that there are no nested transactions (beginTransaction has only been called once) and will through an exception if that is not the case.

return
true if the transaction was yielded

        return yieldIfContendedHelper(true /* check yielding */);