aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2007-08-31 16:11:35 +0000
committerdrh <drh@noemail.net>2007-08-31 16:11:35 +0000
commitcc6bb3eaebcff254e9ddb4d0f204656cf78d107b (patch)
treea5f588f960c518cc14dbd2e5d55242ee2a499ed9 /src
parent3570ad93d8325611dc61a6f01d1c7ce0d7277c03 (diff)
downloadsqlite-cc6bb3eaebcff254e9ddb4d0f204656cf78d107b.tar.gz
sqlite-cc6bb3eaebcff254e9ddb4d0f204656cf78d107b.zip
Initial implementation of the sqlite3_file_control() interface.
Compiles and passes all historical tests but the new method is itself untested. (CVS 4353) FossilOrigin-Name: d3ab3e3911f10b17d0859a34f4f007c790a0cd82
Diffstat (limited to 'src')
-rw-r--r--src/loadext.c1
-rw-r--r--src/main.c35
-rw-r--r--src/os.c6
-rw-r--r--src/os.h2
-rw-r--r--src/os_unix.c17
-rw-r--r--src/os_win.c6
-rw-r--r--src/pager.c11
-rw-r--r--src/pager.h3
-rw-r--r--src/sqlite.h.in44
-rw-r--r--src/sqlite3ext.h4
-rw-r--r--src/test6.c6
11 files changed, 107 insertions, 28 deletions
diff --git a/src/loadext.c b/src/loadext.c
index 2f0e81f77..2ae3aabe8 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -256,6 +256,7 @@ const sqlite3_api_routines sqlite3_apis = {
sqlite3_blob_read,
sqlite3_blob_write,
sqlite3_create_collation_v2,
+ sqlite3_file_control,
sqlite3_memory_highwater,
sqlite3_memory_used,
#ifdef SQLITE_MUTEX_NOOP
diff --git a/src/main.c b/src/main.c
index eda460fd8..a6db28352 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.400 2007/08/30 20:09:48 drh Exp $
+** $Id: main.c,v 1.401 2007/08/31 16:11:36 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -1432,3 +1432,36 @@ int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
+
+/*
+** Invoke the xFileControl method on a particular database.
+*/
+int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
+ int rc = SQLITE_ERROR;
+ int iDb;
+ sqlite3_mutex_enter(db->mutex);
+ if( zDbName==0 ){
+ iDb = 0;
+ }else{
+ for(iDb=0; iDb<db->nDb; iDb++){
+ if( strcmp(db->aDb[iDb].zName, zDbName)==0 ) break;
+ }
+ }
+ if( iDb<db->nDb ){
+ Btree *pBtree = db->aDb[iDb].pBt;
+ if( pBtree ){
+ Pager *pPager;
+ sqlite3BtreeEnter(pBtree);
+ pPager = sqlite3BtreePager(pBtree);
+ if( pPager ){
+ sqlite3_file *fd = sqlite3PagerFile(pPager);
+ if( fd ){
+ rc = sqlite3OsFileControl(fd, op, pArg);
+ }
+ }
+ sqlite3BtreeLeave(pBtree);
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
diff --git a/src/os.c b/src/os.c
index f1d65ab6b..8ca0185d9 100644
--- a/src/os.c
+++ b/src/os.c
@@ -52,12 +52,12 @@ int sqlite3OsLock(sqlite3_file *id, int lockType){
int sqlite3OsUnlock(sqlite3_file *id, int lockType){
return id->pMethods->xUnlock(id, lockType);
}
-int sqlite3OsBreakLock(sqlite3_file *id){
- return id->pMethods->xBreakLock(id);
-}
int sqlite3OsCheckReservedLock(sqlite3_file *id){
return id->pMethods->xCheckReservedLock(id);
}
+int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
+ return id->pMethods->xFileControl(id,op,pArg);
+}
#ifdef SQLITE_TEST
/* The following two variables are used to override the values returned
diff --git a/src/os.h b/src/os.h
index e5c8e7bc6..1570aecc9 100644
--- a/src/os.h
+++ b/src/os.h
@@ -239,9 +239,9 @@ int sqlite3OsSync(sqlite3_file*, int);
int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
int sqlite3OsLock(sqlite3_file*, int);
int sqlite3OsUnlock(sqlite3_file*, int);
-int sqlite3OsBreakLock(sqlite3_file*);
int sqlite3OsCheckReservedLock(sqlite3_file *id);
int sqlite3OsLockState(sqlite3_file *id);
+int sqlite3OsFileControl(sqlite3_file*,int,void*);
int sqlite3OsSectorSize(sqlite3_file *id);
int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
diff --git a/src/os_unix.c b/src/os_unix.c
index c46d82407..54674f7c7 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -2016,11 +2016,10 @@ static int nolockUnixClose(sqlite3_file *id) {
/*
-** TODO: xBreakLock() for this vfs.
+** No xFileControl opcodes are implemented by this VFS.
*/
-static int unixBreakLock(sqlite3_file *id){
- assert(!"TODO: unixBreakLock()");
- return 0;
+static int unixFileControl(sqlite3_file *id, int op, void *pArg){
+ return SQLITE_ERROR;
}
/*
@@ -2067,8 +2066,8 @@ static const sqlite3_io_methods sqlite3UnixIoMethod = {
unixLock,
unixUnlock,
unixCheckReservedLock,
- unixBreakLock,
unixLockState,
+ unixFileControl,
unixSectorSize,
unixDeviceCharacteristics
};
@@ -2089,8 +2088,8 @@ static const sqlite3_io_methods sqlite3AFPLockingUnixIoMethod = {
afpUnixLock,
afpUnixUnlock,
afpUnixCheckReservedLock,
- unixBreakLock,
unixLockState,
+ unixFileControl,
unixSectorSize,
unixDeviceCharacteristics
};
@@ -2110,8 +2109,8 @@ static const sqlite3_io_methods sqlite3FlockLockingUnixIoMethod = {
flockUnixLock,
flockUnixUnlock,
flockUnixCheckReservedLock,
- unixBreakLock,
unixLockState,
+ unixFileControl,
unixSectorSize,
unixDeviceCharacteristics
};
@@ -2131,8 +2130,8 @@ static const sqlite3_io_methods sqlite3DotlockLockingUnixIoMethod = {
dotlockUnixLock,
dotlockUnixUnlock,
dotlockUnixCheckReservedLock,
- unixBreakLock,
unixLockState,
+ unixFileControl,
unixSectorSize,
unixDeviceCharacteristics
};
@@ -2152,8 +2151,8 @@ static const sqlite3_io_methods sqlite3NolockLockingUnixIoMethod = {
nolockUnixLock,
nolockUnixUnlock,
nolockUnixCheckReservedLock,
- unixBreakLock,
unixLockState,
+ unixFileControl,
unixSectorSize,
unixDeviceCharacteristics
};
diff --git a/src/os_win.c b/src/os_win.c
index 0cd6a24f6..233195f0f 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -977,9 +977,9 @@ static int winUnlock(sqlite3_file *id, int locktype){
}
/*
-** Currently unimplemented
+** No xFileControl operations are currently implemented.
*/
-static int winBreakLock(sqlite3_file *id){
+static int winFileControl(sqlite3_file *id){
return SQLITE_ERROR;
}
@@ -1028,8 +1028,8 @@ static const sqlite3_io_methods winIoMethod = {
winLock,
winUnlock,
winCheckReservedLock,
- winBreakLock,
winLockState,
+ winFileControl,
winSectorSize,
winDeviceCharacteristics
};
diff --git a/src/pager.c b/src/pager.c
index fd364ae51..59ef3e804 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.381 2007/08/30 08:08:17 danielk1977 Exp $
+** @(#) $Id: pager.c,v 1.382 2007/08/31 16:11:36 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
@@ -4823,6 +4823,15 @@ const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
}
/*
+** Return the file handle for the database file associated
+** with the pager. This might return NULL if the file has
+** not yet been opened.
+*/
+sqlite3_file *sqlite3PagerFile(Pager *pPager){
+ return pPager->fd;
+}
+
+/*
** Return the directory of the database file.
*/
const char *sqlite3PagerDirname(Pager *pPager){
diff --git a/src/pager.h b/src/pager.h
index 7402dd74e..4933d0069 100644
--- a/src/pager.h
+++ b/src/pager.h
@@ -13,7 +13,7 @@
** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback.
**
-** @(#) $Id: pager.h,v 1.64 2007/08/29 12:31:27 danielk1977 Exp $
+** @(#) $Id: pager.h,v 1.65 2007/08/31 16:11:36 drh Exp $
*/
#ifndef _PAGER_H_
@@ -86,6 +86,7 @@ int sqlite3PagerRefcount(Pager*);
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
const char *sqlite3PagerFilename(Pager*);
const sqlite3_vfs *sqlite3PagerVfs(Pager*);
+sqlite3_file *sqlite3PagerFile(Pager*);
const char *sqlite3PagerDirname(Pager*);
const char *sqlite3PagerJournalname(Pager*);
int sqlite3PagerNosync(Pager*);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 780fb87bc..4ec7226da 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -30,7 +30,7 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
-** @(#) $Id: sqlite.h.in,v 1.251 2007/08/30 20:09:48 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.252 2007/08/31 16:11:36 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@@ -472,9 +472,20 @@ struct sqlite3_file {
** PENDING, or EXCLUSIVE lock on the file. It returns true
** if such a lock exists and false if not.
**
-** xBreakLock() attempts to break a lock held by another process.
-** This can be used to remove a stale dot-file lock, for example.
-** It returns 0 on success and non-zero for a failure.
+** The xFileControl() method is a generic interface that allows custom
+** VFS implementations to directly control an open file using the
+** [sqlite3_file_control()] interface. The second argument (the
+** "op" argument) is intended to be an integer opcode. The third
+** argument is a generic pointer which is intended to be a pointer
+** to a structure that may contain arguments or space in which to
+** write return values. Potential uses for xFileControl() might be
+** functions to enable blocking locks with timeouts, to change the
+** locking strategy (for example to use dot-file locks), to inquire
+** about the status of a lock, or to break stale locks. No standard
+** xFileControl opcodes are currently defined, but this may change in
+** future releases. Applications that define a custom xFileControl
+** method should use opcodes greater than 100 to avoid conflicts
+** with future official opcodes which will be less than that value.
**
** The xSectorSize() method returns the sector size of the
** device that underlies the file. The sector size is the
@@ -520,8 +531,8 @@ struct sqlite3_io_methods {
int (*xLock)(sqlite3_file*, int);
int (*xUnlock)(sqlite3_file*, int);
int (*xCheckReservedLock)(sqlite3_file*);
- int (*xBreakLock)(sqlite3_file*);
int (*xLockState)(sqlite3_file *);
+ int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
/* Additional methods may be added in future releases */
@@ -3438,6 +3449,29 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
+/*
+** CAPI3REF: Low-Level Control Of Database Files
+**
+** The [sqlite3_file_control()] interface makes a direct call to the
+** xFileControl method for the [sqlite3_io_methods] object associated
+** with a particular database identified by the second argument. The
+** name of the database is the name assigned to the database by the
+** <a href="lang_attach.html">ATTACH</a> SQL command that opened the
+** database. To control the main database file, use the name "main"
+** or a NULL pointer. The third and fourth parameters to this routine
+** are passed directly through to the second and third parameters of
+** the xFileControl method. The return value of the xFileControl
+** method becomes the return value of this routine.
+**
+** If the second parameter (zDbName) does not match the name of any
+** open database file, then SQLITE_ERROR is returned. This error
+** code is not remembered and will not be recalled by [sqlite3_errcode()]
+** or [sqlite3_errmsg()]. The underlying xFileControl method might
+** also return SQLITE_ERROR. There is no way to distinguish between
+** an incorrect zDbName and an SQLITE_ERROR return from the underlying
+** xFileControl method.
+*/
+int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
/*
** Undo the hack that converts floating point types to integer for
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index 667650aca..5d4c2dec9 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -15,7 +15,7 @@
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
**
-** @(#) $Id: sqlite3ext.h,v 1.16 2007/08/30 17:15:38 drh Exp $
+** @(#) $Id: sqlite3ext.h,v 1.17 2007/08/31 16:11:36 drh Exp $
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
@@ -165,6 +165,7 @@ struct sqlite3_api_routines {
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*));
+ int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
sqlite3_mutex *(*mutex_alloc)(int);
@@ -324,6 +325,7 @@ struct sqlite3_api_routines {
#define sqlite3_blob_read sqlite3_api->blob_read
#define sqlite3_blob_write sqlite3_api->blob_write
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
+#define sqlite3_file_control sqlite3_api->file_control
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
#define sqlite3_memory_used sqlite3_api->memory_used
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
diff --git a/src/test6.c b/src/test6.c
index 6747fb613..5d47cc79c 100644
--- a/src/test6.c
+++ b/src/test6.c
@@ -476,8 +476,8 @@ static int cfCheckReservedLock(sqlite3_file *pFile){
static int cfLockState(sqlite3_file *pFile){
return sqlite3OsLockState(((CrashFile *)pFile)->pRealFile);
}
-static int cfBreakLock(sqlite3_file *pFile){
- return sqlite3OsBreakLock(((CrashFile *)pFile)->pRealFile);
+static int cfFileControl(sqlite3_file *pFile, int op, void *pArg){
+ return sqlite3OsFileControl(((CrashFile *)pFile)->pRealFile, op, pArg);
}
/*
@@ -503,8 +503,8 @@ static const sqlite3_io_methods CrashFileVtab = {
cfLock, /* xLock */
cfUnlock, /* xUnlock */
cfCheckReservedLock, /* xCheckReservedLock */
- cfBreakLock, /* xBreakLock */
cfLockState, /* xLockState */
+ cfFileControl, /* xFileControl */
cfSectorSize, /* xSectorSize */
cfDeviceCharacteristics /* xDeviceCharacteristics */
};