--- /dev/null
+/*
+** 2020-09-02
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** CREATE TABLE shmlock(
+** connid TEXT,
+** lock TEXT,
+** locktype TEXT,
+** mxFrame INTEGER,
+** dbname HIDDEN
+** );
+*/
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+/* shmlock_vtab is a subclass of sqlite3_vtab which is
+** underlying representation of the virtual table
+*/
+typedef struct shmlock_vtab shmlock_vtab;
+struct shmlock_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db;
+};
+
+/* shmlock_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct shmlock_cursor shmlock_cursor;
+struct shmlock_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ char *zFcntl;
+ int iFcntl;
+
+ const char *azCol[4];
+ int anCol[4];
+ sqlite3_int64 iRowid;
+};
+
+/*
+** Create a new shmlock_vtab object.
+*/
+static int shmlockConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ shmlock_vtab *pNew;
+ int rc;
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE shmlock("
+ "connid TEXT, "
+ "lock TEXT, "
+ "locktype TEXT, "
+ "mxFrame INTEGER,"
+ "dbname HIDDEN"
+ ");"
+ );
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for shmlock_vtab objects.
+*/
+static int shmlockDisconnect(sqlite3_vtab *pVtab){
+ shmlock_vtab *p = (shmlock_vtab*)pVtab;
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new shmlock_cursor object.
+*/
+static int shmlockOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ shmlock_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a shmlock_cursor.
+*/
+static int shmlockClose(sqlite3_vtab_cursor *cur){
+ shmlock_cursor *pCur = (shmlock_cursor*)cur;
+ sqlite3_free(pCur->zFcntl);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a shmlock_cursor to its next row of output.
+*/
+static int shmlockNext(sqlite3_vtab_cursor *cur){
+ shmlock_cursor *pCur = (shmlock_cursor*)cur;
+ int ii = pCur->iFcntl;
+ const char *z = pCur->zFcntl;
+ int iCol;
+
+ memset(pCur->azCol, 0, sizeof(char*)*4);
+ memset(pCur->anCol, 0, sizeof(int)*4);
+ for(iCol=0; iCol<4; iCol++){
+ pCur->azCol[iCol] = &z[ii];
+ while( z[ii]!=' ' && z[ii]!='\n' && z[ii]!='\0' ) ii++;
+ pCur->anCol[iCol] = &z[ii] - pCur->azCol[iCol];
+ if( z[ii]=='\0' ) break;
+ ii++;
+ if( z[ii-1]=='\n' ) break;
+ }
+
+ pCur->iFcntl = ii;
+ pCur->iRowid++;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the shmlock_cursor
+** is currently pointing.
+*/
+static int shmlockColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ shmlock_cursor *pCur = (shmlock_cursor*)cur;
+ if( i<=3 && pCur->azCol[i] ){
+ sqlite3_result_text(ctx, pCur->azCol[i], pCur->anCol[i], SQLITE_TRANSIENT);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int shmlockRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ shmlock_cursor *pCur = (shmlock_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int shmlockEof(sqlite3_vtab_cursor *cur){
+ shmlock_cursor *pCur = (shmlock_cursor*)cur;
+ return pCur->azCol[1]==0;
+}
+
+/*
+** This method is called to "rewind" the shmlock_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to shmlockColumn() or shmlockRowid() or
+** shmlockEof().
+*/
+static int shmlockFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ int rc;
+ shmlock_cursor *pCur = (shmlock_cursor *)pVtabCursor;
+ shmlock_vtab *pTab = (shmlock_vtab*)pVtabCursor->pVtab;
+ const char *zDb = "main";
+
+ if( idxNum==1 ){
+ assert( argc==1 );
+ zDb = (const char*)sqlite3_value_text(argv[0]);
+ }
+ sqlite3_free(pCur->zFcntl);
+ pCur->zFcntl = 0;
+ rc = sqlite3_file_control(
+ pTab->db, zDb, SQLITE_FCNTL_SHMLOCK_GET, (void*)&pCur->zFcntl
+ );
+ pCur->iRowid = 1;
+ pCur->iFcntl = 0;
+ if( rc==SQLITE_NOTFOUND ){
+ rc = SQLITE_OK;
+ }
+ if( pCur->zFcntl ){
+ rc = shmlockNext(pVtabCursor);
+ }
+ return rc;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int shmlockBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int ii;
+
+ /* Search for a dbname=? constraint. If one is found, set idxNum=1 and
+ ** pass the ? as the only argument to xFilter. Otherwise, leave idxNum=0
+ ** and pass no arguments to xFilter. */
+ for(ii=0; ii<pIdxInfo->nConstraint; ii++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
+ if( p->usable && p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==4 ){
+ pIdxInfo->aConstraintUsage[ii].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[ii].omit = 1;
+ pIdxInfo->idxNum = 1;
+ break;
+ }
+ }
+
+ pIdxInfo->estimatedCost = (double)10;
+ pIdxInfo->estimatedRows = 10;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** virtual table.
+*/
+static sqlite3_module shmlockModule = {
+ /* iVersion */ 0,
+ /* xCreate */ 0,
+ /* xConnect */ shmlockConnect,
+ /* xBestIndex */ shmlockBestIndex,
+ /* xDisconnect */ shmlockDisconnect,
+ /* xDestroy */ 0,
+ /* xOpen */ shmlockOpen,
+ /* xClose */ shmlockClose,
+ /* xFilter */ shmlockFilter,
+ /* xNext */ shmlockNext,
+ /* xEof */ shmlockEof,
+ /* xColumn */ shmlockColumn,
+ /* xRowid */ shmlockRowid,
+ /* xUpdate */ 0,
+ /* xBegin */ 0,
+ /* xSync */ 0,
+ /* xCommit */ 0,
+ /* xRollback */ 0,
+ /* xFindMethod */ 0,
+ /* xRename */ 0,
+ /* xSavepoint */ 0,
+ /* xRelease */ 0,
+ /* xRollbackTo */ 0,
+ /* xShadowName */ 0
+};
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_shmlockvtab_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_module(db, "shmlock", &shmlockModule, 0);
+ return rc;
+}
$(TOP)/ext/misc/regexp.c \
$(TOP)/ext/misc/remember.c \
$(TOP)/ext/misc/series.c \
+ $(TOP)/ext/misc/shmlockvtab.c \
$(TOP)/ext/misc/spellfix.c \
$(TOP)/ext/misc/totype.c \
$(TOP)/ext/misc/unionvtab.c \
-C In\sthe\sLemon\soutput,\sadd\sa\sprefix\scomment\sthat\sexplains\sthat\sthe\soutput\sfile\nis\sautomatically\sgenerated\sand\sshows\sthe\sname\sof\sthe\ssource\sfile.
-D 2020-09-01T12:26:55.781
+C Add\sfile-controls\sand\sa\svtab\sfrontend\sfor\squerying\sthe\sunix\sVFS\sfor\sthe\scurrently\sheld\sshm-locks.\sStill\ssome\sissues.
+D 2020-09-01T20:56:28.962
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/misc/series.c 4057dda3579b38ff88b2d3b13b4dd92dbd9d6f90dac2b55c19b0a8ed87ee4959
F ext/misc/sha1.c c8f2253c8792ffab9517695ea7d88c079f0395a5505eefef5c8198fe184ed5ac
F ext/misc/shathree.c 135b7c145db4a09b1650c3e7aff9cb538763a9a361e834c015dd1aaf8d5c9a00
+F ext/misc/shmlockvtab.c 2cf63c9c57c47e551a92fe1f126f718a67a2de7d3714a6183b548ef3585a3639 w ext/misc/shmlocksvtab.c
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f
F ext/misc/sqlar.c 0ace5d3c10fe736dc584bf1159a36b8e2e60fab309d310cd8a0eecd9036621b6
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk b1cd0bc6aedad7ebb667b7f74f835f932f60ee33be2a5c3051fd93eb465f5c75
+F main.mk 9702e0f4d4c530f3516fc062255c0874e5044000bfb81a5210507399ca2054ac
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
-F src/os_unix.c d707ed2867a2fb32101469327acf3274165d9935e9ab9e27bdab0c1a7d661be7
+F src/os_unix.c 1f65273dc9635f4aeab61c4893d3cb809008c9658c5fce56bc069618f0cfa6eb
F src/os_win.c a2149ff0a85c1c3f9cc102a46c673ce87e992396ba3411bfb53db66813b32f1d
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 3700a1c55427a3d4168ad1f1b8a8b0cb9ace1d107e4506e30a8f1e66d8a1195e
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 233e884d7da6601486c7b93aedb97fd29302ae5c03742d0e0eccb4790638bb77
F src/shell.c.in 9bae0c8397e7b592fb404678c4c1fc7944d9dc798a928d1eb40bcd608c33d21b
-F src/sqlite.h.in 473a79ff2c5c6d54a09af88206ea4d02c4b74558f7d29315a4ede05da8eb8732
+F src/sqlite.h.in 67c266c9e0893f8959ccba1de14b21df9c284315a60f2bb040adbbf82868389c
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197
F src/sqliteInt.h d8d69318b1ba3906d4860da1cd1c6b3650b81c9595e5bc360c6469a1e54e09e1
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 986b6391f02cd9b53c1d688be55899f6ffddeb8e8014cd83c1b73ff912579a71
-F src/test1.c 9e52fb797bf74fa327295df38881aa3ade0824bfb0c14abd0719e555b169fd55
+F src/test1.c 1cfa55932b81c8f3980f6983b3f77a7836c2f8e53da1d39d7e831444e714f8a3
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 84d54eb35716174195ee7e5ac846f47308e5dbb0056e8ff568daa133860bab74
-R 7f45e5b59f1c52d29dee23ebb0c2337a
-U drh
-Z 0e6fd8fbc683d31bd259b25e22ecc736
+P d34caf3bb63d0512ea116a8c8c8343b76aa39441bd4b3e98231747a705b91d54
+R 70d4b88230a783c0d9a1569eb690c6e9
+T *branch * shmlock-vtab
+T *sym-shmlock-vtab *
+T -sym-trunk *
+U dan
+Z 051d13975a42f6e641461833c8ed92f1
-d34caf3bb63d0512ea116a8c8c8343b76aa39441bd4b3e98231747a705b91d54
\ No newline at end of file
+ef10e1b386d7a9028eab64e1f4802e3d6b2df11c6723130a29e5effc8dcb2e80
\ No newline at end of file
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
+ char *zShmlockName;
#if SQLITE_MAX_MMAP_SIZE>0
int nFetchOut; /* Number of outstanding xFetch refs */
sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
OSTRACE(("CLOSE %-3d\n", pFile->h));
OpenCounter(-1);
sqlite3_free(pFile->pPreallocatedUnused);
+ sqlite3_free(pFile->zShmlockName);
memset(pFile, 0, sizeof(unixFile));
return SQLITE_OK;
}
}
}
-/* Forward declaration */
+/* Forward declarations used by file-control implementations */
static int unixGetTempname(int nBuf, char *zBuf);
+static int unixFcntlShmlockGet(unixFile *pFile, char **pzOut);
+static int unixFcntlShmlockName(unixFile *pFile, const char *zName);
/*
** Information and control of an open file handle.
return proxyFileControl(id,op,pArg);
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
+#ifndef SQLITE_OMIT_WAL
+ case SQLITE_FCNTL_SHMLOCK_GET: {
+ char **pzOut = (char**)pArg;
+ return unixFcntlShmlockGet((unixFile*)id, pzOut);
+ }
+ case SQLITE_FCNTL_SHMLOCK_NAME: {
+ char *zName = (char*)pArg;
+ return unixFcntlShmlockName((unixFile*)id, zName);
+ }
+#endif
}
return SQLITE_NOTFOUND;
}
u8 id; /* Id of this connection within its unixShmNode */
u16 sharedMask; /* Mask of shared locks held */
u16 exclMask; /* Mask of exclusive locks held */
+ const char *zShmlockName;
};
/*
#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+static int unixFcntlShmlockName(unixFile *pFile, const char *zName){
+ int rc = SQLITE_OK;
+ assert( !pFile->pShm || pFile->pShm->zShmlockName==pFile->zShmlockName );
+ sqlite3_free(pFile->zShmlockName);
+ pFile->zShmlockName = sqlite3_mprintf("%s", zName);
+ if( pFile->zShmlockName==0 ){
+ rc = SQLITE_NOMEM;
+ }
+ if( pFile->pShm){
+ unixShmNode *pShmNode = pFile->pShm->pShmNode;
+ sqlite3_mutex_enter(pShmNode->pShmMutex);
+ pFile->pShm->zShmlockName = pFile->zShmlockName;
+ sqlite3_mutex_leave(pShmNode->pShmMutex);
+ }
+ return rc;
+}
+
+static int unixFcntlShmlockGet(unixFile *pFile, char **pzOut){
+ int rc = SQLITE_OK;
+ unixShm *p = pFile->pShm;
+ const char *aLockName[] = {
+ "WRITE", "CHECKPOINT", "RECOVER",
+ "READ(0)", "READ(1)", "READ(2)", "READ(3)", "READ(4)"
+ };
+ assert( ArraySize(aLockName)==SQLITE_SHM_NLOCK );
+ if( p ){
+ sqlite3_str *pStr = sqlite3_str_new(0);
+ if( pStr==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ }else{
+ int nRow;
+ int i;
+ u32 aReadMark[5];
+ char *zOut = 0;
+ unixShm *pX = 0;
+ unixShmNode *pShmNode = p->pShmNode;
+ sqlite3_mutex_enter(pShmNode->pShmMutex);
+ memcpy(aReadMark, &(pShmNode->apRegion[0])[100], sizeof(aReadMark));
+ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+ if( pX->exclMask|pX->sharedMask ){
+ char zBuf[32];
+ const char *zName = pX->zShmlockName;
+ if( zName==0 ){
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", (void*)pX);
+ zName = zBuf;
+ }
+ assert( (pX->exclMask & pX->sharedMask)==0 );
+ for(i=0; i<SQLITE_SHM_NLOCK; i++){
+ if( (1<<i) & (pX->exclMask|pX->sharedMask) ){
+ int bWrite = (1<<i) & pX->exclMask;
+ if( bWrite==0 && i>=3 ){
+ sqlite3_str_appendf(pStr, "%s %s R %d\n",
+ zName, aLockName[i], aReadMark[i-3]
+ );
+ }else{
+ sqlite3_str_appendf(pStr, "%s %s %s\n",
+ zName, aLockName[i], bWrite ? "W" : "R"
+ );
+ }
+ nRow++;
+ }
+ }
+ }
+ }
+ for(i=0; i<SQLITE_SHM_NLOCK; i++){
+ if( pShmNode->aLock[i]==0 ){
+ struct flock lock;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = UNIX_SHM_BASE+i;
+ lock.l_len = 1;
+ lock.l_type = F_WRLCK;
+ if( osFcntl(pFile->h, F_GETLK, &lock) ){
+ rc = SQLITE_IOERR_LOCK;
+ }else if( lock.l_type!=F_UNLCK ){
+ if( lock.l_type==F_RDLCK && i>=3 ){
+ sqlite3_str_appendf(pStr, "pid.%d %s R %d\n",
+ lock.l_pid, aLockName[i], aReadMark[i]
+ );
+ }else{
+ sqlite3_str_appendf(pStr, "pid.%d %s %s\n",
+ lock.l_pid, aLockName[i], lock.l_type==F_WRLCK ? "W" : "R"
+ );
+ }
+ nRow++;
+ }
+ }
+ }
+ sqlite3_mutex_leave(pShmNode->pShmMutex);
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(sqlite3_str_finish(pStr));
+ }else{
+ rc = sqlite3_str_errcode(pStr);
+ zOut = sqlite3_str_finish(pStr);
+ }
+ *pzOut = zOut;
+ }
+ }
+ return rc;
+}
+
/*
** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
**
** pShmNode->pShmMutex.
*/
sqlite3_mutex_enter(pShmNode->pShmMutex);
+ p->zShmlockName = pDbFd->zShmlockName;
p->pNext = pShmNode->pFirst;
pShmNode->pFirst = p;
sqlite3_mutex_leave(pShmNode->pShmMutex);
#define SQLITE_FCNTL_RESERVE_BYTES 38
#define SQLITE_FCNTL_CKPT_START 39
+#define SQLITE_FCNTL_SHMLOCK_GET 40
+#define SQLITE_FCNTL_SHMLOCK_NAME 42
+
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
return TCL_OK;
}
+/*
+** tclcmd: file_control_shmlock_name DB DBNAME SHMLOCKNAME
+**
+** Return a string that is a temporary filename
+*/
+static int SQLITE_TCLAPI file_control_shmlock_name(
+ 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;
+ const char *zDbName = "main";
+ char *zName = 0;
+
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SHMLOCKNAME");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
+ return TCL_ERROR;
+ }
+ zDbName = Tcl_GetString(objv[2]);
+ zName = Tcl_GetString(objv[3]);
+
+ sqlite3_file_control(db, zDbName, SQLITE_FCNTL_SHMLOCK_NAME, (void*)zName);
+ return TCL_OK;
+}
+
/*
** tclcmd: sqlite3_vfs_list
extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
+ extern int sqlite3_shmlockvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
{ "regexp", sqlite3_regexp_init },
{ "remember", sqlite3_remember_init },
{ "series", sqlite3_series_init },
+ { "shmlockvtab", sqlite3_shmlockvtab_init },
{ "spellfix", sqlite3_spellfix_init },
{ "totype", sqlite3_totype_init },
{ "unionvtab", sqlite3_unionvtab_init },
{ "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
{ "file_control_vfsname", file_control_vfsname, 0 },
{ "file_control_tempfilename", file_control_tempfilename, 0 },
+ { "file_control_shmlock_name", file_control_shmlock_name, 0 },
{ "sqlite3_vfs_list", vfs_list, 0 },
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },