aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2011-12-21 14:42:29 +0000
committerdrh <drh@noemail.net>2011-12-21 14:42:29 +0000
commitf12b3f609f08e923833bc6c37863f11a82582c03 (patch)
treeeac19e5f30021873963f5f39db83917425ab8931 /src
parentf694aa6454630efdb04a7cb9f0d91c0fe5376770 (diff)
downloadsqlite-f12b3f609f08e923833bc6c37863f11a82582c03.tar.gz
sqlite-f12b3f609f08e923833bc6c37863f11a82582c03.zip
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. FossilOrigin-Name: c83627b73285f883719845c1b9fe85f378f28dd2
Diffstat (limited to 'src')
-rw-r--r--src/main.c1
-rw-r--r--src/os_unix.c66
-rw-r--r--src/os_win.c43
-rw-r--r--src/sqlite.h.in10
-rw-r--r--src/tclsqlite.c8
-rw-r--r--src/test1.c33
6 files changed, 132 insertions, 29 deletions
diff --git a/src/main.c b/src/main.c
index 690b73c2e..ea64d8be9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2977,6 +2977,7 @@ int sqlite3_test_control(int op, ...){
** returns a NULL pointer.
*/
const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
+ if( zFilename==0 ) return 0;
zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] ){
int x = strcmp(zFilename, zParam);
diff --git a/src/os_unix.c b/src/os_unix.c
index a9d7de832..4a31c8cde 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -215,13 +215,13 @@ struct unixFile {
int h; /* The file descriptor */
unsigned char eFileLock; /* The type of lock held on this fd */
unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
+ unsigned char szSector; /* Sectorsize/512 */
int lastErrno; /* The unix errno from last I/O error */
void *lockingContext; /* Locking style specific state */
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
- int szSector; /* Sector size */
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
@@ -263,6 +263,7 @@ struct unixFile {
#else
# define UNIXFILE_DIRSYNC 0x00
#endif
+#define UNIXFILE_ZERO_DAMAGE 0x10 /* True if SQLITE_IOCAP_ZERO_DAMAGE */
/*
** Include code that is common to all os_*.c files
@@ -3512,6 +3513,22 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
}
/*
+** If *pArg is inititially negative then this is a query. Set *pArg to
+** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
+**
+** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
+*/
+static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
+ if( *pArg<0 ){
+ *pArg = (pFile->ctrlFlags & mask)!=0;
+ }else if( (*pArg)==0 ){
+ pFile->ctrlFlags &= ~mask;
+ }else{
+ pFile->ctrlFlags |= mask;
+ }
+}
+
+/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
@@ -3537,14 +3554,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
return rc;
}
case SQLITE_FCNTL_PERSIST_WAL: {
- int bPersist = *(int*)pArg;
- if( bPersist<0 ){
- *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
- }else if( bPersist==0 ){
- pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
- }else{
- pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
- }
+ unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_ZERO_DAMAGE: {
+ unixModeBit(pFile, UNIXFILE_ZERO_DAMAGE, (int*)pArg);
return SQLITE_OK;
}
case SQLITE_FCNTL_VFSNAME: {
@@ -3589,27 +3603,37 @@ static int unixSectorSize(sqlite3_file *pFile){
unixFile *p = (unixFile*)pFile;
if( p->szSector==0 ){
#ifdef MISSING_STATVFS
- p->szSector = SQLITE_DEFAULT_SECTOR_SIZE;
+ p->szSector = SQLITE_DEFAULT_SECTOR_SIZE/512;
#else
struct statvfs x;
int sz;
memset(&x, 0, sizeof(x));
osStatvfs(p->zPath, &x);
- p->szSector = sz = (int)x.f_frsize;
+ sz = (int)x.f_frsize;
if( sz<512 || sz>65536 || (sz&(sz-1))!=0 ){
- p->szSector = SQLITE_DEFAULT_SECTOR_SIZE;
+ sz = SQLITE_DEFAULT_SECTOR_SIZE;
}
+ p->szSector = sz/512;
#endif
}
- return p->szSector;
+ return p->szSector*512;
}
/*
-** Return the device characteristics for the file. This is always 0 for unix.
+** Return the device characteristics for the file.
+**
+** This VFS is set up to return SQLITE_IOCAP_ZERO_DAMAGE by default.
+** However, that choice is contraversial sicne technically the underlying
+** file system does not always provide ZERO_DAMAGE. (In other words, after
+** a power-loss event, parts of the file that were never written might end
+** up being altered.) However, non-ZERO-DAMAGE behavior is very, very rare.
+** And asserting ZERO_DAMAGE makes a large reduction in the amount of required
+** I/O. Hence, while ZERO_DAMAGE is on by default, there is a file-control
+** available to turn it off.
*/
-static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
- UNUSED_PARAMETER(NotUsed);
- return SQLITE_IOCAP_ZERO_DAMAGE;
+static int unixDeviceCharacteristics(sqlite3_file *id){
+ unixFile *p = (unixFile*)id;
+ return (p->ctrlFlags & UNIXFILE_ZERO_DAMAGE) ? SQLITE_IOCAP_ZERO_DAMAGE : 0;
}
#ifndef SQLITE_OMIT_WAL
@@ -4568,6 +4592,7 @@ static int fillInUnixFile(
const sqlite3_io_methods *pLockingStyle;
unixFile *pNew = (unixFile *)pId;
int rc = SQLITE_OK;
+ const char *zZeroDam; /* Value of the zero_damage query parameter */
assert( pNew->pInode==NULL );
@@ -4594,10 +4619,11 @@ static int fillInUnixFile(
pNew->h = h;
pNew->pVfs = pVfs;
pNew->zPath = zFilename;
+ zZeroDam = sqlite3_uri_parameter(zFilename, "zero_damage");
+ if( zZeroDam==0 ) zZeroDam = "1";
+ pNew->ctrlFlags = atoi(zZeroDam) ? UNIXFILE_ZERO_DAMAGE : 1;
if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
- pNew->ctrlFlags = UNIXFILE_EXCL;
- }else{
- pNew->ctrlFlags = 0;
+ pNew->ctrlFlags |= UNIXFILE_EXCL;
}
if( isReadOnly ){
pNew->ctrlFlags |= UNIXFILE_RDONLY;
diff --git a/src/os_win.c b/src/os_win.c
index 5e0667d18..ec4d062f9 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -59,7 +59,7 @@ struct winFile {
HANDLE h; /* Handle for accessing the file */
u8 locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
- u8 bPersistWal; /* True to persist WAL files */
+ u8 ctrlFlags; /* Flags. See WINFILE_* below */
DWORD lastErrno; /* The Windows errno from the last I/O error */
DWORD sectorSize; /* Sector size of the device file is on */
winShm *pShm; /* Instance of shared memory on this file */
@@ -75,6 +75,12 @@ struct winFile {
};
/*
+** Allowed values for winFile.ctrlFlags
+*/
+#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
+#define WINFILE_ZERO_DAMAGE 0x10 /* True if SQLITE_IOCAP_ZERO_DAMAGE */
+
+/*
* If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
* various Win32 API heap functions instead of our own.
*/
@@ -2126,6 +2132,22 @@ static int winUnlock(sqlite3_file *id, int locktype){
}
/*
+** If *pArg is inititially negative then this is a query. Set *pArg to
+** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
+**
+** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
+*/
+static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
+ if( *pArg<0 ){
+ *pArg = (pFile->ctrlFlags & mask)!=0;
+ }else if( (*pArg)==0 ){
+ pFile->ctrlFlags &= ~mask;
+ }else{
+ pFile->ctrlFlags |= mask;
+ }
+}
+
+/*
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){
@@ -2160,12 +2182,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
return SQLITE_OK;
}
case SQLITE_FCNTL_PERSIST_WAL: {
- int bPersist = *(int*)pArg;
- if( bPersist<0 ){
- *(int*)pArg = pFile->bPersistWal;
- }else{
- pFile->bPersistWal = bPersist!=0;
- }
+ winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_ZERO_DAMAGE: {
+ winModeBit(pFile, WINFILE_ZERO_DAMAGE, (int*)pArg);
return SQLITE_OK;
}
case SQLITE_FCNTL_VFSNAME: {
@@ -2212,9 +2233,9 @@ static int winSectorSize(sqlite3_file *id){
** Return a vector of device characteristics.
*/
static int winDeviceCharacteristics(sqlite3_file *id){
- UNUSED_PARAMETER(id);
+ winFile *p = (winFile*)id;
return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
- SQLITE_IOCAP_ZERO_DAMAGE;
+ ((p->ctrlFlags & WINFILE_ZERO_DAMAGE)?SQLITE_IOCAP_ZERO_DAMAGE:0);
}
#ifndef SQLITE_OMIT_WAL
@@ -3004,6 +3025,7 @@ static int winOpen(
void *zConverted; /* Filename in OS encoding */
const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
int cnt = 0;
+ const char *zZeroDam; /* Value of zero_damage query parameter */
/* If argument zPath is a NULL pointer, this function is required to open
** a temporary file. Use this buffer to store the file name in.
@@ -3179,6 +3201,9 @@ static int winOpen(
pFile->pVfs = pVfs;
pFile->pShm = 0;
pFile->zPath = zName;
+ zZeroDam = sqlite3_uri_parameter(zName, "zero_damage");
+ if( zZeroDam==0 ) zZeroDam = "1";
+ pFile->ctrlFlags = atoi(zZeroDam) ? WINFILE_ZERO_DAMAGE : 1;
pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index f7a2616ba..e036449d0 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -774,6 +774,15 @@ struct sqlite3_io_methods {
** WAL mode. If the integer is -1, then it is overwritten with the current
** WAL persistence setting.
**
+** ^The [SQLITE_FCNTL_ZERO_DAMAGE] opcode is used to set or query the
+** persistent zero-damage setting. The zero-damage setting determines
+** the [SQLITE_IOCAP_ZERO_DAMAGE] bit of the xDeviceCharacteristics methods.
+** The fourth parameter to
+** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
+** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage
+** mode. If the integer is -1, then it is overwritten with the current
+** zero-damage mode setting.
+**
** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
** a write transaction to indicate that, unless it is rolled back for some
** reason, the entire database file will be overwritten by the current
@@ -802,6 +811,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_PERSIST_WAL 10
#define SQLITE_FCNTL_OVERWRITE 11
#define SQLITE_FCNTL_VFSNAME 12
+#define SQLITE_FCNTL_ZERO_DAMAGE 13
/*
** CAPI3REF: Mutex Handle
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index c8f0fbd31..3692bef9c 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -3001,6 +3001,14 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{
flags &= ~SQLITE_OPEN_FULLMUTEX;
}
+ }else if( strcmp(zArg, "-uri")==0 ){
+ int b;
+ if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
+ if( b ){
+ flags |= SQLITE_OPEN_URI;
+ }else{
+ flags &= ~SQLITE_OPEN_URI;
+ }
}else{
Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
return TCL_ERROR;
diff --git a/src/test1.c b/src/test1.c
index 798366a8c..b96b99ce8 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -5235,6 +5235,38 @@ static int file_control_persist_wal(
return TCL_OK;
}
+/*
+** tclcmd: file_control_zero_damage DB ZERO-DAMAGE-FLAG
+**
+** This TCL command runs the sqlite3_file_control interface with
+** the SQLITE_FCNTL_ZERO_DAMAGE opcode.
+*/
+static int file_control_zero_damage(
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ sqlite3 *db;
+ int rc;
+ int bDamage;
+ char z[100];
+
+ if( objc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, objv[2], &bDamage) ) return TCL_ERROR;
+ rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_ZERO_DAMAGE,(void*)&bDamage);
+ sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bDamage);
+ Tcl_AppendResult(interp, z, (char*)0);
+ return TCL_OK;
+}
+
/*
** tclcmd: file_control_vfsname DB ?AUXDB?
@@ -6093,6 +6125,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
{ "file_control_persist_wal", file_control_persist_wal, 0 },
+ { "file_control_zero_damage", file_control_zero_damage, 0 },
{ "file_control_vfsname", file_control_vfsname, 0 },
{ "sqlite3_vfs_list", vfs_list, 0 },
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },