1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-15 11:41:13 +03:00

Add experimental support for resolving relative database file paths using a fixed user-defined directory.

FossilOrigin-Name: 7354ae8fd3eccee2cf9f6501da5b1a014c31556f
This commit is contained in:
mistachkin
2012-03-14 00:44:01 +00:00
parent 5ff72401c9
commit a112d140ae
8 changed files with 222 additions and 18 deletions

View File

@@ -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

View File

@@ -1 +1 @@
8083f6164f3308c1c1d4f4d84be1894e382fe2e6
7354ae8fd3eccee2cf9f6501da5b1a014c31556f

View 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.
**

View 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{

View 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

View 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}

View 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",

View 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