Skip to content

Commit

Permalink
libsql-ffi: Update bundled SQLite code
Browse files Browse the repository at this point in the history
  • Loading branch information
penberg committed Oct 11, 2024
1 parent 4a0ccc9 commit da524c0
Show file tree
Hide file tree
Showing 2 changed files with 341 additions and 3 deletions.
305 changes: 302 additions & 3 deletions libsql-ffi/bundled/src/sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -10938,6 +10938,44 @@ SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *);
*/
SQLITE_API void *libsql_close_hook(sqlite3 *db, void (*xClose)(void *pCtx, sqlite3 *db), void *arg);

/*
** CAPI3REF: Get the number of frames in the WAL file
** METHOD: sqlite3
**
** ^The [libsql_wal_frame_count(D,P)] interface returns the number of frames
** in the WAL file for [database connection] D into *P.
*/
SQLITE_API int libsql_wal_frame_count(sqlite3*, unsigned int*);

/*
** CAPI3REF: Get a frame from the WAL file
** METHOD: sqlite3
**
** ^The [libsql_wal_get_frame(D,I,P,S)] interface extracts frame I from
** the WAL file for [database connection] D into memory obtained from
** [sqlite3_malloc64()] and returns a pointer to that memory. The size of
** the memory allocated is given by S.
*/
SQLITE_API int libsql_wal_get_frame(sqlite3*, unsigned int, void*, unsigned int);

/*
** CAPI3REF: Begin a WAL commit
** METHOD: sqlite3
*/
SQLITE_API int libsql_wal_insert_begin(sqlite3*);

/*
** CAPI3REF: End a WAL commit
** METHOD: sqlite3
*/
SQLITE_API int libsql_wal_insert_end(sqlite3*);

/*
** CAPI3REF: Insert a frame into the WAL file
** METHOD: sqlite3
*/
SQLITE_API int libsql_wal_insert_frame(sqlite3*, unsigned int, void *, unsigned int);

/*
** CAPI3REF: Low-level system error code
** METHOD: sqlite3
Expand Down Expand Up @@ -13963,6 +14001,7 @@ typedef struct libsql_wal_methods {
/* Read a page from the write-ahead log, if it is present. */
int (*xFindFrame)(wal_impl* pWal, unsigned int, unsigned int *);
int (*xReadFrame)(wal_impl* pWal, unsigned int, int, unsigned char *);
int (*xReadFrameRaw)(wal_impl* pWal, unsigned int, int, unsigned char *);

/* If the WAL is not empty, return the size of the database. */
unsigned int (*xDbsize)(wal_impl* pWal);
Expand Down Expand Up @@ -16378,6 +16417,12 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
SQLITE_PRIVATE unsigned int sqlite3PagerWalFrameCount(Pager *);
SQLITE_PRIVATE int sqlite3PagerWalReadFrame(Pager *, unsigned int, void *, unsigned int);
SQLITE_PRIVATE int sqlite3PagerWalBeginCommit(Pager*);
SQLITE_PRIVATE int sqlite3PagerWalEndCommit(Pager*);
SQLITE_PRIVATE int sqlite3PagerWalInsert(Pager*, unsigned int, void *, unsigned int);

SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
Expand Down Expand Up @@ -57270,6 +57315,7 @@ typedef struct libsql_wal_methods {
/* Read a page from the write-ahead log, if it is present. */
int (*xFindFrame)(wal_impl* pWal, unsigned int, unsigned int *);
int (*xReadFrame)(wal_impl* pWal, unsigned int, int, unsigned char *);
int (*xReadFrameRaw)(wal_impl* pWal, unsigned int, int, unsigned char *);

/* If the WAL is not empty, return the size of the database. */
unsigned int (*xDbsize)(wal_impl* pWal);
Expand Down Expand Up @@ -65214,6 +65260,103 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
return rc;
}

SQLITE_PRIVATE unsigned int sqlite3PagerWalFrameCount(Pager *pPager){
if( pagerUseWal(pPager) ){
// TODO: We are under sqlite3 mutex, but do we need something else?
struct sqlite3_wal* pWal = (void*) pPager->wal->pData;
return pWal->hdr.mxFrame;
}else{
return 0;
}
}

SQLITE_PRIVATE int sqlite3PagerWalReadFrameRaw(
Pager *pPager,
unsigned int iFrame,
void *pFrameOut,
unsigned int nFrameOutLen
){
if( pagerUseWal(pPager) ){
unsigned int nFrameLen = 24+pPager->pageSize;
if( nFrameOutLen!=nFrameLen ) return SQLITE_MISUSE;
return pPager->wal->methods.xReadFrameRaw(pPager->wal->pData, iFrame, nFrameOutLen, pFrameOut);
}else{
return SQLITE_ERROR;
}
}

static void frame_to_pghdr(PgHdr *pPghdr, unsigned int pgno, void *pData) {
pPghdr->pPage = NULL; /* Pcache object page handle */
pPghdr->pData = pData; /* Page data */
pPghdr->pExtra = NULL; /* Extra content */
pPghdr->pCache = NULL; /* PRIVATE: Cache that owns this page */
pPghdr->pDirty = NULL; /* Transient list of dirty sorted by pgno */
pPghdr->pPager = NULL; /* The pager this page is part of */
pPghdr->pgno = pgno; /* Page number for this page */
pPghdr->pageHash = 0; /* Hash of page content */
pPghdr->flags = 0; /* PGHDR flags defined below */
pPghdr->nRef = 1; /* Number of users of this page */
pPghdr->pDirtyNext = NULL; /* Next element in list of dirty pages */
pPghdr->pDirtyPrev = NULL; /* Previous element in list of dirty pages */
}

SQLITE_PRIVATE int sqlite3PagerWalBeginCommit(Pager *pPager) {
int rc;
if (!pagerUseWal(pPager)) {
return SQLITE_ERROR;
}
rc = pagerBeginReadTransaction(pPager);
if (rc != SQLITE_OK) {
return rc;
}
return pPager->wal->methods.xBeginWriteTransaction(pPager->wal->pData);
}

SQLITE_PRIVATE int sqlite3PagerWalEndCommit(Pager *pPager) {
if (!pagerUseWal(pPager)) {
return SQLITE_ERROR;
}
return pPager->wal->methods.xEndWriteTransaction(pPager->wal->pData);
}

SQLITE_PRIVATE int sqlite3PagerWalInsert(Pager *pPager, unsigned int iFrame, void *pBuf, unsigned int nBuf) {
int rc = SQLITE_OK;

// Check if WAL mode is enabled
if (!pagerUseWal(pPager)) {
return SQLITE_ERROR;
}

// Extract information from the WAL frame
u8 *aFrame = (u8*)pBuf;
u32 pgno = sqlite3Get4byte(&aFrame[0]);
u32 nTruncate = sqlite3Get4byte(&aFrame[4]);
u8 *pData = aFrame + 24;

// Prepare the PgHdr structure
PgHdr pghdr;
memset(&pghdr, 0, sizeof(PgHdr));
pghdr.pPage = NULL;
pghdr.pData = pData;
pghdr.pExtra = NULL;
pghdr.pgno = pgno;
pghdr.flags = 0;

// Determine if this is a commit frame
int isCommit = (nTruncate != 0);

// Call xFrames
int nFrames = 0;
rc = pPager->wal->methods.xFrames(pPager->wal->pData,
pPager->pageSize,
&pghdr,
nTruncate,
isCommit,
pPager->walSyncFlags,
&nFrames);
return rc;
}

#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/*
** If pager pPager is a wal-mode database not in exclusive locking mode,
Expand Down Expand Up @@ -67601,9 +67744,10 @@ static int sqlite3WalClose(
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
}
rc = sqlite3WalCheckpoint(pWal, db,
SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0, NULL, NULL
);
rc = SQLITE_ERROR;
//rc = sqlite3WalCheckpoint(pWal, db,
// SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0, NULL, NULL
//);
if( rc==SQLITE_OK ){
int bPersist = -1;
sqlite3OsFileControlHint(
Expand Down Expand Up @@ -68731,6 +68875,29 @@ static int sqlite3WalReadFrame(
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}

/*
** Read the contents of frame iRead from the wal file into buffer pOut
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
** error code otherwise.
*/
static int sqlite3WalReadFrameRaw(
Wal *pWal, /* WAL handle */
u32 iRead, /* Frame to read */
int nOut, /* Size of buffer pOut in bytes */
u8 *pOut /* Buffer to write page data to */
){
int sz;
i64 iOffset;
sz = pWal->hdr.szPage;
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
testcase( sz<=32768 );
testcase( sz>=65536 );
iOffset = walFrameOffset(iRead, sz);
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
sz += WAL_FRAME_HDRSIZE;
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}

/*
** Return the size of the database in pages (or zero, if unknown).
*/
Expand Down Expand Up @@ -69840,6 +70007,7 @@ static int sqlite3WalOpen(
out->methods.xEndReadTransaction = (void (*)(wal_impl *))sqlite3WalEndReadTransaction;
out->methods.xFindFrame = (int (*)(wal_impl *, unsigned int, unsigned int *))sqlite3WalFindFrame;
out->methods.xReadFrame = (int (*)(wal_impl *, unsigned int, int, unsigned char *))sqlite3WalReadFrame;
out->methods.xReadFrameRaw = (int (*)(wal_impl *, unsigned int, int, unsigned char *))sqlite3WalReadFrameRaw;
out->methods.xDbsize = (unsigned int (*)(wal_impl *))sqlite3WalDbsize;
out->methods.xBeginWriteTransaction = (int (*)(wal_impl *))sqlite3WalBeginWriteTransaction;
out->methods.xEndWriteTransaction = (int (*)(wal_impl *))sqlite3WalEndWriteTransaction;
Expand Down Expand Up @@ -182972,6 +183140,137 @@ void *libsql_close_hook(
return pRet;
}

/*
** Return the number of frames in the WAL of the given database.
*/
int libsql_wal_frame_count(
sqlite3* db,
unsigned int *pnFrame
){
int rc = SQLITE_OK;
Pager *pPager;

#ifdef SQLITE_OMIT_WAL
*pnFrame = 0;
return SQLITE_OK;
#else
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif

sqlite3_mutex_enter(db->mutex);
pPager = sqlite3BtreePager(db->aDb[0].pBt);
*pnFrame = sqlite3PagerWalFrameCount(pPager);
sqlite3_mutex_leave(db->mutex);

return rc;
#endif
}

int libsql_wal_get_frame(
sqlite3* db,
unsigned int iFrame,
void *pBuf,
unsigned int nBuf
){
int rc = SQLITE_OK;
Pager *pPager;

#ifdef SQLITE_OMIT_WAL
UNUSED_PARAMETER(iFrame);
UNUSED_PARAMETER(nBuf);
UNUSED_PARAMETER(pBuf);
return SQLITE_OK;
#else

#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif

sqlite3_mutex_enter(db->mutex);
pPager = sqlite3BtreePager(db->aDb[0].pBt);
rc = sqlite3PagerWalReadFrameRaw(pPager, iFrame, pBuf, nBuf);
sqlite3_mutex_leave(db->mutex);

return rc;
#endif
}

/*
** Begin a WAL commit.
*/
int libsql_wal_insert_begin(sqlite3 *db) {
Pager *pPager;
int rc;

sqlite3_mutex_enter(db->mutex);
pPager = sqlite3BtreePager(db->aDb[0].pBt);
rc = sqlite3PagerSharedLock(pPager);
if (rc != SQLITE_OK) {
goto out_unlock;
}
int isOpen = 0;
rc = sqlite3PagerOpenWal(pPager, &isOpen);
if (rc != SQLITE_OK) {
goto out_unlock;
}
rc = sqlite3PagerWalBeginCommit(pPager);
if (rc != SQLITE_OK) {
goto out_unlock;
}
out_unlock:
sqlite3_mutex_leave(db->mutex);
return rc;
}

int libsql_wal_insert_end(sqlite3 *db) {
Pager *pPager;
int rc;

sqlite3_mutex_enter(db->mutex);
pPager = sqlite3BtreePager(db->aDb[0].pBt);
rc = sqlite3PagerWalEndCommit(pPager);
if (rc != SQLITE_OK) {
goto out_unlock;
}
out_unlock:
sqlite3_mutex_leave(db->mutex);
return rc;
}

/*
** Insert a frame into the WAL.
*/
int libsql_wal_insert_frame(
sqlite3* db,
unsigned int iFrame,
void *pBuf,
unsigned int nBuf
){
int rc = SQLITE_OK;
Pager *pPager;

#ifdef SQLITE_OMIT_WAL
*pnFrame = 0;
return SQLITE_OK;
#else
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif

sqlite3_mutex_enter(db->mutex);
pPager = sqlite3BtreePager(db->aDb[0].pBt);
rc = sqlite3PagerWalInsert(pPager, iFrame, pBuf, nBuf);
if (rc != SQLITE_OK) {
goto out_unlock;
}
out_unlock:
sqlite3_mutex_leave(db->mutex);

return rc;
#endif
}

/*
** Register a function to be invoked prior to each autovacuum that
** determines the number of pages to vacuum.
Expand Down
Loading

0 comments on commit da524c0

Please sign in to comment.