]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Update multiplex VFS to handle empty filenames which can occur for during vacuuming...
authorshaneh <shaneh@noemail.net>
Wed, 18 May 2011 02:22:41 +0000 (02:22 +0000)
committershaneh <shaneh@noemail.net>
Wed, 18 May 2011 02:22:41 +0000 (02:22 +0000)
FossilOrigin-Name: a074986045f1a81fb831ffee4a29af13c978b053

manifest
manifest.uuid
src/test_multiplex.c
test/multiplex.test

index 3d4df4239f6e3627dc07c54912a160a421534379..9a8c0464536d7e897992d9926b3c5ed8eaefc092 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sability\sto\slimit\sfilenames\sto\s8+3\susing\sthe\nSQLITE_ENABLE_8_3_NAMES\scompile-time\soption\stogether\swith\sa\sURI\nparameter\sof\s"8_3_names=1".
-D 2011-05-17T20:36:21.474
+C Update\smultiplex\sVFS\sto\shandle\sempty\sfilenames\swhich\scan\soccur\sfor\sduring\svacuuming\s(temp\sfile\snames.)
+D 2011-05-18T02:22:41.100
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -211,7 +211,7 @@ F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
 F src/test_journal.c 785edd54f963aefb3c1628124170a56697c68c70
 F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
 F src/test_malloc.c 7ca7be34e0e09ef0ed6619544552ed95732e41f6
-F src/test_multiplex.c fdabd793ee7a9642c5a8a470def2347144c46d05
+F src/test_multiplex.c c71f0a0cdf2b89a441e0bcefb2fcdf1dd358a820
 F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d
 F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
 F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
@@ -590,7 +590,7 @@ F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd
 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
 F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3
 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
-F test/multiplex.test a88f3e2c16e567e72be7296195c59fbdd6a8d3d4
+F test/multiplex.test 7a8a50c8ed72dfcf4db9ebae977f7a63184639d8
 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
 F test/nan.test dc212a22b36109fd1ae37154292444ef249c5ec2
@@ -937,7 +937,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 9593a640795458ce6e57e02dd5d702b642858f76
-R 87dd50ad185017288f71d71ad9ceabb5
-U drh
-Z 1ba151bdfae18403ba429fed62365eed
+P 96d609856025919571f781207dfa6a24b1732e8d
+R 2d9bd612a3d2dc8f2665702baad38baa
+U shaneh
+Z d27048d3dae68da084505a60e1541c3b
index c295187117f003c14525a59c46d05048248cef3a..1dc5ed78fb06308720f4a8ea384e919bc792762d 100644 (file)
@@ -1 +1 @@
-96d609856025919571f781207dfa6a24b1732e8d
\ No newline at end of file
+a074986045f1a81fb831ffee4a29af13c978b053
\ No newline at end of file
index d8a7db86e1d4f568b3cd745b38eba105636e58dd..861e68e8775d46619be8873b8cfdf68eaf4905a0 100644 (file)
@@ -185,13 +185,72 @@ static void multiplexLeave(void){ sqlite3_mutex_leave(gMultiplex.pMutex); }
 ** than the actual length of the string.  For very long strings (greater
 ** than 1GiB) the value returned might be less than the true string length.
 */
-int multiplexStrlen30(const char *z){
+static int multiplexStrlen30(const char *z){
   const char *z2 = z;
   if( z==0 ) return 0;
   while( *z2 ){ z2++; }
   return 0x3fffffff & (int)(z2 - z);
 }
 
+/*
+** Create a temporary file name in zBuf.  zBuf must be big enough to
+** hold at pOrigVfs->mxPathname characters.  This function departs
+** from the traditional temporary name generation in the os_win
+** and os_unix VFS in several ways, but is necessary so that 
+** the file name is known for temporary files (like those used 
+** during vacuum.)
+**
+** N.B. This routine assumes your underlying VFS is ok with using
+** "/" as a directory seperator.  This is the default for UNIXs
+** and is allowed (even mixed) for most versions of Windows.
+*/
+static int multiplexGetTempname(sqlite3_vfs *pOrigVfs, int nBuf, char *zBuf){
+  static char zChars[] =
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "0123456789";
+  int i,j;
+  int attempts = 0;
+  int exists = 0;
+  int rc = SQLITE_ERROR;
+
+  /* Check that the output buffer is large enough for 
+  ** pVfs->mxPathname characters.
+  */
+  if( pOrigVfs->mxPathname <= nBuf ){
+
+    /* sqlite3_temp_directory should always be less than
+    ** pVfs->mxPathname characters.
+    */
+    sqlite3_snprintf(pOrigVfs->mxPathname,
+                     zBuf,
+                     "%s/",
+                     sqlite3_temp_directory ? sqlite3_temp_directory : ".");
+
+    /* Check that the output buffer is large enough for the temporary file 
+    ** name.
+    */
+    j = multiplexStrlen30(zBuf);
+    if( (j + 8 + 1 + 3 + 1) <= nBuf ){
+      /* Make 3 attempts to generate a unique name. */
+      do {
+        attempts++;
+        sqlite3_randomness(8, &zBuf[j]);
+        for(i=0; i<8; i++){
+          zBuf[j+i] = (char)zChars[ ((unsigned char)zBuf[j+i])%(sizeof(zChars)-1) ];
+        }
+        memcpy(&zBuf[j+i], ".tmp", 5);
+        rc = pOrigVfs->xAccess(pOrigVfs, zBuf, SQLITE_ACCESS_EXISTS, &exists);
+      } while ( (rc==SQLITE_OK) && exists && (attempts<3) );
+      if( rc==SQLITE_OK && exists ){
+        rc = SQLITE_ERROR;
+      }
+    }
+  }
+
+  return rc;
+}
+
 /* Translate an sqlite3_file* that is really a multiplexGroup* into
 ** the sqlite3_file* for the underlying original VFS.
 */
@@ -295,12 +354,12 @@ static int multiplexOpen(
   int flags,                 /* Flags to control the opening */
   int *pOutFlags             /* Flags showing results of opening */
 ){
-  int rc;                                        /* Result code */
+  int rc = SQLITE_OK;                            /* Result code */
   multiplexConn *pMultiplexOpen;                 /* The new multiplex file descriptor */
   multiplexGroup *pGroup;                        /* Corresponding multiplexGroup object */
   sqlite3_file *pSubOpen;                        /* Real file descriptor */
   sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
-  int nName = multiplexStrlen30(zName);
+  int nName;
   int i;
   int sz;
 
@@ -311,23 +370,39 @@ static int multiplexOpen(
   */
   multiplexEnter();
   pMultiplexOpen = (multiplexConn*)pConn;
-  /* allocate space for group */
-  sz = sizeof(multiplexGroup)                                /* multiplexGroup */
-     + (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS)  /* pReal[] */
-     + (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS)      /* *pReal */
-     + SQLITE_MULTIPLEX_MAX_CHUNKS                           /* bOpen[] */
-     + nName + 1;                                            /* zName */
+
+  /* If the second argument to this function is NULL, generate a 
+  ** temporary file name to use.  This will be handled by the
+  ** original xOpen method.  We just need to allocate space for
+  ** it.
+  */
+  if( !zName ){
+    rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, gMultiplex.zName);
+    zName = gMultiplex.zName;
+  }
+
+  if( rc==SQLITE_OK ){
+    /* allocate space for group */
+    nName = multiplexStrlen30(zName);
+    sz = sizeof(multiplexGroup)                                /* multiplexGroup */
+       + (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS)  /* pReal[] */
+       + (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS)      /* *pReal */
+       + SQLITE_MULTIPLEX_MAX_CHUNKS                           /* bOpen[] */
+       + nName + 1;                                            /* zName */
 #ifndef SQLITE_MULTIPLEX_EXT_OVWR
-  sz += SQLITE_MULTIPLEX_EXT_SZ;
-  assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname);
+    sz += SQLITE_MULTIPLEX_EXT_SZ;
+    assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname);
 #else
-  assert(nName >= SQLITE_MULTIPLEX_EXT_SZ);
-  assert(nName < pOrigVfs->mxPathname);
+    assert(nName >= SQLITE_MULTIPLEX_EXT_SZ);
+    assert(nName < pOrigVfs->mxPathname);
 #endif
-  pGroup = sqlite3_malloc( sz );
-  if( pGroup==0 ){
-    rc=SQLITE_NOMEM;
-  }else{
+    pGroup = sqlite3_malloc( sz );
+    if( pGroup==0 ){
+      rc=SQLITE_NOMEM;
+    }
+  }
+
+  if( rc==SQLITE_OK ){
     /* assign pointers to extra space allocated */
     char *p = (char *)&pGroup[1];
     pMultiplexOpen->pGroup = pGroup;
@@ -411,7 +486,7 @@ static int multiplexDelete(
     }
     rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, 
         SQLITE_ACCESS_EXISTS, &exists);
-    if( rc2==SQLITE_OK && exists){
+    if( rc2==SQLITE_OK && exists ){
       /* if it exists, delete it */
       rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir);
       if( rc2!=SQLITE_OK ) rc = rc2;
index 518cbe37a0d662765ce3e85b3f28a996ef567a41..ae60d639e5c1a8cc8b06520bbf657f618781c653 100644 (file)
@@ -567,5 +567,45 @@ if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
   }
 }
 
+#-------------------------------------------------------------------------
+# Test that you can vacuum a multiplex'ed DB.  
+
+ifcapable vacuum {
+
+do_test multiplex-6.0.0 {
+  multiplex_delete test.db
+  sqlite3_multiplex_initialize "" 1
+  sqlite3 db test.db
+  multiplex_set db main 4096 16
+} {SQLITE_OK}
+
+do_test multiplex-6.1.0 {
+  execsql {
+    PRAGMA page_size=1024;
+    PRAGMA journal_mode=DELETE;
+    PRAGMA auto_vacuum=OFF;
+  }
+  execsql {
+    CREATE TABLE t1(a, b);
+    INSERT INTO t1 VALUES(1, randomblob($g_chunk_size));
+    INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
+  }
+} {}
+do_test multiplex-6.2.1 { file size [multiplex_name test.db 0] } [list $g_chunk_size]
+do_test multiplex-6.2.2 { file size [multiplex_name test.db 1] } [list $g_chunk_size]
+
+do_test multiplex-6.3.0 {
+  execsql { VACUUM }
+} {}
+
+do_test multiplex-6.99 {
+  db close
+  multiplex_delete test.db
+  sqlite3_multiplex_shutdown
+} {SQLITE_OK}
+
+}
+
+
 catch { sqlite3_multiplex_shutdown }
 finish_test