I have a simple address table with the following create statement:
"CREATE TABLE " + ADDRESSES_TABLE + " (" + KEY_ADDRESS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_ADDRESS_COUNTRY + " TEXT, " + KEY_ADDRESS_CITY + " TEXT, " + KEY_ADDRESS_STREET + " TEXT, " + KEY_ADDRESS_HOUSE + " TEXT, " + KEY_ADDRESS_POSTAL_CODE + " TEXT," + "UNIQUE("+KEY_ADDRESS_COUNTRY+","+KEY_ADDRESS_CITY+","+KEY_ADDRESS_STREET+","+KEY_ADDRESS_HOUSE+","+KEY_ADDRESS_POSTAL_CODE +") ON CONFLICT IGNORE)"
When I add duplicate records, the insert() metod returns -1 and not the id of the existing row.
The problem is reproducible only on 4.0+. The method works as expected on 2.2 and 2.3.3.
Has anyone faced the same issue?
Unfortunately, the Android documentation is wrong. (And thus your code does not actually work as expected on prior versions of Android, e.g., 2.2 and 2.3.)
In 2.2 and 2.3,
insertWithOnConflict() will return the value of the SQLite C API function sqlite3_last_insert_rowid(), whose documentation clearly states that failed inserts (e.g., where the ON CONFLICT resolution, like IGNORE, is applied) do not affect the return value. Thus, if no prior insert for the connection was performed and a duplicate insert is attempted,
insertWithOnConflict() will return 0. If a prior insert added a row to any table, the method will return the row id of that insert—of course this is grossly incorrect.
insertWithOnConflict() will return the value of the same SQLite C API function, except returning -1 instead of 0.
This change is why you are now observing the error. But if you check the result closely in 2.2 and 2.3, you’ll see that the row ids returned when the
OR IGNORE clause is exercised are not actually the correct row ids (except coincidentally).