Add the start of the "uri-filenames" feature.

FossilOrigin-Name: b8a8132e7148a7c90ca1352f20ab71d97b0bc4b0
This commit is contained in:
dan 2011-04-22 19:37:32 +00:00
parent fc083ab973
commit cd74b611f4
12 changed files with 351 additions and 58 deletions

View File

@ -1,5 +1,5 @@
C Update\sa\scomment\sin\se_createtable.test.
D 2011-04-20T13:35:44.094
C Add\sthe\sstart\sof\sthe\s"uri-filenames"\sfeature.
D 2011-04-22T19:37:32.658
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -134,7 +134,7 @@ F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91
F src/func.c 3a8cb2fb2de3e3aed7f39106daf4878d9d17fcce
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
F src/global.c 29bfb85611dd816b04f10fba0ca910366e128d38
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
@ -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 a8571665d43ff18f89a49d47a281605ce5ea825e
F src/main.c 88a93debb7448053dfa7182fa4ae723a80b0644d
F src/malloc.c 74c740e8ba22b806cfb980c8c0ddea1cbd54a20e
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
@ -164,13 +164,13 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
F src/os_unix.c d7889a0f9389c8c2e1d3b380f5aa1256c22a90e8
F src/os_win.c d149b9a7dfdd38de09afc054f8168cd3cd80630b
F src/pager.c 055239dcdfe12b3f5d97f6f01f85da01e2d6d912
F src/pager.c 24b689bc3639d534f5fb292d2c68038b1e720527
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
F src/pcache1.c d548e31beafa792d1994b663a29a5303569efc4e
F src/pragma.c 49c90ab27a4339d4b5bc0b03c08cbcf20ed8d454
F src/pragma.c 9e778decc3ee9bcaf88904b4a3b0a4360aaf0eab
F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4
F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
@ -178,9 +178,9 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff
F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79
F src/sqlite.h.in fe9a777d43276b4778e92b16a8b89ea6c38bb32b
F src/sqlite.h.in f8777aefc000c9e342cbc6676df168c196c2b624
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
F src/sqliteInt.h ac8f3f5846275c634f6649969304a9e97f6f9854
F src/sqliteInt.h 810f45e3151bc4a5a273aff4b881bfc9148f92c6
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@ -209,7 +209,7 @@ F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
F src/test_journal.c 785edd54f963aefb3c1628124170a56697c68c70
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
F src/test_malloc.c fd6188b1501c0010fb4241ddc9f0d5ac402c688d
F src/test_malloc.c 7ca7be34e0e09ef0ed6619544552ed95732e41f6
F src/test_multiplex.c fdabd793ee7a9642c5a8a470def2347144c46d05
F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
@ -225,7 +225,7 @@ F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
F src/test_syscall.c 162c4ec0137a549c009bb9ecab550527743cfc5d
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c 361ae0a0f1cbf5a28ad0388a258b104017a370c0
F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86
F src/test_vfs.c b6bab7382f4ed27a67b204250c0c22821c6e3ae9
F src/test_vfstrace.c 2265c9895f350c8d3c39b079998fbe7481505cc1
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
@ -233,7 +233,7 @@ F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
F src/trigger.c 144cc18bb701f3286484aae4292a9531f09278c8
F src/update.c 81911be16ece3c3e7716aa18565b4814ec41f8b9
F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60
F src/util.c 465fe10aabf0ca7d7826a156dab919b0b65c525a
F src/util.c 914e860d21496b19a912cd14f6f7a889a22f44e1
F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
F src/vdbe.c 05deeec6659f2579674a5e6510b3ada2a442f8d5
F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797
@ -837,6 +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 a9f84a838e73268c3fa9ed29b03512cb7baa7aca
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
F test/vacuum.test 29b60e8cc9e573b39676df6c4a75fe9e02d04a09
F test/vacuum2.test 91a84c9b08adfc4472097d2e8deb0150214e0e76
@ -929,7 +930,10 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 0dd09fc034c127718366d3a3183e367d2f9fd82d
R 056a0ea57c930302e35ea6c4f7c5b4b7
P d8b149f5e465f7794739ed0210e1e5c53110ee9a
R f623a8b9a02395ad34296947bebabb85
T *branch * uri
T *sym-uri *
T -sym-trunk *
U dan
Z b72241c9e230cb141bfcaf5fbf022480
Z 1128ec625dbb3b0786239aee8b2345ad

View File

@ -1 +1 @@
d8b149f5e465f7794739ed0210e1e5c53110ee9a
b8a8132e7148a7c90ca1352f20ab71d97b0bc4b0

View File

@ -129,7 +129,9 @@ const unsigned char sqlite3CtypeMap[256] = {
};
#endif
#ifndef SQLITE_USE_URI
# define SQLITE_USE_URI 0
#endif
/*
** The following singleton contains the global configuration for
@ -139,6 +141,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
0x7ffffffe, /* mxStrlen */
100, /* szLookaside */
500, /* nLookaside */

View File

@ -426,6 +426,11 @@ int sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_URI: {
sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
break;
}
default: {
rc = SQLITE_ERROR;
break;
@ -1785,6 +1790,150 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
return oldLimit; /* IMP: R-53341-35419 */
}
/*
** This function is used to parse filenames passed by the user to API
** functions sqlite3_open() or sqlite3_open_v2(), and for database filenames
** specified as part of ATTACH statements.
*/
int sqlite3ParseUri(
const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */
const char *zUri, /* Nul-terminated URI to parse */
int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */
sqlite3_vfs **ppVfs, /* OUT: VFS to use */
char **pzFile, /* OUT: Filename component of URI */
char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */
){
int flags = *pFlags;
const char *zVfs = zDefaultVfs;
char *zFile;
int nUri = sqlite3Strlen30(zUri);
assert( *pzErrMsg==0 );
if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri)
&& nUri>=5 && memcmp(zUri, "file:", 5)==0
){
char *zOpt = 0;
int eState; /* Parser state when parsing URI */
int iIn; /* Input character index */
int iOut = 0; /* Output character index */
int nByte = nUri+2; /* Bytes of space to allocate */
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
zFile = sqlite3_malloc(nByte);
if( !zFile ) return SQLITE_NOMEM;
/* Discard the scheme and authority segments of the URI. */
if( zUri[5]=='/' && zUri[6]=='/' ){
iIn = 7;
while( zUri[iIn] && zUri[iIn]!='/' ) iIn++;
}else{
iIn = 5;
}
/* Copy the filename and any query parameters into the zFile buffer.
** Decode %HH escape codes along the way.
**
** Within this loop, variable eState may be set to 0, 1 or 2, depending
** on the parsing context. As follows:
**
** 0: Parsing file-name.
** 1: Parsing name section of a name=value query parameter.
** 2: Parsing value section of a name=value query parameter.
*/
eState = 0;
while( zUri[iIn] && zUri[iIn]!='#' ){
char c = zUri[iIn++];
if( c=='%'
&& sqlite3Isxdigit(zUri[iIn])
&& sqlite3Isxdigit(zUri[iIn+1])
){
int codepoint = (sqlite3HexToInt(zUri[iIn++]) << 4);
codepoint += sqlite3HexToInt(zUri[iIn++]);
assert( codepoint>=0 && codepoint<256 );
if( codepoint==0 ) continue;
c = codepoint;
}else if( (eState==0 && c=='?') || (eState==1 && c=='=') ){
if( eState==0 ){
zOpt = &zFile[iOut+1];
}
eState++;
c = 0;
}else if( eState!=0 && c=='&' ){
if( eState==1 ) zFile[iOut++] = '\0';
eState = 1;
c = 0;
}
zFile[iOut++] = c;
}
if( eState==1 ) zFile[iOut++] = '\0';
zFile[iOut++] = '\0';
zFile[iOut++] = '\0';
/* 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. */
if( zOpt ){
struct Option {
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 }
};
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;
}
}
}
}
zOpt = &zVal[nVal+1];
}
}
}else{
zFile = sqlite3_malloc(nUri+2);
if( !zFile ) return SQLITE_NOMEM;
memcpy(zFile, zUri, nUri);
zFile[nUri] = '\0';
zFile[nUri+1] = '\0';
}
*ppVfs = sqlite3_vfs_find(zVfs);
if( *ppVfs==0 ){
sqlite3_free(zFile);
*pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs);
return SQLITE_ERROR;
}
*pFlags = flags;
*pzFile = zFile;
return SQLITE_OK;
}
/*
** This routine does the work of opening a database on behalf of
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
@ -1796,9 +1945,11 @@ static int openDatabase(
unsigned flags, /* Operational flags */
const char *zVfs /* Name of the VFS to use */
){
sqlite3 *db;
int rc;
int isThreadsafe;
sqlite3 *db; /* Store allocated handle here */
int rc; /* Return code */
int isThreadsafe; /* True for threadsafe connections */
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
*ppDb = 0;
#ifndef SQLITE_OMIT_AUTOINIT
@ -1806,24 +1957,6 @@ 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 ) return SQLITE_MISUSE;
if( sqlite3GlobalConfig.bCoreMutex==0 ){
isThreadsafe = 0;
}else if( flags & SQLITE_OPEN_NOMUTEX ){
@ -1903,13 +2036,6 @@ static int openDatabase(
sqlite3HashInit(&db->aModule);
#endif
db->pVfs = sqlite3_vfs_find(zVfs);
if( !db->pVfs ){
rc = SQLITE_ERROR;
sqlite3Error(db, rc, "no such vfs: %s", zVfs);
goto opendb_out;
}
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
** and UTF-16, so add a version for each to avoid any unnecessary
** conversions. The only error that can occur here is a malloc() failure.
@ -1932,9 +2058,38 @@ static int openDatabase(
createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0,
nocaseCollatingFunc, 0);
/* Parse the filename/URI argument. */
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
if( rc!=SQLITE_OK ){
sqlite3Error(db, rc, "%s", 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(zFilename, db, &db->aDb[0].pBt, 0,
rc = sqlite3BtreeOpen(zOpen, db, &db->aDb[0].pBt, 0,
flags | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_IOERR_NOMEM ){
@ -2027,6 +2182,7 @@ static int openDatabase(
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
opendb_out:
sqlite3_free(zOpen);
if( db ){
assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
sqlite3_mutex_leave(db->mutex);

View File

@ -4299,6 +4299,8 @@ int sqlite3PagerOpen(
int noReadlock = (flags & PAGER_NO_READLOCK)!=0; /* True to omit read-lock */
int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */
u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
const char *zUri = 0; /* URI args to copy */
int nUri = 0; /* Number of bytes of URI args at *zUri */
/* Figure out how much space is required for each journal file-handle
** (there are two of them, the main journal and the sub-journal). This
@ -4329,6 +4331,7 @@ int sqlite3PagerOpen(
** leave both nPathname and zPathname set to 0.
*/
if( zFilename && zFilename[0] ){
const char *z;
nPathname = pVfs->mxPathname+1;
zPathname = sqlite3Malloc(nPathname*2);
if( zPathname==0 ){
@ -4337,6 +4340,12 @@ int sqlite3PagerOpen(
zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
nPathname = sqlite3Strlen30(zPathname);
z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1];
while( *z ){
z += sqlite3Strlen30(z)+1;
z += sqlite3Strlen30(z)+1;
}
nUri = &z[1] - zUri;
if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
/* This branch is taken when the journal path required by
** the database being opened will be more than pVfs->mxPathname
@ -4369,7 +4378,7 @@ int sqlite3PagerOpen(
ROUND8(pcacheSize) + /* PCache object */
ROUND8(pVfs->szOsFile) + /* The main db file */
journalFileSize * 2 + /* The two journal files */
nPathname + 1 + /* zFilename */
nPathname + 1 + nUri + /* zFilename */
nPathname + 8 + 1 /* zJournal */
#ifndef SQLITE_OMIT_WAL
+ nPathname + 4 + 1 /* zWal */
@ -4391,8 +4400,9 @@ int sqlite3PagerOpen(
/* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
if( zPathname ){
assert( nPathname>0 );
pPager->zJournal = (char*)(pPtr += nPathname + 1);
pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri);
memcpy(pPager->zFilename, zPathname, nPathname);
memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
memcpy(pPager->zJournal, zPathname, nPathname);
memcpy(&pPager->zJournal[nPathname], "-journal", 8);
#ifndef SQLITE_OMIT_WAL

View File

@ -49,7 +49,7 @@ static u8 getSafetyLevel(const char *z){
/*
** Interpret the given string as a boolean value.
*/
static u8 getBoolean(const char *z){
u8 sqlite3GetBoolean(const char *z){
return getSafetyLevel(z)&1;
}
@ -219,7 +219,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
mask &= ~(SQLITE_ForeignKeys);
}
if( getBoolean(zRight) ){
if( sqlite3GetBoolean(zRight) ){
db->flags |= mask;
}else{
db->flags &= ~mask;
@ -433,7 +433,7 @@ void sqlite3Pragma(
int b = -1;
assert( pBt!=0 );
if( zRight ){
b = getBoolean(zRight);
b = sqlite3GetBoolean(zRight);
}
if( pId2->n==0 && b>=0 ){
int ii;
@ -1033,7 +1033,7 @@ void sqlite3Pragma(
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
if( zRight ){
if( getBoolean(zRight) ){
if( sqlite3GetBoolean(zRight) ){
sqlite3ParserTrace(stderr, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
@ -1047,7 +1047,7 @@ void sqlite3Pragma(
*/
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
if( zRight ){
sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight));
}
}else

View File

@ -479,6 +479,7 @@ int sqlite3_exec(
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
#define SQLITE_OPEN_URI 0x00100000 /* Ok for sqlite3_open_v2() */
/* Reserved: 0x00F00000 */
@ -1444,6 +1445,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
#define SQLITE_CONFIG_URI 17 /* int */
/*
** CAPI3REF: Database Connection Configuration Options

View File

@ -2420,6 +2420,7 @@ struct Sqlite3Config {
int bMemstat; /* True to enable memory status */
int bCoreMutex; /* True to enable core mutexing */
int bFullMutex; /* True to enable full mutexing */
int bOpenUri; /* True to interpret filenames as URIs */
int mxStrlen; /* Maximum string length */
int szLookaside; /* Default lookaside buffer size */
int nLookaside; /* Default lookaside buffer count */
@ -2655,6 +2656,7 @@ void sqlite3ExprListDelete(sqlite3*, ExprList*);
int sqlite3Init(sqlite3*, char**);
int sqlite3InitCallback(void*, int, char**, char**);
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
u8 sqlite3GetBoolean(const char *z);
void sqlite3ResetInternalSchema(sqlite3*, int);
void sqlite3BeginParse(Parse*,int);
void sqlite3CommitInternalChanges(sqlite3*);
@ -2919,6 +2921,7 @@ char sqlite3ExprAffinity(Expr *pExpr);
int sqlite3Atoi64(const char*, i64*, int, u8);
void sqlite3Error(sqlite3*, int, const char*,...);
void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
u8 sqlite3HexToInt(int h);
int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
const char *sqlite3ErrStr(int);
int sqlite3ReadSchema(Parse *pParse);

View File

@ -1174,6 +1174,35 @@ static int test_config_error(
return TCL_OK;
}
/*
** tclcmd: sqlite3_config_uri BOOLEAN
**
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
** opcodes and verify that they return errors.
*/
static int test_config_uri(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc;
int bOpenUri;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
return TCL_ERROR;
}
if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){
return TCL_ERROR;
}
rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
return TCL_OK;
}
/*
** Usage:
**
@ -1422,6 +1451,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_config_memstatus", test_config_memstatus ,0 },
{ "sqlite3_config_lookaside", test_config_lookaside ,0 },
{ "sqlite3_config_error", test_config_error ,0 },
{ "sqlite3_config_uri", test_config_uri ,0 },
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },

View File

@ -545,7 +545,7 @@ static int tvfsOpen(
/* Evaluate the Tcl script:
**
** SCRIPT xOpen FILENAME
** SCRIPT xOpen FILENAME KEY-VALUE-ARGS
**
** If the script returns an SQLite error code other than SQLITE_OK, an
** error is returned to the caller. If it returns SQLITE_OK, the new
@ -554,7 +554,19 @@ static int tvfsOpen(
*/
Tcl_ResetResult(p->interp);
if( p->pScript && p->mask&TESTVFS_OPEN_MASK ){
tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
Tcl_Obj *pArg = Tcl_NewObj();
Tcl_IncrRefCount(pArg);
if( flags&SQLITE_OPEN_MAIN_DB ){
const char *z = &zName[strlen(zName)+1];
while( *z ){
Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1));
z += strlen(z) + 1;
Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1));
z += strlen(z) + 1;
}
}
tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), pArg, 0);
Tcl_DecrRefCount(pArg);
if( tvfsResultCode(p, &rc) ){
if( rc!=SQLITE_OK ) return rc;
}else{

View File

@ -983,13 +983,12 @@ void sqlite3Put4byte(unsigned char *p, u32 v){
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/*
** Translate a single byte of Hex into an integer.
** This routine only works if h really is a valid hexadecimal
** character: 0..9a..fA..F
*/
static u8 hexToInt(int h){
u8 sqlite3HexToInt(int h){
assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
#ifdef SQLITE_ASCII
h += 9*(1&(h>>6));
@ -999,7 +998,6 @@ static u8 hexToInt(int h){
#endif
return (u8)(h & 0xf);
}
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/*
@ -1016,7 +1014,7 @@ void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
n--;
if( zBlob ){
for(i=0; i<n; i+=2){
zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]);
}
zBlob[i/2] = 0;
}

75
test/uri.test Normal file
View File

@ -0,0 +1,75 @@
# 2011 April 22
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix uri
db close
sqlite3_shutdown
sqlite3_config_uri 1
#-------------------------------------------------------------------------
# Test that file names are correctly extracted from URIs.
#
foreach {tn uri file} {
1 test.db test.db
2 file:test.db test.db
3 file://an-authorityPWD/test.db test.db
4 file:PWD/test.db test.db
5 file:test.db?mork=1 test.db
6 file:test.db?mork=1&tonglor=2 test.db
7 file:test.db?mork=1#boris test.db
8 file:test.db#boris test.db
9 test.db#boris test.db#boris
10 test.db?mork=1#boris test.db?mork=1#boris
11 file:test%2Edb test.db
12 file file
13 http:test.db http:test.db
} {
set uri [string map [list PWD [pwd]] $uri]
set file [string map [list PWD [pwd]] $file]
forcedelete $file
do_test 1.$tn.1 { file exists $file } 0
set DB [sqlite3_open $uri]
do_test 1.$tn.2 { file exists $file } 1
sqlite3_close $DB
}
#-------------------------------------------------------------------------
# Test that URI query parameters are passed through to the VFS layer
# correctly.
#
testvfs tvfs -default 1
tvfs filter xOpen
tvfs script open_method
proc open_method {method file arglist} {
set ::arglist $arglist
}
breakpoint
foreach {tn uri kvlist} {
1 file:test.db?hello=world {hello world}
2 file:test.db?hello&world {hello {} world {}}
3 file:test.db?hello=1&world=2&vfs=tvfs {hello 1 world 2 vfs tvfs}
4 file:test.db?hello=1&world=2&vfs=unix {}
} {
set ::arglist ""
set DB [sqlite3_open $uri]
do_test 2.$tn { set ::arglist } $kvlist
sqlite3_close $DB
}
finish_test