# Troubleshooting cipher\_migrate failure using sqlite3 ruby gem

**URL:** <https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571>\
**Category:** SQLCipher\
**Created:** [September 27, 2022, 3:41pm UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571 "2022-09-27T15:41:41Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![patakijv](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/patakijv/32/1874_2.png) [@patakijv](https://discuss.zetetic.net/u/patakijv)\
**Post date:** [September 27, 2022, 3:41pm UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571/1 "2022-09-27T15:41:41Z")

</div>

**Background:**  
We have a setup that has `sqlcipher` installed and the ruby gem [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) (a wrapper around sqlite3) is built and links to `sqlcipher`.  
I am in the process of testing sqlite databases (we have many) from our current production environment (that runs an older set of sqlite3/sqlcipher) in a newer development environment. I can determine that I need to run `cipher_migrate` to continue to use the dbs in the new environment.

The ruby gem is built natively on installation with the `--with-sqlcipher` flag and I can confirm it is linked - I can use it successfully with new encrypted databases and already migrated older encrypted databases.

In a bash shell in the environment (an Ubuntu Docker container) using `sqlcipher` directly at the command line, I can successfully open the db, enter the key and run `PRAGMA cipher_migrate` and the db will be migrated and returns a value of 0.

**The problem:**  
If I open the db from within the Ruby (on Rails) console using the `sqlite3` gem that is linked to the same installation of `sqlcipher` , enter the key and run `PRAGMA cipher_migrate` it fails with a return error of 1. If I open the db after it was migrated from the command line `sqlcipher` it works as expected. I need to be able to migrate as part of the new app’s process using the ruby gem.

I suspect there is something set in the `sqlite3` gem that is causing a conflict for `sqlcipher` but I don’t know what it could be.

I enabled `cipher_log` at “trace” level and captured what is happening in each case and you can see there is a divergence in the output but I don’t know where to go from here.

**Log using `sqlcipher` directly at bash command line** (snipped because it is long):

> sqlcipher\_codec\_pragma: db=0x40001ad4d0 iDb=0 pParse=0x40019ab1d0 zLeft=cipher\_migrate zRight=(null) ctx=0x40001f2660  
> sqlcipher\_malloc: calling sqlite3Malloc(22)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x40001f3c60,0,22)  
> sqlcipher\_memset: setting 0x40001f3c60[0-22]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x40001f3000,3190); \_SC\_PAGESIZE=4096  
> sqlite3\_key: db=0x40001f3c80  
> sqlite3\_key\_v2: db=0x40001f3c80 zDb=main  
> sqlcipherCodecAttach: db=0x40001f3c80, nDb=0  
> sqlcipherCodecAttach: calling sqlcipher\_activate()  
> sqlcipher\_activate: entering static master mutex  
> sqlcipher\_activate: entered static master mutex  
> sqlcipher\_activate: leaving static master mutex  
> sqlcipher\_activate: left static master mutex  
> sqlcipherCodecAttach: entering database mutex (nil)  
> sqlcipherCodecAttach: entered database mutex (nil)  
> sqlcipherCodecAttach: calling sqlcipher\_codec\_ctx\_init()  
> sqlcipher\_codec\_ctx\_init: allocating context  
> sqlcipher\_malloc: calling sqlite3Malloc(136)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x40002038f0,0,136)  
> sqlcipher\_memset: setting 0x40002038f0[0-136]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4000203000,2424); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_init: allocating kdf\_salt  
> sqlcipher\_malloc: calling sqlite3Malloc(16)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4000203980,0,16)  
> sqlcipher\_memset: setting 0x4000203980[0-16]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4000203000,2448); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_init: allocating hmac\_kdf\_salt  
> sqlcipher\_malloc: calling sqlite3Malloc(16)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x40002039a0,0,16)  
> sqlcipher\_memset: setting 0x40002039a0[0-16]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4000203000,2480); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_init: allocating provider  
> sqlcipher\_malloc: calling sqlite3Malloc(136)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x40002039c0,0,136)  
> sqlcipher\_memset: setting 0x40002039c0[0-136]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4000203000,2632); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_init: entering SQLCIPHER\_MUTEX\_PROVIDER  
> sqlcipher\_codec\_ctx\_init: entered SQLCIPHER\_MUTEX\_PROVIDER  
> sqlcipher\_codec\_ctx\_init: leaving SQLCIPHER\_MUTEX\_PROVIDER  
> sqlcipher\_codec\_ctx\_init: left SQLCIPHER\_MUTEX\_PROVIDER  
> sqlcipher\_openssl\_activate: entering SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_activate: entered SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_activate: leaving SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_activate: left SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> …snipped…

**Log using `sqlite3` ruby gem linked to the same `sqlcipher` installation in same environment as above:**

> sqlcipher\_codec\_pragma: db=0x401e2f8830 iDb=0 pParse=0x40017ff6c0 zLeft=cipher\_migrate zRight=(null) ctx=0x4020b350b0  
> sqlcipher\_malloc: calling sqlite3Malloc(1)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4020f93630,0,1)  
> sqlcipher\_memset: setting 0x4020f93630[0-1]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4020f93000,1585); \_SC\_PAGESIZE=4096  
> sqlite3\_key: db=0x4020bc2810  
> sqlite3\_key\_v2: db=0x4020bc2810 zDb=main  
> **sqlite3\_key\_v2: no key provided**  
> sqlite3\_key: db=0x4020bc2810  
> sqlite3\_key\_v2: db=0x4020bc2810 zDb=main  
> **sqlite3\_key\_v2: no key provided**  
> sqlcipher\_free: calling sqlcipher\_memset(0x4020bc1c60,0,32)  
> sqlcipher\_memset: setting 0x4020bc1c60[0-32]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4020bc1000,3200)  
> sqlite3\_key: db=0x4020bc2810  
> sqlite3\_key\_v2: db=0x4020bc2810 zDb=main  
> **sqlite3\_key\_v2: no key provided**  
> sqlcipher\_free: calling sqlcipher\_memset(0x4020f93650,0,32)  
> sqlcipher\_memset: setting 0x4020f93650[0-32]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4020f93000,1648)  
> sqlite3\_key: db=0x4020bc2810  
> sqlite3\_key\_v2: db=0x4020bc2810 zDb=main  
> **sqlite3\_key\_v2: no key provided**  
> sqlcipher\_free: calling sqlcipher\_memset(0x4020f93680,0,32)  
> sqlcipher\_memset: setting 0x4020f93680[0-32]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4020f93000,1696)  
> **Upgrade format not determined**  
> **An error occurred attempting to migrate the database - last error 1**  
> sqlcipher\_free: calling sqlcipher\_memset(0x4020f93630,0,0)  
> sqlcipher\_memset: setting 0x4020f93630[0-0]=0)  
> sqlcipher\_codec\_pragma: error occurred during cipher\_migrate: 1  
> sqlcipher\_codec\_ctx\_set\_error: ctx=0x4020b350b0, error=1  
> sqlcipher\_codec\_pragma: db=0x401e2f8830 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x4020b350b0  
> sqlcipher\_codec\_pragma: db=0x401e2f8830 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x4020b350b0  
> 1

I’ve bolded some above statements in the log I think may be clues.

As mentioned above, the underlying `sqlcipher` installation is the same in both cases so I suspect some settings that the `sqlite3` gem has imposed are causing the issue but I don’t know what they are.

**Additional information:**

The `cipher_version` for the old installation (where the dbs were built): 3.4.2  
The `cipher_version` for the new installation: 4.5.2 community

The `cipher_settings` for the new installation (I think this is not a command in old):

> PRAGMA kdf\_iter = 256000;  
> PRAGMA cipher\_page\_size = 4096;  
> PRAGMA cipher\_use\_hmac = 1;  
> PRAGMA cipher\_plaintext\_header\_size = 0;  
> PRAGMA cipher\_hmac\_algorithm = HMAC\_SHA512;  
> PRAGMA cipher\_kdf\_algorithm = PBKDF2\_HMAC\_SHA512;

The way the new installation’s ‘sqlcipher’ is installed in the Docker image:

> RUN git clone [https://github.com/sqlcipher/sqlcipher.git](https://github.com/sqlcipher/sqlcipher.git)  
> RUN cd sqlcipher && ./configure   
> –prefix=/usr   
> –enable-tempstore=yes   
> CFLAGS=“-DSQLITE\_HAS\_CODEC”   
> LDFLAGS=“-lcrypto” &&   
> make &&   
> make install &&   
> cd /tmp

The ruby gem is built natively in the installation using the `--with-sqlcipher` flag

Testing the built file for the ruby gem using `ldd` to see that it is linked to `libsqlcipher`:

> `ldd /.../bundle/ruby/2.6.0/bundler/gems/extensions/x86_64-linux/2.6.0/sqlite3-ruby-31ea0084ced0/sqlite3/sqlite3_native.so`  
> libruby.so.2.6 =\> /usr/local/rvm/rubies/ruby-2.6.9/lib/libruby.so.2.6 (0x0000004001842000)  
> **libsqlcipher.so.0 =\> /lib/libsqlcipher.so.0 (0x0000004001bd3000)**  
> libc.so.6 =\> /lib/x86\_64-linux-gnu/libc.so.6 (0x0000004001d00000)  
> libz.so.1 =\> /lib/x86\_64-linux-gnu/libz.so.1 (0x0000004001ef2000)  
> libpthread.so.0 =\> /lib/x86\_64-linux-gnu/libpthread.so.0 (0x0000004001f0e000)  
> librt.so.1 =\> /lib/x86\_64-linux-gnu/librt.so.1 (0x0000004001f31000)  
> libdl.so.2 =\> /lib/x86\_64-linux-gnu/libdl.so.2 (0x0000004001f3e000)  
> libcrypt.so.1 =\> /lib/x86\_64-linux-gnu/libcrypt.so.1 (0x0000004001f44000)  
> libm.so.6 =\> /lib/x86\_64-linux-gnu/libm.so.6 (0x0000004001f7f000)  
> /lib64/ld-linux-x86-64.so.2 (0x0000004000000000)  
> libcrypto.so.1.1 =\> /lib/x86\_64-linux-gnu/libcrypto.so.1.1 (0x00000040020ce000)

Note: `/lib` is a symlink to `/usr/lib`

Can someone deduce from above what is happening here that suggests what is different and what sqlite3/sqlcipher settings should be changed to resolve?

What is the next step for troubleshooting this? Some more info needed?

---

<div class="post-metadata">

**Author:** ![sjlombardo](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/sjlombardo/32/3_2.png) [@sjlombardo](https://discuss.zetetic.net/u/sjlombardo)\
**Post date:** [September 27, 2022, 8:37pm UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571/2 "2022-09-27T20:37:04Z")

</div>

@patakijv - I would take a look at what the sqlite3 gem is doing after opening a connection. PRAGMA cipher\_migrate only works if it is called immediately after keying (either via PRAGMA key or sqlite3\_key). This is because it needs access prior to the database file actually being opened, and before key derivation. If the wrapper library is doing anything that would cause the database to be read or written then it could break cipher\_migrate.

If that doesn’t lead anywhere, or you can’t control the opening sequence to make cipher\_migrate work, you could consider handling the migration manually, e.g. as follows:

[SQLCipher API - Zetetic](https://www.zetetic.net/sqlcipher/sqlcipher-api/#example-3-convert-from-a-3-x-to-4-x-database)

---

<div class="post-metadata">

**Author:** ![patakijv](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/patakijv/32/1874_2.png) [@patakijv](https://discuss.zetetic.net/u/patakijv)\
**Post date:** [September 27, 2022, 11:07pm UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571/3 "2022-09-27T23:07:51Z")

</div>

@sjlombardo

Thanks for the reply.

As far as what happens after opening, it appears the gem calls sqlite3 native [open\_v2 here on initialization](https://github.com/sparklemotion/sqlite3-ruby/blob/master/lib/sqlite3/database.rb#L90) and just after that it should be ignoring a call to `disable_quirk_mode` because we are not passing in `:strict` as an option. After that it sets some variables and then checks for a block (none provided in our case) and then the method ends.

I also tried adding the `PRAGMA cipher_migrate` to the same string as the key like this `db.execute("PRAGMA key = '#{company.db_key}';PRAGMA cipher_migrate;")` so it would all be on one line to remove the chance that the gem could intervene but it doesn’t seem to change the results.

I tried the manual migration steps as you suggested, it seems to have errors along the way and then an “out of memory” exception is thrown during the `ATTACH` steps.  
See log output with some bolded areas I think may be clues because they are error releated:

executing PRAGMA cipher\_page\_size = 1024

> sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017ff6c0 zLeft=cipher\_page\_size zRight=1024 ctx=0x40378aaf90  
> sqlcipher\_free: calling sqlcipher\_memset(0x40372fc3e0,0,4096)  
> sqlcipher\_memset: setting 0x40372fc3e0[0-4096]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x40372fc000,5088)  
> sqlcipher\_malloc: calling sqlite3Malloc(1024)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x40376f8e10,0,1024)  
> sqlcipher\_memset: setting 0x40376f8e10[0-1024]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x40376f8000,4624); \_SC\_PAGESIZE=4096  
> codec\_set\_btree\_to\_codec\_pagesize: sqlite3BtreeSetPageSize() size=1024 reserve=80  
> codec\_set\_btree\_to\_codec\_pagesize: entering database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: entered database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: sqlite3BtreeSetPageSize returned 0  
> codec\_set\_btree\_to\_codec\_pagesize: leaving database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: left database mutex 0x403651a2c0  
> sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x40378aaf90  
> sqlite3Codec: pgno=1, mode=3, page\_sz=1024  
> sqlcipher\_free: calling sqlcipher\_memset((nil),0,0)  
> sqlcipher\_free: calling sqlcipher\_memset((nil),0,0)  
> sqlite3Codec: switch mode=3 offset=16  
> sqlcipher\_page\_cipher: pgno=1, mode=0, size=928  
> sqlcipher\_page\_cipher: comparing hmac on in=0x4037ced268 out=0x40376f91d0 hmac\_sz=64  
> sqlcipher\_page\_cipher: **hmac check failed for pgno=1 returning SQLITE\_ERROR**  
> sqlcipher\_memset: setting 0x40376f8e20[0-1008]=0)  
> sqlite3Codec: **error decrypting page 1 data: 1**  
> sqlcipher\_memset: setting 0x40376f8e20[0-1008]=0)  
> sqlcipher\_codec\_ctx\_set\_error: **ctx=0x40378aaf90, error=1**

executing PRAGMA kdf\_iter = 64000

> sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017ff6c0 zLeft=kdf\_iter zRight=64000 ctx=0x40378aaf90  
> sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x40378aaf90  
> sqlite3Codec: pgno=1, mode=3, page\_sz=1024  
> sqlcipher\_cipher\_ctx\_key\_derive: ctx-\>kdf\_salt\_sz=16 ctx-\>kdf\_iter=64000 ctx-\>fast\_kdf\_iter=2 ctx-\>key\_sz=32  
> cipher\_ctx\_key\_derive: **key material is not present on the context for key derivation**  
> sqlcipher\_codec\_key\_derive: **error occurred deriving read\_ctx key**  
> sqlite3Codec: **error occurred during key derivation: 1**  
> sqlcipher\_codec\_ctx\_set\_error: **ctx=0x40378aaf90, error=1**

executing PRAGMA cipher\_hmac\_algorithm = HMAC\_SHA1

> sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017ff6c0 zLeft=cipher\_hmac\_algorithm zRight=HMAC\_SHA1 ctx=0x40378aaf90  
> sqlcipher\_codec\_ctx\_reserve\_setup: base\_reserve=16 block\_sz=16 md\_size=20 reserve=48  
> codec\_set\_btree\_to\_codec\_pagesize: sqlite3BtreeSetPageSize() size=1024 reserve=48  
> codec\_set\_btree\_to\_codec\_pagesize: entering database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: entered database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: sqlite3BtreeSetPageSize returned 0  
> codec\_set\_btree\_to\_codec\_pagesize: leaving database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: left database mutex 0x403651a2c0  
> sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x40378aaf90  
> sqlite3Codec: pgno=1, mode=3, page\_sz=1024  
> sqlcipher\_cipher\_ctx\_key\_derive: ctx-\>kdf\_salt\_sz=16 ctx-\>kdf\_iter=64000 ctx-\>fast\_kdf\_iter=2 ctx-\>key\_sz=32  
> cipher\_ctx\_key\_derive: **key material is not present on the context for key derivation**  
> sqlcipher\_codec\_key\_derive: **error occurred deriving read\_ctx key**  
> sqlite3Codec: **error occurred during key derivation: 1**  
> sqlcipher\_codec\_ctx\_ **set\_error: ctx=0x40378aaf90, error=1**

executing PRAGMA cipher\_kdf\_algorithm = PBKDF2\_HMAC\_SHA1

> 2022-09-27 15:30:08.688: sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017ff6c0 zLeft=cipher\_kdf\_algorithm zRight=PBKDF2\_HMAC\_SHA1 ctx=0x40378aaf90  
> 2022-09-27 15:30:08.688: sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x40378aaf90  
> sqlite3Codec: pgno=1, mode=3, page\_sz=1024  
> sqlcipher\_cipher\_ctx\_key\_derive: ctx-\>kdf\_salt\_sz=16 ctx-\>kdf\_iter=64000 ctx-\>fast\_kdf\_iter=2 ctx-\>key\_sz=32  
> cipher\_ctx\_key\_derive: **key material is not present on the context for key derivation**  
> sqlcipher\_codec\_key\_derive: **error occurred deriving read\_ctx key**  
> sqlite3Codec: **error occurred during key derivation: 1**  
> sqlcipher\_codec\_ctx\_set\_error: **ctx=0x40378aaf90, error=1**

executing ATTACH DATABASE ‘db/companies/7/company.sqlite.sqlcipher4.sqlite’ AS sqlcipher4 KEY ‘PASSWORD’

> sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x40378aaf90  
> sqlite3Codec: pgno=1, mode=3, page\_sz=1024  
> sqlcipher\_cipher\_ctx\_key\_derive: ctx-\>kdf\_salt\_sz=16 ctx-\>kdf\_iter=64000 ctx-\>fast\_kdf\_iter=2 ctx-\>key\_sz=32  
> cipher\_ctx\_key\_derive: **key material is not present on the context for key derivation**  
> sqlcipher\_codec\_key\_derive: **error occurred deriving read\_ctx key**  
> sqlite3Codec: **error occurred during key derivation: 1**  
> sqlcipher\_codec\_ctx\_set\_error: **ctx=0x40378aaf90, error=1**  
> sqlcipherCodecAttach: db=0x4037cba340, nDb=2  
> sqlcipherCodecAttach: calling sqlcipher\_activate()  
> sqlcipher\_activate: entering static master mutex  
> sqlcipher\_activate: entered static master mutex  
> sqlcipher\_activate: leaving static master mutex  
> sqlcipher\_activate: left static master mutex  
> sqlcipherCodecAttach: entering database mutex 0x403651a2c0  
> sqlcipherCodecAttach: entered database mutex 0x403651a2c0  
> sqlcipherCodecAttach: calling sqlcipher\_codec\_ctx\_init()  
> sqlcipher\_codec\_ctx\_init: allocating context  
> sqlcipher\_malloc: calling sqlite3Malloc(136)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x403722aa10,0,136)  
> sqlcipher\_memset: setting 0x403722aa10[0-136]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x403722a000,2712); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_init: allocating kdf\_salt  
> sqlcipher\_malloc: calling sqlite3Malloc(16)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4036a4fb40,0,16)  
> sqlcipher\_memset: setting 0x4036a4fb40[0-16]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4036a4f000,2896); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_init: allocating hmac\_kdf\_salt  
> sqlcipher\_malloc: calling sqlite3Malloc(16)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4037ba7370,0,16)  
> sqlcipher\_memset: setting 0x4037ba7370[0-16]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4037ba7000,896); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_init: allocating provider  
> sqlcipher\_malloc: calling sqlite3Malloc(136)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x403722aaa0,0,136)  
> sqlcipher\_memset: setting 0x403722aaa0[0-136]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x403722a000,2856); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_init: entering SQLCIPHER\_MUTEX\_PROVIDER  
> sqlcipher\_codec\_ctx\_init: entered SQLCIPHER\_MUTEX\_PROVIDER  
> sqlcipher\_codec\_ctx\_init: leaving SQLCIPHER\_MUTEX\_PROVIDER  
> sqlcipher\_codec\_ctx\_init: left SQLCIPHER\_MUTEX\_PROVIDER  
> sqlcipher\_openssl\_activate: entering SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_activate: entered SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_activate: leaving SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_activate: left SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_free: calling sqlcipher\_memset((nil),0,0)  
> sqlcipher\_malloc: calling sqlite3Malloc(4096)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x40374c5070,0,4096)  
> sqlcipher\_memset: setting 0x40374c5070[0-4096]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x40374c5000,4208); \_SC\_PAGESIZE=4096  
> sqlcipher\_codec\_ctx\_reserve\_setup: base\_reserve=16 block\_sz=16 md\_size=64 reserve=80  
> sqlcipher\_codec\_ctx\_reserve\_setup: base\_reserve=16 block\_sz=16 md\_size=64 reserve=80  
> sqlcipher\_cipher\_ctx\_init: allocating context  
> sqlcipher\_malloc: calling sqlite3Malloc(40)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4036a4fb60,0,40)  
> sqlcipher\_memset: setting 0x4036a4fb60[0-40]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4036a4f000,2952); \_SC\_PAGESIZE=4096  
> sqlcipher\_cipher\_ctx\_init: allocating key  
> sqlcipher\_malloc: calling sqlite3Malloc(32)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4037216e00,0,32)  
> sqlcipher\_memset: setting 0x4037216e00[0-32]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4037216000,3616); \_SC\_PAGESIZE=4096  
> sqlcipher\_cipher\_ctx\_init: allocating hmac\_key  
> sqlcipher\_malloc: calling sqlite3Malloc(32)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4037ba7210,0,32)  
> sqlcipher\_memset: setting 0x4037ba7210[0-32]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4037ba7000,560); \_SC\_PAGESIZE=4096  
> sqlcipher\_cipher\_ctx\_init: allocating context  
> sqlcipher\_malloc: calling sqlite3Malloc(40)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4037ba71e0,0,40)  
> sqlcipher\_memset: setting 0x4037ba71e0[0-40]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4037ba7000,520); \_SC\_PAGESIZE=4096  
> sqlcipher\_cipher\_ctx\_init: allocating key  
> sqlcipher\_malloc: calling sqlite3Malloc(32)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x40362f4fe0,0,32)  
> sqlcipher\_memset: setting 0x40362f4fe0[0-32]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x40362f4000,4096); \_SC\_PAGESIZE=4096  
> sqlcipher\_cipher\_ctx\_init: allocating hmac\_key  
> sqlcipher\_malloc: calling sqlite3Malloc(32)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4036a4f900,0,32)  
> sqlcipher\_memset: setting 0x4036a4f900[0-32]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4036a4f000,2336); \_SC\_PAGESIZE=4096  
> sqlcipher\_free: calling sqlcipher\_memset((nil),0,0)  
> sqlcipher\_malloc: calling sqlite3Malloc(21)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4037b53ef0,0,21)  
> sqlcipher\_memset: setting 0x4037b53ef0[0-21]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4037b53000,3845); \_SC\_PAGESIZE=4096  
> sqlcipher\_cipher\_ctx\_copy: target=0x4037ba71e0, source=0x4036a4fb60  
> sqlcipher\_free: calling sqlcipher\_memset((nil),0,0)  
> sqlcipher\_free: calling sqlcipher\_memset((nil),0,99)  
> sqlcipher\_malloc: calling sqlite3Malloc(21)  
> sqlcipher\_malloc: calling sqlcipher\_memset(0x4037112a00,0,21)  
> sqlcipher\_memset: setting 0x4037112a00[0-21]=0)  
> sqlcipher\_mem\_lock: calling mlock(0x4037112000,2581); \_SC\_PAGESIZE=4096  
> sqlcipherCodecAttach: calling sqlcipherPagerSetCodec()  
> sqlcipherCodecAttach: calling codec\_set\_btree\_to\_codec\_pagesize()  
> codec\_set\_btree\_to\_codec\_pagesize: sqlite3BtreeSetPageSize() size=4096 reserve=80  
> codec\_set\_btree\_to\_codec\_pagesize: entering database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: entered database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: sqlite3BtreeSetPageSize returned 0  
> codec\_set\_btree\_to\_codec\_pagesize: leaving database mutex 0x403651a2c0  
> codec\_set\_btree\_to\_codec\_pagesize: left database mutex 0x403651a2c0  
> sqlcipherCodecAttach: calling sqlite3BtreeSecureDelete()  
> sqlcipherCodecAttach: calling sqlite3BtreeSetAutoVacuum()  
> sqlcipherCodecAttach: leaving database mutex 0x403651a2c0  
> sqlcipherCodecAttach: left database mutex 0x403651a2c0  
> sqlite3Codec: pgno=1, mode=3, page\_sz=1024  
> sqlcipher\_cipher\_ctx\_key\_derive: ctx-\>kdf\_salt\_sz=16 ctx-\>kdf\_iter=64000 ctx-\>fast\_kdf\_iter=2 ctx-\>key\_sz=32  
> cipher\_ctx\_key\_derive: **key material is not present on the context for key derivation**  
> sqlcipher\_codec\_key\_derive: **error occurred deriving read\_ctx key**  
> sqlite3Codec: **error occurred during key derivation: 1**  
> sqlcipher\_codec\_ctx\_set\_error: **ctx=0x40378aaf90, error=1**  
> codec\_ctx\_free: iCtx=0x40017fea40  
> sqlcipher\_free: calling sqlcipher\_memset(0x4036a4fb40,0,16)  
> sqlcipher\_memset: setting 0x4036a4fb40[0-16]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4036a4f000,2896)  
> sqlcipher\_free: calling sqlcipher\_memset(0x4037ba7370,0,16)  
> sqlcipher\_memset: setting 0x4037ba7370[0-16]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4037ba7000,896)  
> sqlcipher\_free: calling sqlcipher\_memset(0x40374c5070,0,4096)  
> sqlcipher\_memset: setting 0x40374c5070[0-4096]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x40374c5000,4208)  
> sqlcipher\_openssl\_deactivate: entering SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_deactivate: entered SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_deactivate: leaving SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_openssl\_deactivate: left SQLCIPHER\_MUTEX\_PROVIDER\_ACTIVATE  
> sqlcipher\_free: calling sqlcipher\_memset(0x403722aaa0,0,136)  
> sqlcipher\_memset: setting 0x403722aaa0[0-136]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x403722a000,2856)  
> cipher\_ctx\_free: iCtx=0x403722aa78  
> sqlcipher\_free: calling sqlcipher\_memset(0x4037216e00,0,32)  
> sqlcipher\_memset: setting 0x4037216e00[0-32]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4037216000,3616)  
> sqlcipher\_free: calling sqlcipher\_memset(0x4037ba7210,0,32)  
> sqlcipher\_memset: setting 0x4037ba7210[0-32]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4037ba7000,560)  
> sqlcipher\_free: calling sqlcipher\_memset(0x4037b53ef0,0,21)  
> sqlcipher\_memset: setting 0x4037b53ef0[0-21]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4037b53000,3845)  
> sqlcipher\_free: calling sqlcipher\_memset((nil),0,99)  
> sqlcipher\_free: calling sqlcipher\_memset(0x4036a4fb60,0,40)  
> sqlcipher\_memset: setting 0x4036a4fb60[0-40]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4036a4f000,2952)  
> cipher\_ctx\_free: iCtx=0x403722aa80  
> sqlcipher\_free: calling sqlcipher\_memset(0x40362f4fe0,0,32)  
> sqlcipher\_memset: setting 0x40362f4fe0[0-32]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x40362f4000,4096)  
> sqlcipher\_free: calling sqlcipher\_memset(0x4036a4f900,0,32)  
> sqlcipher\_memset: setting 0x4036a4f900[0-32]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4036a4f000,2336)  
> sqlcipher\_free: calling sqlcipher\_memset(0x4037112a00,0,21)  
> sqlcipher\_memset: setting 0x4037112a00[0-21]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4037112000,2581)  
> sqlcipher\_free: calling sqlcipher\_memset((nil),0,99)  
> sqlcipher\_free: calling sqlcipher\_memset(0x4037ba71e0,0,40)  
> sqlcipher\_memset: setting 0x4037ba71e0[0-40]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x4037ba7000,520)  
> sqlcipher\_free: calling sqlcipher\_memset(0x403722aa10,0,136)  
> sqlcipher\_memset: setting 0x403722aa10[0-136]=0)  
> sqlcipher\_mem\_unlock: calling munlock(0x403722a000,2712)  
> sqlcipher\_deactivate: entering static master mutex  
> sqlcipher\_deactivate: entered static master mutex  
> sqlcipher\_deactivate: leaving static master mutex  
> sqlcipher\_deactivate: left static master mutex  
> Traceback (most recent call last):  
> 16: from /…/bundle/ruby/2.6.0/gems/activesupport-4.2.10/lib/active\_support/dependencies.rb:274:in `block in require' 15: from /.../bundle/ruby/2.6.0/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:274:in `require’  
> 14: from /…/bundle/ruby/2.6.0/gems/railties-4.2.10/lib/rails/commands.rb:17:in `<top (required)>' 13: from /.../bundle/ruby/2.6.0/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:39:in `run\_command!’  
> 12: from /…/bundle/ruby/2.6.0/gems/railties-4.2.10/lib/rails/commands/commands\_tasks.rb:68:in `console' 11: from /.../bundle/ruby/2.6.0/gems/railties-4.2.10/lib/rails/commands/console.rb:9:in `start’  
> 10: from /…/bundle/ruby/2.6.0/gems/railties-4.2.10/lib/rails/commands/console.rb:110:in `start' 9: from (irb):7 8: from /var/www/lib/content/database/company_content.rb:75:in `forced\_sqlcipher4\_cipher\_migrate’  
> 7: from /…/bundle/ruby/2.6.0/bundler/gems/sqlite3-ruby-31ea0084ced0/lib/sqlite3/database.rb:198:in `execute' 6: from /.../bundle/ruby/2.6.0/bundler/gems/sqlite3-ruby-31ea0084ced0/lib/sqlite3/database.rb:156:in `prepare’  
> 5: from /…/bundle/ruby/2.6.0/bundler/gems/sqlite3-ruby-31ea0084ced0/lib/sqlite3/database.rb:207:in `block in execute' 4: from /.../bundle/ruby/2.6.0/bundler/gems/sqlite3-ruby-31ea0084ced0/lib/sqlite3/database.rb:207:in `to\_a’  
> 3: from /…/bundle/ruby/2.6.0/bundler/gems/sqlite3-ruby-31ea0084ced0/lib/sqlite3/resultset.rb:133:in `each' 2: from /.../bundle/ruby/2.6.0/bundler/gems/sqlite3-ruby-31ea0084ced0/lib/sqlite3/resultset.rb:108:in `next’  
> 1: from /…/bundle/ruby/2.6.0/bundler/gems/sqlite3-ruby-31ea0084ced0/lib/sqlite3/resultset.rb:108:in `step’  
> **SQLite3::MemoryException (out of memory)**

**Note** this is a small database so being out of memory for sure is not because it is an unusually large database.

---

<div class="post-metadata">

**Author:** ![patakijv](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/patakijv/32/1874_2.png) [@patakijv](https://discuss.zetetic.net/u/patakijv)\
**Post date:** [September 29, 2022, 12:24am UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571/4 "2022-09-29T00:24:00Z")

</div>

@sjlombardo Do any of those errors in my previous post for the manual migration steps jump out as being an obvious reason for what might be happening when using the gem linked to sqlcipher and what settings/similar might need to be adjusted so it works?

---

<div class="post-metadata">

**Author:** ![patakijv](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/patakijv/32/1874_2.png) [@patakijv](https://discuss.zetetic.net/u/patakijv)\
**Post date:** [September 29, 2022, 1:07am UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571/5 "2022-09-29T01:07:00Z")

</div>

Well I would l really be interested to hear suggestions for what to try differently to get the `sqlite3 gem` to perform the **cipher\_migrate** or **manual migration** steps to work. If someone does have ideas of things to try, I would be up for testing suggestions. It seems like it is some combination of settings or something that need to be messed with so it works as expected.

In the meantime, I have a workaround of just interacting with `sqlcipher` at the system level from ruby to perform the migration as follows:

```ruby
system("sqlcipher","#{db_file_path}","PRAGMA key='#{db_key}';PRAGMA cipher_migrate;")

```

**For those further interested** in a ruby setup for this, here is a simple sample class for all of the steps together to open, test, migrate if test fails (using system sqlcipher command), etc.

```ruby
require 'sqlite3'
class EncryptedContent
    
    attr_accessor :db, :db_key, :db_file_path

    def initialize(db_key,file_path)
        self.db_key = db_key
        self.db_file_path = file_path
        open_db
    end

    # use sqlcipher system command to cipher migrate the db
    def cipher_migrate_using_system_sqlcipher
        system("sqlcipher","#{db_file_path}","PRAGMA key='#{db_key}';PRAGMA cipher_migrate;")
    end

    # test the db connection by running a simple query
    def test_db_connection
        result = db.execute("SELECT count(*) FROM sqlite_master;") rescue nil
        result.present?
    end

    # set the db key
    def set_db_key
        db.execute("PRAGMA key='#{db_key}';")
    end

    # open the db connection
    def open_db
        self.db = SQLite3::Database.new db_file_path
        set_db_key
        unless test_db_connection
            db.close
            cipher_migrate_using_system_sqlcipher
            self.db = SQLite3::Database.new db_file_path
            set_db_key
        end
    end

end

```

**Note:** the above works with `sqlite3` v1.5.0 ruby gem and `sqlcipher` 4.5.2. installed.

**Further lessons learned here:**

To hopefully save someone else some time I lost (and hair pulling), since v1.5.0 of the gem there are now precompiled versions loaded into `RubyGems` which will be selected when you `bundle` by default. This means there is no native build step anymore by default so you won’t be able to link it to `sqlcipher` unless you override this. So, if you plan to use the gem with `sqlcipher` you must install the gem specifically for the `ruby` platform vs one of the many precompiled platform specific versions. This is [documented here](https://github.com/sparklemotion/sqlite3-ruby#avoiding-the-precompiled-native-gem)

In our case we are using `bundler` v1.17.3 and those instructions say for v2.0 or older to use `bundle config force_ruby_platform true` meaning that ALL of your gems that have native build options will be forced to be built which is not what we wanted because we have over a dozen gems that we prefer to use the precompiled versions when available (saves time and pain of fixing dependency issues). And using `platform: :ruby` in the `Gemfile` was not enough to tell `bundler` with `RubyGems` to do what we wanted.

The solution we found was to tell `bundler` (at least on the older version we are using) to use `git` and `Github` as the source (as opposed to `RubyGems`) and then finally it would build natively:

in `Gemfile`

```ruby
gem 'sqlite3', '1.5.0', platforms: :ruby, git: 'https://github.com/sparklemotion/sqlite3-ruby.git', tag: 'v1.5.0'

```

and don’t forget to tell `bundler` to build the gem with `--with-sqlicpher`

```bash
bundle config --local build.sqlite3 '--with-sqlcipher'

```

You also need to be mindful of where the `sqlcipher` library flles get installed and if in a non-standard location you need to add those to the build config. This is [documented here](https://github.com/sparklemotion/sqlite3-ruby#system-libsqlcipher).

In our case for installation of `sqlcipher` was as identified with a prefix of `/usr` in the original post, so apparently it is standard since we didn’t use the other build config options.

---

<div class="post-metadata">

**Author:** ![sjlombardo](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/sjlombardo/32/3_2.png) [@sjlombardo](https://discuss.zetetic.net/u/sjlombardo)\
**Post date:** [September 29, 2022, 5:36pm UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571/6 "2022-09-29T17:36:46Z")

</div>

Hello @patakijv - I have reviewed the logs and I suspect the problem is that something is manipulating the file encoding, e.g.

> sqlcipher\_codec\_pragma: db=0x4037cba340 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x40378aaf90  
> sqlite3Codec: pgno=1, mode=3, page\_sz=1024

Encoding updates would trigger access to the database, causing key derivation to run. I haven’t poured through the code, but it does seem like there is a fair bit of code managing encoding in the library, even in the native .c files. This makes me wonder whether there is something forcing encoding during the execution of a statement. Do you have any insight on that?

---

<div class="post-metadata">

**Author:** ![patakijv](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/patakijv/32/1874_2.png) [@patakijv](https://discuss.zetetic.net/u/patakijv)\
**Post date:** [September 29, 2022, 10:47pm UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571/7 "2022-09-29T22:47:19Z")

</div>

@sjlombardo

> [@sjlombardo](#):
>
> This makes me wonder whether there is something forcing encoding during the execution of a statement. Do you have any insight on that?

Hmm… I don’t necessarily have insight… but I am willing to help dig around … if by encoding, if you look at [this line of the initialization method](https://github.com/sparklemotion/sqlite3-ruby/blob/master/lib/sqlite3/database.rb#L90) where it calls the underlying `sqlite3` `open_v2` method, I see it shows `file.encode("utf-8")` as the first argument. Is this what you mean by encoding? I thought that was just encoding the file path string, not the file contents. What do you think?

The first argument into the method is a string and the `encode` method is for strings.

```auto
irb(main):001:0> file="/some/path/to/db.sqlite"
=> "/some/path/to/db.sqlite"
irb(main):002:0> file.encode("utf-8")
=> "/some/path/to/db.sqlite"

```

Maybe you are not referring to this reference to `encoding`.

According to documentation on [sqlite3 open](https://www.sqlite.org/c3ref/open.html)

> The default encoding will be UTF-8 for databases created using sqlite3\_open() or sqlite3\_open\_v2(). The default encoding for databases created using sqlite3\_open16() will be UTF-16 in the native byte order.

Are you suspecting that the encoding should be different than UTF-8?

---

<div class="post-metadata">

**Author:** ![sjlombardo](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/sjlombardo/32/3_2.png) [@sjlombardo](https://discuss.zetetic.net/u/sjlombardo)\
**Post date:** [September 30, 2022, 2:36pm UTC](https://discuss.zetetic.net/t/troubleshooting-cipher-migrate-failure-using-sqlite3-ruby-gem/5571/8 "2022-09-30T14:36:42Z")

</div>

Hello @patakijv - I agree that the `file.encode` is just dealing with the file name. The encoding I’m referring to is the database encoding, i.e. [PRAGMA encoding](https://www.sqlite.org/pragma.html#pragma_encoding). You can see from the logs in several places a line like this:

```auto
sqlcipher_codec_pragma: db=0x4037cba340 iDb=0 pParse=0x40017fef90 zLeft=encoding zRight=(null) ctx=0x40378aaf90

```

This line indicates that `PRAGMA encoding` is being invoked. Since encoding settings are stored in the [database header](https://www.sqlite.org/fileformat.html) SQLCipher will read the first page invoking key derivation and making migration or setting changes impossible.

Looking closer at the code, I believe the library is be checking the database encoding when stepping in order to handle conversions in [statement.c](https://github.com/sparklemotion/sqlite3-ruby/blob/194493be44cd41b73e612eed69ba49354f0d32e7/ext/sqlite3/statement.c#L121). That check is in turn invoking `PRAGMA encoding` on the database handle in [database.c](https://github.com/sparklemotion/sqlite3-ruby/blob/e27f9b0fff1d2cc6af352758fca9b5466835617c/ext/sqlite3/database.c#L670).

That being the case, one possible workaround would be to invoke `PRAGMA cipher_migrate` using `db.execute_batch2` function instead of `db.execute`. [execute\_batch2](https://github.com/sparklemotion/sqlite3-ruby/blob/a5d9a90a497d253b8105e8d7d4017aa5fb2e90d9/lib/sqlite3/database.rb#L303) appears to avoid using the prepare / step interface and instead passes the SQL statements directly to [`sqlite3_exec`](https://github.com/sparklemotion/sqlite3-ruby/blob/e27f9b0fff1d2cc6af352758fca9b5466835617c/ext/sqlite3/database.c#L735) without any encoding checks.
