Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 708b22b1e3 | |||
| 891d6b4e9e | |||
| 1ba30db8bd | |||
| a6bf20b587 | |||
| 1e45c7db56 | |||
| e43d6aee45 | |||
| a2df53bd61 | |||
| f157d10f9f | |||
| fb546afb4d | |||
| f8563c00b2 |
+1
-5
@@ -566,6 +566,7 @@ SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
|
||||
DBFUZZ_OPT =
|
||||
|
||||
@@ -1185,11 +1186,6 @@ KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS)
|
||||
|
||||
DBSELFTEST_OPT += -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_FTS4
|
||||
|
||||
dbselftest$(TEXE): $(TOP)/test/dbselftest.c sqlite3.c
|
||||
$(LTLINK) $(DBSELFTEST_OPT) -o $@ $(TOP)/test/dbselftest.c sqlite3.c $(TLIBS)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
|
||||
$(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS)
|
||||
|
||||
|
||||
+1
-1
@@ -1510,7 +1510,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_
|
||||
#
|
||||
MPTESTER_COMPILE_OPTS = -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS5
|
||||
FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
|
||||
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
||||
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
##########################################################################
|
||||
# 2016 Mar 8
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
proc process_cmdline {} {
|
||||
cmdline::process ::A $::argv {
|
||||
{make "try to build missing tools"}
|
||||
{verbose "make more noise"}
|
||||
database
|
||||
database2
|
||||
} {
|
||||
This script uses/tests the following tools:
|
||||
|
||||
dbselftest
|
||||
rbu
|
||||
sqldiff
|
||||
sqlite3
|
||||
|
||||
The user passes the names of two database files - a.db and b.db below - as
|
||||
arguments. This program:
|
||||
|
||||
1. Runs [dbselftest --init] against both databases.
|
||||
2. Runs [sqldiff --rbu --vtab a.db b.db | sqlite3 <tmpname>.db] to create an
|
||||
RBU database.
|
||||
3. Runs [rbu b.db <tmpname>.db] to patch b.db to a.db.
|
||||
4. Runs [sqldiff --table selftest a.db b.db] to check that the selftest
|
||||
tables are now identical.
|
||||
5. Runs [dbselftest] against both databases.
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
###########################################################################
|
||||
# Command line options processor. This is generic code that can be copied
|
||||
# between scripts.
|
||||
#
|
||||
namespace eval cmdline {
|
||||
proc cmdline_error {O E {msg ""}} {
|
||||
if {$msg != ""} {
|
||||
puts stderr "Error: $msg"
|
||||
puts stderr ""
|
||||
}
|
||||
|
||||
set L [list]
|
||||
foreach o $O {
|
||||
if {[llength $o]==1} {
|
||||
lappend L [string toupper $o]
|
||||
}
|
||||
}
|
||||
|
||||
puts stderr "Usage: $::argv0 ?SWITCHES? $L"
|
||||
puts stderr ""
|
||||
puts stderr "Switches are:"
|
||||
foreach o $O {
|
||||
if {[llength $o]==3} {
|
||||
foreach {a b c} $o {}
|
||||
puts stderr [format " -%-15s %s (default \"%s\")" "$a VAL" $c $b]
|
||||
} elseif {[llength $o]==2} {
|
||||
foreach {a b} $o {}
|
||||
puts stderr [format " -%-15s %s" $a $b]
|
||||
}
|
||||
}
|
||||
puts stderr ""
|
||||
puts stderr $E
|
||||
exit -1
|
||||
}
|
||||
|
||||
proc process {avar lArgs O E} {
|
||||
upvar $avar A
|
||||
set zTrailing "" ;# True if ... is present in $O
|
||||
set lPosargs [list]
|
||||
|
||||
# Populate A() with default values. Also, for each switch in the command
|
||||
# line spec, set an entry in the idx() array as follows:
|
||||
#
|
||||
# {tblname t1 "table name to use"}
|
||||
# -> [set idx(-tblname) {tblname t1 "table name to use"}
|
||||
#
|
||||
# For each position parameter, append its name to $lPosargs. If the ...
|
||||
# specifier is present, set $zTrailing to the name of the prefix.
|
||||
#
|
||||
foreach o $O {
|
||||
set nm [lindex $o 0]
|
||||
set nArg [llength $o]
|
||||
switch -- $nArg {
|
||||
1 {
|
||||
if {[string range $nm end-2 end]=="..."} {
|
||||
set zTrailing [string range $nm 0 end-3]
|
||||
} else {
|
||||
lappend lPosargs $nm
|
||||
}
|
||||
}
|
||||
2 {
|
||||
set A($nm) 0
|
||||
set idx(-$nm) $o
|
||||
}
|
||||
3 {
|
||||
set A($nm) [lindex $o 1]
|
||||
set idx(-$nm) $o
|
||||
}
|
||||
default {
|
||||
error "Error in command line specification"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Set explicitly specified option values
|
||||
#
|
||||
set nArg [llength $lArgs]
|
||||
for {set i 0} {$i < $nArg} {incr i} {
|
||||
set opt [lindex $lArgs $i]
|
||||
if {[string range $opt 0 0]!="-" || $opt=="--"} break
|
||||
set c [array names idx "${opt}*"]
|
||||
if {[llength $c]==0} { cmdline_error $O $E "Unrecognized option: $opt"}
|
||||
if {[llength $c]>1} { cmdline_error $O $E "Ambiguous option: $opt"}
|
||||
|
||||
if {[llength $idx($c)]==3} {
|
||||
if {$i==[llength $lArgs]-1} {
|
||||
cmdline_error $O $E "Option requires argument: $c"
|
||||
}
|
||||
incr i
|
||||
set A([lindex $idx($c) 0]) [lindex $lArgs $i]
|
||||
} else {
|
||||
set A([lindex $idx($c) 0]) 1
|
||||
}
|
||||
}
|
||||
|
||||
# Deal with position arguments.
|
||||
#
|
||||
set nPosarg [llength $lPosargs]
|
||||
set nRem [expr $nArg - $i]
|
||||
if {$nRem < $nPosarg || ($zTrailing=="" && $nRem > $nPosarg)} {
|
||||
cmdline_error $O $E
|
||||
}
|
||||
for {set j 0} {$j < $nPosarg} {incr j} {
|
||||
set A([lindex $lPosargs $j]) [lindex $lArgs [expr $j+$i]]
|
||||
}
|
||||
if {$zTrailing!=""} {
|
||||
set A($zTrailing) [lrange $lArgs [expr $j+$i] end]
|
||||
}
|
||||
}
|
||||
} ;# namespace eval cmdline
|
||||
# End of command line options processor.
|
||||
###########################################################################
|
||||
###########################################################################
|
||||
|
||||
process_cmdline
|
||||
|
||||
# Check that the specified tool is present.
|
||||
#
|
||||
proc check_for_tool {tool} {
|
||||
if {[file exists $tool]==0 || [file executable $tool]==0} {
|
||||
puts stderr "Missing $tool... exiting. (run \[make $tool\])"
|
||||
exit -1
|
||||
}
|
||||
}
|
||||
|
||||
if {$A(make)} {
|
||||
if {$A(verbose)} { puts "building tools..." }
|
||||
exec make dbselftest rbu sqlite3 sqldiff
|
||||
}
|
||||
|
||||
check_for_tool dbselftest
|
||||
check_for_tool rbu
|
||||
check_for_tool sqlite3
|
||||
check_for_tool sqldiff
|
||||
|
||||
exec ./sqlite3 $A(database) "DROP TABLE selftest;"
|
||||
exec ./sqlite3 $A(database2) "DROP TABLE selftest;"
|
||||
|
||||
# Run [dbselftest --init] on both databases
|
||||
if {$A(verbose)} { puts "Running \[dbselftest --init\]" }
|
||||
exec ./dbselftest --init $A(database)
|
||||
exec ./dbselftest --init $A(database2)
|
||||
|
||||
# Create an RBU patch.
|
||||
set tmpname "./rrt-[format %x [expr int(rand()*0x7FFFFFFF)]].db"
|
||||
if {$A(verbose)} { puts "rbu database is $tmpname" }
|
||||
exec ./sqldiff --rbu --vtab $A(database2) $A(database) | ./sqlite3 $tmpname
|
||||
|
||||
# Run the [rbu] patch.
|
||||
if {$A(verbose)} { puts "Running \[rbu]" }
|
||||
exec ./rbu $A(database2) $tmpname
|
||||
|
||||
set selftest_diff [exec ./sqldiff --table selftest $A(database) $A(database2)]
|
||||
if {$selftest_diff != ""} {
|
||||
puts stderr "patching table \"selftest\" failed: $selftest_diff"
|
||||
exit -1
|
||||
}
|
||||
|
||||
# Run [dbselftest] on both databases
|
||||
if {$A(verbose)} { puts "Running \[dbselftest]" }
|
||||
exec ./dbselftest $A(database)
|
||||
exec ./dbselftest $A(database2)
|
||||
|
||||
# Remove the RBU database
|
||||
file delete $tmpname
|
||||
puts "round trip test successful."
|
||||
|
||||
@@ -477,10 +477,9 @@ SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
DBFUZZ_OPT =
|
||||
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
DBSELFTEST_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
DBSELFTEST_OPT += -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
|
||||
ST_OPT = -DSQLITE_THREADSAFE=0
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
@@ -902,9 +901,6 @@ speedtest1$(EXE): $(TOP)/test/speedtest1.c sqlite3.c
|
||||
kvtest$(EXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(TCCX) -I. $(KV_OPT) -o kvtest$(EXE) $(TOP)/test/kvtest.c sqlite3.c $(THREADLIB)
|
||||
|
||||
dbselftest$(EXE): $(TOP)/test/dbselftest.c sqlite3.c
|
||||
$(TCCX) -I. $(DBSELFTEST_OPT) -o dbselftest$(EXE) $(TOP)/test/dbselftest.c sqlite3.c $(THREADLIB)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o
|
||||
$(TCC) -I. -o rbu$(EXE) $(TOP)/ext/rbu/rbu.c sqlite3.o \
|
||||
$(THREADLIB)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
C Begin\smoving\sseparate\sboolean\svariables\sin\sthe\sShellState\sobject\sof\sthe\sCLI\ninto\sthe\sshellFlgs\sbitmask.
|
||||
D 2017-03-09T13:50:49.349
|
||||
F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
|
||||
C The\soutput\sof\sthe\s".dump"\scommand\sin\sthe\sCLI\squotes\snewline\sand\scarriage-return\ncharacters\susing\s"char(10)"\sand\s"char(13)".
|
||||
D 2017-03-11T01:56:41.692
|
||||
F Makefile.in 2dae2a56457c2885425a480e1053de8096aff924
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2
|
||||
F Makefile.msc 9020fa41eb91f657ae0cc44145d0a2f3af520860
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION 3605fa447e4623f5ff4a6adc97b1fde9a257b8f2
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -250,7 +250,6 @@ F ext/rbu/rbuA.test c1a7b3e2d926b8f8448bb3b4ae787e314ee4b2b3
|
||||
F ext/rbu/rbuB.test c25bc325b8072a766e56bb76c001866b405925c2
|
||||
F ext/rbu/rbuC.test efe47db508a0269b683cb2a1913a425ffd39a831
|
||||
F ext/rbu/rbu_common.tcl a38e8e2d4a50fd6aaf151633714c1b1d2fae3ead
|
||||
F ext/rbu/rbu_round_trip.tcl f3216836bbaeb10d76a2c70b89c13f59eabbd117
|
||||
F ext/rbu/rbucrash.test 8d2ed5d4b05fef6c00c2a6b5f7ead71fa172a695
|
||||
F ext/rbu/rbucrash2.test b2ecbdd7bb72c88bd217c65bd00dafa07f7f2d4d
|
||||
F ext/rbu/rbudiff.test 3e605cf624d00d04d0fb1316a3acec4fbe3b3ac5
|
||||
@@ -323,7 +322,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 08e0b151abb46353c677ac4974b50c6077f85eee
|
||||
F main.mk 0ec10b604f4668f7e85a358954babe75c94dc0d5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -365,7 +364,7 @@ F src/insert.c 3ed64afc49c0a2221e397b9f65d231ffbef506fe
|
||||
F src/legacy.c e88ed13c2d531decde75d42c2e35623fb9ce3cb0
|
||||
F src/loadext.c a68d8d1d14cf7488bb29dc5311cb1ce9a4404258
|
||||
F src/main.c 158326243c5ddc8b98a1e983fa488650cf76d760
|
||||
F src/malloc.c d0a1474236486165bcb349af82e2a6560178bf7b
|
||||
F src/malloc.c 89c98e3619d362dcffa5c1c639b364b65b474751
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c fd7cd6fe21d46fe0a4186367dd8dc26d87b787eb
|
||||
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
@@ -400,7 +399,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c d12f3539f80db38b09015561b569e0eb1c4b6c5f
|
||||
F src/shell.c 397e51c3eeb3a9dc21667a0a384eb14403cc5eea
|
||||
F src/shell.c 353f3cebb938099577494326e2853010512e0625
|
||||
F src/sqlite.h.in 4d0c08f8640c586564a7032b259c5f69bf397850
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
|
||||
@@ -643,7 +642,6 @@ F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
|
||||
F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbselftest.c b2e6cfac59066dbcb7334b66304bb15a5508dd42
|
||||
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||
@@ -1008,7 +1006,7 @@ F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
|
||||
F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
|
||||
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
|
||||
F test/oserror.test b32dc34f2363ef18532e3a0a7358e3e7e321974f
|
||||
F test/ossfuzz.c e469138f4be3e92df6173b79b3b216ab6e17b407
|
||||
F test/ossfuzz.c f04b9f236e51d4db701bdebe8ac01318c83102a8
|
||||
F test/ossshell.c d9f1a6f43e7bab45d6be857a5800f5d4a1861db3
|
||||
F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f
|
||||
F test/pager1.test 841868017e9dd3cb459b8d78862091a7d9cff21d
|
||||
@@ -1564,7 +1562,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 2ea300fb8f7c497f3f092dc91f4305d8431c27d9
|
||||
R 193fb708e3eeb9be14d6692d9fad8ed4
|
||||
P 7359fcacaadc349f520536311dcd1d0b5cea7673
|
||||
R 21dd742a2e245e17ea4fce05d92294e6
|
||||
T *branch * string-quoting-dump
|
||||
T *sym-string-quoting-dump *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z 6ea8a21fbd5a369fc4273386c415b1f4
|
||||
Z 185539d207724f873d847ed122ae7c58
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
50eec5d9aa38fab1a85d788356ffdaf6c35d9ece
|
||||
8b2954dd8376e2de985cf5dedeb6eec32c430505
|
||||
@@ -230,6 +230,13 @@ static void mallocWithAlarm(int n, void **pp){
|
||||
** following xRoundup() call. */
|
||||
nFull = sqlite3GlobalConfig.m.xRoundup(n);
|
||||
|
||||
#ifdef SQLITE_MAX_MEMORY
|
||||
if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nFull>SQLITE_MAX_MEMORY ){
|
||||
*pp = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
|
||||
if( mem0.alarmThreshold>0 ){
|
||||
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
||||
|
||||
+286
-64
@@ -1490,32 +1490,52 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
|
||||
|
||||
/*
|
||||
** Output the given string as a quoted string using SQL quoting conventions.
|
||||
**
|
||||
** The "\n" and "\r" characters are converted to char(10) and char(13)
|
||||
** to prevent them from being transformed by end-of-line translators.
|
||||
*/
|
||||
static void output_quoted_string(FILE *out, const char *z){
|
||||
int i;
|
||||
int nSingle = 0;
|
||||
char c;
|
||||
setBinaryMode(out, 1);
|
||||
for(i=0; z[i]; i++){
|
||||
if( z[i]=='\'' ) nSingle++;
|
||||
}
|
||||
if( nSingle==0 ){
|
||||
for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
|
||||
if( c==0 ){
|
||||
utf8_printf(out,"'%s'",z);
|
||||
}else{
|
||||
raw_printf(out,"'");
|
||||
int inQuote = 0;
|
||||
int bStarted = 0;
|
||||
while( *z ){
|
||||
for(i=0; z[i] && z[i]!='\''; i++){}
|
||||
if( i==0 ){
|
||||
raw_printf(out,"''");
|
||||
z++;
|
||||
}else if( z[i]=='\'' ){
|
||||
utf8_printf(out,"%.*s''",i,z);
|
||||
z += i+1;
|
||||
}else{
|
||||
utf8_printf(out,"%s",z);
|
||||
for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
|
||||
if( c=='\'' ) i++;
|
||||
if( i ){
|
||||
if( !inQuote ){
|
||||
if( bStarted ) raw_printf(out, "||");
|
||||
raw_printf(out, "'");
|
||||
inQuote = 1;
|
||||
}
|
||||
utf8_printf(out, "%.*s", i, z);
|
||||
z += i;
|
||||
bStarted = 1;
|
||||
}
|
||||
if( c=='\'' ){
|
||||
raw_printf(out, "'");
|
||||
continue;
|
||||
}
|
||||
if( inQuote ){
|
||||
raw_printf(out, "'");
|
||||
inQuote = 0;
|
||||
}
|
||||
if( c==0 ){
|
||||
break;
|
||||
}
|
||||
for(i=0; (c = z[i])=='\r' || c=='\n'; i++){
|
||||
if( bStarted ) raw_printf(out, "||");
|
||||
raw_printf(out, "char(%d)", c);
|
||||
bStarted = 1;
|
||||
}
|
||||
z += i;
|
||||
}
|
||||
raw_printf(out,"'");
|
||||
if( inQuote ) raw_printf(out, "'");
|
||||
}
|
||||
setTextMode(out, 1);
|
||||
}
|
||||
@@ -2007,9 +2027,13 @@ static int shell_callback(
|
||||
}else if( aiType && aiType[i]==SQLITE_TEXT ){
|
||||
if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
|
||||
output_quoted_string(p->out, azArg[i]);
|
||||
}else if( aiType && (aiType[i]==SQLITE_INTEGER
|
||||
|| aiType[i]==SQLITE_FLOAT) ){
|
||||
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
|
||||
utf8_printf(p->out,"%s%s",zSep, azArg[i]);
|
||||
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
|
||||
char z[50];
|
||||
double r = sqlite3_column_double(p->pStmt, i);
|
||||
sqlite3_snprintf(50,z,"%!.20g", r);
|
||||
raw_printf(p->out, "%s%s", zSep, z);
|
||||
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
|
||||
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
|
||||
int nBlob = sqlite3_column_bytes(p->pStmt, i);
|
||||
@@ -2054,6 +2078,69 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
return shell_callback(pArg, nArg, azArg, azCol, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the callback routine from sqlite3_exec() that appends all
|
||||
** output onto the end of a ShellText object.
|
||||
*/
|
||||
static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
|
||||
ShellText *p = (ShellText*)pArg;
|
||||
int i;
|
||||
if( p->n ) appendText(p, "|", 0);
|
||||
for(i=0; i<nArg; i++){
|
||||
if( i ) appendText(p, ",", 0);
|
||||
if( azArg[i] ) appendText(p, azArg[i], 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate an appropriate SELFTEST table in the main database.
|
||||
*/
|
||||
static void createSelftestTable(ShellState *p){
|
||||
char *zErrMsg = 0;
|
||||
sqlite3_exec(p->db,
|
||||
"SAVEPOINT selftest_init;\n"
|
||||
"CREATE TABLE IF NOT EXISTS selftest(\n"
|
||||
" tno INTEGER PRIMARY KEY,\n" /* Test number */
|
||||
" op TEXT,\n" /* Operator: memo run */
|
||||
" cmd TEXT,\n" /* Command text */
|
||||
" ans TEXT\n" /* Desired answer */
|
||||
");"
|
||||
"CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n"
|
||||
"INSERT INTO [_shell$self](rowid,op,cmd)\n"
|
||||
" VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n"
|
||||
" 'memo','Tests generated by --init');\n"
|
||||
"INSERT INTO [_shell$self]\n"
|
||||
" SELECT 'run',\n"
|
||||
" 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
|
||||
"FROM sqlite_master ORDER BY 2'',224))',\n"
|
||||
" hex(sha3_query('SELECT type,name,tbl_name,sql "
|
||||
"FROM sqlite_master ORDER BY 2',224));\n"
|
||||
"INSERT INTO [_shell$self]\n"
|
||||
" SELECT 'run',"
|
||||
" 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
|
||||
" printf('%w',name) || '\" NOT INDEXED'',224))',\n"
|
||||
" hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
|
||||
" FROM (\n"
|
||||
" SELECT name FROM sqlite_master\n"
|
||||
" WHERE type='table'\n"
|
||||
" AND name<>'selftest'\n"
|
||||
" AND coalesce(rootpage,0)>0\n"
|
||||
" )\n"
|
||||
" ORDER BY name;\n"
|
||||
"INSERT INTO [_shell$self]\n"
|
||||
" VALUES('run','PRAGMA integrity_check','ok');\n"
|
||||
"INSERT INTO selftest(tno,op,cmd,ans)"
|
||||
" SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
|
||||
"DROP TABLE [_shell$self];"
|
||||
,0,0,&zErrMsg);
|
||||
if( zErrMsg ){
|
||||
utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
}
|
||||
sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Set the destination table field of the ShellState structure to
|
||||
@@ -2196,6 +2283,31 @@ static void displayLinuxIoStats(FILE *out){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Display a single line of status using 64-bit values.
|
||||
*/
|
||||
static void displayStatLine(
|
||||
ShellState *p, /* The shell context */
|
||||
char *zLabel, /* Label for this one line */
|
||||
char *zFormat, /* Format for the result */
|
||||
int iStatusCtrl, /* Which status to display */
|
||||
int bReset /* True to reset the stats */
|
||||
){
|
||||
sqlite3_int64 iCur = -1;
|
||||
sqlite3_int64 iHiwtr = -1;
|
||||
int i, nPercent;
|
||||
char zLine[200];
|
||||
sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset);
|
||||
for(i=0, nPercent=0; zFormat[i]; i++){
|
||||
if( zFormat[i]=='%' ) nPercent++;
|
||||
}
|
||||
if( nPercent>1 ){
|
||||
sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
|
||||
}
|
||||
raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
|
||||
}
|
||||
|
||||
/*
|
||||
** Display memory stats.
|
||||
@@ -2209,57 +2321,31 @@ static int display_stats(
|
||||
int iHiwtr;
|
||||
|
||||
if( pArg && pArg->out ){
|
||||
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out,
|
||||
"Memory Used: %d (max %d) bytes\n",
|
||||
iCur, iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n",
|
||||
iCur, iHiwtr);
|
||||
displayStatLine(pArg, "Memory Used:",
|
||||
"%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
|
||||
displayStatLine(pArg, "Number of Outstanding Allocations:",
|
||||
"%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
|
||||
if( pArg->shellFlgs & SHFLG_Pagecache ){
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out,
|
||||
"Number of Pcache Pages Used: %d (max %d) pages\n",
|
||||
iCur, iHiwtr);
|
||||
displayStatLine(pArg, "Number of Pcache Pages Used:",
|
||||
"%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
|
||||
}
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out,
|
||||
"Number of Pcache Overflow Bytes: %d (max %d) bytes\n",
|
||||
iCur, iHiwtr);
|
||||
displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
|
||||
"%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
|
||||
if( pArg->shellFlgs & SHFLG_Scratch ){
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out,
|
||||
"Number of Scratch Allocations Used: %d (max %d)\n",
|
||||
iCur, iHiwtr);
|
||||
displayStatLine(pArg, "Number of Scratch Allocations Used:",
|
||||
"%lld (max %lld)", SQLITE_STATUS_SCRATCH_USED, bReset);
|
||||
}
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out,
|
||||
"Number of Scratch Overflow Bytes: %d (max %d) bytes\n",
|
||||
iCur, iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out, "Largest Allocation: %d bytes\n",
|
||||
iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out, "Largest Pcache Allocation: %d bytes\n",
|
||||
iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out, "Largest Scratch Allocation: %d bytes\n",
|
||||
iHiwtr);
|
||||
displayStatLine(pArg, "Number of Scratch Overflow Bytes:",
|
||||
"%lld (max %lld) bytes", SQLITE_STATUS_SCRATCH_OVERFLOW, bReset);
|
||||
displayStatLine(pArg, "Largest Allocation:",
|
||||
"%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
|
||||
displayStatLine(pArg, "Largest Pcache Allocation:",
|
||||
"%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
|
||||
displayStatLine(pArg, "Largest Scratch Allocation:",
|
||||
"%lld bytes", SQLITE_STATUS_SCRATCH_SIZE, bReset);
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
|
||||
raw_printf(pArg->out, "Deepest Parser Stack: %d (max %d)\n",
|
||||
iCur, iHiwtr);
|
||||
displayStatLine(pArg, "Deepest Parser Stack:",
|
||||
"%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2850,6 +2936,23 @@ static char **tableColumnList(ShellState *p, const char *zTab){
|
||||
return azCol;
|
||||
}
|
||||
|
||||
/*
|
||||
** Toggle the reverse_unordered_selects setting.
|
||||
*/
|
||||
static void toggleSelectOrder(sqlite3 *db){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int iSetting = 0;
|
||||
char zStmt[100];
|
||||
sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0);
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
iSetting = sqlite3_column_int(pStmt, 0);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_snprintf(sizeof(zStmt), zStmt,
|
||||
"PRAGMA reverse_unordered_selects(%d)", !iSetting);
|
||||
sqlite3_exec(db, zStmt, 0, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** This is a different callback routine used for dumping the database.
|
||||
** Each row received by this callback consists of a table name,
|
||||
@@ -2946,6 +3049,12 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
p->zDestTable = sTable.z;
|
||||
p->mode = p->cMode = MODE_Insert;
|
||||
rc = shell_exec(p->db, sSelect.z, shell_callback, p, 0);
|
||||
if( (rc&0xff)==SQLITE_CORRUPT ){
|
||||
raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
|
||||
toggleSelectOrder(p->db);
|
||||
shell_exec(p->db, sSelect.z, shell_callback, p, 0);
|
||||
toggleSelectOrder(p->db);
|
||||
}
|
||||
p->zDestTable = savedDestTable;
|
||||
p->mode = savedMode;
|
||||
freeText(&sTable);
|
||||
@@ -5704,6 +5813,119 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
#endif
|
||||
|
||||
if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
|
||||
int bIsInit = 0; /* True to initialize the SELFTEST table */
|
||||
int bVerbose = 0; /* Verbose output */
|
||||
int bSelftestExists; /* True if SELFTEST already exists */
|
||||
char **azTest = 0; /* Content of the SELFTEST table */
|
||||
int nRow = 0; /* Number of rows in the SELFTEST table */
|
||||
int nCol = 4; /* Number of columns in the SELFTEST table */
|
||||
int i; /* Loop counter */
|
||||
int nTest = 0; /* Number of tests runs */
|
||||
int nErr = 0; /* Number of errors seen */
|
||||
ShellText str; /* Answer for a query */
|
||||
static char *azDefaultTest[] = {
|
||||
0, 0, 0, 0,
|
||||
"0", "memo", "Missing SELFTEST table - default checks only", "",
|
||||
"1", "run", "PRAGMA integrity_check", "ok"
|
||||
};
|
||||
static const int nDefaultRow = 2;
|
||||
|
||||
open_db(p,0);
|
||||
for(i=1; i<nArg; i++){
|
||||
const char *z = azArg[i];
|
||||
if( z[0]=='-' && z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-init")==0 ){
|
||||
bIsInit = 1;
|
||||
}else
|
||||
if( strcmp(z,"-v")==0 ){
|
||||
bVerbose++;
|
||||
}else
|
||||
{
|
||||
utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
|
||||
azArg[i], azArg[0]);
|
||||
raw_printf(stderr, "Should be one of: --init -v\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}
|
||||
if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
|
||||
!= SQLITE_OK ){
|
||||
bSelftestExists = 0;
|
||||
}else{
|
||||
bSelftestExists = 1;
|
||||
}
|
||||
if( bIsInit ){
|
||||
createSelftestTable(p);
|
||||
bSelftestExists = 1;
|
||||
}
|
||||
if( bSelftestExists ){
|
||||
rc = sqlite3_get_table(p->db,
|
||||
"SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
|
||||
&azTest, &nRow, &nCol, 0);
|
||||
if( rc ){
|
||||
raw_printf(stderr, "Error querying the selftest table\n");
|
||||
rc = 1;
|
||||
sqlite3_free_table(azTest);
|
||||
goto meta_command_exit;
|
||||
}else if( nRow==0 ){
|
||||
sqlite3_free_table(azTest);
|
||||
azTest = azDefaultTest;
|
||||
nRow = nDefaultRow;
|
||||
}
|
||||
}else{
|
||||
azTest = azDefaultTest;
|
||||
nRow = nDefaultRow;
|
||||
}
|
||||
initText(&str);
|
||||
appendText(&str, "x", 0);
|
||||
for(i=1; i<=nRow; i++){
|
||||
int tno = atoi(azTest[i*nCol]);
|
||||
const char *zOp = azTest[i*nCol+1];
|
||||
const char *zSql = azTest[i*nCol+2];
|
||||
const char *zAns = azTest[i*nCol+3];
|
||||
|
||||
if( bVerbose>0 ){
|
||||
char *zQuote = sqlite3_mprintf("%q", zSql);
|
||||
printf("%d: %s %s\n", tno, zOp, zSql);
|
||||
sqlite3_free(zQuote);
|
||||
}
|
||||
if( strcmp(zOp,"memo")==0 ){
|
||||
utf8_printf(p->out, "%s\n", zSql);
|
||||
}else
|
||||
if( strcmp(zOp,"run")==0 ){
|
||||
char *zErrMsg = 0;
|
||||
str.n = 0;
|
||||
str.z[0] = 0;
|
||||
rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
|
||||
nTest++;
|
||||
if( bVerbose ){
|
||||
utf8_printf(p->out, "Result: %s\n", str.z);
|
||||
}
|
||||
if( rc || zErrMsg ){
|
||||
nErr++;
|
||||
rc = 1;
|
||||
utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
}else if( strcmp(zAns,str.z)!=0 ){
|
||||
nErr++;
|
||||
rc = 1;
|
||||
utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
|
||||
utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
|
||||
}
|
||||
}else
|
||||
{
|
||||
utf8_printf(stderr,
|
||||
"Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeText(&str);
|
||||
if( azTest!=azDefaultTest ) sqlite3_free_table(azTest);
|
||||
utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
|
||||
}else
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
|
||||
if( nArg<2 || nArg>3 ){
|
||||
raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
|
||||
|
||||
@@ -1,786 +0,0 @@
|
||||
/*
|
||||
** 2017-02-07
|
||||
**
|
||||
** 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 program implements an SQLite database self-verification utility.
|
||||
** Usage:
|
||||
**
|
||||
** dbselftest DATABASE ...
|
||||
**
|
||||
** This program reads the "selftest" table in DATABASE, in rowid order,
|
||||
** and runs each of the tests described there, reporting results at the
|
||||
** end.
|
||||
**
|
||||
** The intent of this program is to have a set of test database files that
|
||||
** can be run using future versions of SQLite in order to verify that
|
||||
** legacy database files continue to be readable. In other words, the
|
||||
** intent is to confirm that there have been no breaking changes in the
|
||||
** file format. The program can also be used to verify that database files
|
||||
** are fully compatible between different architectures.
|
||||
**
|
||||
** The selftest table looks like this:
|
||||
**
|
||||
** CREATE TABLE selftest (
|
||||
** id INTEGER PRIMARY KEY, -- Run tests in ascending order
|
||||
** op TEXT, -- "test", "regexp", "print", etc.
|
||||
** cmdtxt TEXT, -- Usually the SQL to be run
|
||||
** expected TEXT -- Expected results
|
||||
** );
|
||||
**
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
static const char zHelp[] =
|
||||
"Usage: dbselftest [OPTIONS] DBFILE ...\n"
|
||||
"\n"
|
||||
" --init Create the selftest table\n"
|
||||
" -q Suppress most output. Errors only\n"
|
||||
" -v Show extra output\n"
|
||||
;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** The following code from ext/misc/sha1.c
|
||||
**
|
||||
** Context for the SHA1 hash
|
||||
*/
|
||||
typedef struct SHA1Context SHA1Context;
|
||||
struct SHA1Context {
|
||||
unsigned int state[5];
|
||||
unsigned int count[2];
|
||||
unsigned char buffer[64];
|
||||
};
|
||||
|
||||
|
||||
#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
|
||||
/*
|
||||
* GCC by itself only generates left rotates. Use right rotates if
|
||||
* possible to be kinder to dinky implementations with iterative rotate
|
||||
* instructions.
|
||||
*/
|
||||
#define SHA_ROT(op, x, k) \
|
||||
({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
|
||||
#define rol(x,k) SHA_ROT("roll", x, k)
|
||||
#define ror(x,k) SHA_ROT("rorl", x, k)
|
||||
|
||||
#else
|
||||
/* Generic C equivalent */
|
||||
#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
|
||||
#define rol(x,k) SHA_ROT(x,k,32-(k))
|
||||
#define ror(x,k) SHA_ROT(x,32-(k),k)
|
||||
#endif
|
||||
|
||||
|
||||
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|
||||
|(rol(block[i],8)&0x00FF00FF))
|
||||
#define blk0be(i) block[i]
|
||||
#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
|
||||
^block[(i+2)&15]^block[i&15],1))
|
||||
|
||||
/*
|
||||
* (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
|
||||
*
|
||||
* Rl0() for little-endian and Rb0() for big-endian. Endianness is
|
||||
* determined at run-time.
|
||||
*/
|
||||
#define Rl0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define Rb0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R1(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R2(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
|
||||
#define R3(v,w,x,y,z,i) \
|
||||
z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
|
||||
#define R4(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
|
||||
|
||||
/*
|
||||
* Hash a single 512-bit block. This is the core of the algorithm.
|
||||
*/
|
||||
void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
|
||||
unsigned int qq[5]; /* a, b, c, d, e; */
|
||||
static int one = 1;
|
||||
unsigned int block[16];
|
||||
memcpy(block, buffer, 64);
|
||||
memcpy(qq,state,5*sizeof(unsigned int));
|
||||
|
||||
#define a qq[0]
|
||||
#define b qq[1]
|
||||
#define c qq[2]
|
||||
#define d qq[3]
|
||||
#define e qq[4]
|
||||
|
||||
/* Copy p->state[] to working vars */
|
||||
/*
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
*/
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
if( 1 == *(unsigned char*)&one ){
|
||||
Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
|
||||
Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
|
||||
Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
|
||||
Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
|
||||
}else{
|
||||
Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
|
||||
Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
|
||||
Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
|
||||
Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
|
||||
}
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
|
||||
#undef a
|
||||
#undef b
|
||||
#undef c
|
||||
#undef d
|
||||
#undef e
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a SHA1 context */
|
||||
static void hash_init(SHA1Context *p){
|
||||
/* SHA1 initialization constants */
|
||||
p->state[0] = 0x67452301;
|
||||
p->state[1] = 0xEFCDAB89;
|
||||
p->state[2] = 0x98BADCFE;
|
||||
p->state[3] = 0x10325476;
|
||||
p->state[4] = 0xC3D2E1F0;
|
||||
p->count[0] = p->count[1] = 0;
|
||||
}
|
||||
|
||||
/* Add new content to the SHA1 hash */
|
||||
static void hash_step(
|
||||
SHA1Context *p, /* Add content to this context */
|
||||
const unsigned char *data, /* Data to be added */
|
||||
unsigned int len /* Number of bytes in data */
|
||||
){
|
||||
unsigned int i, j;
|
||||
|
||||
j = p->count[0];
|
||||
if( (p->count[0] += len << 3) < j ){
|
||||
p->count[1] += (len>>29)+1;
|
||||
}
|
||||
j = (j >> 3) & 63;
|
||||
if( (j + len) > 63 ){
|
||||
(void)memcpy(&p->buffer[j], data, (i = 64-j));
|
||||
SHA1Transform(p->state, p->buffer);
|
||||
for(; i + 63 < len; i += 64){
|
||||
SHA1Transform(p->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}else{
|
||||
i = 0;
|
||||
}
|
||||
(void)memcpy(&p->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
/* Compute a string using sqlite3_vsnprintf() and hash it */
|
||||
static void hash_step_vformat(
|
||||
SHA1Context *p, /* Add content to this context */
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
va_list ap;
|
||||
int n;
|
||||
char zBuf[50];
|
||||
va_start(ap, zFormat);
|
||||
sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
|
||||
va_end(ap);
|
||||
n = (int)strlen(zBuf);
|
||||
hash_step(p, (unsigned char*)zBuf, n);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and compute the message digest. Render the
|
||||
** message digest as lower-case hexadecimal and put it into
|
||||
** zOut[]. zOut[] must be at least 41 bytes long. */
|
||||
static void hash_finish(
|
||||
SHA1Context *p, /* The SHA1 context to finish and render */
|
||||
char *zOut /* Store hexadecimal hash here */
|
||||
){
|
||||
unsigned int i;
|
||||
unsigned char finalcount[8];
|
||||
unsigned char digest[20];
|
||||
static const char zEncode[] = "0123456789abcdef";
|
||||
|
||||
for (i = 0; i < 8; i++){
|
||||
finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
hash_step(p, (const unsigned char *)"\200", 1);
|
||||
while ((p->count[0] & 504) != 448){
|
||||
hash_step(p, (const unsigned char *)"\0", 1);
|
||||
}
|
||||
hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++){
|
||||
digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
for(i=0; i<20; i++){
|
||||
zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
|
||||
zOut[i*2+1] = zEncode[digest[i] & 0xf];
|
||||
}
|
||||
zOut[i*2]= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha1(X) function.
|
||||
**
|
||||
** Return a lower-case hexadecimal rendering of the SHA1 hash of the
|
||||
** argument X. If X is a BLOB, it is hashed as is. For all other
|
||||
** types of input, X is converted into a UTF-8 string and the string
|
||||
** is hash without the trailing 0x00 terminator. The hash of a NULL
|
||||
** value is NULL.
|
||||
*/
|
||||
static void sha1Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
SHA1Context cx;
|
||||
int eType = sqlite3_value_type(argv[0]);
|
||||
int nByte = sqlite3_value_bytes(argv[0]);
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( eType==SQLITE_NULL ) return;
|
||||
hash_init(&cx);
|
||||
if( eType==SQLITE_BLOB ){
|
||||
hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
|
||||
}else{
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** Run a prepared statement and compute the SHA1 hash on the
|
||||
** result rows.
|
||||
*/
|
||||
static void sha1RunStatement(SHA1Context *pCtx, sqlite3_stmt *pStmt){
|
||||
int nCol = sqlite3_column_count(pStmt);
|
||||
const char *z = sqlite3_sql(pStmt);
|
||||
int n = (int)strlen(z);
|
||||
|
||||
hash_step_vformat(pCtx,"S%d:",n);
|
||||
hash_step(pCtx,(unsigned char*)z,n);
|
||||
|
||||
/* Compute a hash over the result of the query */
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
int i;
|
||||
hash_step(pCtx,(const unsigned char*)"R",1);
|
||||
for(i=0; i<nCol; i++){
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL: {
|
||||
hash_step(pCtx, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
hash_step(pCtx, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
hash_step(pCtx,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
|
||||
hash_step_vformat(pCtx,"T%d:",n2);
|
||||
hash_step(pCtx, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
|
||||
hash_step_vformat(pCtx,"B%d:",n2);
|
||||
hash_step(pCtx, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run one or more statements of SQL. Compute a SHA1 hash of the output.
|
||||
*/
|
||||
static int sha1Exec(
|
||||
sqlite3 *db, /* Run against this database connection */
|
||||
const char *zSql, /* The SQL to be run */
|
||||
char *zOut /* Store the SHA1 hash as hexadecimal in this buffer */
|
||||
){
|
||||
sqlite3_stmt *pStmt = 0; /* A prepared statement */
|
||||
int rc; /* Result of an API call */
|
||||
SHA1Context cx; /* The SHA1 hash context */
|
||||
|
||||
hash_init(&cx);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
sha1RunStatement(&cx, pStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha1_query(SQL) function.
|
||||
**
|
||||
** This function compiles and runs the SQL statement(s) given in the
|
||||
** argument. The results are hashed using SHA1 and that hash is returned.
|
||||
**
|
||||
** The original SQL text is included as part of the hash.
|
||||
**
|
||||
** The hash is not just a concatenation of the outputs. Each query
|
||||
** is delimited and each row and value within the query is delimited,
|
||||
** with all values being marked with their datatypes.
|
||||
*/
|
||||
static void sha1QueryFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
SHA1Context cx;
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( zSql==0 ) return;
|
||||
hash_init(&cx);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
|
||||
zSql, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
if( !sqlite3_stmt_readonly(pStmt) ){
|
||||
char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
sha1RunStatement(&cx, pStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
/* End of ext/misc/sha1.c
|
||||
******************************************************************************/
|
||||
|
||||
/* How much output to display */
|
||||
#define VOLUME_MIN 0
|
||||
#define VOLUME_OFF 0
|
||||
#define VOLUME_ERROR_ONLY 1
|
||||
#define VOLUME_LOW 2
|
||||
#define VOLUME_ECHO 3
|
||||
#define VOLUME_VERBOSE 4
|
||||
#define VOLUME_MAX 4
|
||||
|
||||
/* A string accumulator
|
||||
*/
|
||||
typedef struct Str {
|
||||
char *z; /* Accumulated text */
|
||||
int n; /* Bytes of z[] used so far */
|
||||
int nAlloc; /* Bytes allocated for z[] */
|
||||
} Str;
|
||||
|
||||
/* Append text to the Str object
|
||||
*/
|
||||
static void strAppend(Str *p, const char *z){
|
||||
int n = (int)strlen(z);
|
||||
if( p->n+n >= p->nAlloc ){
|
||||
p->nAlloc += p->n+n + 100;
|
||||
p->z = sqlite3_realloc(p->z, p->nAlloc);
|
||||
if( z==0 ){
|
||||
printf("Could not allocate %d bytes\n", p->nAlloc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
memcpy(p->z+p->n, z, n+1);
|
||||
p->n += n;
|
||||
}
|
||||
|
||||
/* This is an sqlite3_exec() callback that will capture all
|
||||
** output in a Str.
|
||||
**
|
||||
** Columns are separated by ",". Rows are separated by "|".
|
||||
*/
|
||||
static int execCallback(void *pStr, int argc, char **argv, char **colv){
|
||||
int i;
|
||||
Str *p = (Str*)pStr;
|
||||
if( p->n ) strAppend(p, "|");
|
||||
for(i=0; i<argc; i++){
|
||||
const char *z = (const char*)argv[i];
|
||||
if( z==0 ) z = "NULL";
|
||||
if( i>0 ) strAppend(p, ",");
|
||||
strAppend(p, z);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run an SQL statement constructing using sqlite3_vmprintf().
|
||||
** Return the number of errors.
|
||||
*/
|
||||
static int runSql(sqlite3 *db, const char *zFormat, ...){
|
||||
char *zSql;
|
||||
char *zErr = 0;
|
||||
int rc;
|
||||
int nErr = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ){
|
||||
printf("Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
|
||||
if( rc || zErr ){
|
||||
printf("SQL error in [%s]: code=%d: %s\n", zSql, rc, zErr);
|
||||
nErr++;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return nErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a prepared statement using a formatted string.
|
||||
*/
|
||||
static sqlite3_stmt *prepareSql(sqlite3 *db, const char *zFormat, ...){
|
||||
char *zSql;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ){
|
||||
printf("Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
printf("SQL error in [%s]: code=%d: %s\n", zSql, rc, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Construct the standard selftest configuration for the database.
|
||||
*/
|
||||
static int buildSelftestTable(sqlite3 *db){
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int tno = 110;
|
||||
char *zSql;
|
||||
char zHash[50];
|
||||
|
||||
rc = runSql(db,
|
||||
"CREATE TABLE IF NOT EXISTS selftest(\n"
|
||||
" tno INTEGER PRIMARY KEY, -- test number\n"
|
||||
" op TEXT, -- what kind of test\n"
|
||||
" sql TEXT, -- SQL text for the test\n"
|
||||
" ans TEXT -- expected answer\n"
|
||||
");"
|
||||
"INSERT INTO selftest"
|
||||
" VALUES(100,'memo','Hashes generated using --init',NULL);"
|
||||
);
|
||||
if( rc ) return 1;
|
||||
tno = 110;
|
||||
zSql = "SELECT type,name,tbl_name,sql FROM sqlite_master ORDER BY name";
|
||||
sha1Exec(db, zSql, zHash);
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'sha1',%Q,%Q)", tno, zSql, zHash);
|
||||
tno += 10;
|
||||
pStmt = prepareSql(db,
|
||||
"SELECT lower(name) FROM sqlite_master"
|
||||
" WHERE type='table' AND sql NOT GLOB 'CREATE VIRTUAL*'"
|
||||
" AND name<>'selftest'"
|
||||
" ORDER BY 1");
|
||||
if( pStmt==0 ) return 1;
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
zSql = sqlite3_mprintf("SELECT * FROM \"%w\" NOT INDEXED",
|
||||
sqlite3_column_text(pStmt, 0));
|
||||
if( zSql==0 ){
|
||||
printf("Of of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
sha1Exec(db, zSql, zHash);
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'sha1',%Q,%Q)", tno, zSql, zHash);
|
||||
tno += 10;
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) break;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
if( rc ) return 1;
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'run','PRAGMA integrity_check','ok');", tno);
|
||||
if( rc ) return 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the named table exists
|
||||
*/
|
||||
static int tableExists(sqlite3 *db, const char *zTab){
|
||||
return sqlite3_table_column_metadata(db, "main", zTab, 0, 0, 0, 0, 0, 0)
|
||||
== SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Default selftest table content, for use when there is no selftest table
|
||||
*/
|
||||
static char *azDefaultTest[] = {
|
||||
0, 0, 0, 0,
|
||||
"0", "memo", "Missing SELFTEST table - default checks only", "",
|
||||
"1", "run", "PRAGMA integrity_check", "ok"
|
||||
};
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int eVolume = VOLUME_LOW; /* How much output to display */
|
||||
const char **azDb = 0; /* Name of the database file */
|
||||
int nDb = 0; /* Number of database files to check */
|
||||
int doInit = 0; /* True if --init is present */
|
||||
sqlite3 *db = 0; /* Open database connection */
|
||||
int rc; /* Return code from API calls */
|
||||
char *zErrMsg = 0; /* An error message return */
|
||||
char **azTest; /* Content of the selftest table */
|
||||
int nRow = 0, nCol = 0; /* Rows and columns in azTest[] */
|
||||
int i; /* Loop counter */
|
||||
int nErr = 0; /* Number of errors */
|
||||
int iDb; /* Loop counter for databases */
|
||||
Str str; /* Result accumulator */
|
||||
int nTest = 0; /* Number of tests run */
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
if( z[0]=='-' ){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z, "-help")==0 ){
|
||||
printf("%s", zHelp);
|
||||
return 0;
|
||||
}else
|
||||
if( strcmp(z, "-init")==0 ){
|
||||
doInit = 1;
|
||||
}else
|
||||
if( strcmp(z, "-a")==0 ){
|
||||
if( eVolume>VOLUME_MIN) eVolume--;
|
||||
}else
|
||||
if( strcmp(z, "-v")==0 ){
|
||||
if( eVolume<VOLUME_MAX) eVolume++;
|
||||
}else
|
||||
{
|
||||
printf("unknown option: \"%s\"\nUse --help for more information\n",
|
||||
argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}else{
|
||||
nDb++;
|
||||
azDb = sqlite3_realloc(azDb, nDb*sizeof(azDb[0]));
|
||||
if( azDb==0 ){
|
||||
printf("out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
azDb[nDb-1] = argv[i];
|
||||
}
|
||||
}
|
||||
if( nDb==0 ){
|
||||
printf("No databases specified. Use --help for more info\n");
|
||||
return 1;
|
||||
}
|
||||
if( eVolume>=VOLUME_LOW ){
|
||||
printf("SQLite %s\n", sqlite3_sourceid());
|
||||
}
|
||||
memset(&str, 0, sizeof(str));
|
||||
strAppend(&str, "\n");
|
||||
for(iDb=0; iDb<nDb; iDb++, sqlite3_close(db)){
|
||||
rc = sqlite3_open_v2(azDb[iDb], &db,
|
||||
doInit ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY, 0);
|
||||
if( rc ){
|
||||
printf("Cannot open \"%s\": %s\n", azDb[iDb], sqlite3_errmsg(db));
|
||||
return 1;
|
||||
}
|
||||
rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8, 0,
|
||||
sha1Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0,
|
||||
sha1QueryFunc, 0, 0);
|
||||
}
|
||||
if( rc ){
|
||||
printf("Initialization error: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
if( doInit && !tableExists(db, "selftest") ){
|
||||
buildSelftestTable(db);
|
||||
}
|
||||
if( !tableExists(db, "selftest") ){
|
||||
azTest = azDefaultTest;
|
||||
nCol = 4;
|
||||
nRow = 2;
|
||||
}else{
|
||||
rc = sqlite3_get_table(db,
|
||||
"SELECT tno,op,sql,ans FROM selftest ORDER BY tno",
|
||||
&azTest, &nRow, &nCol, &zErrMsg);
|
||||
if( rc || zErrMsg ){
|
||||
printf("Error querying selftest: %s\n", zErrMsg);
|
||||
sqlite3_free_table(azTest);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for(i=1; i<=nRow; i++){
|
||||
int tno = atoi(azTest[i*nCol]);
|
||||
const char *zOp = azTest[i*nCol+1];
|
||||
const char *zSql = azTest[i*nCol+2];
|
||||
const char *zAns = azTest[i*nCol+3];
|
||||
|
||||
if( eVolume>=VOLUME_ECHO ){
|
||||
char *zQuote = sqlite3_mprintf("%q", zSql);
|
||||
printf("%d: %s %s\n", tno, zOp, zSql);
|
||||
sqlite3_free(zQuote);
|
||||
}
|
||||
if( strcmp(zOp,"memo")==0 ){
|
||||
if( eVolume>=VOLUME_LOW ){
|
||||
printf("%s: %s\n", azDb[iDb], zSql);
|
||||
}
|
||||
}else
|
||||
if( strcmp(zOp,"sha1")==0 ){
|
||||
char zOut[44];
|
||||
rc = sha1Exec(db, zSql, zOut);
|
||||
nTest++;
|
||||
if( eVolume>=VOLUME_VERBOSE ){
|
||||
printf("Result: %s\n", zOut);
|
||||
}
|
||||
if( rc ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: error-code-%d: %s\n", tno, rc, sqlite3_errmsg(db));
|
||||
}
|
||||
}else if( strcmp(zAns,zOut)!=0 ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: Expected: [%s]\n", tno, zAns);
|
||||
printf("%d: Got: [%s]\n", tno, zOut);
|
||||
}
|
||||
}
|
||||
}else
|
||||
if( strcmp(zOp,"run")==0 ){
|
||||
str.n = 0;
|
||||
str.z[0] = 0;
|
||||
zErrMsg = 0;
|
||||
rc = sqlite3_exec(db, zSql, execCallback, &str, &zErrMsg);
|
||||
nTest++;
|
||||
if( eVolume>=VOLUME_VERBOSE ){
|
||||
printf("Result: %s\n", str.z);
|
||||
}
|
||||
if( rc || zErrMsg ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: error-code-%d: %s\n", tno, rc, zErrMsg);
|
||||
}
|
||||
sqlite3_free(zErrMsg);
|
||||
}else if( strcmp(zAns,str.z)!=0 ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: Expected: [%s]\n", tno, zAns);
|
||||
printf("%d: Got: [%s]\n", tno, str.z);
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
printf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( azTest!=azDefaultTest ) sqlite3_free_table(azTest);
|
||||
}
|
||||
if( eVolume>=VOLUME_LOW || (nErr>0 && eVolume>=VOLUME_ERROR_ONLY) ){
|
||||
printf("%d errors out of %d tests on %d databases\n", nErr, nTest, nDb);
|
||||
}
|
||||
return nErr;
|
||||
}
|
||||
+30
-11
@@ -6,12 +6,33 @@
|
||||
#include <stdint.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/* Return the current real-world time in milliseconds since the
|
||||
** Julian epoch (-4714-11-24).
|
||||
*/
|
||||
static sqlite3_int64 timeOfDay(void){
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
|
||||
clockVfs->xCurrentTimeInt64(clockVfs, &t);
|
||||
}else{
|
||||
double r;
|
||||
clockVfs->xCurrentTime(clockVfs, &r);
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
/*
|
||||
** Progress handler callback
|
||||
** Progress handler callback.
|
||||
**
|
||||
** The argument is the cutoff-time after which all processing should
|
||||
** stop. So return non-zero if the cut-off time is exceeded.
|
||||
*/
|
||||
static int progress_handler(void *pReturn) {
|
||||
return *(int*)pReturn;
|
||||
sqlite3_int64 iCutoffTime = *(sqlite3_int64*)pReturn;
|
||||
return timeOfDay()>=iCutoffTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -31,13 +52,13 @@ static int exec_handler(void *pCnt, int argc, char **argv, char **namev){
|
||||
** fuzzed input.
|
||||
*/
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
int progressArg = 0; /* 1 causes progress handler abort */
|
||||
int execCnt = 0; /* Abort row callback when count reaches zero */
|
||||
char *zErrMsg = 0; /* Error message returned by sqlite_exec() */
|
||||
sqlite3 *db; /* The database connection */
|
||||
uint8_t uSelector; /* First byte of input data[] */
|
||||
int rc; /* Return code from various interfaces */
|
||||
char *zSql; /* Zero-terminated copy of data[] */
|
||||
sqlite3_int64 iCutoff; /* Cutoff timer */
|
||||
|
||||
if( size<3 ) return 0; /* Early out if unsufficient data */
|
||||
|
||||
@@ -56,16 +77,14 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
if( rc ) return 0;
|
||||
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
/* Bit 0 of the selector enables progress callbacks. Bit 1 is the
|
||||
** return code from progress callbacks */
|
||||
if( uSelector & 1 ){
|
||||
sqlite3_progress_handler(db, 4, progress_handler, (void*)&progressArg);
|
||||
}
|
||||
/* Invoke the progress handler every 500 thousand instructions (approximately
|
||||
** 20 to 40 times per second) to check to see if we are taking too long.
|
||||
*/
|
||||
iCutoff = timeOfDay() + 10000; /* Now + 10 seconds */
|
||||
sqlite3_progress_handler(db, 500000, progress_handler, (void*)&iCutoff);
|
||||
#endif
|
||||
uSelector >>= 1;
|
||||
progressArg = uSelector & 1; uSelector >>= 1;
|
||||
|
||||
/* Bit 2 of the selector enables foreign key constraints */
|
||||
/* Bit 1 of the selector enables foreign key constraints */
|
||||
sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc);
|
||||
uSelector >>= 1;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user