/ Check-in [68240e75]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Have the ATTACH command do URI interpretation in the same way as sqlite3_open() and sqlite3_open_v2() do.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | uri
Files: files | file ages | folders
SHA1: 68240e75e87a54cde93352b0ec364d34365a8170
User & Date: dan 2011-04-23 15:54:54
Context
2011-04-23
19:06
Test that it is now possible to use different VFSs for two databases attached to a single handle. check-in: 2af51f85 user: dan tags: uri
15:54
Have the ATTACH command do URI interpretation in the same way as sqlite3_open() and sqlite3_open_v2() do. check-in: 68240e75 user: dan tags: uri
10:12
Fix parsing of %00 in uri handling code. check-in: 44f0874a user: dan tags: uri
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/attach.c.

    66     66     sqlite3_value **argv
    67     67   ){
    68     68     int i;
    69     69     int rc = 0;
    70     70     sqlite3 *db = sqlite3_context_db_handle(context);
    71     71     const char *zName;
    72     72     const char *zFile;
           73  +  char *zPath = 0;
           74  +  char *zErr = 0;
           75  +  int flags;
    73     76     Db *aNew;
    74     77     char *zErrDyn = 0;
           78  +  sqlite3_vfs *pVfs;
    75     79   
    76     80     UNUSED_PARAMETER(NotUsed);
    77     81   
    78     82     zFile = (const char *)sqlite3_value_text(argv[0]);
    79     83     zName = (const char *)sqlite3_value_text(argv[1]);
    80     84     if( zFile==0 ) zFile = "";
    81     85     if( zName==0 ) zName = "";
................................................................................
   120    124     aNew = &db->aDb[db->nDb];
   121    125     memset(aNew, 0, sizeof(*aNew));
   122    126   
   123    127     /* Open the database file. If the btree is successfully opened, use
   124    128     ** it to obtain the database schema. At this point the schema may
   125    129     ** or may not be initialised.
   126    130     */
   127         -  rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0,
   128         -                        db->openFlags | SQLITE_OPEN_MAIN_DB);
          131  +  flags = db->openFlags;
          132  +  rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
          133  +  if( rc!=SQLITE_OK ){
          134  +    sqlite3_result_error(context, zErr, -1);
          135  +    sqlite3_free(zErr);
          136  +    return;
          137  +  }
          138  +  assert( pVfs );
          139  +  flags |= SQLITE_OPEN_MAIN_DB;
          140  +  rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
          141  +  sqlite3_free( zPath );
   129    142     db->nDb++;
   130    143     if( rc==SQLITE_CONSTRAINT ){
   131    144       rc = SQLITE_ERROR;
   132    145       zErrDyn = sqlite3MPrintf(db, "database is already attached");
   133    146     }else if( rc==SQLITE_OK ){
   134    147       Pager *pPager;
   135    148       aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);

Changes to src/btree.c.

  1684   1684   ** If the database is already opened in the same database connection
  1685   1685   ** and we are in shared cache mode, then the open will fail with an
  1686   1686   ** SQLITE_CONSTRAINT error.  We cannot allow two or more BtShared
  1687   1687   ** objects in the same database connection since doing so will lead
  1688   1688   ** to problems with locking.
  1689   1689   */
  1690   1690   int sqlite3BtreeOpen(
         1691  +  sqlite3_vfs *pVfs,      /* VFS to use for this b-tree */
  1691   1692     const char *zFilename,  /* Name of the file containing the BTree database */
  1692   1693     sqlite3 *db,            /* Associated database handle */
  1693   1694     Btree **ppBtree,        /* Pointer to new Btree object written here */
  1694   1695     int flags,              /* Options */
  1695   1696     int vfsFlags            /* Flags passed through to sqlite3_vfs.xOpen() */
  1696   1697   ){
  1697         -  sqlite3_vfs *pVfs;             /* The VFS to use for this btree */
  1698   1698     BtShared *pBt = 0;             /* Shared part of btree structure */
  1699   1699     Btree *p;                      /* Handle to return */
  1700   1700     sqlite3_mutex *mutexOpen = 0;  /* Prevents a race condition. Ticket #3537 */
  1701   1701     int rc = SQLITE_OK;            /* Result code from this function */
  1702   1702     u8 nReserve;                   /* Byte of unused space on each page */
  1703   1703     unsigned char zDbHeader[100];  /* Database header content */
  1704   1704   
................................................................................
  1712   1712     const int isMemdb = 0;
  1713   1713   #else
  1714   1714     const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0)
  1715   1715                          || (isTempDb && sqlite3TempInMemory(db));
  1716   1716   #endif
  1717   1717   
  1718   1718     assert( db!=0 );
         1719  +  assert( pVfs!=0 );
  1719   1720     assert( sqlite3_mutex_held(db->mutex) );
  1720   1721     assert( (flags&0xff)==flags );   /* flags fit in 8 bits */
  1721   1722   
  1722   1723     /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */
  1723   1724     assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 );
  1724   1725   
  1725   1726     /* A BTREE_SINGLE database is always a temporary and/or ephemeral */
................................................................................
  1730   1731     }
  1731   1732     if( isMemdb ){
  1732   1733       flags |= BTREE_MEMORY;
  1733   1734     }
  1734   1735     if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
  1735   1736       vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
  1736   1737     }
  1737         -  pVfs = db->pVfs;
  1738   1738     p = sqlite3MallocZero(sizeof(Btree));
  1739   1739     if( !p ){
  1740   1740       return SQLITE_NOMEM;
  1741   1741     }
  1742   1742     p->inTrans = TRANS_NONE;
  1743   1743     p->db = db;
  1744   1744   #ifndef SQLITE_OMIT_SHARED_CACHE

Changes to src/btree.h.

    38     38   */
    39     39   typedef struct Btree Btree;
    40     40   typedef struct BtCursor BtCursor;
    41     41   typedef struct BtShared BtShared;
    42     42   
    43     43   
    44     44   int sqlite3BtreeOpen(
           45  +  sqlite3_vfs *pVfs,       /* VFS to use with this b-tree */
    45     46     const char *zFilename,   /* Name of database file to open */
    46     47     sqlite3 *db,             /* Associated database connection */
    47     48     Btree **ppBtree,         /* Return open Btree* here */
    48     49     int flags,               /* Flags */
    49     50     int vfsFlags             /* Flags passed through to VFS open */
    50     51   );
    51     52   

Changes to src/build.c.

  3439   3439       static const int flags = 
  3440   3440             SQLITE_OPEN_READWRITE |
  3441   3441             SQLITE_OPEN_CREATE |
  3442   3442             SQLITE_OPEN_EXCLUSIVE |
  3443   3443             SQLITE_OPEN_DELETEONCLOSE |
  3444   3444             SQLITE_OPEN_TEMP_DB;
  3445   3445   
  3446         -    rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags);
         3446  +    rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags);
  3447   3447       if( rc!=SQLITE_OK ){
  3448   3448         sqlite3ErrorMsg(pParse, "unable to open a temporary database "
  3449   3449           "file for storing temporary tables");
  3450   3450         pParse->rc = rc;
  3451   3451         return 1;
  3452   3452       }
  3453   3453       db->aDb[1].pBt = pBt;

Changes to src/date.c.

  1035   1035     sqlite3_int64 iT;
  1036   1036     char zBuf[20];
  1037   1037   
  1038   1038     UNUSED_PARAMETER(argc);
  1039   1039     UNUSED_PARAMETER(argv);
  1040   1040   
  1041   1041     db = sqlite3_context_db_handle(context);
  1042         -  sqlite3OsCurrentTimeInt64(db->pVfs, &iT);
         1042  +  sqlite3OsCurrentTimeInt64(db->pVfs &iT);
  1043   1043     t = iT/1000 - 10000*(sqlite3_int64)21086676;
  1044   1044   #ifdef HAVE_GMTIME_R
  1045   1045     {
  1046   1046       struct tm sNow;
  1047   1047       gmtime_r(&t, &sNow);
  1048   1048       strftime(zBuf, 20, zFormat, &sNow);
  1049   1049     }

Changes to src/main.c.

  2102   2102     if( ((1<<(flags&7)) & 0x46)==0 ){
  2103   2103       rc = SQLITE_MISUSE;
  2104   2104       goto opendb_out;
  2105   2105     }
  2106   2106   
  2107   2107     /* Open the backend database driver */
  2108   2108     db->openFlags = flags;
  2109         -  rc = sqlite3BtreeOpen(zOpen, db, &db->aDb[0].pBt, 0,
         2109  +  rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
  2110   2110                           flags | SQLITE_OPEN_MAIN_DB);
  2111   2111     if( rc!=SQLITE_OK ){
  2112   2112       if( rc==SQLITE_IOERR_NOMEM ){
  2113   2113         rc = SQLITE_NOMEM;
  2114   2114       }
  2115   2115       sqlite3Error(db, rc, 0);
  2116   2116       goto opendb_out;

Changes to src/test3.c.

    74     74     if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
    75     75     nRefSqlite3++;
    76     76     if( nRefSqlite3==1 ){
    77     77       sDb.pVfs = sqlite3_vfs_find(0);
    78     78       sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
    79     79       sqlite3_mutex_enter(sDb.mutex);
    80     80     }
    81         -  rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, 0, 
           81  +  rc = sqlite3BtreeOpen(sDb.pVfs, argv[1], &sDb, &pBt, 0, 
    82     82        SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
    83     83     if( rc!=SQLITE_OK ){
    84     84       Tcl_AppendResult(interp, errorName(rc), 0);
    85     85       return TCL_ERROR;
    86     86     }
    87     87     sqlite3BtreeSetCacheSize(pBt, nCache);
    88     88     sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);

Changes to src/vdbe.c.

  3128   3128         SQLITE_OPEN_DELETEONCLOSE |
  3129   3129         SQLITE_OPEN_TRANSIENT_DB;
  3130   3130   
  3131   3131     assert( pOp->p1>=0 );
  3132   3132     pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
  3133   3133     if( pCx==0 ) goto no_mem;
  3134   3134     pCx->nullRow = 1;
  3135         -  rc = sqlite3BtreeOpen(0, db, &pCx->pBt, 
         3135  +  rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, 
  3136   3136                           BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
  3137   3137     if( rc==SQLITE_OK ){
  3138   3138       rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
  3139   3139     }
  3140   3140     if( rc==SQLITE_OK ){
  3141   3141       /* If a transient index is required, create it by calling
  3142   3142       ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before

Changes to test/uri.test.

    43     43     set file [string map [list PWD [pwd]] $file]
    44     44   
    45     45     forcedelete $file
    46     46     do_test 1.$tn.1 { file exists $file } 0
    47     47     set DB [sqlite3_open $uri]
    48     48     do_test 1.$tn.2 { file exists $file } 1
    49     49     sqlite3_close $DB
           50  +  forcedelete $file
           51  +
           52  +  do_test 1.$tn.3 { file exists $file } 0
           53  +  sqlite3 db xxx.db
           54  +  execsql { ATTACH $uri AS aux }
           55  +  do_test 1.$tn.4 { file exists $file } 1
           56  +  db close
    50     57   }
    51     58   
    52     59   
    53     60   #-------------------------------------------------------------------------
    54     61   # Test that URI query parameters are passed through to the VFS layer
    55     62   # correctly.
    56     63   #
................................................................................
    69     76     6      file:test%00.db?hello%00extra=world%00ex     {hello world}
    70     77     7      file:test%00.db?hello%00=world%00            {hello world}
    71     78     8      file:test%00.db?=world&xyz=abc               {xyz abc}
    72     79     9      file:test.db?%00hello=world&xyz=abc          {xyz abc}
    73     80     10     file:test.db?hello=%00world&xyz=             {hello {} xyz {}}
    74     81     11     file:test.db?=#ravada                        {}
    75     82     12     file:test.db?&&&&&&&&hello=world&&&&&&&      {hello world}
           83  +  13     test.db?&&&&&&&&hello=world&&&&&&&           {}
           84  +  14     http:test.db?hello&world                     {}
    76     85   } {
    77     86     set ::arglist ""
    78     87     set DB [sqlite3_open $uri]
    79         -  do_test 2.$tn { set ::arglist } $kvlist
           88  +  do_test 2.$tn.1 { set ::arglist } $kvlist
    80     89     sqlite3_close $DB
           90  +
           91  +  sqlite3 db xxx.db
           92  +  set ::arglist ""
           93  +  execsql { ATTACH $uri AS aux }
           94  +  do_test 2.$tn.2 { set ::arglist } $kvlist
           95  +  db close
    81     96   }
    82     97   tvfs delete
    83     98   
    84     99   #-------------------------------------------------------------------------
    85    100   # Test that specifying a non-existent VFS raises an error.
    86    101   #
    87    102   do_test 3.1 {
    88    103     list [catch { sqlite3 db "file:test.db?vfs=nosuchvfs" } msg] $msg
    89    104   } {1 {no such vfs: nosuchvfs}}
          105  +
          106  +#-------------------------------------------------------------------------
          107  +# Test the "readonly" URI option.
          108  +#
          109  +do_test 4.0 {
          110  +  sqlite3 db test.db
          111  +  db eval {CREATE TABLE t1(a, b)}
          112  +  db close
          113  +} {}
          114  +foreach {tn uri ro} {
          115  +  1    "file:test.db"                                 0
          116  +  2    "file:test.db?readonly=0"                      0
          117  +  3    "file:test.db?readonly=1&readwrite=0&create=0" 1
          118  +} {
          119  +  set RES(0) {0 {}}
          120  +  set RES(1) {1 {attempt to write a readonly database}}
          121  +
          122  +  do_test 4.$tn {
          123  +    sqlite3 db $uri
          124  +    catchsql { INSERT INTO t1 VALUES(1, 2) }
          125  +  } $RES($ro)
          126  +  db close
          127  +}
    90    128   
    91    129   finish_test
    92    130