mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Add the sqlite_dbpage virtual table (enabled using SQLITE_ENABLE_DBPAGE_VTAB).
Make that virtual table and dbstat available to the command-line shell. FossilOrigin-Name: eaeeb09d4aa1dbccdd2488af8461e2a8c8a53d92c63fd56330be041ad72a9e4a
This commit is contained in:
10
Makefile.in
10
Makefile.in
@ -166,7 +166,8 @@ USE_AMALGAMATION = @USE_AMALGAMATION@
|
|||||||
#
|
#
|
||||||
LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||||
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
|
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
|
||||||
callback.lo complete.lo ctime.lo date.lo dbstat.lo delete.lo \
|
callback.lo complete.lo ctime.lo \
|
||||||
|
date.lo dbpage.lo dbstat.lo delete.lo \
|
||||||
expr.lo fault.lo fkey.lo \
|
expr.lo fault.lo fkey.lo \
|
||||||
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
|
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
|
||||||
fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
|
fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
|
||||||
@ -215,6 +216,7 @@ SRC = \
|
|||||||
$(TOP)/src/complete.c \
|
$(TOP)/src/complete.c \
|
||||||
$(TOP)/src/ctime.c \
|
$(TOP)/src/ctime.c \
|
||||||
$(TOP)/src/date.c \
|
$(TOP)/src/date.c \
|
||||||
|
$(TOP)/src/dbpage.c \
|
||||||
$(TOP)/src/dbstat.c \
|
$(TOP)/src/dbstat.c \
|
||||||
$(TOP)/src/delete.c \
|
$(TOP)/src/delete.c \
|
||||||
$(TOP)/src/expr.c \
|
$(TOP)/src/expr.c \
|
||||||
@ -450,6 +452,7 @@ TESTSRC2 = \
|
|||||||
$(TOP)/src/build.c \
|
$(TOP)/src/build.c \
|
||||||
$(TOP)/src/ctime.c \
|
$(TOP)/src/ctime.c \
|
||||||
$(TOP)/src/date.c \
|
$(TOP)/src/date.c \
|
||||||
|
$(TOP)/src/dbpage.c \
|
||||||
$(TOP)/src/dbstat.c \
|
$(TOP)/src/dbstat.c \
|
||||||
$(TOP)/src/expr.c \
|
$(TOP)/src/expr.c \
|
||||||
$(TOP)/src/func.c \
|
$(TOP)/src/func.c \
|
||||||
@ -570,6 +573,8 @@ SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4
|
|||||||
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||||
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||||
|
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||||
|
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||||
@ -753,6 +758,9 @@ ctime.lo: $(TOP)/src/ctime.c $(HDR)
|
|||||||
date.lo: $(TOP)/src/date.c $(HDR)
|
date.lo: $(TOP)/src/date.c $(HDR)
|
||||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/date.c
|
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/date.c
|
||||||
|
|
||||||
|
dbpage.lo: $(TOP)/src/dbpage.c $(HDR)
|
||||||
|
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbpage.c
|
||||||
|
|
||||||
dbstat.lo: $(TOP)/src/dbstat.c $(HDR)
|
dbstat.lo: $(TOP)/src/dbstat.c $(HDR)
|
||||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbstat.c
|
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbstat.c
|
||||||
|
|
||||||
|
10
Makefile.msc
10
Makefile.msc
@ -1091,7 +1091,8 @@ LTLIBS = $(LTLIBS) $(LIBICU)
|
|||||||
#
|
#
|
||||||
LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
|
LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
|
||||||
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
|
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
|
||||||
callback.lo complete.lo ctime.lo date.lo dbstat.lo delete.lo \
|
callback.lo complete.lo ctime.lo \
|
||||||
|
date.lo dbpage.lo dbstat.lo delete.lo \
|
||||||
expr.lo fault.lo fkey.lo \
|
expr.lo fault.lo fkey.lo \
|
||||||
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
|
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
|
||||||
fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
|
fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
|
||||||
@ -1154,6 +1155,7 @@ SRC00 = \
|
|||||||
$(TOP)\src\complete.c \
|
$(TOP)\src\complete.c \
|
||||||
$(TOP)\src\ctime.c \
|
$(TOP)\src\ctime.c \
|
||||||
$(TOP)\src\date.c \
|
$(TOP)\src\date.c \
|
||||||
|
$(TOP)\src\dbpage.c \
|
||||||
$(TOP)\src\dbstat.c \
|
$(TOP)\src\dbstat.c \
|
||||||
$(TOP)\src\delete.c \
|
$(TOP)\src\delete.c \
|
||||||
$(TOP)\src\expr.c \
|
$(TOP)\src\expr.c \
|
||||||
@ -1505,6 +1507,7 @@ FUZZDATA = \
|
|||||||
#
|
#
|
||||||
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
|
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
|
||||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
|
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
|
||||||
|
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
# <<mark>>
|
# <<mark>>
|
||||||
@ -1742,7 +1745,10 @@ ctime.lo: $(TOP)\src\ctime.c $(HDR)
|
|||||||
date.lo: $(TOP)\src\date.c $(HDR)
|
date.lo: $(TOP)\src\date.c $(HDR)
|
||||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\date.c
|
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\date.c
|
||||||
|
|
||||||
dbstat.lo: $(TOP)\src\date.c $(HDR)
|
dbpage.lo: $(TOP)\src\dbpage.c $(HDR)
|
||||||
|
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\dbpage.c
|
||||||
|
|
||||||
|
dbstat.lo: $(TOP)\src\dbstat.c $(HDR)
|
||||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\dbstat.c
|
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\dbstat.c
|
||||||
|
|
||||||
delete.lo: $(TOP)\src\delete.c $(HDR)
|
delete.lo: $(TOP)\src\delete.c $(HDR)
|
||||||
|
16
ext/repair/README.md
Normal file
16
ext/repair/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
This folder contains extensions and utility programs intended to analyze
|
||||||
|
live database files, detect problems, and possibly fix them.
|
||||||
|
|
||||||
|
As SQLite is being used on larger and larger databases, database sizes
|
||||||
|
are growing into the terabyte range. At that size, hardware malfunctions
|
||||||
|
and/or cosmic rays will occasionally corrupt a database file. Detecting
|
||||||
|
problems and fixing errors a terabyte-sized databases can take hours or days,
|
||||||
|
and it is undesirable to take applications that depend on the databases
|
||||||
|
off-line for such a long time.
|
||||||
|
The utilities in the folder are intended to provide mechanisms for
|
||||||
|
detecting and fixing problems in large databases while those databases
|
||||||
|
are in active use.
|
||||||
|
|
||||||
|
The utilities and extensions in this folder are experimental and under
|
||||||
|
active development at the time of this writing (2017-10-12). If and when
|
||||||
|
they stabilize, this README will be updated to reflect that fact.
|
299
ext/repair/checkfreelist.c
Normal file
299
ext/repair/checkfreelist.c
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
** 2017 October 11
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** This module exports a single C function:
|
||||||
|
**
|
||||||
|
** int sqlite3_check_freelist(sqlite3 *db, const char *zDb);
|
||||||
|
**
|
||||||
|
** This function checks the free-list in database zDb (one of "main",
|
||||||
|
** "temp", etc.) and reports any errors by invoking the sqlite3_log()
|
||||||
|
** function. It returns SQLITE_OK if successful, or an SQLite error
|
||||||
|
** code otherwise. It is not an error if the free-list is corrupted but
|
||||||
|
** no IO or OOM errors occur.
|
||||||
|
**
|
||||||
|
** If this file is compiled and loaded as an SQLite loadable extension,
|
||||||
|
** it adds an SQL function "checkfreelist" to the database handle, to
|
||||||
|
** be invoked as follows:
|
||||||
|
**
|
||||||
|
** SELECT checkfreelist(<database-name>);
|
||||||
|
**
|
||||||
|
** This function performs the same checks as sqlite3_check_freelist(),
|
||||||
|
** except that it returns all error messages as a single text value,
|
||||||
|
** separated by newline characters. If the freelist is not corrupted
|
||||||
|
** in any way, an empty string is returned.
|
||||||
|
**
|
||||||
|
** To compile this module for use as an SQLite loadable extension:
|
||||||
|
**
|
||||||
|
** gcc -Os -fPIC -shared checkfreelist.c -o checkfreelist.so
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sqlite3ext.h"
|
||||||
|
SQLITE_EXTENSION_INIT1
|
||||||
|
|
||||||
|
#ifndef SQLITE_AMALGAMATION
|
||||||
|
# include <string.h>
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <assert.h>
|
||||||
|
# define ALWAYS(X) 1
|
||||||
|
# define NEVER(X) 0
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
#define get4byte(x) ( \
|
||||||
|
((u32)((x)[0])<<24) + \
|
||||||
|
((u32)((x)[1])<<16) + \
|
||||||
|
((u32)((x)[2])<<8) + \
|
||||||
|
((u32)((x)[3])) \
|
||||||
|
)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Execute a single PRAGMA statement and return the integer value returned
|
||||||
|
** via output parameter (*pnOut).
|
||||||
|
**
|
||||||
|
** The SQL statement passed as the third argument should be a printf-style
|
||||||
|
** format string containing a single "%s" which will be replace by the
|
||||||
|
** value passed as the second argument. e.g.
|
||||||
|
**
|
||||||
|
** sqlGetInteger(db, "main", "PRAGMA %s.page_count", pnOut)
|
||||||
|
**
|
||||||
|
** executes "PRAGMA main.page_count" and stores the results in (*pnOut).
|
||||||
|
*/
|
||||||
|
static int sqlGetInteger(
|
||||||
|
sqlite3 *db, /* Database handle */
|
||||||
|
const char *zDb, /* Database name ("main", "temp" etc.) */
|
||||||
|
const char *zFmt, /* SQL statement format */
|
||||||
|
u32 *pnOut /* OUT: Integer value */
|
||||||
|
){
|
||||||
|
int rc, rc2;
|
||||||
|
char *zSql;
|
||||||
|
sqlite3_stmt *pStmt = 0;
|
||||||
|
int bOk = 0;
|
||||||
|
|
||||||
|
zSql = sqlite3_mprintf(zFmt, zDb);
|
||||||
|
if( zSql==0 ){
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
}else{
|
||||||
|
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||||
|
sqlite3_free(zSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||||
|
*pnOut = (u32)sqlite3_column_int(pStmt, 0);
|
||||||
|
bOk = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc2 = sqlite3_finalize(pStmt);
|
||||||
|
if( rc==SQLITE_OK ) rc = rc2;
|
||||||
|
if( rc==SQLITE_OK && bOk==0 ) rc = SQLITE_ERROR;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Argument zFmt must be a printf-style format string and must be
|
||||||
|
** followed by its required arguments. If argument pzOut is NULL,
|
||||||
|
** then the results of printf()ing the format string are passed to
|
||||||
|
** sqlite3_log(). Otherwise, they are appended to the string
|
||||||
|
** at (*pzOut).
|
||||||
|
*/
|
||||||
|
static int checkFreelistError(char **pzOut, const char *zFmt, ...){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
char *zErr = 0;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, zFmt);
|
||||||
|
zErr = sqlite3_vmprintf(zFmt, ap);
|
||||||
|
if( zErr==0 ){
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
}else{
|
||||||
|
if( pzOut ){
|
||||||
|
*pzOut = sqlite3_mprintf("%s%z%s", *pzOut?"\n":"", *pzOut, zErr);
|
||||||
|
if( *pzOut==0 ) rc = SQLITE_NOMEM;
|
||||||
|
}else{
|
||||||
|
sqlite3_log(SQLITE_ERROR, "checkfreelist: %s", zErr);
|
||||||
|
}
|
||||||
|
sqlite3_free(zErr);
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int checkFreelist(
|
||||||
|
sqlite3 *db,
|
||||||
|
const char *zDb,
|
||||||
|
char **pzOut
|
||||||
|
){
|
||||||
|
/* This query returns one row for each page on the free list. Each row has
|
||||||
|
** two columns - the page number and page content. */
|
||||||
|
const char *zTrunk =
|
||||||
|
"WITH freelist_trunk(i, d, n) AS ("
|
||||||
|
"SELECT 1, NULL, sqlite_readint32(data, 32) "
|
||||||
|
"FROM sqlite_dbpage(:1) WHERE pgno=1 "
|
||||||
|
"UNION ALL "
|
||||||
|
"SELECT n, data, sqlite_readint32(data) "
|
||||||
|
"FROM freelist_trunk, sqlite_dbpage(:1) WHERE pgno=n "
|
||||||
|
")"
|
||||||
|
"SELECT i, d FROM freelist_trunk WHERE i!=1;";
|
||||||
|
|
||||||
|
int rc, rc2; /* Return code */
|
||||||
|
sqlite3_stmt *pTrunk = 0; /* Compilation of zTrunk */
|
||||||
|
u32 nPage = 0; /* Number of pages in db */
|
||||||
|
u32 nExpected = 0; /* Expected number of free pages */
|
||||||
|
u32 nFree = 0; /* Number of pages on free list */
|
||||||
|
|
||||||
|
if( zDb==0 ) zDb = "main";
|
||||||
|
|
||||||
|
if( (rc = sqlGetInteger(db, zDb, "PRAGMA %s.page_count", &nPage))
|
||||||
|
|| (rc = sqlGetInteger(db, zDb, "PRAGMA %s.freelist_count", &nExpected))
|
||||||
|
){
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sqlite3_prepare_v2(db, zTrunk, -1, &pTrunk, 0);
|
||||||
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
|
sqlite3_bind_text(pTrunk, 1, zDb, -1, SQLITE_STATIC);
|
||||||
|
while( rc==SQLITE_OK && sqlite3_step(pTrunk)==SQLITE_ROW ){
|
||||||
|
u32 i;
|
||||||
|
u32 iTrunk = (u32)sqlite3_column_int(pTrunk, 0);
|
||||||
|
const u8 *aData = (const u8*)sqlite3_column_blob(pTrunk, 1);
|
||||||
|
int nData = sqlite3_column_bytes(pTrunk, 1);
|
||||||
|
u32 iNext = get4byte(&aData[0]);
|
||||||
|
u32 nLeaf = get4byte(&aData[4]);
|
||||||
|
|
||||||
|
if( nLeaf>((nData/4)-2-6) ){
|
||||||
|
rc = checkFreelistError(pzOut,
|
||||||
|
"leaf count out of range (%d) on trunk page %d",
|
||||||
|
(int)nLeaf, (int)iTrunk
|
||||||
|
);
|
||||||
|
nLeaf = (nData/4) - 2 - 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
nFree += 1+nLeaf;
|
||||||
|
if( iNext>nPage ){
|
||||||
|
rc = checkFreelistError(pzOut,
|
||||||
|
"trunk page %d is out of range", (int)iNext
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; rc==SQLITE_OK && i<nLeaf; i++){
|
||||||
|
u32 iLeaf = get4byte(&aData[8 + 4*i]);
|
||||||
|
if( iLeaf==0 || iLeaf>nPage ){
|
||||||
|
rc = checkFreelistError(pzOut,
|
||||||
|
"leaf page %d is out of range (child %d of trunk page %d)",
|
||||||
|
(int)iLeaf, (int)i, (int)iTrunk
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK && nFree!=nExpected ){
|
||||||
|
rc = checkFreelistError(pzOut,
|
||||||
|
"free-list count mismatch: actual=%d header=%d",
|
||||||
|
(int)nFree, (int)nExpected
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc2 = sqlite3_finalize(pTrunk);
|
||||||
|
if( rc==SQLITE_OK ) rc = rc2;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sqlite3_check_freelist(sqlite3 *db, const char *zDb){
|
||||||
|
return checkFreelist(db, zDb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkfreelist_function(
|
||||||
|
sqlite3_context *pCtx,
|
||||||
|
int nArg,
|
||||||
|
sqlite3_value **apArg
|
||||||
|
){
|
||||||
|
const char *zDb;
|
||||||
|
int rc;
|
||||||
|
char *zOut = 0;
|
||||||
|
sqlite3 *db = sqlite3_context_db_handle(pCtx);
|
||||||
|
|
||||||
|
assert( nArg==1 );
|
||||||
|
zDb = (const char*)sqlite3_value_text(apArg[0]);
|
||||||
|
rc = checkFreelist(db, zDb, &zOut);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
sqlite3_result_text(pCtx, zOut?zOut:"ok", -1, SQLITE_TRANSIENT);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_error_code(pCtx, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_free(zOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An SQL function invoked as follows:
|
||||||
|
**
|
||||||
|
** sqlite_readint32(BLOB) -- Decode 32-bit integer from start of blob
|
||||||
|
*/
|
||||||
|
static void readint_function(
|
||||||
|
sqlite3_context *pCtx,
|
||||||
|
int nArg,
|
||||||
|
sqlite3_value **apArg
|
||||||
|
){
|
||||||
|
const u8 *zBlob;
|
||||||
|
int nBlob;
|
||||||
|
int iOff = 0;
|
||||||
|
u32 iRet = 0;
|
||||||
|
|
||||||
|
if( nArg!=1 && nArg!=2 ){
|
||||||
|
sqlite3_result_error(
|
||||||
|
pCtx, "wrong number of arguments to function sqlite_readint32()", -1
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( nArg==2 ){
|
||||||
|
iOff = sqlite3_value_int(apArg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
zBlob = sqlite3_value_blob(apArg[0]);
|
||||||
|
nBlob = sqlite3_value_bytes(apArg[0]);
|
||||||
|
|
||||||
|
if( nBlob>=(iOff+4) ){
|
||||||
|
iRet = get4byte(&zBlob[iOff]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_result_int64(pCtx, (sqlite3_int64)iRet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Register the SQL functions.
|
||||||
|
*/
|
||||||
|
static int cflRegister(sqlite3 *db){
|
||||||
|
int rc = sqlite3_create_function(
|
||||||
|
db, "sqlite_readint32", -1, SQLITE_UTF8, 0, readint_function, 0, 0
|
||||||
|
);
|
||||||
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
|
rc = sqlite3_create_function(
|
||||||
|
db, "checkfreelist", 1, SQLITE_UTF8, 0, checkfreelist_function, 0, 0
|
||||||
|
);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Extension load function.
|
||||||
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
|
__declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
int sqlite3_checkfreelist_init(
|
||||||
|
sqlite3 *db,
|
||||||
|
char **pzErrMsg,
|
||||||
|
const sqlite3_api_routines *pApi
|
||||||
|
){
|
||||||
|
SQLITE_EXTENSION_INIT2(pApi);
|
||||||
|
return cflRegister(db);
|
||||||
|
}
|
7
main.mk
7
main.mk
@ -55,7 +55,8 @@ THREADLIB += $(LIBS)
|
|||||||
LIBOBJ+= vdbe.o parse.o \
|
LIBOBJ+= vdbe.o parse.o \
|
||||||
alter.o analyze.o attach.o auth.o \
|
alter.o analyze.o attach.o auth.o \
|
||||||
backup.o bitvec.o btmutex.o btree.o build.o \
|
backup.o bitvec.o btmutex.o btree.o build.o \
|
||||||
callback.o complete.o ctime.o date.o dbstat.o delete.o expr.o \
|
callback.o complete.o ctime.o \
|
||||||
|
date.o dbpage.o dbstat.o delete.o expr.o \
|
||||||
fault.o fkey.o \
|
fault.o fkey.o \
|
||||||
fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
|
fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
|
||||||
fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \
|
fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \
|
||||||
@ -96,6 +97,7 @@ SRC = \
|
|||||||
$(TOP)/src/complete.c \
|
$(TOP)/src/complete.c \
|
||||||
$(TOP)/src/ctime.c \
|
$(TOP)/src/ctime.c \
|
||||||
$(TOP)/src/date.c \
|
$(TOP)/src/date.c \
|
||||||
|
$(TOP)/src/dbpage.c \
|
||||||
$(TOP)/src/dbstat.c \
|
$(TOP)/src/dbstat.c \
|
||||||
$(TOP)/src/delete.c \
|
$(TOP)/src/delete.c \
|
||||||
$(TOP)/src/expr.c \
|
$(TOP)/src/expr.c \
|
||||||
@ -360,6 +362,7 @@ TESTSRC2 = \
|
|||||||
$(TOP)/src/btree.c \
|
$(TOP)/src/btree.c \
|
||||||
$(TOP)/src/build.c \
|
$(TOP)/src/build.c \
|
||||||
$(TOP)/src/date.c \
|
$(TOP)/src/date.c \
|
||||||
|
$(TOP)/src/dbpage.c \
|
||||||
$(TOP)/src/dbstat.c \
|
$(TOP)/src/dbstat.c \
|
||||||
$(TOP)/src/expr.c \
|
$(TOP)/src/expr.c \
|
||||||
$(TOP)/src/func.c \
|
$(TOP)/src/func.c \
|
||||||
@ -481,6 +484,8 @@ SHELL_OPT += -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
|
|||||||
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||||
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||||
|
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||||
|
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||||
|
30
manifest
30
manifest
@ -1,8 +1,8 @@
|
|||||||
C The\ssrc/shell.c\sfile\sis\snow\sgenerated\sfrom\ssrc/shell.c.in,\sso\sremove\sshell.c\nfrom\sversion\scontrol\sand\supdate\sthe\smakefiles\sto\sbuild\sit\sautomatically.
|
C Add\sthe\ssqlite_dbpage\svirtual\stable\s(enabled\susing\sSQLITE_ENABLE_DBPAGE_VTAB).\nMake\sthat\svirtual\stable\sand\sdbstat\savailable\sto\sthe\scommand-line\sshell.
|
||||||
D 2017-10-12T13:47:48.544
|
D 2017-10-12T20:37:20.278
|
||||||
F Makefile.in 9c9f4dea3f622464cba9768501aceca187d2bbae10b60bf420b531cd776fe5c0
|
F Makefile.in cb88ca5a6d8e116a50bd19bf477384498df475c5463cbbf53f36624ce308ed62
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc 3f96a87fb271b06aede7e304234cce096edd3d5ad76507ccc4716b20511a3b20
|
F Makefile.msc 918f07fee01bf858d20df6b37802161423f216da1ece14794afee12de4992e35
|
||||||
F README.md f5c87359573c4d255425e588a56554b50fdcc2afba4e017a2e02a43701456afd
|
F README.md f5c87359573c4d255425e588a56554b50fdcc2afba4e017a2e02a43701456afd
|
||||||
F VERSION f81232df28e2d3ff049feefad5fbd5489cc33697f6bd2ecf61af7f0dde3b83d0
|
F VERSION f81232df28e2d3ff049feefad5fbd5489cc33697f6bd2ecf61af7f0dde3b83d0
|
||||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||||
@ -325,6 +325,8 @@ F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
|
|||||||
F ext/rbu/sqlite3rbu.c 64bd08c1011456f90564ed167abce3a9c2af421a924b21eb57231e078da04feb
|
F ext/rbu/sqlite3rbu.c 64bd08c1011456f90564ed167abce3a9c2af421a924b21eb57231e078da04feb
|
||||||
F ext/rbu/sqlite3rbu.h b42bcd4d8357268c6c39ab2a60b29c091e89328fa8cc49c8fac5ab8d007e79b2
|
F ext/rbu/sqlite3rbu.h b42bcd4d8357268c6c39ab2a60b29c091e89328fa8cc49c8fac5ab8d007e79b2
|
||||||
F ext/rbu/test_rbu.c 7073979b9cc80912bb03599ac8d85ab5d3bf03cfacd3463f2dcdd7822997533a
|
F ext/rbu/test_rbu.c 7073979b9cc80912bb03599ac8d85ab5d3bf03cfacd3463f2dcdd7822997533a
|
||||||
|
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
|
||||||
|
F ext/repair/checkfreelist.c 0abb84b4545016d57ba1a2aa8884c72c73ed838968909858c03bc1f38fb6b054
|
||||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||||
F ext/rtree/rtree.c f2fd34db37ea053798f8e66b44a473449b21301d2b92505ee576823789e909fb
|
F ext/rtree/rtree.c f2fd34db37ea053798f8e66b44a473449b21301d2b92505ee576823789e909fb
|
||||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||||
@ -382,7 +384,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
|||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||||
F main.mk 3e671408634fb8e8eaa296e80627066a2524053db5a9c5c28c6ec06cf7e99a51
|
F main.mk 8be17ffd37df86bfbd696072045cd360600499876f7144313090f96ce3a37a55
|
||||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||||
@ -409,6 +411,7 @@ F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f30868
|
|||||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||||
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
||||||
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
||||||
|
F src/dbpage.c c625a0bd605d4cea9a3258b8db49a5474a04976e95a9fe380cdaf74e8eb6736d
|
||||||
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
||||||
F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
|
F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
|
||||||
F src/expr.c 4d2d0aafd945424f638ee03e11330f03288ccf616e025498f3c8602d01609a0a
|
F src/expr.c 4d2d0aafd945424f638ee03e11330f03288ccf616e025498f3c8602d01609a0a
|
||||||
@ -423,7 +426,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
|||||||
F src/insert.c 1f33ef4ca0553b60fff03aa171370f8709a3e945acfcc68ccafc92752d872f40
|
F src/insert.c 1f33ef4ca0553b60fff03aa171370f8709a3e945acfcc68ccafc92752d872f40
|
||||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||||
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
|
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
|
||||||
F src/main.c a4bdadaaa827e7380cba4de878ed7947dab5aeb84f617118ba6a0422cd745b4b
|
F src/main.c 54637b9e7f91de6d281e577cd1a997762a4613f51a0509790027ca9865185d7c
|
||||||
F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
|
F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
|
||||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||||
@ -459,11 +462,11 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
|||||||
F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
|
F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
|
||||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||||
F src/select.c 42aca61e739c405ddd8a1b702977a7743c7d52a94885f7c5596bd7e73e6bff18
|
F src/select.c 42aca61e739c405ddd8a1b702977a7743c7d52a94885f7c5596bd7e73e6bff18
|
||||||
F src/shell.c.in 423944f4ad73a7e73d9c06e645e19ac1aa5f45c22069936e3a008b28a5df8003
|
F src/shell.c.in 5446de0a90c15d713bbdb5827cf57ec30d1c3497097f39ec2c2e874dcca34ca3
|
||||||
F src/sqlite.h.in ab4f8a29d1580dfaeb6891fa1b83cff8229ba0daa56994707ceaca71495d9ab7
|
F src/sqlite.h.in ab4f8a29d1580dfaeb6891fa1b83cff8229ba0daa56994707ceaca71495d9ab7
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h a1fd3aa82f967da436164e0728a7d6841651fd0c6e27b9044e0eb9f6c8462e47
|
F src/sqlite3ext.h a1fd3aa82f967da436164e0728a7d6841651fd0c6e27b9044e0eb9f6c8462e47
|
||||||
F src/sqliteInt.h c07bc88eca1f59ce73e1f486187d0df4effe67c4579e112dfdd91c159e5c0569
|
F src/sqliteInt.h 6f93fd6fde862410ac26b930f70752c38ad99ea78c3fc28356bac78049c53bd9
|
||||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||||
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
||||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||||
@ -645,6 +648,7 @@ F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
|
|||||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||||
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
|
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
|
||||||
F test/check.test 33a698e8c63613449d85d624a38ef669bf20331daabebe3891c9405dd6df463a
|
F test/check.test 33a698e8c63613449d85d624a38ef669bf20331daabebe3891c9405dd6df463a
|
||||||
|
F test/checkfreelist.test 100283a3e6b8a3018c7fab7cfdaf03d1d6540fc66453114e248cf82b25784d3b
|
||||||
F test/close.test 799ea4599d2f5704b0a30f477d17c2c760d8523fa5d0c8be4a7df2a8cad787d8
|
F test/close.test 799ea4599d2f5704b0a30f477d17c2c760d8523fa5d0c8be4a7df2a8cad787d8
|
||||||
F test/closure01.test b1703ba40639cfc9b295cf478d70739415eec6a4
|
F test/closure01.test b1703ba40639cfc9b295cf478d70739415eec6a4
|
||||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||||
@ -707,6 +711,7 @@ F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
|
|||||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||||
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
|
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
|
||||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||||
|
F test/dbpage.test 9cf4dc92a4de67c81e5c32b24e3fbb8c4757e4b642694a219b3090a4f9277a4d
|
||||||
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
||||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||||
@ -1597,7 +1602,7 @@ F tool/mkshellc.tcl 574307265b49d813301fba91ccd74e6a26d33f65f74b6891c320a0ffbee0
|
|||||||
F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
|
F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
|
||||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||||
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
||||||
F tool/mksqlite3c.tcl b258d679829a9305f5cf107b7d97b9bf23adb3773df42947fed5ef7b180dfbd9
|
F tool/mksqlite3c.tcl 1fb69d39166f52d802a70ec37d99bca51d011c8ab30be27bc495be493196ae41
|
||||||
F tool/mksqlite3h.tcl f92f994d9709aeb9e2b6e6f9fc8b069d2f55202c8e23f453edc44390a25982dc
|
F tool/mksqlite3h.tcl f92f994d9709aeb9e2b6e6f9fc8b069d2f55202c8e23f453edc44390a25982dc
|
||||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||||
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
|
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
|
||||||
@ -1656,7 +1661,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 292921692c8919d29f0a67d03ca953d5c1c4900d8c8567cceab27513732be598
|
P 36acc0a97fdcc6f54f29c68c4e131702f69c3e59e58237ff4e5c647928699956 dfdebd12bfc80b91d234ab328cb6106d5d37ccb79b58e36e556c1a8af640a4ab
|
||||||
R 55fc95c237c6d381b00d7c404f68ae59
|
R a8e3c658e72c296e51cc10d88be952b0
|
||||||
|
T +closed dfdebd12bfc80b91d234ab328cb6106d5d37ccb79b58e36e556c1a8af640a4ab
|
||||||
U drh
|
U drh
|
||||||
Z 4cb9f1b7e5b96c77468dac8db9ac0cf0
|
Z 03ff5b730193797e00df33319c2ae82d
|
||||||
|
@ -1 +1 @@
|
|||||||
36acc0a97fdcc6f54f29c68c4e131702f69c3e59e58237ff4e5c647928699956
|
eaeeb09d4aa1dbccdd2488af8461e2a8c8a53d92c63fd56330be041ad72a9e4a
|
329
src/dbpage.c
Normal file
329
src/dbpage.c
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
** 2017-10-11
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
******************************************************************************
|
||||||
|
**
|
||||||
|
** This file contains an implementation of the "sqlite_dbpage" virtual table.
|
||||||
|
**
|
||||||
|
** The sqlite_dbpage virtual table is used to read or write whole raw
|
||||||
|
** pages of the database file. The pager interface is used so that
|
||||||
|
** uncommitted changes and changes recorded in the WAL file are correctly
|
||||||
|
** retrieved.
|
||||||
|
**
|
||||||
|
** Usage example:
|
||||||
|
**
|
||||||
|
** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
|
||||||
|
**
|
||||||
|
** This is an eponymous virtual table so it does not need to be created before
|
||||||
|
** use. The optional argument to the sqlite_dbpage() table name is the
|
||||||
|
** schema for the database file that is to be read. The default schema is
|
||||||
|
** "main".
|
||||||
|
**
|
||||||
|
** The data field of sqlite_dbpage table can be updated. The new
|
||||||
|
** value must be a BLOB which is the correct page size, otherwise the
|
||||||
|
** update fails. Rows may not be deleted or inserted.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sqliteInt.h" /* Requires access to internal data structures */
|
||||||
|
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
|
||||||
|
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||||
|
|
||||||
|
typedef struct DbpageTable DbpageTable;
|
||||||
|
typedef struct DbpageCursor DbpageCursor;
|
||||||
|
|
||||||
|
struct DbpageCursor {
|
||||||
|
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
||||||
|
int pgno; /* Current page number */
|
||||||
|
int mxPgno; /* Last page to visit on this scan */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DbpageTable {
|
||||||
|
sqlite3_vtab base; /* Base class. Must be first */
|
||||||
|
sqlite3 *db; /* The database */
|
||||||
|
Pager *pPager; /* Pager being read/written */
|
||||||
|
int iDb; /* Index of database to analyze */
|
||||||
|
int szPage; /* Size of each page in bytes */
|
||||||
|
int nPage; /* Number of pages in the file */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Connect to or create a dbpagevfs virtual table.
|
||||||
|
*/
|
||||||
|
static int dbpageConnect(
|
||||||
|
sqlite3 *db,
|
||||||
|
void *pAux,
|
||||||
|
int argc, const char *const*argv,
|
||||||
|
sqlite3_vtab **ppVtab,
|
||||||
|
char **pzErr
|
||||||
|
){
|
||||||
|
DbpageTable *pTab = 0;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
int iDb;
|
||||||
|
|
||||||
|
if( argc>=4 ){
|
||||||
|
Token nm;
|
||||||
|
sqlite3TokenInit(&nm, (char*)argv[3]);
|
||||||
|
iDb = sqlite3FindDb(db, &nm);
|
||||||
|
if( iDb<0 ){
|
||||||
|
*pzErr = sqlite3_mprintf("no such schema: %s", argv[3]);
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
iDb = 0;
|
||||||
|
}
|
||||||
|
rc = sqlite3_declare_vtab(db,
|
||||||
|
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
|
||||||
|
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( rc==SQLITE_OK || pTab==0 );
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
Btree *pBt = db->aDb[iDb].pBt;
|
||||||
|
memset(pTab, 0, sizeof(DbpageTable));
|
||||||
|
pTab->db = db;
|
||||||
|
pTab->iDb = iDb;
|
||||||
|
pTab->pPager = pBt ? sqlite3BtreePager(pBt) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppVtab = (sqlite3_vtab*)pTab;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Disconnect from or destroy a dbpagevfs virtual table.
|
||||||
|
*/
|
||||||
|
static int dbpageDisconnect(sqlite3_vtab *pVtab){
|
||||||
|
sqlite3_free(pVtab);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** idxNum:
|
||||||
|
**
|
||||||
|
** 0 full table scan
|
||||||
|
** 1 pgno=?1
|
||||||
|
*/
|
||||||
|
static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||||
|
int i;
|
||||||
|
pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */
|
||||||
|
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||||
|
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
|
||||||
|
if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||||
|
pIdxInfo->estimatedRows = 1;
|
||||||
|
pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
|
||||||
|
pIdxInfo->estimatedCost = 1.0;
|
||||||
|
pIdxInfo->idxNum = 1;
|
||||||
|
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||||
|
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( pIdxInfo->nOrderBy>=1
|
||||||
|
&& pIdxInfo->aOrderBy[0].iColumn<=0
|
||||||
|
&& pIdxInfo->aOrderBy[0].desc==0
|
||||||
|
){
|
||||||
|
pIdxInfo->orderByConsumed = 1;
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Open a new dbpagevfs cursor.
|
||||||
|
*/
|
||||||
|
static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||||
|
DbpageCursor *pCsr;
|
||||||
|
|
||||||
|
pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
|
||||||
|
if( pCsr==0 ){
|
||||||
|
return SQLITE_NOMEM_BKPT;
|
||||||
|
}else{
|
||||||
|
memset(pCsr, 0, sizeof(DbpageCursor));
|
||||||
|
pCsr->base.pVtab = pVTab;
|
||||||
|
pCsr->pgno = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Close a dbpagevfs cursor.
|
||||||
|
*/
|
||||||
|
static int dbpageClose(sqlite3_vtab_cursor *pCursor){
|
||||||
|
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
||||||
|
sqlite3_free(pCsr);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Move a dbpagevfs cursor to the next entry in the file.
|
||||||
|
*/
|
||||||
|
static int dbpageNext(sqlite3_vtab_cursor *pCursor){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
||||||
|
pCsr->pgno++;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dbpageEof(sqlite3_vtab_cursor *pCursor){
|
||||||
|
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
||||||
|
return pCsr->pgno > pCsr->mxPgno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dbpageFilter(
|
||||||
|
sqlite3_vtab_cursor *pCursor,
|
||||||
|
int idxNum, const char *idxStr,
|
||||||
|
int argc, sqlite3_value **argv
|
||||||
|
){
|
||||||
|
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
||||||
|
DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
|
||||||
|
|
||||||
|
pTab->szPage = sqlite3BtreeGetPageSize(pBt);
|
||||||
|
pTab->nPage = sqlite3BtreeLastPage(pBt);
|
||||||
|
if( idxNum==1 ){
|
||||||
|
pCsr->pgno = sqlite3_value_int(argv[0]);
|
||||||
|
if( pCsr->pgno<1 || pCsr->pgno>pTab->nPage ){
|
||||||
|
pCsr->pgno = 1;
|
||||||
|
pCsr->mxPgno = 0;
|
||||||
|
}else{
|
||||||
|
pCsr->mxPgno = pCsr->pgno;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
pCsr->pgno = 1;
|
||||||
|
pCsr->mxPgno = pTab->nPage;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dbpageColumn(
|
||||||
|
sqlite3_vtab_cursor *pCursor,
|
||||||
|
sqlite3_context *ctx,
|
||||||
|
int i
|
||||||
|
){
|
||||||
|
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
||||||
|
DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
switch( i ){
|
||||||
|
case 0: { /* pgno */
|
||||||
|
sqlite3_result_int(ctx, pCsr->pgno);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: { /* data */
|
||||||
|
DbPage *pDbPage = 0;
|
||||||
|
rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage,
|
||||||
|
SQLITE_TRANSIENT);
|
||||||
|
}
|
||||||
|
sqlite3PagerUnref(pDbPage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: { /* schema */
|
||||||
|
sqlite3 *db = sqlite3_context_db_handle(ctx);
|
||||||
|
sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
||||||
|
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
||||||
|
*pRowid = pCsr->pgno;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dbpageUpdate(
|
||||||
|
sqlite3_vtab *pVtab,
|
||||||
|
int argc,
|
||||||
|
sqlite3_value **argv,
|
||||||
|
sqlite_int64 *pRowid
|
||||||
|
){
|
||||||
|
DbpageTable *pTab = (DbpageTable *)pVtab;
|
||||||
|
int pgno;
|
||||||
|
DbPage *pDbPage = 0;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
char *zErr = 0;
|
||||||
|
|
||||||
|
if( argc==1 ){
|
||||||
|
zErr = "cannot delete";
|
||||||
|
goto update_fail;
|
||||||
|
}
|
||||||
|
pgno = sqlite3_value_int(argv[0]);
|
||||||
|
if( pgno<1 || pgno>pTab->nPage ){
|
||||||
|
zErr = "bad page number";
|
||||||
|
goto update_fail;
|
||||||
|
}
|
||||||
|
if( sqlite3_value_int(argv[1])!=pgno ){
|
||||||
|
zErr = "cannot insert";
|
||||||
|
goto update_fail;
|
||||||
|
}
|
||||||
|
if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
|
||||||
|
|| sqlite3_value_bytes(argv[3])!=pTab->szPage
|
||||||
|
){
|
||||||
|
zErr = "bad page value";
|
||||||
|
goto update_fail;
|
||||||
|
}
|
||||||
|
rc = sqlite3PagerGet(pTab->pPager, pgno, (DbPage**)&pDbPage, 0);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sqlite3PagerWrite(pDbPage);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
memcpy(sqlite3PagerGetData(pDbPage),
|
||||||
|
sqlite3_value_blob(argv[3]),
|
||||||
|
pTab->szPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3PagerUnref(pDbPage);
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
update_fail:
|
||||||
|
sqlite3_free(pVtab->zErrMsg);
|
||||||
|
pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Invoke this routine to register the "dbpage" virtual table module
|
||||||
|
*/
|
||||||
|
int sqlite3DbpageRegister(sqlite3 *db){
|
||||||
|
static sqlite3_module dbpage_module = {
|
||||||
|
0, /* iVersion */
|
||||||
|
dbpageConnect, /* xCreate */
|
||||||
|
dbpageConnect, /* xConnect */
|
||||||
|
dbpageBestIndex, /* xBestIndex */
|
||||||
|
dbpageDisconnect, /* xDisconnect */
|
||||||
|
dbpageDisconnect, /* xDestroy */
|
||||||
|
dbpageOpen, /* xOpen - open a cursor */
|
||||||
|
dbpageClose, /* xClose - close a cursor */
|
||||||
|
dbpageFilter, /* xFilter - configure scan constraints */
|
||||||
|
dbpageNext, /* xNext - advance a cursor */
|
||||||
|
dbpageEof, /* xEof - check for end of scan */
|
||||||
|
dbpageColumn, /* xColumn - read data */
|
||||||
|
dbpageRowid, /* xRowid - read data */
|
||||||
|
dbpageUpdate, /* xUpdate */
|
||||||
|
0, /* xBegin */
|
||||||
|
0, /* xSync */
|
||||||
|
0, /* xCommit */
|
||||||
|
0, /* xRollback */
|
||||||
|
0, /* xFindMethod */
|
||||||
|
0, /* xRename */
|
||||||
|
0, /* xSavepoint */
|
||||||
|
0, /* xRelease */
|
||||||
|
0, /* xRollbackTo */
|
||||||
|
};
|
||||||
|
return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
|
||||||
|
}
|
||||||
|
#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||||
|
int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
|
||||||
|
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
|
@ -3054,6 +3054,12 @@ static int openDatabase(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_DBPAGE_VTAB
|
||||||
|
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||||
|
rc = sqlite3DbpageRegister(db);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
||||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||||
rc = sqlite3DbstatRegister(db);
|
rc = sqlite3DbstatRegister(db);
|
||||||
|
@ -3611,20 +3611,24 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
|||||||
{ "schema size:",
|
{ "schema size:",
|
||||||
"SELECT total(length(sql)) FROM %s" },
|
"SELECT total(length(sql)) FROM %s" },
|
||||||
};
|
};
|
||||||
sqlite3_file *pFile = 0;
|
|
||||||
int i;
|
int i;
|
||||||
char *zSchemaTab;
|
char *zSchemaTab;
|
||||||
char *zDb = nArg>=2 ? azArg[1] : "main";
|
char *zDb = nArg>=2 ? azArg[1] : "main";
|
||||||
|
sqlite3_stmt *pStmt = 0;
|
||||||
unsigned char aHdr[100];
|
unsigned char aHdr[100];
|
||||||
open_db(p, 0);
|
open_db(p, 0);
|
||||||
if( p->db==0 ) return 1;
|
if( p->db==0 ) return 1;
|
||||||
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
|
sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
|
||||||
if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
|
-1, &pStmt, 0);
|
||||||
return 1;
|
sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
|
||||||
}
|
if( sqlite3_step(pStmt)==SQLITE_ROW
|
||||||
i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
|
&& sqlite3_column_bytes(pStmt,0)>100
|
||||||
if( i!=SQLITE_OK ){
|
){
|
||||||
|
memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
|
||||||
|
sqlite3_finalize(pStmt);
|
||||||
|
}else{
|
||||||
raw_printf(stderr, "unable to read database header\n");
|
raw_printf(stderr, "unable to read database header\n");
|
||||||
|
sqlite3_finalize(pStmt);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
i = get2byteInt(aHdr+16);
|
i = get2byteInt(aHdr+16);
|
||||||
|
@ -4400,6 +4400,9 @@ int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
|
|||||||
int sqlite3ThreadJoin(SQLiteThread*, void**);
|
int sqlite3ThreadJoin(SQLiteThread*, void**);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
|
||||||
|
int sqlite3DbpageRegister(sqlite3*);
|
||||||
|
#endif
|
||||||
#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
|
#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
|
||||||
int sqlite3DbstatRegister(sqlite3*);
|
int sqlite3DbstatRegister(sqlite3*);
|
||||||
#endif
|
#endif
|
||||||
|
123
test/checkfreelist.test
Normal file
123
test/checkfreelist.test
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
# 2017-10-11
|
||||||
|
#
|
||||||
|
# The author disclaims copyright to this source code. In place of
|
||||||
|
# a legal notice, here is a blessing:
|
||||||
|
#
|
||||||
|
# May you do good and not evil.
|
||||||
|
# May you find forgiveness for yourself and forgive others.
|
||||||
|
# May you share freely, never taking more than you give.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing the checkfreelist extension.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set testprefix checkfreelist
|
||||||
|
|
||||||
|
ifcapable !vtab||!compound {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if {[file exists ../checkfreelist.so]==0} {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.0 {
|
||||||
|
CREATE TABLE t1(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
db enable_load_extension 1
|
||||||
|
do_execsql_test 1.1 {
|
||||||
|
SELECT load_extension('../checkfreelist.so');
|
||||||
|
} {{}}
|
||||||
|
|
||||||
|
do_execsql_test 1.2 { SELECT checkfreelist('main') } {ok}
|
||||||
|
do_execsql_test 1.3 {
|
||||||
|
WITH s(i) AS (
|
||||||
|
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000
|
||||||
|
)
|
||||||
|
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s;
|
||||||
|
DELETE FROM t1 WHERE rowid%3;
|
||||||
|
PRAGMA freelist_count;
|
||||||
|
} {6726}
|
||||||
|
|
||||||
|
do_execsql_test 1.4 { SELECT checkfreelist('main') } {ok}
|
||||||
|
do_execsql_test 1.5 {
|
||||||
|
WITH freelist_trunk(i, d, n) AS (
|
||||||
|
SELECT 1, NULL, sqlite_readint32(data, 32) FROM sqlite_dbpage WHERE pgno=1
|
||||||
|
UNION ALL
|
||||||
|
SELECT n, data, sqlite_readint32(data)
|
||||||
|
FROM freelist_trunk, sqlite_dbpage WHERE pgno=n
|
||||||
|
)
|
||||||
|
SELECT i FROM freelist_trunk WHERE i!=1;
|
||||||
|
} {
|
||||||
|
10010 9716 9344 8970 8596 8223 7848 7475 7103 6728 6355 5983 5609 5235
|
||||||
|
4861 4488 4113 3741 3368 2993 2620 2248 1873 1500 1126 753 378 5
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.6 { SELECT checkfreelist('main') } {ok}
|
||||||
|
|
||||||
|
proc set_int {blob idx newval} {
|
||||||
|
binary scan $blob I* ints
|
||||||
|
lset ints $idx $newval
|
||||||
|
binary format I* $ints
|
||||||
|
}
|
||||||
|
db func set_int set_int
|
||||||
|
|
||||||
|
proc get_int {blob idx} {
|
||||||
|
binary scan $blob I* ints
|
||||||
|
lindex $ints $idx
|
||||||
|
}
|
||||||
|
db func get_int get_int
|
||||||
|
|
||||||
|
do_execsql_test 1.7 {
|
||||||
|
BEGIN;
|
||||||
|
UPDATE sqlite_dbpage
|
||||||
|
SET data = set_int(data, 1, get_int(data, 1)-1)
|
||||||
|
WHERE pgno=4861;
|
||||||
|
SELECT checkfreelist('main');
|
||||||
|
ROLLBACK;
|
||||||
|
} {{free-list count mismatch: actual=6725 header=6726}}
|
||||||
|
|
||||||
|
do_execsql_test 1.8 {
|
||||||
|
BEGIN;
|
||||||
|
UPDATE sqlite_dbpage
|
||||||
|
SET data = set_int(data, 5, (SELECT * FROM pragma_page_count)+1)
|
||||||
|
WHERE pgno=4861;
|
||||||
|
SELECT checkfreelist('main');
|
||||||
|
ROLLBACK;
|
||||||
|
} {{leaf page 10093 is out of range (child 3 of trunk page 4861)}}
|
||||||
|
|
||||||
|
do_execsql_test 1.9 {
|
||||||
|
BEGIN;
|
||||||
|
UPDATE sqlite_dbpage
|
||||||
|
SET data = set_int(data, 5, 0)
|
||||||
|
WHERE pgno=4861;
|
||||||
|
SELECT checkfreelist('main');
|
||||||
|
ROLLBACK;
|
||||||
|
} {{leaf page 0 is out of range (child 3 of trunk page 4861)}}
|
||||||
|
|
||||||
|
do_execsql_test 1.10 {
|
||||||
|
BEGIN;
|
||||||
|
UPDATE sqlite_dbpage
|
||||||
|
SET data = set_int(data, get_int(data, 1)+1, 0)
|
||||||
|
WHERE pgno=5;
|
||||||
|
SELECT checkfreelist('main');
|
||||||
|
ROLLBACK;
|
||||||
|
} {{leaf page 0 is out of range (child 247 of trunk page 5)}}
|
||||||
|
|
||||||
|
do_execsql_test 1.11 {
|
||||||
|
BEGIN;
|
||||||
|
UPDATE sqlite_dbpage
|
||||||
|
SET data = set_int(data, 1, 249)
|
||||||
|
WHERE pgno=5;
|
||||||
|
SELECT checkfreelist('main');
|
||||||
|
ROLLBACK;
|
||||||
|
} {{leaf count out of range (249) on trunk page 5}}
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
69
test/dbpage.test
Normal file
69
test/dbpage.test
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# 2017-10-11
|
||||||
|
#
|
||||||
|
# The author disclaims copyright to this source code. In place of
|
||||||
|
# a legal notice, here is a blessing:
|
||||||
|
#
|
||||||
|
# May you do good and not evil.
|
||||||
|
# May you find forgiveness for yourself and forgive others.
|
||||||
|
# May you share freely, never taking more than you give.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing the sqlite_dbpage virtual table.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set testprefix dbpage
|
||||||
|
|
||||||
|
ifcapable !vtab||!compound {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 100 {
|
||||||
|
PRAGMA page_size=4096;
|
||||||
|
PRAGMA journal_mode=WAL;
|
||||||
|
CREATE TABLE t1(a,b);
|
||||||
|
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
|
||||||
|
INSERT INTO t1(a,b) SELECT x, printf('%d-x%.*c',x,x,'x') FROM c;
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
} {wal ok}
|
||||||
|
do_execsql_test 110 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('main') ORDER BY pgno;
|
||||||
|
} {1 X'53514C6974' 2 X'0500000001' 3 X'0D0000004E' 4 X'0D00000016'}
|
||||||
|
do_execsql_test 120 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=2;
|
||||||
|
} {2 X'0500000001'}
|
||||||
|
do_execsql_test 130 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=4;
|
||||||
|
} {4 X'0D00000016'}
|
||||||
|
do_execsql_test 140 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=5;
|
||||||
|
} {}
|
||||||
|
do_execsql_test 150 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=0;
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_execsql_test 200 {
|
||||||
|
CREATE TEMP TABLE saved_content(x);
|
||||||
|
INSERT INTO saved_content(x) SELECT data FROM sqlite_dbpage WHERE pgno=4;
|
||||||
|
UPDATE sqlite_dbpage SET data=zeroblob(4096) WHERE pgno=4;
|
||||||
|
} {}
|
||||||
|
do_catchsql_test 210 {
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
} {1 {database disk image is malformed}}
|
||||||
|
do_execsql_test 220 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('main') ORDER BY pgno;
|
||||||
|
} {1 X'53514C6974' 2 X'0500000001' 3 X'0D0000004E' 4 X'0000000000'}
|
||||||
|
do_execsql_test 230 {
|
||||||
|
UPDATE sqlite_dbpage SET data=(SELECT x FROM saved_content) WHERE pgno=4;
|
||||||
|
} {}
|
||||||
|
do_catchsql_test 230 {
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
} {0 ok}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
@ -394,6 +394,7 @@ foreach file {
|
|||||||
fts3_icu.c
|
fts3_icu.c
|
||||||
sqlite3rbu.c
|
sqlite3rbu.c
|
||||||
dbstat.c
|
dbstat.c
|
||||||
|
dbpage.c
|
||||||
sqlite3session.c
|
sqlite3session.c
|
||||||
json1.c
|
json1.c
|
||||||
fts5.c
|
fts5.c
|
||||||
|
Reference in New Issue
Block a user