99#include "pager.h"
1010#include "btreeInt.h"
1111#endif
12+ #include <sys/stat.h>
1213#include <zlib.h>
1314#include "ceshim.h"
1415
@@ -104,21 +105,17 @@ struct __attribute__ ((__packed__)) ceshim_map_entry {
104105** An instance of this structure is attached to each ceshim VFS to
105106** provide auxiliary non-persisted information.
106107*/
108+ typedef struct ceshim_file ceshim_file ;
107109typedef struct ceshim_info ceshim_info ;
108110struct ceshim_info {
109- sqlite3_vfs * pRootVfs ; /* The underlying real VFS */
110-
111- // Pointers to custom compress functions implemented by the user
112- int (* xCompressBound )(void * pCtx , int nSrc );
113- int (* xCompress )(void * pCtx , char * aDest , int * pnDest , char * aSrc , int nSrc );
114- int (* xUncompress )(void * pCtx , char * aDest , int * pnDest , char * aSrc , int nSrc );
115-
116- const char * zVfsName ; /* Name of this VFS */
117- char * zUppJournalPath ; /* Path to redirect upper journal */
118- sqlite3_vfs * pCeshimVfs ; /* Pointer back to the ceshim VFS */
119- unsigned char zDbHeader [100 ]; /* Sqlite3 DB header */
120- ceshim_header ceshimHeader ; /* Ceshim header with page mapping data */
121- CeshimMemPage * pPage1 ; /* Page 1 of the pager */
111+ sqlite3_vfs * pRootVfs ; // The underlying real VFS
112+ const char * zVfsName ; // Name of this VFS
113+ char * zUppJournalPath ; // Path to redirect upper journal
114+ sqlite3_vfs * pCeshimVfs ; // Pointer back to the ceshim VFS
115+ ceshim_file * pFile ; // Pointer back to the ceshim_file representing the dest. db.
116+ unsigned char zDbHeader [100 ]; // Sqlite3 DB header
117+ ceshim_header ceshimHeader ; // Ceshim header with page mapping data
118+ CeshimMemPage * pPage1 ; // Page 1 of the pager
122119 Pgno lwrPageFile ; // max pgno in lower pager, used to update pager header
123120 CeshimMMTblEntry * mmTbl ; // The master mapping table
124121 u16 mmTblCurrIx ; // Index of the current page map in mmTbl
@@ -134,12 +131,16 @@ struct ceshim_info {
134131 // bools
135132 u8 bPgMapDirty :1 ; // Curr page map needs to be persisted
136133 u8 bReadOnly :1 ; // True when db was open for read-only
134+
135+ // Pointers to custom compress functions implemented by the user
136+ int (* xCompressBound )(void * pCtx , int nSrc );
137+ int (* xCompress )(void * pCtx , char * aDest , int * pnDest , char * aSrc , int nSrc );
138+ int (* xUncompress )(void * pCtx , char * aDest , int * pnDest , char * aSrc , int nSrc );
137139};
138140
139141/*
140142** The sqlite3_file object for the shim.
141143*/
142- typedef struct ceshim_file ceshim_file ;
143144struct ceshim_file {
144145 sqlite3_file base ; /* Base class. Must be first */
145146 ceshim_info * pInfo ; /* Custom info for this file */
@@ -1419,6 +1420,9 @@ static int ceshimOpen(
14191420 p -> zFName = zName ? fileTail (zName ) : "<temp>" ;
14201421 p -> pReal = (sqlite3_file * )& p [1 ];
14211422 p -> pPager = NULL ;
1423+
1424+ // We need this for import
1425+ pInfo -> pFile = p ;
14221426
14231427 // Process URI parameters
14241428 if ( flags & SQLITE_OPEN_URI ){
@@ -1812,3 +1816,71 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
18121816){
18131817 _ceshim_register ("ceshim-cli" , NULL , NULL , ceshimDefaultCompressBound , ceshimDefaultCompress , ceshimDefaultUncompress , 1 );
18141818}
1819+
1820+ int ceshimBuild (const char * srcDbPath , const char * destUri ){
1821+ int rc = SQLITE_ERROR ;
1822+ unsigned char zDbHeader [100 ];
1823+
1824+ // _ceshim_register must be done early enough to avoid SQLITE_MISUSE error
1825+ if ( (rc = _ceshim_register ("ceshim-build" , NULL , NULL , ceshimDefaultCompressBound , ceshimDefaultCompress , ceshimDefaultUncompress , 0 ))== SQLITE_OK ){
1826+ sqlite3_vfs * pVfs = sqlite3_vfs_find (NULL );
1827+ if ( pVfs ){
1828+ Pager * pPager ;
1829+ int vfsFlags = SQLITE_OPEN_READONLY | SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_URI ;
1830+ if ( (rc = sqlite3PagerOpen (pVfs , & pPager , srcDbPath , EXTRA_SIZE , 0 , vfsFlags , ceshimPageReinit ))== SQLITE_OK ){
1831+ sqlite3PagerSetJournalMode (pPager , PAGER_JOURNALMODE_OFF );
1832+ if ( (rc = sqlite3PagerReadFileheader (pPager ,sizeof (zDbHeader ),zDbHeader )) == SQLITE_OK ){
1833+ u32 pageSize = (zDbHeader [16 ]<<8 ) | (zDbHeader [17 ]<<16 );
1834+ if ( pageSize >=512 && pageSize <=SQLITE_MAX_PAGE_SIZE // validate range
1835+ && ((pageSize - 1 )& pageSize )== 0 ){ // validate page size is a power of 2
1836+ u8 nReserve = zDbHeader [20 ];
1837+ if ( (rc = sqlite3PagerSetPagesize (pPager , & pageSize , nReserve )) == SQLITE_OK ){
1838+ u32 fileChangeCounter = sqlite3Get4byte (zDbHeader + 24 );
1839+ u32 pageCount = sqlite3Get4byte (zDbHeader + 28 );
1840+ u32 schemaFormat = sqlite3Get4byte (zDbHeader + 44 );
1841+ u32 versionValidForNumber = sqlite3Get4byte (zDbHeader + 92 );
1842+
1843+ // If we didn't get page count, figure it out from the file size
1844+ if ( !(pageCount > 0 && fileChangeCounter == versionValidForNumber ) ){
1845+ struct stat st ;
1846+ if ( stat (srcDbPath , & st )== 0 ){
1847+ off_t size = st .st_size ;
1848+ pageCount = st .st_size /pageSize ;
1849+ }
1850+ }
1851+
1852+ // lock pager, prepare to read
1853+ if ( rc == SQLITE_OK && (rc = sqlite3PagerSharedLock (pPager ))== SQLITE_OK ){
1854+ // get destination ready to receive data
1855+ sqlite3 * pDb ;
1856+ if ( (rc = sqlite3_open_v2 (destUri , & pDb , SQLITE_OPEN_READWRITE |SQLITE_OPEN_CREATE , "ceshim-build" ))== SQLITE_OK ){
1857+ sqlite3_vfs * pVfs = sqlite3_vfs_find ("ceshim-build" );
1858+ ceshim_info * pInfo = (ceshim_info * )pVfs -> pAppData ;
1859+ // import all pages
1860+ for (Pgno i = 0 ; i < pageCount ; i ++ ){
1861+ // read source page
1862+ DbPage * pPage ;
1863+ rc = sqlite3PagerGet (pPager , i + 1 , & pPage , 0 );
1864+ if ( rc == SQLITE_OK ){
1865+ // write destination page
1866+ void * pData = sqlite3PagerGetData (pPage );
1867+ rc = ceshimWrite ((sqlite3_file * )pInfo -> pFile , pData , pageSize , pageSize * i );
1868+ if (i > 1 ) sqlite3PagerUnref (pPage );
1869+ if ( rc != SQLITE_OK ) break ;
1870+ }else {
1871+ break ;
1872+ }
1873+ }
1874+ rc = sqlite3_close (pDb );
1875+ }
1876+ }
1877+ }
1878+ }
1879+ }else {
1880+ rc = SQLITE_CORRUPT ;
1881+ }
1882+ }
1883+ }
1884+ }
1885+ return rc ;
1886+ }
0 commit comments