I have a content provider backed by an SQLiteDatabase
. Consider the following two calls:
//the following call results in "DELETE FROM DETAILS":
context.getContentResolver().delete(getContentUriOfDetailTable(), null, null); //line 1
//the following call results in "DELETE FROM MASTER":
context.getContentResolver().delete(getContentUriOfMasterTable(), null, null); //line 2
As I know content providers are thread safe, when backed by an SQLiteDatabase. But is there a guarantee, that the execution of the SQL triggered by line 1 is finished before the SQL triggered by line 2 will be executed?
Background:
There is a foreign key reference from table DETAIL to MASTER and I got a bugreport
SQLiteConstraintException: foreign key constraint failed (code 19)
from line 2, though I cannot reproduce it.
Tables:
CREATE TABLE MASTER
(_id PRIMARY KEY autoincrement,
VALUE text
);
CREATE TABLE DETAILS (
_id PRIMARY KEY autoincrement,
MASTERIDX integer not null,
VALUE text,
FOREIGN KEY(MASTERIDX) REFERENCES MASTER(_id)
);
My ContentProvider is nothing special:
public class MyDbContentProvider extends ContentProvider {
private MyDbOpenHelper mDbHelper;
//...
//...
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = mDbHelper.getWritableDatabase();
int rowsDeleted = 0;
String where;
MyUriMatcher.MatchResult matchRes = mURIMatcher.matchTable(uri);
TableDef tableDef = matchRes.tableDef;
switch (matchRes.uriType) {
case ALL_ITEMS:
where = selection;
break;
case SINGLE_ITEM:
String idstr = uri.getLastPathSegment();
where = TableDef._ID + " = " + idstr;
if (!TextUtils.isEmpty(selection)) {
where += " AND (" + selection + ")";
}
break;
default:
throw new IllegalArgumentException("Unsupported URI for delete: " + uri);
}
try {
rowsDeleted = db.delete(tableDef.getTableName(), where, selectionArgs);
} catch (SQLException e) {
throw createCustomSqlException(e, "DELETE", uri, null, where, selectionArgs);
}
// notify all listeners of changes:
if (rowsDeleted > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsDeleted;
}
}
Here is the stack trace:
android.database.SQLException: SQLiteConstraintException: foreign key constraint failed (code 19) for DELETE for following URI: content://de.myapp.mobil.myappDbProvider/master and this selection: null
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:858)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
at android.database.sqlite.SQLiteDatabase.delete(SQLiteDatabase.java:1494)
at de.myapp.mobil.MyDbContentProvider.delete(MyDbContentProvider.java:267)
at android.content.ContentProvider$Transport.delete(ContentProvider.java:228)
at android.content.ContentResolver.delete(ContentResolver.java:958)
at de.myapp.CommonDbContract$TableDef.deleteAll(CommonDbContract.java:119)
at de.myapp.mobil.MyDbContract.deleteAll(MyDbContract.java:1730)
at de.myapp.mobil.MyDbContract.recreateDbOrDeleteAll(MyDbContract.java:1761)
at de.myapp.mobil.SettingsActivity$ResetAllCommand.execute(SettingsActivity.java:77)
at de.myapp.mobil.SettingsActivity$ResetAllCommand.execute(SettingsActivity.java:1)
at de.myapp.DlgUtils$DataCommand.execute(DlgUtils.java:54)
at de.myapp.DlgUtils$CombinedCommand.execute(DlgUtils.java:116)
at de.myapp.DlgUtils$CommandWrapper.onClick(DlgUtils.java:157)