/ Check-in [c83627b7]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the ability to enable or disable SQLITE_IOCAP_ZERO_DAMAGE using a URI parameter for both unix and windows. Add a file-control to query or disable the ZERO_DAMAGE setting. Add the -uri option to the "sqlite3" TCL command in tclsqlite3.c. Allow the sqlite3_uri_parameter() interface to accept a NULL pointer for its first parameter.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | statvfs
Files: files | file ages | folders
SHA1: c83627b73285f883719845c1b9fe85f378f28dd2
User & Date: drh 2011-12-21 14:42:29
Context
2011-12-22
01:46
Remove a redundant assignment operator. check-in: 19a6852a user: drh tags: statvfs
2011-12-21
14:42
Add the ability to enable or disable SQLITE_IOCAP_ZERO_DAMAGE using a URI parameter for both unix and windows. Add a file-control to query or disable the ZERO_DAMAGE setting. Add the -uri option to the "sqlite3" TCL command in tclsqlite3.c. Allow the sqlite3_uri_parameter() interface to accept a NULL pointer for its first parameter. check-in: c83627b7 user: drh tags: statvfs
2011-12-20
22:18
Remove the code that tries to detect OOO header writes on a WAL recovery. The code is made obsolete by syncing the WAL header. check-in: 7ac713a1 user: drh tags: statvfs
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/main.c.

  2973   2973   ** The zFilename argument is the filename pointer passed into the xOpen()
  2974   2974   ** method of a VFS implementation.  The zParam argument is the name of the
  2975   2975   ** query parameter we seek.  This routine returns the value of the zParam
  2976   2976   ** parameter if it exists.  If the parameter does not exist, this routine
  2977   2977   ** returns a NULL pointer.
  2978   2978   */
  2979   2979   const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
         2980  +  if( zFilename==0 ) return 0;
  2980   2981     zFilename += sqlite3Strlen30(zFilename) + 1;
  2981   2982     while( zFilename[0] ){
  2982   2983       int x = strcmp(zFilename, zParam);
  2983   2984       zFilename += sqlite3Strlen30(zFilename) + 1;
  2984   2985       if( x==0 ) return zFilename;
  2985   2986       zFilename += sqlite3Strlen30(zFilename) + 1;
  2986   2987     }

Changes to src/os_unix.c.

   211    211   struct unixFile {
   212    212     sqlite3_io_methods const *pMethod;  /* Always the first entry */
   213    213     sqlite3_vfs *pVfs;                  /* The VFS that created this unixFile */
   214    214     unixInodeInfo *pInode;              /* Info about locks on this inode */
   215    215     int h;                              /* The file descriptor */
   216    216     unsigned char eFileLock;            /* The type of lock held on this fd */
   217    217     unsigned char ctrlFlags;            /* Behavioral bits.  UNIXFILE_* flags */
          218  +  unsigned char szSector;             /* Sectorsize/512 */
   218    219     int lastErrno;                      /* The unix errno from last I/O error */
   219    220     void *lockingContext;               /* Locking style specific state */
   220    221     UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
   221    222     const char *zPath;                  /* Name of the file */
   222    223     unixShm *pShm;                      /* Shared memory segment information */
   223    224     int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
   224         -  int szSector;                       /* Sector size */
   225    225   #if SQLITE_ENABLE_LOCKING_STYLE
   226    226     int openFlags;                      /* The flags specified at open() */
   227    227   #endif
   228    228   #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
   229    229     unsigned fsFlags;                   /* cached details from statfs() */
   230    230   #endif
   231    231   #if OS_VXWORKS
................................................................................
   259    259   #define UNIXFILE_RDONLY      0x02     /* Connection is read only */
   260    260   #define UNIXFILE_PERSIST_WAL 0x04     /* Persistent WAL mode */
   261    261   #ifndef SQLITE_DISABLE_DIRSYNC
   262    262   # define UNIXFILE_DIRSYNC    0x08     /* Directory sync needed */
   263    263   #else
   264    264   # define UNIXFILE_DIRSYNC    0x00
   265    265   #endif
          266  +#define UNIXFILE_ZERO_DAMAGE 0x10     /* True if SQLITE_IOCAP_ZERO_DAMAGE */
   266    267   
   267    268   /*
   268    269   ** Include code that is common to all os_*.c files
   269    270   */
   270    271   #include "os_common.h"
   271    272   
   272    273   /*
................................................................................
  3506   3507         }
  3507   3508   #endif
  3508   3509       }
  3509   3510     }
  3510   3511   
  3511   3512     return SQLITE_OK;
  3512   3513   }
         3514  +
         3515  +/*
         3516  +** If *pArg is inititially negative then this is a query.  Set *pArg to
         3517  +** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
         3518  +**
         3519  +** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
         3520  +*/
         3521  +static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
         3522  +  if( *pArg<0 ){
         3523  +    *pArg = (pFile->ctrlFlags & mask)!=0;
         3524  +  }else if( (*pArg)==0 ){
         3525  +    pFile->ctrlFlags &= ~mask;
         3526  +  }else{
         3527  +    pFile->ctrlFlags |= mask;
         3528  +  }
         3529  +}
  3513   3530   
  3514   3531   /*
  3515   3532   ** Information and control of an open file handle.
  3516   3533   */
  3517   3534   static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  3518   3535     unixFile *pFile = (unixFile*)id;
  3519   3536     switch( op ){
................................................................................
  3533   3550         int rc;
  3534   3551         SimulateIOErrorBenign(1);
  3535   3552         rc = fcntlSizeHint(pFile, *(i64 *)pArg);
  3536   3553         SimulateIOErrorBenign(0);
  3537   3554         return rc;
  3538   3555       }
  3539   3556       case SQLITE_FCNTL_PERSIST_WAL: {
  3540         -      int bPersist = *(int*)pArg;
  3541         -      if( bPersist<0 ){
  3542         -        *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
  3543         -      }else if( bPersist==0 ){
  3544         -        pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
  3545         -      }else{
  3546         -        pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
  3547         -      }
         3557  +      unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg);
         3558  +      return SQLITE_OK;
         3559  +    }
         3560  +    case SQLITE_FCNTL_ZERO_DAMAGE: {
         3561  +      unixModeBit(pFile, UNIXFILE_ZERO_DAMAGE, (int*)pArg);
  3548   3562         return SQLITE_OK;
  3549   3563       }
  3550   3564       case SQLITE_FCNTL_VFSNAME: {
  3551   3565         *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
  3552   3566         return SQLITE_OK;
  3553   3567       }
  3554   3568   #ifndef NDEBUG
................................................................................
  3585   3599   ** a database and its journal file) that the sector size will be the
  3586   3600   ** same for both.
  3587   3601   */
  3588   3602   static int unixSectorSize(sqlite3_file *pFile){
  3589   3603     unixFile *p = (unixFile*)pFile;
  3590   3604     if( p->szSector==0 ){
  3591   3605   #ifdef MISSING_STATVFS
  3592         -    p->szSector = SQLITE_DEFAULT_SECTOR_SIZE;
         3606  +    p->szSector = SQLITE_DEFAULT_SECTOR_SIZE/512;
  3593   3607   #else
  3594   3608       struct statvfs x;
  3595   3609       int sz;
  3596   3610       memset(&x, 0, sizeof(x));
  3597   3611       osStatvfs(p->zPath, &x);
  3598         -    p->szSector = sz = (int)x.f_frsize;
         3612  +    sz = (int)x.f_frsize;
  3599   3613       if( sz<512 || sz>65536 || (sz&(sz-1))!=0 ){
  3600         -      p->szSector = SQLITE_DEFAULT_SECTOR_SIZE;
         3614  +      sz = SQLITE_DEFAULT_SECTOR_SIZE;
  3601   3615       }
         3616  +    p->szSector = sz/512;
  3602   3617   #endif
  3603   3618     }
  3604         -  return p->szSector;
         3619  +  return p->szSector*512;
  3605   3620   }
  3606   3621   
  3607   3622   /*
  3608         -** Return the device characteristics for the file. This is always 0 for unix.
         3623  +** Return the device characteristics for the file.
         3624  +**
         3625  +** This VFS is set up to return SQLITE_IOCAP_ZERO_DAMAGE by default.
         3626  +** However, that choice is contraversial sicne technically the underlying
         3627  +** file system does not always provide ZERO_DAMAGE.  (In other words, after
         3628  +** a power-loss event, parts of the file that were never written might end
         3629  +** up being altered.)  However, non-ZERO-DAMAGE behavior is very, very rare.
         3630  +** And asserting ZERO_DAMAGE makes a large reduction in the amount of required
         3631  +** I/O.  Hence, while ZERO_DAMAGE is on by default, there is a file-control
         3632  +** available to turn it off.
  3609   3633   */
  3610         -static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
  3611         -  UNUSED_PARAMETER(NotUsed);
  3612         -  return SQLITE_IOCAP_ZERO_DAMAGE;
         3634  +static int unixDeviceCharacteristics(sqlite3_file *id){
         3635  +  unixFile *p = (unixFile*)id;
         3636  +  return (p->ctrlFlags & UNIXFILE_ZERO_DAMAGE) ? SQLITE_IOCAP_ZERO_DAMAGE : 0;
  3613   3637   }
  3614   3638   
  3615   3639   #ifndef SQLITE_OMIT_WAL
  3616   3640   
  3617   3641   
  3618   3642   /*
  3619   3643   ** Object used to represent an shared memory buffer.  
................................................................................
  4564   4588     int noLock,             /* Omit locking if true */
  4565   4589     int isDelete,           /* Delete on close if true */
  4566   4590     int isReadOnly          /* True if the file is opened read-only */
  4567   4591   ){
  4568   4592     const sqlite3_io_methods *pLockingStyle;
  4569   4593     unixFile *pNew = (unixFile *)pId;
  4570   4594     int rc = SQLITE_OK;
         4595  +  const char *zZeroDam;   /* Value of the zero_damage query parameter */
  4571   4596   
  4572   4597     assert( pNew->pInode==NULL );
  4573   4598   
  4574   4599     /* Parameter isDelete is only used on vxworks. Express this explicitly 
  4575   4600     ** here to prevent compiler warnings about unused parameters.
  4576   4601     */
  4577   4602     UNUSED_PARAMETER(isDelete);
................................................................................
  4590   4615     /* No locking occurs in temporary files */
  4591   4616     assert( zFilename!=0 || noLock );
  4592   4617   
  4593   4618     OSTRACE(("OPEN    %-3d %s\n", h, zFilename));
  4594   4619     pNew->h = h;
  4595   4620     pNew->pVfs = pVfs;
  4596   4621     pNew->zPath = zFilename;
         4622  +  zZeroDam = sqlite3_uri_parameter(zFilename, "zero_damage");
         4623  +  if( zZeroDam==0 ) zZeroDam = "1";
         4624  +  pNew->ctrlFlags = atoi(zZeroDam) ? UNIXFILE_ZERO_DAMAGE : 1;
  4597   4625     if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
  4598         -    pNew->ctrlFlags = UNIXFILE_EXCL;
  4599         -  }else{
  4600         -    pNew->ctrlFlags = 0;
         4626  +    pNew->ctrlFlags |= UNIXFILE_EXCL;
  4601   4627     }
  4602   4628     if( isReadOnly ){
  4603   4629       pNew->ctrlFlags |= UNIXFILE_RDONLY;
  4604   4630     }
  4605   4631     if( syncDir ){
  4606   4632       pNew->ctrlFlags |= UNIXFILE_DIRSYNC;
  4607   4633     }

Changes to src/os_win.c.

    55     55   typedef struct winFile winFile;
    56     56   struct winFile {
    57     57     const sqlite3_io_methods *pMethod; /*** Must be first ***/
    58     58     sqlite3_vfs *pVfs;      /* The VFS used to open this file */
    59     59     HANDLE h;               /* Handle for accessing the file */
    60     60     u8 locktype;            /* Type of lock currently held on this file */
    61     61     short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
    62         -  u8 bPersistWal;         /* True to persist WAL files */
           62  +  u8 ctrlFlags;           /* Flags.  See WINFILE_* below */
    63     63     DWORD lastErrno;        /* The Windows errno from the last I/O error */
    64     64     DWORD sectorSize;       /* Sector size of the device file is on */
    65     65     winShm *pShm;           /* Instance of shared memory on this file */
    66     66     const char *zPath;      /* Full pathname of this file */
    67     67     int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
    68     68   #if SQLITE_OS_WINCE
    69     69     LPWSTR zDeleteOnClose;  /* Name of file to delete when closing */
................................................................................
    70     70     HANDLE hMutex;          /* Mutex used to control access to shared lock */  
    71     71     HANDLE hShared;         /* Shared memory segment used for locking */
    72     72     winceLock local;        /* Locks obtained by this instance of winFile */
    73     73     winceLock *shared;      /* Global shared lock memory for the file  */
    74     74   #endif
    75     75   };
    76     76   
           77  +/*
           78  +** Allowed values for winFile.ctrlFlags
           79  +*/
           80  +#define WINFILE_PERSIST_WAL     0x04   /* Persistent WAL mode */
           81  +#define WINFILE_ZERO_DAMAGE     0x10   /* True if SQLITE_IOCAP_ZERO_DAMAGE */
           82  +
    77     83   /*
    78     84    * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
    79     85    * various Win32 API heap functions instead of our own.
    80     86    */
    81     87   #ifdef SQLITE_WIN32_MALLOC
    82     88   /*
    83     89    * The initial size of the Win32-specific heap.  This value may be zero.
................................................................................
  2120   2126     }
  2121   2127     if( type>=PENDING_LOCK ){
  2122   2128       osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
  2123   2129     }
  2124   2130     pFile->locktype = (u8)locktype;
  2125   2131     return rc;
  2126   2132   }
         2133  +
         2134  +/*
         2135  +** If *pArg is inititially negative then this is a query.  Set *pArg to
         2136  +** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
         2137  +**
         2138  +** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
         2139  +*/
         2140  +static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
         2141  +  if( *pArg<0 ){
         2142  +    *pArg = (pFile->ctrlFlags & mask)!=0;
         2143  +  }else if( (*pArg)==0 ){
         2144  +    pFile->ctrlFlags &= ~mask;
         2145  +  }else{
         2146  +    pFile->ctrlFlags |= mask;
         2147  +  }
         2148  +}
  2127   2149   
  2128   2150   /*
  2129   2151   ** Control and query of the open file handle.
  2130   2152   */
  2131   2153   static int winFileControl(sqlite3_file *id, int op, void *pArg){
  2132   2154     winFile *pFile = (winFile*)id;
  2133   2155     switch( op ){
................................................................................
  2156   2178             }
  2157   2179           }
  2158   2180           return rc;
  2159   2181         }
  2160   2182         return SQLITE_OK;
  2161   2183       }
  2162   2184       case SQLITE_FCNTL_PERSIST_WAL: {
  2163         -      int bPersist = *(int*)pArg;
  2164         -      if( bPersist<0 ){
  2165         -        *(int*)pArg = pFile->bPersistWal;
  2166         -      }else{
  2167         -        pFile->bPersistWal = bPersist!=0;
  2168         -      }
         2185  +      winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
         2186  +      return SQLITE_OK;
         2187  +    }
         2188  +    case SQLITE_FCNTL_ZERO_DAMAGE: {
         2189  +      winModeBit(pFile, WINFILE_ZERO_DAMAGE, (int*)pArg);
  2169   2190         return SQLITE_OK;
  2170   2191       }
  2171   2192       case SQLITE_FCNTL_VFSNAME: {
  2172   2193         *(char**)pArg = sqlite3_mprintf("win32");
  2173   2194         return SQLITE_OK;
  2174   2195       }
  2175   2196       case SQLITE_FCNTL_SYNC_OMITTED: {
................................................................................
  2208   2229     return (int)(((winFile*)id)->sectorSize);
  2209   2230   }
  2210   2231   
  2211   2232   /*
  2212   2233   ** Return a vector of device characteristics.
  2213   2234   */
  2214   2235   static int winDeviceCharacteristics(sqlite3_file *id){
  2215         -  UNUSED_PARAMETER(id);
         2236  +  winFile *p = (winFile*)id;
  2216   2237     return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
  2217         -         SQLITE_IOCAP_ZERO_DAMAGE;
         2238  +         ((p->ctrlFlags & WINFILE_ZERO_DAMAGE)?SQLITE_IOCAP_ZERO_DAMAGE:0);
  2218   2239   }
  2219   2240   
  2220   2241   #ifndef SQLITE_OMIT_WAL
  2221   2242   
  2222   2243   /* 
  2223   2244   ** Windows will only let you create file view mappings
  2224   2245   ** on allocation size granularity boundaries.
................................................................................
  3000   3021   #if SQLITE_OS_WINCE
  3001   3022     int isTemp = 0;
  3002   3023   #endif
  3003   3024     winFile *pFile = (winFile*)id;
  3004   3025     void *zConverted;              /* Filename in OS encoding */
  3005   3026     const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
  3006   3027     int cnt = 0;
         3028  +  const char *zZeroDam;          /* Value of zero_damage query parameter */
  3007   3029   
  3008   3030     /* If argument zPath is a NULL pointer, this function is required to open
  3009   3031     ** a temporary file. Use this buffer to store the file name in.
  3010   3032     */
  3011   3033     char zTmpname[MAX_PATH+1];     /* Buffer used to create temp filename */
  3012   3034   
  3013   3035     int rc = SQLITE_OK;            /* Function Return Code */
................................................................................
  3175   3197     memset(pFile, 0, sizeof(*pFile));
  3176   3198     pFile->pMethod = &winIoMethod;
  3177   3199     pFile->h = h;
  3178   3200     pFile->lastErrno = NO_ERROR;
  3179   3201     pFile->pVfs = pVfs;
  3180   3202     pFile->pShm = 0;
  3181   3203     pFile->zPath = zName;
         3204  +  zZeroDam = sqlite3_uri_parameter(zName, "zero_damage");
         3205  +  if( zZeroDam==0 ) zZeroDam = "1";
         3206  +  pFile->ctrlFlags = atoi(zZeroDam) ? WINFILE_ZERO_DAMAGE : 1;
  3182   3207     pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
  3183   3208   
  3184   3209   #if SQLITE_OS_WINCE
  3185   3210     if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
  3186   3211          && !winceCreateLock(zName, pFile)
  3187   3212     ){
  3188   3213       osCloseHandle(h);

Changes to src/sqlite.h.in.

   769    769   ** have write permission on the directory containing the database file want
   770    770   ** to read the database file, as the WAL and shared memory files must exist
   771    771   ** in order for the database to be readable.  The fourth parameter to
   772    772   ** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
   773    773   ** That integer is 0 to disable persistent WAL mode or 1 to enable persistent
   774    774   ** WAL mode.  If the integer is -1, then it is overwritten with the current
   775    775   ** WAL persistence setting.
          776  +**
          777  +** ^The [SQLITE_FCNTL_ZERO_DAMAGE] opcode is used to set or query the
          778  +** persistent zero-damage setting.  The zero-damage setting determines
          779  +** the [SQLITE_IOCAP_ZERO_DAMAGE] bit of the xDeviceCharacteristics methods.
          780  +** The fourth parameter to
          781  +** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
          782  +** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage
          783  +** mode.  If the integer is -1, then it is overwritten with the current
          784  +** zero-damage mode setting.
   776    785   **
   777    786   ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
   778    787   ** a write transaction to indicate that, unless it is rolled back for some
   779    788   ** reason, the entire database file will be overwritten by the current 
   780    789   ** transaction. This is used by VACUUM operations.
   781    790   **
   782    791   ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
................................................................................
   798    807   #define SQLITE_FCNTL_CHUNK_SIZE       6
   799    808   #define SQLITE_FCNTL_FILE_POINTER     7
   800    809   #define SQLITE_FCNTL_SYNC_OMITTED     8
   801    810   #define SQLITE_FCNTL_WIN32_AV_RETRY   9
   802    811   #define SQLITE_FCNTL_PERSIST_WAL     10
   803    812   #define SQLITE_FCNTL_OVERWRITE       11
   804    813   #define SQLITE_FCNTL_VFSNAME         12
          814  +#define SQLITE_FCNTL_ZERO_DAMAGE     13
   805    815   
   806    816   /*
   807    817   ** CAPI3REF: Mutex Handle
   808    818   **
   809    819   ** The mutex module within SQLite defines [sqlite3_mutex] to be an
   810    820   ** abstract type for a mutex object.  The SQLite core never looks
   811    821   ** at the internal representation of an [sqlite3_mutex].  It only

Changes to src/tclsqlite.c.

  2996   2996         int b;
  2997   2997         if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
  2998   2998         if( b ){
  2999   2999           flags |= SQLITE_OPEN_FULLMUTEX;
  3000   3000           flags &= ~SQLITE_OPEN_NOMUTEX;
  3001   3001         }else{
  3002   3002           flags &= ~SQLITE_OPEN_FULLMUTEX;
         3003  +      }
         3004  +    }else if( strcmp(zArg, "-uri")==0 ){
         3005  +      int b;
         3006  +      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3007  +      if( b ){
         3008  +        flags |= SQLITE_OPEN_URI;
         3009  +      }else{
         3010  +        flags &= ~SQLITE_OPEN_URI;
  3003   3011         }
  3004   3012       }else{
  3005   3013         Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
  3006   3014         return TCL_ERROR;
  3007   3015       }
  3008   3016     }
  3009   3017     if( objc<3 || (objc&1)!=1 ){

Changes to src/test1.c.

  5231   5231     if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
  5232   5232     rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
  5233   5233     sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
  5234   5234     Tcl_AppendResult(interp, z, (char*)0);
  5235   5235     return TCL_OK;  
  5236   5236   }
  5237   5237   
         5238  +/*
         5239  +** tclcmd:   file_control_zero_damage DB ZERO-DAMAGE-FLAG
         5240  +**
         5241  +** This TCL command runs the sqlite3_file_control interface with
         5242  +** the SQLITE_FCNTL_ZERO_DAMAGE opcode.
         5243  +*/
         5244  +static int file_control_zero_damage(
         5245  +  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
         5246  +  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
         5247  +  int objc,              /* Number of arguments */
         5248  +  Tcl_Obj *CONST objv[]  /* Command arguments */
         5249  +){
         5250  +  sqlite3 *db;
         5251  +  int rc;
         5252  +  int bDamage;
         5253  +  char z[100];
         5254  +
         5255  +  if( objc!=3 ){
         5256  +    Tcl_AppendResult(interp, "wrong # args: should be \"",
         5257  +        Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
         5258  +    return TCL_ERROR;
         5259  +  }
         5260  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
         5261  +    return TCL_ERROR;
         5262  +  }
         5263  +  if( Tcl_GetIntFromObj(interp, objv[2], &bDamage) ) return TCL_ERROR;
         5264  +  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_ZERO_DAMAGE,(void*)&bDamage);
         5265  +  sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bDamage);
         5266  +  Tcl_AppendResult(interp, z, (char*)0);
         5267  +  return TCL_OK;  
         5268  +}
         5269  +
  5238   5270   
  5239   5271   /*
  5240   5272   ** tclcmd:   file_control_vfsname DB ?AUXDB?
  5241   5273   **
  5242   5274   ** Return a string that describes the stack of VFSes.
  5243   5275   */
  5244   5276   static int file_control_vfsname(
................................................................................
  6089   6121        { "file_control_test",          file_control_test,   0   },
  6090   6122        { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
  6091   6123        { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
  6092   6124        { "file_control_chunksize_test", file_control_chunksize_test,  0   },
  6093   6125        { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
  6094   6126        { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
  6095   6127        { "file_control_persist_wal",    file_control_persist_wal,     0   },
         6128  +     { "file_control_zero_damage",    file_control_zero_damage,     0   },
  6096   6129        { "file_control_vfsname",        file_control_vfsname,         0   },
  6097   6130        { "sqlite3_vfs_list",           vfs_list,     0   },
  6098   6131        { "sqlite3_create_function_v2", test_create_function_v2, 0 },
  6099   6132   
  6100   6133        /* Functions from os.h */
  6101   6134   #ifndef SQLITE_OMIT_UTF16
  6102   6135        { "add_test_collate",        test_collate, 0            },

Added test/zerodamage.test.

            1  +# 2011 December 21
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# 
           12  +# This file implements tests of the SQLITE_IOCAP_ZERO_DAMAGE property
           13  +# and the SQLITE_FCNTL_ZERO_DAMAGE file-control for manipulating it.
           14  +#
           15  +
           16  +set testdir [file dirname $argv0]
           17  +source $testdir/tester.tcl
           18  +set testprefix wal5
           19  +
           20  +# ZERO_DAMAGE defaults to true
           21  +#
           22  +do_test zerodamage-1.0 {
           23  +  file_control_zero_damage db -1
           24  +} {0 1}
           25  +
           26  +# Check the ability to turn zero-damage on and off.
           27  +#
           28  +do_test zerodamage-1.1 {
           29  +  file_control_zero_damage db 0
           30  +  file_control_zero_damage db -1
           31  +} {0 0}
           32  +do_test zerodamage-1.2 {
           33  +  file_control_zero_damage db 1
           34  +  file_control_zero_damage db -1
           35  +} {0 1}
           36  +
           37  +# Run a transaction with zero-damage on, a small page size and a much larger
           38  +# sectorsize.  Verify that the maximum journal size is small - that the
           39  +# rollback journal is not being padded.
           40  +#
           41  +do_test zerodamage-2.0 {
           42  +  db close
           43  +  testvfs tv -default 1
           44  +  tv sectorsize 8192
           45  +  sqlite3 db file:test.db?zero_damage=1 -uri 1
           46  +  unset -nocomplain ::max_journal_size
           47  +  set ::max_journal_size 0
           48  +  proc xDeleteCallback {method file args} {
           49  +    set sz [file size $file]
           50  +    if {$sz>$::max_journal_size} {set ::max_journal_size $sz}
           51  +  }
           52  +  tv filter xDelete
           53  +  tv script xDeleteCallback
           54  +  register_wholenumber_module db
           55  +  db eval {
           56  +    PRAGMA page_size=1024;
           57  +    PRAGMA journal_mode=DELETE;
           58  +    PRAGMA cache_size=5;
           59  +    CREATE VIRTUAL TABLE nums USING wholenumber;
           60  +    CREATE TABLE t1(x, y);
           61  +    INSERT INTO t1 SELECT value, randomblob(100) FROM nums
           62  +                    WHERE value BETWEEN 1 AND 400;
           63  +  }
           64  +  set ::max_journal_size 0
           65  +  db eval {
           66  +    UPDATE t1 SET y=randomblob(50) WHERE x=123;
           67  +  }
           68  +  concat [file_control_zero_damage db -1] [set ::max_journal_size]
           69  +} {0 1 2576}
           70  +
           71  +# Repeat the previous step with zero-damage turned off.  This time the
           72  +# maximum rollback journal size should be much larger.
           73  +#
           74  +do_test zerodamage-2.1 {
           75  +  set ::max_journal_size 0
           76  +  db close
           77  +  sqlite3 db file:test.db?zero_damage=0 -uri 1
           78  +  db eval {
           79  +    UPDATE t1 SET y=randomblob(50) WHERE x=124;
           80  +  }
           81  +  concat [file_control_zero_damage db -1] [set ::max_journal_size]
           82  +} {0 0 24704}
           83  +
           84  +# Run a WAL-mode transaction with ZERO_DAMAGE on to verify that the
           85  +# WAL file does not get too big.
           86  +#
           87  +do_test zerodamage-3.0 {
           88  +  db eval {
           89  +     PRAGMA journal_mode=WAL;
           90  +  }
           91  +  db close
           92  +  sqlite3 db file:test.db?zero_damage=1 -uri 1
           93  +  db eval {
           94  +     UPDATE t1 SET y=randomblob(50) WHERE x=124;
           95  +  }
           96  +  file size test.db-wal
           97  +} {1080}
           98  +
           99  +# Repeat the previous with ZERO_DAMAGE off.  Verify that the WAL file
          100  +# is padded.
          101  +#
          102  +do_test zerodamage-3.1 {
          103  +  db close
          104  +  sqlite3 db file:test.db?zero_damage=0 -uri 1
          105  +  db eval {
          106  +     UPDATE t1 SET y=randomblob(50) WHERE x=124;
          107  +  }
          108  +  file size test.db-wal
          109  +} {8416}