Zipvfs C Example Code
This page contains example C code demonstrating how to use the Zipvfs module. Two examples are provided:
- Example One: How to create a VFS that uses the popular compression library zlib to compress data.
- Example Two: How to create a routine that compacts the database if doing so would result in disk-space savings of 10% or greater.
Using Zlib Compression With Zipvfs
This example demonstrates how to create a Zipvfs VFS that uses zlib to compress data and how to open a database connection that uses it. This example uses the zipvfs_create_vfs() API.
Functions compress(), uncompress() and compressBound() are utility functions supplied by the zlib library.
/* Zlib xCompressBound callback. */ static int zlibBound(void *pCtx, int nByte){ return compressBound(nByte); } /* Zlib xCompress callback. */ static int zlibCompress(void *pCtx, char *aDest, int *pnDest, char *aSrc, int nSrc){ uLongf n = *pnDest; /* In/out buffer size for compress() */ int rc; /* compress() return code */ rc = compress((Bytef*)aDest, &n, (Bytef*)aSrc, nSrc); *pnDest = n; return (rc==Z_OK ? SQLITE_OK : SQLITE_ERROR); } /* Zlib xUncompress callback. */ static int zlibUncompress(void *pCtx, char *aDest, int *pnDest, char *aSrc, int nSrc){ uLongf n = *pnDest; /* In/out buffer size for uncompress() */ int rc; /* uncompress() return code */ rc = uncompress((Bytef*)aDest, &n, (Bytef*)aSrc, nSrc); *pnDest = n; return (rc==Z_OK ? SQLITE_OK : SQLITE_ERROR); } /* ** Open a connection to a Zipvfs database file that uses zlib to compress ** data. If the connection is opened successfully, the new database handle ** is stored in *pDb and SQLITE_OK is returned. Otherwise, an error code ** is returned. ** ** The first time this function is called it creates a VFS that uses ** zlib to use with the new database connection. Each subsequent call reuses ** the same VFS. Note that there is a race condition in this code since the ** calls to check if the VFS has already been created and to actually create ** it are not protected by any kind of mutex primitive. */ int open_connection(const char *zName, sqlite3 **pDb){ /* Check if the VFS has already been created. If not, try to create it. ** If an error occurs while trying to create the new VFS (unlikely), return ** an error code immediately. Otherwise, proceed. ** ** The second parameter passed to zipvfs_create_vfs() is a NULL pointer. ** This means the new VFS will use the current default VFS to read and write ** the Zipvfs database file. This is normally the desired behaviour. */ if( sqlite3_vfs_find("zlib")==0 ){ int rc = zipvfs_create_vfs("zlib", 0, 0, zlibBound, zlibCompress, zlibUncompress); if( rc!=SQLITE_OK ){ *pDb = 0; return rc; } } /* Open a database connection using the VFS "zlib". */ return sqlite3_open_v2(zName, pDb, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "zlib"); }
Compacting a Database
This example demonstrates using the ZIPVFS_CTRL_STAT and ZIPVFS_CTRL_COMPACT file-control operations together to selectively compact a zipvfs database file based on the amount of disk space that can be reclaimed by doing so.
/* ** Parameter zName must be the name (e.g. "main") of a zipvfs database attached ** to database handle db. If doing so will reduce the size of the database ** file by approximately 10% or greater, then this routine compacts the file. ** So as not to require an excessive amount of temporary disk space, it does ** so using a series of incremental compact operations, each one compacting ** 500 KB of the file. */ int compact_database(sqlite3 *db, const char *zName){ ZipvfsStat stat; /* Stat data for zipvfs file. */ int rc; /* Return code of file_control() calls */ sqlite3_int64 nFree; /* Total number of free bytes in file */ rc = sqlite3_file_control(db, zName, ZIPVFS_CTRL_STAT, (void *)&stat); if( rc!=SQLITE_OK ) return rc; /* Calculate the total number of free bytes in the file. This is roughly ** the amount of disk space that could be freed by compacting the database. ** It is only a rough estimate as the size of the file on disk is rounded ** up to the nearest integer multiple of the page-size both before and after ** the compact operation. So in practice the number of bytes of disk space ** freed may be up to (pagesize-1) bytes less than or greater than the ** value calculated here. */ nFree = stat.nFreeByte + stat.nFragByte + stat.nGapByte; /* stat.nFileByte is the current size of the zipvfs database. If nFree is ** greater than or equal to 10% of this, attempt to compact the database. ** ** The compact operation could be done using a single call to ** sqlite3_file_control() by specifying a NULL pointer as the final argument. ** However, this requires creating a journal file approximately the same ** size as the zipvfs database file itself, which may be very large. Instead, ** the following loop compacts the file using multiple transactions, each ** requiring a journal file approximately 500KB or less in size. If a power ** failure occurs during this loop, the file will not be corrupted. Following ** recovery, the next call to this function will pick up at the point where ** the power failure occurred. */ if( nFree>=(stat.nFileByte/10) ){ sqlite3_int64 nByte; do{ nByte = 500 * 1024; rc = sqlite3_file_control(db, zName, ZIPVFS_CTRL_COMPACT, (void *)&nByte); }while( nByte>0 && rc==SQLITE_OK ); } return rc; }