Change the supported URI options to "mode" and "cache".

FossilOrigin-Name: 0a694a0b27e3ce251ce313cb5d19a7637c2fa309
This commit is contained in:
dan 2011-05-03 10:22:32 +00:00
parent fb261ceceb
commit 78e9dd2b54
4 changed files with 166 additions and 74 deletions

View File

@ -1,5 +1,5 @@
C Merge\sthe\slatest\strunk\schanges\sinto\suri\sbranch.
D 2011-05-02T17:41:01.076
C Change\sthe\ssupported\sURI\soptions\sto\s"mode"\sand\s"cache".
D 2011-05-03T10:22:32.361
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -143,7 +143,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 3ae0d52da013a6326310655be6473fd472347b85
F src/main.c 933d0bcf586ba7acbe2ce3f37d35c474a8306109
F src/main.c 8e13c02ec1992f94dcc06b4b2bc0001a79b3e68f
F src/malloc.c 74c740e8ba22b806cfb980c8c0ddea1cbd54a20e
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
@ -837,7 +837,7 @@ F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
F test/unixexcl.test 9d80a54d86d2261f660758928959368ffc36151e
F test/unordered.test e81169ce2a8f31b2c6b66af691887e1376ab3ced
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
F test/uri.test 062ba42524a5042985e7994dc2289259424b60bf
F test/uri.test 2e2dea3054bc6b3e5e1bf43fbab09a847ed9eb5f
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
F test/vacuum.test 29b60e8cc9e573b39676df6c4a75fe9e02d04a09
F test/vacuum2.test 91a84c9b08adfc4472097d2e8deb0150214e0e76
@ -931,7 +931,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 2af51f856c6203f836d8bb62b6b79b19554886e7 f55156c5194e85c47728b8a97fde3e5f0a5c9b56
R 5b3361d8c251d725e8fb18c102b1e7f2
P 7fdd0786c7e0d66baf3aba4485128e16a4e5ea46
R 9466d8a507f14eedc64f1b5ce9c925cf
U dan
Z ce77508d586b51f29df902539114b8b5
Z bebe00795592ddf7acadaf3bca1d1f57

View File

@ -1 +1 @@
7fdd0786c7e0d66baf3aba4485128e16a4e5ea46
0a694a0b27e3ce251ce313cb5d19a7637c2fa309

View File

@ -1803,18 +1803,7 @@ int sqlite3ParseUri(
char **pzFile, /* OUT: Filename component of URI */
char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */
){
struct UriOption {
const char *zOption;
int mask;
} aOpt [] = {
{ "vfs", 0 },
{ "readonly", SQLITE_OPEN_READONLY },
{ "readwrite", SQLITE_OPEN_READWRITE },
{ "create", SQLITE_OPEN_CREATE },
{ "sharedcache", SQLITE_OPEN_SHAREDCACHE },
{ "privatecache", SQLITE_OPEN_PRIVATECACHE }
};
int rc = SQLITE_OK;
int flags = *pFlags;
const char *zVfs = zDefaultVfs;
char *zFile;
@ -1864,7 +1853,12 @@ int sqlite3ParseUri(
codepoint += sqlite3HexToInt(zUri[iIn++]);
assert( codepoint>=0 && codepoint<256 );
if( codepoint==0 ){
if( codepoint>=128 ){
*pzErrMsg = sqlite3_mprintf("invalid uri escape: %.3s", &zUri[-3]);
rc = SQLITE_ERROR;
goto parse_uri_out;
}
else if( codepoint==0 ){
/* This branch is taken when "%00" appears within the URI. In this
** case we ignore all text in the remainder of the path, name or
** value currently being parsed. So ignore the current character
@ -1904,27 +1898,70 @@ int sqlite3ParseUri(
/* Check if there were any options specified that should be interpreted
** here. Options that are interpreted here include "vfs" and those that
** correspond to flags that may be passed to the sqlite3_open_v2()
** method. */
** method. */
zOpt = &zFile[sqlite3Strlen30(zFile)+1];
while( zOpt[0] ){
int nOpt = sqlite3Strlen30(zOpt);
char *zVal = &zOpt[nOpt+1];
int nVal = sqlite3Strlen30(zVal);
int i;
for(i=0; i<ArraySize(aOpt); i++){
const char *z = aOpt[i].zOption;
if( nOpt==sqlite3Strlen30(z) && 0==memcmp(zOpt, z, nOpt) ){
int mask = aOpt[i].mask;
if( mask==0 ){
zVfs = zVal;
}else{
if( zVal[0]=='\0' || sqlite3GetBoolean(zVal) ){
flags |= mask;
}else{
flags &= ~mask;
if( nOpt==3 && sqlite3_strnicmp("vfs", zOpt, 3)==0 ){
zVfs = zVal;
}else{
struct OpenMode {
const char *z;
int mode;
} *aMode = 0;
char *zModeType;
int mask;
int limit;
if( nOpt==5 && sqlite3_strnicmp("cache", zOpt, 5)==0 ){
static struct OpenMode aCacheMode[] = {
{ "shared", SQLITE_OPEN_SHAREDCACHE },
{ "private", SQLITE_OPEN_PRIVATECACHE },
{ 0, 0 }
};
mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE;
aMode = aCacheMode;
limit = mask;
zModeType = "cache";
}
if( nOpt==4 && sqlite3_strnicmp("mode", zOpt, 4)==0 ){
static struct OpenMode aOpenMode[] = {
{ "ro", SQLITE_OPEN_READONLY },
{ "rw", SQLITE_OPEN_READWRITE },
{ "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE },
{ 0, 0 }
};
mask = SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
aMode = aOpenMode;
limit = mask & flags;
zModeType = "access";
}
if( aMode ){
int i;
int mode = 0;
for(i=0; aMode[i].z; i++){
const char *z = aMode[i].z;
if( nVal==strlen(z) && 0==sqlite3_strnicmp(zVal, z, nVal) ){
mode = aMode[i].mode;
break;
}
}
if( mode==0 ){
*pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal);
rc = SQLITE_ERROR;
goto parse_uri_out;
}
if( mode>limit ){
rc = SQLITE_PERM;
goto parse_uri_out;
}
flags = (flags & ~mask) | mode;
}
}
@ -1942,12 +1979,16 @@ int sqlite3ParseUri(
*ppVfs = sqlite3_vfs_find(zVfs);
if( *ppVfs==0 ){
*pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs);
rc = SQLITE_ERROR;
}
parse_uri_out:
if( rc!=SQLITE_OK ){
sqlite3_free(zFile);
return SQLITE_ERROR;
zFile = 0;
}
*pFlags = flags;
*pzFile = zFile;
return SQLITE_OK;
return rc;
}
@ -1974,6 +2015,27 @@ static int openDatabase(
if( rc ) return rc;
#endif
/* Only allow sensible combinations of bits in the flags argument.
** Throw an error if any non-sense combination is used. If we
** do not block illegal combinations here, it could trigger
** assert() statements in deeper layers. Sensible combinations
** are:
**
** 1: SQLITE_OPEN_READONLY
** 2: SQLITE_OPEN_READWRITE
** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
*/
assert( SQLITE_OPEN_READONLY == 0x01 );
assert( SQLITE_OPEN_READWRITE == 0x02 );
assert( SQLITE_OPEN_CREATE == 0x04 );
testcase( (1<<(flags&7))==0x02 ); /* READONLY */
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
if( ((1<<(flags&7)) & 0x46)==0 ){
rc = SQLITE_MISUSE;
goto opendb_out;
}
if( sqlite3GlobalConfig.bCoreMutex==0 ){
isThreadsafe = 0;
}else if( flags & SQLITE_OPEN_NOMUTEX ){
@ -2078,32 +2140,11 @@ static int openDatabase(
/* Parse the filename/URI argument. */
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
if( rc!=SQLITE_OK ){
sqlite3Error(db, rc, "%s", zErrMsg);
sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
sqlite3_free(zErrMsg);
goto opendb_out;
}
/* Only allow sensible combinations of bits in the flags argument.
** Throw an error if any non-sense combination is used. If we
** do not block illegal combinations here, it could trigger
** assert() statements in deeper layers. Sensible combinations
** are:
**
** 1: SQLITE_OPEN_READONLY
** 2: SQLITE_OPEN_READWRITE
** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
*/
assert( SQLITE_OPEN_READONLY == 0x01 );
assert( SQLITE_OPEN_READWRITE == 0x02 );
assert( SQLITE_OPEN_CREATE == 0x04 );
testcase( (1<<(flags&7))==0x02 ); /* READONLY */
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
if( ((1<<(flags&7)) & 0x46)==0 ){
rc = SQLITE_MISUSE;
goto opendb_out;
}
/* Open the backend database driver */
db->openFlags = flags;
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,

View File

@ -117,26 +117,77 @@ do_test 3.1 {
#
# TODO: Fix this after the list of options is decided.
#
do_test 4.0 {
sqlite3 db test.db
db eval {CREATE TABLE t1(a, b)}
db close
} {}
foreach {tn uri ro} {
1 "file:test.db" 0
2 "file:test.db?readonly=0" 0
3 "file:test.db?readonly=1&readwrite=0&create=0" 1
foreach {tn mode create_ok write_ok readonly_ok} {
1 ro 0 0 1
2 rw 0 1 0
3 rwc 1 1 0
} {
set RES(0) {0 {}}
set RES(1) {1 {attempt to write a readonly database}}
catch { db close }
forcedelete test.db
do_test 4.$tn {
sqlite3 db $uri
catchsql { INSERT INTO t1 VALUES(1, 2) }
} $RES($ro)
set A(1) {0 {}}
set A(0) {1 {unable to open database file}}
do_test 4.1.$tn.1 {
list [catch {sqlite3 db "file:test.db?mode=$mode"} msg] $msg
} $A($create_ok)
catch { db close }
forcedelete test.db
sqlite3 db test.db
db eval { CREATE TABLE t1(a, b) }
db close
set A(1) {0 {}}
set A(0) {1 {attempt to write a readonly database}}
do_test 4.1.$tn.2 {
sqlite3 db "file:test.db?mode=$mode"
catchsql { INSERT INTO t1 VALUES(1, 2) }
} $A($write_ok)
set A(1) {0 {}}
set A(0) {1 {access permission denied}}
do_test 4.1.$tn.3 {
list [catch {sqlite3 db "file:test.db?mode=$mode" -readonly 1} msg] $msg
} $A($readonly_ok)
}
set orig [sqlite3_enable_shared_cache]
foreach {tn options sc_default is_shared} {
1 "" 1 1
2 "cache=private" 1 0
3 "cache=shared" 1 1
4 "" 0 0
5 "cache=private" 0 0
6 "cache=shared" 0 1
} {
catch { db close }
forcedelete test.db
sqlite3_enable_shared_cache 1
sqlite3 db2 test.db
db2 eval {CREATE TABLE t1(a, b)}
sqlite3_enable_shared_cache $sc_default
sqlite3 db "file:test.db?$options"
db eval {SELECT * FROM t1}
set A(1) {1 {database table is locked: t1}}
set A(0) {0 {}}
do_test 4.2.$tn {
db2 eval {BEGIN; INSERT INTO t1 VALUES(1, 2);}
catchsql { SELECT * FROM t1 }
} $A($is_shared)
db2 close
}
do_test 4.3.1 {
list [catch {sqlite3 db "file:test.db?mode=rc"} msg] $msg
} {1 {no such access mode: rc}}
do_test 4.3.2 {
list [catch {sqlite3 db "file:test.db?cache=public"} msg] $msg
} {1 {no such cache mode: public}}
#-------------------------------------------------------------------------
# Test that things work if an ATTACHed database uses a different VFS than
# the main database. The important point is that for all operations
@ -177,7 +228,7 @@ do_test 5.1.1 {
CREATE TABLE t1(a, b);
CREATE TABLE aux.t2(a, b);
PRAGMA main.journal_mode = WAL;
PRAGMA aux.journal_mode = PERSIST;
PRAGMA aux.journal_mode = WAL;
INSERT INTO t1 VALUES('x', 'y');
INSERT INTO t2 VALUES('x', 'y');
}