]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add file-controls and a vtab frontend for querying the unix VFS for the currently...
authordan <dan@noemail.net>
Tue, 1 Sep 2020 20:56:28 +0000 (20:56 +0000)
committerdan <dan@noemail.net>
Tue, 1 Sep 2020 20:56:28 +0000 (20:56 +0000)
FossilOrigin-Name: ef10e1b386d7a9028eab64e1f4802e3d6b2df11c6723130a29e5effc8dcb2e80

ext/misc/shmlockvtab.c [new file with mode: 0644]
main.mk
manifest
manifest.uuid
src/os_unix.c
src/sqlite.h.in
src/test1.c

diff --git a/ext/misc/shmlockvtab.c b/ext/misc/shmlockvtab.c
new file mode 100644 (file)
index 0000000..f45e395
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+** 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;
+}
diff --git a/main.mk b/main.mk
index 693887bd664603ee1651adea38a7a1ccc943c719..a99f08dbc735ca61cd60e287671a9e87e0a789b2 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -377,6 +377,7 @@ TESTSRC += \
   $(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 \
index c80c5cffe675975287abc8298dc7b444b71b8b53..1090c254291d90d003a78ffb3253556895a435d1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -317,6 +317,7 @@ F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a
 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
@@ -457,7 +458,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
 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
@@ -519,7 +520,7 @@ F src/os.c 80e4cf3e5da06be03ca641661e331ce60eeeeabf0d7354dbb1c0e166d0eedbbe
 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
@@ -537,7 +538,7 @@ F src/resolve.c 97b91fb25d86881ff20c9ad2ad98412c6c1bb5f7d6c9bb044db250cbc9cfcd4b
 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
@@ -545,7 +546,7 @@ F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a3
 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
@@ -1879,7 +1880,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 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
index 12efad1e94cbe6732c8ac9e5bec5d2c018016bde..f1ab915fa5dc31f07706b84aec442b018626bff5 100644 (file)
@@ -1 +1 @@
-d34caf3bb63d0512ea116a8c8c8343b76aa39441bd4b3e98231747a705b91d54
\ No newline at end of file
+ef10e1b386d7a9028eab64e1f4802e3d6b2df11c6723130a29e5effc8dcb2e80
\ No newline at end of file
index 5419a042a63635c8145f58c71f9a3e9423a7d513..4ad408ea004c3f6c7fc43efecfaa0cc52e65e2d1 100644 (file)
@@ -229,6 +229,7 @@ struct unixFile {
   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 */
@@ -2112,6 +2113,7 @@ static int closeUnixFile(sqlite3_file *id){
   OSTRACE(("CLOSE   %-3d\n", pFile->h));
   OpenCounter(-1);
   sqlite3_free(pFile->pPreallocatedUnused);
+  sqlite3_free(pFile->zShmlockName);
   memset(pFile, 0, sizeof(unixFile));
   return SQLITE_OK;
 }
@@ -3928,8 +3930,10 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
   }
 }
 
-/* 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.
@@ -4046,6 +4050,16 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
       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;
 }
@@ -4283,6 +4297,7 @@ struct unixShm {
   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;
 };
 
 /*
@@ -4291,6 +4306,106 @@ struct unixShm {
 #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.
 **
@@ -4629,6 +4744,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
   ** pShmNode->pShmMutex.
   */
   sqlite3_mutex_enter(pShmNode->pShmMutex);
+  p->zShmlockName = pDbFd->zShmlockName;
   p->pNext = pShmNode->pFirst;
   pShmNode->pFirst = p;
   sqlite3_mutex_leave(pShmNode->pShmMutex);
index 2a8ad56ce9b59bf67379a093508bfd1a087b62ce..d8c738d7162216740b22e0565cc189eca7af275a 100644 (file)
@@ -1167,6 +1167,9 @@ struct sqlite3_io_methods {
 #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
index 04b9f7a0113349ac03d7420c02feeac34e9b24cd..36c30462f49d5049112073ac88dc607b2aa1a8f5 100644 (file)
@@ -6271,6 +6271,35 @@ static int SQLITE_TCLAPI file_control_tempfilename(
   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
@@ -7292,6 +7321,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
   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*);
@@ -7321,6 +7351,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
     { "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            },
@@ -8161,6 +8192,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      { "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 },