public void Clear() { sqlite3_free(ref this.pData); this.pData = null; this.pExtra = null; this.pDirty = null; this.pgno = 0; this.pPager = null; #if SQLITE_CHECK_PAGES this.pageHash=0; #endif this.flags = 0; this.nRef = 0; this.pCache = null; this.pDirtyNext = null; this.pDirtyPrev = null; this.pPgHdr1 = null; }
/* ** Check that there are at least nSavepoint savepoints open. If there are ** currently less than nSavepoints open, then open one or more savepoints ** to make up the difference. If the number of savepoints is already ** equal to nSavepoint, then this function is a no-op. ** ** If a memory allocation fails, SQLITE_NOMEM is returned. If an error ** occurs while opening the sub-journal file, then an IO error code is ** returned. Otherwise, SQLITE_OK. */ static int sqlite3PagerOpenSavepoint( Pager pPager, int nSavepoint ) { int rc = SQLITE_OK; /* Return code */ int nCurrent = pPager.nSavepoint; /* Current number of savepoints */ if ( nSavepoint > nCurrent && pPager.useJournal != 0 ) { int ii; /* Iterator variable */ PagerSavepoint[] aNew; /* New Pager.aSavepoint array */ /* Either there is no active journal or the sub-journal is open or ** the journal is always stored in memory */ Debug.Assert( pPager.nSavepoint == 0 || isOpen( pPager.sjfd ) || pPager.journalMode == PAGER_JOURNALMODE_MEMORY ); /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM ** if the allocation fails. Otherwise, zero the new portion in case a ** malloc failure occurs while populating it in the for(...) loop below. */ //aNew = (PagerSavepoint *)sqlite3Realloc( // pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint //); Array.Resize( ref pPager.aSavepoint, nSavepoint ); aNew = pPager.aSavepoint; //if( null==aNew ){ // return SQLITE_NOMEM; //} // memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint)); // pPager.aSavepoint = aNew; pPager.nSavepoint = nSavepoint; /* Populate the PagerSavepoint structures just allocated. */ for ( ii = nCurrent; ii < nSavepoint; ii++ ) { Debug.Assert( pPager.dbSizeValid ); aNew[ii] = new PagerSavepoint(); aNew[ii].nOrig = pPager.dbSize; if ( isOpen( pPager.jfd ) && ALWAYS( pPager.journalOff > 0 ) ) { aNew[ii].iOffset = pPager.journalOff; } else { aNew[ii].iOffset = (int)JOURNAL_HDR_SZ( pPager ); } aNew[ii].iSubRec = pPager.nSubRec; aNew[ii].pInSavepoint = sqlite3BitvecCreate( pPager.dbSize ); if ( null == aNew[ii].pInSavepoint ) { return SQLITE_NOMEM; } } /* Open the sub-journal, if it is not already opened. */ rc = openSubJournal( pPager ); assertTruncateConstraint( pPager ); } return rc; }
//# define CODEC2(P,D,N,X,E,O) O=(char*)D static bool CODEC2( Pager P, byte[] D, uint N, int X, ref byte[] O ) { O = D; return false; }
// The E parameter is what executes when there is an error, // cannot implement here, since this is not really a macro // calling code must be modified to call E when truen //# define CODEC2(P,D,N,X,E,O) \ //if( P.xCodec==0 ){ O=(char*)D; }else \ //if( (O=(char*)(P.xCodec(P.pCodec,D,N,X)))==0 ){ E; } static bool CODEC2( Pager P, byte[] D, uint N, int X, ref byte[] O ) { if ( P.xCodec == null ) { O = D; // do nothing return false; } else { return ( ( O = P.xCodec( P.pCodec, D, N, X ) ) == null ); } }
/* ** The following two macros are used within the PAGERTRACE() macros above ** to print out file-descriptors. ** ** PAGERID() takes a pointer to a Pager struct as its argument. The ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file ** struct as its argument. */ //#define PAGERID(p) ((int)(p.fd)) static int PAGERID( Pager p ) { return p.GetHashCode(); }
static sqlite3_file sqlite3Pager_get_fd( Pager pPager ) { return ( isOpen( pPager.fd ) ) ? pPager.fd : null; }
/* BEGIN CRYPTO */ static void sqlite3pager_get_codec( Pager pPager, ref codec_ctx ctx ) { ctx = pPager.pCodec; }
/* ** The journal file must be open when this function is called. ** ** This function is a no-op if the journal file has not been written to ** within the current transaction (i.e. if Pager.journalOff==0). ** ** If doTruncate is non-zero or the Pager.journalSizeLimit variable is ** set to 0, then truncate the journal file to zero bytes in size. Otherwise, ** zero the 28-byte header at the start of the journal file. In either case, ** if the pager is not in no-sync mode, sync the journal file immediately ** after writing or truncating it. ** ** If Pager.journalSizeLimit is set to a positive, non-zero value, and ** following the truncation or zeroing described above the size of the ** journal file in bytes is larger than this value, then truncate the ** journal file to Pager.journalSizeLimit bytes. The journal file does ** not need to be synced following this operation. ** ** If an IO error occurs, abandon processing and return the IO error code. ** Otherwise, return SQLITE_OK. */ static int zeroJournalHdr( Pager pPager, int doTruncate ) { int rc = SQLITE_OK; /* Return code */ Debug.Assert( isOpen( pPager.jfd ) ); if ( pPager.journalOff != 0 ) { i64 iLimit = pPager.journalSizeLimit; /* Local cache of jsl */ IOTRACE( "JZEROHDR %p\n", pPager ); if ( doTruncate != 0 || iLimit == 0 ) { rc = sqlite3OsTruncate( pPager.jfd, 0 ); } else { byte[] zeroHdr = new byte[28];// = {0}; rc = sqlite3OsWrite( pPager.jfd, zeroHdr, zeroHdr.Length, 0 ); } if ( rc == SQLITE_OK && !pPager.noSync ) { rc = sqlite3OsSync( pPager.jfd, SQLITE_SYNC_DATAONLY | pPager.sync_flags ); } /* At this point the transaction is committed but the write lock ** is still held on the file. If there is a size limit configured for ** the persistent journal and the journal file currently consumes more ** space than that limit allows for, truncate it now. There is no need ** to sync the file following this operation. */ if ( rc == SQLITE_OK && iLimit > 0 ) { i64 sz = 0; rc = sqlite3OsFileSize( pPager.jfd, ref sz ); if ( rc == SQLITE_OK && sz > iLimit ) { rc = sqlite3OsTruncate( pPager.jfd, iLimit ); } } } return rc; }
/* ** Set or retrieve the codec for this pager */ static void sqlite3PagerSetCodec( Pager pPager, dxCodec xCodec, //void *(*xCodec)(void*,void*,Pgno,int), dxCodecSizeChng xCodecSizeChng, //void (*xCodecSizeChng)(void*,int,int), dxCodecFree xCodecFree, //void (*xCodecFree)(void*), codec_ctx pCodec ) { if ( pPager.xCodecFree != null ) pPager.xCodecFree( ref pPager.pCodec ); pPager.xCodec = (pPager.memDb!=0) ? null : xCodec; pPager.xCodecSizeChng = xCodecSizeChng; pPager.xCodecFree = xCodecFree; pPager.pCodec = pCodec; pagerReportSize( pPager ); }
/* ** Return true if fsync() calls are disabled for this pager. Return FALSE ** if fsync()s are executed normally. */ static bool sqlite3PagerNosync( Pager pPager ) { return pPager.noSync; }
/* ** Return the full pathname of the journal file. */ static string sqlite3PagerJournalname( Pager pPager ) { return pPager.zJournal; }
/* ** Return the file handle for the database file associated ** with the pager. This might return NULL if the file has ** not yet been opened. */ static sqlite3_file sqlite3PagerFile( Pager pPager ) { return pPager.fd; }
/* ** Return the VFS structure for the pager. */ static sqlite3_vfs sqlite3PagerVfs( Pager pPager ) { return pPager.pVfs; }
/* ** Return the full pathname of the database file. */ static string sqlite3PagerFilename( Pager pPager ) { return pPager.zFilename; }
/* ** This function is called to rollback or release (commit) a savepoint. ** The savepoint to release or rollback need not be the most recently ** created savepoint. ** ** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE. ** If it is SAVEPOINT_RELEASE, then release and destroy the savepoint with ** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes ** that have occurred since the specified savepoint was created. ** ** The savepoint to rollback or release is identified by parameter ** iSavepoint. A value of 0 means to operate on the outermost savepoint ** (the first created). A value of (Pager.nSavepoint-1) means operate ** on the most recently created savepoint. If iSavepoint is greater than ** (Pager.nSavepoint-1), then this function is a no-op. ** ** If a negative value is passed to this function, then the current ** transaction is rolled back. This is different to calling ** sqlite3PagerRollback() because this function does not terminate ** the transaction or unlock the database, it just restores the ** contents of the database to its original state. ** ** In any case, all savepoints with an index greater than iSavepoint ** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE), ** then savepoint iSavepoint is also destroyed. ** ** This function may return SQLITE_NOMEM if a memory allocation fails, ** or an IO error code if an IO error occurs while rolling back a ** savepoint. If no errors occur, SQLITE_OK is returned. */ static int sqlite3PagerSavepoint( Pager pPager, int op, int iSavepoint ) { int rc = SQLITE_OK; Debug.Assert( op == SAVEPOINT_RELEASE || op == SAVEPOINT_ROLLBACK ); Debug.Assert( iSavepoint >= 0 || op == SAVEPOINT_ROLLBACK ); if ( iSavepoint < pPager.nSavepoint ) { int ii; /* Iterator variable */ int nNew; /* Number of remaining savepoints after this op. */ /* Figure out how many savepoints will still be active after this ** operation. Store this value in nNew. Then free resources associated ** with any savepoints that are destroyed by this operation. */ nNew = iSavepoint + ((op == SAVEPOINT_RELEASE) ? 0 : 1); for (ii = nNew; ii < pPager.nSavepoint; ii++) { sqlite3BitvecDestroy( ref pPager.aSavepoint[ii].pInSavepoint ); } pPager.nSavepoint = nNew; /* If this is a release of the outermost savepoint, truncate ** the sub-journal to zero bytes in size. */ if (op == SAVEPOINT_RELEASE) { if (nNew == 0 && isOpen(pPager.sjfd)) { /* Only truncate if it is an in-memory sub-journal. */ if (sqlite3IsMemJournal(pPager.sjfd)) { rc = sqlite3OsTruncate(pPager.sjfd, 0); Debug.Assert(rc == SQLITE_OK); } pPager.nSubRec = 0; } } /* Else this is a rollback operation, playback the specified savepoint. ** If this is a temp-file, it is possible that the journal file has ** not yet been opened. In this case there have been no changes to ** the database file, so the playback operation can be skipped. */ else if ( isOpen( pPager.jfd ) ) { PagerSavepoint pSavepoint = ( nNew == 0 ) ? null : pPager.aSavepoint[nNew - 1]; rc = pagerPlaybackSavepoint( pPager, pSavepoint ); Debug.Assert( rc != SQLITE_DONE ); } } return rc; }
/* ** Return the offset of the sector boundary at or immediately ** following the value in pPager.journalOff, assuming a sector ** size of pPager.sectorSize bytes. ** ** i.e for a sector size of 512: ** ** Pager.journalOff Return value ** --------------------------------------- ** 0 0 ** 512 512 ** 100 512 ** 2000 2048 ** */ static i64 journalHdrOffset( Pager pPager ) { i64 offset = 0; i64 c = pPager.journalOff; if ( c != 0 ) { offset = (int)( ( ( c - 1 ) / pPager.sectorSize + 1 ) * pPager.sectorSize );//offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager); } Debug.Assert( offset % pPager.sectorSize == 0 ); //Debug.Assert(offset % JOURNAL_HDR_SZ(pPager) == 0); Debug.Assert( offset >= c ); Debug.Assert( ( offset - c ) < pPager.sectorSize );//Debug.Assert( (offset-c)<JOURNAL_HDR_SZ(pPager) ); return offset; }
static void seekJournalHdr( Pager pPager ) { pPager.journalOff = journalHdrOffset( pPager ); }
static object sqlite3PagerGetCodec( Pager pPager ) { return pPager.pCodec; }
/* ** The journal file must be open when this routine is called. A journal ** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the ** current location. ** ** The format for the journal header is as follows: ** - 8 bytes: Magic identifying journal format. ** - 4 bytes: Number of records in journal, or -1 no-sync mode is on. ** - 4 bytes: Random number used for page hash. ** - 4 bytes: Initial database page count. ** - 4 bytes: Sector size used by the process that wrote this journal. ** - 4 bytes: Database page size. ** ** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space. */ static int writeJournalHdr( Pager pPager ) { int rc = SQLITE_OK; /* Return code */ byte[] zHeader = pPager.pTmpSpace; /* Temporary space used to build header */ u32 nHeader = (u32)pPager.pageSize; /* Size of buffer pointed to by zHeader */ u32 nWrite; /* Bytes of header sector written */ int ii; /* Loop counter */ Debug.Assert( isOpen( pPager.jfd ) ); /* Journal file must be open. */ if ( nHeader > JOURNAL_HDR_SZ( pPager ) ) { nHeader = JOURNAL_HDR_SZ( pPager ); } /* If there are active savepoints and any of them were created ** since the most recent journal header was written, update the ** PagerSavepoint.iHdrOffset fields now. */ for ( ii = 0; ii < pPager.nSavepoint; ii++ ) { if ( pPager.aSavepoint[ii].iHdrOffset == 0 ) { pPager.aSavepoint[ii].iHdrOffset = pPager.journalOff; } } pPager.journalHdr = pPager.journalOff = journalHdrOffset( pPager ); /* ** Write the nRec Field - the number of page records that follow this ** journal header. Normally, zero is written to this value at this time. ** After the records are added to the journal (and the journal synced, ** if in full-sync mode), the zero is overwritten with the true number ** of records (see syncJournal()). ** ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When ** reading the journal this value tells SQLite to assume that the ** rest of the journal file contains valid page records. This assumption ** is dangerous, as if a failure occurred whilst writing to the journal ** file it may contain some garbage data. There are two scenarios ** where this risk can be ignored: ** ** * When the pager is in no-sync mode. Corruption can follow a ** power failure in this case anyway. ** ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees ** that garbage data is never appended to the journal file. */ Debug.Assert( isOpen( pPager.fd ) || pPager.noSync ); if ( ( pPager.noSync ) || ( pPager.journalMode == PAGER_JOURNALMODE_MEMORY ) || ( sqlite3OsDeviceCharacteristics( pPager.fd ) & SQLITE_IOCAP_SAFE_APPEND ) != 0 ) { aJournalMagic.CopyTo( zHeader, 0 );// memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); put32bits( zHeader, aJournalMagic.Length, 0xffffffff ); } else { Array.Clear( zHeader, 0, aJournalMagic.Length + 4 );//memset(zHeader, 0, sizeof(aJournalMagic)+4); } /* The random check-hash initialiser */ i64 i64Temp = 0; sqlite3_randomness( sizeof( i64 ), ref i64Temp ); pPager.cksumInit = (u32)i64Temp; put32bits( zHeader, aJournalMagic.Length + 4, pPager.cksumInit ); /* The initial database size */ put32bits( zHeader, aJournalMagic.Length + 8, pPager.dbOrigSize ); /* The assumed sector size for this process */ put32bits( zHeader, aJournalMagic.Length + 12, pPager.sectorSize ); /* The page size */ put32bits( zHeader, aJournalMagic.Length + 16, (u32)pPager.pageSize ); /* Initializing the tail of the buffer is not necessary. Everything ** works find if the following memset() is omitted. But initializing ** the memory prevents valgrind from complaining, so we are willing to ** take the performance hit. */ // memset(&zHeader[sizeof(aJournalMagic)+20], 0, // nHeader-(sizeof(aJournalMagic)+20)); Array.Clear( zHeader, aJournalMagic.Length + 20, (int)nHeader - ( aJournalMagic.Length + 20 ) ); /* In theory, it is only necessary to write the 28 bytes that the ** journal header consumes to the journal file here. Then increment the ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next ** record is written to the following sector (leaving a gap in the file ** that will be implicitly filled in by the OS). ** ** However it has been discovered that on some systems this pattern can ** be significantly slower than contiguously writing data to the file, ** even if that means explicitly writing data to the block of ** (JOURNAL_HDR_SZ - 28) bytes that will not be used. So that is what ** is done. ** ** The loop is required here in case the sector-size is larger than the ** database page size. Since the zHeader buffer is only Pager.pageSize ** bytes in size, more than one call to sqlite3OsWrite() may be required ** to populate the entire journal header sector. */ for ( nWrite = 0; rc == SQLITE_OK && nWrite < JOURNAL_HDR_SZ( pPager ); nWrite += nHeader ) { IOTRACE( "JHDR %p %lld %d\n", pPager, pPager.journalHdr, nHeader ); rc = sqlite3OsWrite( pPager.jfd, zHeader, (int)nHeader, pPager.journalOff ); pPager.journalOff += (int)nHeader; } return rc; }
/* ** Move the page pPg to location pgno in the file. ** ** There must be no references to the page previously located at ** pgno (which we call pPgOld) though that page is allowed to be ** in cache. If the page previously located at pgno is not already ** in the rollback journal, it is not put there by by this routine. ** ** References to the page pPg remain valid. Updating any ** meta-data associated with pPg (i.e. data stored in the nExtra bytes ** allocated along with the page) is the responsibility of the caller. ** ** A transaction must be active when this routine is called. It used to be ** required that a statement transaction was not active, but this restriction ** has been removed (CREATE INDEX needs to move a page when a statement ** transaction is active). ** ** If the fourth argument, isCommit, is non-zero, then this page is being ** moved as part of a database reorganization just before the transaction ** is being committed. In this case, it is guaranteed that the database page ** pPg refers to will not be written to again within this transaction. ** ** This function may return SQLITE_NOMEM or an IO error code if an error ** occurs. Otherwise, it returns SQLITE_OK. */ static int sqlite3PagerMovepage( Pager pPager, DbPage pPg, u32 pgno, int isCommit ) { PgHdr pPgOld; /* The page being overwritten. */ u32 needSyncPgno = 0; /* Old value of pPg.pgno, if sync is required */ int rc; /* Return code */ Pgno origPgno; /* The original page number */ Debug.Assert( pPg.nRef > 0 ); /* In order to be able to rollback, an in-memory database must journal ** the page we are moving from. */ if ( #if SQLITE_OMIT_MEMORYDB 1==MEMDB #else pPager.memDb != 0 #endif ) { rc = sqlite3PagerWrite( pPg ); if ( rc != 0 ) return rc; } /* If the page being moved is dirty and has not been saved by the latest ** savepoint, then save the current contents of the page into the ** sub-journal now. This is required to handle the following scenario: ** ** BEGIN; ** <journal page X, then modify it in memory> ** SAVEPOINT one; ** <Move page X to location Y> ** ROLLBACK TO one; ** ** If page X were not written to the sub-journal here, it would not ** be possible to restore its contents when the "ROLLBACK TO one" ** statement were is processed. ** ** subjournalPage() may need to allocate space to store pPg.pgno into ** one or more savepoint bitvecs. This is the reason this function ** may return SQLITE_NOMEM. */ if ( ( pPg.flags & PGHDR_DIRTY ) != 0 && subjRequiresPage( pPg ) && SQLITE_OK != ( rc = subjournalPage( pPg ) ) ) { return rc; } PAGERTRACE( "MOVE %d page %d (needSync=%d) moves to %d\n", PAGERID( pPager ), pPg.pgno, ( pPg.flags & PGHDR_NEED_SYNC ) != 0 ? 1 : 0, pgno ); IOTRACE( "MOVE %p %d %d\n", pPager, pPg.pgno, pgno ); /* If the journal needs to be sync()ed before page pPg.pgno can ** be written to, store pPg.pgno in local variable needSyncPgno. ** ** If the isCommit flag is set, there is no need to remember that ** the journal needs to be sync()ed before database page pPg.pgno ** can be written to. The caller has already promised not to write to it. */ if ( ( ( pPg.flags & PGHDR_NEED_SYNC ) != 0 ) && 0 == isCommit ) { needSyncPgno = pPg.pgno; Debug.Assert( pageInJournal( pPg ) || pPg.pgno > pPager.dbOrigSize ); Debug.Assert( ( pPg.flags & PGHDR_DIRTY ) != 0 ); Debug.Assert( pPager.needSync ); } /* If the cache contains a page with page-number pgno, remove it ** from its hash chain. Also, if the PgHdr.needSync was set for ** page pgno before the 'move' operation, it needs to be retained ** for the page moved there. */ pPg.flags &= ~PGHDR_NEED_SYNC; pPgOld = pager_lookup( pPager, pgno ); Debug.Assert( null == pPgOld || pPgOld.nRef == 1 ); if ( pPgOld != null ) { pPg.flags |= ( pPgOld.flags & PGHDR_NEED_SYNC ); if ( #if SQLITE_OMIT_MEMORYDB 1==MEMDB #else pPager.memDb != 0 #endif ) { /* Do not discard pages from an in-memory database since we might ** need to rollback later. Just move the page out of the way. */ Debug.Assert( pPager.dbSizeValid ); sqlite3PcacheMove( pPgOld, pPager.dbSize + 1 ); } else { sqlite3PcacheDrop( pPgOld ); } } origPgno = pPg.pgno; sqlite3PcacheMove( pPg, pgno ); sqlite3PcacheMakeDirty( pPg ); pPager.dbModified = true; if ( needSyncPgno != 0 ) { /* If needSyncPgno is non-zero, then the journal file needs to be ** sync()ed before any data is written to database file page needSyncPgno. ** Currently, no such page exists in the page-cache and the ** "is journaled" bitvec flag has been set. This needs to be remedied by ** loading the page into the pager-cache and setting the PgHdr.needSync ** flag. ** ** If the attempt to load the page into the page-cache fails, (due ** to a malloc() or IO failure), clear the bit in the pInJournal[] ** array. Otherwise, if the page is loaded and written again in ** this transaction, it may be written to the database file before ** it is synced into the journal file. This way, it may end up in ** the journal file twice, but that is not a problem. ** ** The sqlite3PagerGet() call may cause the journal to sync. So make ** sure the Pager.needSync flag is set too. */ PgHdr pPgHdr = null; Debug.Assert( pPager.needSync ); rc = sqlite3PagerGet( pPager, needSyncPgno, ref pPgHdr ); if ( rc != SQLITE_OK ) { if ( needSyncPgno <= pPager.dbOrigSize ) { Debug.Assert( pPager.pTmpSpace != null ); u32[] pTemp = new u32[pPager.pTmpSpace.Length]; sqlite3BitvecClear( pPager.pInJournal, needSyncPgno, pTemp );//pPager.pTmpSpace ); } return rc; } pPager.needSync = true; Debug.Assert( pPager.noSync == false && #if SQLITE_OMIT_MEMORYDB 0==MEMDB #else 0 == pPager.memDb #endif ); pPgHdr.flags |= PGHDR_NEED_SYNC; sqlite3PcacheMakeDirty( pPgHdr ); sqlite3PagerUnref( pPgHdr ); } /* ** For an in-memory database, make sure the original page continues ** to exist, in case the transaction needs to roll back. Use pPgOld ** as the original page since it has already been allocated. */ if ( #if SQLITE_OMIT_MEMORYDB MEMDB != 0 #else pPager.memDb != 0 #endif ) { sqlite3PcacheMove( pPgOld, origPgno ); sqlite3PagerUnref( pPgOld ); } return SQLITE_OK; }
static int sqlite3pager_is_mj_pgno( Pager pPager, Pgno pgno ) { return ( PAGER_MJ_PGNO( pPager ) == pgno ) ? 1 : 0; }
/* ** Get/set the locking-mode for this pager. Parameter eMode must be one ** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or ** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then ** the locking-mode is set to the value specified. ** ** The returned value is either PAGER_LOCKINGMODE_NORMAL or ** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated) ** locking-mode. */ static bool sqlite3PagerLockingMode( Pager pPager, int eMode ) { Debug.Assert( eMode == PAGER_LOCKINGMODE_QUERY || eMode == PAGER_LOCKINGMODE_NORMAL || eMode == PAGER_LOCKINGMODE_EXCLUSIVE ); Debug.Assert( PAGER_LOCKINGMODE_QUERY < 0 ); Debug.Assert( PAGER_LOCKINGMODE_NORMAL >= 0 && PAGER_LOCKINGMODE_EXCLUSIVE >= 0 ); if ( eMode >= 0 && !pPager.tempFile ) { pPager.exclusiveMode = eMode != 0; } return pPager.exclusiveMode; }
static void sqlite3pager_sqlite3PagerSetCodec( Pager pPager, dxCodec xCodec, dxCodecSizeChng xCodecSizeChng, dxCodecFree xCodecFree, codec_ctx pCodec ) { sqlite3PagerSetCodec( pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec ); }
/* ** Get/set the journal-mode for this pager. Parameter eMode must be one of: ** ** PAGER_JOURNALMODE_QUERY ** PAGER_JOURNALMODE_DELETE ** PAGER_JOURNALMODE_TRUNCATE ** PAGER_JOURNALMODE_PERSIST ** PAGER_JOURNALMODE_OFF ** PAGER_JOURNALMODE_MEMORY ** ** If the parameter is not _QUERY, then the journal_mode is set to the ** value specified if the change is allowed. The change is disallowed ** for the following reasons: ** ** * An in-memory database can only have its journal_mode set to _OFF ** or _MEMORY. ** ** * The journal mode may not be changed while a transaction is active. ** ** The returned indicate the current (possibly updated) journal-mode. */ static int sqlite3PagerJournalMode( Pager pPager, int eMode ) { Debug.Assert( eMode == PAGER_JOURNALMODE_QUERY || eMode == PAGER_JOURNALMODE_DELETE || eMode == PAGER_JOURNALMODE_TRUNCATE || eMode == PAGER_JOURNALMODE_PERSIST || eMode == PAGER_JOURNALMODE_OFF || eMode == PAGER_JOURNALMODE_MEMORY ); Debug.Assert( PAGER_JOURNALMODE_QUERY < 0 ); if ( eMode >= 0 && ( #if SQLITE_OMIT_MEMORYDB 0==MEMDB #else 0 == pPager.memDb #endif || eMode == PAGER_JOURNALMODE_MEMORY || eMode == PAGER_JOURNALMODE_OFF ) && !pPager.dbModified && ( !isOpen( pPager.jfd ) || 0 == pPager.journalOff ) ) { if ( isOpen( pPager.jfd ) ) { sqlite3OsClose( pPager.jfd ); } pPager.journalMode = (u8)eMode; } return (int)pPager.journalMode; }
/* ** A macro used for invoking the codec if there is one */ // The E parameter is what executes when there is an error, // cannot implement here, since this is not really a macro // calling code must be modified to call E when truen #if SQLITE_HAS_CODEC //# define CODEC1(P,D,N,X,E) \ //if( P.xCodec && P.xCodec(P.pCodec,D,N,X)==0 ){ E; } static bool CODEC1( Pager P, byte[] D, uint N /* page number */, int X /* E (moved to caller */) { return ( ( P.xCodec != null ) && ( P.xCodec( P.pCodec, D, N, X ) == null ) ); }
/* ** Get/set the size-limit used for persistent journal files. ** ** Setting the size limit to -1 means no limit is enforced. ** An attempt to set a limit smaller than -1 is a no-op. */ static i64 sqlite3PagerJournalSizeLimit( Pager pPager, i64 iLimit ) { if ( iLimit >= -1 ) { pPager.journalSizeLimit = iLimit; } return pPager.journalSizeLimit; }
//# define CODEC1(P,D,N,X,E) /* NO-OP */ static bool CODEC1 (Pager P, byte[] D, uint N /* page number */, int X /* E (moved to caller */) { return false; }
/* ** Return a pointer to the pPager.pBackup variable. The backup module ** in backup.c maintains the content of this variable. This module ** uses it opaquely as an argument to sqlite3BackupRestart() and ** sqlite3BackupUpdate() only. */ static sqlite3_backup sqlite3PagerBackupPtr( Pager pPager ) { return pPager.pBackup; }
const int SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT = -1;//#define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1 #endif /* ** The type used to represent a page number. The first page in a file ** is called page 1. 0 is used to represent "not a page". */ //typedef u32 Pgno; /* ** Each open file is managed by a separate instance of the "Pager" structure. */ //typedef struct Pager Pager; /* ** Handle type for pages. */ //typedef struct PgHdr DbPage; /* ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is ** reserved for working around a windows/posix incompatibility). It is ** used in the journal to signify that the remainder of the journal file ** is devoted to storing a master journal name - there are no more pages to ** roll back. See comments for function writeMasterJournal() in pager.c ** for details. */ //#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) static Pgno PAGER_MJ_PGNO( Pager x ) { return ( (Pgno)( ( PENDING_BYTE / ( ( x ).pageSize ) ) + 1 ) ); }
/* ** This function determines whether or not the atomic-write optimization ** can be used with this pager. The optimization can be used if: ** ** (a) the value returned by OsDeviceCharacteristics() indicates that ** a database page may be written atomically, and ** (b) the value returned by OsSectorSize() is less than or equal ** to the page size. ** ** The optimization is also always enabled for temporary files. It is ** an error to call this function if pPager is opened on an in-memory ** database. ** ** If the optimization cannot be used, 0 is returned. If it can be used, ** then the value returned is the size of the journal file when it ** contains rollback data for exactly one page. */ #if SQLITE_ENABLE_ATOMIC_WRITE static int jrnlBufferSize(Pager *pPager){ assert( 0==MEMDB ); if( !pPager.tempFile ){ int dc; /* Device characteristics */ int nSector; /* Sector size */ int szPage; /* Page size */ assert( isOpen(pPager.fd) ); dc = sqlite3OsDeviceCharacteristics(pPager.fd); nSector = pPager.sectorSize; szPage = pPager.pageSize; assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); if( 0==(dc&(SQLITE_IOCAP_ATOMIC|(szPage>>8)) || nSector>szPage) ){ return 0; } } return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); }