]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add experimental support for resolving relative database file paths using a fixed...
authormistachkin <mistachkin@noemail.net>
Wed, 14 Mar 2012 00:44:01 +0000 (00:44 +0000)
committermistachkin <mistachkin@noemail.net>
Wed, 14 Mar 2012 00:44:01 +0000 (00:44 +0000)
FossilOrigin-Name: 7354ae8fd3eccee2cf9f6501da5b1a014c31556f

manifest
manifest.uuid
src/main.c
src/os_win.c
src/pragma.c
src/sqlite.h.in
src/test1.c
test/pragma.test

index c71ea05a4c6124113678d3a476bba00daded5552..60cc76289847851af45def71c39e798652285735 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sassert\sto\sverify\sthe\snumber\sof\scharacters\sto\swrite\sin\ssqlite3_win32_write_debug.
-D 2012-03-13T03:38:22.981
+C Add\sexperimental\ssupport\sfor\sresolving\srelative\sdatabase\sfile\spaths\susing\sa\sfixed\suser-defined\sdirectory.
+D 2012-03-14T00:44:01.952
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -147,7 +147,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
 F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
 F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
 F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d
-F src/main.c dcb4a15254dca9cc59dba63e813a8c140c021832
+F src/main.c 5808bc6e2d2a80c3d73c42622fa162dc3cc24893
 F src/malloc.c 15afac5e59b6584efe072e9933aefb4230e74f97
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c b3677415e69603d6a0e7c5410a1b3731d55beda1
@@ -167,14 +167,14 @@ F src/os.h 38aabd5e3ecd4162332076f55bb09cec02165cca
 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
 F src/os_unix.c 0e3d2942d228d0366fb80a3640f35caf413b66d1
-F src/os_win.c c47a86a8b8a958fc8cae06a45e56ed3217a686e4
+F src/os_win.c ed4f4f5cad8c708d5e443139df0d65e9354b8368
 F src/pager.c 3955b62cdb5bb64559607cb474dd12a6c8e1d4a5
 F src/pager.h ef1eaf8593e78f73885c1dfac27ad83bee23bdc5
 F src/parse.y 1ddd71ae55f4b7cbb2672526ea4de023de0f519e
 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
 F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c
 F src/pcache1.c b30b1c35908346ecc43d8d9d17f2ddf6817f8f60
-F src/pragma.c e708b3bb5704605816f617e0b1d63a5488060715
+F src/pragma.c 149d8400ff783741d41389176832241cbff8f856
 F src/prepare.c ec4989f7f480544bdc4192fe663470d2a2d7d61e
 F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
@@ -182,14 +182,14 @@ F src/resolve.c 3d3e80a98f203ac6b9329e9621e29eda85ddfd40
 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
 F src/select.c 44ccdcb5d2a1c48622c179b2d72167b716388581
 F src/shell.c aa28f117033ba3e44b5eaaf2ad572222bcdfd66e
-F src/sqlite.h.in f46e368d1a28b09d876e35444785674d170f2d62
+F src/sqlite.h.in 21d17ec95bc6004908f8d8158ffd9021790d1b06
 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
 F src/sqliteInt.h b013dab7d43fb67c3ca2f0253d7863abb37e233c
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
 F src/tclsqlite.c 2aeb69958965dad0842d5ea1456f1a958ef296e6
-F src/test1.c 328cbe4a4ee6d10d67ece2a7adaa2770569fae0f
+F src/test1.c 8e1e72e09d7941d9d22fd6a544df39e2e3f4efd9
 F src/test2.c 711555927f1f7e8db9aab86b512bc6934a774abe
 F src/test3.c 91d3f1a09cfae3533ef17d8b484a160f3d1f1a21
 F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
@@ -636,7 +636,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
 F test/permutations.test 2b5a1b64a8e5114757457fbce9010387d1fe7682
-F test/pragma.test c51c148defe32bf4a419a522f95d26838d5cf677
+F test/pragma.test eba5bd337ae68870985cd1776659bb136b33dada
 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
@@ -992,7 +992,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P 7af88ad306612dd316827c506dbf8df7477b2ec1
-R 733fe38048c4d65e48f1419dbebc0b16
+P 8083f6164f3308c1c1d4f4d84be1894e382fe2e6
+R ecb2eb3e3cb321cdfbc1971b31d42211
 U mistachkin
-Z ac12a0ffda13979ead9c043455a8d437
+Z 0c49ed1cd4cd58d4e2dd23c2fb64b825
index 5704843a7760d24341616b22754af91980ec90d0..b333b0d42bf0aa8b174fe3e45dafb5025e2daafc 100644 (file)
@@ -1 +1 @@
-8083f6164f3308c1c1d4f4d84be1894e382fe2e6
\ No newline at end of file
+7354ae8fd3eccee2cf9f6501da5b1a014c31556f
\ No newline at end of file
index 3a1dff576ac1d63cca38210721cd973d5b426de8..601138b8df98ee2fe02c3bff5faad66d68c18a99 100644 (file)
@@ -74,6 +74,15 @@ void (*sqlite3IoTrace)(const char*, ...) = 0;
 */
 char *sqlite3_temp_directory = 0;
 
+/*
+** If the following global variable points to a string which is the
+** name of a directory, then that directory will be used to store
+** all database files specified with a relative pathname.
+**
+** See also the "PRAGMA data_store_directory" SQL command.
+*/
+char *sqlite3_data_directory = 0;
+
 /*
 ** Initialize SQLite.  
 **
index 6a8a4f3cddbab20c54044e123b6ad6fbb4a3c0bf..f2869218208451eb4d44f9f0cefe736fd2272342 100644 (file)
@@ -3703,6 +3703,43 @@ static int winAccess(
 }
 
 
+/*
+** Returns non-zero if the specified path name should be used verbatim.  If
+** non-zero is returned from this function, the calling function must simply
+** use the provided path name verbatim -OR- resolve it into a full path name
+** using the GetFullPathName Win32 API function (if available).
+*/
+static BOOL winIsVerbatimPathname(
+  const char *zPathname
+){
+  /*
+  ** If the path name starts with a forward slash or a backslash, it is either
+  ** a legal UNC name, a volume relative path, or an absolute path name in the
+  ** "Unix" format on Windows.  There is no easy way to differentiate between
+  ** the final two cases; therefore, we return the safer return value of TRUE
+  ** so that callers of this function will simply use it verbatim.
+  */
+  if ( zPathname[0]=='/' || zPathname[0]=='\\' ){
+    return TRUE;
+  }
+
+  /*
+  ** If the path name starts with a letter and a colon it is either a volume
+  ** relative path or an absolute path.  Callers of this function must not
+  ** attempt to treat it as a relative path name (i.e. they should simply use
+  ** it verbatim).
+  */
+  if ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' ){
+    return TRUE;
+  }
+
+  /*
+  ** If we get to this point, the path name should almost certainly be a purely
+  ** relative one (i.e. not a UNC name, not absolute, and not volume relative).
+  */
+  return FALSE;
+}
+
 /*
 ** Turn a relative pathname into a full pathname.  Write the full
 ** pathname into zOut[].  zOut[] will be at least pVfs->mxPathname
@@ -3718,16 +3755,47 @@ static int winFullPathname(
 #if defined(__CYGWIN__)
   SimulateIOError( return SQLITE_ERROR );
   UNUSED_PARAMETER(nFull);
-  cygwin_conv_to_full_win32_path(zRelative, zFull);
+  assert( pVfs->mxPathname>=MAX_PATH );
+  assert( nFull>=pVfs->mxPathname );
+  if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
+    /*
+    ** NOTE: We are dealing with a relative path name and the data
+    **       directory has been set.  Therefore, use it as the basis
+    **       for converting the relative path name to an absolute
+    **       one by prepending the data directory and a slash.
+    */
+    char zOut[MAX_PATH+1];
+    memset(zOut, 0, MAX_PATH+1);
+    cygwin_conv_to_win32_path(zRelative, zOut); /* POSIX to Win32 */
+    sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
+                     sqlite3_data_directory, zOut);
+  }else{
+    /*
+    ** NOTE: The Cygwin docs state that the maximum length needed
+    **       for the buffer passed to cygwin_conv_to_full_win32_path
+    **       is MAX_PATH.
+    */
+    cygwin_conv_to_full_win32_path(zRelative, zFull);
+  }
   return SQLITE_OK;
 #endif
 
-#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
+#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
   SimulateIOError( return SQLITE_ERROR );
-  UNUSED_PARAMETER(nFull);
   /* WinCE has no concept of a relative pathname, or so I am told. */
   /* WinRT has no way to convert a relative path to an absolute one. */
-  sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
+  if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
+    /*
+    ** NOTE: We are dealing with a relative path name and the data
+    **       directory has been set.  Therefore, use it as the basis
+    **       for converting the relative path name to an absolute
+    **       one by prepending the data directory and a backslash.
+    */
+    sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
+                     sqlite3_data_directory, zRelative);
+  }else{
+    sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
+  }
   return SQLITE_OK;
 #endif
 
@@ -3749,7 +3817,17 @@ static int winFullPathname(
   ** current working directory has been unlinked.
   */
   SimulateIOError( return SQLITE_ERROR );
-  UNUSED_PARAMETER(nFull);
+  if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
+    /*
+    ** NOTE: We are dealing with a relative path name and the data
+    **       directory has been set.  Therefore, use it as the basis
+    **       for converting the relative path name to an absolute
+    **       one by prepending the data directory and a backslash.
+    */
+    sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
+                     sqlite3_data_directory, zRelative);
+    return SQLITE_OK;
+  }
   zConverted = convertUtf8Filename(zRelative);
   if( zConverted==0 ){
     return SQLITE_IOERR_NOMEM;
@@ -3783,7 +3861,7 @@ static int winFullPathname(
   }
 #endif
   if( zOut ){
-    sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut);
+    sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
     sqlite3_free(zOut);
     return SQLITE_OK;
   }else{
index 2db0b61508524656fa9581d3365922b978c6cb4d..2507acedf6a728c1c75f5373ef06a7700ea23154 100644 (file)
@@ -804,6 +804,48 @@ void sqlite3Pragma(
     }
   }else
 
+  /*
+  **   PRAGMA data_store_directory
+  **   PRAGMA data_store_directory = ""|"directory_name"
+  **
+  ** Return or set the local value of the data_store_directory flag.  Changing
+  ** the value sets a specific directory to be used for database files that
+  ** were specified with a relative pathname.  Setting to a null string reverts
+  ** to the default database directory, which for database files specified with
+  ** a relative path will probably be based on the current directory for the
+  ** process.  Database file specified with an absolute path are not impacted
+  ** by this setting, regardless of its value.
+  **
+  */
+  if( sqlite3StrICmp(zLeft, "data_store_directory")==0 ){
+    if( !zRight ){
+      if( sqlite3_data_directory ){
+        sqlite3VdbeSetNumCols(v, 1);
+        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, 
+            "data_store_directory", SQLITE_STATIC);
+        sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_data_directory, 0);
+        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+      }
+    }else{
+#ifndef SQLITE_OMIT_WSD
+      if( zRight[0] ){
+        int res;
+        rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
+        if( rc!=SQLITE_OK || res==0 ){
+          sqlite3ErrorMsg(pParse, "not a writable directory");
+          goto pragma_out;
+        }
+      }
+      sqlite3_free(sqlite3_data_directory);
+      if( zRight[0] ){
+        sqlite3_data_directory = sqlite3_mprintf("%s", zRight);
+      }else{
+        sqlite3_data_directory = 0;
+      }
+#endif /* SQLITE_OMIT_WSD */
+    }
+  }else
+
 #if !defined(SQLITE_ENABLE_LOCKING_STYLE)
 #  if defined(__APPLE__)
 #    define SQLITE_ENABLE_LOCKING_STYLE 1
index b43fe208f8e276d49a642397e2a31ddb998fe3ed..44d52e828b19072c2d16e07f8a9af33fe4c78a12 100644 (file)
@@ -4443,6 +4443,39 @@ int sqlite3_sleep(int);
 */
 SQLITE_EXTERN char *sqlite3_temp_directory;
 
+/*
+** CAPI3REF: Name Of The Folder Holding Database Files
+**
+** ^(If this global variable is made to point to a string which is
+** the name of a folder (a.k.a. directory), then all database files
+** specified with a relative pathname and created or accessed by
+** SQLite when using a built-in [sqlite3_vfs | VFS] will be assumed
+** to be relative to that directory.)^ ^If this variable is a NULL
+** pointer, then SQLite assumes that all database files specified
+** with a relative pathname are relative to the current directory
+** for the process.
+**
+** It is not safe to read or modify this variable in more than one
+** thread at a time.  It is not safe to read or modify this variable
+** if a [database connection] is being used at the same time in a separate
+** thread.
+** It is intended that this variable be set once
+** as part of process initialization and before any SQLite interface
+** routines have been called and that this variable remain unchanged
+** thereafter.
+**
+** ^The [data_store_directory pragma] may modify this variable and cause
+** it to point to memory obtained from [sqlite3_malloc].  ^Furthermore,
+** the [data_store_directory pragma] always assumes that any string
+** that this variable points to is held in memory obtained from 
+** [sqlite3_malloc] and the pragma may attempt to free that memory
+** using [sqlite3_free].
+** Hence, if this variable is modified directly, either it should be
+** made NULL or made to point to memory obtained from [sqlite3_malloc]
+** or else the use of the [data_store_directory pragma] should be avoided.
+*/
+SQLITE_EXTERN char *sqlite3_data_directory;
+
 /*
 ** CAPI3REF: Test For Auto-Commit Mode
 ** KEYWORDS: {autocommit mode}
index 281823d5a87712fefc7100f29c28a5baf95d39cc..2e0bd932a2c44a6903fd2a3d89104e1760df0f89 100644 (file)
@@ -6261,6 +6261,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
       (char*)&sqlite_static_bind_nbyte, TCL_LINK_INT);
   Tcl_LinkVar(interp, "sqlite_temp_directory",
       (char*)&sqlite3_temp_directory, TCL_LINK_STRING);
+  Tcl_LinkVar(interp, "sqlite_data_directory",
+      (char*)&sqlite3_data_directory, TCL_LINK_STRING);
   Tcl_LinkVar(interp, "bitmask_size",
       (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
   Tcl_LinkVar(interp, "sqlite_sync_count",
index bb10327c3acfb03fb191b57754fef5d786e6e2dc..f8773f1b22cb01f97d961c51fe9ba476401d896c 100644 (file)
@@ -40,6 +40,7 @@ do_not_use_codec
 # pragma-15.*: Test that the value set using the cache_size pragma is not
 #              reset when the schema is reloaded.
 # pragma-16.*: Test proxy locking
+# pragma-20.*: Test data_store_directory.
 #
 
 ifcapable !pragma {
@@ -1510,5 +1511,44 @@ do_test pragma-19.5 {
   file tail [lindex [execsql {PRAGMA filename}] 0]
 } {test.db}
 
-
+# Test data_store_directory pragma
+#
+db close
+sqlite3 db test.db
+file mkdir data_dir
+do_test pragma-20.1 {
+  catchsql {PRAGMA data_store_directory}
+} {0 {}}
+do_test pragma-20.2 {
+  set pwd [string map {' ''} [file nativename [get_pwd]]]
+  catchsql "PRAGMA data_store_directory='$pwd';"
+} {0 {}}
+do_test pragma-20.3 {
+  catchsql {PRAGMA data_store_directory}
+} [list 0 [list [file nativename [get_pwd]]]]
+do_test pragma-20.4 {
+  set pwd [string map {' ''} [file nativename \
+    [file join [get_pwd] data_dir]]]
+  catchsql "PRAGMA data_store_directory='$pwd';"
+} {0 {}}
+do_test pragma-20.5 {
+  sqlite3 db2 test2.db
+  catchsql "PRAGMA database_list;" db2
+} [list 0 [list 0 main [file nativename \
+    [file join [get_pwd] data_dir test2.db]]]]
+catch {db2 close}
+do_test pragma-20.6 {
+  sqlite3 db2 [file join [get_pwd] test2.db]
+  catchsql "PRAGMA database_list;" db2
+} [list 0 [list 0 main [file nativename \
+    [file join [get_pwd] test2.db]]]]
+catch {db2 close}
+do_test pragma-20.7 {
+  catchsql "PRAGMA data_store_directory='';"
+} {0 {}}
+do_test pragma-20.8 {
+  catchsql {PRAGMA data_store_directory}
+} {0 {}}
+
+forcedelete data_dir
 finish_test