Compare commits

...

10 Commits

Author SHA1 Message Date
drh 708b22b1e3 The output of the ".dump" command in the CLI quotes newline and carriage-return
characters using "char(10)" and "char(13)".

FossilOrigin-Name: 8b2954dd8376e2de985cf5dedeb6eec32c430505
2017-03-11 01:56:41 +00:00
drh 891d6b4e9e Increase the number of significant digits in floating point literals on
".dump" output from the shell.

FossilOrigin-Name: 7359fcacaadc349f520536311dcd1d0b5cea7673
2017-03-11 00:46:57 +00:00
dan 1ba30db8bd Remove the rbu_round_trip.tcl script. It is now part of project "test-dbs".
FossilOrigin-Name: b5bf2957677e8f2acd7426b302229a966de08fd9
2017-03-10 18:36:34 +00:00
drh a6bf20b587 Fix an error in the SQLITE_MAX_MEMORY implementation resulting from a bad
merge.  Update the OSSFuzz interface so that it times out after running
the byte-code engine for 10 seconds.

FossilOrigin-Name: f8560c60d10c0365b33342ab05b5a953987b0471
2017-03-10 17:03:11 +00:00
drh 1e45c7db56 Add the -DSQLITE_MAX_MEMORY=N compile-time option. The default is no limit.
FossilOrigin-Name: eabd4ef498a0f0d97d65e321c4d06ab90523ed61
2017-03-10 16:22:40 +00:00
drh e43d6aee45 Add the SQLITE_MAX_MEMORY compile-time option that provides a hard upper bound
on the amount of memory that SQLite will use, per process.

FossilOrigin-Name: 77dfe2abdae88dea81217f352d87e5ba2c822715
2017-03-10 15:55:54 +00:00
drh a2df53bd61 Enhance the ".stats" dot-command in the CLI to use sqlite3_status64() instead
of sqlite3_status().

FossilOrigin-Name: 118f5c0564fef70cbd06fc0d9dbb2baec162cc39
2017-03-10 14:36:10 +00:00
drh f157d10f9f Improvements to ".selftest --init". Tests are number in increments of 10
starting with 100.  The tests are generated inside a SAVEPOINT.  Errors are
reported during test generation.  Tests can be appended to existing tests.
Add a test case to verify the schema.

FossilOrigin-Name: b044b152aac2ec606750940ea816ad4a4aef8eb6
2017-03-10 01:05:38 +00:00
drh fb546afb4d Remove the test/dbselftest.c program. In its place, add the ".selftest"
command to the CLI.  The new CLI version is .selftest is slightly different
in that it uses SHA3 hashing instead of SHA1, so the new is subtly 
incompatible with the old.

FossilOrigin-Name: f4fcd46f08ba59d2a3e772cad98383129f648386
2017-03-09 22:00:33 +00:00
drh f8563c00b2 Fix the ".dump" command to correctly extract tail data from corrupt
WITHOUT ROWID tables.

FossilOrigin-Name: 6c627e50622d8bcd25ec7d5503f3fafd725673a8
2017-03-09 18:13:52 +00:00
10 changed files with 341 additions and 1091 deletions
+1 -5
View File
@@ -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
View File
@@ -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
-205
View File
@@ -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."
+1 -5
View File
@@ -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)
+14 -13
View File
@@ -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
View File
@@ -1 +1 @@
50eec5d9aa38fab1a85d788356ffdaf6c35d9ece
8b2954dd8376e2de985cf5dedeb6eec32c430505
+7
View File
@@ -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
View File
@@ -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");
-786
View File
@@ -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
View File
@@ -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;