From 243b21cbaa3d360fbdfb91ea3e18398125129167 Mon Sep 17 00:00:00 2001
From: MartinChoo <214582617@qq.com>
Date: Wed, 23 Jul 2025 17:38:02 +0800
Subject: [PATCH 01/12] History features of sqlite

---
 src/sqlite3.c | 2451 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 2438 insertions(+), 13 deletions(-)

diff --git a/src/sqlite3.c b/src/sqlite3.c
index 7fb290f..ad78006 100644
--- a/src/sqlite3.c
+++ b/src/sqlite3.c
@@ -2915,6 +2915,11 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
 */
 SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
 
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+#define SQLITE_DBCONFIG_SET_SHAREDBLOCK  2004
+#define SQLITE_DBCONFIG_USE_SHAREDBLOCK  2005
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
+
 /*
 ** CAPI3REF: Set the Last Insert Rowid value.
 ** METHOD: sqlite3
@@ -3274,6 +3279,16 @@ SQLITE_API int sqlite3_get_table(
 );
 SQLITE_API void sqlite3_free_table(char **result);
 
+// export the symbols
+#ifdef SQLITE_EXPORT_SYMBOLS
+#if defined(__GNUC__)
+#  define EXPORT_SYMBOLS  __attribute__ ((visibility ("default")))
+#elif defined(_MSC_VER)
+#  define EXPORT_SYMBOLS  __declspec(dllexport)
+#else
+#  define EXPORT_SYMBOLS
+#endif
+#endif
 /*
 ** CAPI3REF: Formatted String Printing Functions
 **
@@ -5312,6 +5327,10 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
 */
 SQLITE_API int sqlite3_step(sqlite3_stmt*);
 
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+SQLITE_API int sqlite3_set_droptable_handle(sqlite3*, void (*xFunc)(sqlite3*,const char*,const char*));
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
+
 /*
 ** CAPI3REF: Number of columns in a result set
 ** METHOD: sqlite3_stmt
@@ -6712,6 +6731,44 @@ SQLITE_API int sqlite3_collation_needed16(
   void(*)(void*,sqlite3*,int eTextRep,const void*)
 );
 
+#ifdef SQLITE_HAS_CODEC
+/*
+** Specify the key for an encrypted database.  This routine should be
+** called right after sqlite3_open().
+**
+** The code to implement this API is not available in the public release
+** of SQLite.
+*/
+SQLITE_API int sqlite3_key(
+  sqlite3 *db,                   /* Database to be rekeyed */
+  const void *pKey, int nKey     /* The key */
+);
+SQLITE_API int sqlite3_key_v2(
+  sqlite3 *db,                   /* Database to be rekeyed */
+  const char *zDbName,           /* Name of the database */
+  const void *pKey, int nKey     /* The key */
+);
+
+/*
+** Change the key on an open database.  If the current database is not
+** encrypted, this routine will encrypt it.  If pNew==0 or nNew==0, the
+** database is decrypted.
+**
+** The code to implement this API is not available in the public release
+** of SQLite.
+*/
+SQLITE_API int sqlite3_rekey(
+  sqlite3 *db,                   /* Database to be rekeyed */
+  const void *pKey, int nKey     /* The new key */
+);
+SQLITE_API int sqlite3_rekey_v2(
+  sqlite3 *db,                   /* Database to be rekeyed */
+  const char *zDbName,           /* Name of the database */
+  const void *pKey, int nKey     /* The new key */
+);
+
+#endif /* SQLITE_HAS_CODEC */
+
 #ifdef SQLITE_ENABLE_CEROD
 /*
 ** Specify the activation key for a CEROD database.  Unless
@@ -10149,6 +10206,27 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
 */
 SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
 
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+typedef struct Sqlite3SharedBlockMethods Sqlite3SharedBlockMethods;
+struct Sqlite3SharedBlockMethods {
+  int iVersion;
+  void* pContext;
+  int countAllRows;
+  int startPos;
+  int requiredPos;
+  int (*xAddRow)(void* pCtx, int addedRows);
+  int (*xReset)(void* pCtx, int startPos);
+  int (*xFinish)(void* pCtx, int addedRows, int totalRows);
+  int (*xPutString)(void *pCtx, int addedRows, int column, const char* text, int len);
+  int (*xPutLong)(void *pCtx, int addedRows, int column, sqlite3_int64 value);
+  int (*xPutDouble)(void *pCtx, int addedRows, int column, double value);
+  int (*xPutBlob)(void *pCtx, int addedRows, int column, const void* blob, int len);
+  int (*xPutNull)(void *pCtx, int addedRows, int column);
+  int (*xPutOther)(void *pCtx, int addedRows, int column);
+  /* Additional methods may be added in future releases */
+};
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
+
 /*
 ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
 **
@@ -15771,6 +15849,9 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
 /* Functions used to configure a Pager object. */
 SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
 SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
+#ifdef SQLITE_HAS_CODEC
+SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*, Pager*);
+#endif /* SQLITE_HAS_CODEC */
 SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
 SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
 SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
@@ -15867,6 +15948,10 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
 
 SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
 
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
+#endif /* defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) */
+
 /* Functions to support testing and debugging. */
 #if !defined(NDEBUG) || defined(SQLITE_TEST)
 SQLITE_PRIVATE   Pgno sqlite3PagerPagenumber(DbPage*);
@@ -17497,6 +17582,21 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
 */
 #define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2)
 
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+typedef void (*sqlite3_xDropTableHandle)(sqlite3*, const char*, const char*);
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
+
+#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED)
+typedef struct CodecParameter {
+  int kdfIter;
+  int pageSize;
+  u8 cipher;
+  u8 hmacAlgo;
+  u8 kdfAlgo;
+  u8 reserved;
+} CodecParameter;
+#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */
+
 /*
 ** Each database connection is an instance of the following structure.
 */
@@ -17641,6 +17741,15 @@ struct sqlite3 {
 #ifdef SQLITE_USER_AUTHENTICATION
   sqlite3_userauth auth;        /* User authentication information */
 #endif
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+  unsigned int isDropTable;
+  char *mDropTableName;
+  char *mDropSchemaName;
+  sqlite3_xDropTableHandle xDropTableHandle;        /* User drop table callback */
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
+#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED)
+  CodecParameter codecParm;
+#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */
 };
 
 /*
@@ -20733,7 +20842,14 @@ SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*);
 SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*);
 SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
                     sqlite3_vfs**,char**,char **);
-#define sqlite3CodecQueryParameters(A,B,C) 0
+#ifdef SQLITE_HAS_CODEC
+SQLITE_PRIVATE   int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*);
+#else
+# define sqlite3CodecQueryParameters(A,B,C) 0
+#endif /* SQLITE_HAS_CODEC */
+#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED)
+SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p);
+#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */
 SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
 
 #ifdef SQLITE_UNTESTABLE
@@ -22095,6 +22211,9 @@ static const char * const sqlite3azCompileOpt[] = {
 #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID
   "FTS5_NO_WITHOUT_ROWID",
 #endif
+#if SQLITE_HAS_CODEC
+  "HAS_CODEC",
+#endif
 #if HAVE_ISNAN || SQLITE_HAVE_ISNAN
   "HAVE_ISNAN",
 #endif
@@ -22103,6 +22222,9 @@ static const char * const sqlite3azCompileOpt[] = {
   "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX),
 # endif
 #endif
+#if SQLITE_SHARED_BLOCK_OPTIMIZATION
+ "SHARED_BLOCK_OPTIMIZATION",
+#endif
 #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
   "IGNORE_AFP_LOCK_ERRORS",
 #endif
@@ -22678,9 +22800,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
 ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
 ** disabled. The default value may be changed by compiling with the
 ** SQLITE_USE_URI symbol defined.
+**
+** URI filenames are enabled by default if SQLITE_HAS_CODEC is
+** enabled.
 */
 #ifndef SQLITE_USE_URI
-# define SQLITE_USE_URI 0
+# ifdef SQLITE_HAS_CODEC
+#  define SQLITE_USE_URI 1
+# else
+#  define SQLITE_USE_URI 0
+# endif /* SQLITE_HAS_CODEC */
 #endif
 
 /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
@@ -23449,6 +23578,13 @@ struct Vdbe {
   int nScan;              /* Entries in aScan[] */
   ScanStatus *aScan;      /* Scan definitions for sqlite3_stmt_scanstatus() */
 #endif
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+  Sqlite3SharedBlockMethods *pSharedBlock;
+  int totalRows;
+  int blockFull;
+  int startPos;
+  int addedRows;
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
 };
 
 /*
@@ -35960,7 +36096,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){
   return (u8)(h & 0xf);
 }
 
-#if !defined(SQLITE_OMIT_BLOB_LITERAL)
+#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
 /*
 ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
 ** value.  Return a pointer to its binary value.  Space to hold the
@@ -35981,7 +36117,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
   }
   return zBlob;
 }
-#endif /* !SQLITE_OMIT_BLOB_LITERAL */
+#endif /* !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) */
 
 /*
 ** Log an error that is an API call on a connection pointer that should
@@ -56898,6 +57034,20 @@ int sqlite3PagerTrace=1;  /* True to enable tracing */
 */
 #define UNKNOWN_LOCK                (EXCLUSIVE_LOCK+1)
 
+#ifdef SQLITE_HAS_CODEC
+/*
+** A macro used for invoking the codec if there is one
+*/
+# define CODEC1(P,D,N,X,E) \
+    if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; }
+# define CODEC2(P,D,N,X,E,O) \
+    if( P->xCodec==0 ){ O=(char*)D; }else \
+    if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; }
+#else
+# define CODEC1(P,D,N,X,E)   /* NO-OP */
+# define CODEC2(P,D,N,X,E,O) O=(char*)D
+#endif /* SQLITE_HAS_CODEC */
+
 /*
 ** The maximum allowed sector size. 64KiB. If the xSectorsize() method
 ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
@@ -57186,6 +57336,12 @@ struct Pager {
 #endif
   void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
   int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
+#ifdef SQLITE_HAS_CODEC
+  void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
+  void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
+  void (*xCodecFree)(void*);             /* Destructor for the codec */
+  void *pCodec;               /* First argument to xCodec... methods */
+#endif /* SQLITE_HAS_CODEC */
   char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */
   PCache *pPCache;            /* Pointer to page cache object */
 #ifndef SQLITE_OMIT_WAL
@@ -57307,6 +57463,9 @@ static const unsigned char aJournalMagic[] = {
 SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
   if( pPager->fd->pMethods==0 ) return 0;
   if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
+#ifdef SQLITE_HAS_CODEC
+  if( pPager->xCodec!=0 ) return 0;
+#endif /* SQLITE_HAS_CODEC */
 #ifndef SQLITE_OMIT_WAL
   if( pPager->pWal ){
     u32 iRead = 0;
@@ -57540,7 +57699,11 @@ static void setGetterMethod(Pager *pPager){
   if( pPager->errCode ){
     pPager->xGet = getPageError;
 #if SQLITE_MAX_MMAP_SIZE>0
-  }else if( USEFETCH(pPager) ){
+  }else if( USEFETCH(pPager)
+#ifdef SQLITE_HAS_CODEC
+   && pPager->xCodec==0
+#endif /* SQLITE_HAS_CODEC */
+  ){
     pPager->xGet = getPageMMap;
 #endif /* SQLITE_MAX_MMAP_SIZE>0 */
   }else{
@@ -58732,6 +58895,32 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
   return cksum;
 }
 
+#ifdef SQLITE_HAS_CODEC
+/*
+** Report the current page size and number of reserved bytes back
+** to the codec.
+*/
+static void pagerReportSize(Pager *pPager){
+  if( pPager->xCodecSizeChng ){
+    pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
+                           (int)pPager->nReserve);
+  }
+}
+/*
+** Make sure the number of reserved bits is the same in the destination
+** pager as it is in the source.  This comes up when a VACUUM changes the
+** number of reserved bits to the "optimal" amount.
+*/
+SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
+  if( pDest->nReserve!=pSrc->nReserve ){
+    pDest->nReserve = pSrc->nReserve;
+    pagerReportSize(pDest);
+  }
+}
+#else
+# define pagerReportSize(X)     /* No-op if we do not support a codec */
+#endif
+
 /*
 ** Read a single page from either the journal file (if isMainJrnl==1) or
 ** from the sub-journal (if isMainJrnl==0) and playback that page.
@@ -58783,6 +58972,11 @@ static int pager_playback_one_page(
   char *aData;                  /* Temporary storage for the page */
   sqlite3_file *jfd;            /* The file descriptor for the journal file */
   int isSynced;                 /* True if journal page is synced */
+#ifdef SQLITE_HAS_CODEC
+  /* The jrnlEnc flag is true if Journal pages should be passed through
+  ** the codec.  It is false for pure in-memory journals. */
+  const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
+#endif /* SQLITE_HAS_CODEC */
 
   assert( (isMainJrnl&~1)==0 );      /* isMainJrnl is 0 or 1 */
   assert( (isSavepnt&~1)==0 );       /* isSavepnt is 0 or 1 */
@@ -58912,12 +59106,30 @@ static int pager_playback_one_page(
     ** is if the data was just read from an in-memory sub-journal. In that
     ** case it must be encrypted here before it is copied into the database
     ** file.  */
+#ifdef SQLITE_HAS_CODEC
+    if( !jrnlEnc ){
+      CODEC2(pPager, aData, pgno, 7, rc=pPager->errCode, aData);
+      if (rc == SQLITE_OK) {
+        rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
+        CODEC1(pPager, aData, pgno, 3, rc=pPager->errCode);
+      }
+    }else
+#endif /* SQLITE_HAS_CODEC */
     rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
 
     if( pgno>pPager->dbFileSize ){
       pPager->dbFileSize = pgno;
     }
     if( pPager->pBackup ){
+#ifdef SQLITE_HAS_CODEC
+      if( jrnlEnc ){
+        CODEC1(pPager, aData, pgno, 3, rc=pPager->errCode);
+        if (rc == SQLITE_OK) {
+          sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
+          CODEC2(pPager, aData, pgno, 7, rc=pPager->errCode, aData);
+        }
+      }else
+#endif /* SQLITE_HAS_CODEC */
       sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
     }
   }else if( !isMainJrnl && pPg==0 ){
@@ -58968,6 +59180,10 @@ static int pager_playback_one_page(
     if( pgno==1 ){
       memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
     }
+#if SQLITE_HAS_CODEC
+    /* Decode the page just read from disk */
+    if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=pPager->errCode); }
+#endif /* SQLITE_HAS_CODEC */
     sqlite3PcacheRelease(pPg);
   }
   return rc;
@@ -59511,7 +59727,7 @@ static int readDbPage(PgHdr *pPg){
   assert( isOpen(pPager->fd) );
 
   if( pagerUseWal(pPager) ){
-    rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
+    rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);  // find in wal-index
     if( rc ) return rc;
   }
   if( iFrame ){
@@ -59546,6 +59762,8 @@ static int readDbPage(PgHdr *pPg){
       memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
     }
   }
+  CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = pPager->errCode);
+
   PAGER_INCR(sqlite3_pager_readdb_count);
   PAGER_INCR(pPager->nRead);
   IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
@@ -60691,6 +60909,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
   sqlite3OsClose(pPager->fd);
   sqlite3PageFree(pTmp);
   sqlite3PcacheClose(pPager->pPCache);
+#ifdef SQLITE_HAS_CODEC
+  if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
+#endif /* SQLITE_HAS_CODEC */
+
   assert( !pPager->aSavepoint && !pPager->pInJournal );
   assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );
 
@@ -60941,7 +61163,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
       assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
       if( pList->pgno==1 ) pager_write_changecounter(pList);
 
-      pData = pList->pData;
+      CODEC2(pPager, pList->pData, pgno, 6, return pPager->errCode, pData);
 
       /* Write out the page data. */
       rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
@@ -61030,6 +61252,11 @@ static int subjournalPage(PgHdr *pPg){
       void *pData = pPg->pData;
       i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
       char *pData2;
+#if SQLITE_HAS_CODEC
+      if( !pPager->subjInMemory ){
+        CODEC2(pPager, pData, pPg->pgno, 7, return pPager->errCode, pData2);
+      }else
+#endif /* SQLITE_HAS_CODEC */
       pData2 = pData;
       PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
       rc = write32bits(pPager->sjfd, offset, pPg->pgno);
@@ -62122,6 +62349,9 @@ static int getPageMMap(
   );
 
   assert( USEFETCH(pPager) );
+#ifdef SQLITE_HAS_CODEC
+  assert( pPager->xCodec==0 );
+#endif /* SQLITE_HAS_CODEC */
 
   /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
   ** allows the compiler optimizer to reuse the results of the "pgno>1"
@@ -62466,7 +62696,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
   assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) );
 
   assert( pPager->journalHdr<=pPager->journalOff );
-  pData2 = pPg->pData;
+  CODEC2(pPager, pPg->pData, pPg->pgno, 7, return pPager->errCode, pData2);
   cksum = pager_cksum(pPager, (u8*)pData2);
 
   /* Even if an IO or diskfull error occurs while journalling the
@@ -62831,7 +63061,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
       if( DIRECT_MODE ){
         const void *zBuf;
         assert( pPager->dbFileSize>0 );
-        zBuf = pPgHdr->pData;
+        CODEC2(pPager, pPgHdr->pData, 1, 6, rc=pPager->errCode, zBuf);
         if( rc==SQLITE_OK ){
           rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
           pPager->aStat[PAGER_STAT_WRITE]++;
@@ -63594,6 +63824,48 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
   return pPager->zJournal;
 }
 
+#ifdef SQLITE_HAS_CODEC
+/*
+** Set or retrieve the codec for this pager
+*/
+SQLITE_PRIVATE void sqlite3PagerSetCodec(
+  Pager *pPager,
+  void *(*xCodec)(void*,void*,Pgno,int),
+  void (*xCodecSizeChng)(void*,int,int),
+  void (*xCodecFree)(void*),
+  void *pCodec
+){
+  if( pPager->xCodecFree ){
+    pPager->xCodecFree(pPager->pCodec);
+  }else{
+    pager_reset(pPager);
+  }
+  pPager->xCodec = pPager->memDb ? 0 : xCodec;
+  pPager->xCodecSizeChng = xCodecSizeChng;
+  pPager->xCodecFree = xCodecFree;
+  pPager->pCodec = pCodec;
+  setGetterMethod(pPager);
+  pagerReportSize(pPager);
+}
+SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
+  return pPager->pCodec;
+}
+
+/*
+** This function is called by the wal module when writing page content
+** into the log file.
+**
+** This function returns a pointer to a buffer containing the encrypted
+** page content. If a malloc fails, this function may return NULL.
+*/
+SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
+  void *aData = 0;
+  CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
+  return aData;
+}
+
+#endif /* SQLITE_HAS_CODEC */
+
 #ifndef SQLITE_OMIT_AUTOVACUUM
 /*
 ** Move the page pPg to location pgno in the file.
@@ -68144,7 +68416,11 @@ static int walWriteOneFrame(
   int rc;                         /* Result code from subfunctions */
   void *pData;                    /* Data actually written */
   u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */
+#ifdef SQLITE_HAS_CODEC
+  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
+#else
   pData = pPage->pData;
+#endif /* SQLITE_HAS_CODEC */
   walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
   rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
   if( rc ) return rc;
@@ -68329,7 +68605,11 @@ static int walFrames(
         if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
           pWal->iReCksum = iWrite;
         }
+#ifdef SQLITE_HAS_CODEC
+        if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
+#else
         pData = p->pData;
+#endif /* SQLITE_HAS_CODEC */
         rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
         if( rc ) return rc;
         p->flags &= ~PGHDR_WAL_APPEND;
@@ -81473,6 +81753,13 @@ static int backupOnePage(
   int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
   const int nCopy = MIN(nSrcPgsz, nDestPgsz);
   const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
+#ifdef SQLITE_HAS_CODEC
+  /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is
+  ** guaranteed that the shared-mutex is held by this thread, handle
+  ** p->pSrc may not actually be the owner.  */
+  int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
+  int nDestReserve = sqlite3BtreeGetRequestedReserve(p->pDest);
+#endif /* SQLITE_HAS_CODEC */
   int rc = SQLITE_OK;
   i64 iOff;
 
@@ -81483,6 +81770,26 @@ static int backupOnePage(
   assert( zSrcData );
   assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 );
 
+#ifdef SQLITE_HAS_CODEC
+  /* Backup is not possible if the page size of the destination is changing
+  ** and a codec is in use.
+  */
+  if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){
+    rc = SQLITE_READONLY;
+  }
+
+  /* Backup is not possible if the number of bytes of reserve space differ
+  ** between source and destination.  If there is a difference, try to
+  ** fix the destination to agree with the source.  If that is not possible,
+  ** then the backup cannot proceed.
+  */
+  if( nSrcReserve!=nDestReserve ){
+    u32 newPgsz = nSrcPgsz;
+    rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve);
+    if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY;
+  }
+#endif /* SQLITE_HAS_CODEC */
+
   /* This loop runs once for each destination page spanned by the source
   ** page. For each iteration, variable iOff is set to the byte offset
   ** of the destination page.
@@ -81981,6 +82288,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
   b.pDest = pTo;
   b.iNext = 1;
 
+#ifdef SQLITE_HAS_CODEC
+  sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom));
+#endif /* SQLITE_HAS_CODEC */
+
   /* 0x7FFFFFFF is the hard limit for the number of pages in a database
   ** file. By passing this as the number of pages to copy to
   ** sqlite3_backup_step(), we can guarantee that the copy finishes
@@ -90447,6 +90758,15 @@ end_of_step:
   return (rc&db->errMask);
 }
 
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+SQLITE_API int sqlite3_set_droptable_handle(sqlite3 *db, void (*xFunc)(sqlite3*, const char*, const char*)){
+  sqlite3_mutex_enter(db->mutex);
+  db->xDropTableHandle = xFunc;
+  sqlite3_mutex_leave(db->mutex);
+  return 0;
+}
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
+
 /*
 ** This is the top-level implementation of sqlite3_step().  Call
 ** sqlite3Step() to do most of the work.  If a schema error occurs,
@@ -90466,6 +90786,13 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
   while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
          && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
     int savedPc = v->pc;
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+    Sqlite3SharedBlockMethods *pSharedBlock = v->pSharedBlock;
+    int totalRows = v->totalRows;
+    int blockFull = v->blockFull;
+    int startPos = v->startPos;
+    int addedRows = v->addedRows;
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
     rc = sqlite3Reprepare(v);
     if( rc!=SQLITE_OK ){
       /* This case occurs after failing to recompile an sql statement.
@@ -90487,6 +90814,15 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
       }
       break;
     }
+
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+    v->pSharedBlock = pSharedBlock;
+    v->totalRows = totalRows;
+    v->blockFull = blockFull;
+    v->startPos = startPos;
+    v->addedRows = addedRows;
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
+
     sqlite3_reset(pStmt);
     if( savedPc>=0 ){
       /* Setting minWriteFileFormat to 254 is a signal to the OP_Init and
@@ -90497,6 +90833,20 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
     }
     assert( v->expired==0 );
   }
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+  if( rc==SQLITE_DONE && db->xDropTableHandle!=NULL && db->isDropTable==1 ){
+    db->isDropTable = 0;
+    db->xDropTableHandle(db, db->mDropTableName, db->mDropSchemaName);
+  }
+  if( db->mDropTableName!=NULL ){
+    sqlite3_free(db->mDropTableName);
+    db->mDropTableName = NULL;
+  }
+  if( db->mDropSchemaName!=NULL ){
+    sqlite3_free(db->mDropSchemaName);
+    db->mDropSchemaName = NULL;
+  }
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
   sqlite3_mutex_leave(db->mutex);
   return rc;
 }
@@ -92944,6 +93294,61 @@ static int checkSavepointCount(sqlite3 *db){
 }
 #endif
 
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+static int copySharedBlockRow(
+  Vdbe *p,                    /* The VDBE */
+  Op *pOp,                    /* Current operation */
+  Mem *pMem,
+  void *pCtx
+){
+  int i = 0;
+
+  int rc = p->pSharedBlock->xAddRow(pCtx, p->addedRows);
+  if( rc!=SQLITE_OK ){
+    return rc;
+  }
+
+  for(i=0; i<pOp->p2; i++){
+    switch (sqlite3_value_type(&pMem[i])) {
+      case SQLITE_INTEGER:{
+        rc = p->pSharedBlock->xPutLong(pCtx, p->addedRows, i, (sqlite3_int64)pMem[i].u.i);
+        break;
+      }
+      case SQLITE_FLOAT: {
+        rc = p->pSharedBlock->xPutDouble(pCtx, p->addedRows, i, pMem[i].u.r);
+        break;
+      }
+      case SQLITE_TEXT: {
+        Deephemeralize(&pMem[i]);
+        sqlite3VdbeMemNulTerminate(&pMem[i]);
+        sqlite3VdbeChangeEncoding(&pMem[i],SQLITE_UTF8);
+        rc = p->pSharedBlock->xPutString(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n+1);
+        break;
+      }
+      case SQLITE_BLOB: {
+        rc = p->pSharedBlock->xPutBlob(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n);
+        break;
+      }
+      case SQLITE_NULL: {
+        rc = p->pSharedBlock->xPutNull(pCtx, p->addedRows, i);
+        break;
+      }
+      default:
+        rc = p->pSharedBlock->xPutOther(pCtx, p->addedRows, i);
+        break;
+    }
+    if( rc!=SQLITE_OK ){
+        return rc;
+    }
+  }
+
+  return rc;
+no_mem:
+  rc = SQLITE_NOMEM;
+  return rc;
+}
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
+
 /*
 ** Return the register of pOp->p2 after first preparing it to be
 ** overwritten with an integer value.
@@ -93542,6 +93947,12 @@ case OP_Halt: {
   VdbeFrame *pFrame;
   int pcx;
 
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+  if( p->pSharedBlock!=NULL ){
+    p->pSharedBlock->xFinish(p->pSharedBlock->pContext, p->addedRows, p->totalRows);
+  }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
+
 #ifdef SQLITE_DEBUG
   if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
 #endif
@@ -93991,6 +94402,43 @@ case OP_ResultRow: {
   assert( pOp->p1>0 || CORRUPT_DB );
   assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
 
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+  if( p->pSharedBlock!=NULL ){
+    void *pCtx = p->pSharedBlock->pContext;
+    p->totalRows++;
+    if( p->totalRows<=p->startPos || p->blockFull ){
+      break;
+    }
+    Mem *pMem = &aMem[pOp->p1];
+    rc = copySharedBlockRow(p, pOp, pMem, pCtx);
+    if( rc==SQLITE_FULL && p->addedRows && (p->startPos + p->addedRows) <= p->pSharedBlock->requiredPos ){
+      p->startPos += p->addedRows;
+      p->addedRows = 0;
+      p->pSharedBlock->xReset(pCtx,p->startPos);
+      p->blockFull = 0;
+      rc = copySharedBlockRow(p, pOp, pMem, pCtx);
+    }
+
+    if( rc==SQLITE_OK ){
+      p->addedRows++;
+    }else if( rc==SQLITE_FULL ){
+      p->blockFull = 1;
+    }else{
+      //SQLITE_NOMEM
+      goto no_mem;
+    }
+
+    if( p->blockFull && p->pSharedBlock->countAllRows==0 ){
+      p->pSharedBlock->xFinish(pCtx, p->addedRows, p->totalRows);
+      rc = SQLITE_DONE;
+      goto vdbe_return;
+    }else if( p->blockFull && p->pSharedBlock->countAllRows==1 ){
+      rc = SQLITE_OK;
+    }
+    break;
+  }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
+
   p->cacheCtr = (p->cacheCtr + 2)|1;
   p->pResultRow = &aMem[pOp->p1];
 #ifdef SQLITE_DEBUG
@@ -94793,6 +95241,17 @@ case OP_Compare: {
 ** This opcode must immediately follow an OP_Compare opcode.
 */
 case OP_Jump: {             /* jump */
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+  if( pOp->p5&0x80 ){
+    if( p->pSharedBlock!=NULL ){
+      if( p->totalRows < p->startPos || p->blockFull ){
+        p->totalRows++;
+        pOp = &aOp[pOp->p2 - 1];
+      }
+    }
+    break;
+  }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
   assert( pOp>aOp && pOp[-1].opcode==OP_Compare );
   assert( iCompareIsInit );
   if( iCompare<0 ){
@@ -99867,6 +100326,20 @@ case OP_IfNotZero: {        /* jump, in1 */
 ** and jump to P2 if the new value is exactly zero.
 */
 case OP_DecrJumpZero: {      /* jump, in1 */
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+  if( pOp->p5&0x80 ){
+    if( p->pSharedBlock!=NULL ){
+      if( p->totalRows < p->startPos || p->blockFull ){
+         pIn1 = &aMem[pOp->p1];
+         assert( pIn1->flags&MEM_Int );
+         if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--;
+         VdbeBranchTaken(pIn1->u.i==-1, 2);
+         if( pIn1->u.i==-1 ) goto jump_to_p2;
+      }
+    }
+    break;
+  }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
   pIn1 = &aMem[pOp->p1];
   assert( pIn1->flags&MEM_Int );
   if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--;
@@ -119592,6 +120065,40 @@ static void attachFunc(
   if( rc==SQLITE_OK && pNew->zDbSName==0 ){
     rc = SQLITE_NOMEM_BKPT;
   }
+#ifdef SQLITE_HAS_CODEC
+  if( rc==SQLITE_OK ){
+    extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
+    extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
+    int nKey;
+    char *zKey;
+    int t = sqlite3_value_type(argv[2]);
+    switch( t ){
+      case SQLITE_INTEGER:
+      case SQLITE_FLOAT:
+        zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
+        rc = SQLITE_ERROR;
+        break;
+
+      case SQLITE_TEXT:
+      case SQLITE_BLOB:
+        nKey = sqlite3_value_bytes(argv[2]);
+        zKey = (char *)sqlite3_value_blob(argv[2]);
+        rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
+        break;
+
+      case SQLITE_NULL:
+        /* No key specified.  Use the key from URI filename, or if none,
+        ** use the key from the main database. */
+        if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){
+          sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
+          if( nKey || sqlite3BtreeGetRequestedReserve(db->aDb[0].pBt)>0 ){
+            rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
+          }
+        }
+        break;
+    }
+  }
+#endif /* SQLITE_HAS_CODEC */
   sqlite3_free_filename( zPath );
 
   /* If the file was opened successfully, read the schema for the new database.
@@ -121163,8 +121670,24 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char
   testcase( zTabName[0]==0 );  /* Zero-length table names are allowed */
   pDb = &db->aDb[iDb];
   p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+  u8 tableType = p->eTabType;
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
   sqlite3DeleteTable(db, p);
   db->mDbFlags |= DBFLAG_SchemaChange;
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+  if( tableType!=TABTYP_VIEW ){
+    db->isDropTable = 1;
+    db->mDropTableName = sqlite3_malloc(strlen(zTabName) + 1);
+    if( db->mDropTableName!=NULL ){
+      memcpy(db->mDropTableName, zTabName, strlen(zTabName) + 1);
+    }
+    db->mDropSchemaName = sqlite3_malloc(strlen(db->aDb[iDb].zDbSName) + 1);
+    if( db->mDropSchemaName!=NULL ){
+      memcpy(db->mDropSchemaName, db->aDb[iDb].zDbSName, strlen(db->aDb[iDb].zDbSName) + 1);
+    }
+  }
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
 }
 
 /*
@@ -129771,10 +130294,16 @@ static void groupConcatValue(sqlite3_context *context){
 */
 SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
   int rc = sqlite3_overload_function(db, "MATCH", 2);
+#ifdef SQLITE_HAS_CODEC
+  extern void sqlite3CodecExportData(sqlite3_context *, int, sqlite3_value **);
+#endif /* SQLITE_HAS_CODEC */
   assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
   if( rc==SQLITE_NOMEM ){
     sqlite3OomFault(db);
   }
+#ifdef SQLITE_HAS_CODEC
+  sqlite3CreateFunc(db, "export_database", 1, SQLITE_TEXT, 0, sqlite3CodecExportData, 0, 0, 0, 0, 0);
+#endif /* SQLITE_HAS_CODEC */
 }
 
 /*
@@ -135492,6 +136021,10 @@ struct sqlite3_api_routines {
   /* Version 3.44.0 and later */
   void *(*get_clientdata)(sqlite3*,const char*);
   int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+  /* handle after drop table done */
+  int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*));
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
 };
 
 /*
@@ -135825,6 +136358,10 @@ typedef int (*sqlite3_loadext_entry)(
 /* Version 3.44.0 and later */
 #define sqlite3_get_clientdata         sqlite3_api->get_clientdata
 #define sqlite3_set_clientdata         sqlite3_api->set_clientdata
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+/* handle after drop table done */
+#define sqlite3_set_droptable_handle   sqlite3_api->set_droptable_handle
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
 
 #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -135848,7 +136385,7 @@ typedef int (*sqlite3_loadext_entry)(
 /************** Continuing where we left off in loadext.c ********************/
 /* #include "sqliteInt.h" */
 
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS)
 /*
 ** Some API routines are omitted when various features are
 ** excluded from a build of SQLite.  Substitute a NULL pointer
@@ -135862,7 +136399,9 @@ typedef int (*sqlite3_loadext_entry)(
 # define sqlite3_column_origin_name     0
 # define sqlite3_column_origin_name16   0
 #endif
+#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */
 
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
 #ifdef SQLITE_OMIT_AUTHORIZATION
 # define sqlite3_set_authorizer         0
 #endif
@@ -135943,6 +136482,7 @@ typedef int (*sqlite3_loadext_entry)(
 #if defined(SQLITE_OMIT_TRACE)
 # define sqlite3_trace_v2      0
 #endif
+#endif /* !SQLITE_OMIT_LOAD_EXTENSION */
 
 /*
 ** The following structure contains pointers to all SQLite API routines.
@@ -135959,6 +136499,7 @@ typedef int (*sqlite3_loadext_entry)(
 ** also check to make sure that the pointer to the function is
 ** not NULL before calling it.
 */
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS)
 static const sqlite3_api_routines sqlite3Apis = {
   sqlite3_aggregate_context,
 #ifndef SQLITE_OMIT_DEPRECATED
@@ -136228,7 +136769,11 @@ static const sqlite3_api_routines sqlite3Apis = {
   sqlite3_bind_blob64,
   sqlite3_bind_text64,
   sqlite3_cancel_auto_extension,
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
   sqlite3_load_extension,
+#else
+  0,
+#endif /* !SQLITE_OMIT_LOAD_EXTENSION */
   sqlite3_malloc64,
   sqlite3_msize,
   sqlite3_realloc64,
@@ -136346,7 +136891,10 @@ static const sqlite3_api_routines sqlite3Apis = {
   sqlite3_stmt_explain,
   /* Version 3.44.0 and later */
   sqlite3_get_clientdata,
-  sqlite3_set_clientdata
+  sqlite3_set_clientdata,
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+  sqlite3_set_droptable_handle
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
 };
 
 /* True if x is the directory separator character
@@ -136357,6 +136905,9 @@ static const sqlite3_api_routines sqlite3Apis = {
 # define DirSep(X)  ((X)=='/')
 #endif
 
+#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
 /*
 ** Attempt to load an SQLite extension library contained in the file
 ** zFile.  The entry point is zProc.  zProc may be 0 in which case a
@@ -136836,6 +137387,9 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
 #define PragTyp_WAL_CHECKPOINT                43
 #define PragTyp_LOCK_STATUS                   44
 #define PragTyp_STATS                         45
+#ifdef SQLITE_HAS_CODEC
+#define PragTyp_KEY                          255
+#endif /* SQLITE_HAS_CODEC */
 
 /* Property flags associated with various pragma. */
 #define PragFlg_NeedSchema 0x01 /* Force schema load before running */
@@ -137126,6 +137680,18 @@ static const PragmaName aPragmaName[] = {
   /* ePragFlg:  */ PragFlg_Result0,
   /* ColNames:  */ 0, 0,
   /* iArg:      */ 0 },
+#if defined(SQLITE_HAS_CODEC)
+ {/* zName:     */ "hexkey",
+  /* ePragTyp:  */ PragTyp_KEY,
+  /* ePragFlg:  */ 0,
+  /* ColNames:  */ 0, 0,
+  /* iArg:      */ 2 },
+ {/* zName:     */ "hexrekey",
+  /* ePragTyp:  */ PragTyp_KEY,
+  /* ePragFlg:  */ 0,
+  /* ColNames:  */ 0, 0,
+  /* iArg:      */ 3 },
+#endif
 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 #if !defined(SQLITE_OMIT_CHECK)
  {/* zName:     */ "ignore_check_constraints",
@@ -137178,6 +137744,13 @@ static const PragmaName aPragmaName[] = {
   /* ColNames:  */ 0, 0,
   /* iArg:      */ 0 },
 #endif
+#if defined(SQLITE_HAS_CODEC)
+ {/* zName:     */ "key",
+  /* ePragTyp:  */ PragTyp_KEY,
+  /* ePragFlg:  */ 0,
+  /* ColNames:  */ 0, 0,
+  /* iArg:      */ 0 },
+#endif
 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
  {/* zName:     */ "legacy_alter_table",
   /* ePragTyp:  */ PragTyp_FLAG,
@@ -137285,6 +137858,15 @@ static const PragmaName aPragmaName[] = {
   /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
   /* ColNames:  */ 0, 0,
   /* iArg:      */ SQLITE_RecTriggers },
+#endif
+#if defined(SQLITE_HAS_CODEC)
+ {/* zName:     */ "rekey",
+  /* ePragTyp:  */ PragTyp_KEY,
+  /* ePragFlg:  */ 0,
+  /* ColNames:  */ 0, 0,
+  /* iArg:      */ 1 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
  {/* zName:     */ "reverse_unordered_selects",
   /* ePragTyp:  */ PragTyp_FLAG,
   /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
@@ -137373,6 +137955,18 @@ static const PragmaName aPragmaName[] = {
   /* ePragFlg:  */ PragFlg_NoColumns1,
   /* ColNames:  */ 0, 0,
   /* iArg:      */ 0 },
+#endif
+#if defined(SQLITE_HAS_CODEC)
+ {/* zName:     */ "textkey",
+  /* ePragTyp:  */ PragTyp_KEY,
+  /* ePragFlg:  */ 0,
+  /* ColNames:  */ 0, 0,
+  /* iArg:      */ 4 },
+ {/* zName:     */ "textrekey",
+  /* ePragTyp:  */ PragTyp_KEY,
+  /* ePragFlg:  */ 0,
+  /* ColNames:  */ 0, 0,
+  /* iArg:      */ 5 },
 #endif
  {/* zName:     */ "threads",
   /* ePragTyp:  */ PragTyp_THREADS,
@@ -137814,6 +138408,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
   Vdbe *v = sqlite3GetVdbe(pParse);  /* Prepared statement */
   const PragmaName *pPragma;   /* The pragma */
 
+#ifdef SQLITE_HAS_CODEC
+  extern int sqlite3CodecPragma(sqlite3*, int, Parse *, const char *, const char *);
+#endif /* SQLITE_HAS_CODEC */
+
   if( v==0 ) return;
   sqlite3VdbeRunOnlyOnce(v);
   pParse->nMem = 2;
@@ -137883,6 +138481,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
     goto pragma_out;
   }
 
+#ifdef SQLITE_HAS_CODEC
+  if(sqlite3CodecPragma(db, iDb, pParse, zLeft, zRight)) {
+    /* sqlite3CodecPragma executes internal */
+    goto pragma_out;
+  }
+#endif
+  /* END CODEC */
+
   /* Locate the pragma in the lookup table */
   pPragma = pragmaLocate(zLeft);
   if( pPragma==0 ){
@@ -140023,6 +140629,48 @@ SQLITE_PRIVATE void sqlite3Pragma(
   }
 #endif
 
+#ifdef SQLITE_HAS_CODEC
+  /* Pragma        iArg
+  ** ----------   ------
+  **  key           0
+  **  rekey         1
+  **  hexkey        2
+  **  hexrekey      3
+  **  textkey       4
+  **  textrekey     5
+  */
+  case PragTyp_KEY: {
+    if( zRight ){
+      char zBuf[40];
+      const char *zKey = zRight;
+      int n;
+      if( pPragma->iArg==2 || pPragma->iArg==3 ){
+        u8 iByte;
+        int i;
+        for(i=0, iByte=0; i<(int)(sizeof(zBuf)*2) && sqlite3Isxdigit(zRight[i]); i++){
+          iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
+          if( (i&1)!=0 ) zBuf[i/2] = iByte;
+        }
+        zKey = zBuf;
+        n = i/2;
+      }else{
+        n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1;
+      }
+      if( (pPragma->iArg & 1)==0 ){
+        rc = sqlite3_key_v2(db, zDb, zKey, n);
+      }else{
+        rc = sqlite3_rekey_v2(db, zDb, zKey, n);
+      }
+      if( rc==SQLITE_OK && n!=0 ){
+        sqlite3VdbeSetNumCols(v, 1);
+        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC);
+        returnSingleText(v, "ok");
+      }
+    }
+    break;
+  }
+#endif /* SQLITE_HAS_CODEC */
+
 #if defined(SQLITE_ENABLE_CEROD)
   case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){
     if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
@@ -142579,9 +143227,25 @@ static void selectInnerLoop(
   assert( p->pEList!=0 );
   hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
   if( pSort && pSort->pOrderBy==0 ) pSort = 0;
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+  if( hasDistinct && (pDistinct->eTnctType==WHERE_DISTINCT_UNIQUE) ){
+    hasDistinct = WHERE_DISTINCT_NOOP;
+    sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
+  }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
   if( pSort==0 && !hasDistinct ){
     assert( iContinue!=0 );
     codeOffset(v, p->iOffset, iContinue);
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+    if( eDest==SRT_Output ){
+      if( p->iLimit ){
+        sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak);
+        sqlite3VdbeChangeP5(v, 128);
+      }
+      sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue);
+      sqlite3VdbeChangeP5(v, 128);
+    }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
   }
 
   /* Pull the requested columns.
@@ -142710,6 +143374,16 @@ static void selectInnerLoop(
     fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct);
     if( pSort==0 ){
       codeOffset(v, p->iOffset, iContinue);
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+      if( eDest==SRT_Output ){
+        if( p->iLimit ){
+          sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak);
+          sqlite3VdbeChangeP5(v, 128);
+        }
+        sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue);
+        sqlite3VdbeChangeP5(v, 128);
+      }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
     }
   }
 
@@ -143173,11 +143847,23 @@ static void generateSortTail(
     addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
     VdbeCoverage(v);
     assert( p->iLimit==0 && p->iOffset==0 );
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+    if( eDest==SRT_Output ){
+      sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue);
+      sqlite3VdbeChangeP5(v, 128);
+    }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
     sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
     bSeq = 0;
   }else{
     addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
     codeOffset(v, p->iOffset, addrContinue);
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+    if( eDest==SRT_Output ){
+      sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue);
+      sqlite3VdbeChangeP5(v, 128);
+    }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
     iSortTab = iTab;
     bSeq = 1;
     if( p->iOffset>0 ){
@@ -153658,6 +154344,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
   }
   nRes = sqlite3BtreeGetRequestedReserve(pMain);
 
+#ifdef SQLITE_HAS_CODEC
+  /* A VACUUM cannot change the pagesize of an encrypted database. */
+  if( db->nextPagesize ){
+    extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
+    int nKey;
+    char *zKey;
+    sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey);
+    if( nKey ) db->nextPagesize = 0;
+  }
+#endif /* SQLITE_HAS_CODEC */
+
   sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
   sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
   sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL);
@@ -177753,6 +178450,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db);
 /************** End of rtree.h ***********************************************/
 /************** Continuing where we left off in main.c ***********************/
 #endif
+#include "sqlite3tokenizer.h"
 #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
 /************** Include sqliteicu.h in the middle of main.c ******************/
 /************** Begin file sqliteicu.h ***************************************/
@@ -178752,6 +179450,29 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
       rc = setupLookaside(db, pBuf, sz, cnt);
       break;
     }
+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION
+    case SQLITE_DBCONFIG_SET_SHAREDBLOCK: {
+      Vdbe *pVdbe = (Vdbe *)va_arg(ap, sqlite3_stmt*);
+      Sqlite3SharedBlockMethods *pSharedBlock = va_arg(ap, Sqlite3SharedBlockMethods*);
+      if( pVdbe==NULL ){
+        rc = SQLITE_MISUSE;
+        break;
+      }
+      pVdbe->pSharedBlock = pSharedBlock;
+      if( pSharedBlock!=NULL ){
+        pVdbe->startPos = pSharedBlock->startPos;
+      }
+      pVdbe->totalRows = 0;
+      pVdbe->blockFull = 0;
+      pVdbe->addedRows = 0;
+      rc = SQLITE_OK;
+      break;
+    }
+    case SQLITE_DBCONFIG_USE_SHAREDBLOCK: {
+      rc = SQLITE_OK;
+      break;
+    }
+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */
     default: {
       static const struct {
         int op;      /* The opcode */
@@ -181006,7 +181727,41 @@ static const char *uriParameter(const char *zFilename, const char *zParam){
   return 0;
 }
 
-
+#ifdef SQLITE_HAS_CODEC
+/*
+** Process URI filename query parameters relevant to the SQLite Encryption
+** Extension.  Return true if any of the relevant query parameters are
+** seen and return false if not.
+*/
+SQLITE_PRIVATE int sqlite3CodecQueryParameters(
+  sqlite3 *db,           /* Database connection */
+  const char *zDb,       /* Which schema is being created/attached */
+  const char *zUri       /* URI filename */
+){
+  const char *zKey;
+  if( zUri==0 ){
+    return 0;
+  }else if( (zKey = uriParameter(zUri, "hexkey"))!=0 && zKey[0] ){
+    u8 iByte;
+    int i;
+    char zDecoded[40];
+    for(i=0, iByte=0; i<(int)(sizeof(zDecoded)*2) && sqlite3Isxdigit(zKey[i]); i++){
+      iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
+      if( (i&1)!=0 ) zDecoded[i/2] = iByte;
+    }
+    sqlite3_key_v2(db, zDb, zDecoded, i/2);
+    return 1;
+  }else if( (zKey = uriParameter(zUri, "key"))!=0 ){
+    sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey));
+    return 1;
+  }else if( (zKey = uriParameter(zUri, "textkey"))!=0 ){
+    sqlite3_key_v2(db, zDb, zKey, -1);
+    return 1;
+  }else{
+    return 0;
+  }
+}
+#endif /* SQLITE_HAS_CODEC */
 
 /*
 ** This routine does the work of opening a database on behalf of
@@ -181354,6 +182109,12 @@ opendb_out:
   }else if( rc!=SQLITE_OK ){
     db->eOpenState = SQLITE_STATE_SICK;
   }
+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK
+  db->isDropTable = 0;
+  db->mDropTableName = NULL;
+  db->mDropSchemaName = NULL;
+  db->xDropTableHandle = NULL;
+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */
   *ppDb = db;
 #ifdef SQLITE_ENABLE_SQLLOG
   if( sqlite3GlobalConfig.xSqllog ){
@@ -181362,6 +182123,14 @@ opendb_out:
     sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
   }
 #endif
+#ifdef SQLITE_HAS_CODEC
+  if( rc==SQLITE_OK ) {
+#ifdef SQLITE_CODEC_ATTACH_CHANGED
+    sqlite3CodecResetParameters(&db->codecParm);
+#endif /* SQLITE_CODEC_ATTACH_CHANGED */
+    sqlite3CodecQueryParameters(db, 0, zOpen);
+  }
+#endif /* SQLITE_HAS_CODEC */
   sqlite3_free_filename(zOpen);
   return rc;
 }
@@ -234858,7 +235627,7 @@ static void sqlite3Fts5ParseSetDistance(
               );
           return;
         }
-        nNear = nNear * 10 + (p->p[i] - '0');
+        if( nNear<214748363 ) nNear = nNear * 10 + (p->p[i] - '0');
       }
     }else{
       nNear = FTS5_DEFAULT_NEARDIST;
@@ -252924,3 +253693,1659 @@ SQLITE_API int sqlite3_stmt_init(
 /* Return the source-id for this library */
 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
 /************************** End of sqlite3.c ******************************/
+
+#ifdef SQLITE_HAS_CODEC
+/************** Begin file hw_codec_openssl.h *******************************/
+#ifndef EXPOSE_INTERNAL_FUNC
+#define CODEC_STATIC static
+#else
+#define CODEC_STATIC
+#endif
+
+#define DEFAULT_CIPHER "aes-256-gcm"
+
+typedef struct{
+  unsigned char *buffer;
+  int bufferSize;
+}Buffer;
+/************** End file hw_codec_openssl.h *********************************/
+/************** Begin file hw_codec.h ***************************************/
+#define DEFAULT_PAGE_SIZE 1024
+#define DEFAULT_ITER 10000
+#define FILE_HEADER_SIZE 16
+#define SALT_SIZE FILE_HEADER_SIZE
+#define HMAC_SALT_MASK 0x3a
+#define HMAC_ITER 2
+#define MAX_HMAC_SIZE 64
+#define MAX_INIT_VECTOR_SIZE 16
+#define MIN_BLOCK_SIZE 16
+
+#define CODEC_OPERATION_ENCRYPT 1
+#define CODEC_OPERATION_DECRYPT 0
+
+#define KEY_CONTEXT_HEAD_SIZE (sizeof(CodecConstant) + 3 * sizeof(int))
+
+typedef struct{
+  void *cipher;
+  int keySize;
+  int keyInfoSize;
+  int cipherPageSize;
+  int initVectorSize;
+  int hmacSize;
+  int reserveSize;
+  int hmacAlgo;
+  int kdfAlgo;
+  int rekeyHmacAlgo;
+}CodecConstant;
+
+typedef struct{
+  CodecConstant codecConst;
+  int deriveFlag;
+  int iter;
+  int passwordSize;
+  unsigned char *password;
+  unsigned char *key;
+  unsigned char *hmacKey;
+  unsigned char *keyInfo;
+}KeyContext;
+
+typedef struct{
+  Btree *pBt;
+  int savePassword;
+  unsigned char salt[SALT_SIZE];
+  unsigned char hmacSalt[SALT_SIZE];
+  unsigned char *buffer;
+  KeyContext *readCtx;
+  KeyContext *writeCtx;
+}CodecContext;
+
+/************** End file hw_codec.h *****************************************/
+/************** Begin file hw_codec_openssl.c *******************************/
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/crypto.h>
+
+unsigned int openssl_init_count = 0;
+unsigned int openssl_external_init_flag = 0;
+sqlite3_mutex *openssl_random_mutex = NULL;
+
+CODEC_STATIC void opensslActive(){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+
+  if(openssl_init_count == 0){
+    if(EVP_get_cipherbyname(DEFAULT_CIPHER) == NULL){
+      OpenSSL_add_all_algorithms();
+    }else{
+      openssl_external_init_flag = 1;
+    }
+  }
+
+  if(openssl_random_mutex == NULL){
+    openssl_random_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+  }
+  openssl_init_count++;
+
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return;
+}
+
+CODEC_STATIC void opensslDeactive(){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+
+  openssl_init_count--;
+  if(openssl_init_count == 0){
+    if(openssl_external_init_flag){
+      openssl_external_init_flag = 0;
+    }else{
+      EVP_cleanup();
+    }
+  }
+
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return;
+}
+
+CODEC_STATIC int opensslGetRandom(Buffer *buffer){
+  sqlite3_mutex_enter(openssl_random_mutex);
+  int rc = RAND_bytes(buffer->buffer, buffer->bufferSize);
+  sqlite3_mutex_leave(openssl_random_mutex);
+  if(rc != 1){
+    return SQLITE_ERROR;
+  }
+  return SQLITE_OK;
+}
+
+CODEC_STATIC void *opensslGetCipher(const char *cipherName){
+  return (void *)EVP_get_cipherbyname(cipherName);
+}
+
+CODEC_STATIC int opensslFreeCipher(void *cipher){
+  return SQLITE_OK;
+}
+
+CODEC_STATIC const char *opensslGetCipherName(void *cipher){
+  return EVP_CIPHER_name((EVP_CIPHER *)cipher);
+}
+
+CODEC_STATIC int opensslGetKeySize(void *cipher){
+  return EVP_CIPHER_key_length((EVP_CIPHER *)cipher);
+}
+
+CODEC_STATIC int opensslGetInitVectorSize(void *cipher){
+  return EVP_CIPHER_iv_length((EVP_CIPHER *)cipher);
+}
+
+#define CIPHER_HMAC_ALGORITHM_SHA1 1
+#define CIPHER_HMAC_ALGORITHM_SHA256 2
+#define CIPHER_HMAC_ALGORITHM_SHA512 3
+
+#define DEFAULT_HMAC_ALGORITHM CIPHER_HMAC_ALGORITHM_SHA1
+
+#define CIPHER_HMAC_ALGORITHM_NAME_SHA1 "SHA1"
+#define CIPHER_HMAC_ALGORITHM_NAME_SHA256 "SHA256"
+#define CIPHER_HMAC_ALGORITHM_NAME_SHA512 "SHA512"
+
+#define CIPHER_KDF_ALGORITHM_SHA1 1
+#define CIPHER_KDF_ALGORITHM_SHA256 2
+#define CIPHER_KDF_ALGORITHM_SHA512 3
+
+#define DEFAULT_KDF_ALGORITHM CIPHER_KDF_ALGORITHM_SHA1
+
+#define CIPHER_KDF_ALGORITHM_NAME_SHA1 "KDF_SHA1"
+#define CIPHER_KDF_ALGORITHM_NAME_SHA256 "KDF_SHA256"
+#define CIPHER_KDF_ALGORITHM_NAME_SHA512 "KDF_SHA512"
+
+
+CODEC_STATIC int opensslGetHmacSize(KeyContext *keyCtx){
+  if( keyCtx==NULL ){
+    return 0;
+  }
+  if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){
+    return EVP_MD_size(EVP_sha1());
+  }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){
+    return EVP_MD_size(EVP_sha256());
+  }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){
+    return EVP_MD_size(EVP_sha512());
+  }
+  return 0;
+}
+
+CODEC_STATIC int opensslGetBlockSize(void *cipher){
+  return EVP_CIPHER_block_size((EVP_CIPHER *)cipher);
+}
+
+CODEC_STATIC void *opensslGetCtx(void *cipher, int mode, unsigned char *key, unsigned char *initVector){
+  EVP_CIPHER_CTX *tmpCtx = EVP_CIPHER_CTX_new();
+  if(tmpCtx == NULL){
+    return (void *)tmpCtx;
+  }
+  EVP_CipherInit_ex(tmpCtx, (EVP_CIPHER *)cipher, NULL, NULL, NULL, mode);
+  EVP_CIPHER_CTX_set_padding(tmpCtx, 0);
+  EVP_CipherInit_ex(tmpCtx, NULL, NULL, key, initVector, mode);
+  return (void *)tmpCtx;
+}
+
+CODEC_STATIC int opensslCipher(void *iCtx, Buffer *input, unsigned char *output){
+  int outputLength = 0;
+  int cipherLength;
+  EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)iCtx;
+  EVP_CipherUpdate(ctx, output, &cipherLength, input->buffer, input->bufferSize);
+  outputLength += cipherLength;
+  output += cipherLength;
+  EVP_CipherFinal_ex(ctx, output, &cipherLength);
+  outputLength += cipherLength;
+  if(outputLength != input->bufferSize){
+    return SQLITE_ERROR;
+  }
+  return SQLITE_OK;
+}
+
+CODEC_STATIC void opensslFreeCtx(void *ctx){
+  EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)ctx);
+}
+
+CODEC_STATIC int opensslHmac(Buffer *key, Buffer *input1, Buffer *input2, Buffer *output, int hmacAlgo){
+  HMAC_CTX *ctx = HMAC_CTX_new();
+  if(ctx == NULL){
+    return SQLITE_ERROR;
+  }
+  if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){
+    HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha1(), NULL);
+  }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){
+    HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha256(), NULL);
+  }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){
+    HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha512(), NULL);
+  }
+  HMAC_Update(ctx, input1->buffer, input1->bufferSize);
+  HMAC_Update(ctx, input2->buffer, input2->bufferSize);
+  HMAC_Final(ctx, output->buffer, (unsigned int *)(&output->bufferSize));
+
+  HMAC_CTX_free(ctx);
+  return SQLITE_OK;
+}
+
+CODEC_STATIC void opensslKdf(Buffer *password, Buffer *salt, int workfactor, Buffer *key, int kdfAlgo){
+  if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){
+    PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize,
+      workfactor, EVP_sha1(), key->bufferSize, key->buffer);
+  }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){
+    PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize,
+      workfactor, EVP_sha256(), key->bufferSize, key->buffer);
+  }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){
+    PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize,
+      workfactor, EVP_sha512(), key->bufferSize, key->buffer);
+  }
+}
+
+/************** End file hw_codec_openssl.c *********************************/
+/************** Begin file hw_codec.c ***************************************/
+
+#include "securec.h"
+
+typedef enum{
+  OPERATE_CONTEXT_READ = 0,
+  OPERATE_CONTEXT_WRITE,
+  OPERATE_CONTEXT_BOTH
+}OperateContext;
+
+CODEC_STATIC int sqlite3CodecIsHex(const unsigned char *buffer, int bufferSize){
+  int i;
+  for(i = 0; i < bufferSize; i++){
+    if((buffer[i] < '0' || buffer[i] > '9') &&
+      (buffer[i] < 'a' || buffer[i] > 'f') &&
+      (buffer[i] < 'A' || buffer[i] > 'F')){
+      return 0;
+    }
+  }
+  return 1;
+}
+
+CODEC_STATIC int sqlite3CodecHex2int(char input){
+  if(input >= '0' && input <= '9'){
+    return (int)(input - '0');
+  }else if(input >= 'a' && input <= 'f'){
+    return (int)(input - 'a') + 10;
+  }else if(input >= 'A' && input <= 'F'){
+    return (int)(input - 'A') + 10;
+  }else{
+    return 0;
+  }
+}
+
+CODEC_STATIC void sqlite3CodecHex2Bin(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){
+  int i;
+  for(i = 0; i < inputBuffersize - 1; i += 2){
+    outputBuffer[i / 2] = sqlite3CodecHex2int(inputBuffer[i]) << 4 | sqlite3CodecHex2int(inputBuffer[i + 1]);
+  }
+  return;
+}
+
+CODEC_STATIC void sqlite3CodecBin2Hex(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){
+  char *buffer = NULL;
+  int i;
+  for(i = 0; i < inputBuffersize; i++){
+    buffer = (char *)(outputBuffer + i * 2);
+    sqlite3_snprintf(3, buffer, "%02x ", inputBuffer[i]);
+  }
+  return;
+}
+
+CODEC_STATIC int sqlite3CodecIfMemset(unsigned char *input, unsigned char val, int len){
+  int i;
+  for(i = 0; i < len; i++){
+    if(input[i] != val){
+      return 0;
+    }
+  }
+  return 1;
+}
+
+CODEC_STATIC int sqlite3CodecIsKeyInfoFormat(const unsigned char *input, int inputSize){
+  return (input[0] == 'x') && (input[1] == '\'') && (input[inputSize - 1] == '\'') && (sqlite3CodecIsHex(input + 2, inputSize - 3)) ? 1 : 0;
+}
+
+CODEC_STATIC void sqlite3CodecSetError(CodecContext *ctx, int error){
+  if(ctx->pBt){
+    ctx->pBt->pBt->pPager->errCode = error;
+    ctx->pBt->pBt->db->errCode = error;
+  }
+  return;
+}
+
+CODEC_STATIC void sqlite3CodecClearDeriveKey(KeyContext *keyCtx){
+  if(keyCtx->key != NULL){
+    (void)memset_s(keyCtx->key, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize);
+    sqlite3_free(keyCtx->key);
+    keyCtx->key = NULL;
+  }
+  if(keyCtx->hmacKey != NULL){
+    (void)memset_s(keyCtx->hmacKey, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize);
+    sqlite3_free(keyCtx->hmacKey);
+    keyCtx->hmacKey = NULL;
+  }
+  if(keyCtx->keyInfo != NULL){
+    (void)memset_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, 0, keyCtx->codecConst.keyInfoSize);
+    sqlite3_free(keyCtx->keyInfo);
+    keyCtx->keyInfo = NULL;
+  }
+  keyCtx->deriveFlag = 0;
+}
+
+CODEC_STATIC void sqlite3CodecClearPassword(KeyContext *keyCtx){
+  if(keyCtx->password != NULL){
+    (void)memset_s(keyCtx->password, keyCtx->passwordSize, 0, keyCtx->passwordSize);
+    sqlite3_free(keyCtx->password);
+    keyCtx->password = NULL;
+  }
+  keyCtx->passwordSize = 0;
+}
+
+CODEC_STATIC void sqlite3CodecInitDeriveKeyMemory(KeyContext *keyCtx){
+  keyCtx->key = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize);
+  keyCtx->hmacKey = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize);
+  keyCtx->keyInfo = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keyInfoSize);
+  return;
+}
+
+CODEC_STATIC int sqlite3CodecKeyCtxCmp(KeyContext *first, KeyContext *second){
+  if(memcmp((unsigned char *)first, (unsigned char *)second, sizeof(CodecConstant))){
+    return 0;
+  }
+  if(first->iter != second->iter){
+    return 0;
+  }
+  if(first->passwordSize != second->passwordSize){
+    return 0;
+  }
+  if((first->password != second->password) && memcmp(first->password, second->password, first->passwordSize)){
+    return 0;
+  }
+  return 1;
+}
+
+// This function will free all resources of key context, except it self.
+CODEC_STATIC void sqlite3CodecFreeKeyContext(KeyContext *keyCtx){
+  sqlite3CodecClearDeriveKey(keyCtx);
+  sqlite3CodecClearPassword(keyCtx);
+  (void)opensslFreeCipher(keyCtx->codecConst.cipher);
+  (void)memset_s(keyCtx, sizeof(KeyContext), 0, KEY_CONTEXT_HEAD_SIZE);
+}
+
+// You should clear key derive result of output before you call this function
+CODEC_STATIC int sqlite3CodecCopyDeriveKey(KeyContext *input, KeyContext *output){
+  errno_t rc = EOK;
+  if(input->key != NULL && input->codecConst.keySize > 0){
+    output->key = (unsigned char *)sqlite3Malloc(output->codecConst.keySize);
+    if(output->key == NULL){
+      sqlite3CodecFreeKeyContext(output);
+      return SQLITE_NOMEM;
+    }
+    rc = memcpy_s(output->key, output->codecConst.keySize, input->key, input->codecConst.keySize);
+    if(rc != EOK){
+      sqlite3CodecFreeKeyContext(output);
+      return SQLITE_ERROR;
+    }
+  }
+  if(input->hmacKey != NULL && input->codecConst.keySize > 0){
+    output->hmacKey = (unsigned char *)sqlite3Malloc(output->codecConst.keySize);
+    if(output->hmacKey == NULL){
+      sqlite3CodecFreeKeyContext(output);
+      return SQLITE_NOMEM;
+    }
+    rc = memcpy_s(output->hmacKey, output->codecConst.keySize, input->hmacKey, input->codecConst.keySize);
+    if(rc != EOK){
+      sqlite3CodecFreeKeyContext(output);
+      return SQLITE_ERROR;
+    }
+  }
+  if(input->keyInfo != NULL && input->codecConst.keyInfoSize > 0){
+    output->keyInfo = (unsigned char *)sqlite3Malloc(output->codecConst.keyInfoSize);
+    if(output->keyInfo == NULL){
+      sqlite3CodecFreeKeyContext(output);
+      return SQLITE_NOMEM;
+    }
+    rc = memcpy_s(output->keyInfo, output->codecConst.keyInfoSize, input->keyInfo, input->codecConst.keyInfoSize);
+    if(rc != EOK){
+      sqlite3CodecFreeKeyContext(output);
+      return SQLITE_ERROR;
+    }
+  }
+  return SQLITE_OK;
+}
+
+// You should set all key infos including salt before you call this function
+CODEC_STATIC int sqlite3CodecDeriveKey(CodecContext *ctx, OperateContext whichKey){
+  KeyContext *keyCtx = NULL;
+  KeyContext *secondKeyCtx = NULL;
+  switch(whichKey){
+    case OPERATE_CONTEXT_READ:
+      keyCtx = ctx->readCtx;
+      secondKeyCtx = ctx->writeCtx;
+      break;
+    case OPERATE_CONTEXT_WRITE:
+      keyCtx = ctx->writeCtx;
+      secondKeyCtx = ctx->readCtx;
+      break;
+    default:
+      return SQLITE_ERROR;
+  }
+  if(keyCtx->password == NULL || keyCtx->passwordSize <= 0){
+    return SQLITE_ERROR;
+  }
+  if(keyCtx->deriveFlag){
+    return SQLITE_OK;
+  }
+  errno_t memcpyRc = EOK;
+  unsigned char salt[SALT_SIZE];
+  if (ctx->pBt != NULL && sqlite3OsRead(ctx->pBt->pBt->pPager->fd, salt, SALT_SIZE, 0) == SQLITE_OK) {
+    assert(SALT_SIZE == FILE_HEADER_SIZE);
+    if (memcmp(SQLITE_FILE_HEADER, salt, SALT_SIZE) != 0 && memcmp(ctx->salt, salt, SALT_SIZE) != 0) {
+      memcpyRc = memcpy_s(ctx->salt, FILE_HEADER_SIZE, salt, SALT_SIZE);
+      if(memcpyRc != EOK){
+        return SQLITE_ERROR;
+      }
+    }
+  }
+  sqlite3CodecInitDeriveKeyMemory(keyCtx);
+  if(keyCtx->key == NULL || keyCtx->hmacKey == NULL || keyCtx->keyInfo == NULL){
+    sqlite3CodecClearDeriveKey(keyCtx);
+    return SQLITE_NOMEM;
+  }
+  if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize) &&
+    (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){
+    sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key);
+    sqlite3CodecHex2Bin(keyCtx->password + 2 + keyCtx->codecConst.keySize * 2, SALT_SIZE * 2, ctx->salt);
+    memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize);
+    if(memcpyRc != EOK){
+      return SQLITE_ERROR;
+    }
+  }else if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize - SALT_SIZE * 2) &&
+    (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){
+    sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key);
+    memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize);
+    if(memcpyRc != EOK){
+      return SQLITE_ERROR;
+    }
+    sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2);
+    keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\'';
+  }else{
+    Buffer password;
+    Buffer salt;
+    Buffer key;
+    password.buffer = keyCtx->password;
+    password.bufferSize = keyCtx->passwordSize;
+    salt.buffer = ctx->salt;
+    salt.bufferSize = SALT_SIZE;
+    key.buffer = keyCtx->key;
+    key.bufferSize = keyCtx->codecConst.keySize;
+    opensslKdf(&password, &salt, keyCtx->iter, &key, keyCtx->codecConst.kdfAlgo);
+    keyCtx->keyInfo[0] = 'x';
+    keyCtx->keyInfo[1] = '\'';
+    sqlite3CodecBin2Hex(keyCtx->key, keyCtx->codecConst.keySize, keyCtx->keyInfo + 2);
+    sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2);
+    keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\'';
+  }
+  int i;
+  for(i = 0; i < SALT_SIZE; i++){
+    ctx->hmacSalt[i] = ctx->salt[i] ^ HMAC_SALT_MASK;
+  }
+  Buffer hmacPassword;
+  Buffer hmacSalt;
+  Buffer hmacKey;
+  hmacPassword.buffer = keyCtx->key;
+  hmacPassword.bufferSize = keyCtx->codecConst.keySize;
+  hmacSalt.buffer = ctx->hmacSalt;
+  hmacSalt.bufferSize = SALT_SIZE;
+  hmacKey.buffer = keyCtx->hmacKey;
+  hmacKey.bufferSize = keyCtx->codecConst.keySize;
+  opensslKdf(&hmacPassword, &hmacSalt, HMAC_ITER, &hmacKey, keyCtx->codecConst.kdfAlgo);
+  keyCtx->deriveFlag = 1;
+  if(sqlite3CodecKeyCtxCmp(keyCtx, secondKeyCtx)){
+    sqlite3CodecClearDeriveKey(secondKeyCtx);
+    int rc = sqlite3CodecCopyDeriveKey(keyCtx, secondKeyCtx);
+    if(rc == SQLITE_OK){
+      secondKeyCtx->deriveFlag = 1;
+      // clear password
+      if(!(ctx->savePassword)){
+        sqlite3CodecClearPassword(secondKeyCtx);
+      }
+    }
+  }
+  // clear password
+  if(!(ctx->savePassword)){
+    sqlite3CodecClearPassword(keyCtx);
+  }
+  return SQLITE_OK;
+}
+
+// This function may clear key derive infos
+CODEC_STATIC int sqlite3CodecSetCodecConstant(KeyContext *keyCtx, const char *cipherName){
+  if(keyCtx->codecConst.cipher){
+    if(sqlite3StrICmp(cipherName, opensslGetCipherName(keyCtx->codecConst.cipher)) == 0){
+      return SQLITE_OK;
+    }
+  }
+  sqlite3CodecClearDeriveKey(keyCtx);
+  void *cipher = opensslGetCipher(cipherName);
+  if(cipher != NULL){
+    keyCtx->codecConst.cipher = cipher;
+  } else {
+    return SQLITE_ERROR;
+  }
+  keyCtx->codecConst.keySize = opensslGetKeySize(keyCtx->codecConst.cipher);
+  keyCtx->codecConst.keyInfoSize = (keyCtx->codecConst.keySize + SALT_SIZE) * 2 + 3;
+  keyCtx->codecConst.initVectorSize = opensslGetInitVectorSize(keyCtx->codecConst.cipher);
+  return SQLITE_OK;
+}
+
+// You should clear key derive infos before you call this function
+CODEC_STATIC int sqlite3CodecSetIter(KeyContext *keyCtx, int iter){
+  keyCtx->iter = iter;
+  return SQLITE_OK;
+}
+
+#ifdef SQLITE_CODEC_ATTACH_CHANGED
+#define CIPHER_ID_AES_256_CBC 0
+#define CIPHER_ID_AES_256_GCM 1
+
+#define CIPHER_TOTAL_NUM 2
+
+#define CIPHER_NAME_AES_256_CBC "aes-256-cbc"
+#define CIPHER_NAME_AES_256_GCM "aes-256-gcm"
+
+struct CodecCipherNameId {
+  int cipherId;
+  const char *cipherName;
+};
+
+static const struct CodecCipherNameId g_cipherNameIdMap[CIPHER_TOTAL_NUM] = {
+  { CIPHER_ID_AES_256_CBC, CIPHER_NAME_AES_256_CBC },
+  { CIPHER_ID_AES_256_GCM, CIPHER_NAME_AES_256_GCM }
+};
+
+SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p)
+{
+  p->kdfIter = DEFAULT_ITER;
+  p->pageSize = DEFAULT_PAGE_SIZE;
+  p->cipher = CIPHER_ID_AES_256_GCM;
+  p->hmacAlgo = DEFAULT_HMAC_ALGORITHM;
+  p->kdfAlgo = DEFAULT_KDF_ALGORITHM;
+}
+
+CODEC_STATIC void sqlite3CodecSetDefaultAttachCipher(CodecParameter *parm, const char *cipherName){
+  int i;
+  for( i=0; i<CIPHER_TOTAL_NUM; i++ ){
+    if( sqlite3StrICmp(cipherName, g_cipherNameIdMap[i].cipherName)==0 ){
+      sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+      parm->cipher = g_cipherNameIdMap[i].cipherId;
+      sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+      return;
+    }
+  }
+  sqlite3_log(SQLITE_WARNING, "invalid attach cipher algorithm");
+}
+
+CODEC_STATIC const char *sqlite3CodecGetDefaultAttachCipher(CodecParameter *parm){
+  const char *attachedCipher = CIPHER_NAME_AES_256_GCM;
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  if( (parm->cipher>=0) && (parm->cipher<CIPHER_TOTAL_NUM) ){
+    attachedCipher = g_cipherNameIdMap[parm->cipher].cipherName;
+  }
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return attachedCipher;
+}
+
+CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfIter(CodecParameter *parm, int iter){
+  if( iter<=0 ){
+    return;
+  }
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  parm->kdfIter = iter;
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+
+CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfIter(CodecParameter *parm){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  int iterNum = parm->kdfIter;
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return iterNum;
+}
+
+CODEC_STATIC void sqlite3CodecSetDefaultAttachHmacAlgo(CodecParameter *parm, int hmacAlgo){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  parm->hmacAlgo = hmacAlgo;
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+
+CODEC_STATIC int sqlite3CodecGetDefaultAttachHmacAlgo(CodecParameter *parm){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  int hmacAlgo = parm->hmacAlgo;
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return hmacAlgo;
+}
+
+CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfAlgo(CodecParameter *parm, int kdfAlgo){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  parm->kdfAlgo = kdfAlgo;
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+
+CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfAlgo(CodecParameter *parm){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  int kdfAlgo = parm->kdfAlgo;
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return kdfAlgo;
+}
+
+CODEC_STATIC void sqlite3CodecSetDefaultAttachPageSize(CodecParameter *parm, int pageSize){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  parm->pageSize = pageSize;
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+
+CODEC_STATIC int sqlite3CodecGetDefaultAttachPageSize(CodecParameter *parm){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  int pageSize = parm->pageSize;
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return pageSize;
+}
+
+#endif /* SQLITE_CODEC_ATTACH_CHANGED */
+
+// You should clear key derive infos and password infos before you call this function
+CODEC_STATIC int sqlite3CodecSetPassword(KeyContext *keyCtx, const void *zKey, int nKey){
+  keyCtx->passwordSize = nKey;
+  keyCtx->password = (unsigned char *)sqlite3Malloc(keyCtx->passwordSize);
+  if(keyCtx->password == NULL){
+    return SQLITE_NOMEM;
+  }
+  errno_t rc = memcpy_s(keyCtx->password, keyCtx->passwordSize, zKey, nKey);
+  if(rc != EOK){
+    sqlite3CodecClearPassword(keyCtx);
+    return SQLITE_ERROR;
+  }
+  return SQLITE_OK;
+}
+
+// You should clear key derive infos and password infos before you call this function
+CODEC_STATIC int sqlite3CodecSetHmacAlgorithm(KeyContext *keyCtx, int hmacAlgo){
+  keyCtx->codecConst.hmacAlgo = hmacAlgo;
+  keyCtx->codecConst.hmacSize = opensslGetHmacSize(keyCtx);
+  int cipherBlockSize = opensslGetBlockSize(keyCtx->codecConst.cipher);
+  int blockSize = cipherBlockSize;
+  while(blockSize < MIN_BLOCK_SIZE){
+    blockSize += cipherBlockSize;
+  }
+  int reserveSize = MAX_INIT_VECTOR_SIZE + keyCtx->codecConst.hmacSize;
+  if(reserveSize % blockSize == 0){
+    keyCtx->codecConst.reserveSize = reserveSize;
+  }else{
+    keyCtx->codecConst.reserveSize = (reserveSize / blockSize + 1) * blockSize;
+  }
+  return SQLITE_OK;
+}
+
+CODEC_STATIC int sqlite3CodecSetKdfAlgorithm(KeyContext *keyCtx, int kdfAlgo){
+  keyCtx->codecConst.kdfAlgo = kdfAlgo;
+  return SQLITE_OK;
+}
+
+CODEC_STATIC int sqlite3CodecSetCipherPageSize(CodecContext *ctx, int size){
+  if(!((size != 0) && ((size & (size - 1)) == 0)) || size < 512 || size > 65536) {
+    sqlite3_log(SQLITE_ERROR, "codec: cipher_page_size not a power of 2 and between 512 and 65536 inclusive(%d).", size);
+    return SQLITE_ERROR;
+  }
+  int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize;
+  (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize);
+  sqlite3_free(ctx->buffer);
+  ctx->readCtx->codecConst.cipherPageSize = size;
+  ctx->writeCtx->codecConst.cipherPageSize = size;
+
+  ctx->buffer = (unsigned char *)sqlite3Malloc(size);
+  if (ctx->buffer == NULL) {
+    sqlite3_log(SQLITE_NOMEM, "codec: alloc mem failed when set cipher page size(%d).", size);
+    return SQLITE_NOMEM;
+  }
+  return SQLITE_OK;
+}
+
+// You should clear output before you call this function
+CODEC_STATIC int sqlite3CodecCopyKeyContext(KeyContext *input, KeyContext *output){
+  errno_t rc = memcpy_s(output, sizeof(KeyContext), input, KEY_CONTEXT_HEAD_SIZE);
+  if(rc != EOK){
+    return SQLITE_ERROR;
+  }
+  if(input->password != NULL && input->passwordSize > 0){
+    output->password = (unsigned char *)sqlite3Malloc(output->passwordSize);
+    if(output->password == NULL){
+      sqlite3CodecFreeKeyContext(output);
+      return SQLITE_NOMEM;
+    }
+    rc = memcpy_s(output->password, output->passwordSize, input->password, input->passwordSize);
+    if(rc != EOK){
+      sqlite3CodecFreeKeyContext(output);
+      return SQLITE_ERROR;
+    }
+  }
+  return sqlite3CodecCopyDeriveKey(input, output);
+}
+
+// You should clear key context before you call this function
+#ifdef SQLITE_CODEC_ATTACH_CHANGED
+CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int attachFlag){
+#else
+CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){
+#endif /* SQLITE_CODEC_ATTACH_CHANGED */
+  int rc = SQLITE_OK;
+  KeyContext *keyCtx = ctx->readCtx;
+#ifdef SQLITE_CODEC_ATTACH_CHANGED
+  if( attachFlag!=0 ){
+    CodecParameter *parm = &p->db->codecParm;
+    int hmacAlgo = sqlite3CodecGetDefaultAttachHmacAlgo(parm);
+    rc = sqlite3CodecSetCodecConstant(keyCtx, sqlite3CodecGetDefaultAttachCipher(parm));
+    rc += sqlite3CodecSetIter(keyCtx, sqlite3CodecGetDefaultAttachKdfIter(parm));
+    if( hmacAlgo!=0 ){
+      rc += sqlite3CodecSetHmacAlgorithm(keyCtx, hmacAlgo);
+    }
+    int attachKdfAlgo = sqlite3CodecGetDefaultAttachKdfAlgo(parm);
+    if( attachKdfAlgo!=0 ){
+      rc += sqlite3CodecSetKdfAlgorithm(keyCtx, attachKdfAlgo);
+    }
+    int cipherPageSize = sqlite3CodecGetDefaultAttachPageSize(parm);
+    if( cipherPageSize!=0 ){
+      rc += sqlite3CodecSetCipherPageSize(ctx, cipherPageSize);
+      if ( rc != SQLITE_OK ) {
+        sqlite3CodecFreeKeyContext(keyCtx);
+        return SQLITE_ERROR;
+      }
+      rc += sqlite3BtreeSetPageSize(p, cipherPageSize, keyCtx->codecConst.reserveSize, 0);
+    }
+  }else{
+    rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER);
+    rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER);
+    rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM);
+    rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM);
+  }
+#else
+  rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER);
+  rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER);
+  rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM);
+  rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM);
+#endif /* SQLITE_CODEC_ATTACH_CHANGED */
+  keyCtx->codecConst.rekeyHmacAlgo = DEFAULT_HMAC_ALGORITHM;
+  rc += sqlite3CodecSetPassword(keyCtx, zKey, nKey);
+  if(rc != SQLITE_OK){
+    sqlite3CodecFreeKeyContext(keyCtx);
+    return SQLITE_ERROR;
+  }
+  return SQLITE_OK;
+}
+
+// This function will free all resources of codec context, except it self.
+CODEC_STATIC void sqlite3CodecFreeContext(CodecContext *ctx){
+  if(ctx->buffer){
+    int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize;
+    (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize);
+    sqlite3_free(ctx->buffer);
+    ctx->buffer = NULL;
+  }
+  if(ctx->readCtx){
+    sqlite3CodecFreeKeyContext(ctx->readCtx);
+    sqlite3_free(ctx->readCtx);
+    ctx->readCtx = NULL;
+  }
+  if(ctx->writeCtx){
+    sqlite3CodecFreeKeyContext(ctx->writeCtx);
+    sqlite3_free(ctx->writeCtx);
+    ctx->writeCtx = NULL;
+  }
+  (void)memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext));
+  return;
+}
+#ifdef SQLITE_CODEC_ATTACH_CHANGED
+CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int nDb){
+  int attachFlag = (nDb > 1) ? 1 : 0;
+  int defaultPageSz = attachFlag ? p->db->codecParm.pageSize : DEFAULT_PAGE_SIZE;
+#else
+CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){
+  int defaultPageSz = DEFAULT_PAGE_SIZE;
+#endif /* SQLITE_CODEC_ATTACH_CHANGED */
+  sqlite3_file *fd = p->pBt->pPager->fd;
+  ctx->pBt = p;
+  ctx->savePassword = 0;
+  ctx->buffer = (unsigned char *)sqlite3Malloc(defaultPageSz);
+  ctx->readCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext));
+  ctx->writeCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext));
+  if(ctx->buffer == NULL || ctx->readCtx == NULL || ctx->writeCtx == NULL){
+    sqlite3CodecFreeContext(ctx);
+    return SQLITE_NOMEM;
+  }
+  errno_t memsetRc = memset_s(ctx->buffer, defaultPageSz, 0, defaultPageSz);
+  memsetRc += memset_s(ctx->readCtx, sizeof(KeyContext), 0, sizeof(KeyContext));
+  memsetRc += memset_s(ctx->writeCtx, sizeof(KeyContext), 0, sizeof(KeyContext));
+  if(memsetRc != EOK){
+    sqlite3CodecFreeContext(ctx);
+    return SQLITE_ERROR;
+  }
+  ctx->readCtx->codecConst.cipherPageSize = defaultPageSz;
+  ctx->writeCtx->codecConst.cipherPageSize = defaultPageSz;
+#ifdef SQLITE_CODEC_ATTACH_CHANGED
+  int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey, attachFlag);
+#else
+  int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey);
+#endif /* SQLITE_CODEC_ATTACH_CHANGED */
+  if(rc != SQLITE_OK){
+    sqlite3CodecFreeContext(ctx);
+    return SQLITE_ERROR;
+  }
+  rc = sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx);
+  if(rc != SQLITE_OK){
+    sqlite3CodecFreeContext(ctx);
+    return SQLITE_ERROR;
+  }
+  if(fd == NULL || !(isOpen(fd)) || sqlite3OsRead(fd, ctx->salt, SALT_SIZE, 0) != SQLITE_OK){
+    Buffer salt;
+    salt.buffer = ctx->salt;
+    salt.bufferSize = SALT_SIZE;
+    rc = opensslGetRandom(&salt);
+    if(rc != SQLITE_OK){
+      sqlite3CodecFreeContext(ctx);
+      return rc;
+    }
+  }
+  return SQLITE_OK;
+}
+
+CODEC_STATIC int sqlite3CodecGetDbIndex(sqlite3 *db, const char *zDb){
+  int nDbIndex;
+  if(zDb == NULL){
+    return 0;
+  }
+  for(nDbIndex = 0; nDbIndex < db->nDb; nDbIndex++){
+    const char *zDbSName = db->aDb[nDbIndex].zDbSName;
+    if(strcmp(zDbSName, zDb) == 0){
+      return nDbIndex;
+    }
+  }
+  return 0;
+}
+
+CODEC_STATIC void sqlite3CodecTransPgno(Pgno input, unsigned char *output){
+#ifdef CIPHER_BIG_ENDAIN
+  sqlite3Put4byte(output, input);
+#else
+  output[0] = (u8)input;
+  output[1] = (u8)(input>>8);
+  output[2] = (u8)(input>>16);
+  output[3] = (u8)(input>>24);
+#endif
+}
+
+CODEC_STATIC int sqlite3CodecHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){
+  Buffer key;
+  key.buffer = ctx->hmacKey;
+  key.bufferSize = ctx->codecConst.keySize;
+  Buffer input1;
+  input1.buffer = input;
+  input1.bufferSize = bufferSize;
+  Buffer input2;
+  unsigned char pgnoBuffer[sizeof(Pgno)];
+  sqlite3CodecTransPgno(pgno, pgnoBuffer);
+  input2.buffer = pgnoBuffer;
+  input2.bufferSize = sizeof(Pgno);
+  Buffer outputBuffer;
+  outputBuffer.buffer = output;
+  outputBuffer.bufferSize = 0;
+  int rc = opensslHmac(&key, &input1, &input2, &outputBuffer, ctx->codecConst.hmacAlgo);
+  if(rc != SQLITE_OK || outputBuffer.bufferSize != ctx->codecConst.hmacSize){
+    return SQLITE_ERROR;
+  }
+  return SQLITE_OK;
+}
+
+CODEC_STATIC int sqlite3CodecCheckHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *expectResult){
+  if (ctx->codecConst.hmacSize <= 0) {
+    return 1;
+  }
+  int rc = SQLITE_OK;
+  if (ctx->codecConst.hmacSize <= MAX_HMAC_SIZE) {
+    unsigned char buffer[MAX_HMAC_SIZE];
+    rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, buffer);
+    if(rc != SQLITE_OK){
+      return 1;
+    }
+    return memcmp(buffer, expectResult, ctx->codecConst.hmacSize);
+  } else {
+    unsigned char *output = (unsigned char *)malloc(ctx->codecConst.hmacSize);
+    if (output == NULL) {
+      return 1;
+    }
+    rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, output);
+    if(rc != SQLITE_OK){
+      free(output);
+      return 1;
+    }
+    rc = memcmp(output, expectResult, ctx->codecConst.hmacSize);
+    free(output);
+    return rc;
+  }
+}
+
+CODEC_STATIC int sqlite3CodecEncryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){
+  KeyContext *keyCtx = NULL;
+  switch(whichKey){
+    case OPERATE_CONTEXT_READ:
+      keyCtx = ctx->readCtx;
+      break;
+    case OPERATE_CONTEXT_WRITE:
+      keyCtx = ctx->writeCtx;
+      break;
+    default:
+      return SQLITE_ERROR;
+  }
+  int rc = SQLITE_OK;
+  if(!(keyCtx->deriveFlag)){
+    rc = sqlite3CodecDeriveKey(ctx, whichKey);
+    if(rc != SQLITE_OK){
+      return rc;
+    }
+  }
+  if(keyCtx->codecConst.keySize == 0){
+    return SQLITE_ERROR;
+  }
+  Buffer inputBuffer;
+  inputBuffer.buffer = input;
+  inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize;
+  Buffer initVector;
+  initVector.buffer = output + inputBuffer.bufferSize;
+  initVector.bufferSize = keyCtx->codecConst.initVectorSize;
+  rc = opensslGetRandom(&initVector);
+  if(rc != SQLITE_OK){
+    return rc;
+  }
+  void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_ENCRYPT, keyCtx->key, initVector.buffer);
+  if(cipherCtx == NULL){
+    return SQLITE_ERROR;
+  }
+  rc = opensslCipher(cipherCtx, &inputBuffer, output);
+  opensslFreeCtx(cipherCtx);
+  if(rc != SQLITE_OK){
+    return rc;
+  }
+  rc = sqlite3CodecHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, output, output + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize);
+  if(rc != SQLITE_OK){
+    return rc;
+  }
+  return SQLITE_OK;
+}
+
+CODEC_STATIC int sqlite3CodecDecryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){
+  KeyContext *keyCtx = NULL;
+  switch(whichKey){
+    case OPERATE_CONTEXT_READ:
+      keyCtx = ctx->readCtx;
+      break;
+    case OPERATE_CONTEXT_WRITE:
+      keyCtx = ctx->writeCtx;
+      break;
+    default:
+      return SQLITE_ERROR;
+  }
+  int rc = SQLITE_OK;
+  if(!(keyCtx->deriveFlag)){
+    rc = sqlite3CodecDeriveKey(ctx, whichKey);
+    if(rc != SQLITE_OK){
+      return rc;
+    }
+  }
+  if(keyCtx->codecConst.keySize == 0){
+    return SQLITE_ERROR;
+  }
+  if(sqlite3CodecIfMemset(input, 0, bufferSize)){
+    errno_t memsetRc = memset_s(output, bufferSize, 0, bufferSize);
+    if(memsetRc != EOK){
+      return SQLITE_ERROR;
+    }
+    return SQLITE_OK;
+  }else{
+    Buffer inputBuffer;
+    inputBuffer.buffer = input;
+    inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize;
+    if(sqlite3CodecCheckHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, input, input + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize)){
+      sqlite3_log(SQLITE_ERROR, "codec: check hmac error at page %d, hmac %d, kdf %d, pageSize %d, iter %d.",
+        pgno, keyCtx->codecConst.hmacAlgo, keyCtx->codecConst.kdfAlgo, keyCtx->codecConst.cipherPageSize, keyCtx->iter);
+      return pgno == 1 ? SQLITE_NOTADB : SQLITE_ERROR;
+    }
+    unsigned char *initVector = input + inputBuffer.bufferSize;
+    void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_DECRYPT, keyCtx->key, initVector);
+    if(cipherCtx == NULL){
+      return SQLITE_ERROR;
+    }
+    rc = opensslCipher(cipherCtx, &inputBuffer, output);
+    opensslFreeCtx(cipherCtx);
+    if(rc != SQLITE_OK){
+      return rc;
+    }
+  }
+  return SQLITE_OK;
+}
+
+void* sqlite3Codec(void *ctx, void *data, Pgno pgno, int mode){
+  CodecContext *pCtx = (CodecContext *)ctx;
+  unsigned char *pData = (unsigned char *)data;
+  int offset = 0;
+  int rc = SQLITE_OK;
+  errno_t memcpyRc = EOK;
+  if(ctx == NULL || data == NULL){
+    return NULL;
+  }
+  if(pgno == 1){
+    offset = FILE_HEADER_SIZE;
+  }
+  int cipherPageSize = pCtx->readCtx->codecConst.cipherPageSize;
+  switch(mode){
+    case 0:
+    case 2:
+    case 3:
+      if(pgno == 1){
+        memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, SQLITE_FILE_HEADER, FILE_HEADER_SIZE);
+        if(memcpyRc != EOK){
+          sqlite3CodecSetError(pCtx, SQLITE_ERROR);
+          return NULL;
+        }
+      }
+      rc = sqlite3CodecDecryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset);
+      if(rc != SQLITE_OK){
+        sqlite3CodecSetError(pCtx, rc);
+        return NULL;
+      }
+      (void)memcpy_s(pData, cipherPageSize, pCtx->buffer, cipherPageSize);
+      return pData;
+      break;
+    case 6:
+      if(pgno == 1){
+        memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE);
+        if(memcpyRc != EOK){
+          sqlite3CodecSetError(pCtx, SQLITE_ERROR);
+          return NULL;
+        }
+      }
+      rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_WRITE, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset);
+      if(rc != SQLITE_OK){
+        sqlite3CodecSetError(pCtx, rc);
+        return NULL;
+      }
+      return pCtx->buffer;
+      break;
+    case 7:
+      if(pgno == 1){
+        memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE);
+        if(memcpyRc != EOK){
+          sqlite3CodecSetError(pCtx, SQLITE_ERROR);
+          return NULL;
+        }
+      }
+      rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset);
+      if(rc != SQLITE_OK){
+        sqlite3CodecSetError(pCtx, rc);
+        return NULL;
+      }
+      return pCtx->buffer;
+      break;
+    default:
+      return NULL;
+      break;
+  }
+}
+
+void sqlite3CodecDetach(void *ctx){
+  if(ctx != NULL){
+    sqlite3CodecFreeContext((CodecContext *)ctx);
+    sqlite3_free(ctx);
+    opensslDeactive();
+  }
+  return;
+}
+
+int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){
+  if(db == NULL){
+    return SQLITE_ERROR;
+  }
+  Btree *p = db->aDb[nDb].pBt;
+  if(p == NULL || pKey == NULL || nKey <= 0){
+    return SQLITE_OK;
+  }
+  opensslActive();
+  CodecContext *ctx = (CodecContext *)sqlite3Malloc(sizeof(CodecContext));
+  if(ctx == NULL){
+    return SQLITE_NOMEM;
+  }
+  errno_t memsetRc = memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext));
+  if(memsetRc != EOK){
+    sqlite3_free(ctx);
+    return SQLITE_ERROR;
+  }
+  sqlite3_mutex_enter(db->mutex);
+#ifdef SQLITE_CODEC_ATTACH_CHANGED
+  int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey, nDb);
+#else
+  int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey);
+#endif /* SQLITE_CODEC_ATTACH_CHANGED */
+  if(rc != SQLITE_OK){
+    sqlite3_free(ctx);
+    return rc;
+  }
+  sqlite3PagerSetCodec(sqlite3BtreePager(p), sqlite3Codec, NULL, sqlite3CodecDetach, (void *)ctx);
+
+  db->nextPagesize = ctx->readCtx->codecConst.cipherPageSize;
+  p->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
+  sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0);
+  sqlite3BtreeSecureDelete(p, 1);
+  if(isOpen(p->pBt->pPager->fd)){
+    sqlite3BtreeSetAutoVacuum(p, SQLITE_DEFAULT_AUTOVACUUM);
+  }
+
+  sqlite3_mutex_leave(db->mutex);
+
+  return SQLITE_OK;
+}
+
+void sqlite3CodecGetKey(sqlite3* db, int nDb, void **pKey, int *nKey)
+{
+  Btree *p = db->aDb[nDb].pBt;
+  if(p == NULL){
+    return;
+  }
+  CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec);
+  if(ctx){
+    if(ctx->savePassword){
+      *pKey = ctx->readCtx->password;
+      *nKey = ctx->readCtx->passwordSize;
+    }else{
+      *pKey = ctx->readCtx->keyInfo;
+      *nKey = ctx->readCtx->codecConst.keyInfoSize;
+    }
+  }else{
+    *pKey = NULL;
+    *nKey = 0;
+  }
+  return;
+}
+
+int sqlite3_key(sqlite3 *db, const void *pKey, int nKey){
+  return sqlite3_key_v2(db, "main", pKey, nKey);
+}
+
+int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){
+  if(db == NULL || pKey == NULL || nKey <= 0){
+    return SQLITE_ERROR;
+  }
+  int iDb = sqlite3CodecGetDbIndex(db, zDb);
+  return sqlite3CodecAttach(db, iDb, pKey, nKey);
+}
+
+int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey){
+  return sqlite3_rekey_v2(db, "main", pKey, nKey);
+}
+
+int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){
+  if(db == NULL || pKey == NULL || nKey == 0){
+    return SQLITE_ERROR;
+  }
+  int iDb = sqlite3CodecGetDbIndex(db, zDb);
+  Btree *p = db->aDb[iDb].pBt;
+  if(p == NULL){
+    return SQLITE_OK;
+  }
+  int pageCount;
+  Pgno pgno;
+  PgHdr *page = NULL;
+  Pager *pPager = p->pBt->pPager;
+  CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec);
+  if(ctx == NULL){
+    return SQLITE_OK;
+  }
+  sqlite3CodecClearDeriveKey(ctx->writeCtx);
+  sqlite3CodecClearPassword(ctx->writeCtx);
+  int rc = sqlite3CodecSetPassword(ctx->writeCtx, pKey, nKey);
+  if(rc != SQLITE_OK){
+    return rc;
+  }
+  sqlite3_mutex_enter(db->mutex);
+  (void)sqlite3BtreeBeginTrans(p, 1, 0);
+  sqlite3PagerPagecount(pPager, &pageCount);
+  // support hmac algo changed by using rekey operation
+  int oldHmacAlgo = ctx->writeCtx->codecConst.hmacAlgo;
+  if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=ctx->writeCtx->codecConst.hmacAlgo ){
+    sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo);
+    sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo);
+  }
+
+  for(pgno = 1; pgno <= (unsigned int)pageCount; pgno++){
+    if(PAGER_SJ_PGNO(pPager) != pgno){
+      rc = sqlite3PagerGet(pPager, pgno, &page, 0);
+      if(rc == SQLITE_OK){
+        rc = sqlite3PagerWrite(page);
+        if(rc == SQLITE_OK){
+          sqlite3PagerUnref(page);
+        }else{
+          sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when writing page %d: errno = %d.", pgno, rc);
+        }
+      }else{
+        sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when reading page %d: errno = %d.", pgno, rc);
+      }
+    }
+  }
+  if(rc == SQLITE_OK){
+    (void)sqlite3BtreeCommit(p);
+    sqlite3CodecFreeKeyContext(ctx->readCtx);
+    (void)sqlite3CodecCopyKeyContext(ctx->writeCtx, ctx->readCtx);
+  }else{
+    if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=oldHmacAlgo ){
+      sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, oldHmacAlgo);
+      sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, oldHmacAlgo);
+    }
+    (void)sqlite3BtreeRollback(p, SQLITE_ABORT_ROLLBACK, 0);
+  }
+  sqlite3_mutex_leave(db->mutex);
+
+  return rc;
+}
+
+void sqlite3_activate_see(const char* zPassPhrase){
+  return;
+}
+
+CODEC_STATIC void sqlite3CodecReturnPragmaResult(Parse *parse, const char *label, const char *value){
+  Vdbe *v = sqlite3GetVdbe(parse);
+  sqlite3VdbeSetNumCols(v, 1);
+  sqlite3VdbeSetColName(v, 0, COLNAME_NAME, label, SQLITE_STATIC);
+  sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, 0);
+  sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+  return;
+}
+
+// Each configuration setting operation should be done before read/write DB file or there might be some error.
+int sqlite3CodecPragma(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight){
+  Btree *p = db->aDb[iDb].pBt;
+  if(p == NULL){
+    return 0;
+  }
+  CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec);
+#ifdef SQLITE_CODEC_ATTACH_CHANGED
+  CodecParameter *parm = &db->codecParm;
+  if(sqlite3StrICmp(zLeft, "cipher_default_attach_cipher") == 0 && zRight != NULL){
+    (void)sqlite3CodecSetDefaultAttachCipher(parm, zRight);
+    return 1;
+  }else if(sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_iter") == 0 && zRight != NULL){
+    (void)sqlite3CodecSetDefaultAttachKdfIter(parm, atoi(zRight));
+    return 1;
+  }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_hmac_algo")==0 && zRight!=NULL ){
+    /*
+    ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect.
+    ** This behavior is to ensure backward compatible.
+    */
+    if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){
+      sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA1);
+      sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1);
+    }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){
+      sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA256);
+      sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256);
+    }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){
+      sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA512);
+      sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512);
+    }else{
+      return 0;
+    }
+    return 1;
+  }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_algo")==0 && zRight!=NULL ){
+    if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){
+      sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1);
+    }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){
+      sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256);
+    }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){
+      sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512);
+    }else{
+      return 0;
+    }
+    return 1;
+  }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_page_size")==0 && zRight!=NULL ){
+    (void)sqlite3CodecSetDefaultAttachPageSize(parm, atoi(zRight));
+    return 1;
+  }
+#endif /* SQLITE_CODEC_ATTACH_CHANGED */
+  if(ctx == NULL){
+    return 0;
+  }
+  if(sqlite3StrICmp(zLeft, "codec_cipher") == 0){
+    if(zRight){
+      sqlite3_mutex_enter(db->mutex);
+      (void)sqlite3CodecSetCodecConstant(ctx->readCtx, zRight);
+      (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo);
+      (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo);
+      sqlite3CodecFreeKeyContext(ctx->writeCtx);
+      (void)sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx);
+      sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0);
+      sqlite3_mutex_leave(db->mutex);
+    }else{
+      sqlite3CodecReturnPragmaResult(parse, "codec_cipher", opensslGetCipherName(ctx->writeCtx->codecConst.cipher));
+    }
+  }else if(sqlite3StrICmp(zLeft, "codec_kdf_iter") == 0){
+    if(zRight){
+      (void)sqlite3CodecSetIter(ctx->readCtx, atoi(zRight));
+      (void)sqlite3CodecSetIter(ctx->writeCtx, atoi(zRight));
+    }else{
+      char *iter = sqlite3_mprintf("%d", ctx->writeCtx->iter);
+      if(iter != NULL){
+        sqlite3CodecReturnPragmaResult(parse, "codec_kdf_iter", iter);
+        sqlite3_free(iter);
+      }
+    }
+  }else if( sqlite3StrICmp(zLeft, "codec_hmac_algo")==0 ){
+    /*
+    ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. 
+    ** This behavior is to ensure backward compatible.
+    */
+    if(zRight){
+      sqlite3_mutex_enter(db->mutex);
+      if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){
+        (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA1);
+        (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA1);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1);
+      }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){
+        (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA256);
+        (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA256);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256);
+      }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){
+        (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA512);
+        (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA512);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512);
+      }else{
+        sqlite3_mutex_leave(db->mutex);
+        return 0;
+      }
+      sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0);
+      sqlite3_mutex_leave(db->mutex);
+    }else{
+      if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1);
+      }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256);
+      }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512);
+      }
+    }
+  }else if( sqlite3StrICmp(zLeft, "codec_kdf_algo")==0 ){
+    if(zRight){
+      sqlite3_mutex_enter(db->mutex);
+      if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1);
+      }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256);
+      }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512);
+        (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512);
+      }else{
+        sqlite3_mutex_leave(db->mutex);
+        return 0;
+      }
+      sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0);
+      sqlite3_mutex_leave(db->mutex);
+    }else{
+      if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA1);
+      }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA256);
+      }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA512);
+      }
+    }
+  }else if( sqlite3StrICmp(zLeft, "codec_page_size")==0 ){
+    if(zRight){
+      sqlite3_mutex_enter(db->mutex);
+      int rc = sqlite3CodecSetCipherPageSize(ctx, atoi(zRight));
+      if (rc != SQLITE_OK){
+        sqlite3_mutex_leave(db->mutex);
+        return 0;
+      }
+      sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0);
+      sqlite3_mutex_leave(db->mutex);
+    } else {
+      char *pageSize = sqlite3_mprintf("%d", ctx->readCtx->codecConst.cipherPageSize);
+      if (pageSize != NULL) {
+        sqlite3CodecReturnPragmaResult(parse, "codec_page_size", pageSize);
+        sqlite3_free(pageSize);
+      }
+    }
+  }else if(sqlite3StrICmp(zLeft, "codec_rekey_hmac_algo") == 0){
+    if(zRight){
+      sqlite3_mutex_enter(db->mutex);
+      if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){
+        ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA1;
+      }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){
+        ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA256;
+      }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){
+        ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA512;
+      }else{
+        sqlite3_mutex_leave(db->mutex);
+        return 0;
+      }
+      sqlite3_mutex_leave(db->mutex);
+    }else{
+      if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1);
+      }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256);
+      }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){
+        sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512);
+      }
+    }
+  }else{
+    return 0;
+  }
+  return 1;
+}
+
+CODEC_STATIC int sqlite3CodecExportMetadata(sqlite3 *db, const char *dbName, const char *metaName){
+  char *sql = sqlite3_mprintf("PRAGMA %s;", metaName);
+  if(sql == NULL){
+    return SQLITE_NOMEM;
+  }
+  sqlite3_stmt *statement = NULL;
+  int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL);
+  sqlite3_free(sql);
+  if(rc != SQLITE_OK){
+    return rc;
+  }
+  rc = sqlite3_step(statement);
+  if(rc != SQLITE_ROW){
+    sqlite3_finalize(statement);
+    return rc;
+  }
+  int metadata = sqlite3_column_int(statement, 0);
+  sqlite3_finalize(statement);
+
+  sql = sqlite3_mprintf("PRAGMA %s.%s=%d;", dbName, metaName, metadata);
+  if(sql == NULL){
+    return SQLITE_NOMEM;
+  }
+  rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+  sqlite3_free(sql);
+  return rc;
+}
+
+CODEC_STATIC int sqlite3CodecBatchExportSql(sqlite3 *db, const char *sql, char **errMsg){
+  sqlite3_stmt *statement = NULL;
+  int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL);
+  if(rc != SQLITE_OK){
+    return rc;
+  }
+  while(sqlite3_step(statement) == SQLITE_ROW){
+    rc = sqlite3_exec(db, (char*)sqlite3_column_text(statement, 0), NULL, NULL, errMsg);
+    if(rc != SQLITE_OK){
+      sqlite3_finalize(statement);
+      return rc;
+    }
+  }
+  sqlite3_finalize(statement);
+  return rc;
+}
+
+void sqlite3CodecExportData(sqlite3_context *context, int argc, sqlite3_value **argv){
+  sqlite3 *db = sqlite3_context_db_handle(context);
+  const char *dbName = (const char*) sqlite3_value_text(argv[0]);
+
+  int rc = SQLITE_OK;
+  char *sql = NULL;
+  char *errMsg = NULL;
+
+  u64 flagsBackup = db->flags;
+  u32 mDbFlagsBackup = db->mDbFlags;
+  int nChangeBackup = db->nChange;
+  int nTotalChangeBackup = db->nTotalChange;
+  int (*xTraceBackup)(u32,void*,void*,void*) = db->trace.xV2;
+
+  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
+  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
+  db->mDbFlags |= DBFLAG_PreferBuiltin;
+  db->trace.xV2 = 0;
+
+  rc = sqlite3CodecExportMetadata(db, dbName, "schema_version");
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  rc = sqlite3CodecExportMetadata(db, dbName, "user_version");
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  rc = sqlite3CodecExportMetadata(db, dbName, "application_id");
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  sql = sqlite3_mprintf("SELECT 'CREATE TABLE %s.' || substr(sql,14) FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence' AND rootpage>0;", dbName);
+  if(sql == NULL){
+    rc = SQLITE_NOMEM;
+    goto export_finish;
+  }
+  rc = sqlite3CodecBatchExportSql(db, sql, &errMsg);
+  sqlite3_free(sql);
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  sql = sqlite3_mprintf("SELECT 'CREATE INDEX %s.' || substr(sql,14) FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%';", dbName);
+  if(sql == NULL){
+    rc = SQLITE_NOMEM;
+    goto export_finish;
+  }
+  rc = sqlite3CodecBatchExportSql(db, sql, &errMsg);
+  sqlite3_free(sql);
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  sql = sqlite3_mprintf("SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%';", dbName);
+  if(sql == NULL){
+    rc = SQLITE_NOMEM;
+    goto export_finish;
+  }
+  rc = sqlite3CodecBatchExportSql(db, sql, &errMsg);
+  sqlite3_free(sql);
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM main.sqlite_master WHERE type = 'table' AND name!='sqlite_sequence' AND rootpage>0;", dbName);
+  if(sql == NULL){
+    rc = SQLITE_NOMEM;
+    goto export_finish;
+  }
+  rc = sqlite3CodecBatchExportSql(db, sql, &errMsg);
+  sqlite3_free(sql);
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  sql = sqlite3_mprintf("SELECT 'DELETE FROM %s.' || quote(name) || ';' FROM %s.sqlite_master WHERE name='sqlite_sequence';", dbName, dbName);
+  if(sql == NULL){
+    rc = SQLITE_NOMEM;
+    goto export_finish;
+  }
+  rc = sqlite3CodecBatchExportSql(db, sql, &errMsg);
+  sqlite3_free(sql);
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM %s.sqlite_master WHERE name=='sqlite_sequence';", dbName, dbName);
+  if(sql == NULL){
+    rc = SQLITE_NOMEM;
+    goto export_finish;
+  }
+  rc = sqlite3CodecBatchExportSql(db, sql, &errMsg);
+  sqlite3_free(sql);
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+  sql = sqlite3_mprintf("INSERT INTO %s.sqlite_master SELECT type, name, tbl_name, rootpage, sql FROM main.sqlite_master WHERE type='view' OR type='trigger' OR (type='table' AND rootpage=0);", dbName, dbName);
+  if(sql == NULL){
+    rc = SQLITE_NOMEM;
+    goto export_finish;
+  }
+  rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg);
+  sqlite3_free(sql);
+  if(rc != SQLITE_OK){
+    goto export_finish;
+  }
+export_finish:
+  db->flags = flagsBackup;
+  db->mDbFlags = mDbFlagsBackup;
+  db->nChange = nChangeBackup;
+  db->nTotalChange = nTotalChangeBackup;
+  db->trace.xV2 = xTraceBackup;
+  if(rc != SQLITE_OK){
+    if(errMsg != NULL) {
+      sqlite3_result_error(context, errMsg, -1);
+      sqlite3DbFree(db, errMsg);
+    } else {
+      sqlite3_result_error(context, sqlite3ErrStr(rc), -1);
+    }
+  }
+  return;
+}
+/************** End file hw_codec.c *****************************************/
+#endif
+
+// export the symbols
+#ifdef SQLITE_EXPORT_SYMBOLS
+struct sqlite3_api_routines_extra {
+  int (*initialize)();
+  int (*config)(int,...);
+  int (*key)(sqlite3*,const void*,int);
+  int (*key_v2)(sqlite3*,const char*,const void*,int);
+  int (*rekey)(sqlite3*,const void*,int);
+  int (*rekey_v2)(sqlite3*,const char*,const void*,int);
+};
+
+typedef struct sqlite3_api_routines_extra sqlite3_api_routines_extra;
+static const sqlite3_api_routines_extra sqlite3ExtraApis = {
+  sqlite3_initialize,
+  sqlite3_config,
+#ifdef SQLITE_HAS_CODEC
+  sqlite3_key,
+  sqlite3_key_v2,
+  sqlite3_rekey,
+  sqlite3_rekey_v2
+#else
+  0,
+  0,
+  0,
+  0
+#endif /* SQLITE_HAS_CODEC */
+};
+
+EXPORT_SYMBOLS const sqlite3_api_routines *sqlite3_export_symbols = &sqlite3Apis;
+EXPORT_SYMBOLS const sqlite3_api_routines_extra *sqlite3_export_extra_symbols = &sqlite3ExtraApis;
+/************** End export the symbols *****************************************/
+#endif /* SQLITE_EXPORT_SYMBOLS */
-- 
2.34.1