/ Check-in [0715eb00]
Login

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

Overview
Comment:Add untested implementations of experimental APIs sqlite3_snapshot_get(), _open() and _free().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | snapshot-get
Files: files | file ages | folders
SHA1: 0715eb00aa8891400cd50a15509d3d7b13789626
User & Date: dan 2015-12-05 20:51:54
Context
2015-12-07
14:33
Add tests for snapshot_get(), _open() and _free(). check-in: 502cc6f3 user: dan tags: snapshot-get
2015-12-05
20:51
Add untested implementations of experimental APIs sqlite3_snapshot_get(), _open() and _free(). check-in: 0715eb00 user: dan tags: snapshot-get
2015-12-04
13:44
Remove the dependence on "exec ls -U" from the vtabH.test module, as the -U option to "ls" is not universally available. check-in: 4ecbc75b user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/main.c.

  3862   3862       (void)SQLITE_MISUSE_BKPT;
  3863   3863       return -1;
  3864   3864     }
  3865   3865   #endif
  3866   3866     pBt = sqlite3DbNameToBtree(db, zDbName);
  3867   3867     return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
  3868   3868   }
         3869  +
         3870  +#ifdef SQLITE_ENABLE_SNAPSHOT
         3871  +/*
         3872  +** Obtain a snapshot handle for the snapshot of database zDb currently 
         3873  +** being read by handle db.
         3874  +*/
         3875  +int sqlite3_snapshot_get(
         3876  +  sqlite3 *db, 
         3877  +  const char *zDb,
         3878  +  sqlite3_snapshot **ppSnapshot
         3879  +){
         3880  +  int rc = SQLITE_ERROR;
         3881  +#ifndef SQLITE_OMIT_WAL
         3882  +  int iDb;
         3883  +
         3884  +#ifdef SQLITE_ENABLE_API_ARMOR
         3885  +  if( !sqlite3SafetyCheckOk(db) ){
         3886  +    return SQLITE_MISUSE_BKPT;
         3887  +  }
         3888  +#endif
         3889  +  sqlite3_mutex_enter(db->mutex);
         3890  +
         3891  +  iDb = sqlite3FindDbName(db, zDb);
         3892  +  if( iDb==0 || iDb>1 ){
         3893  +    Btree *pBt = db->aDb[iDb].pBt;
         3894  +    if( 0!=sqlite3BtreeIsInReadTrans(pBt) 
         3895  +     && 0==sqlite3BtreeIsInTrans(pBt)
         3896  +    ){
         3897  +      rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
         3898  +    }
         3899  +  }
         3900  +
         3901  +  sqlite3_mutex_leave(db->mutex);
         3902  +#endif   /* SQLITE_OMIT_WAL */
         3903  +  return rc;
         3904  +}
         3905  +
         3906  +/*
         3907  +** Open a read-transaction on the snapshot idendified by pSnapshot.
         3908  +*/
         3909  +int sqlite3_snapshot_open(
         3910  +  sqlite3 *db, 
         3911  +  const char *zDb, 
         3912  +  sqlite3_snapshot *pSnapshot
         3913  +){
         3914  +  int rc = SQLITE_ERROR;
         3915  +#ifndef SQLITE_OMIT_WAL
         3916  +
         3917  +#ifdef SQLITE_ENABLE_API_ARMOR
         3918  +  if( !sqlite3SafetyCheckOk(db) ){
         3919  +    return SQLITE_MISUSE_BKPT;
         3920  +  }
         3921  +#endif
         3922  +  sqlite3_mutex_enter(db->mutex);
         3923  +  if( db->autoCommit==0 ){
         3924  +    int iDb;
         3925  +    iDb = sqlite3FindDbName(db, zDb);
         3926  +    if( iDb==0 || iDb>1 ){
         3927  +      Btree *pBt = db->aDb[iDb].pBt;
         3928  +      if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
         3929  +        rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot);
         3930  +        if( rc==SQLITE_OK ){
         3931  +          rc = sqlite3BtreeBeginTrans(pBt, 0);
         3932  +          sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
         3933  +        }
         3934  +      }
         3935  +    }
         3936  +  }
         3937  +
         3938  +  sqlite3_mutex_leave(db->mutex);
         3939  +#endif   /* SQLITE_OMIT_WAL */
         3940  +  return rc;
         3941  +}
         3942  +
         3943  +/*
         3944  +** Free a snapshot handle obtained from sqlite3_snapshot_get().
         3945  +*/
         3946  +void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
         3947  +  sqlite3_free(pSnapshot);
         3948  +}
         3949  +#endif /* SQLITE_ENABLE_SNAPSHOT */
         3950  +

Changes to src/pager.c.

  7297   7297         pPager->pWal = 0;
  7298   7298         pagerFixMaplimit(pPager);
  7299   7299       }
  7300   7300     }
  7301   7301     return rc;
  7302   7302   }
  7303   7303   
         7304  +#ifdef SQLITE_ENABLE_SNAPSHOT
         7305  +/*
         7306  +** If this is a WAL database, obtain a snapshot handle for the snapshot
         7307  +** currently open. Otherwise, return an error.
         7308  +*/
         7309  +int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
         7310  +  int rc = SQLITE_ERROR;
         7311  +  if( pPager->pWal ){
         7312  +    rc = sqlite3WalSnapshotGet(pPager->pWal, ppSnapshot);
         7313  +  }
         7314  +  return rc;
         7315  +}
         7316  +
         7317  +/*
         7318  +** If this is a WAL database, store a pointer to pSnapshot. Next time a
         7319  +** read transaction is opened, attempt to read from the snapshot it 
         7320  +** identifies. If this is not a WAL database, return an error.
         7321  +*/
         7322  +int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
         7323  +  int rc = SQLITE_OK;
         7324  +  if( pPager->pWal ){
         7325  +    sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
         7326  +  }else{
         7327  +    rc = SQLITE_ERROR;
         7328  +  }
         7329  +  return rc;
         7330  +}
         7331  +#endif /* SQLITE_ENABLE_SNAPSHOT */
  7304   7332   #endif /* !SQLITE_OMIT_WAL */
  7305   7333   
  7306   7334   #ifdef SQLITE_ENABLE_ZIPVFS
  7307   7335   /*
  7308   7336   ** A read-lock must be held on the pager when this function is called. If
  7309   7337   ** the pager is in WAL mode and the WAL file currently contains one or more
  7310   7338   ** frames, return the size in bytes of the page images stored within the

Changes to src/pager.h.

   164    164   
   165    165   #ifndef SQLITE_OMIT_WAL
   166    166     int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
   167    167     int sqlite3PagerWalSupported(Pager *pPager);
   168    168     int sqlite3PagerWalCallback(Pager *pPager);
   169    169     int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
   170    170     int sqlite3PagerCloseWal(Pager *pPager);
          171  +# ifdef SQLITE_ENABLE_SNAPSHOT
          172  +  int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
          173  +  int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
          174  +# endif
   171    175   #endif
   172    176   
   173    177   #ifdef SQLITE_ENABLE_ZIPVFS
   174    178     int sqlite3PagerWalFramesize(Pager *pPager);
   175    179   #endif
   176    180   
   177    181   /* Functions used to query pager state and configuration. */

Changes to src/sqlite.h.in.

  7874   7874   ** Otherwise, if no error occurs, SQLITE_OK is returned.
  7875   7875   **
  7876   7876   ** This function does not set the database handle error code or message
  7877   7877   ** returned by the sqlite3_errcode() and sqlite3_errmsg() functions.
  7878   7878   */
  7879   7879   int sqlite3_db_cacheflush(sqlite3*);
  7880   7880   
         7881  +/*
         7882  +** CAPI3REF: Open old database snapshots.
         7883  +**
         7884  +** The second argument passed to sqlite3_snapshot_get() must be the name
         7885  +** of a database file attached to the database handle passed as the first.
         7886  +** The database handle must have an open read transaction on the named 
         7887  +** database, which must be in wal mode. 
         7888  +**
         7889  +** If successful, sqlite3_snapshot_get() sets *ppSnapshot to point to a new
         7890  +** snapshot handle that may be used with sqlite3_snapshot_open() and returns
         7891  +** SQLITE_OK.
         7892  +**
         7893  +** If the specified database does not exist, or is not a wal mode database, 
         7894  +** or the database handle does not have an open read transaction on it,
         7895  +** SQLITE_ERROR is returned. If any other error occurs, for example an IO 
         7896  +** error or an OOM condition, the corresponding SQLite error code is 
         7897  +** returned.
         7898  +*/
         7899  +typedef struct sqlite3_snapshot sqlite3_snapshot;
         7900  +int sqlite3_snapshot_get(sqlite3*, const char*, sqlite3_snapshot **ppSnapshot);
         7901  +int sqlite3_snapshot_open(sqlite3*, const char*, sqlite3_snapshot*);
         7902  +void sqlite3_snapshot_free(sqlite3_snapshot*);
         7903  +
  7881   7904   /*
  7882   7905   ** Undo the hack that converts floating point types to integer for
  7883   7906   ** builds on processors without floating point support.
  7884   7907   */
  7885   7908   #ifdef SQLITE_OMIT_FLOATING_POINT
  7886   7909   # undef double
  7887   7910   #endif
  7888   7911   
  7889   7912   #ifdef __cplusplus
  7890   7913   }  /* End of the 'extern "C"' block */
  7891   7914   #endif
  7892   7915   #endif /* _SQLITE3_H_ */

Changes to src/test1.c.

  2264   2264       Tcl_WrongNumArgs(interp, 1, objv, "");
  2265   2265       return TCL_ERROR;
  2266   2266     }
  2267   2267     pVfs->xCurrentTimeInt64(pVfs, &t);
  2268   2268     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t));
  2269   2269     return TCL_OK;
  2270   2270   }
         2271  +
         2272  +/*
         2273  +** Usage: sqlite3_snapshot_get DB DBNAME
         2274  +*/
         2275  +static int test_snapshot_get(
         2276  +  void * clientData,
         2277  +  Tcl_Interp *interp,
         2278  +  int objc,
         2279  +  Tcl_Obj *CONST objv[]
         2280  +){
         2281  +  int rc;
         2282  +  sqlite3 *db;
         2283  +  char *zName;
         2284  +  sqlite3_snapshot *pSnapshot = 0;
         2285  +
         2286  +  if( objc!=3 ){
         2287  +    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
         2288  +    return TCL_ERROR;
         2289  +  }
         2290  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
         2291  +  zName = Tcl_GetString(objv[2]);
         2292  +
         2293  +  rc = sqlite3_snapshot_get(db, zName, &pSnapshot);
         2294  +  if( rc!=SQLITE_OK ){
         2295  +    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
         2296  +    return TCL_ERROR;
         2297  +  }else{
         2298  +    char zBuf[100];
         2299  +    if( sqlite3TestMakePointerStr(interp, zBuf, pSnapshot) ) return TCL_ERROR;
         2300  +    Tcl_SetObjResult(interp, Tcl_NewStringObj(zBuf, -1));
         2301  +  }
         2302  +  return TCL_OK;
         2303  +}
         2304  +
         2305  +/*
         2306  +** Usage: sqlite3_snapshot_open DB DBNAME SNAPSHOT
         2307  +*/
         2308  +static int test_snapshot_open(
         2309  +  void * clientData,
         2310  +  Tcl_Interp *interp,
         2311  +  int objc,
         2312  +  Tcl_Obj *CONST objv[]
         2313  +){
         2314  +  int rc;
         2315  +  sqlite3 *db;
         2316  +  char *zName;
         2317  +  sqlite3_snapshot *pSnapshot;
         2318  +
         2319  +  if( objc!=4 ){
         2320  +    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT");
         2321  +    return TCL_ERROR;
         2322  +  }
         2323  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
         2324  +  zName = Tcl_GetString(objv[2]);
         2325  +  pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[3]));
         2326  +
         2327  +  rc = sqlite3_snapshot_open(db, zName, pSnapshot);
         2328  +  if( rc!=SQLITE_OK ){
         2329  +    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
         2330  +    return TCL_ERROR;
         2331  +  }
         2332  +  return TCL_OK;
         2333  +}
         2334  +
         2335  +/*
         2336  +** Usage: sqlite3_snapshot_free SNAPSHOT
         2337  +*/
         2338  +static int test_snapshot_free(
         2339  +  void * clientData,
         2340  +  Tcl_Interp *interp,
         2341  +  int objc,
         2342  +  Tcl_Obj *CONST objv[]
         2343  +){
         2344  +  sqlite3_snapshot *pSnapshot;
         2345  +  if( objc!=2 ){
         2346  +    Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT");
         2347  +    return TCL_ERROR;
         2348  +  }
         2349  +  pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         2350  +  sqlite3_snapshot_free(pSnapshot);
         2351  +  return TCL_OK;
         2352  +}
  2271   2353   
  2272   2354   /*
  2273   2355   ** Usage:  sqlite3_next_stmt  DB  STMT
  2274   2356   **
  2275   2357   ** Return the next statment in sequence after STMT.
  2276   2358   */
  2277   2359   static int test_next_stmt(
................................................................................
  7079   7161        { "sqlite3_stmt_scanstatus",       test_stmt_scanstatus,   0 },
  7080   7162        { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset,   0 },
  7081   7163   #endif
  7082   7164   #ifdef SQLITE_ENABLE_SQLLOG
  7083   7165        { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
  7084   7166   #endif
  7085   7167        { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },
         7168  +#ifdef SQLITE_ENABLE_SNAPSHOT
         7169  +     { "sqlite3_snapshot_get", test_snapshot_get, 0 },
         7170  +     { "sqlite3_snapshot_open", test_snapshot_open, 0 },
         7171  +     { "sqlite3_snapshot_free", test_snapshot_free, 0 },
         7172  +#endif
  7086   7173     };
  7087   7174     static int bitmask_size = sizeof(Bitmask)*8;
  7088   7175     static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  7089   7176     int i;
  7090   7177     extern int sqlite3_sync_count, sqlite3_fullsync_count;
  7091   7178     extern int sqlite3_opentemp_count;
  7092   7179     extern int sqlite3_like_count;

Changes to src/wal.c.

   430    430     WalIndexHdr hdr;           /* Wal-index header for current transaction */
   431    431     u32 minFrame;              /* Ignore wal frames before this one */
   432    432     const char *zWalName;      /* Name of WAL file */
   433    433     u32 nCkpt;                 /* Checkpoint sequence counter in the wal-header */
   434    434   #ifdef SQLITE_DEBUG
   435    435     u8 lockError;              /* True if a locking error has occurred */
   436    436   #endif
          437  +#ifdef SQLITE_ENABLE_SNAPSHOT
          438  +  WalIndexHdr *pSnapshot;
          439  +#endif
   437    440   };
   438    441   
   439    442   /*
   440    443   ** Candidate values for Wal.exclusiveMode.
   441    444   */
   442    445   #define WAL_NORMAL_MODE     0
   443    446   #define WAL_EXCLUSIVE_MODE  1     
................................................................................
  2143   2146   */
  2144   2147   static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
  2145   2148     volatile WalCkptInfo *pInfo;    /* Checkpoint information in wal-index */
  2146   2149     u32 mxReadMark;                 /* Largest aReadMark[] value */
  2147   2150     int mxI;                        /* Index of largest aReadMark[] value */
  2148   2151     int i;                          /* Loop counter */
  2149   2152     int rc = SQLITE_OK;             /* Return code  */
         2153  +  int mxFrame;                    /* Wal frame to lock to */
  2150   2154   
  2151   2155     assert( pWal->readLock<0 );     /* Not currently locked */
  2152   2156   
  2153   2157     /* Take steps to avoid spinning forever if there is a protocol error.
  2154   2158     **
  2155   2159     ** Circumstances that cause a RETRY should only last for the briefest
  2156   2160     ** instances of time.  No I/O or other system calls are done while the
................................................................................
  2206   2210       }
  2207   2211       if( rc!=SQLITE_OK ){
  2208   2212         return rc;
  2209   2213       }
  2210   2214     }
  2211   2215   
  2212   2216     pInfo = walCkptInfo(pWal);
  2213         -  if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
         2217  +  if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame 
         2218  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2219  +   && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0
         2220  +     || 0==memcmp(&pWal->hdr, pWal->pSnapshot, sizeof(WalIndexHdr)))
         2221  +#endif
         2222  +  ){
  2214   2223       /* The WAL has been completely backfilled (or it is empty).
  2215   2224       ** and can be safely ignored.
  2216   2225       */
  2217   2226       rc = walLockShared(pWal, WAL_READ_LOCK(0));
  2218   2227       walShmBarrier(pWal);
  2219   2228       if( rc==SQLITE_OK ){
  2220   2229         if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
................................................................................
  2244   2253     /* If we get this far, it means that the reader will want to use
  2245   2254     ** the WAL to get at content from recent commits.  The job now is
  2246   2255     ** to select one of the aReadMark[] entries that is closest to
  2247   2256     ** but not exceeding pWal->hdr.mxFrame and lock that entry.
  2248   2257     */
  2249   2258     mxReadMark = 0;
  2250   2259     mxI = 0;
         2260  +  mxFrame = pWal->hdr.mxFrame;
         2261  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2262  +  if( pWal->pSnapshot ) mxFrame = pWal->pSnapshot->mxFrame;
         2263  +#endif
  2251   2264     for(i=1; i<WAL_NREADER; i++){
  2252   2265       u32 thisMark = pInfo->aReadMark[i];
  2253         -    if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
         2266  +    if( mxReadMark<=thisMark && thisMark<=mxFrame ){
  2254   2267         assert( thisMark!=READMARK_NOT_USED );
  2255   2268         mxReadMark = thisMark;
  2256   2269         mxI = i;
  2257   2270       }
  2258   2271     }
  2259   2272     /* There was once an "if" here. The extra "{" is to preserve indentation. */
  2260   2273     {
  2261   2274       if( (pWal->readOnly & WAL_SHM_RDONLY)==0
  2262         -     && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
         2275  +     && (mxReadMark<mxFrame || mxI==0)
  2263   2276       ){
  2264   2277         for(i=1; i<WAL_NREADER; i++){
  2265   2278           rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
  2266   2279           if( rc==SQLITE_OK ){
  2267         -          mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
         2280  +          mxReadMark = pInfo->aReadMark[i] = mxFrame;
  2268   2281             mxI = i;
  2269   2282             walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
  2270   2283             break;
  2271   2284           }else if( rc!=SQLITE_BUSY ){
  2272   2285             return rc;
  2273   2286           }
  2274   2287         }
................................................................................
  2345   2358   ** Pager layer will use this to know that is cache is stale and
  2346   2359   ** needs to be flushed.
  2347   2360   */
  2348   2361   int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
  2349   2362     int rc;                         /* Return code */
  2350   2363     int cnt = 0;                    /* Number of TryBeginRead attempts */
  2351   2364   
         2365  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2366  +  int bChanged = 0;
         2367  +  WalIndexHdr *pSnapshot = pWal->pSnapshot;
         2368  +  if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))){
         2369  +    bChanged = 1;
         2370  +  }
         2371  +#endif
         2372  +
  2352   2373     do{
  2353   2374       rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
  2354   2375     }while( rc==WAL_RETRY );
  2355   2376     testcase( (rc&0xff)==SQLITE_BUSY );
  2356   2377     testcase( (rc&0xff)==SQLITE_IOERR );
  2357   2378     testcase( rc==SQLITE_PROTOCOL );
  2358   2379     testcase( rc==SQLITE_OK );
         2380  +
         2381  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2382  +  if( rc==SQLITE_OK ){
         2383  +    if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr)) ){
         2384  +      volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
         2385  +      rc = walLockShared(pWal, WAL_READ_LOCK(0));
         2386  +      if( rc==SQLITE_OK ){
         2387  +        if( pInfo->nBackfill<=pSnapshot->mxFrame 
         2388  +         && pSnapshot->aSalt[0]==pWal->hdr.aSalt[0]
         2389  +         && pSnapshot->aSalt[1]==pWal->hdr.aSalt[1]
         2390  +        ){
         2391  +          assert( pWal->readLock>0 );
         2392  +          assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
         2393  +          memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
         2394  +          *pChanged = bChanged;
         2395  +        }else{
         2396  +          rc = SQLITE_BUSY_SNAPSHOT;
         2397  +        }
         2398  +        walUnlockShared(pWal, WAL_READ_LOCK(0));
         2399  +      }
         2400  +      if( rc!=SQLITE_OK ){
         2401  +        sqlite3WalEndReadTransaction(pWal);
         2402  +      }
         2403  +    }
         2404  +  }
         2405  +#endif
  2359   2406     return rc;
  2360   2407   }
  2361   2408   
  2362   2409   /*
  2363   2410   ** Finish with a read transaction.  All this does is release the
  2364   2411   ** read-lock.
  2365   2412   */
................................................................................
  3161   3208   ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
  3162   3209   ** WAL module is using shared-memory, return false. 
  3163   3210   */
  3164   3211   int sqlite3WalHeapMemory(Wal *pWal){
  3165   3212     return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
  3166   3213   }
  3167   3214   
         3215  +#ifdef SQLITE_ENABLE_SNAPSHOT
         3216  +int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){
         3217  +  int rc = SQLITE_OK;
         3218  +  WalIndexHdr *pRet;
         3219  +
         3220  +  assert( pWal->readLock>=0 && pWal->writeLock==0 );
         3221  +
         3222  +  pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr));
         3223  +  if( pRet==0 ){
         3224  +    rc = SQLITE_NOMEM;
         3225  +  }else{
         3226  +    memcpy(pRet, &pWal->hdr, sizeof(WalIndexHdr));
         3227  +    *ppSnapshot = (sqlite3_snapshot*)pRet;
         3228  +  }
         3229  +
         3230  +  return rc;
         3231  +}
         3232  +
         3233  +void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
         3234  +  pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
         3235  +}
         3236  +#endif /* SQLITE_ENABLE_SNAPSHOT */
         3237  +
  3168   3238   #ifdef SQLITE_ENABLE_ZIPVFS
  3169   3239   /*
  3170   3240   ** If the argument is not NULL, it points to a Wal object that holds a
  3171   3241   ** read-lock. This function returns the database page-size if it is known,
  3172   3242   ** or zero if it is not (or if pWal is NULL).
  3173   3243   */
  3174   3244   int sqlite3WalFramesize(Wal *pWal){
  3175   3245     assert( pWal==0 || pWal->readLock>=0 );
  3176   3246     return (pWal ? pWal->szPage : 0);
  3177   3247   }
  3178   3248   #endif
  3179   3249   
  3180   3250   #endif /* #ifndef SQLITE_OMIT_WAL */

Changes to src/wal.h.

   121    121   int sqlite3WalExclusiveMode(Wal *pWal, int op);
   122    122   
   123    123   /* Return true if the argument is non-NULL and the WAL module is using
   124    124   ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
   125    125   ** WAL module is using shared-memory, return false. 
   126    126   */
   127    127   int sqlite3WalHeapMemory(Wal *pWal);
          128  +
          129  +#ifdef SQLITE_ENABLE_SNAPSHOT
          130  +int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
          131  +void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
          132  +#endif
   128    133   
   129    134   #ifdef SQLITE_ENABLE_ZIPVFS
   130    135   /* If the WAL file is not empty, return the number of bytes of content
   131    136   ** stored in each frame (i.e. the db page-size when the WAL was created).
   132    137   */
   133    138   int sqlite3WalFramesize(Wal *pWal);
   134    139   #endif
   135    140   
   136    141   #endif /* ifndef SQLITE_OMIT_WAL */
   137    142   #endif /* _WAL_H_ */