mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Merge all the enhancements and bug fixes from trunk, since none are
destablizing. Call this the second beta. FossilOrigin-Name: fb3ee1b7cac09e4950e4f48b44c277e4f391cb6c8f069644732d2389ca653da4
This commit is contained in:
28
Makefile.in
28
Makefile.in
@ -166,7 +166,8 @@ USE_AMALGAMATION = @USE_AMALGAMATION@
|
||||
#
|
||||
LIBOBJS0 = alter.lo analyze.lo attach.lo auth.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 \
|
||||
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 \
|
||||
@ -215,6 +216,7 @@ SRC = \
|
||||
$(TOP)/src/complete.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/dbpage.c \
|
||||
$(TOP)/src/dbstat.c \
|
||||
$(TOP)/src/delete.c \
|
||||
$(TOP)/src/expr.c \
|
||||
@ -394,6 +396,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_intarray.c \
|
||||
$(TOP)/src/test_journal.c \
|
||||
$(TOP)/src/test_malloc.c \
|
||||
$(TOP)/src/test_md5.c \
|
||||
$(TOP)/src/test_multiplex.c \
|
||||
$(TOP)/src/test_mutex.c \
|
||||
$(TOP)/src/test_onefile.c \
|
||||
@ -405,6 +408,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_superlock.c \
|
||||
$(TOP)/src/test_syscall.c \
|
||||
$(TOP)/src/test_tclsh.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
@ -450,6 +454,7 @@ TESTSRC2 = \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/dbpage.c \
|
||||
$(TOP)/src/dbstat.c \
|
||||
$(TOP)/src/expr.c \
|
||||
$(TOP)/src/func.c \
|
||||
@ -570,6 +575,8 @@ SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4
|
||||
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
@ -753,6 +760,9 @@ ctime.lo: $(TOP)/src/ctime.c $(HDR)
|
||||
date.lo: $(TOP)/src/date.c $(HDR)
|
||||
$(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)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbstat.c
|
||||
|
||||
@ -937,7 +947,7 @@ tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
tclsqlite-shell.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DTCLSH=1 -o $@ -c $(TOP)/src/tclsqlite.c
|
||||
$(LTCOMPILE) -DTCLSH -o $@ -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
tclsqlite-stubs.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c
|
||||
@ -1103,12 +1113,14 @@ sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
|
||||
# necessary because the test fixture requires non-API symbols which are
|
||||
# hidden when the library is built via the amalgamation).
|
||||
#
|
||||
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DBUILD_sqlite
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
@ -1169,14 +1181,8 @@ valgrindtest: $(TESTPROGS) valgrindfuzz
|
||||
smoketest: $(TESTPROGS) fuzzcheck$(TEXE)
|
||||
./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)
|
||||
|
||||
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
|
||||
echo "#define TCLSH 2" > $@
|
||||
echo "#define SQLITE_ENABLE_DBSTAT_VTAB 1" >> $@
|
||||
cat sqlite3.c $(TOP)/src/tclsqlite.c >> $@
|
||||
echo "static const char *tclsh_main_loop(void){" >> $@
|
||||
echo "static const char *zMainloop = " >> $@
|
||||
$(TCLSH_CMD) $(TOP)/tool/tostr.tcl $(TOP)/tool/spaceanal.tcl >> $@
|
||||
echo "; return zMainloop; }" >> $@
|
||||
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
|
||||
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
|
||||
|
||||
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
|
||||
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
27
Makefile.msc
27
Makefile.msc
@ -1091,7 +1091,8 @@ LTLIBS = $(LTLIBS) $(LIBICU)
|
||||
#
|
||||
LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.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 \
|
||||
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 \
|
||||
@ -1154,6 +1155,7 @@ SRC00 = \
|
||||
$(TOP)\src\complete.c \
|
||||
$(TOP)\src\ctime.c \
|
||||
$(TOP)\src\date.c \
|
||||
$(TOP)\src\dbpage.c \
|
||||
$(TOP)\src\dbstat.c \
|
||||
$(TOP)\src\delete.c \
|
||||
$(TOP)\src\expr.c \
|
||||
@ -1372,6 +1374,7 @@ TESTSRC = \
|
||||
$(TOP)\src\test_intarray.c \
|
||||
$(TOP)\src\test_journal.c \
|
||||
$(TOP)\src\test_malloc.c \
|
||||
$(TOP)\src\test_md5.c \
|
||||
$(TOP)\src\test_multiplex.c \
|
||||
$(TOP)\src\test_mutex.c \
|
||||
$(TOP)\src\test_onefile.c \
|
||||
@ -1383,6 +1386,7 @@ TESTSRC = \
|
||||
$(TOP)\src\test_server.c \
|
||||
$(TOP)\src\test_superlock.c \
|
||||
$(TOP)\src\test_syscall.c \
|
||||
$(TOP)\src\test_tclsh.c \
|
||||
$(TOP)\src\test_tclvar.c \
|
||||
$(TOP)\src\test_thread.c \
|
||||
$(TOP)\src\test_vfs.c \
|
||||
@ -1505,6 +1509,7 @@ FUZZDATA = \
|
||||
#
|
||||
!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_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
@ -1742,7 +1747,10 @@ ctime.lo: $(TOP)\src\ctime.c $(HDR)
|
||||
date.lo: $(TOP)\src\date.c $(HDR)
|
||||
$(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
|
||||
|
||||
delete.lo: $(TOP)\src\delete.c $(HDR)
|
||||
@ -1926,7 +1934,7 @@ tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
|
||||
tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DTCLSH=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
|
||||
tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
@ -2097,12 +2105,13 @@ sqlite3rbu.lo: $(TOP)\ext\rbu\sqlite3rbu.c $(HDR) $(EXTHDR)
|
||||
# necessary because the test fixture requires non-API symbols which are
|
||||
# hidden when the library is built via the amalgamation).
|
||||
#
|
||||
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS = -DTCLSH_INIT_PROC=sqlite3TestInit -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE=""
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN)
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
|
||||
@ -2182,14 +2191,8 @@ smoketest: $(TESTPROGS)
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
|
||||
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(SQLITE_TCL_DEP)
|
||||
echo #define TCLSH 2 > $@
|
||||
echo #define SQLITE_ENABLE_DBSTAT_VTAB 1 >> $@
|
||||
copy $@ + $(SQLITE3C) + $(TOP)\src\tclsqlite.c $@
|
||||
echo static const char *tclsh_main_loop(void){ >> $@
|
||||
echo static const char *zMainloop = >> $@
|
||||
$(TCLSH_CMD) $(TOP)\tool\tostr.tcl $(TOP)\tool\spaceanal.tcl >> $@
|
||||
echo ; return zMainloop; } >> $@
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@
|
||||
|
||||
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
|
||||
|
@ -928,6 +928,7 @@ LIBRESOBJS =
|
||||
#
|
||||
!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_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
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);
|
||||
}
|
29
main.mk
29
main.mk
@ -55,7 +55,8 @@ THREADLIB += $(LIBS)
|
||||
LIBOBJ+= vdbe.o parse.o \
|
||||
alter.o analyze.o attach.o auth.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 \
|
||||
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 \
|
||||
@ -96,6 +97,7 @@ SRC = \
|
||||
$(TOP)/src/complete.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/dbpage.c \
|
||||
$(TOP)/src/dbstat.c \
|
||||
$(TOP)/src/delete.c \
|
||||
$(TOP)/src/expr.c \
|
||||
@ -306,6 +308,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_intarray.c \
|
||||
$(TOP)/src/test_journal.c \
|
||||
$(TOP)/src/test_malloc.c \
|
||||
$(TOP)/src/test_md5.c \
|
||||
$(TOP)/src/test_multiplex.c \
|
||||
$(TOP)/src/test_mutex.c \
|
||||
$(TOP)/src/test_onefile.c \
|
||||
@ -318,6 +321,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_sqllog.c \
|
||||
$(TOP)/src/test_superlock.c \
|
||||
$(TOP)/src/test_syscall.c \
|
||||
$(TOP)/src/test_tclsh.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
@ -360,6 +364,7 @@ TESTSRC2 = \
|
||||
$(TOP)/src/btree.c \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/dbpage.c \
|
||||
$(TOP)/src/dbstat.c \
|
||||
$(TOP)/src/expr.c \
|
||||
$(TOP)/src/func.c \
|
||||
@ -481,6 +486,8 @@ SHELL_OPT += -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
|
||||
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
@ -770,17 +777,11 @@ sqlite3rbu.o: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
|
||||
# Rules for building test programs and for running tests
|
||||
#
|
||||
tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH -o tclsqlite3 \
|
||||
$(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB)
|
||||
|
||||
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
|
||||
echo "#define TCLSH 2" > $@
|
||||
echo "#define SQLITE_ENABLE_DBSTAT_VTAB 1" >> $@
|
||||
cat sqlite3.c $(TOP)/src/tclsqlite.c >> $@
|
||||
echo "static const char *tclsh_main_loop(void){" >> $@
|
||||
echo "static const char *zMainloop = " >> $@
|
||||
tclsh $(TOP)/tool/tostr.tcl $(TOP)/tool/spaceanal.tcl >> $@
|
||||
echo "; return zMainloop; }" >> $@
|
||||
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/sqlite3_analyzer.c.in $(TOP)/tool/mkccode.tcl
|
||||
tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
|
||||
|
||||
sqlite3_analyzer$(EXE): sqlite3_analyzer.c
|
||||
$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB)
|
||||
@ -796,21 +797,23 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
|
||||
|
||||
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
|
||||
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
|
||||
$(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \
|
||||
-o testfixture$(EXE) $(LIBTCL) libsqlite3.a $(THREADLIB)
|
||||
|
||||
amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c \
|
||||
$(TOP)/ext/session/test_session.c
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
|
||||
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
|
||||
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \
|
||||
$(TOP)/ext/session/test_session.c \
|
||||
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
|
||||
|
||||
fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
|
||||
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
|
||||
-DSQLITE_ENABLE_FTS3=1 \
|
||||
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \
|
||||
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
|
||||
|
63
manifest
63
manifest
@ -1,8 +1,8 @@
|
||||
C Updates\sto\sthe\sMakefiles\sfor\sMSVC.\s\sCherrypick\sof\s[ac8786f3f9f35cb6].
|
||||
D 2017-10-14T19:58:37.221
|
||||
F Makefile.in 9c9f4dea3f622464cba9768501aceca187d2bbae10b60bf420b531cd776fe5c0
|
||||
C Merge\sall\sthe\senhancements\sand\sbug\sfixes\sfrom\strunk,\ssince\snone\sare\ndestablizing.\s\sCall\sthis\sthe\ssecond\sbeta.
|
||||
D 2017-10-21T17:17:17.187
|
||||
F Makefile.in e016061b23e60ac9ec27c65cb577292b6bde0307ca55abd874ab3487b3b1beb2
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 4a7ebdaacec1abd415d2847c8f5b42053c5963294e925672d43d2972a5bb2cb6
|
||||
F Makefile.msc 37740aba9c4bb359c627eadccf1cfd7be4f5f847078723777ea7763969e533b1
|
||||
F README.md f5c87359573c4d255425e588a56554b50fdcc2afba4e017a2e02a43701456afd
|
||||
F VERSION f81232df28e2d3ff049feefad5fbd5489cc33697f6bd2ecf61af7f0dde3b83d0
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@ -11,7 +11,7 @@ F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 1a47d071e3d5435f8f7ebff7eb6703848bbd65d4
|
||||
F autoconf/Makefile.msc b045158822d2320d5551cb7291ecc685dd6123324b928490691deed71274c305
|
||||
F autoconf/Makefile.msc 645b8a9774281515dc4a8de65d8a914f7b418ba8bd1c48b53ccbf43d3b339715
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 2893b823ecc86cea13739f6c8109a41392254d1db08235c5615e0af5722c8578
|
||||
@ -325,6 +325,8 @@ F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
|
||||
F ext/rbu/sqlite3rbu.c 64bd08c1011456f90564ed167abce3a9c2af421a924b21eb57231e078da04feb
|
||||
F ext/rbu/sqlite3rbu.h b42bcd4d8357268c6c39ab2a60b29c091e89328fa8cc49c8fac5ab8d007e79b2
|
||||
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/rtree.c f2fd34db37ea053798f8e66b44a473449b21301d2b92505ee576823789e909fb
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
@ -382,7 +384,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 3e671408634fb8e8eaa296e80627066a2524053db5a9c5c28c6ec06cf7e99a51
|
||||
F main.mk a39528d993afc1f0c0aebde2e3623ab4171d3bba484eea1e5241615c706c9ce8
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@ -401,14 +403,15 @@ F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 8565b061a6a6fad850230c73d6a7a8ffb88f3370e3352a8689a9a672160c5cc5
|
||||
F src/btree.c 75229a5a47985997f861b428552acd14fe42b657f755cba5e0b1a007bd77b2ea
|
||||
F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09
|
||||
F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc
|
||||
F src/build.c 6ffe76970aeee4bc94e60cf0138269e67109061a853e13098c38a904dd66e673
|
||||
F src/build.c e24b61144f9c9b15c4aa05954514190361061da721e56dcd1af6e0e945ee5909
|
||||
F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f308688
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
||||
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
||||
F src/dbpage.c c625a0bd605d4cea9a3258b8db49a5474a04976e95a9fe380cdaf74e8eb6736d
|
||||
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
||||
F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
|
||||
F src/expr.c 4d2d0aafd945424f638ee03e11330f03288ccf616e025498f3c8602d01609a0a
|
||||
@ -423,7 +426,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 1f33ef4ca0553b60fff03aa171370f8709a3e945acfcc68ccafc92752d872f40
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
|
||||
F src/main.c a4bdadaaa827e7380cba4de878ed7947dab5aeb84f617118ba6a0422cd745b4b
|
||||
F src/main.c 54637b9e7f91de6d281e577cd1a997762a4613f51a0509790027ca9865185d7c
|
||||
F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@ -456,18 +459,18 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/prepare.c 9a141a1b02dca53beaa9771699d390aafcac01f5d1f1c0ae6e23ded8dcdb709a
|
||||
F src/printf.c 40aee47ae9be4bd3dbdc8968bd07fddc027be8edec8daddf24d3391d36698a1c
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
|
||||
F src/resolve.c 5a461643f294ec510ca615b67256fc3861e4c8eff5f29e5940491e70553b1955
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 42aca61e739c405ddd8a1b702977a7743c7d52a94885f7c5596bd7e73e6bff18
|
||||
F src/shell.c.in 423944f4ad73a7e73d9c06e645e19ac1aa5f45c22069936e3a008b28a5df8003
|
||||
F src/select.c e6a068d9ea54417d625578086d3d482284af8d5a449bb3593d40c257080806a8
|
||||
F src/shell.c.in f13262c8778f0cd76bf8d9c01bbf5ef66842e6b14e1705cd60d86ab32a6ce69f
|
||||
F src/sqlite.h.in ab4f8a29d1580dfaeb6891fa1b83cff8229ba0daa56994707ceaca71495d9ab7
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h a1fd3aa82f967da436164e0728a7d6841651fd0c6e27b9044e0eb9f6c8462e47
|
||||
F src/sqliteInt.h c07bc88eca1f59ce73e1f486187d0df4effe67c4579e112dfdd91c159e5c0569
|
||||
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
|
||||
F src/sqliteInt.h 6f93fd6fde862410ac26b930f70752c38ad99ea78c3fc28356bac78049c53bd9
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 487951d81f9704800fd9f0ffdaa2f935a83ccb6be3575c2c4ef83e4789b4c828
|
||||
F src/tclsqlite.c 1833388c01e3b77f4c712185ee7250b9423ee0981ce6ae7e401e47db0319a696
|
||||
F src/test1.c 8ef15f7a357f85dfc41c6c748ce9c947b4f676e01bb5ae6a45bee4923dff8b51
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
|
||||
@ -496,6 +499,7 @@ F src/test_intarray.h f3b7672f5d1056eac563c0d6ea8480a660b1475c
|
||||
F src/test_journal.c 619f2aa10e0d7a5f87c0f06825bc61dfce1c6b9c7f3ad990fb13de6c3b8874a3
|
||||
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
|
||||
F src/test_malloc.c 4f06a805de86be5216a127b3777ca2d5a1ff99d1a9238374ce136a47411be36c
|
||||
F src/test_md5.c 7268e1e8c399d4a5e181b64ac20e1e6f3bc4dd9fc87abac02db145a3d951fa8c
|
||||
F src/test_multiplex.c e054459f7633f3ff8ce1245da724f9a8be189e4e
|
||||
F src/test_multiplex.h 5436d03f2d0501d04f3ed50a75819e190495b635
|
||||
F src/test_mutex.c 7f4337ba23ee6b1d2ec81c189653608cb069926a
|
||||
@ -510,6 +514,7 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
|
||||
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
|
||||
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
|
||||
F src/test_tclsh.c 74fcfb7f3b0ff1f871e62263dd84ffba46a8e9d477439115e0fb2035e4bf69e1
|
||||
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
|
||||
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
|
||||
F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
|
||||
@ -539,7 +544,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 839db09792fead5052bb35e533fa485e134913d547d05b5f42e537b73e63f07a
|
||||
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||
F src/walker.c 3ccfa8637f95355bff61144e01a615b8ef26f79c312880848da73f03367da1e6
|
||||
F src/where.c 049522adcf5426f1a8c3ed07be15e1ffa3266afd34e8e7bee64b63e2fbfad0b5
|
||||
F src/where.c d8c6d690c4b11f30211de073011fe19352364a6303ae053f45cb66f9576ba8a9
|
||||
F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
|
||||
F src/wherecode.c e8c2ece5843ea56e6c90277d421f2d628f3f7b7c976642369cc519f008e1d2b1
|
||||
F src/whereexpr.c afcac9cccfc0fdaccbdda94034a398947b6dc47dbf821c1b496261722832a6a4
|
||||
@ -563,7 +568,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
|
||||
F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f
|
||||
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
|
||||
F test/analyze8.test c05a461d0a6b05991106467d0c47480f2e709c82
|
||||
F test/analyze9.test b817b8e798315fc65b820a5463f73ad5f48ed8dd
|
||||
F test/analyze9.test dac0bdc7eab965b9ad639ca83564d98717aaf13ce5a776f23d9a3680238cecd8
|
||||
F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a
|
||||
F test/analyzeB.test a4c1c3048f6d9e090eb76e83eecb18bcf6d31a70
|
||||
F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
|
||||
@ -645,6 +650,7 @@ F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
|
||||
F test/check.test 33a698e8c63613449d85d624a38ef669bf20331daabebe3891c9405dd6df463a
|
||||
F test/checkfreelist.test 100283a3e6b8a3018c7fab7cfdaf03d1d6540fc66453114e248cf82b25784d3b
|
||||
F test/close.test 799ea4599d2f5704b0a30f477d17c2c760d8523fa5d0c8be4a7df2a8cad787d8
|
||||
F test/closure01.test b1703ba40639cfc9b295cf478d70739415eec6a4
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
@ -684,7 +690,7 @@ F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
|
||||
F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
|
||||
F test/corruptI.test 075fe1d75aa1d84e2949be56b6264376c41502e4
|
||||
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
|
||||
F test/corruptK.test 814a59ec699d8546b4e29005fba3d16e933ef2fe
|
||||
F test/corruptK.test 251ef631d095e882d455d2183961fa9ba879b4156e18e96c5d2b84aa7ef5f7a9
|
||||
F test/cost.test 1eedbfd868f806f3fa08ff072b04cf270dcf61c8
|
||||
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
|
||||
F test/coveridxscan.test b629e896b14df2f000a99b8d170d80589c46562c
|
||||
@ -707,6 +713,7 @@ F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbpage.test 9cf4dc92a4de67c81e5c32b24e3fbb8c4757e4b642694a219b3090a4f9277a4d
|
||||
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||
@ -1098,7 +1105,7 @@ F test/parser1.test 391b9bf9a229547a129c61ac345ed1a6f5eb1854
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test d911c9ba49088d22054a05dc73743f677872a92ac89288bcdeafa0ebf3f9c531
|
||||
F test/permutations.test 490e3333b9b1aefb7ebc6e9ab2ae0e382b7dd8713ccc4a2786b0f75467c2ab6b
|
||||
F test/pragma.test c31b5e98998c160a4c85b1e04f590655c67f2daa7f73854640cd120610e3ac15
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
@ -1150,7 +1157,7 @@ F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
|
||||
F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
|
||||
F test/savepoint7.test cde525ea3075283eb950cdcdefe23ead4f700daa
|
||||
F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2
|
||||
F test/scanstatus.test 5253c219e331318a437f436268e0e82345700285
|
||||
F test/scanstatus.test 1ba0e2ee25dcd1d55ec770803b19832cffaecbf0b15d376807759ebeed3669b0
|
||||
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
|
||||
@ -1586,6 +1593,7 @@ F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
|
||||
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
|
||||
F tool/mkkeywordhash.c 2e852ac0dfdc5af18886dc1ce7e9676d11714ae3df0a282dc7d90b3a0fe2033c
|
||||
F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66eefaa4
|
||||
@ -1597,7 +1605,7 @@ F tool/mkshellc.tcl 574307265b49d813301fba91ccd74e6a26d33f65f74b6891c320a0ffbee0
|
||||
F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
||||
F tool/mksqlite3c.tcl b258d679829a9305f5cf107b7d97b9bf23adb3773df42947fed5ef7b180dfbd9
|
||||
F tool/mksqlite3c.tcl 1fb69d39166f52d802a70ec37d99bca51d011c8ab30be27bc495be493196ae41
|
||||
F tool/mksqlite3h.tcl f92f994d9709aeb9e2b6e6f9fc8b069d2f55202c8e23f453edc44390a25982dc
|
||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
|
||||
@ -1622,13 +1630,13 @@ F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
|
||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
|
||||
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
||||
F tool/split-sqlite3c.tcl 3efcd4240b738f6bb2b5af0aea7e1e0ef9bc1c61654f645076cec883030b710c
|
||||
F tool/sqldiff.c 30879bbc8de686df4624e86adce2d8981f500904c1cfb55b5d1eea2ffd9341eb
|
||||
F tool/sqlite3_analyzer.c.in 771d15fb9c67645fd8ef932a438f98959da4b7c7da3cb87ae1850b27c969edf3
|
||||
F tool/srcck1.c 371de5363b70154012955544f86fdee8f6e5326f
|
||||
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
|
||||
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
|
||||
F tool/symbols.sh c5a617b8c61a0926747a56c65f5671ef8ac0e148
|
||||
F tool/tostr.tcl 96022f35ada2194f6f8ccf6fd95809e90ed277c4
|
||||
F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
|
||||
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
|
||||
F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
||||
@ -1656,8 +1664,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P de20133d44773f0b3b8869db5c1cb2a90f0426a54c7f40d12a930003343ad8e0
|
||||
Q +ac8786f3f9f35cb6fa72c65f5ca41cc6659f4702cd29ab0c9dcf04d3d1189090
|
||||
R 8e422c1ee06cd57625ef547ccd862b5a
|
||||
U mistachkin
|
||||
Z 0ed36b5b53069fc1c0ccb6054caf79bd
|
||||
P 92eb721faefcdd8396072722d3e4d7ca41b860b306e4bb0f0191dde8f30d0add 6ee8cb6ae5fd076ec226bb184b5690ba29f9df8cfaef47aaf13336873b4c1f6c
|
||||
R cbea5558ab489dc3dc438260e1496797
|
||||
U drh
|
||||
Z 9e651e977f775eeb3bfb6c192219eebf
|
||||
|
@ -1 +1 @@
|
||||
92eb721faefcdd8396072722d3e4d7ca41b860b306e4bb0f0191dde8f30d0add
|
||||
fb3ee1b7cac09e4950e4f48b44c277e4f391cb6c8f069644732d2389ca653da4
|
13
src/btree.c
13
src/btree.c
@ -4824,7 +4824,7 @@ static const void *fetchPayload(
|
||||
BtCursor *pCur, /* Cursor pointing to entry to read from */
|
||||
u32 *pAmt /* Write the number of available bytes here */
|
||||
){
|
||||
u32 amt;
|
||||
int amt;
|
||||
assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage);
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
@ -4833,9 +4833,14 @@ static const void *fetchPayload(
|
||||
assert( pCur->info.nSize>0 );
|
||||
assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB );
|
||||
assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);
|
||||
amt = (int)(pCur->pPage->aDataEnd - pCur->info.pPayload);
|
||||
if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
|
||||
*pAmt = amt;
|
||||
amt = pCur->info.nLocal;
|
||||
if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){
|
||||
/* There is too little space on the page for the expected amount
|
||||
** of local content. Database must be corrupt. */
|
||||
assert( CORRUPT_DB );
|
||||
amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload));
|
||||
}
|
||||
*pAmt = (u32)amt;
|
||||
return (void*)pCur->info.pPayload;
|
||||
}
|
||||
|
||||
|
@ -1063,12 +1063,10 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
Column *pCol;
|
||||
sqlite3 *db = pParse->db;
|
||||
if( (p = pParse->pNewTable)==0 ) return;
|
||||
#if SQLITE_MAX_COLUMN
|
||||
if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
||||
sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
|
||||
if( z==0 ) return;
|
||||
memcpy(z, pName->z, pName->n);
|
||||
|
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
|
||||
|
||||
#ifdef SQLITE_ENABLE_DBPAGE_VTAB
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3DbpageRegister(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3DbstatRegister(db);
|
||||
|
@ -959,12 +959,10 @@ static int resolveCompoundOrderBy(
|
||||
pOrderBy = pSelect->pOrderBy;
|
||||
if( pOrderBy==0 ) return 0;
|
||||
db = pParse->db;
|
||||
#if SQLITE_MAX_COLUMN
|
||||
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
pOrderBy->a[i].done = 0;
|
||||
}
|
||||
@ -1056,12 +1054,10 @@ int sqlite3ResolveOrderGroupBy(
|
||||
struct ExprList_item *pItem;
|
||||
|
||||
if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
|
||||
#if SQLITE_MAX_COLUMN
|
||||
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
pEList = pSelect->pEList;
|
||||
assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */
|
||||
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
||||
|
@ -1689,6 +1689,7 @@ int sqlite3ColumnsFromExprList(
|
||||
nCol = pEList->nExpr;
|
||||
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
|
||||
testcase( aCol==0 );
|
||||
if( nCol>32767 ) nCol = 32767;
|
||||
}else{
|
||||
nCol = 0;
|
||||
aCol = 0;
|
||||
@ -4596,12 +4597,10 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
sqlite3ExprListDelete(db, pEList);
|
||||
p->pEList = pNew;
|
||||
}
|
||||
#if SQLITE_MAX_COLUMN
|
||||
if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
||||
sqlite3ErrorMsg(pParse, "too many columns in result set");
|
||||
return WRC_Abort;
|
||||
}
|
||||
#endif
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
|
@ -3611,20 +3611,24 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
||||
{ "schema size:",
|
||||
"SELECT total(length(sql)) FROM %s" },
|
||||
};
|
||||
sqlite3_file *pFile = 0;
|
||||
int i;
|
||||
char *zSchemaTab;
|
||||
char *zDb = nArg>=2 ? azArg[1] : "main";
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
unsigned char aHdr[100];
|
||||
open_db(p, 0);
|
||||
if( p->db==0 ) return 1;
|
||||
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
|
||||
if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
|
||||
return 1;
|
||||
}
|
||||
i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
|
||||
if( i!=SQLITE_OK ){
|
||||
sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
|
||||
-1, &pStmt, 0);
|
||||
sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW
|
||||
&& sqlite3_column_bytes(pStmt,0)>100
|
||||
){
|
||||
memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
|
||||
sqlite3_finalize(pStmt);
|
||||
}else{
|
||||
raw_printf(stderr, "unable to read database header\n");
|
||||
sqlite3_finalize(pStmt);
|
||||
return 1;
|
||||
}
|
||||
i = get2byteInt(aHdr+16);
|
||||
@ -4244,7 +4248,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
utf8_printf(stderr,
|
||||
"testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
|
||||
p->zTestcase, azArg[1], zRes);
|
||||
rc = 2;
|
||||
rc = 1;
|
||||
}else{
|
||||
utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
|
||||
p->nCheck++;
|
||||
|
@ -134,7 +134,7 @@ struct sqlite3_api_routines {
|
||||
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||
const char*,const char*),void*);
|
||||
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||
char * (*snprintf)(int,char*,const char*,...);
|
||||
char * (*xsnprintf)(int,char*,const char*,...);
|
||||
int (*step)(sqlite3_stmt*);
|
||||
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||
char const**,char const**,int*,int*,int*);
|
||||
@ -418,7 +418,7 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||
#define sqlite3_snprintf sqlite3_api->snprintf
|
||||
#define sqlite3_snprintf sqlite3_api->xsnprintf
|
||||
#define sqlite3_step sqlite3_api->step
|
||||
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||
|
@ -4400,6 +4400,9 @@ int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
|
||||
int sqlite3ThreadJoin(SQLiteThread*, void**);
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
|
||||
int sqlite3DbpageRegister(sqlite3*);
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
|
||||
int sqlite3DbstatRegister(sqlite3*);
|
||||
#endif
|
||||
|
844
src/tclsqlite.c
844
src/tclsqlite.c
@ -14,17 +14,19 @@
|
||||
**
|
||||
** Compile-time options:
|
||||
**
|
||||
** -DTCLSH=1 Add a "main()" routine that works as a tclsh.
|
||||
** -DTCLSH Add a "main()" routine that works as a tclsh.
|
||||
**
|
||||
** -DSQLITE_TCLMD5 When used in conjuction with -DTCLSH=1, add
|
||||
** four new commands to the TCL interpreter for
|
||||
** generating MD5 checksums: md5, md5file,
|
||||
** md5-10x8, and md5file-10x8.
|
||||
** -DTCLSH_INIT_PROC=name
|
||||
**
|
||||
** -DSQLITE_TEST When used in conjuction with -DTCLSH=1, add
|
||||
** hundreds of new commands used for testing
|
||||
** SQLite. This option implies -DSQLITE_TCLMD5.
|
||||
** Invoke name(interp) to initialize the Tcl interpreter.
|
||||
** If name(interp) returns a non-NULL string, then run
|
||||
** that string as a Tcl script to launch the application.
|
||||
** If name(interp) returns NULL, then run the regular
|
||||
** tclsh-emulator code.
|
||||
*/
|
||||
#ifdef TCLSH_INIT_PROC
|
||||
# define TCLSH 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If requested, include the SQLite compiler options file for MSVC.
|
||||
@ -3286,7 +3288,42 @@ static int SQLITE_TCLAPI DbObjCmd(
|
||||
** Return the version string for this database.
|
||||
*/
|
||||
case DB_VERSION: {
|
||||
Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC);
|
||||
int i;
|
||||
for(i=2; i<objc; i++){
|
||||
const char *zArg = Tcl_GetString(objv[i]);
|
||||
/* Optional arguments to $db version are used for testing purpose */
|
||||
#ifdef SQLITE_TEST
|
||||
/* $db version -use-legacy-prepare BOOLEAN
|
||||
**
|
||||
** Turn the use of legacy sqlite3_prepare() on or off.
|
||||
*/
|
||||
if( strcmp(zArg, "-use-legacy-prepare")==0 && i+1<objc ){
|
||||
i++;
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[i], &pDb->bLegacyPrepare) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}else
|
||||
|
||||
/* $db version -last-stmt-ptr
|
||||
**
|
||||
** Return a string which is a hex encoding of the pointer to the
|
||||
** most recent sqlite3_stmt in the statement cache.
|
||||
*/
|
||||
if( strcmp(zArg, "-last-stmt-ptr")==0 ){
|
||||
char zBuf[100];
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "%p",
|
||||
pDb->stmtList ? pDb->stmtList->pStmt: 0);
|
||||
Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
|
||||
}else
|
||||
#endif /* SQLITE_TEST */
|
||||
{
|
||||
Tcl_AppendResult(interp, "unknown argument: ", zArg, (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
if( i==2 ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3546,721 +3583,56 @@ int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
#endif
|
||||
|
||||
#ifdef TCLSH
|
||||
/*****************************************************************************
|
||||
** All of the code that follows is used to build standalone TCL interpreters
|
||||
** that are statically linked with SQLite. Enable these by compiling
|
||||
** with -DTCLSH=n where n can be 1 or 2. An n of 1 generates a standard
|
||||
** tclsh but with SQLite built in. An n of 2 generates the SQLite space
|
||||
** analysis program.
|
||||
/*
|
||||
** If the TCLSH macro is defined, add code to make a stand-alone program.
|
||||
*/
|
||||
#if defined(TCLSH)
|
||||
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5)
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If compiled on a machine that doesn't have a 32-bit integer,
|
||||
* you just set "uint32" to the appropriate datatype for an
|
||||
* unsigned 32-bit integer. For example:
|
||||
*
|
||||
* cc -Duint32='unsigned long' md5.c
|
||||
*
|
||||
*/
|
||||
#ifndef uint32
|
||||
# define uint32 unsigned int
|
||||
#endif
|
||||
|
||||
struct MD5Context {
|
||||
int isInit;
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
typedef struct MD5Context MD5Context;
|
||||
|
||||
/*
|
||||
* Note: this code is harmless on little-endian machines.
|
||||
*/
|
||||
static void byteReverse (unsigned char *buf, unsigned longs){
|
||||
uint32 t;
|
||||
do {
|
||||
t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
|
||||
((unsigned)buf[1]<<8 | buf[0]);
|
||||
*(uint32 *)buf = t;
|
||||
buf += 4;
|
||||
} while (--longs);
|
||||
}
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
static void MD5Transform(uint32 buf[4], const uint32 in[16]){
|
||||
register uint32 a, b, c, d;
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
static void MD5Init(MD5Context *ctx){
|
||||
ctx->isInit = 1;
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
static
|
||||
void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
||||
uint32 t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if ( t ) {
|
||||
unsigned char *p = (unsigned char *)ctx->in + t;
|
||||
|
||||
t = 64-t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
static void MD5Final(unsigned char digest[16], MD5Context *ctx){
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count-8);
|
||||
}
|
||||
byteReverse(ctx->in, 14);
|
||||
|
||||
/* Append length in bits and transform */
|
||||
memcpy(ctx->in + 14*4, ctx->bits, 8);
|
||||
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
byteReverse((unsigned char *)ctx->buf, 4);
|
||||
memcpy(digest, ctx->buf, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
|
||||
/* This is the main routine for an ordinary TCL shell. If there are
|
||||
** are arguments, run the first argument as a script. Otherwise,
|
||||
** read TCL commands from standard input
|
||||
*/
|
||||
static void MD5DigestToBase16(unsigned char *digest, char *zBuf){
|
||||
static char const zEncode[] = "0123456789abcdef";
|
||||
int i, j;
|
||||
|
||||
for(j=i=0; i<16; i++){
|
||||
int a = digest[i];
|
||||
zBuf[j++] = zEncode[(a>>4)&0xf];
|
||||
zBuf[j++] = zEncode[a & 0xf];
|
||||
}
|
||||
zBuf[j] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
|
||||
** each representing 16 bits of the digest and separated from each
|
||||
** other by a "-" character.
|
||||
*/
|
||||
static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
|
||||
int i, j;
|
||||
unsigned int x;
|
||||
for(i=j=0; i<16; i+=2){
|
||||
x = digest[i]*256 + digest[i+1];
|
||||
if( i>0 ) zDigest[j++] = '-';
|
||||
sqlite3_snprintf(50-j, &zDigest[j], "%05u", x);
|
||||
j += 5;
|
||||
}
|
||||
zDigest[j] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** A TCL command for md5. The argument is the text to be hashed. The
|
||||
** Result is the hash in base64.
|
||||
*/
|
||||
static int SQLITE_TCLAPI md5_cmd(
|
||||
void*cd,
|
||||
Tcl_Interp *interp,
|
||||
int argc,
|
||||
const char **argv
|
||||
){
|
||||
MD5Context ctx;
|
||||
unsigned char digest[16];
|
||||
char zBuf[50];
|
||||
void (*converter)(unsigned char*, char*);
|
||||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" TEXT\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
|
||||
MD5Final(digest, &ctx);
|
||||
converter = (void(*)(unsigned char*,char*))cd;
|
||||
converter(digest, zBuf);
|
||||
Tcl_AppendResult(interp, zBuf, (char*)0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** A TCL command to take the md5 hash of a file. The argument is the
|
||||
** name of the file.
|
||||
*/
|
||||
static int SQLITE_TCLAPI md5file_cmd(
|
||||
void*cd,
|
||||
Tcl_Interp *interp,
|
||||
int argc,
|
||||
const char **argv
|
||||
){
|
||||
FILE *in;
|
||||
int ofst;
|
||||
int amt;
|
||||
MD5Context ctx;
|
||||
void (*converter)(unsigned char*, char*);
|
||||
unsigned char digest[16];
|
||||
char zBuf[10240];
|
||||
|
||||
if( argc!=2 && argc!=4 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" FILENAME [OFFSET AMT]\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( argc==4 ){
|
||||
ofst = atoi(argv[2]);
|
||||
amt = atoi(argv[3]);
|
||||
}else{
|
||||
ofst = 0;
|
||||
amt = 2147483647;
|
||||
}
|
||||
in = fopen(argv[1],"rb");
|
||||
if( in==0 ){
|
||||
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||
"\" for reading", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
fseek(in, ofst, SEEK_SET);
|
||||
MD5Init(&ctx);
|
||||
while( amt>0 ){
|
||||
int n;
|
||||
n = (int)fread(zBuf, 1, sizeof(zBuf)<=amt ? sizeof(zBuf) : amt, in);
|
||||
if( n<=0 ) break;
|
||||
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
|
||||
amt -= n;
|
||||
}
|
||||
fclose(in);
|
||||
MD5Final(digest, &ctx);
|
||||
converter = (void(*)(unsigned char*,char*))cd;
|
||||
converter(digest, zBuf);
|
||||
Tcl_AppendResult(interp, zBuf, (char*)0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register the four new TCL commands for generating MD5 checksums
|
||||
** with the TCL interpreter.
|
||||
*/
|
||||
int Md5_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd,
|
||||
MD5DigestToBase16, 0);
|
||||
Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc*)md5_cmd,
|
||||
MD5DigestToBase10x8, 0);
|
||||
Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd,
|
||||
MD5DigestToBase16, 0);
|
||||
Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc*)md5file_cmd,
|
||||
MD5DigestToBase10x8, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) */
|
||||
|
||||
#if defined(SQLITE_TEST)
|
||||
/*
|
||||
** During testing, the special md5sum() aggregate function is available.
|
||||
** inside SQLite. The following routines implement that function.
|
||||
*/
|
||||
static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
MD5Context *p;
|
||||
int i;
|
||||
if( argc<1 ) return;
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p==0 ) return;
|
||||
if( !p->isInit ){
|
||||
MD5Init(p);
|
||||
}
|
||||
for(i=0; i<argc; i++){
|
||||
const char *zData = (char*)sqlite3_value_text(argv[i]);
|
||||
if( zData ){
|
||||
MD5Update(p, (unsigned char*)zData, (int)strlen(zData));
|
||||
}
|
||||
}
|
||||
}
|
||||
static void md5finalize(sqlite3_context *context){
|
||||
MD5Context *p;
|
||||
unsigned char digest[16];
|
||||
char zBuf[33];
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
MD5Final(digest,p);
|
||||
MD5DigestToBase16(digest, zBuf);
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
int Md5_Register(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pThunk
|
||||
){
|
||||
int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
|
||||
md5step, md5finalize);
|
||||
sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
|
||||
return rc;
|
||||
}
|
||||
#endif /* defined(SQLITE_TEST) */
|
||||
|
||||
|
||||
/*
|
||||
** If the macro TCLSH is one, then put in code this for the
|
||||
** "main" routine that will initialize Tcl and take input from
|
||||
** standard input, or if a file is named on the command line
|
||||
** the TCL interpreter reads and evaluates that file.
|
||||
*/
|
||||
#if TCLSH==1
|
||||
static const char *tclsh_main_loop(void){
|
||||
static const char zMainloop[] =
|
||||
"set line {}\n"
|
||||
"while {![eof stdin]} {\n"
|
||||
"if {$line!=\"\"} {\n"
|
||||
"puts -nonewline \"> \"\n"
|
||||
"} else {\n"
|
||||
"puts -nonewline \"% \"\n"
|
||||
"}\n"
|
||||
"flush stdout\n"
|
||||
"append line [gets stdin]\n"
|
||||
"if {[info complete $line]} {\n"
|
||||
"if {[catch {uplevel #0 $line} result]} {\n"
|
||||
"puts stderr \"Error: $result\"\n"
|
||||
"} elseif {$result!=\"\"} {\n"
|
||||
"puts $result\n"
|
||||
"if {[llength $argv]>=1} {\n"
|
||||
"set argv0 [lindex $argv 0]\n"
|
||||
"set argv [lrange $argv 1 end]\n"
|
||||
"source $argv0\n"
|
||||
"} else {\n"
|
||||
"set line {}\n"
|
||||
"while {![eof stdin]} {\n"
|
||||
"if {$line!=\"\"} {\n"
|
||||
"puts -nonewline \"> \"\n"
|
||||
"} else {\n"
|
||||
"puts -nonewline \"% \"\n"
|
||||
"}\n"
|
||||
"flush stdout\n"
|
||||
"append line [gets stdin]\n"
|
||||
"if {[info complete $line]} {\n"
|
||||
"if {[catch {uplevel #0 $line} result]} {\n"
|
||||
"puts stderr \"Error: $result\"\n"
|
||||
"} elseif {$result!=\"\"} {\n"
|
||||
"puts $result\n"
|
||||
"}\n"
|
||||
"set line {}\n"
|
||||
"} else {\n"
|
||||
"append line \\n\n"
|
||||
"}\n"
|
||||
"set line {}\n"
|
||||
"} else {\n"
|
||||
"append line \\n\n"
|
||||
"}\n"
|
||||
"}\n"
|
||||
;
|
||||
return zMainloop;
|
||||
}
|
||||
#endif
|
||||
#if TCLSH==2
|
||||
static const char *tclsh_main_loop(void);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
static void init_all(Tcl_Interp *);
|
||||
static int SQLITE_TCLAPI init_all_cmd(
|
||||
ClientData cd,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
|
||||
Tcl_Interp *slave;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SLAVE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
slave = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
|
||||
if( !slave ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
init_all(slave);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Tclcmd: db_use_legacy_prepare DB BOOLEAN
|
||||
**
|
||||
** The first argument to this command must be a database command created by
|
||||
** [sqlite3]. If the second argument is true, then the handle is configured
|
||||
** to use the sqlite3_prepare_v2() function to prepare statements. If it
|
||||
** is false, sqlite3_prepare().
|
||||
*/
|
||||
static int SQLITE_TCLAPI db_use_legacy_prepare_cmd(
|
||||
ClientData cd,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
SqliteDb *pDb;
|
||||
int bPrepare;
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
|
||||
Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pDb = (SqliteDb*)cmdInfo.objClientData;
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[2], &bPrepare) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
pDb->bLegacyPrepare = bPrepare;
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Tclcmd: db_last_stmt_ptr DB
|
||||
**
|
||||
** If the statement cache associated with database DB is not empty,
|
||||
** return the text representation of the most recently used statement
|
||||
** handle.
|
||||
*/
|
||||
static int SQLITE_TCLAPI db_last_stmt_ptr(
|
||||
ClientData cd,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*);
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
SqliteDb *pDb;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char zBuf[100];
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
|
||||
Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pDb = (SqliteDb*)cmdInfo.objClientData;
|
||||
|
||||
if( pDb->stmtList ) pStmt = pDb->stmtList->pStmt;
|
||||
if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
/*
|
||||
** Configure the interpreter passed as the first argument to have access
|
||||
** to the commands and linked variables that make up:
|
||||
**
|
||||
** * the [sqlite3] extension itself,
|
||||
**
|
||||
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
|
||||
**
|
||||
** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
|
||||
** test suite.
|
||||
*/
|
||||
static void init_all(Tcl_Interp *interp){
|
||||
Sqlite3_Init(interp);
|
||||
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5)
|
||||
Md5_Init(interp);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
{
|
||||
extern int Sqliteconfig_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest1_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest2_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest3_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest4_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest5_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest6_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest7_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest8_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest9_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestasync_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_blob_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
|
||||
extern int Sqlitetest_func_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_hexio_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_init_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_malloc_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_mutex_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestschema_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestsse_Init(Tcl_Interp*);
|
||||
extern int Sqlitetesttclvar_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestfs_Init(Tcl_Interp*);
|
||||
extern int SqlitetestThread_Init(Tcl_Interp*);
|
||||
extern int SqlitetestOnefile_Init();
|
||||
extern int SqlitetestOsinst_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestbackup_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestintarray_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestvfs_Init(Tcl_Interp *);
|
||||
extern int Sqlitetestrtree_Init(Tcl_Interp*);
|
||||
extern int Sqlitequota_Init(Tcl_Interp*);
|
||||
extern int Sqlitemultiplex_Init(Tcl_Interp*);
|
||||
extern int SqliteSuperlock_Init(Tcl_Interp*);
|
||||
extern int SqlitetestSyscall_Init(Tcl_Interp*);
|
||||
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
||||
extern int TestSession_Init(Tcl_Interp*);
|
||||
#endif
|
||||
extern int Fts5tcl_Init(Tcl_Interp *);
|
||||
extern int SqliteRbu_Init(Tcl_Interp*);
|
||||
extern int Sqlitetesttcl_Init(Tcl_Interp*);
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
extern int Zipvfs_Init(Tcl_Interp*);
|
||||
Zipvfs_Init(interp);
|
||||
#endif
|
||||
|
||||
Sqliteconfig_Init(interp);
|
||||
Sqlitetest1_Init(interp);
|
||||
Sqlitetest2_Init(interp);
|
||||
Sqlitetest3_Init(interp);
|
||||
Sqlitetest4_Init(interp);
|
||||
Sqlitetest5_Init(interp);
|
||||
Sqlitetest6_Init(interp);
|
||||
Sqlitetest7_Init(interp);
|
||||
Sqlitetest8_Init(interp);
|
||||
Sqlitetest9_Init(interp);
|
||||
Sqlitetestasync_Init(interp);
|
||||
Sqlitetest_autoext_Init(interp);
|
||||
Sqlitetest_blob_Init(interp);
|
||||
Sqlitetest_demovfs_Init(interp);
|
||||
Sqlitetest_func_Init(interp);
|
||||
Sqlitetest_hexio_Init(interp);
|
||||
Sqlitetest_init_Init(interp);
|
||||
Sqlitetest_malloc_Init(interp);
|
||||
Sqlitetest_mutex_Init(interp);
|
||||
Sqlitetestschema_Init(interp);
|
||||
Sqlitetesttclvar_Init(interp);
|
||||
Sqlitetestfs_Init(interp);
|
||||
SqlitetestThread_Init(interp);
|
||||
SqlitetestOnefile_Init();
|
||||
SqlitetestOsinst_Init(interp);
|
||||
Sqlitetestbackup_Init(interp);
|
||||
Sqlitetestintarray_Init(interp);
|
||||
Sqlitetestvfs_Init(interp);
|
||||
Sqlitetestrtree_Init(interp);
|
||||
Sqlitequota_Init(interp);
|
||||
Sqlitemultiplex_Init(interp);
|
||||
SqliteSuperlock_Init(interp);
|
||||
SqlitetestSyscall_Init(interp);
|
||||
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
||||
TestSession_Init(interp);
|
||||
#endif
|
||||
Fts5tcl_Init(interp);
|
||||
SqliteRbu_Init(interp);
|
||||
Sqlitetesttcl_Init(interp);
|
||||
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
Sqlitetestfts3_Init(interp);
|
||||
#endif
|
||||
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "load_testfixture_extensions", init_all_cmd, 0, 0
|
||||
);
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0
|
||||
);
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "db_last_stmt_ptr", db_last_stmt_ptr, 0, 0
|
||||
);
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
Sqlitetestsse_Init(interp);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Needed for the setrlimit() system call on unix */
|
||||
#if defined(unix)
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#define TCLSH_MAIN main /* Needed to fake out mktclapp */
|
||||
int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){
|
||||
Tcl_Interp *interp;
|
||||
int i;
|
||||
const char *zScript = 0;
|
||||
char zArgc[32];
|
||||
#if defined(TCLSH_INIT_PROC)
|
||||
extern const char *TCLSH_INIT_PROC(Tcl_Interp*);
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32_WCE)
|
||||
if( getenv("BREAK") ){
|
||||
@ -4271,17 +3643,6 @@ int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Since the primary use case for this binary is testing of SQLite,
|
||||
** be sure to generate core files if we crash */
|
||||
#if defined(SQLITE_TEST) && defined(unix)
|
||||
{ struct rlimit x;
|
||||
getrlimit(RLIMIT_CORE, &x);
|
||||
x.rlim_cur = x.rlim_max;
|
||||
setrlimit(RLIMIT_CORE, &x);
|
||||
}
|
||||
#endif /* SQLITE_TEST && unix */
|
||||
|
||||
|
||||
/* Call sqlite3_shutdown() once before doing anything else. This is to
|
||||
** test that sqlite3_shutdown() can be safely called by a process before
|
||||
** sqlite3_initialize() is. */
|
||||
@ -4290,32 +3651,27 @@ int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){
|
||||
Tcl_FindExecutable(argv[0]);
|
||||
Tcl_SetSystemEncoding(NULL, "utf-8");
|
||||
interp = Tcl_CreateInterp();
|
||||
Sqlite3_Init(interp);
|
||||
|
||||
#if TCLSH==2
|
||||
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
|
||||
#endif
|
||||
|
||||
init_all(interp);
|
||||
if( argc>=2 ){
|
||||
int i;
|
||||
char zArgc[32];
|
||||
sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
|
||||
Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
|
||||
for(i=3-TCLSH; i<argc; i++){
|
||||
Tcl_SetVar(interp, "argv", argv[i],
|
||||
TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
|
||||
}
|
||||
if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
|
||||
const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
|
||||
if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp);
|
||||
fprintf(stderr,"%s: %s\n", *argv, zInfo);
|
||||
return 1;
|
||||
}
|
||||
sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-1);
|
||||
Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar(interp,"argv0",argv[0],TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
|
||||
for(i=1; i<argc; i++){
|
||||
Tcl_SetVar(interp, "argv", argv[i],
|
||||
TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
|
||||
}
|
||||
if( TCLSH==2 || argc<=1 ){
|
||||
Tcl_GlobalEval(interp, tclsh_main_loop());
|
||||
#if defined(TCLSH_INIT_PROC)
|
||||
zScript = TCLSH_INIT_PROC(interp);
|
||||
#endif
|
||||
if( zScript==0 ){
|
||||
zScript = tclsh_main_loop();
|
||||
}
|
||||
if( Tcl_GlobalEval(interp, zScript)!=TCL_OK ){
|
||||
const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
|
||||
if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp);
|
||||
fprintf(stderr,"%s: %s\n", *argv, zInfo);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
450
src/test_md5.c
Normal file
450
src/test_md5.c
Normal file
@ -0,0 +1,450 @@
|
||||
/*
|
||||
** 2017-10-13
|
||||
**
|
||||
** 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 code to implement an MD5 extension to TCL.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sqlite3.h"
|
||||
#if defined(INCLUDE_SQLITE_TCL_H)
|
||||
# include "sqlite_tcl.h"
|
||||
#else
|
||||
# include "tcl.h"
|
||||
# ifndef SQLITE_TCLAPI
|
||||
# define SQLITE_TCLAPI
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If compiled on a machine that doesn't have a 32-bit integer,
|
||||
* you just set "uint32" to the appropriate datatype for an
|
||||
* unsigned 32-bit integer. For example:
|
||||
*
|
||||
* cc -Duint32='unsigned long' md5.c
|
||||
*
|
||||
*/
|
||||
#ifndef uint32
|
||||
# define uint32 unsigned int
|
||||
#endif
|
||||
|
||||
struct MD5Context {
|
||||
int isInit;
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
typedef struct MD5Context MD5Context;
|
||||
|
||||
/*
|
||||
* Note: this code is harmless on little-endian machines.
|
||||
*/
|
||||
static void byteReverse (unsigned char *buf, unsigned longs){
|
||||
uint32 t;
|
||||
do {
|
||||
t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
|
||||
((unsigned)buf[1]<<8 | buf[0]);
|
||||
*(uint32 *)buf = t;
|
||||
buf += 4;
|
||||
} while (--longs);
|
||||
}
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
static void MD5Transform(uint32 buf[4], const uint32 in[16]){
|
||||
register uint32 a, b, c, d;
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
static void MD5Init(MD5Context *ctx){
|
||||
ctx->isInit = 1;
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
static
|
||||
void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
||||
uint32 t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if ( t ) {
|
||||
unsigned char *p = (unsigned char *)ctx->in + t;
|
||||
|
||||
t = 64-t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
static void MD5Final(unsigned char digest[16], MD5Context *ctx){
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count-8);
|
||||
}
|
||||
byteReverse(ctx->in, 14);
|
||||
|
||||
/* Append length in bits and transform */
|
||||
memcpy(ctx->in + 14*4, ctx->bits, 8);
|
||||
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
byteReverse((unsigned char *)ctx->buf, 4);
|
||||
memcpy(digest, ctx->buf, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
|
||||
*/
|
||||
static void MD5DigestToBase16(unsigned char *digest, char *zBuf){
|
||||
static char const zEncode[] = "0123456789abcdef";
|
||||
int i, j;
|
||||
|
||||
for(j=i=0; i<16; i++){
|
||||
int a = digest[i];
|
||||
zBuf[j++] = zEncode[(a>>4)&0xf];
|
||||
zBuf[j++] = zEncode[a & 0xf];
|
||||
}
|
||||
zBuf[j] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
|
||||
** each representing 16 bits of the digest and separated from each
|
||||
** other by a "-" character.
|
||||
*/
|
||||
static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
|
||||
int i, j;
|
||||
unsigned int x;
|
||||
for(i=j=0; i<16; i+=2){
|
||||
x = digest[i]*256 + digest[i+1];
|
||||
if( i>0 ) zDigest[j++] = '-';
|
||||
sqlite3_snprintf(50-j, &zDigest[j], "%05u", x);
|
||||
j += 5;
|
||||
}
|
||||
zDigest[j] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** A TCL command for md5. The argument is the text to be hashed. The
|
||||
** Result is the hash in base64.
|
||||
*/
|
||||
static int SQLITE_TCLAPI md5_cmd(
|
||||
void*cd,
|
||||
Tcl_Interp *interp,
|
||||
int argc,
|
||||
const char **argv
|
||||
){
|
||||
MD5Context ctx;
|
||||
unsigned char digest[16];
|
||||
char zBuf[50];
|
||||
void (*converter)(unsigned char*, char*);
|
||||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" TEXT\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
|
||||
MD5Final(digest, &ctx);
|
||||
converter = (void(*)(unsigned char*,char*))cd;
|
||||
converter(digest, zBuf);
|
||||
Tcl_AppendResult(interp, zBuf, (char*)0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** A TCL command to take the md5 hash of a file. The argument is the
|
||||
** name of the file.
|
||||
*/
|
||||
static int SQLITE_TCLAPI md5file_cmd(
|
||||
void*cd,
|
||||
Tcl_Interp *interp,
|
||||
int argc,
|
||||
const char **argv
|
||||
){
|
||||
FILE *in;
|
||||
int ofst;
|
||||
int amt;
|
||||
MD5Context ctx;
|
||||
void (*converter)(unsigned char*, char*);
|
||||
unsigned char digest[16];
|
||||
char zBuf[10240];
|
||||
|
||||
if( argc!=2 && argc!=4 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" FILENAME [OFFSET AMT]\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( argc==4 ){
|
||||
ofst = atoi(argv[2]);
|
||||
amt = atoi(argv[3]);
|
||||
}else{
|
||||
ofst = 0;
|
||||
amt = 2147483647;
|
||||
}
|
||||
in = fopen(argv[1],"rb");
|
||||
if( in==0 ){
|
||||
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||
"\" for reading", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
fseek(in, ofst, SEEK_SET);
|
||||
MD5Init(&ctx);
|
||||
while( amt>0 ){
|
||||
int n;
|
||||
n = (int)fread(zBuf, 1, sizeof(zBuf)<=amt ? sizeof(zBuf) : amt, in);
|
||||
if( n<=0 ) break;
|
||||
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
|
||||
amt -= n;
|
||||
}
|
||||
fclose(in);
|
||||
MD5Final(digest, &ctx);
|
||||
converter = (void(*)(unsigned char*,char*))cd;
|
||||
converter(digest, zBuf);
|
||||
Tcl_AppendResult(interp, zBuf, (char*)0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register the four new TCL commands for generating MD5 checksums
|
||||
** with the TCL interpreter.
|
||||
*/
|
||||
int Md5_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd,
|
||||
MD5DigestToBase16, 0);
|
||||
Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc*)md5_cmd,
|
||||
MD5DigestToBase10x8, 0);
|
||||
Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd,
|
||||
MD5DigestToBase16, 0);
|
||||
Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc*)md5file_cmd,
|
||||
MD5DigestToBase10x8, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** During testing, the special md5sum() aggregate function is available.
|
||||
** inside SQLite. The following routines implement that function.
|
||||
*/
|
||||
static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
MD5Context *p;
|
||||
int i;
|
||||
if( argc<1 ) return;
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p==0 ) return;
|
||||
if( !p->isInit ){
|
||||
MD5Init(p);
|
||||
}
|
||||
for(i=0; i<argc; i++){
|
||||
const char *zData = (char*)sqlite3_value_text(argv[i]);
|
||||
if( zData ){
|
||||
MD5Update(p, (unsigned char*)zData, (int)strlen(zData));
|
||||
}
|
||||
}
|
||||
}
|
||||
static void md5finalize(sqlite3_context *context){
|
||||
MD5Context *p;
|
||||
unsigned char digest[16];
|
||||
char zBuf[33];
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
MD5Final(digest,p);
|
||||
MD5DigestToBase16(digest, zBuf);
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
int Md5_Register(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pThunk
|
||||
){
|
||||
int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
|
||||
md5step, md5finalize);
|
||||
sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
|
||||
return rc;
|
||||
}
|
198
src/test_tclsh.c
Normal file
198
src/test_tclsh.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
** 2017-10-13
|
||||
**
|
||||
** 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 extensions to the the "tclsqlite.c" module used for
|
||||
** testing. Basically, all of the other "test_*.c" modules are linked
|
||||
** into the enhanced tclsh used for testing (and named "testfixture" or
|
||||
** "testfixture.exe") using logic encoded by this file.
|
||||
**
|
||||
** The code in this file used to be found in tclsqlite3.c, contained within
|
||||
** #if SQLITE_TEST ... #endif. It is factored out into this separate module
|
||||
** in an effort to keep the tclsqlite.c file pure.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#if defined(INCLUDE_SQLITE_TCL_H)
|
||||
# include "sqlite_tcl.h"
|
||||
#else
|
||||
# include "tcl.h"
|
||||
# ifndef SQLITE_TCLAPI
|
||||
# define SQLITE_TCLAPI
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Needed for the setrlimit() system call on unix */
|
||||
#if defined(unix)
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
/* Forward declaration */
|
||||
static int SQLITE_TCLAPI load_testfixture_extensions(
|
||||
ClientData cd,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
);
|
||||
|
||||
/*
|
||||
** This routine is the primary export of this file.
|
||||
**
|
||||
** Configure the interpreter passed as the first argument to have access
|
||||
** to the commands and linked variables that make up:
|
||||
**
|
||||
** * the [sqlite3] extension itself,
|
||||
**
|
||||
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
|
||||
**
|
||||
** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
|
||||
** test suite.
|
||||
*/
|
||||
const char *sqlite3TestInit(Tcl_Interp *interp){
|
||||
extern int Sqlite3_Init(Tcl_Interp*);
|
||||
extern int Sqliteconfig_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest1_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest2_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest3_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest4_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest5_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest6_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest7_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest8_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest9_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestasync_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_blob_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
|
||||
extern int Sqlitetest_func_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_hexio_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_init_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_malloc_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_mutex_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestschema_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestsse_Init(Tcl_Interp*);
|
||||
extern int Sqlitetesttclvar_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestfs_Init(Tcl_Interp*);
|
||||
extern int SqlitetestThread_Init(Tcl_Interp*);
|
||||
extern int SqlitetestOnefile_Init();
|
||||
extern int SqlitetestOsinst_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestbackup_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestintarray_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestvfs_Init(Tcl_Interp *);
|
||||
extern int Sqlitetestrtree_Init(Tcl_Interp*);
|
||||
extern int Sqlitequota_Init(Tcl_Interp*);
|
||||
extern int Sqlitemultiplex_Init(Tcl_Interp*);
|
||||
extern int SqliteSuperlock_Init(Tcl_Interp*);
|
||||
extern int SqlitetestSyscall_Init(Tcl_Interp*);
|
||||
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
||||
extern int TestSession_Init(Tcl_Interp*);
|
||||
#endif
|
||||
extern int Md5_Init(Tcl_Interp*);
|
||||
extern int Fts5tcl_Init(Tcl_Interp *);
|
||||
extern int SqliteRbu_Init(Tcl_Interp*);
|
||||
extern int Sqlitetesttcl_Init(Tcl_Interp*);
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
extern int Zipvfs_Init(Tcl_Interp*);
|
||||
#endif
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
|
||||
/* Since the primary use case for this binary is testing of SQLite,
|
||||
** be sure to generate core files if we crash */
|
||||
#if defined(unix)
|
||||
{ struct rlimit x;
|
||||
getrlimit(RLIMIT_CORE, &x);
|
||||
x.rlim_cur = x.rlim_max;
|
||||
setrlimit(RLIMIT_CORE, &x);
|
||||
}
|
||||
#endif /* unix */
|
||||
|
||||
if( Tcl_GetCommandInfo(interp, "sqlite3", &cmdInfo)==0 ){
|
||||
Sqlite3_Init(interp);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
Zipvfs_Init(interp);
|
||||
#endif
|
||||
Md5_Init(interp);
|
||||
Sqliteconfig_Init(interp);
|
||||
Sqlitetest1_Init(interp);
|
||||
Sqlitetest2_Init(interp);
|
||||
Sqlitetest3_Init(interp);
|
||||
Sqlitetest4_Init(interp);
|
||||
Sqlitetest5_Init(interp);
|
||||
Sqlitetest6_Init(interp);
|
||||
Sqlitetest7_Init(interp);
|
||||
Sqlitetest8_Init(interp);
|
||||
Sqlitetest9_Init(interp);
|
||||
Sqlitetestasync_Init(interp);
|
||||
Sqlitetest_autoext_Init(interp);
|
||||
Sqlitetest_blob_Init(interp);
|
||||
Sqlitetest_demovfs_Init(interp);
|
||||
Sqlitetest_func_Init(interp);
|
||||
Sqlitetest_hexio_Init(interp);
|
||||
Sqlitetest_init_Init(interp);
|
||||
Sqlitetest_malloc_Init(interp);
|
||||
Sqlitetest_mutex_Init(interp);
|
||||
Sqlitetestschema_Init(interp);
|
||||
Sqlitetesttclvar_Init(interp);
|
||||
Sqlitetestfs_Init(interp);
|
||||
SqlitetestThread_Init(interp);
|
||||
SqlitetestOnefile_Init();
|
||||
SqlitetestOsinst_Init(interp);
|
||||
Sqlitetestbackup_Init(interp);
|
||||
Sqlitetestintarray_Init(interp);
|
||||
Sqlitetestvfs_Init(interp);
|
||||
Sqlitetestrtree_Init(interp);
|
||||
Sqlitequota_Init(interp);
|
||||
Sqlitemultiplex_Init(interp);
|
||||
SqliteSuperlock_Init(interp);
|
||||
SqlitetestSyscall_Init(interp);
|
||||
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
||||
TestSession_Init(interp);
|
||||
#endif
|
||||
Fts5tcl_Init(interp);
|
||||
SqliteRbu_Init(interp);
|
||||
Sqlitetesttcl_Init(interp);
|
||||
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
Sqlitetestfts3_Init(interp);
|
||||
#endif
|
||||
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tclcmd: load_testfixture_extensions
|
||||
*/
|
||||
static int SQLITE_TCLAPI load_testfixture_extensions(
|
||||
ClientData cd,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
|
||||
Tcl_Interp *slave;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SLAVE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
slave = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
|
||||
if( !slave ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
(void)sqlite3TestInit(slave);
|
||||
return TCL_OK;
|
||||
}
|
21
src/where.c
21
src/where.c
@ -1885,18 +1885,19 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
** Return TRUE if all of the following are true:
|
||||
**
|
||||
** (1) X has the same or lower cost that Y
|
||||
** (2) X is a proper subset of Y
|
||||
** (3) X skips at least as many columns as Y
|
||||
**
|
||||
** By "proper subset" we mean that X uses fewer WHERE clause terms
|
||||
** than Y and that every WHERE clause term used by X is also used
|
||||
** by Y.
|
||||
** (2) X uses fewer WHERE clause terms than Y
|
||||
** (3) Every WHERE clause term used by X is also used by Y
|
||||
** (4) X skips at least as many columns as Y
|
||||
** (5) If X is a covering index, than Y is too
|
||||
**
|
||||
** Conditions (2) and (3) mean that X is a "proper subset" of Y.
|
||||
** If X is a proper subset of Y then Y is a better choice and ought
|
||||
** to have a lower cost. This routine returns TRUE when that cost
|
||||
** relationship is inverted and needs to be adjusted. The third rule
|
||||
** relationship is inverted and needs to be adjusted. Constraint (4)
|
||||
** was added because if X uses skip-scan less than Y it still might
|
||||
** deserve a lower cost even if it is a proper subset of Y.
|
||||
** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
|
||||
** was added because a covering index probably deserves to have a lower cost
|
||||
** than a non-covering index even if it is a proper subset.
|
||||
*/
|
||||
static int whereLoopCheaperProperSubset(
|
||||
const WhereLoop *pX, /* First WhereLoop to compare */
|
||||
@ -1918,6 +1919,10 @@ static int whereLoopCheaperProperSubset(
|
||||
}
|
||||
if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
|
||||
}
|
||||
if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
|
||||
&& (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
|
||||
return 0; /* Constraint (5) */
|
||||
}
|
||||
return 1; /* All conditions meet */
|
||||
}
|
||||
|
||||
|
@ -1052,8 +1052,11 @@ do_execsql_test 23.0 {
|
||||
do_eqp_test 23.1 {
|
||||
SELECT * FROM t4 WHERE
|
||||
(e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300
|
||||
-- Formerly used index i41. But i41 is not a covering index whereas
|
||||
-- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the
|
||||
-- PRIMARY KEY is preferred.
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t4 USING INDEX i41 (e=? AND c=? AND b=? AND a<?)}
|
||||
0 0 0 {SEARCH TABLE t4 USING PRIMARY KEY (c=? AND b=? AND a<?)}
|
||||
}
|
||||
do_eqp_test 23.2 {
|
||||
SELECT * FROM t4 WHERE
|
||||
|
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
|
||||
|
@ -107,6 +107,115 @@ do_catchsql_test 2.3 {
|
||||
INSERT INTO t1 VALUES(randomblob(900));
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
proc hex2blob {hex} {
|
||||
# Split on newlines:
|
||||
set bytes [list]
|
||||
foreach l [split $hex "\n"] {
|
||||
if {[string is space $l]} continue
|
||||
set L [list]
|
||||
foreach b [split $l] {
|
||||
if {[string is xdigit $b] && [string length $b]==2} {
|
||||
lappend L [expr "0x$b"]
|
||||
}
|
||||
}
|
||||
if {[llength $L]!=16} {
|
||||
error "Badly formed hex (1)"
|
||||
}
|
||||
set bytes [concat $bytes $L]
|
||||
}
|
||||
|
||||
binary format c* $bytes
|
||||
}
|
||||
|
||||
reset_db
|
||||
db func hex2blob hex2blob
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
PRAGMA page_size=1024;
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE TABLE t2(a, b, c);
|
||||
CREATE TABLE t3(a, b, c);
|
||||
CREATE TABLE t4(a, b, c);
|
||||
CREATE TABLE t5(a, b, c);
|
||||
}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
UPDATE sqlite_dbpage SET data = hex2blob('
|
||||
000: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
010: 04 00 01 01 20 40 20 20 00 00 3e d9 00 00 00 06 .... @ ..>.....
|
||||
020: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
|
||||
030: 0f 00 00 00 00 00 00 00 00 00 00 01 00 00 83 00 ................
|
||||
040: 00 00 00 00 00 00 00 00 00 00 00 00 00 38 00 00 .............8..
|
||||
050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3e d9 ..............>.
|
||||
060: 00 2d e6 07 0d 00 00 00 01 03 a0 00 03 e0 00 00 .-..............
|
||||
070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
0a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
0b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
0c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
0d0: 00 00 00 00 00 c1 00 00 00 00 00 00 00 00 00 00 ................
|
||||
0e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
0f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
160: 00 83 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
180: 00 00 00 00 00 00 00 00 00 00 07 00 30 00 00 00 ............0...
|
||||
190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
1a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
1b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
1c0: 02 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 ................
|
||||
1d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
1e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
1f0: 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
220: 00 00 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
230: 0c 00 00 00 00 00 00 60 00 00 00 06 00 00 c3 00 .......`........
|
||||
240: 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
270: 00 00 00 18 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
290: 04 00 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
2a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
2b0: 00 00 00 00 83 00 8c 00 00 00 00 00 00 00 00 00 ................
|
||||
2c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
2d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
2e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
2f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
310: 00 78 00 00 00 00 00 00 00 00 00 00 00 00 70 00 .x............p.
|
||||
320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
340: 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
350: 00 00 00 00 00 68 00 00 00 00 00 00 00 00 00 00 .....h..........
|
||||
360: 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 ................
|
||||
370: 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 ................
|
||||
380: 00 00 00 00 70 00 00 00 00 00 00 00 00 00 00 00 ....p...........
|
||||
390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
3a0: 5e 01 07 17 1b 1b 01 81 13 74 61 62 6c 65 73 65 ^........tablese
|
||||
3b0: 6e 73 6f 32 73 73 65 6e 73 6f 72 73 02 43 52 45 nso2ssensors.CRE
|
||||
3c0: 41 54 45 20 54 41 42 4c 45 20 73 65 6e 73 6f 72 ATE TABLE sensor
|
||||
3d0: 73 20 0a 20 20 24 20 20 20 20 20 20 20 20 20 20 s . $
|
||||
3e0: b8 6e 61 6d 65 21 74 65 78 74 2c 20 79 61 6c 20 .name!text, yal
|
||||
3f0: 72 65 61 6c 2c 20 74 69 6d 65 20 74 65 78 74 29 real, time text)
|
||||
') WHERE pgno=1
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_catchsql_test 3.3 {
|
||||
PRAGMA integrity_check;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
|
||||
|
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
|
@ -194,7 +194,7 @@ test_suite "valgrind" -prefix "" -description {
|
||||
} -files [
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault* *_err* wal.test \
|
||||
shell*.test crash8.test atof1.test selectG.test \
|
||||
tkt-fc62af4523.test numindex1.test
|
||||
tkt-fc62af4523.test numindex1.test corruptK.test
|
||||
] -initialize {
|
||||
set ::G(valgrind) 1
|
||||
} -shutdown {
|
||||
@ -1065,7 +1065,7 @@ test_suite "no_optimization" -description {
|
||||
test_suite "prepare" -description {
|
||||
Run tests with the db connection using sqlite3_prepare() instead of _v2().
|
||||
} -dbconfig {
|
||||
db_use_legacy_prepare $::dbhandle 1
|
||||
$::dbhandle version -use-legacy-prepare 1
|
||||
#$::dbhandle cache size 0
|
||||
} -files [
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault* \
|
||||
|
@ -30,7 +30,7 @@ do_execsql_test 1.0 {
|
||||
}
|
||||
|
||||
proc do_scanstatus_test {tn res} {
|
||||
set stmt [db_last_stmt_ptr db]
|
||||
set stmt [db version -last-stmt-ptr]
|
||||
set idx 0
|
||||
set ret [list]
|
||||
while {1} {
|
||||
@ -79,7 +79,7 @@ do_scanstatus_test 1.9 {
|
||||
}
|
||||
|
||||
do_test 1.9 {
|
||||
sqlite3_stmt_scanstatus_reset [db_last_stmt_ptr db]
|
||||
sqlite3_stmt_scanstatus_reset [db version -last-stmt-ptr]
|
||||
} {}
|
||||
|
||||
do_scanstatus_test 1.10 {
|
||||
|
93
tool/mkccode.tcl
Executable file
93
tool/mkccode.tcl
Executable file
@ -0,0 +1,93 @@
|
||||
#!/usr/bin/tclsh
|
||||
#
|
||||
# Use this script to build C-language source code for a program that uses
|
||||
# tclsqlite.c together with custom TCL scripts and/or C extensions for
|
||||
# either SQLite or TCL.
|
||||
#
|
||||
# Usage example:
|
||||
#
|
||||
# tclsh mktclsqliteprog.tcl demoapp.c.in >demoapp.c
|
||||
#
|
||||
# The demoapp.c.in file contains a mixture of C code, TCL script, and
|
||||
# processing directives used by mktclsqliteprog.tcl to build the final C-code
|
||||
# output file. Most lines of demoapp.c.in are copied straight through into
|
||||
# the output. The following control directives are recognized:
|
||||
#
|
||||
# BEGIN_STRING
|
||||
#
|
||||
# This marks the beginning of large string literal - usually a TCL
|
||||
# script of some kind. Subsequent lines of text through the first
|
||||
# line that begins with END_STRING are converted into a C-language
|
||||
# string literal.
|
||||
#
|
||||
# INCLUDE path
|
||||
#
|
||||
# The path argument is the name of a file to be inserted in place of
|
||||
# the INCLUDE line. The path can begin with $ROOT to signify the
|
||||
# root of the SQLite source tree, or $HOME to signify the directory
|
||||
# that contains the demoapp.c.in input script itself. If the path does
|
||||
# not begin with either $ROOT or $HOME, then it is interpreted relative
|
||||
# to the current working directory.
|
||||
#
|
||||
# If the INCLUDE occurs in the middle of BEGIN_STRING...END_STRING
|
||||
# then all of the text in the input file is converted into C-language
|
||||
# string literals.
|
||||
#
|
||||
# None of the control directives described above will nest. Only the
|
||||
# top-level input file ("demoapp.c.in" in the example) is interpreted.
|
||||
# referenced files are copied verbatim.
|
||||
#
|
||||
if {[llength $argv]!=1} {
|
||||
puts stderr "Usage: $argv0 TEMPLATE >OUTPUT"
|
||||
exit 1
|
||||
}
|
||||
set infile [lindex $argv 0]
|
||||
set ROOT [file normalize [file dir $argv0]/..]
|
||||
set HOME [file normalize [file dir $infile]]
|
||||
set in [open $infile rb]
|
||||
puts [subst {/* DO NOT EDIT
|
||||
**
|
||||
** This file was generated by \"$argv0 $infile\".
|
||||
** To make changes, edit $infile then rerun the generator
|
||||
** command.
|
||||
*/}]
|
||||
set instr 0
|
||||
while {1} {
|
||||
set line [gets $in]
|
||||
if {[eof $in]} break
|
||||
if {[regexp {^INCLUDE (.*)} $line all path]} {
|
||||
regsub {^\$ROOT\y} $path $ROOT path
|
||||
regsub {^\$HOME\y} $path $HOME path
|
||||
set in2 [open $path rb]
|
||||
puts "/* INCLUDE $path */"
|
||||
if {$instr} {
|
||||
while {1} {
|
||||
set line [gets $in2]
|
||||
if {[eof $in2]} break
|
||||
set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
|
||||
puts "\"$x\\n\""
|
||||
}
|
||||
} else {
|
||||
puts [read $in2]
|
||||
}
|
||||
puts "/* END $path */"
|
||||
close $in2
|
||||
continue
|
||||
}
|
||||
if {[regexp {^BEGIN_STRING} $line]} {
|
||||
set instr 1
|
||||
puts "/* BEGIN_STRING */"
|
||||
continue
|
||||
}
|
||||
if {[regexp {^END_STRING} $line]} {
|
||||
set instr 0
|
||||
puts "/* END_STRING */"
|
||||
continue
|
||||
}
|
||||
if {$instr} {
|
||||
set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
|
||||
puts "\"$x\\n\""
|
||||
} else {
|
||||
puts $line
|
||||
}
|
||||
}
|
@ -394,6 +394,7 @@ foreach file {
|
||||
fts3_icu.c
|
||||
sqlite3rbu.c
|
||||
dbstat.c
|
||||
dbpage.c
|
||||
sqlite3session.c
|
||||
json1.c
|
||||
fts5.c
|
||||
|
@ -15,6 +15,7 @@ set END {^/\*+ End of %s \*+/}
|
||||
|
||||
set in [open sqlite3.c]
|
||||
set out1 [open sqlite3-all.c w]
|
||||
fconfigure $out1 -translation lf
|
||||
|
||||
# Copy the header from sqlite3.c into sqlite3-all.c
|
||||
#
|
||||
@ -48,6 +49,7 @@ proc write_one_file {content} {
|
||||
global filecnt
|
||||
incr filecnt
|
||||
set out [open sqlite3-$filecnt.c w]
|
||||
fconfigure $out -translation lf
|
||||
puts -nonewline $out $content
|
||||
close $out
|
||||
puts $::out1 "#include \"sqlite3-$filecnt.c\""
|
||||
|
27
tool/sqlite3_analyzer.c.in
Normal file
27
tool/sqlite3_analyzer.c.in
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
** Read an SQLite database file and analyze its space utilization. Generate
|
||||
** text on standard output.
|
||||
*/
|
||||
#define TCLSH_INIT_PROC sqlite3_analyzer_init_proc
|
||||
#define SQLITE_ENABLE_DBSTAT_VTAB 1
|
||||
#undef SQLITE_THREADSAFE
|
||||
#define SQLITE_THREADSAFE 0
|
||||
#undef SQLITE_ENABLE_COLUMN_METADATA
|
||||
#define SQLITE_OMIT_DECLTYPE 1
|
||||
#define SQLITE_OMIT_DEPRECATED 1
|
||||
#define SQLITE_OMIT_PROGRESS_CALLBACK 1
|
||||
#define SQLITE_OMIT_SHARED_CACHE 1
|
||||
#define SQLITE_DEFAULT_MEMSTATUS 0
|
||||
#define SQLITE_MAX_EXPR_DEPTH 0
|
||||
#define SQLITE_OMIT_LOAD_EXTENSION 1
|
||||
INCLUDE sqlite3.c
|
||||
INCLUDE $ROOT/src/tclsqlite.c
|
||||
|
||||
const char *sqlite3_analyzer_init_proc(Tcl_Interp *interp){
|
||||
(void)interp;
|
||||
return
|
||||
BEGIN_STRING
|
||||
INCLUDE $ROOT/tool/spaceanal.tcl
|
||||
END_STRING
|
||||
;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#!/usr/bin/tcl
|
||||
#
|
||||
# Convert input text into a C string
|
||||
#
|
||||
set in [open [lindex $argv 0] rb]
|
||||
while {![eof $in]} {
|
||||
set line [gets $in]
|
||||
if {[eof $in]} break;
|
||||
set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
|
||||
puts "\"$x\\n\""
|
||||
}
|
||||
close $in
|
Reference in New Issue
Block a user