SQLiteDatabasepublic 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_LENGTHMaximum 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_READWRITEFlag 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_READONLYFlag 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_COLLATORSFlag 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_NECESSARYFlag for {@link #openDatabase} to create the database file if it does not already exist. | private boolean | mInnerTransactionIsSuccessfulIndicates whether the most-recently started transaction has been marked as successful. | private boolean | mTransactionIsSuccessfulValid 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 | mLockSynchronize 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_MSIf 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 | mNativeHandleUsed by native code, do not rename | int | mTempTableSequenceUsed to make temp table names unique | private String | mPathThe path for the database file | private int | mFlagsThe flags passed to open/create | private CursorFactory | mFactoryThe optional factory to use when creating new Cursors | private WeakHashMap | mPrograms | private final RuntimeException | mLeakedException | final boolean | mLogStats | private boolean | mLockingEnabledIf set then the SQLiteDatabase is made thread-safe by using locks
around critical sections | private final Map | mSyncUpdateInfoMaps 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}.
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 |
---|
void | addSQLiteClosable(SQLiteClosable closable)
lock();
try {
mPrograms.put(closable, null);
} finally {
unlock();
}
| public void | beginTransaction()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 void | checkLockHoldTime()
// 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 void | close()Close the database.
lock();
try {
closeClosable();
releaseReference();
} finally {
unlock();
}
| private void | closeClosable()
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 SQLiteStatement | compileStatement(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.
lock();
try {
return new SQLiteStatement(this, sql);
} finally {
unlock();
}
| public static android.database.sqlite.SQLiteDatabase | create(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.
// This is a magic string with special meaning for SQLite.
return openDatabase(":memory:", factory, CREATE_IF_NECESSARY);
| private native void | dbclose()Native call to close the database.
| private native void | dbopen(java.lang.String path, int flags)Native call to open the database.
| public int | delete(java.lang.String table, java.lang.String whereClause, java.lang.String[] whereArgs)Convenience method for deleting rows in the database.
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 void | endTransaction()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 void | execSQL(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
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 void | execSQL(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,
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 void | finalize()
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.String | findEditTable(java.lang.String tables)Finds the name of the first table, which is editable.
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 long | getMaximumSize()Returns the maximum size the database may grow to.
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 long | getPageSize()Returns the current 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.String | getPath()Getter for the path to the database file.
return mPath;
| public java.util.Map | getSyncedTables()
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 int | getVersion()Gets 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 boolean | inTransaction()return true if there is a transaction pending
return mLock.getHoldCount() > 0;
| public long | insert(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues values)Convenience method for inserting a row into the database.
try {
return insertWithOnConflict(table, nullColumnHack, values, null);
} catch (SQLException e) {
Log.e(TAG, "Error inserting " + values, e);
return -1;
}
| public long | insertOrThrow(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues values)Convenience method for inserting a row into the database.
return insertWithOnConflict(table, nullColumnHack, values, null);
| public long | insertWithOnConflict(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.
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 boolean | isDbLockedByCurrentThread()Checks if the database lock is held by this thread.
return mLock.isHeldByCurrentThread();
| public boolean | isDbLockedByOtherThreads()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 !mLock.isHeldByCurrentThread() && mLock.isLocked();
| public boolean | isOpen()
return mNativeHandle != 0;
| public boolean | isReadOnly()return whether the DB is opened as read only.
return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
| native int | lastChangeCount()Returns the number of changes made in the last statement executed.
| native long | lastInsertRow()Returns the row ID of the last row inserted into the database.
| void | lock()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.
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 void | lockForced()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.
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();
}
}
| void | logTimeStat(boolean read, long begin, long end)
EventLog.writeEvent(DB_OPERATION_EVENT, mPath, read ? 0 : 1, end - begin);
| public void | markTableSyncable(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.
markTableSyncable(table, "_id", table, deletedTable);
| public void | markTableSyncable(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.
markTableSyncable(table, foreignKey, updateTable, null);
| private void | markTableSyncable(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.
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 void | native_execSQL(java.lang.String sql)Native call to execute a raw SQL statement. {@link #lock} must be held
when calling this method.
| native void | native_setLocale(java.lang.String loc, int flags)Native call to set the locale. {@link #lock} must be held when calling
this method.
| public boolean | needUpgrade(int newVersion)
return newVersion > getVersion();
| protected void | onAllReferencesReleased()
if (isOpen()) {
dbclose();
}
| void | onCorruption()
/* 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.SQLiteDatabase | openDatabase(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.
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.SQLiteDatabase | openOrCreateDatabase(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.SQLiteDatabase | openOrCreateDatabase(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.Cursor | query(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.
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
groupBy, having, orderBy, limit);
| public android.database.Cursor | query(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.
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, null /* limit */);
| public android.database.Cursor | query(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.
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, limit);
| public android.database.Cursor | queryWithFactory(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.
String sql = SQLiteQueryBuilder.buildQueryString(
distinct, table, columns, selection, groupBy, having, orderBy, limit);
return rawQueryWithFactory(
cursorFactory, sql, selectionArgs, findEditTable(table));
| public android.database.Cursor | rawQuery(java.lang.String sql, java.lang.String[] selectionArgs)Runs the provided SQL and returns a {@link Cursor} over the result set.
return rawQueryWithFactory(null, sql, selectionArgs, null);
| public android.database.Cursor | rawQuery(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.
SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
null, sql, selectionArgs, null);
c.setLoadStyle(initialRead, maxRead);
return c;
| public android.database.Cursor | rawQueryWithFactory(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.
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 int | releaseMemory()Attempts to release memory that SQLite holds but does not require to
operate properly. Typically this memory will come from the page cache.
| void | removeSQLiteClosable(SQLiteClosable closable)
lock();
try {
mPrograms.remove(closable);
} finally {
unlock();
}
| public long | replace(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues initialValues)Convenience method for replacing a row in the database.
try {
return insertWithOnConflict(table, nullColumnHack, initialValues,
ConflictAlgorithm.REPLACE);
} catch (SQLException e) {
Log.e(TAG, "Error inserting " + initialValues, e);
return -1;
}
| public long | replaceOrThrow(java.lang.String table, java.lang.String nullColumnHack, android.content.ContentValues initialValues)Convenience method for replacing a row in the database.
return insertWithOnConflict(table, nullColumnHack, initialValues,
ConflictAlgorithm.REPLACE);
| void | rowUpdated(java.lang.String table, long rowId)Call for each row that is updated in a cursor.
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 void | setLocale(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.
lock();
try {
native_setLocale(locale.toString(), mFlags);
} finally {
unlock();
}
| public void | setLockingEnabled(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.
mLockingEnabled = lockingEnabled;
| public long | setMaximumSize(long numBytes)Sets the maximum size the database will grow to. The maximum size cannot
be set below the current 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 void | setPageSize(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.
execSQL("PRAGMA page_size = " + numBytes);
| public void | setTransactionSuccessful()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.
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 void | setVersion(int version)Sets the database version.
execSQL("PRAGMA user_version = " + version);
| void | unlock()Releases the database lock. This is a no-op if mLockingEnabled is false.
if (!mLockingEnabled) return;
if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
if (mLock.getHoldCount() == 1) {
checkLockHoldTime();
}
}
mLock.unlock();
| private void | unlockForced()Releases the database lock.
if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
if (mLock.getHoldCount() == 1) {
checkLockHoldTime();
}
}
mLock.unlock();
| public int | update(java.lang.String table, android.content.ContentValues values, java.lang.String whereClause, java.lang.String[] whereArgs)Convenience method for updating rows in the database.
return updateWithOnConflict(table, values, whereClause, whereArgs, null);
| public int | updateWithOnConflict(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.
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 boolean | yieldIfContended()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 yieldIfContendedHelper(false /* do not check yielding */);
| private boolean | yieldIfContendedHelper(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 boolean | yieldIfContendedSafely()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 yieldIfContendedHelper(true /* check yielding */);
|
|