@@ -867,5 +867,79 @@ const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx) {
867867 return ctx -> read_ctx -> provider -> get_provider_name (ctx -> read_ctx );
868868}
869869
870+ int sqlcipher_codec_ctx_migrate (codec_ctx * ctx ) {
871+ u32 meta ;
872+ int rc = 0 ;
873+ int command_idx = 0 ;
874+ sqlite3 * db = ctx -> pBt -> db ;
875+ const char * db_filename = sqlite3_db_filename (db , "main" );
876+ const char * migrated_db_filename = sqlite3_mprintf ("%s-migrated" , db_filename );
877+ const char * key = ctx -> read_ctx -> pass ;
878+ int db_idx = db -> nDb ;
879+ CODEC_TRACE (("current database count:%d\n" , db_idx ));
880+ if (db_filename ){
881+ char * attach_command = sqlite3_mprintf ("ATTACH DATABASE '%s-migrated' as migrate KEY '%s';" ,
882+ db_filename , key );
883+ const char * commands [] = {
884+ "PRAGMA kdf_iter = '4000';" ,
885+ attach_command ,
886+ "SELECT sqlcipher_export('migrate');" ,
887+ };
888+ for (command_idx = 0 ; command_idx < ArraySize (commands ); command_idx ++ ){
889+ const char * command = commands [command_idx ];
890+ rc = sqlite3_exec (db , command , NULL , NULL , NULL );
891+ if (rc != SQLITE_OK ){
892+ break ;
893+ }
894+ }
895+ sqlite3_free (attach_command );
896+ if (rc == SQLITE_OK ){
897+
898+ static const unsigned char aCopy [] = {
899+ BTREE_SCHEMA_VERSION , 1 , /* Add one to the old schema cookie */
900+ BTREE_DEFAULT_CACHE_SIZE , 0 , /* Preserve the default page cache size */
901+ BTREE_TEXT_ENCODING , 0 , /* Preserve the text encoding */
902+ BTREE_USER_VERSION , 0 , /* Preserve the user version */
903+ BTREE_APPLICATION_ID , 0 , /* Preserve the application id */
904+ };
905+
906+ CODEC_TRACE (("current database count:%d\n" , db -> nDb ));
907+ Btree * pDest = db -> aDb [0 ].pBt ;
908+ Btree * pSrc = db -> aDb [db -> nDb - 1 ].pBt ;
909+
910+ CODEC_TRACE (("pSrc is '%p'\n" , (void * )pSrc ));
911+ CODEC_TRACE (("pDest is '%p'\n" , (void * )pDest ));
912+
913+ //rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
914+ rc = sqlite3BtreeBeginTrans (pSrc , 2 );
915+ rc = sqlite3BtreeBeginTrans (pDest , 2 );
916+
917+ assert ( 1 == sqlite3BtreeIsInTrans (pDest ) );
918+ assert ( 1 == sqlite3BtreeIsInTrans (pSrc ) );
919+
920+ CODEC_TRACE (("before metadata copy\n" ));
921+ int i = 0 ;
922+ for (i = 0 ; i < ArraySize (aCopy ); i += 2 ){
923+ sqlite3BtreeGetMeta (pSrc , aCopy [i ], & meta );
924+ rc = sqlite3BtreeUpdateMeta (pDest , aCopy [i ], meta + aCopy [i + 1 ]);
925+ if ( NEVER (rc != SQLITE_OK ) ) goto handle_error ;
926+ }
927+ rc = sqlite3BtreeCopyFile (pSrc , pDest );
928+ if ( rc != SQLITE_OK ) goto handle_error ;
929+ rc = sqlite3BtreeCommit (pDest );
930+ rc = sqlite3_exec (db , "DETACH DATABASE migrate;" , NULL , NULL , NULL );
931+ remove (migrated_db_filename );
932+ }
933+ sqlite3_free (migrated_db_filename );
934+ }
935+ goto exit ;
936+
937+ handle_error :
938+ CODEC_TRACE (("An error occurred\n" ));
939+
940+ exit :
941+ return rc ;
942+ }
943+
870944#endif
871945/* END SQLCIPHER */
0 commit comments