-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
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
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
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
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
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
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
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
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
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
-d8b149f5e465f7794739ed0210e1e5c53110ee9a
\ No newline at end of file
+b8a8132e7148a7c90ca1352f20ab71d97b0bc4b0
\ No newline at end of file
};
#endif
-
+#ifndef SQLITE_USE_URI
+# define SQLITE_USE_URI 0
+#endif
/*
** The following singleton contains the global configuration for
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
+ SQLITE_USE_URI, /* bOpenUri */
0x7ffffffe, /* mxStrlen */
100, /* szLookaside */
500, /* nLookaside */
break;
}
+ case SQLITE_CONFIG_URI: {
+ sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
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"
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
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 ){
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.
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 ){
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);
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
** 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 ){
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
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 */
/* 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
/*
** Interpret the given string as a boolean value.
*/
-static u8 getBoolean(const char *z){
+u8 sqlite3GetBoolean(const char *z){
return getSafetyLevel(z)&1;
}
mask &= ~(SQLITE_ForeignKeys);
}
- if( getBoolean(zRight) ){
+ if( sqlite3GetBoolean(zRight) ){
db->flags |= mask;
}else{
db->flags &= ~mask;
int b = -1;
assert( pBt!=0 );
if( zRight ){
- b = getBoolean(zRight);
+ b = sqlite3GetBoolean(zRight);
}
if( pId2->n==0 && b>=0 ){
int ii;
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
if( zRight ){
- if( getBoolean(zRight) ){
+ if( sqlite3GetBoolean(zRight) ){
sqlite3ParserTrace(stderr, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
*/
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
if( zRight ){
- sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
+ sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight));
}
}else
#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 */
#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
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 */
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*);
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);
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:
**
{ "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 },
/* 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
*/
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{
-#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));
#endif
return (u8)(h & 0xf);
}
-#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/*
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;
}
--- /dev/null
+# 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
+