Attaching on-disk database to in-memory database

Hi all,

I ran into a few issues while working with an in-memory database and trying to attach a on-disk database. The project I’m working on is using the Android Library, version 3.5.9.

Here is what the app is doing:

  1. Create an on-disk database with a password. The ‘cipher_page_size’ is set to 4096.
  2. Create an in-memory database without changing any settings.
  3. Attach the on-disk database to the in-memory one.
  4. I get an exception saying file is not a database.

I found out that, if I do not use a password to create the on-disk database, it works.
I also found out that, if I change the cipher page size to 1024 for the on-disk database, it works.

Questions I have:

  1. Is the exception thrown because the two databases have different page sizes?
  2. As a follow-up, does that imply the in-memory database have default page size of 1024?
  3. My understanding is that the in-memory database is not encrypted. Does that mean it does not even have cipher_page_size setting?
  4. Any steps I am missing or am doing wrong?

Thank you very much,

Hi @Endor

The project I’m working on is using the Android Library, version 3.5.9.

SQLCipher for Android uses SQLCipher core 3.4.2. The default cipher_page_size in 3.4.2 was 1024. You would need to specify the non-standard (relative to SQLCipher core 3.4.2) cipher_page_size in order to interface with that attached database. So they would both have different cipher_page_size values. An example is below:

$ ./sqlcipher :memory:sqlite
sqlite> ATTACH DATABASE 'otherdb.db' AS other KEY 'otherkey';
sqlite> PRAGMA other.cipher_page_size = 4096;
sqlite> SELECT COUNT(*) FROM other.sqlite_master;

I found out that, if I do not use a password to create the on-disk database, it works.

This is because SQLite moved to 4096 as a default page size with the release of SQLite 3.12.0, before SQLCipher migrated to using a value of 4096. If you do not key the database, the SQLCipher codec is not attached and defaults to the SQLite behavior.

Thank you very much for the much detailed answer. Appreciate it.

Hi @developernotes

If I may ask a follow-up question, is there a workaround for the case where we want to attach an existing encrypted database with a non-default page size?

And could you clarify a bit about the differences between page_size and cipher_page_size.

Thanks again,

Hello @Endor

With SQLCipher for Android you will want to utilize a SQLiteDatabaseHook when constructing your connection, specifying your non-default cipher_page_size value in the postKey event. An example can be found here. If you need to maintain a different page size between the attached database and the originating database, please see the comments below about using cipher_default_page_size instead.

SQLite uses PRAGMA page_size to determine the size of the database page written to disk, whereas SQLCipher utilizes the variable cipher_page_size for adjusting SQLCipher-encrypted database files. The documentation for the latter is available here. Additionally, SQLCipher also supports cipher_default_page_size (documented here) which allows for differing the page size for future connections that differ from the configurations set on the current connection.

Thank you again for your feedback.

I should be blamed for having you pointing out what’s clearly available on the documentation page. :man_facepalming:

Hi @Endor

No problem at all, thanks for your interest in SQLCipher!