reverse SQLite check-in 5a877221

This commit is contained in:
Stephen Lombardo 2020-05-13 16:33:13 -04:00
parent b8e6e270b1
commit ba6367543d
21 changed files with 601 additions and 58 deletions

View File

@ -187,6 +187,42 @@ static void attachFunc(
if( rc==SQLITE_OK && pNew->zDbSName==0 ){ if( rc==SQLITE_OK && pNew->zDbSName==0 ){
rc = SQLITE_NOMEM_BKPT; rc = SQLITE_NOMEM_BKPT;
} }
#ifdef SQLITE_HAS_CODEC
if( rc==SQLITE_OK ){
extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
int t = sqlite3_value_type(argv[2]);
switch( t ){
case SQLITE_INTEGER:
case SQLITE_FLOAT:
zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
rc = SQLITE_ERROR;
break;
case SQLITE_TEXT:
case SQLITE_BLOB:
nKey = sqlite3_value_bytes(argv[2]);
zKey = (char *)sqlite3_value_blob(argv[2]);
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
break;
case SQLITE_NULL:
/* No key specified. Use the key from URI filename, or if none,
** use the key from the main database. */
if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
}
}
break;
}
}
#endif
sqlite3_free( zPath ); sqlite3_free( zPath );
/* If the file was opened successfully, read the schema for the new database. /* If the file was opened successfully, read the schema for the new database.

View File

@ -256,6 +256,13 @@ static int backupOnePage(
int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
const int nCopy = MIN(nSrcPgsz, nDestPgsz); const int nCopy = MIN(nSrcPgsz, nDestPgsz);
const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
#ifdef SQLITE_HAS_CODEC
/* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is
** guaranteed that the shared-mutex is held by this thread, handle
** p->pSrc may not actually be the owner. */
int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest);
#endif
int rc = SQLITE_OK; int rc = SQLITE_OK;
i64 iOff; i64 iOff;
@ -272,6 +279,26 @@ static int backupOnePage(
rc = SQLITE_READONLY; rc = SQLITE_READONLY;
} }
#ifdef SQLITE_HAS_CODEC
/* Backup is not possible if the page size of the destination is changing
** and a codec is in use.
*/
if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){
rc = SQLITE_READONLY;
}
/* Backup is not possible if the number of bytes of reserve space differ
** between source and destination. If there is a difference, try to
** fix the destination to agree with the source. If that is not possible,
** then the backup cannot proceed.
*/
if( nSrcReserve!=nDestReserve ){
u32 newPgsz = nSrcPgsz;
rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve);
if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY;
}
#endif
/* This loop runs once for each destination page spanned by the source /* This loop runs once for each destination page spanned by the source
** page. For each iteration, variable iOff is set to the byte offset ** page. For each iteration, variable iOff is set to the byte offset
** of the destination page. ** of the destination page.
@ -767,6 +794,10 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
b.pDest = pTo; b.pDest = pTo;
b.iNext = 1; b.iNext = 1;
#ifdef SQLITE_HAS_CODEC
sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom));
#endif
/* 0x7FFFFFFF is the hard limit for the number of pages in a database /* 0x7FFFFFFF is the hard limit for the number of pages in a database
** file. By passing this as the number of pages to copy to ** file. By passing this as the number of pages to copy to
** sqlite3_backup_step(), we can guarantee that the copy finishes ** sqlite3_backup_step(), we can guarantee that the copy finishes

View File

@ -2859,6 +2859,9 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
assert( nReserve>=-1 && nReserve<=255 ); assert( nReserve>=-1 && nReserve<=255 );
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
#if SQLITE_HAS_CODEC
if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve;
#endif
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){ if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
return SQLITE_READONLY; return SQLITE_READONLY;
@ -2919,6 +2922,9 @@ int sqlite3BtreeGetOptimalReserve(Btree *p){
int n; int n;
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
n = sqlite3BtreeGetReserveNoMutex(p); n = sqlite3BtreeGetReserveNoMutex(p);
#ifdef SQLITE_HAS_CODEC
if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve;
#endif
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
return n; return n;
} }

View File

@ -417,6 +417,9 @@ struct BtShared {
#endif #endif
u8 inTransaction; /* Transaction state */ u8 inTransaction; /* Transaction state */
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
#ifdef SQLITE_HAS_CODEC
u8 optimalReserve; /* Desired amount of reserved space per page */
#endif
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */

View File

@ -355,6 +355,9 @@ static const char * const sqlite3azCompileOpt[] = {
#if SQLITE_FTS5_NO_WITHOUT_ROWID #if SQLITE_FTS5_NO_WITHOUT_ROWID
"FTS5_NO_WITHOUT_ROWID", "FTS5_NO_WITHOUT_ROWID",
#endif #endif
#if SQLITE_HAS_CODEC
"HAS_CODEC",
#endif
#if HAVE_ISNAN || SQLITE_HAVE_ISNAN #if HAVE_ISNAN || SQLITE_HAVE_ISNAN
"HAVE_ISNAN", "HAVE_ISNAN",
#endif #endif

View File

@ -135,9 +135,16 @@ const unsigned char sqlite3CtypeMap[256] = {
** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
** disabled. The default value may be changed by compiling with the ** disabled. The default value may be changed by compiling with the
** SQLITE_USE_URI symbol defined. ** SQLITE_USE_URI symbol defined.
**
** URI filenames are enabled by default if SQLITE_HAS_CODEC is
** enabled.
*/ */
#ifndef SQLITE_USE_URI #ifndef SQLITE_USE_URI
# define SQLITE_USE_URI 0 # ifdef SQLITE_HAS_CODEC
# define SQLITE_USE_URI 1
# else
# define SQLITE_USE_URI 0
# endif
#endif #endif
/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the

View File

@ -3007,6 +3007,41 @@ static const char *uriParameter(const char *zFilename, const char *zParam){
return 0; return 0;
} }
#if defined(SQLITE_HAS_CODEC)
/*
** Process URI filename query parameters relevant to the SQLite Encryption
** Extension. Return true if any of the relevant query parameters are
** seen and return false if not.
*/
int sqlite3CodecQueryParameters(
sqlite3 *db, /* Database connection */
const char *zDb, /* Which schema is being created/attached */
const char *zUri /* URI filename */
){
const char *zKey;
if( zUri==0 ){
return 0;
}else if( (zKey = uriParameter(zUri, "hexkey"))!=0 && zKey[0] ){
u8 iByte;
int i;
char zDecoded[40];
for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
if( (i&1)!=0 ) zDecoded[i/2] = iByte;
}
sqlite3_key_v2(db, zDb, zDecoded, i/2);
return 1;
}else if( (zKey = uriParameter(zUri, "key"))!=0 ){
sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey));
return 1;
}else if( (zKey = uriParameter(zUri, "textkey"))!=0 ){
sqlite3_key_v2(db, zDb, zKey, -1);
return 1;
}else{
return 0;
}
}
#endif
/* /*
@ -3397,6 +3432,9 @@ opendb_out:
void *pArg = sqlite3GlobalConfig.pSqllogArg; void *pArg = sqlite3GlobalConfig.pSqllogArg;
sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
} }
#endif
#if defined(SQLITE_HAS_CODEC)
if( rc==SQLITE_OK ) sqlite3CodecQueryParameters(db, 0, zOpen);
#endif #endif
sqlite3_free(zOpen); sqlite3_free(zOpen);
return rc & 0xff; return rc & 0xff;

View File

@ -406,6 +406,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
*/ */
#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
/*
** A macro used for invoking the codec if there is one
*/
#ifdef SQLITE_HAS_CODEC
# define CODEC1(P,D,N,X,E) \
if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; }
# 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; }
#else
# define CODEC1(P,D,N,X,E) /* NO-OP */
# define CODEC2(P,D,N,X,E,O) O=(char*)D
#endif
/* /*
** The maximum allowed sector size. 64KiB. If the xSectorsize() method ** The maximum allowed sector size. 64KiB. If the xSectorsize() method
** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
@ -691,6 +705,12 @@ struct Pager {
#endif #endif
void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
#ifdef SQLITE_HAS_CODEC
void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
void (*xCodecFree)(void*); /* Destructor for the codec */
void *pCodec; /* First argument to xCodec... methods */
#endif
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
PCache *pPCache; /* Pointer to page cache object */ PCache *pPCache; /* Pointer to page cache object */
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
@ -817,6 +837,9 @@ static const unsigned char aJournalMagic[] = {
int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
if( pPager->fd->pMethods==0 ) return 0; if( pPager->fd->pMethods==0 ) return 0;
if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
#ifdef SQLITE_HAS_CODEC
if( pPager->xCodec!=0 ) return 0;
#endif
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
if( pPager->pWal ){ if( pPager->pWal ){
u32 iRead = 0; u32 iRead = 0;
@ -1050,7 +1073,11 @@ static void setGetterMethod(Pager *pPager){
if( pPager->errCode ){ if( pPager->errCode ){
pPager->xGet = getPageError; pPager->xGet = getPageError;
#if SQLITE_MAX_MMAP_SIZE>0 #if SQLITE_MAX_MMAP_SIZE>0
}else if( USEFETCH(pPager) ){ }else if( USEFETCH(pPager)
#ifdef SQLITE_HAS_CODEC
&& pPager->xCodec==0
#endif
){
pPager->xGet = getPageMMap; pPager->xGet = getPageMMap;
#endif /* SQLITE_MAX_MMAP_SIZE>0 */ #endif /* SQLITE_MAX_MMAP_SIZE>0 */
}else{ }else{
@ -2198,6 +2225,35 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
return cksum; return cksum;
} }
/*
** Report the current page size and number of reserved bytes back
** to the codec.
*/
#ifdef SQLITE_HAS_CODEC
static void pagerReportSize(Pager *pPager){
if( pPager->xCodecSizeChng ){
pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
(int)pPager->nReserve);
}
}
#else
# define pagerReportSize(X) /* No-op if we do not support a codec */
#endif
#ifdef SQLITE_HAS_CODEC
/*
** Make sure the number of reserved bits is the same in the destination
** pager as it is in the source. This comes up when a VACUUM changes the
** number of reserved bits to the "optimal" amount.
*/
void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
if( pDest->nReserve!=pSrc->nReserve ){
pDest->nReserve = pSrc->nReserve;
pagerReportSize(pDest);
}
}
#endif
/* /*
** Read a single page from either the journal file (if isMainJrnl==1) or ** Read a single page from either the journal file (if isMainJrnl==1) or
** from the sub-journal (if isMainJrnl==0) and playback that page. ** from the sub-journal (if isMainJrnl==0) and playback that page.
@ -2249,6 +2305,11 @@ static int pager_playback_one_page(
char *aData; /* Temporary storage for the page */ char *aData; /* Temporary storage for the page */
sqlite3_file *jfd; /* The file descriptor for the journal file */ sqlite3_file *jfd; /* The file descriptor for the journal file */
int isSynced; /* True if journal page is synced */ int isSynced; /* True if journal page is synced */
#ifdef SQLITE_HAS_CODEC
/* The jrnlEnc flag is true if Journal pages should be passed through
** the codec. It is false for pure in-memory journals. */
const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
#endif
assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
@ -2311,6 +2372,7 @@ static int pager_playback_one_page(
*/ */
if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
pPager->nReserve = ((u8*)aData)[20]; pPager->nReserve = ((u8*)aData)[20];
pagerReportSize(pPager);
} }
/* If the pager is in CACHEMOD state, then there must be a copy of this /* If the pager is in CACHEMOD state, then there must be a copy of this
@ -2378,12 +2440,26 @@ static int pager_playback_one_page(
** is if the data was just read from an in-memory sub-journal. In that ** is if the data was just read from an in-memory sub-journal. In that
** case it must be encrypted here before it is copied into the database ** case it must be encrypted here before it is copied into the database
** file. */ ** file. */
#ifdef SQLITE_HAS_CODEC
if( !jrnlEnc ){
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
}else
#endif
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
if( pgno>pPager->dbFileSize ){ if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno; pPager->dbFileSize = pgno;
} }
if( pPager->pBackup ){ if( pPager->pBackup ){
#ifdef SQLITE_HAS_CODEC
if( jrnlEnc ){
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);
}else
#endif
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
} }
}else if( !isMainJrnl && pPg==0 ){ }else if( !isMainJrnl && pPg==0 ){
@ -2434,6 +2510,11 @@ static int pager_playback_one_page(
if( pgno==1 ){ if( pgno==1 ){
memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
} }
/* Decode the page just read from disk */
#if SQLITE_HAS_CODEC
if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); }
#endif
sqlite3PcacheRelease(pPg); sqlite3PcacheRelease(pPg);
} }
return rc; return rc;
@ -2993,6 +3074,8 @@ static int readDbPage(PgHdr *pPg){
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
} }
} }
CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT);
PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead); PAGER_INCR(pPager->nRead);
IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
@ -3736,6 +3819,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
if( nReserve<0 ) nReserve = pPager->nReserve; if( nReserve<0 ) nReserve = pPager->nReserve;
assert( nReserve>=0 && nReserve<1000 ); assert( nReserve>=0 && nReserve<1000 );
pPager->nReserve = (i16)nReserve; pPager->nReserve = (i16)nReserve;
pagerReportSize(pPager);
pagerFixMaplimit(pPager); pagerFixMaplimit(pPager);
} }
return rc; return rc;
@ -4131,6 +4215,11 @@ int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
sqlite3OsClose(pPager->fd); sqlite3OsClose(pPager->fd);
sqlite3PageFree(pTmp); sqlite3PageFree(pTmp);
sqlite3PcacheClose(pPager->pPCache); sqlite3PcacheClose(pPager->pPCache);
#ifdef SQLITE_HAS_CODEC
if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
#endif
assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !pPager->aSavepoint && !pPager->pInJournal );
assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );
@ -4381,7 +4470,8 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
if( pList->pgno==1 ) pager_write_changecounter(pList); if( pList->pgno==1 ) pager_write_changecounter(pList);
pData = pList->pData; /* Encode the database */
CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);
/* Write out the page data. */ /* Write out the page data. */
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
@ -4470,6 +4560,12 @@ static int subjournalPage(PgHdr *pPg){
void *pData = pPg->pData; void *pData = pPg->pData;
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
char *pData2; char *pData2;
#if SQLITE_HAS_CODEC
if( !pPager->subjInMemory ){
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
}else
#endif
pData2 = pData; pData2 = pData;
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
rc = write32bits(pPager->sjfd, offset, pPg->pgno); rc = write32bits(pPager->sjfd, offset, pPg->pgno);
@ -5551,6 +5647,9 @@ static int getPageMMap(
); );
assert( USEFETCH(pPager) ); assert( USEFETCH(pPager) );
#ifdef SQLITE_HAS_CODEC
assert( pPager->xCodec==0 );
#endif
/* Optimization note: Adding the "pgno<=1" term before "pgno==0" here /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here
** allows the compiler optimizer to reuse the results of the "pgno>1" ** allows the compiler optimizer to reuse the results of the "pgno>1"
@ -5879,7 +5978,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
assert( pPager->journalHdr<=pPager->journalOff ); assert( pPager->journalHdr<=pPager->journalOff );
pData2 = pPg->pData; CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
cksum = pager_cksum(pPager, (u8*)pData2); cksum = pager_cksum(pPager, (u8*)pData2);
/* Even if an IO or diskfull error occurs while journalling the /* Even if an IO or diskfull error occurs while journalling the
@ -6244,7 +6343,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
if( DIRECT_MODE ){ if( DIRECT_MODE ){
const void *zBuf; const void *zBuf;
assert( pPager->dbFileSize>0 ); assert( pPager->dbFileSize>0 );
zBuf = pPgHdr->pData; CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
pPager->aStat[PAGER_STAT_WRITE]++; pPager->aStat[PAGER_STAT_WRITE]++;
@ -7003,6 +7102,54 @@ const char *sqlite3PagerJournalname(Pager *pPager){
return pPager->zJournal; return pPager->zJournal;
} }
#ifdef SQLITE_HAS_CODEC
/*
** Set or retrieve the codec for this pager
*/
void sqlite3PagerSetCodec(
Pager *pPager,
void *(*xCodec)(void*,void*,Pgno,int),
void (*xCodecSizeChng)(void*,int,int),
void (*xCodecFree)(void*),
void *pCodec
){
if( pPager->xCodecFree ){
pPager->xCodecFree(pPager->pCodec);
}else{
pager_reset(pPager);
}
pPager->xCodec = pPager->memDb ? 0 : xCodec;
pPager->xCodecSizeChng = xCodecSizeChng;
pPager->xCodecFree = xCodecFree;
pPager->pCodec = pCodec;
setGetterMethod(pPager);
pagerReportSize(pPager);
}
void *sqlite3PagerGetCodec(Pager *pPager){
return pPager->pCodec;
}
/*
** This function is called by the wal module when writing page content
** into the log file.
**
** This function returns a pointer to a buffer containing the encrypted
** page content. If a malloc fails, this function may return NULL.
*/
void *sqlite3PagerCodec(PgHdr *pPg){
void *aData = 0;
CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
return aData;
}
/*
** Return the current pager state
*/
int sqlite3PagerState(Pager *pPager){
return pPager->eState;
}
#endif /* SQLITE_HAS_CODEC */
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
/* /*
** Move the page pPg to location pgno in the file. ** Move the page pPg to location pgno in the file.

View File

@ -128,6 +128,9 @@ int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
/* Functions used to configure a Pager object. */ /* Functions used to configure a Pager object. */
void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u32*, int); int sqlite3PagerSetPagesize(Pager*, u32*, int);
#ifdef SQLITE_HAS_CODEC
void sqlite3PagerAlignReserve(Pager*,Pager*);
#endif
int sqlite3PagerMaxPageCount(Pager*, int); int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int);
int sqlite3PagerSetSpillsize(Pager*, int); int sqlite3PagerSetSpillsize(Pager*, int);
@ -221,6 +224,10 @@ void sqlite3PagerTruncateImage(Pager*,Pgno);
void sqlite3PagerRekey(DbPage*, Pgno, u16); void sqlite3PagerRekey(DbPage*, Pgno, u16);
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
void *sqlite3PagerCodec(DbPage *);
#endif
/* Functions to support testing and debugging. */ /* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST) #if !defined(NDEBUG) || defined(SQLITE_TEST)
Pgno sqlite3PagerPagenumber(DbPage*); Pgno sqlite3PagerPagenumber(DbPage*);

View File

@ -2230,11 +2230,59 @@ void sqlite3Pragma(
} }
#endif #endif
#if defined(SQLITE_ENABLE_CEROD) #ifdef SQLITE_HAS_CODEC
/* Pragma iArg
** ---------- ------
** key 0
** rekey 1
** hexkey 2
** hexrekey 3
** textkey 4
** textrekey 5
*/
case PragTyp_KEY: {
if( zRight ){
char zBuf[40];
const char *zKey = zRight;
int n;
if( pPragma->iArg==2 || pPragma->iArg==3 ){
u8 iByte;
int i;
for(i=0, iByte=0; i<sizeof(zBuf)*2 && sqlite3Isxdigit(zRight[i]); i++){
iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
if( (i&1)!=0 ) zBuf[i/2] = iByte;
}
zKey = zBuf;
n = i/2;
}else{
n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1;
}
if( (pPragma->iArg & 1)==0 ){
rc = sqlite3_key_v2(db, zDb, zKey, n);
}else{
rc = sqlite3_rekey_v2(db, zDb, zKey, n);
}
if( rc==SQLITE_OK && n!=0 ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC);
returnSingleText(v, "ok");
}
}
break;
}
#endif
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){
#ifdef SQLITE_HAS_CODEC
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
sqlite3_activate_see(&zRight[4]);
}
#endif
#ifdef SQLITE_ENABLE_CEROD
if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
sqlite3_activate_cerod(&zRight[6]); sqlite3_activate_cerod(&zRight[6]);
} }
#endif
} }
break; break;
#endif #endif

View File

@ -5,50 +5,51 @@
*/ */
/* The various pragma types */ /* The various pragma types */
#define PragTyp_ACTIVATE_EXTENSIONS 0 #define PragTyp_HEADER_VALUE 0
#define PragTyp_HEADER_VALUE 1 #define PragTyp_AUTO_VACUUM 1
#define PragTyp_AUTO_VACUUM 2 #define PragTyp_FLAG 2
#define PragTyp_FLAG 3 #define PragTyp_BUSY_TIMEOUT 3
#define PragTyp_BUSY_TIMEOUT 4 #define PragTyp_CACHE_SIZE 4
#define PragTyp_CACHE_SIZE 5 #define PragTyp_CACHE_SPILL 5
#define PragTyp_CACHE_SPILL 6 #define PragTyp_CASE_SENSITIVE_LIKE 6
#define PragTyp_CASE_SENSITIVE_LIKE 7 #define PragTyp_COLLATION_LIST 7
#define PragTyp_COLLATION_LIST 8 #define PragTyp_COMPILE_OPTIONS 8
#define PragTyp_COMPILE_OPTIONS 9 #define PragTyp_DATA_STORE_DIRECTORY 9
#define PragTyp_DATA_STORE_DIRECTORY 10 #define PragTyp_DATABASE_LIST 10
#define PragTyp_DATABASE_LIST 11 #define PragTyp_DEFAULT_CACHE_SIZE 11
#define PragTyp_DEFAULT_CACHE_SIZE 12 #define PragTyp_ENCODING 12
#define PragTyp_ENCODING 13 #define PragTyp_FOREIGN_KEY_CHECK 13
#define PragTyp_FOREIGN_KEY_CHECK 14 #define PragTyp_FOREIGN_KEY_LIST 14
#define PragTyp_FOREIGN_KEY_LIST 15 #define PragTyp_FUNCTION_LIST 15
#define PragTyp_FUNCTION_LIST 16 #define PragTyp_HARD_HEAP_LIMIT 16
#define PragTyp_HARD_HEAP_LIMIT 17 #define PragTyp_INCREMENTAL_VACUUM 17
#define PragTyp_INCREMENTAL_VACUUM 18 #define PragTyp_INDEX_INFO 18
#define PragTyp_INDEX_INFO 19 #define PragTyp_INDEX_LIST 19
#define PragTyp_INDEX_LIST 20 #define PragTyp_INTEGRITY_CHECK 20
#define PragTyp_INTEGRITY_CHECK 21 #define PragTyp_JOURNAL_MODE 21
#define PragTyp_JOURNAL_MODE 22 #define PragTyp_JOURNAL_SIZE_LIMIT 22
#define PragTyp_JOURNAL_SIZE_LIMIT 23 #define PragTyp_LOCK_PROXY_FILE 23
#define PragTyp_LOCK_PROXY_FILE 24 #define PragTyp_LOCKING_MODE 24
#define PragTyp_LOCKING_MODE 25 #define PragTyp_PAGE_COUNT 25
#define PragTyp_PAGE_COUNT 26 #define PragTyp_MMAP_SIZE 26
#define PragTyp_MMAP_SIZE 27 #define PragTyp_MODULE_LIST 27
#define PragTyp_MODULE_LIST 28 #define PragTyp_OPTIMIZE 28
#define PragTyp_OPTIMIZE 29 #define PragTyp_PAGE_SIZE 29
#define PragTyp_PAGE_SIZE 30 #define PragTyp_PRAGMA_LIST 30
#define PragTyp_PRAGMA_LIST 31 #define PragTyp_SECURE_DELETE 31
#define PragTyp_SECURE_DELETE 32 #define PragTyp_SHRINK_MEMORY 32
#define PragTyp_SHRINK_MEMORY 33 #define PragTyp_SOFT_HEAP_LIMIT 33
#define PragTyp_SOFT_HEAP_LIMIT 34 #define PragTyp_SYNCHRONOUS 34
#define PragTyp_SYNCHRONOUS 35 #define PragTyp_TABLE_INFO 35
#define PragTyp_TABLE_INFO 36 #define PragTyp_TEMP_STORE 36
#define PragTyp_TEMP_STORE 37 #define PragTyp_TEMP_STORE_DIRECTORY 37
#define PragTyp_TEMP_STORE_DIRECTORY 38 #define PragTyp_THREADS 38
#define PragTyp_THREADS 39 #define PragTyp_WAL_AUTOCHECKPOINT 39
#define PragTyp_WAL_AUTOCHECKPOINT 40 #define PragTyp_WAL_CHECKPOINT 40
#define PragTyp_WAL_CHECKPOINT 41 #define PragTyp_ACTIVATE_EXTENSIONS 41
#define PragTyp_LOCK_STATUS 42 #define PragTyp_KEY 42
#define PragTyp_STATS 43 #define PragTyp_LOCK_STATUS 43
#define PragTyp_STATS 44
/* Property flags associated with various pragma. */ /* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */
@ -132,7 +133,7 @@ typedef struct PragmaName {
u64 iArg; /* Extra argument */ u64 iArg; /* Extra argument */
} PragmaName; } PragmaName;
static const PragmaName aPragmaName[] = { static const PragmaName aPragmaName[] = {
#if defined(SQLITE_ENABLE_CEROD) #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
{/* zName: */ "activate_extensions", {/* zName: */ "activate_extensions",
/* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
/* ePragFlg: */ 0, /* ePragFlg: */ 0,
@ -328,6 +329,18 @@ static const PragmaName aPragmaName[] = {
/* ePragFlg: */ PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 0, 0, /* ColNames: */ 0, 0,
/* iArg: */ 0 }, /* iArg: */ 0 },
#if defined(SQLITE_HAS_CODEC)
{/* zName: */ "hexkey",
/* ePragTyp: */ PragTyp_KEY,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
/* iArg: */ 2 },
{/* zName: */ "hexrekey",
/* ePragTyp: */ PragTyp_KEY,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
/* iArg: */ 3 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_CHECK) #if !defined(SQLITE_OMIT_CHECK)
{/* zName: */ "ignore_check_constraints", {/* zName: */ "ignore_check_constraints",
@ -380,6 +393,13 @@ static const PragmaName aPragmaName[] = {
/* ColNames: */ 0, 0, /* ColNames: */ 0, 0,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if defined(SQLITE_HAS_CODEC)
{/* zName: */ "key",
/* ePragTyp: */ PragTyp_KEY,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{/* zName: */ "legacy_alter_table", {/* zName: */ "legacy_alter_table",
/* ePragTyp: */ PragTyp_FLAG, /* ePragTyp: */ PragTyp_FLAG,
@ -487,6 +507,15 @@ static const PragmaName aPragmaName[] = {
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
/* ColNames: */ 0, 0, /* ColNames: */ 0, 0,
/* iArg: */ SQLITE_RecTriggers }, /* iArg: */ SQLITE_RecTriggers },
#endif
#if defined(SQLITE_HAS_CODEC)
{/* zName: */ "rekey",
/* ePragTyp: */ PragTyp_KEY,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
/* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{/* zName: */ "reverse_unordered_selects", {/* zName: */ "reverse_unordered_selects",
/* ePragTyp: */ PragTyp_FLAG, /* ePragTyp: */ PragTyp_FLAG,
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
@ -570,6 +599,18 @@ static const PragmaName aPragmaName[] = {
/* ePragFlg: */ PragFlg_NoColumns1, /* ePragFlg: */ PragFlg_NoColumns1,
/* ColNames: */ 0, 0, /* ColNames: */ 0, 0,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif
#if defined(SQLITE_HAS_CODEC)
{/* zName: */ "textkey",
/* ePragTyp: */ PragTyp_KEY,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
/* iArg: */ 4 },
{/* zName: */ "textrekey",
/* ePragTyp: */ PragTyp_KEY,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
/* iArg: */ 5 },
#endif #endif
{/* zName: */ "threads", {/* zName: */ "threads",
/* ePragTyp: */ PragTyp_THREADS, /* ePragTyp: */ PragTyp_THREADS,
@ -639,4 +680,4 @@ static const PragmaName aPragmaName[] = {
/* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif #endif
}; };
/* Number of pragmas: 66 on by default, 76 total. */ /* Number of pragmas: 66 on by default, 82 total. */

View File

@ -5817,6 +5817,51 @@ int sqlite3_collation_needed16(
void(*)(void*,sqlite3*,int eTextRep,const void*) void(*)(void*,sqlite3*,int eTextRep,const void*)
); );
#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database. This routine should be
** called right after sqlite3_open().
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
int sqlite3_key(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The key */
);
int sqlite3_key_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The key */
);
/*
** Change the key on an open database. If the current database is not
** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
** database is decrypted.
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
int sqlite3_rekey(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
int sqlite3_rekey_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The new key */
);
/*
** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
void sqlite3_activate_see(
const char *zPassPhrase /* Activation phrase */
);
#endif
#ifdef SQLITE_ENABLE_CEROD #ifdef SQLITE_ENABLE_CEROD
/* /*
** Specify the activation key for a CEROD database. Unless ** Specify the activation key for a CEROD database. Unless

View File

@ -4113,7 +4113,11 @@ void sqlite3AddGenerated(Parse*,Expr*,Token*);
void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
int sqlite3ParseUri(const char*,const char*,unsigned int*, int sqlite3ParseUri(const char*,const char*,unsigned int*,
sqlite3_vfs**,char**,char **); sqlite3_vfs**,char**,char **);
#define sqlite3CodecQueryParameters(A,B,C) 0 #ifdef SQLITE_HAS_CODEC
int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*);
#else
# define sqlite3CodecQueryParameters(A,B,C) 0
#endif
Btree *sqlite3DbNameToBtree(sqlite3*,const char*); Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
#ifdef SQLITE_UNTESTABLE #ifdef SQLITE_UNTESTABLE

View File

@ -3094,10 +3094,22 @@ deserialize_error:
** Change the encryption key on the currently open database. ** Change the encryption key on the currently open database.
*/ */
case DB_REKEY: { case DB_REKEY: {
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
int nKey;
void *pKey;
#endif
if( objc!=3 ){ if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "KEY"); Tcl_WrongNumArgs(interp, 2, objv, "KEY");
return TCL_ERROR; return TCL_ERROR;
} }
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
rc = sqlite3_rekey(pDb->db, pKey, nKey);
if( rc ){
Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0);
rc = TCL_ERROR;
}
#endif
break; break;
} }
@ -3666,6 +3678,9 @@ static int sqliteCmdUsage(
"HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
" ?-nofollow BOOLEAN?" " ?-nofollow BOOLEAN?"
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
" ?-key CODECKEY?"
#endif
); );
return TCL_ERROR; return TCL_ERROR;
} }
@ -3700,6 +3715,10 @@ static int SQLITE_TCLAPI DbMain(
const char *zVfs = 0; const char *zVfs = 0;
int flags; int flags;
Tcl_DString translatedFilename; Tcl_DString translatedFilename;
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
void *pKey = 0;
int nKey = 0;
#endif
int rc; int rc;
/* In normal use, each TCL interpreter runs in a single thread. So /* In normal use, each TCL interpreter runs in a single thread. So
@ -3726,7 +3745,11 @@ static int SQLITE_TCLAPI DbMain(
return TCL_OK; return TCL_OK;
} }
if( strcmp(zArg,"-has-codec")==0 ){ if( strcmp(zArg,"-has-codec")==0 ){
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
Tcl_AppendResult(interp,"1",(char*)0);
#else
Tcl_AppendResult(interp,"0",(char*)0); Tcl_AppendResult(interp,"0",(char*)0);
#endif
return TCL_OK; return TCL_OK;
} }
if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv); if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv);
@ -3741,7 +3764,9 @@ static int SQLITE_TCLAPI DbMain(
if( i==objc-1 ) return sqliteCmdUsage(interp, objv); if( i==objc-1 ) return sqliteCmdUsage(interp, objv);
i++; i++;
if( strcmp(zArg,"-key")==0 ){ if( strcmp(zArg,"-key")==0 ){
/* no-op */ #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
pKey = Tcl_GetByteArrayFromObj(objv[i], &nKey);
#endif
}else if( strcmp(zArg, "-vfs")==0 ){ }else if( strcmp(zArg, "-vfs")==0 ){
zVfs = Tcl_GetString(objv[i]); zVfs = Tcl_GetString(objv[i]);
}else if( strcmp(zArg, "-readonly")==0 ){ }else if( strcmp(zArg, "-readonly")==0 ){
@ -3817,6 +3842,11 @@ static int SQLITE_TCLAPI DbMain(
}else{ }else{
zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc)); zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc));
} }
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
if( p->db ){
sqlite3_key(p->db, pKey, nKey);
}
#endif
if( p->db==0 ){ if( p->db==0 ){
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
Tcl_Free((char*)p); Tcl_Free((char*)p);

View File

@ -655,6 +655,20 @@ static int SQLITE_TCLAPI test_key(
int argc, /* Number of arguments */ int argc, /* Number of arguments */
char **argv /* Text of each argument */ char **argv /* Text of each argument */
){ ){
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
sqlite3 *db;
const char *zKey;
int nKey;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" FILENAME\"", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
zKey = argv[2];
nKey = strlen(zKey);
sqlite3_key(db, zKey, nKey);
#endif
return TCL_OK; return TCL_OK;
} }
@ -669,6 +683,20 @@ static int SQLITE_TCLAPI test_rekey(
int argc, /* Number of arguments */ int argc, /* Number of arguments */
char **argv /* Text of each argument */ char **argv /* Text of each argument */
){ ){
#ifdef SQLITE_HAS_CODEC
sqlite3 *db;
const char *zKey;
int nKey;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" FILENAME\"", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
zKey = argv[2];
nKey = strlen(zKey);
sqlite3_rekey(db, zKey, nKey);
#endif
return TCL_OK; return TCL_OK;
} }

View File

@ -226,7 +226,11 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY);
#endif #endif
#ifdef SQLITE_HAS_CODEC
Tcl_SetVar2(interp, "sqlite_options", "has_codec", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "has_codec", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "has_codec", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
Tcl_SetVar2(interp, "sqlite_options", "like_match_blobs", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "like_match_blobs", "0", TCL_GLOBAL_ONLY);

View File

@ -287,6 +287,22 @@ static int SQLITE_TCLAPI sqlthread_open(
zFilename = Tcl_GetString(objv[2]); zFilename = Tcl_GetString(objv[2]);
sqlite3_open(zFilename, &db); sqlite3_open(zFilename, &db);
#ifdef SQLITE_HAS_CODEC
if( db && objc>=4 ){
const char *zKey;
int nKey;
int rc;
zKey = Tcl_GetStringFromObj(objv[3], &nKey);
rc = sqlite3_key(db, zKey, nKey);
if( rc!=SQLITE_OK ){
char *zErrMsg = sqlite3_mprintf("error %d: %s", rc, sqlite3_errmsg(db));
sqlite3_close(db);
Tcl_AppendResult(interp, zErrMsg, (char*)0);
sqlite3_free(zErrMsg);
return TCL_ERROR;
}
}
#endif
Md5_Register(db, 0, 0); Md5_Register(db, 0, 0);
sqlite3_busy_handler(db, xBusy, 0); sqlite3_busy_handler(db, xBusy, 0);

View File

@ -1256,7 +1256,7 @@ u8 sqlite3HexToInt(int h){
return (u8)(h & 0xf); return (u8)(h & 0xf);
} }
#if !defined(SQLITE_OMIT_BLOB_LITERAL) #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/* /*
** Convert a BLOB literal of the form "x'hhhhhh'" into its binary ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
** value. Return a pointer to its binary value. Space to hold the ** value. Return a pointer to its binary value. Space to hold the
@ -1277,7 +1277,7 @@ void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
} }
return zBlob; return zBlob;
} }
#endif /* !SQLITE_OMIT_BLOB_LITERAL */ #endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
/* /*
** Log an error that is an API call on a connection pointer that should ** Log an error that is an API call on a connection pointer that should

View File

@ -235,6 +235,17 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
} }
nRes = sqlite3BtreeGetOptimalReserve(pMain); nRes = sqlite3BtreeGetOptimalReserve(pMain);
/* A VACUUM cannot change the pagesize of an encrypted database. */
#ifdef SQLITE_HAS_CODEC
if( db->nextPagesize ){
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey);
if( nKey ) db->nextPagesize = 0;
}
#endif
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL); sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);

View File

@ -3253,7 +3253,11 @@ static int walWriteOneFrame(
int rc; /* Result code from subfunctions */ int rc; /* Result code from subfunctions */
void *pData; /* Data actually written */ void *pData; /* Data actually written */
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
#if defined(SQLITE_HAS_CODEC)
if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
#else
pData = pPage->pData; pData = pPage->pData;
#endif
walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
if( rc ) return rc; if( rc ) return rc;
@ -3436,7 +3440,11 @@ int sqlite3WalFrames(
if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){ if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
pWal->iReCksum = iWrite; pWal->iReCksum = iWrite;
} }
#if defined(SQLITE_HAS_CODEC)
if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
#else
pData = p->pData; pData = p->pData;
#endif
rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
if( rc ) return rc; if( rc ) return rc;
p->flags &= ~PGHDR_WAL_APPEND; p->flags &= ~PGHDR_WAL_APPEND;

View File

@ -370,8 +370,38 @@ set pragma_def {
COLS: database status COLS: database status
IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST) IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
NAME: key
TYPE: KEY
ARG: 0
IF: defined(SQLITE_HAS_CODEC)
NAME: rekey
TYPE: KEY
ARG: 1
IF: defined(SQLITE_HAS_CODEC)
NAME: hexkey
TYPE: KEY
ARG: 2
IF: defined(SQLITE_HAS_CODEC)
NAME: hexrekey
TYPE: KEY
ARG: 3
IF: defined(SQLITE_HAS_CODEC)
NAME: textkey
TYPE: KEY
ARG: 4
IF: defined(SQLITE_HAS_CODEC)
NAME: textrekey
TYPE: KEY
ARG: 5
IF: defined(SQLITE_HAS_CODEC)
NAME: activate_extensions NAME: activate_extensions
IF: defined(SQLITE_ENABLE_CEROD) IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
NAME: soft_heap_limit NAME: soft_heap_limit
FLAG: Result0 FLAG: Result0
@ -466,7 +496,7 @@ record_one
set allnames [lsort [array names allbyname]] set allnames [lsort [array names allbyname]]
# Generate #defines for all pragma type names. Group the pragmas that are # Generate #defines for all pragma type names. Group the pragmas that are
# omit in default builds (ex: defined(SQLITE_DEBUG)) # omit in default builds (defined(SQLITE_DEBUG) and defined(SQLITE_HAS_CODEC))
# at the end. # at the end.
# #
puts $fd "\n/* The various pragma types */" puts $fd "\n/* The various pragma types */"