How to solve room data integrity error due to identityHash mismatch? - sqlite

Issue:
Whenever I make changes to the database or the model, I get the following Room data integrity error:
My understanding is that I shouldn't need to increase the version number since I am using .fallbackToDestructiveMigration().
Background:
I using DB Browser for SQLite (v3.12.0) to make changes to the database.
I frequently make changes to my app/database, which is still in development. So, I am using a .fallbackToDestructiveMigration() (see codelab example).
File: RoomDB.java
#Database(entities =
{Note.class, Label.class, Join_ScheduleLabel.class, Schedule.class},
version = 1)
#TypeConverters(DataConverters.class)
public abstract class RoomDB extends androidx.room.RoomDatabase {
public static final String DATABASE_NAME = "vk_prepop.sqlite";
private static RoomDB INSTANCE;
public static RoomDB getInstance(final Context context) {
if (INSTANCE == null) {
synchronized (RoomDB.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context.getApplicationContext(),
RoomDB.class,
DATABASE_NAME)
// Source: https://developer.android.com/training/data-storage/room/prepopulate
.createFromAsset(DATABASE_NAME)
// Todo: Remove Destructive Migration
// Wipes and rebuilds instead of migrating if no Migration object.
.fallbackToDestructiveMigration()
.build();
}
}
}
return INSTANCE;
}
public abstract RoomDao getRoomDao();
}
Troubleshooting Steps Taken:
Verifying the entities of the RoomDB.java file match the models and database.
Going into the App Info and tapping "Clear data" (see SO answer).
Uninstalling the app.
Making setting android:allowBackup="false" in the manifest (see SO answer).
Possible Solution:
In live-love's answer he says there may be an identityHash mismatch, but I am not sure how to resolve this using DB Browser for SQLite.

My understanding is that I shouldn't need to increase the version number since I am using .fallbackToDestructiveMigration().
The fallBackToDestructiveMigration only runs if a migration is required and there is no Migration covering the migration.
In your situation the issue is that you have included the room_master_table in the pre-packaged database and hence the identity_hash columns is available for comparison (which would be incorrect if changes were made to the schema that affected how room generates the identity_hash from the schema).
By including the room_master_table you are introducing an unnecessary complexity.
If you omit this table from the pre-packaged database, then it will be created and populated, with the appropriate identity_hash when it is created from the asset (i.e. when the database doesn't exist). As such you then only have to make the appropriate changes to the asset (the pre-packaged database), delete the current database (e.g. uninstall the App or clear the Apps data) and then run the App.

live-love's answer states that there may be an identityHash mismatch. Indeed this was the case. Here is how I resolved the issue using DB Browser for SQLite (v3.12.0).
Step 1: In Android Studio's project panel choose the "Project" view:
Step 2: Then double-click on the json file for your schema:
Step 3: Copy the identityHash in this json file:
Step 4: Open your database in DB Browser for SQLite. Click the "Browse Data" tab. Then from the drop-down menu choose "room_master_table".
Step 5: Compare the identifyHash from the json file in Android Studio to the identityHash in DB Browser for SQLite. If the hashes are different, this can be the cause of you Room data integrity error.
Step 6: So, paste the identityHash from the Android Studio's json file into the identityHash cell in the DB Browser for SQLite.
Step 7: Then press Ctrl+Shift+S to save the database.
Step 8: Click "Close Database".
Step 9: In your app on your phone or emulator go to "App Info" -> "Storage" -> "Clear data".
Step 10: Then in Android Studio press "Run app".
Problem solved... at least for me. If these steps did not help, please review these additional troubleshooting steps.

Related

Web2py Error" <class 'sqlite3.OperationalError'> no such table: application

When I try to add a new record to Web2py Database I get this error. I've moved the repository from a different machine but all of my files are same.
My previous database DAL connection parameters are as follow:
from gluon.contrib.appconfig import AppConfig
myconf = AppConfig(reload=True)
if not request.env.web2py_runtime_gae:
db = DAL(myconf.get('db.'+myconf.get('db.mode')+'_uri'),
pool_size=myconf.get('db.pool_size'),
migrate=myconf.get('db.migrate'),
migrate_enabled=myconf.get('db.migrate_enabled'),
#fake_migrate_all=myconf.get('db.fake_migrate_all'),
fake_migrate_all=True,
check_reserved=['all'])
else:
db = DAL('google:datastore+ndb')
session.connect(request, response, db=db)
It was giving me user_auth not found error so I changed it into this by following the official docs:
from gluon.contrib.appconfig import AppConfig
myconf = AppConfig(reload=True)
if not request.env.web2py_runtime_gae:
db = DAL('sqlite://storage.sqlite', pool_size=1, check_reserved=['all'], migrate=False, fake_migrate_all=True)
else:
db = DAL('google:datastore+ndb')
It shows all the table in /database and in "Database_Administration" console I try to add a new record I get the error below.
Web2py Error" <class 'sqlite3.OperationalError'> no such table: application
There is no table in my app named "application" so it has to be related to app. Please advise.
Go to your database folder in "applications/yourappname/databases". Remove all the tables and then recreate tables. You must had copied it from somewhere and couldn't get all the tables loaded. Set migrate=True and fake_migrate_all=false. Then rerun server and go to your app in web2py server panel. Select "Edit" and go to "database administration" under "Models" on the admin panel. You will get all the tables recreated on your own machine. If this is not the case that you've copied from some other source....still do the following by deleting all the tables. You will surely get it up and running.
You have created a completely new database, but by setting fake_migrate_all=True, you have made web2py think all the tables have been created even though they never were. Instead, you should initially leave migrate=True (the default), and do not set fake_migrate_all. In that case, web2py will create the tables upon the first request (after that, you can disable migrations until you need to make another change).

Qt - sync SQLite data base on application close

Data base is oppened in application by following code:
db = QSqlDatabase::addDatabase("QSQLITE");
bool dbExists = QFile::exists("base.db");
db.setDatabaseName("base.db"); // ":memory:"
if (!db.open()) {
db.close();
QMessageBox::critical(0, tr("Cannot open database"),
tr("Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information how "
"to build it."), QMessageBox::Cancel);
return;
}
if (!dbExists)
createDB();
I've mapped some tables to widgets via QDataWidgetMapper. All work fine during application run. Changes take effect. But all the chages are lost after restarting application with existing base.db. Application starts much faster, so it opens this file but with unchanged data base.
I've tried to close application by
db.close();
this->close();
There is no luck. Even the sync query did not help after db.open:
QSqlQuery query(db);
query.exec("PRAGMA synchronous = ON;");
What have I missed to sync changes to base.db?
UPDATE. You can try to build sqlwidgetmapper standard example and change :memory: to "base.db" file. It doesn't save changed data to file too.
Problem is possibly manual submit policy.
Either switch that to auto, or manually call QDataWidgetMapper::submit() at appropriate time (before new value is lost from the widget).

first realm db can be open encrypted but writeCopyToPath cannot

I'm using Realm 0.98.6 with Xcode 7.3 in an OSX app to create an encrypted realm database and then making a clean copy to place in my bundle. The original database opens with the Realm Browser (after pasting in the key), but the copy does not.
Here is the code I use to create both the databases. There are no writes in the routines called, just a mix of realm.adds and realm.appends to create a collection of related objects:
let config = Realm.Configuration(path: realmTempFile, encryptionKey: key)
let realm = try! Realm(configuration: config)
try! realm.write {
loadAuthors(authorFile, realm: realm)
loadVolumes(volumesFile, realm: realm)
}
try! realm.writeCopyToPath(realmFile, encryptionKey: key)
If I remove the encryptionKey parameters from the config and writecopy, then both databases open ok with the Realm Browser.
In case it matters, I'm deleting the db files with the Finder (and associated lock files) before each attempt. (I've also tried changing the names to mitigate any temporary files hanging around.). The only obvious difference between the two files is 7.5 vs 6.9 MB filesize for the 'original' and 'copy' respectively (i.e., as expected the copy is slightly smaller).
I'd love some suggestions! It's a pretty vanilla program of <400 lines that loads a db for later use in an iOS & Android app. I can always ship the bigger file, but it's making me wary of what else I might not know... thanks in advance!

SQLite data cleanup in Windows 8 application

In my windows 8.1 application i am using SQLitePCL on top of SQLite.
I create the tables and populate my test data on application launch.
I only create DB tables if the tables are not existing through SQL is exists keyword in the queries.
Now how do i clean up the populated test data. Do i have to run delete queries when application shuts down ?.
I am testing through Windows simulator 8. Is there no way to clean up the app data which will flush the db in the simulator ?
cheers,
Saurav
I suggest you to recreate DB schema every time you need to flush populated data. You have at least two options to achieve that:
At first: in the same way as you create DB tables if they are not exist, you can delete DB when the data should be flushed and recreate it. I use this code to open/create DB file.
private async Task<bool> IsDBExistAsync()
{
bool isExist = true;
try
{
StorageFile sf = await ApplicationData.Current.LocalFolder.GetFileAsync(DATABASE_NAME);
}
catch (Exception)
{
isExist = false;
}
return isExist;
}
At second: open explorer window and navigate to C:\Users\{username}\AppData\Local\Packages\{package_family_name}\LocalState and delete DB file manually when it is not needed anymore. "package_family_name" is specified in Package.appxmanifest of your app (Packaging tab).
Bonus item: if you are developing phone part - you can access local storage using Windows Phone Power Tools utility.

Phonegap Sqlite Vacuum

We have an offline capable tablet app using VSNomad (through Phonegap) with Sqlite local database. One thing I've noticed is when we delete all data from tables and drop tables (doing an "app reset") on an iPad it doesn't reflect that space has been opened up.
I've come across "VACUUM" command for Sqlite however I am unsure how/if this can be used with our implementation. When I tried to run it I get an error saying cannot run within a transaction.
Here's examples of how we're implementing
http://docs.phonegap.com/en/2.7.0/cordova_storage_storage.md.html#Storage
app.shared.db().transaction(function (tx) {
tx.executeSql('VACUUM', [], function (tx, results) {
alert('done');
}, function (tx, error) {
alert('error');
alert(error.message);
});
});
Is it possible to run a vacuum like this?
I implemented your code and I get:
E/SQLiteQuery(18724): exception: not an error; query: VACUUM
Searching a bit further I found out that the vacuum sql command can not be given while connected to the database, so cannot be run from the database open and transaction from within javascript nor phonegap. Can only be given from command line.
But there must be another way... (looking in to that).
For now I have a few suggestions for database management:
Make sure you can delete the app and start with a fresh database (see below)
Prevent growing of the database: empty table and not drop table all the time (transaction.executeSql('DELETE FROM tablename;');) Note: don't use the '*' mark
Populate your database if it's the first run, see: http://mebefreelancer.wordpress.com/2012/08/14/phonegap-if-database-exists-do-something-else-populate-database/
Try to set up your app in a way the database is being migrated in a nice way: see enter link description here (a django /south kind of way for migrations)

Resources