-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
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
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
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
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;
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
/* 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;
}
}
*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;
}
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 ){
/* 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,
#
# TODO: Fix this after the list of options is decided.
#
-do_test 4.0 {
+foreach {tn mode create_ok write_ok readonly_ok} {
+ 1 ro 0 0 1
+ 2 rw 0 1 0
+ 3 rwc 1 1 0
+} {
+ catch { db close }
+ forcedelete test.db
+
+ 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 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
-} {
- set RES(0) {0 {}}
- set RES(1) {1 {attempt to write a readonly database}}
- do_test 4.$tn {
- sqlite3 db $uri
+ 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) }
- } $RES($ro)
- db close
+ } $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
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');
}