Zipvfs

Zipvfs Example Code
Login

Zipvfs Example Code

Zipvfs C Example Code

This page contains example C code demonstrating how to use the Zipvfs module. Two examples are provided:

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;
}