]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the start of the "uri-filenames" feature.
authordan <dan@noemail.net>
Fri, 22 Apr 2011 19:37:32 +0000 (19:37 +0000)
committerdan <dan@noemail.net>
Fri, 22 Apr 2011 19:37:32 +0000 (19:37 +0000)
FossilOrigin-Name: b8a8132e7148a7c90ca1352f20ab71d97b0bc4b0

12 files changed:
manifest
manifest.uuid
src/global.c
src/main.c
src/pager.c
src/pragma.c
src/sqlite.h.in
src/sqliteInt.h
src/test_malloc.c
src/test_vfs.c
src/util.c
test/uri.test [new file with mode: 0644]

index bcd5754bbe3fb033e11143bfad5a442049bce14f..936a159dc6a7e86cc1b61de121231aca62fc804d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index fde4759710ba6e3d3977e656d8ab678131e6ec95..66d198381bcf569d2f3cc3cc05fdd10948ef32e2 100644 (file)
@@ -1 +1 @@
-d8b149f5e465f7794739ed0210e1e5c53110ee9a
\ No newline at end of file
+b8a8132e7148a7c90ca1352f20ab71d97b0bc4b0
\ No newline at end of file
index 0c890684d97b623de7a5a38fa56d7b0268fb2d32..f01eaa8f4a83a79ae527ca72ff5fecbf1906db14 100644 (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 */
index 4aaa61899cbd426a0e0342872aff037162fa9c7a..e2bcf009b804a10459b71532ccb94722b6f707a7 100644 (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);
index 94f647dcc94e05653f30484f6b1ec2036a70f457..8ad6984f8aad55830926c217c9679ca89fd5d089 100644 (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
index 75ab26d441a0463a1d15e16b160d7c338f592596..799805c40b851961378dd03b7edd986d708a5e20 100644 (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
 
index 421da8e6bd2a3d5696d15340a479a4e776f87c94..abe5bc00805ef4c94159d57cb9a4ffca2df756af 100644 (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
index ea0925e4175ebf9d818f43b3d47f69e27ee8eb63..da1d42207c19bcf2fa7097c5b35ebcf2cc686870 100644 (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);
index c63ded7035bd121004972cfe967f1b25e1fb96cc..5023dca4455b20c6dcc54221465a763f3d70f1ce 100644 (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 },
index 64b3cb574b5eb81cb33c8a4125fc53a99426285d..53bdca68c125128480b93e7a36a2408b53cc0f06 100644 (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{
index 1c9b401f898a9a671f55f8b75be199720d68a27d..50dc591207167ab93f8906201f1d835f0b057e5c 100644 (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;
   }
diff --git a/test/uri.test b/test/uri.test
new file mode 100644 (file)
index 0000000..b10130b
--- /dev/null
@@ -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
+