Compare commits
109 Commits
rtree-fix
...
multi-drop
| Author | SHA1 | Date | |
|---|---|---|---|
| 4760a0655f | |||
| 313aaff7cd | |||
| 4859e9c642 | |||
| 3ffea6bc31 | |||
| c5c3cde0e3 | |||
| 29962f9194 | |||
| 0809210f9d | |||
| b3e1f4cc3c | |||
| b0f9538628 | |||
| 19fb027eb5 | |||
| c3004fc223 | |||
| 6b4c974bec | |||
| 91d7bd8ec7 | |||
| 087e6c9ada | |||
| 09a71d8d44 | |||
| 8597eee119 | |||
| b542933cba | |||
| 6324cdfdcd | |||
| 2aea6083bd | |||
| 39670a5345 | |||
| 8732fce985 | |||
| f8dc7d20f7 | |||
| 5b985fee64 | |||
| 1ffaa03adc | |||
| 32888c2b30 | |||
| f79b0bdcbf | |||
| 7c6433cfff | |||
| 09e1900cdc | |||
| 1103eb423e | |||
| f286ad9211 | |||
| afeec79847 | |||
| dfd991c3b9 | |||
| 7598e7d70e | |||
| 9c59c87448 | |||
| ee299cc7d4 | |||
| 645f21f15b | |||
| b088e892a0 | |||
| 5956d1d942 | |||
| 1545243368 | |||
| f7ad684c5a | |||
| 0b8c3126f4 | |||
| 639db50a02 | |||
| 9591a9f069 | |||
| 6a00f707e8 | |||
| b783f56c58 | |||
| b2897c221d | |||
| ebd99d5708 | |||
| eb715f022f | |||
| cfcb3b9208 | |||
| 626d619218 | |||
| 21eda699d7 | |||
| b468e68322 | |||
| 4b2eeb289b | |||
| 68d92c4ad3 | |||
| 4189c44cff | |||
| ae71fa5d59 | |||
| a1507a3fa0 | |||
| ebea8458e2 | |||
| 9a28311b6a | |||
| 74b0aad09f | |||
| f40da9226d | |||
| cfc62ceefd | |||
| e7bdb2172c | |||
| 6c6356f7f2 | |||
| 9f34a05e98 | |||
| e0a9935be1 | |||
| d43e7adca7 | |||
| 99a94a124c | |||
| 42eb6a91cd | |||
| 6161cdd446 | |||
| 837efb4cbe | |||
| 4dd59fd997 | |||
| fd2500f98b | |||
| 816f677c1c | |||
| 9d00aba895 | |||
| 5e5831a760 | |||
| 95b5295f52 | |||
| 54eb54c7de | |||
| 8e821c251d | |||
| 98a8ffb3b3 | |||
| 38e0492b91 | |||
| 84dea8264b | |||
| b29047838d | |||
| 18b6019cdd | |||
| 3c5a810646 | |||
| ece3567aec | |||
| 589c407f12 | |||
| 25e172d429 | |||
| 0f777cd622 | |||
| 722bd1fe89 | |||
| 204b41955e | |||
| 71cdea8f5f | |||
| 8babc01892 | |||
| 72c7bb3e1a | |||
| db9cc74c9c | |||
| 5e922865aa | |||
| d90ecb5d6e | |||
| 406eb5a146 | |||
| a545de6827 | |||
| 8374f7dfaf | |||
| fbb72fae8f | |||
| 87ad06ed99 | |||
| 17589f7811 | |||
| b75dc61a53 | |||
| 95295a7e9b | |||
| 3eae6664a0 | |||
| 45cf8ad02a | |||
| 2065a9b730 | |||
| 87ac2b043a |
+6
-2
@@ -418,6 +418,8 @@ TESTSRC = \
|
||||
$(TOP)/ext/recover/sqlite3recover.c \
|
||||
$(TOP)/ext/recover/dbdata.c \
|
||||
$(TOP)/ext/recover/test_recover.c \
|
||||
$(TOP)/ext/intck/test_intck.c \
|
||||
$(TOP)/ext/intck/sqlite3intck.c \
|
||||
$(TOP)/ext/rbu/test_rbu.c
|
||||
|
||||
# Statically linked extensions
|
||||
@@ -815,7 +817,8 @@ has_tclsh85:
|
||||
touch .target_source
|
||||
|
||||
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl src-verify has_tclsh84
|
||||
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS)
|
||||
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS) \
|
||||
$(EXTRA_SRC)
|
||||
cp tsrc/sqlite3ext.h .
|
||||
cp $(TOP)/ext/session/sqlite3session.h .
|
||||
|
||||
@@ -826,7 +829,8 @@ sqlite3r.c: sqlite3.c sqlite3r.h has_tclsh84
|
||||
cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
|
||||
cp $(TOP)/ext/recover/sqlite3recover.h tsrc/
|
||||
cp $(TOP)/ext/recover/dbdata.c tsrc/
|
||||
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover $(AMALGAMATION_LINE_MACROS)
|
||||
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover \
|
||||
$(AMALGAMATION_LINE_MACROS) $(EXTRA_SRC)
|
||||
|
||||
sqlite3ext.h: .target_source
|
||||
cp tsrc/sqlite3ext.h .
|
||||
|
||||
+10
-1
@@ -18,6 +18,13 @@ USE_AMALGAMATION = 1
|
||||
!ENDIF
|
||||
# <</mark>>
|
||||
|
||||
# Optionally set EXTRA_SRC to a list of C files to append to
|
||||
# the generated sqlite3.c.
|
||||
#
|
||||
!IFNDEF EXTRA_SRC
|
||||
EXTRA_SRC =
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
|
||||
#
|
||||
!IFNDEF USE_FULLWARN
|
||||
@@ -1595,6 +1602,8 @@ TESTEXT = \
|
||||
$(TOP)\ext\rtree\test_rtreedoc.c \
|
||||
$(TOP)\ext\recover\sqlite3recover.c \
|
||||
$(TOP)\ext\recover\test_recover.c \
|
||||
$(TOP)\ext\intck\test_intck.c \
|
||||
$(TOP)\ext\intck\sqlite3intck.c \
|
||||
$(TOP)\ext\recover\dbdata.c
|
||||
|
||||
# If use of zlib is enabled, add the "zipfile.c" source file.
|
||||
@@ -1913,7 +1922,7 @@ mptest: mptester.exe
|
||||
echo > .target_source
|
||||
|
||||
sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-verify.exe
|
||||
$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS)
|
||||
$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS) $(EXTRA_SRC)
|
||||
|
||||
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
|
||||
$(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
@@ -18,6 +18,13 @@
|
||||
TOP = .
|
||||
|
||||
|
||||
# Optionally set EXTRA_SRC to a list of C files to append to
|
||||
# the generated sqlite3.c.
|
||||
#
|
||||
!IFNDEF EXTRA_SRC
|
||||
EXTRA_SRC =
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
|
||||
#
|
||||
!IFNDEF USE_FULLWARN
|
||||
|
||||
@@ -6837,23 +6837,26 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
|
||||
static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
|
||||
int ii;
|
||||
Fts5TokenDataIter *pT = pIter->pTokenDataIter;
|
||||
Fts5Index *pIndex = pIter->pIndex;
|
||||
|
||||
for(ii=0; ii<pT->nIter; ii++){
|
||||
Fts5Iter *p = pT->apIter[ii];
|
||||
if( p->base.bEof==0
|
||||
&& (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom))
|
||||
){
|
||||
fts5MultiIterNext(p->pIndex, p, bFrom, iFrom);
|
||||
fts5MultiIterNext(pIndex, p, bFrom, iFrom);
|
||||
while( bFrom && p->base.bEof==0
|
||||
&& p->base.iRowid<iFrom
|
||||
&& p->pIndex->rc==SQLITE_OK
|
||||
&& pIndex->rc==SQLITE_OK
|
||||
){
|
||||
fts5MultiIterNext(p->pIndex, p, 0, 0);
|
||||
fts5MultiIterNext(pIndex, p, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fts5IterSetOutputsTokendata(pIter);
|
||||
if( pIndex->rc==SQLITE_OK ){
|
||||
fts5IterSetOutputsTokendata(pIter);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -127,7 +127,7 @@ do_execsql_test 3.0 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_faultsim_test 3 -faults oom* -prep {
|
||||
do_faultsim_test 3.1 -faults oom* -prep {
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT rowid FROM t1('BBB AND AAA');
|
||||
@@ -136,6 +136,15 @@ do_faultsim_test 3 -faults oom* -prep {
|
||||
faultsim_integrity_check
|
||||
faultsim_test_result {0 {10 35}}
|
||||
}
|
||||
do_faultsim_test 3.2 -faults oom* -prep {
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT count(*) FROM t1('BBB');
|
||||
}
|
||||
} -test {
|
||||
faultsim_integrity_check
|
||||
faultsim_test_result {0 27}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
# 2008 Feb 19
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The focus of this file is testing the incremental integrity check
|
||||
# (intck) extension.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] intck_common.tcl]
|
||||
set testprefix intck1
|
||||
|
||||
foreach {tn sql} {
|
||||
1 "CREATE TABLE t1(a PRIMARY KEY, b)"
|
||||
2 "CREATE TABLE t2(a PRIMARY KEY, b) WITHOUT ROWID "
|
||||
3 "CREATE TABLE t3(a PRIMARY KEY, b) WITHOUT rowID;"
|
||||
4 "CREATE TABLE t4(a PRIMARY KEY, ROWID)"
|
||||
5 {CREATE TABLE t5(a PRIMARY KEY, ROWID) WITHOUT ROWID
|
||||
}
|
||||
} {
|
||||
do_test 1.1.$tn {
|
||||
db eval $sql
|
||||
set {} {}
|
||||
} {}
|
||||
}
|
||||
|
||||
set space " \n\v\t\r\f"
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT name, (rtrim(sql, $space) LIKE '%rowid')
|
||||
FROM sqlite_schema WHERE type='table'
|
||||
ORDER BY 1
|
||||
} {
|
||||
t1 0
|
||||
t2 1
|
||||
t3 1
|
||||
t4 0
|
||||
t5 1
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
CREATE TABLE x1(a COLLATE nocase, b INTEGER, c BLOB);
|
||||
INSERT INTO x1 VALUES('lEtTeRs', 1234, 1234);
|
||||
}
|
||||
do_execsql_test 1.3.1 {
|
||||
WITH wrapper(c1, c2, c3) AS (
|
||||
SELECT a, b, c FROM x1
|
||||
)
|
||||
SELECT * FROM wrapper WHERE c1='letters';
|
||||
} {lEtTeRs 1234 1234}
|
||||
do_execsql_test 1.3.2 {
|
||||
WITH wrapper(c1, c2, c3) AS (
|
||||
SELECT a, b, c FROM x1
|
||||
)
|
||||
SELECT * FROM wrapper WHERE c2='1234';
|
||||
} {lEtTeRs 1234 1234}
|
||||
do_execsql_test 1.3.2 {
|
||||
WITH wrapper(c1, c2, c3) AS (
|
||||
SELECT a, b, c FROM x1
|
||||
)
|
||||
SELECT * FROM wrapper WHERE c3='1234';
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
CREATE TABLE z1(a, b);
|
||||
CREATE INDEX z1ab ON z1(a+b COLLATE nocase);
|
||||
}
|
||||
do_execsql_test 1.4.1 {
|
||||
SELECT * FROM z1 INDEXED BY z1ab
|
||||
}
|
||||
|
||||
do_catchsql_test 1.5.1 {
|
||||
CREATE INDEX z1b ON z1(b ASC NULLS LAST);
|
||||
} {1 {unsupported use of NULLS LAST}}
|
||||
do_catchsql_test 1.5.2 {
|
||||
CREATE INDEX z1b ON z1(b DESC NULLS LAST);
|
||||
} {1 {unsupported use of NULLS LAST}}
|
||||
do_catchsql_test 1.5.3 {
|
||||
CREATE INDEX z1b ON z1(b ASC NULLS FIRST);
|
||||
} {1 {unsupported use of NULLS FIRST}}
|
||||
do_catchsql_test 1.5.4 {
|
||||
CREATE INDEX z1b ON z1(b DESC NULLS FIRST);
|
||||
} {1 {unsupported use of NULLS FIRST}}
|
||||
|
||||
|
||||
reset_db
|
||||
do_execsql_test 1.6.1 {
|
||||
CREATE TABLE t1(i INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
ANALYZE;
|
||||
INSERT INTO sqlite_stat1 VALUES('t1', 'i1', '10000 10000');
|
||||
ANALYZE sqlite_schema;
|
||||
} {}
|
||||
do_eqp_test 1.6.2 {
|
||||
SELECT 1 FROM t1 INDEXED BY i1 WHERE (b, i) IS (?, ?);
|
||||
} {SEARCH}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_test 2.0 {
|
||||
set ic [sqlite3_intck db main]
|
||||
$ic close
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
|
||||
CREATE INDEX i1 ON t1(a COLLATE nocase);
|
||||
CREATE INDEX i2 ON t1(b, a);
|
||||
CREATE INDEX i3 ON t1(b + a COLLATE nocase) WHERE a!=1;
|
||||
}
|
||||
|
||||
do_intck_test 2.2 {
|
||||
}
|
||||
|
||||
# Delete a row from each of the i1 and i2 indexes using the imposter
|
||||
# table interface.
|
||||
#
|
||||
do_test 2.3 {
|
||||
db eval {SELECT name, rootpage FROM sqlite_schema} {
|
||||
set R($name) $rootpage
|
||||
}
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(i1)
|
||||
db eval { CREATE TABLE imp1(a PRIMARY KEY, rowid) WITHOUT ROWID; }
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(i2)
|
||||
db eval { CREATE TABLE imp2(b, a, rowid, PRIMARY KEY(b, a)) WITHOUT ROWID; }
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
|
||||
db eval {
|
||||
DELETE FROM imp1 WHERE rowid=1;
|
||||
DELETE FROM imp2 WHERE rowid=2;
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
} {}
|
||||
|
||||
do_intck_test 2.4 {
|
||||
{entry (1,1) missing from index i1}
|
||||
{entry (4,3,2) missing from index i2}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE x1(a, b, c, PRIMARY KEY(c, b)) WITHOUT ROWID;
|
||||
CREATE INDEX x1a ON x1(a COLLATE nocase);
|
||||
|
||||
INSERT INTO x1 VALUES(1, 2, 'three');
|
||||
INSERT INTO x1 VALUES(4, 5, 'six');
|
||||
INSERT INTO x1 VALUES(7, 8, 'nine');
|
||||
}
|
||||
|
||||
do_intck_test 3.1 { }
|
||||
|
||||
do_test 3.2 {
|
||||
db eval {SELECT name, rootpage FROM sqlite_schema} {
|
||||
set R($name) $rootpage
|
||||
}
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(x1a)
|
||||
db eval { CREATE TABLE imp1(c, b, a, PRIMARY KEY(c, b)) WITHOUT ROWID }
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
|
||||
db eval {
|
||||
DELETE FROM imp1 WHERE a=5;
|
||||
}
|
||||
execsql_pp {
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
} {}
|
||||
|
||||
do_intck_test 3.3 {
|
||||
{entry (4,'six',5) missing from index x1a}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE www(x, y, z);
|
||||
CREATE INDEX w1 ON www( (x+1), z );
|
||||
INSERT INTO www VALUES(1, 1, 1), (2, 2, 2);
|
||||
}
|
||||
|
||||
do_intck_test 4.1 { }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a COLLATE NOCASE);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
}
|
||||
|
||||
do_test 5.1 {
|
||||
set ic [sqlite3_intck db nosuchdb]
|
||||
$ic step
|
||||
} {SQLITE_ERROR}
|
||||
|
||||
do_test 5.2 {
|
||||
$ic close
|
||||
set ic [sqlite3_intck db {}]
|
||||
while {[$ic step]=="SQLITE_OK"} {}
|
||||
set res [$ic error]
|
||||
$ic close
|
||||
set res
|
||||
} {SQLITE_OK {}}
|
||||
|
||||
do_test 5.3 { test_do_intck db "main" } {}
|
||||
|
||||
do_test 5.4 {
|
||||
set ret {}
|
||||
set ic [sqlite3_intck db main]
|
||||
db eval [$ic test_sql t1] {
|
||||
if {$error_message!=""} { lappend ret $error_message }
|
||||
}
|
||||
$ic close
|
||||
set ret
|
||||
} {}
|
||||
|
||||
do_test 5.5 {
|
||||
set ret {}
|
||||
set ic [sqlite3_intck db main]
|
||||
db eval [$ic test_sql {}] {
|
||||
if {$error_message!=""} { lappend ret $error_message }
|
||||
}
|
||||
$ic close
|
||||
set ret
|
||||
} {}
|
||||
|
||||
db cache flush
|
||||
|
||||
do_test 5.6 {
|
||||
set ret {}
|
||||
set ic [sqlite3_intck db main]
|
||||
$ic step
|
||||
db eval [$ic test_sql {}] {
|
||||
if {$error_message!=""} { lappend ret $error_message }
|
||||
}
|
||||
$ic close
|
||||
set ret
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 6.0 {
|
||||
CREATE TABLE t1(x, y, PRIMARY KEY(x)) WITHOUT ROWID;
|
||||
CREATE INDEX i1 ON t1(y, x);
|
||||
INSERT INTO t1 VALUES(X'0000', X'1111');
|
||||
}
|
||||
|
||||
do_intck_test 6.1 {}
|
||||
|
||||
do_execsql_test 6.2.1 {
|
||||
PRAGMA writable_schema = 1;
|
||||
UPDATE sqlite_schema SET sql = 'CREATE INDEX i1' WHERE name='i1';
|
||||
} {}
|
||||
do_intck_test 6.2.2 {}
|
||||
|
||||
do_execsql_test 6.3.1 {
|
||||
UPDATE sqlite_schema SET sql = 'CREATE INDEX i1(y' WHERE name='i1';
|
||||
} {}
|
||||
do_intck_test 6.3.2 {}
|
||||
|
||||
do_execsql_test 6.4.1 {
|
||||
UPDATE sqlite_schema
|
||||
SET sql = 'CREATE INDEX i1(y) hello world'
|
||||
WHERE name='i1';
|
||||
} {}
|
||||
do_intck_test 6.4.2 {}
|
||||
|
||||
do_execsql_test 6.5.1 {
|
||||
UPDATE sqlite_schema
|
||||
SET sql = 'CREATE INDEX i1(y, x) WHERE 1 '
|
||||
WHERE name='i1';
|
||||
} {}
|
||||
do_intck_test 6.5.2 {}
|
||||
|
||||
do_execsql_test 6.6.1 {
|
||||
UPDATE sqlite_schema
|
||||
SET sql = 'CREATE INDEX i1( , ) WHERE 1 '
|
||||
WHERE name='i1';
|
||||
} {}
|
||||
|
||||
do_test 6.7.2 {
|
||||
set ic [sqlite3_intck db main]
|
||||
$ic step
|
||||
} {SQLITE_ERROR}
|
||||
do_test 6.5.3 {
|
||||
$ic error
|
||||
} {SQLITE_ERROR {near "AS": syntax error}}
|
||||
$ic close
|
||||
|
||||
do_execsql_test 6.6.1 {
|
||||
UPDATE sqlite_schema
|
||||
SET sql = 'CREATE INDEX i1([y'
|
||||
WHERE name='i1';
|
||||
} {}
|
||||
do_intck_test 6.6.2 {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE x1("1", "22", "3333", four);
|
||||
CREATE INDEX i1 ON x1( "1" , "22", NULL);
|
||||
INSERT INTO x1 VALUES(1, 22, 3333, NULL);
|
||||
INSERT INTO x1 VALUES(1, 22, 3333, NULL);
|
||||
}
|
||||
do_execsql_test 7.1 " CREATE INDEX i2 ON x1( \"1\"\r\n\t ) "
|
||||
do_execsql_test 7.2 { CREATE INDEX i3 ON x1( "22" || 'abc''def' || `1` ) }
|
||||
do_execsql_test 7.3 { CREATE INDEX i4 ON x1( [22] + [1] ) }
|
||||
do_execsql_test 7.4 { CREATE INDEX i5 ON x1( four||'hello' ) }
|
||||
|
||||
do_intck_test 7.5 {}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,176 @@
|
||||
# 2024 Feb 19
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The focus of this file is testing the incremental integrity check
|
||||
# (intck) extension.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] intck_common.tcl]
|
||||
set testprefix intck2
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
}
|
||||
|
||||
proc imposter_edit {obj create sql} {
|
||||
sqlite3 xdb test.db
|
||||
set pgno [xdb one {SELECT rootpage FROM sqlite_schema WHERE name=$obj}]
|
||||
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER xdb main 1 $pgno
|
||||
xdb eval $create
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER xdb main 0 0
|
||||
xdb eval $sql
|
||||
xdb close
|
||||
}
|
||||
|
||||
imposter_edit i1 {
|
||||
CREATE TABLE imp(b, a, PRIMARY KEY(b)) WITHOUT ROWID;
|
||||
} {
|
||||
DELETE FROM imp WHERE b='two';
|
||||
INSERT INTO imp(b, a) VALUES('four', 4);
|
||||
}
|
||||
|
||||
do_intck_test 1.1 {
|
||||
{surplus entry ('four',4) in index i1}
|
||||
{entry ('two',2) missing from index i1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE x1(a, b, "c d");
|
||||
CREATE INDEX x1a ON x1(a COLLATE nocase DESC , b ASC);
|
||||
CREATE INDEX x1b ON x1( a || b || ' "''" ' COLLATE binary ASC );
|
||||
CREATE INDEX x1c ON x1( format('%s', a)ASC, format('%d', "c d" ) );
|
||||
INSERT INTO x1 VALUES('one', 2, 3);
|
||||
INSERT INTO x1 VALUES('One', 4, 5);
|
||||
INSERT INTO x1 VALUES('ONE', 6, 7);
|
||||
INSERT INTO x1 VALUES(NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
do_intck_test 2.1 {}
|
||||
|
||||
imposter_edit x1 {
|
||||
CREATE TABLE imp(a, b, c);
|
||||
} {
|
||||
DELETE FROM imp WHERE c=7;
|
||||
}
|
||||
do_intck_test 2.2 {
|
||||
{surplus entry ('ONE',6,3) in index x1a}
|
||||
{surplus entry ('ONE6 "''" ',3) in index x1b}
|
||||
{surplus entry ('ONE','7',3) in index x1c}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE x1(a, b, c);
|
||||
CREATE INDEX x1all ON x1(a DESC, b ASC, c DESC);
|
||||
INSERT INTO x1 VALUES(2, 1, 2);
|
||||
INSERT INTO x1 VALUES(2, 1, 1);
|
||||
INSERT INTO x1 VALUES(2, 2, 2);
|
||||
INSERT INTO x1 VALUES(2, 2, 1);
|
||||
INSERT INTO x1 VALUES(1, 1, 2);
|
||||
INSERT INTO x1 VALUES(1, 1, 1);
|
||||
INSERT INTO x1 VALUES(1, 2, 2);
|
||||
INSERT INTO x1 VALUES(1, 2, 1);
|
||||
}
|
||||
|
||||
do_intck_test 3.1 {
|
||||
}
|
||||
|
||||
imposter_edit x1 {
|
||||
CREATE TABLE imp(a, b, c);
|
||||
} {
|
||||
DELETE FROM imp WHERE 1;
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_intck_test 3.2 {
|
||||
{surplus entry (2,1,2,1) in index x1all}
|
||||
{surplus entry (2,1,1,2) in index x1all}
|
||||
{surplus entry (2,2,2,3) in index x1all}
|
||||
{surplus entry (2,2,1,4) in index x1all}
|
||||
{surplus entry (1,1,2,5) in index x1all}
|
||||
{surplus entry (1,1,1,6) in index x1all}
|
||||
{surplus entry (1,2,2,7) in index x1all}
|
||||
{surplus entry (1,2,1,8) in index x1all}
|
||||
}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
DELETE FROM x1;
|
||||
INSERT INTO x1 VALUES(NULL, NULL, NULL);
|
||||
INSERT INTO x1 VALUES(NULL, NULL, NULL);
|
||||
INSERT INTO x1 VALUES(NULL, NULL, NULL);
|
||||
INSERT INTO x1 VALUES(NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
do_intck_test 3.4 {
|
||||
}
|
||||
|
||||
imposter_edit x1 {
|
||||
CREATE TABLE imp(a, b, c);
|
||||
} {
|
||||
DELETE FROM imp WHERE 1;
|
||||
INSERT INTO imp(rowid) VALUES(-123);
|
||||
INSERT INTO imp(rowid) VALUES(456);
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_intck_test 3.5 {
|
||||
{entry (NULL,NULL,NULL,-123) missing from index x1all}
|
||||
{entry (NULL,NULL,NULL,456) missing from index x1all}
|
||||
{surplus entry (NULL,NULL,NULL,1) in index x1all}
|
||||
{surplus entry (NULL,NULL,NULL,2) in index x1all}
|
||||
{surplus entry (NULL,NULL,NULL,3) in index x1all}
|
||||
{surplus entry (NULL,NULL,NULL,4) in index x1all}
|
||||
}
|
||||
|
||||
reset_db
|
||||
|
||||
do_execsql_test 3.6 {
|
||||
CREATE TABLE w1(a PRIMARY KEY, b, c);
|
||||
INSERT INTO w1 VALUES(1.0, NULL, NULL);
|
||||
INSERT INTO w1 VALUES(33.0, NULL, NULL);
|
||||
INSERT INTO w1 VALUES(100.0, NULL, NULL);
|
||||
CREATE INDEX w1bc ON w1(b, c);
|
||||
}
|
||||
|
||||
do_intck_test 3.7 {
|
||||
}
|
||||
|
||||
imposter_edit w1 {
|
||||
CREATE TABLE imp(a, b, c);
|
||||
} {
|
||||
DELETE FROM imp WHERE a=33;
|
||||
INSERT INTO imp(a) VALUES(1234.5);
|
||||
INSERT INTO imp(a) VALUES(-1234.5);
|
||||
}
|
||||
|
||||
do_intck_test 3.8 {
|
||||
{surplus entry (33.0,2) in index sqlite_autoindex_w1_1}
|
||||
{entry (1234.5,4) missing from index sqlite_autoindex_w1_1}
|
||||
{entry (NULL,NULL,4) missing from index w1bc}
|
||||
{entry (-1234.5,5) missing from index sqlite_autoindex_w1_1}
|
||||
{entry (NULL,NULL,5) missing from index w1bc}
|
||||
{surplus entry (NULL,NULL,2) in index w1bc}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,56 @@
|
||||
# 2024 Feb 18
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
|
||||
proc do_intck {db {bSuspend 0}} {
|
||||
set ic [sqlite3_intck $db main]
|
||||
|
||||
set ret [list]
|
||||
while {"SQLITE_OK"==[$ic step]} {
|
||||
set msg [$ic message]
|
||||
if {$msg!=""} {
|
||||
lappend ret $msg
|
||||
}
|
||||
if {$bSuspend} {
|
||||
$ic unlock
|
||||
#puts "SQL: [$ic test_sql {}]"
|
||||
#execsql_pp "EXPLAIN query plan [$ic test_sql {}]"
|
||||
#explain_i [$ic test_sql {}]
|
||||
}
|
||||
}
|
||||
|
||||
set err [$ic error]
|
||||
if {[lindex $err 0]!="SQLITE_OK"} {
|
||||
error $err
|
||||
}
|
||||
$ic close
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
proc intck_sql {db tbl} {
|
||||
set ic [sqlite3_intck $db main]
|
||||
set sql [$ic test_sql $tbl]
|
||||
$ic close
|
||||
return $sql
|
||||
}
|
||||
|
||||
proc do_intck_test {tn expect} {
|
||||
uplevel [list do_test $tn.a [list do_intck db] [list {*}$expect]]
|
||||
uplevel [list do_test $tn.b [list do_intck db 1] [list {*}$expect]]
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# 2024 February 24
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] intck_common.tcl]
|
||||
set testprefix intckbusy
|
||||
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(2, 'two', 'three');
|
||||
INSERT INTO t1 VALUES(3, NULL, NULL);
|
||||
CREATE INDEX i1 ON t1(b, c);
|
||||
}
|
||||
|
||||
sqlite3 db2 test.db
|
||||
|
||||
do_execsql_test -db db2 1.1 {
|
||||
BEGIN EXCLUSIVE;
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
}
|
||||
|
||||
do_test 1.2 {
|
||||
set ic [sqlite3_intck db main]
|
||||
$ic step
|
||||
} {SQLITE_BUSY}
|
||||
do_test 1.3 {
|
||||
$ic unlock
|
||||
} {SQLITE_BUSY}
|
||||
do_test 1.4 {
|
||||
$ic error
|
||||
} {SQLITE_BUSY {database is locked}}
|
||||
do_test 1.4 {
|
||||
$ic close
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
# 2024 Feb 21
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The focus of this file is testing the intck extensions response
|
||||
# to corruption at the b-tree level.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] intck_common.tcl]
|
||||
set testprefix intckcorrupt
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 1.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
| size 356352 pagesize 4096 filename crash-acaae0347204ae.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 d0 00 00 00 .....@ ........
|
||||
| 32: 40 00 ea 00 00 00 00 00 00 40 00 00 00 40 00 00 @........@...@..
|
||||
| 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O
|
||||
| 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^...
|
||||
| 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par
|
||||
| 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE
|
||||
| 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa
|
||||
| 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT
|
||||
| 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q...
|
||||
| 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node
|
||||
| 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T
|
||||
| 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n
|
||||
| 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR
|
||||
| 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data).
|
||||
| 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_
|
||||
| 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR
|
||||
| 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r
|
||||
| 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE
|
||||
| 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
|
||||
| 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q..
|
||||
| 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C
|
||||
| 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA
|
||||
| 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr
|
||||
| 4064: 65 65 28 69 64 2c 78 30 20 50 52 49 4d 41 52 59 ee(id,x0 PRIMARY
|
||||
| 4080: 20 4b 45 59 2c 70 61 72 65 6e 74 6e 6f 64 65 29 KEY,parentnode)
|
||||
| page 2 offset 4096
|
||||
| 0: 51 03 06 17 1b 1b 01 7b 74 61 62 6c 65 74 31 5f Q.......tablet1_
|
||||
| 16: 6e 6f 64 65 74 31 5f 6e 6f 64 65 03 43 52 45 41 nodet1_node.CREA
|
||||
| 32: 54 45 20 54 41 42 4c 45 20 22 74 31 5f 6e 6f 64 TE TABLE .t1_nod
|
||||
| 48: 65 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 45 47 45 e.(nodeno INTEGE
|
||||
| 64: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 64 61 R PRIMARY KEY,da
|
||||
| 80: 74 61 29 5c 02 07 17 1d 1d 01 81 0b 74 61 62 6c ta).........tabl
|
||||
| 96: 65 74 31 5f 72 6f 77 69 64 74 31 5f 72 6f 77 69 et1_rowidt1_rowi
|
||||
| 112: 64 02 43 52 45 41 54 45 20 54 41 42 4c 45 00 00 d.CREATE TABLE..
|
||||
| 128: 01 0a 02 00 00 00 01 0e 0d 00 00 00 00 24 0e 0d .............$..
|
||||
| 144: 0c 1a 06 85 50 46 60 27 70 08 00 00 00 00 00 00 ....PF`'p.......
|
||||
| 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to
|
||||
| 3840: 79 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 y half.....#.bot
|
||||
| 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r
|
||||
| 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half.......
|
||||
| 3888: 6c 65 66 74 20 43 15 f6 e6 f6 46 50 34 35 24 54 left C....FP45$T
|
||||
| 3904: 15 44 52 05 44 14 24 c4 52 02 27 43 15 f6 e6 f6 .DR.D.$.R.'C....
|
||||
| 3920: 46 52 22 8e 6f 64 65 6e 6f 20 49 4e 54 45 47 45 FR..odeno INTEGE
|
||||
| 3936: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 64 61 R PRIMARY KEY,da
|
||||
| 3952: 74 61 29 5c 02 07 17 1d 1d 01 81 0b 74 61 62 6c ta).........tabl
|
||||
| 3968: 65 74 31 5f 72 6f 74 74 6f 6d 20 65 64 67 65 0f et1_rottom edge.
|
||||
| 3984: 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 65 ....!.right edge
|
||||
| 4000: 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 65 .......left edge
|
||||
| 4016: 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 05 .......center...
|
||||
| 4032: 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 20 ..1.upper-right
|
||||
| 4048: 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f 77 corner.....1.low
|
||||
| 4064: 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 16 er-right corner.
|
||||
| 4080: 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 74 ..../.upper-left
|
||||
| page 3 offset 8192
|
||||
| 0: 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 01 8c 6f corner...../..o
|
||||
| 16: 77 65 72 2d 6c 53 51 4c 69 74 65 20 66 6f 72 6d wer-lSQLite form
|
||||
| 32: 61 74 20 33 00 10 00 01 01 00 40 20 20 00 00 00 at 3......@ ...
|
||||
| 48: 00 00 00 00 2f 00 00 0d eb 13 00 00 00 03 00 00 ..../...........
|
||||
| 64: 00 04 00 00 00 00 00 00 00 06 00 00 00 01 00 00 ................
|
||||
| 80: 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| page 6 offset 20480
|
||||
| 128: 00 00 00 00 00 00 00 00 97 3d 04 ae 7c 01 00 00 .........=..|...
|
||||
| 624: 00 00 00 00 00 00 21 97 3d 04 ae 7c 01 00 00 00 ......!.=..|....
|
||||
| 1120: 00 00 00 00 00 20 97 3d 04 ae 7c 01 00 00 00 00 ..... .=..|.....
|
||||
| 1616: 00 00 00 00 1f 97 3d 04 ae 7c 01 00 00 00 00 00 ......=..|......
|
||||
| 2112: 00 00 00 1e 97 3d 04 ae 7c 01 00 00 00 00 00 00 .....=..|.......
|
||||
| 2608: 00 00 1d 97 d3 d0 4a e7 c0 00 00 00 00 00 00 00 ......J.........
|
||||
| 3088: 00 00 00 00 00 00 00 00 00 00 00 00 01 f3 00 00 ................
|
||||
| 3600: 23 97 3d 04 ae 7c 01 00 00 00 00 00 00 00 00 00 #.=..|..........
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 26 ...............&
|
||||
| page 8 offset 28672
|
||||
| 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0......
|
||||
| 1072: 97 4d 1e 14 00 ae 7c 00 00 00 00 00 00 00 00 00 .M....|.........
|
||||
| 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
|
||||
| page 10 offset 36864
|
||||
| 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0......
|
||||
| 1072: 9a ee c1 80 fd 78 1f ce 1b ae eb b4 00 00 00 00 .....x..........
|
||||
| 1088: 13 20 ff 20 00 70 00 00 00 60 50 00 00 00 11 e0 . . .p...`P.....
|
||||
| 1104: 00 00 00 70 00 00 00 60 50 05 35 14 c6 97 46 52 ...p...`P.5...FR
|
||||
| 1120: 06 66 f7 26 d6 17 42 03 30 01 00 00 10 10 04 02 .f.&..B.0.......
|
||||
| 1136: 02 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 .........@......
|
||||
| 1152: 00 00 00 00 00 40 00 00 00 40 00 00 00 00 00 00 .....@...@......
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................
|
||||
| page 12 offset 45056
|
||||
| 0: 0d 00 00 00 01 04 30 00 04 30 e1 b4 30 97 4d 46 ......0..0..0.MF
|
||||
| 16: 14 00 ae 7c 00 00 00 00 00 00 00 03 00 00 43 00 ...|..........C.
|
||||
| page 47 offset 188416
|
||||
| 2512: 00 00 00 00 00 00 00 00 be 00 00 00 00 00 00 00 ................
|
||||
| page 87 offset 352256
|
||||
| 2512: 00 00 00 00 00 00 00 00 aa 00 00 00 00 00 00 00 ................
|
||||
| end crash-acaae0347204ae.db
|
||||
}]} {}
|
||||
|
||||
do_intck_test 1.1 {
|
||||
{corruption found while reading database schema}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 2.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
| size 28672 pagesize 4096 filename crash-3afa1ca9e9c1bd.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 06 0e 88 00 0f b8 0f 6d ...............m
|
||||
| 112: 0f 3a 0f 0b 0e d5 0e 88 01 00 00 00 00 00 00 00 .:..............
|
||||
| 3712: 00 00 00 00 00 00 00 00 4b 06 06 17 25 25 01 5b ........K...%%.[
|
||||
| 3728: 74 61 62 6c 65 73 71 6c 69 74 65 5f 73 74 61 74 tablesqlite_stat
|
||||
| 3744: 31 73 71 6c 69 74 65 5f 73 74 61 74 31 07 43 52 1sqlite_stat1.CR
|
||||
| 3760: 45 41 54 45 20 54 41 42 4c 45 20 73 71 6c 69 74 EATE TABLE sqlit
|
||||
| 3776: 65 5f 73 74 61 74 31 28 74 62 6c 2c 69 64 78 2c e_stat1(tbl,idx,
|
||||
| 3792: 73 74 61 74 29 34 05 06 17 13 11 01 53 69 6e 64 stat)4......Sind
|
||||
| 3808: 65 78 63 31 63 63 31 06 43 52 45 41 54 45 20 55 exc1cc1.CREATE U
|
||||
| 3824: 4e 49 51 55 45 20 49 4e 44 45 58 20 63 31 63 20 NIQUE INDEX c1c
|
||||
| 3840: 4f 4e 20 63 31 28 63 2c 20 62 29 2d 04 06 17 13 ON c1(c, b)-....
|
||||
| 3856: 11 01 45 69 6e 64 65 78 63 31 64 63 31 05 43 52 ..Eindexc1dc1.CR
|
||||
| 3872: 45 41 54 45 20 49 4e 44 45 58 20 63 31 64 20 4f EATE INDEX c1d O
|
||||
| 3888: 4e 20 63 31 28 64 2c 20 62 29 31 03 06 17 13 11 N c1(d, b)1.....
|
||||
| 3904: 01 4d 69 6e 64 65 78 62 31 63 62 31 05 43 52 45 .Mindexb1cb1.CRE
|
||||
| 3920: 41 54 45 20 55 4e 49 51 55 45 20 49 4e 44 45 58 ATE UNIQUE INDEX
|
||||
| 3936: 20 62 31 63 20 4f 4e 20 62 31 28 63 29 49 02 06 b1c ON b1(c)I..
|
||||
| 3952: 17 11 11 0f 7f 74 61 62 6c 65 63 31 63 31 03 43 .....tablec1c1.C
|
||||
| 3968: 52 45 41 54 45 20 54 41 42 4c 45 20 63 31 28 61 REATE TABLE c1(a
|
||||
| 3984: 20 49 4e 54 20 50 52 49 4d 41 52 59 20 4b 45 59 INT PRIMARY KEY
|
||||
| 4000: 2c 20 62 2c 20 63 2c 20 64 29 20 57 49 54 48 4f , b, c, d) WITHO
|
||||
| 4016: 55 54 20 52 4f 57 49 44 46 01 06 17 11 11 01 79 UT ROWIDF......y
|
||||
| 4032: 74 61 62 6c 65 62 31 62 31 02 43 52 45 41 54 45 tableb1b1.CREATE
|
||||
| 4048: 20 54 41 42 4c 45 20 62 31 28 61 20 49 4e 54 20 TABLE b1(a INT
|
||||
| 4064: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 2c 20 PRIMARY KEY, b,
|
||||
| 4080: 63 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 c) WITHOUT ROWID
|
||||
| page 2 offset 4096
|
||||
| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f e2 ................
|
||||
| 16: 0f da 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 06 ................
|
||||
| 4048: 67 07 07 04 01 0f 01 06 66 06 07 04 01 0f 01 05 g.......f.......
|
||||
| 4064: 65 05 07 04 01 0f 01 04 64 04 07 04 01 0f 01 03 e.......d.......
|
||||
| 4080: 63 03 07 04 01 0f 01 02 62 0f 05 04 09 0f 09 61 c.......b......a
|
||||
| page 3 offset 8192
|
||||
| 0: 0a 00 00 00 07 0f bd 00 0f f9 0f ef 0f e5 0f db ................
|
||||
| 16: 0f d1 0f c7 0f bd 00 00 00 00 01 00 00 00 00 00 ................
|
||||
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 09 05 01 ................
|
||||
| 4032: 0f 01 01 07 61 07 07 09 05 01 0f 01 01 06 61 06 ....a.........a.
|
||||
| 4048: 06 09 05 01 0f 01 01 05 61 05 05 09 05 01 0f 01 ........a.......
|
||||
| 4064: 01 04 61 04 04 09 05 01 0f 01 01 03 61 03 03 09 ..a.........a...
|
||||
| 4080: 05 01 0f 01 01 02 61 0f 02 06 05 09 0f 09 09 61 ......a........a
|
||||
| page 4 offset 12288
|
||||
| 0: 0a 00 00 00 07 0f d8 00 0f fc 0f f0 0f ea 0f e4 ................
|
||||
| 16: 0f de 0f d8 0f f6 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4048: 00 00 00 00 00 00 00 00 05 03 01 01 07 07 05 03 ................
|
||||
| 4064: 01 01 06 06 05 03 01 01 05 05 05 03 01 01 04 04 ................
|
||||
| 4080: 05 03 01 01 03 03 05 03 01 01 0f 02 03 03 09 09 ................
|
||||
| page 5 offset 16384
|
||||
| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f 00 ................
|
||||
| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................
|
||||
| 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a.......
|
||||
| 4064: 61 05 07 04 01 1f 01 04 61 04 07 04 01 0f 01 03 a.......a.......
|
||||
| 4080: 61 03 07 04 01 0f 01 02 61 02 05 04 09 0f 09 61 a.......a......a
|
||||
| page 6 offset 20480
|
||||
| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f ea 0f e2 00 00 ................
|
||||
| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................
|
||||
| 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a.......
|
||||
| 4064: 61 05 07 04 01 0f 01 04 61 04 07 04 01 0f 01 03 a.......a.......
|
||||
| 4080: 61 03 07 04 01 0f 01 0f 61 02 05 04 09 0f 09 61 a.......a......a
|
||||
| page 7 offset 24576
|
||||
| 0: 0d 00 00 00 05 0f 1c 00 0f f0 0f e0 0f d3 0f c5 ................
|
||||
| 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4016: 00 00 00 00 00 00 00 00 0b 05 04 11 11 13 62 31 ..............b1
|
||||
| 4032: 62 31 37 20 31 0c 04 04 11 13 13 62 31 62 31 63 b17 1......b1b1c
|
||||
| 4048: 37 20 31 0b 03 04 11 11 13 63 31 63 31 37 20 31 7 1......c1c17 1
|
||||
| 4064: 0e 02 04 11 13 07 63 31 63 31 64 37 20 31 20 31 ......c1c1d7 1 1
|
||||
| 4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00 ......c1c1c7 1..
|
||||
| end crash-3afa1ca9e9c1bd.db
|
||||
}]} {}
|
||||
|
||||
do_intck_test 2.1 {
|
||||
{corruption found while reading database schema}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 3);
|
||||
}
|
||||
|
||||
do_test 3.1 {
|
||||
set pgno [db one {SELECT rootpage FROM sqlite_schema WHERE name='t1'}]
|
||||
db close
|
||||
hexio_write test.db [expr ($pgno-1)*1024] 0000
|
||||
} {2}
|
||||
|
||||
sqlite3 db test.db
|
||||
do_intck_test 3.2 {
|
||||
{corruption found while scanning database object i1}
|
||||
{corruption found while scanning database object t1}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# 2024 February 24
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] intck_common.tcl]
|
||||
set testprefix intckfault
|
||||
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(2, 'two', 'three');
|
||||
INSERT INTO t1 VALUES(3, NULL, NULL);
|
||||
CREATE INDEX i1 ON t1(b, c);
|
||||
}
|
||||
|
||||
do_faultsim_test 1 -faults oom-t* -prep {
|
||||
} -body {
|
||||
set ::ic [sqlite3_intck db main]
|
||||
set nStep 0
|
||||
while {"SQLITE_OK"==[$::ic step]} {
|
||||
incr nStep
|
||||
if {$nStep==3} { $::ic unlock }
|
||||
}
|
||||
set res [$::ic error]
|
||||
$::ic close
|
||||
set res
|
||||
} -test {
|
||||
catch { $::ic close }
|
||||
puts $testresult
|
||||
puts $testnfail
|
||||
faultsim_test_result {0 {SQLITE_OK {}}} {0 {SQLITE_NOMEM {}}} {0 {SQLITE_NOMEM {out of memory}}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,941 @@
|
||||
/*
|
||||
** 2024-02-08
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
#include "sqlite3intck.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** nKeyVal:
|
||||
** The number of values that make up the 'key' for the current pCheck
|
||||
** statement.
|
||||
**
|
||||
** rc:
|
||||
** Error code returned by most recent sqlite3_intck_step() or
|
||||
** sqlite3_intck_unlock() call. This is set to SQLITE_DONE when
|
||||
** the integrity-check operation is finished.
|
||||
**
|
||||
** zErr:
|
||||
** If the object has entered the error state, this is the error message.
|
||||
** Is freed using sqlite3_free() when the object is deleted.
|
||||
**
|
||||
** zTestSql:
|
||||
** The value returned by the most recent call to sqlite3_intck_testsql().
|
||||
** Each call to testsql() frees the previous zTestSql value (using
|
||||
** sqlite3_free()) and replaces it with the new value it will return.
|
||||
*/
|
||||
struct sqlite3_intck {
|
||||
sqlite3 *db;
|
||||
const char *zDb; /* Copy of zDb parameter to _open() */
|
||||
char *zObj; /* Current object. Or NULL. */
|
||||
|
||||
sqlite3_stmt *pCheck; /* Current check statement */
|
||||
char *zKey;
|
||||
int nKeyVal;
|
||||
|
||||
char *zMessage;
|
||||
int bCorruptSchema;
|
||||
|
||||
int rc; /* Error code */
|
||||
char *zErr; /* Error message */
|
||||
char *zTestSql; /* Returned by sqlite3_intck_test_sql() */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Some error has occurred while using database p->db. Save the error message
|
||||
** and error code currently held by the database handle in p->rc and p->zErr.
|
||||
*/
|
||||
static void intckSaveErrmsg(sqlite3_intck *p){
|
||||
p->rc = sqlite3_errcode(p->db);
|
||||
sqlite3_free(p->zErr);
|
||||
p->zErr = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
|
||||
}
|
||||
|
||||
/*
|
||||
** If the handle passed as the first argument is already in the error state,
|
||||
** then this function is a no-op (returns NULL immediately). Otherwise, if an
|
||||
** error occurs within this function, it leaves an error in said handle.
|
||||
**
|
||||
** Otherwise, this function attempts to prepare SQL statement zSql and
|
||||
** return the resulting statement handle to the user.
|
||||
*/
|
||||
static sqlite3_stmt *intckPrepare(sqlite3_intck *p, const char *zSql){
|
||||
sqlite3_stmt *pRet = 0;
|
||||
if( p->rc==SQLITE_OK ){
|
||||
p->rc = sqlite3_prepare_v2(p->db, zSql, -1, &pRet, 0);
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
intckSaveErrmsg(p);
|
||||
assert( pRet==0 );
|
||||
}
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the handle passed as the first argument is already in the error state,
|
||||
** then this function is a no-op (returns NULL immediately). Otherwise, if an
|
||||
** error occurs within this function, it leaves an error in said handle.
|
||||
**
|
||||
** Otherwise, this function treats argument zFmt as a printf() style format
|
||||
** string. It formats it according to the trailing arguments and then
|
||||
** attempts to prepare the results and return the resulting prepared
|
||||
** statement.
|
||||
*/
|
||||
static sqlite3_stmt *intckPrepareFmt(sqlite3_intck *p, const char *zFmt, ...){
|
||||
sqlite3_stmt *pRet = 0;
|
||||
va_list ap;
|
||||
char *zSql = 0;
|
||||
va_start(ap, zFmt);
|
||||
zSql = sqlite3_vmprintf(zFmt, ap);
|
||||
if( p->rc==SQLITE_OK && zSql==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
pRet = intckPrepare(p, zSql);
|
||||
sqlite3_free(zSql);
|
||||
va_end(ap);
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Finalize SQL statement pStmt. If an error occurs and the handle passed
|
||||
** as the first argument does not already contain an error, store the
|
||||
** error in the handle.
|
||||
*/
|
||||
static void intckFinalize(sqlite3_intck *p, sqlite3_stmt *pStmt){
|
||||
int rc = sqlite3_finalize(pStmt);
|
||||
if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){
|
||||
intckSaveErrmsg(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If there is already an error in handle p, return it. Otherwise, call
|
||||
** sqlite3_step() on the statement handle and return that value.
|
||||
*/
|
||||
static int intckStep(sqlite3_intck *p, sqlite3_stmt *pStmt){
|
||||
if( p->rc ) return p->rc;
|
||||
return sqlite3_step(pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute SQL statement zSql. There is no way to obtain any results
|
||||
** returned by the statement. This function uses the sqlite3_intck error
|
||||
** code convention.
|
||||
*/
|
||||
static void intckExec(sqlite3_intck *p, const char *zSql){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
pStmt = intckPrepare(p, zSql);
|
||||
intckStep(p, pStmt);
|
||||
intckFinalize(p, pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around sqlite3_mprintf() that uses the sqlite3_intck error
|
||||
** code convention.
|
||||
*/
|
||||
static char *intckMprintf(sqlite3_intck *p, const char *zFmt, ...){
|
||||
va_list ap;
|
||||
char *zRet = 0;
|
||||
va_start(ap, zFmt);
|
||||
zRet = sqlite3_vmprintf(zFmt, ap);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( zRet==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
}else{
|
||||
sqlite3_free(zRet);
|
||||
zRet = 0;
|
||||
}
|
||||
return zRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is used by sqlite3_intck_unlock() to save the vector key value
|
||||
** required to restart the current pCheck query as a nul-terminated string
|
||||
** in p->zKey.
|
||||
*/
|
||||
static void intckSaveKey(sqlite3_intck *p){
|
||||
int ii;
|
||||
char *zSql = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
sqlite3_stmt *pXinfo = 0;
|
||||
const char *zDir = 0;
|
||||
|
||||
assert( p->pCheck );
|
||||
assert( p->zKey==0 );
|
||||
|
||||
pXinfo = intckPrepareFmt(p,
|
||||
"SELECT group_concat(desc, '') FROM %Q.sqlite_schema s, "
|
||||
"pragma_index_xinfo(%Q, %Q) "
|
||||
"WHERE s.type='index' AND s.name=%Q",
|
||||
p->zDb, p->zObj, p->zDb, p->zObj
|
||||
);
|
||||
if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXinfo) ){
|
||||
zDir = (const char*)sqlite3_column_text(pXinfo, 0);
|
||||
}
|
||||
|
||||
if( zDir==0 ){
|
||||
/* Object is a table, not an index. This is the easy case,as there are
|
||||
** no DESC columns or NULL values in a primary key. */
|
||||
const char *zSep = "SELECT '(' || ";
|
||||
for(ii=0; ii<p->nKeyVal; ii++){
|
||||
zSql = intckMprintf(p, "%z%squote(?)", zSql, zSep);
|
||||
zSep = " || ', ' || ";
|
||||
}
|
||||
zSql = intckMprintf(p, "%z || ')'", zSql);
|
||||
}else{
|
||||
|
||||
/* Object is an index. */
|
||||
assert( p->nKeyVal>1 );
|
||||
for(ii=p->nKeyVal; ii>0; ii--){
|
||||
int bLastIsDesc = zDir[ii-1]=='1';
|
||||
int bLastIsNull = sqlite3_column_type(p->pCheck, ii)==SQLITE_NULL;
|
||||
const char *zLast = sqlite3_column_name(p->pCheck, ii);
|
||||
char *zLhs = 0;
|
||||
char *zRhs = 0;
|
||||
char *zWhere = 0;
|
||||
|
||||
if( bLastIsNull ){
|
||||
if( bLastIsDesc ) continue;
|
||||
zWhere = intckMprintf(p, "'%s IS NOT NULL'", zLast);
|
||||
}else{
|
||||
const char *zOp = bLastIsDesc ? "<" : ">";
|
||||
zWhere = intckMprintf(p, "'%s %s ' || quote(?%d)", zLast, zOp, ii);
|
||||
}
|
||||
|
||||
if( ii>1 ){
|
||||
const char *zLhsSep = "";
|
||||
const char *zRhsSep = "";
|
||||
int jj;
|
||||
for(jj=0; jj<ii-1; jj++){
|
||||
const char *zAlias = (const char*)sqlite3_column_name(p->pCheck,jj+1);
|
||||
zLhs = intckMprintf(p, "%z%s%s", zLhs, zLhsSep, zAlias);
|
||||
zRhs = intckMprintf(p, "%z%squote(?%d)", zRhs, zRhsSep, jj+1);
|
||||
zLhsSep = ",";
|
||||
zRhsSep = " || ',' || ";
|
||||
}
|
||||
|
||||
zWhere = intckMprintf(p,
|
||||
"'(%z) IS (' || %z || ') AND ' || %z",
|
||||
zLhs, zRhs, zWhere);
|
||||
}
|
||||
zWhere = intckMprintf(p, "'WHERE ' || %z", zWhere);
|
||||
|
||||
zSql = intckMprintf(p, "%z%s(quote( %z ) )",
|
||||
zSql,
|
||||
(zSql==0 ? "VALUES" : ",\n "),
|
||||
zWhere
|
||||
);
|
||||
}
|
||||
zSql = intckMprintf(p,
|
||||
"WITH wc(q) AS (\n%z\n)"
|
||||
"SELECT 'VALUES' || group_concat('(' || q || ')', ',\n ') FROM wc"
|
||||
, zSql
|
||||
);
|
||||
}
|
||||
|
||||
pStmt = intckPrepare(p, zSql);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
for(ii=0; ii<p->nKeyVal; ii++){
|
||||
sqlite3_bind_value(pStmt, ii+1, sqlite3_column_value(p->pCheck, ii+1));
|
||||
}
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
p->zKey = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0));
|
||||
}
|
||||
intckFinalize(p, pStmt);
|
||||
}
|
||||
|
||||
sqlite3_free(zSql);
|
||||
intckFinalize(p, pXinfo);
|
||||
}
|
||||
|
||||
/*
|
||||
** Find the next database object (table or index) to check. If successful,
|
||||
** set sqlite3_intck.zObj to point to a nul-terminated buffer containing
|
||||
** the object's name before returning.
|
||||
*/
|
||||
static void intckFindObject(sqlite3_intck *p){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char *zPrev = p->zObj;
|
||||
p->zObj = 0;
|
||||
|
||||
assert( p->rc==SQLITE_OK );
|
||||
assert( p->pCheck==0 );
|
||||
|
||||
pStmt = intckPrepareFmt(p,
|
||||
"WITH tables(table_name) AS ("
|
||||
" SELECT name"
|
||||
" FROM %Q.sqlite_schema WHERE (type='table' OR type='index') AND rootpage"
|
||||
" UNION ALL "
|
||||
" SELECT 'sqlite_schema'"
|
||||
")"
|
||||
"SELECT table_name FROM tables "
|
||||
"WHERE ?1 IS NULL OR table_name%s?1 "
|
||||
"ORDER BY 1"
|
||||
, p->zDb, (p->zKey ? ">=" : ">")
|
||||
);
|
||||
|
||||
if( p->rc==SQLITE_OK ){
|
||||
sqlite3_bind_text(pStmt, 1, zPrev, -1, SQLITE_TRANSIENT);
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
p->zObj = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0));
|
||||
}
|
||||
}
|
||||
intckFinalize(p, pStmt);
|
||||
|
||||
/* If this is a new object, ensure the previous key value is cleared. */
|
||||
if( sqlite3_stricmp(p->zObj, zPrev) ){
|
||||
sqlite3_free(p->zKey);
|
||||
p->zKey = 0;
|
||||
}
|
||||
|
||||
sqlite3_free(zPrev);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the size in bytes of the first token in nul-terminated buffer z.
|
||||
** For the purposes of this call, a token is either:
|
||||
**
|
||||
** * a quoted SQL string,
|
||||
* * a contiguous series of ascii alphabet characters, or
|
||||
* * any other single byte.
|
||||
*/
|
||||
static int intckGetToken(const char *z){
|
||||
char c = z[0];
|
||||
int iRet = 1;
|
||||
if( c=='\'' || c=='"' || c=='`' ){
|
||||
while( 1 ){
|
||||
if( z[iRet]==c ){
|
||||
iRet++;
|
||||
if( z[iRet]!=c ) break;
|
||||
}
|
||||
iRet++;
|
||||
}
|
||||
}
|
||||
else if( c=='[' ){
|
||||
while( z[iRet++]!=']' && z[iRet] );
|
||||
}
|
||||
else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){
|
||||
while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){
|
||||
iRet++;
|
||||
}
|
||||
}
|
||||
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if argument c is an ascii whitespace character.
|
||||
*/
|
||||
static int intckIsSpace(char c){
|
||||
return (c==' ' || c=='\t' || c=='\n' || c=='\r');
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument z points to the text of a CREATE INDEX statement. This function
|
||||
** identifies the part of the text that contains either the index WHERE
|
||||
** clause (if iCol<0) or the iCol'th column of the index.
|
||||
**
|
||||
** If (iCol<0), the identified fragment does not include the "WHERE" keyword,
|
||||
** only the expression that follows it. If (iCol>=0) then the identified
|
||||
** fragment does not include any trailing sort-order keywords - "ASC" or
|
||||
** "DESC".
|
||||
**
|
||||
** If the CREATE INDEX statement does not contain the requested field or
|
||||
** clause, NULL is returned and (*pnByte) is set to 0. Otherwise, a pointer to
|
||||
** the identified fragment is returned and output parameter (*pnByte) set
|
||||
** to its size in bytes.
|
||||
*/
|
||||
static const char *intckParseCreateIndex(const char *z, int iCol, int *pnByte){
|
||||
int iOff = 0;
|
||||
int iThisCol = 0;
|
||||
int iStart = 0;
|
||||
int nOpen = 0;
|
||||
|
||||
const char *zRet = 0;
|
||||
int nRet = 0;
|
||||
|
||||
int iEndOfCol = 0;
|
||||
|
||||
/* Skip forward until the first "(" token */
|
||||
while( z[iOff]!='(' ){
|
||||
iOff += intckGetToken(&z[iOff]);
|
||||
if( z[iOff]=='\0' ) return 0;
|
||||
}
|
||||
assert( z[iOff]=='(' );
|
||||
|
||||
nOpen = 1;
|
||||
iOff++;
|
||||
iStart = iOff;
|
||||
while( z[iOff] ){
|
||||
const char *zToken = &z[iOff];
|
||||
int nToken = 0;
|
||||
|
||||
/* Check if this is the end of the current column - either a "," or ")"
|
||||
** when nOpen==1. */
|
||||
if( nOpen==1 ){
|
||||
if( z[iOff]==',' || z[iOff]==')' ){
|
||||
if( iCol==iThisCol ){
|
||||
int iEnd = iEndOfCol ? iEndOfCol : iOff;
|
||||
nRet = (iEnd - iStart);
|
||||
zRet = &z[iStart];
|
||||
break;
|
||||
}
|
||||
iStart = iOff+1;
|
||||
while( intckIsSpace(z[iStart]) ) iStart++;
|
||||
iThisCol++;
|
||||
}
|
||||
if( z[iOff]==')' ) break;
|
||||
}
|
||||
if( z[iOff]=='(' ) nOpen++;
|
||||
if( z[iOff]==')' ) nOpen--;
|
||||
nToken = intckGetToken(zToken);
|
||||
|
||||
if( (nToken==3 && 0==sqlite3_strnicmp(zToken, "ASC", nToken))
|
||||
|| (nToken==4 && 0==sqlite3_strnicmp(zToken, "DESC", nToken))
|
||||
){
|
||||
iEndOfCol = iOff;
|
||||
}else if( 0==intckIsSpace(zToken[0]) ){
|
||||
iEndOfCol = 0;
|
||||
}
|
||||
|
||||
iOff += nToken;
|
||||
}
|
||||
|
||||
/* iStart is now the byte offset of 1 byte passed the final ')' in the
|
||||
** CREATE INDEX statement. Try to find a WHERE clause to return. */
|
||||
while( zRet==0 && z[iOff] ){
|
||||
int n = intckGetToken(&z[iOff]);
|
||||
if( n==5 && 0==sqlite3_strnicmp(&z[iOff], "where", 5) ){
|
||||
zRet = &z[iOff+5];
|
||||
nRet = strlen(zRet);
|
||||
}
|
||||
iOff += n;
|
||||
}
|
||||
|
||||
/* Trim any whitespace from the start and end of the returned string. */
|
||||
if( zRet ){
|
||||
while( intckIsSpace(zRet[0]) ){
|
||||
nRet--;
|
||||
zRet++;
|
||||
}
|
||||
while( nRet>0 && intckIsSpace(zRet[nRet-1]) ) nRet--;
|
||||
}
|
||||
|
||||
*pnByte = nRet;
|
||||
return zRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** User-defined SQL function wrapper for intckParseCreateIndex():
|
||||
**
|
||||
** SELECT parse_create_index(<sql>, <icol>);
|
||||
*/
|
||||
static void intckParseCreateIndexFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
const char *zSql = (const char*)sqlite3_value_text(apVal[0]);
|
||||
int idx = sqlite3_value_int(apVal[1]);
|
||||
const char *zRes = 0;
|
||||
int nRes = 0;
|
||||
|
||||
assert( nVal==2 );
|
||||
if( zSql ){
|
||||
zRes = intckParseCreateIndex(zSql, idx, &nRes);
|
||||
}
|
||||
sqlite3_result_text(pCtx, zRes, nRes, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if sqlite3_intck.db has automatic indexes enabled, false
|
||||
** otherwise.
|
||||
*/
|
||||
static int intckGetAutoIndex(sqlite3_intck *p){
|
||||
int bRet = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
pStmt = intckPrepare(p, "PRAGMA automatic_index");
|
||||
if( SQLITE_ROW==intckStep(p, pStmt) ){
|
||||
bRet = sqlite3_column_int(pStmt, 0);
|
||||
}
|
||||
intckFinalize(p, pStmt);
|
||||
return bRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if zObj is an index, or false otherwise.
|
||||
*/
|
||||
static int intckIsIndex(sqlite3_intck *p, const char *zObj){
|
||||
int bRet = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
pStmt = intckPrepareFmt(p,
|
||||
"SELECT 1 FROM %Q.sqlite_schema WHERE name=%Q AND type='index'",
|
||||
p->zDb, zObj
|
||||
);
|
||||
if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
bRet = 1;
|
||||
}
|
||||
intckFinalize(p, pStmt);
|
||||
return bRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to a nul-terminated buffer containing the SQL statement
|
||||
** used to check database object zObj (a table or index) for corruption.
|
||||
** If parameter zPrev is not NULL, then it must be a string containing the
|
||||
** vector key required to restart the check where it left off last time.
|
||||
** If pnKeyVal is not NULL, then (*pnKeyVal) is set to the number of
|
||||
** columns in the vector key value for the specified object.
|
||||
**
|
||||
** This function uses the sqlite3_intck error code convention.
|
||||
*/
|
||||
static char *intckCheckObjectSql(
|
||||
sqlite3_intck *p, /* Integrity check object */
|
||||
const char *zObj, /* Object (table or index) to scan */
|
||||
const char *zPrev, /* Restart key vector, if any */
|
||||
int *pnKeyVal /* OUT: Number of key-values for this scan */
|
||||
){
|
||||
char *zRet = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int bAutoIndex = 0;
|
||||
int bIsIndex = 0;
|
||||
|
||||
const char *zCommon =
|
||||
/* Relation without_rowid also contains just one row. Column "b" is
|
||||
** set to true if the table being examined is a WITHOUT ROWID table,
|
||||
** or false otherwise. */
|
||||
", without_rowid(b) AS ("
|
||||
" SELECT EXISTS ("
|
||||
" SELECT 1 FROM tabname, pragma_index_list(tab, db) AS l"
|
||||
" WHERE origin='pk' "
|
||||
" AND NOT EXISTS (SELECT 1 FROM sqlite_schema WHERE name=l.name)"
|
||||
" )"
|
||||
")"
|
||||
""
|
||||
/* Table idx_cols contains 1 row for each column in each index on the
|
||||
** table being checked. Columns are:
|
||||
**
|
||||
** idx_name: Name of the index.
|
||||
** idx_ispk: True if this index is the PK of a WITHOUT ROWID table.
|
||||
** col_name: Name of indexed column, or NULL for index on expression.
|
||||
** col_expr: Indexed expression, including COLLATE clause.
|
||||
** col_alias: Alias used for column in 'intck_wrapper' table.
|
||||
*/
|
||||
", idx_cols(idx_name, idx_ispk, col_name, col_expr, col_alias) AS ("
|
||||
" SELECT l.name, (l.origin=='pk' AND w.b), i.name, COALESCE(("
|
||||
" SELECT parse_create_index(sql, i.seqno) FROM "
|
||||
" sqlite_schema WHERE name = l.name"
|
||||
" ), format('\"%w\"', i.name) || ' COLLATE ' || quote(i.coll)),"
|
||||
" 'c' || row_number() OVER ()"
|
||||
" FROM "
|
||||
" tabname t,"
|
||||
" without_rowid w,"
|
||||
" pragma_index_list(t.tab, t.db) l,"
|
||||
" pragma_index_xinfo(l.name) i"
|
||||
" WHERE i.key"
|
||||
" UNION ALL"
|
||||
" SELECT '', 1, '_rowid_', '_rowid_', 'r1' FROM without_rowid WHERE b=0"
|
||||
")"
|
||||
""
|
||||
""
|
||||
/*
|
||||
** For a PK declared as "PRIMARY KEY(a, b) ... WITHOUT ROWID", where
|
||||
** the intck_wrapper aliases of "a" and "b" are "c1" and "c2":
|
||||
**
|
||||
** o_pk: "o.c1, o.c2"
|
||||
** i_pk: "i.'a', i.'b'"
|
||||
** ...
|
||||
** n_pk: 2
|
||||
*/
|
||||
", tabpk(db, tab, idx, o_pk, i_pk, q_pk, eq_pk, ps_pk, pk_pk, n_pk) AS ("
|
||||
" WITH pkfields(f, a) AS ("
|
||||
" SELECT i.col_name, i.col_alias FROM idx_cols i WHERE i.idx_ispk"
|
||||
" )"
|
||||
" SELECT t.db, t.tab, t.idx, "
|
||||
" group_concat(a, ', '), "
|
||||
" group_concat('i.'||quote(f), ', '), "
|
||||
" group_concat('quote(o.'||a||')', ' || '','' || '), "
|
||||
" format('(%s)==(%s)',"
|
||||
" group_concat('o.'||a, ', '), "
|
||||
" group_concat(format('\"%w\"', f), ', ')"
|
||||
" ),"
|
||||
" group_concat('%s', ','),"
|
||||
" group_concat('quote('||a||')', ', '), "
|
||||
" count(*)"
|
||||
" FROM tabname t, pkfields"
|
||||
")"
|
||||
""
|
||||
", idx(name, match_expr, partial, partial_alias, idx_ps, idx_idx) AS ("
|
||||
" SELECT idx_name,"
|
||||
" format('(%s,%s) IS (%s,%s)', "
|
||||
" group_concat(i.col_expr, ', '), i_pk,"
|
||||
" group_concat('o.'||i.col_alias, ', '), o_pk"
|
||||
" ), "
|
||||
" parse_create_index("
|
||||
" (SELECT sql FROM sqlite_schema WHERE name=idx_name), -1"
|
||||
" ),"
|
||||
" 'cond' || row_number() OVER ()"
|
||||
" , group_concat('%s', ',')"
|
||||
" , group_concat('quote('||i.col_alias||')', ', ')"
|
||||
" FROM tabpk t, "
|
||||
" without_rowid w,"
|
||||
" idx_cols i"
|
||||
" WHERE i.idx_ispk==0 "
|
||||
" GROUP BY idx_name"
|
||||
")"
|
||||
""
|
||||
", wrapper_with(s) AS ("
|
||||
" SELECT 'intck_wrapper AS (\n SELECT\n ' || ("
|
||||
" WITH f(a, b) AS ("
|
||||
" SELECT col_expr, col_alias FROM idx_cols"
|
||||
" UNION ALL "
|
||||
" SELECT partial, partial_alias FROM idx WHERE partial IS NOT NULL"
|
||||
" )"
|
||||
" SELECT group_concat(format('%s AS %s', a, b), ',\n ') FROM f"
|
||||
" )"
|
||||
" || format('\n FROM %Q.%Q ', t.db, t.tab)"
|
||||
/* If the object being checked is a table, append "NOT INDEXED".
|
||||
** Otherwise, append "INDEXED BY <index>", and then, if the index
|
||||
** is a partial index " WHERE <condition>". */
|
||||
" || CASE WHEN t.idx IS NULL THEN "
|
||||
" 'NOT INDEXED'"
|
||||
" ELSE"
|
||||
" format('INDEXED BY %Q%s', t.idx, ' WHERE '||i.partial)"
|
||||
" END"
|
||||
" || '\n)'"
|
||||
" FROM tabname t LEFT JOIN idx i ON (i.name=t.idx)"
|
||||
")"
|
||||
""
|
||||
;
|
||||
|
||||
bAutoIndex = intckGetAutoIndex(p);
|
||||
if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 0");
|
||||
|
||||
bIsIndex = intckIsIndex(p, zObj);
|
||||
if( bIsIndex ){
|
||||
pStmt = intckPrepareFmt(p,
|
||||
/* Table idxname contains a single row. The first column, "db", contains
|
||||
** the name of the db containing the table (e.g. "main") and the second,
|
||||
** "tab", the name of the table itself. */
|
||||
"WITH tabname(db, tab, idx) AS ("
|
||||
" SELECT %Q, (SELECT tbl_name FROM %Q.sqlite_schema WHERE name=%Q), %Q "
|
||||
")"
|
||||
""
|
||||
", whereclause(w_c) AS (%s)"
|
||||
""
|
||||
"%s" /* zCommon */
|
||||
""
|
||||
", case_statement(c) AS ("
|
||||
" SELECT "
|
||||
" 'CASE WHEN (' || group_concat(col_alias, ', ') || ', 1) IS (\n' "
|
||||
" || ' SELECT ' || group_concat(col_expr, ', ') || ', 1 FROM '"
|
||||
" || format('%%Q.%%Q NOT INDEXED WHERE %%s\n', t.db, t.tab, p.eq_pk)"
|
||||
" || ' )\n THEN NULL\n '"
|
||||
" || 'ELSE format(''surplus entry ('"
|
||||
" || group_concat('%%s', ',') || ',' || p.ps_pk"
|
||||
" || ') in index ' || t.idx || ''', ' "
|
||||
" || group_concat('quote('||i.col_alias||')', ', ') || ', ' || p.pk_pk"
|
||||
" || ')'"
|
||||
" || '\n END AS error_message'"
|
||||
" FROM tabname t, tabpk p, idx_cols i WHERE i.idx_name=t.idx"
|
||||
")"
|
||||
""
|
||||
", thiskey(k, n) AS ("
|
||||
" SELECT group_concat(i.col_alias, ', ') || ', ' || p.o_pk, "
|
||||
" count(*) + p.n_pk "
|
||||
" FROM tabpk p, idx_cols i WHERE i.idx_name=p.idx"
|
||||
")"
|
||||
""
|
||||
", main_select(m, n) AS ("
|
||||
" SELECT format("
|
||||
" 'WITH %%s\n' ||"
|
||||
" ', idx_checker AS (\n' ||"
|
||||
" ' SELECT %%s,\n' ||"
|
||||
" ' %%s\n' || "
|
||||
" ' FROM intck_wrapper AS o\n' ||"
|
||||
" ')\n',"
|
||||
" ww.s, c, t.k"
|
||||
" ), t.n"
|
||||
" FROM case_statement, wrapper_with ww, thiskey t"
|
||||
")"
|
||||
|
||||
"SELECT m || "
|
||||
" group_concat('SELECT * FROM idx_checker ' || w_c, ' UNION ALL '), n"
|
||||
" FROM "
|
||||
"main_select, whereclause "
|
||||
, p->zDb, p->zDb, zObj, zObj
|
||||
, zPrev ? zPrev : "VALUES('')", zCommon
|
||||
);
|
||||
}else{
|
||||
pStmt = intckPrepareFmt(p,
|
||||
/* Table tabname contains a single row. The first column, "db", contains
|
||||
** the name of the db containing the table (e.g. "main") and the second,
|
||||
** "tab", the name of the table itself. */
|
||||
"WITH tabname(db, tab, idx, prev) AS (SELECT %Q, %Q, NULL, %Q)"
|
||||
""
|
||||
"%s" /* zCommon */
|
||||
|
||||
/* expr(e) contains one row for each index on table zObj. Value e
|
||||
** is set to an expression that evaluates to NULL if the required
|
||||
** entry is present in the index, or an error message otherwise. */
|
||||
", expr(e, p) AS ("
|
||||
" SELECT format('CASE WHEN EXISTS \n"
|
||||
" (SELECT 1 FROM %%Q.%%Q AS i INDEXED BY %%Q WHERE %%s%%s)\n"
|
||||
" THEN NULL\n"
|
||||
" ELSE format(''entry (%%s,%%s) missing from index %%s'', %%s, %%s)\n"
|
||||
" END\n'"
|
||||
" , t.db, t.tab, i.name, i.match_expr, ' AND (' || partial || ')',"
|
||||
" i.idx_ps, t.ps_pk, i.name, i.idx_idx, t.pk_pk),"
|
||||
" CASE WHEN partial IS NULL THEN NULL ELSE i.partial_alias END"
|
||||
" FROM tabpk t, idx i"
|
||||
")"
|
||||
|
||||
", numbered(ii, cond, e) AS ("
|
||||
" SELECT 0, 'n.ii=0', 'NULL'"
|
||||
" UNION ALL "
|
||||
" SELECT row_number() OVER (),"
|
||||
" '(n.ii='||row_number() OVER ()||COALESCE(' AND '||p||')', ')'), e"
|
||||
" FROM expr"
|
||||
")"
|
||||
|
||||
", counter_with(w) AS ("
|
||||
" SELECT 'WITH intck_counter(ii) AS (\n ' || "
|
||||
" group_concat('SELECT '||ii, ' UNION ALL\n ') "
|
||||
" || '\n)' FROM numbered"
|
||||
")"
|
||||
""
|
||||
", case_statement(c) AS ("
|
||||
" SELECT 'CASE ' || "
|
||||
" group_concat(format('\n WHEN %%s THEN (%%s)', cond, e), '') ||"
|
||||
" '\nEND AS error_message'"
|
||||
" FROM numbered"
|
||||
")"
|
||||
""
|
||||
|
||||
/* This table contains a single row consisting of a single value -
|
||||
** the text of an SQL expression that may be used by the main SQL
|
||||
** statement to output an SQL literal that can be used to resume
|
||||
** the scan if it is suspended. e.g. for a rowid table, an expression
|
||||
** like:
|
||||
**
|
||||
** format('(%d,%d)', _rowid_, n.ii)
|
||||
*/
|
||||
", thiskey(k, n) AS ("
|
||||
" SELECT o_pk || ', ii', n_pk+1 FROM tabpk"
|
||||
")"
|
||||
""
|
||||
", whereclause(w_c) AS ("
|
||||
" SELECT CASE WHEN prev!='' THEN "
|
||||
" '\nWHERE (' || o_pk ||', n.ii) > ' || prev"
|
||||
" ELSE ''"
|
||||
" END"
|
||||
" FROM tabpk, tabname"
|
||||
")"
|
||||
""
|
||||
", main_select(m, n) AS ("
|
||||
" SELECT format("
|
||||
" '%%s, %%s\nSELECT %%s,\n%%s\nFROM intck_wrapper AS o"
|
||||
", intck_counter AS n%%s\nORDER BY %%s', "
|
||||
" w, ww.s, c, thiskey.k, whereclause.w_c, t.o_pk"
|
||||
" ), thiskey.n"
|
||||
" FROM case_statement, tabpk t, counter_with, "
|
||||
" wrapper_with ww, thiskey, whereclause"
|
||||
")"
|
||||
|
||||
"SELECT m, n FROM main_select",
|
||||
p->zDb, zObj, zPrev, zCommon
|
||||
);
|
||||
}
|
||||
|
||||
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
zRet = intckMprintf(p, "%s", (const char*)sqlite3_column_text(pStmt, 0));
|
||||
if( pnKeyVal ){
|
||||
*pnKeyVal = sqlite3_column_int(pStmt, 1);
|
||||
}
|
||||
}
|
||||
intckFinalize(p, pStmt);
|
||||
|
||||
if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 1");
|
||||
return zRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new integrity-check object.
|
||||
*/
|
||||
int sqlite3_intck_open(
|
||||
sqlite3 *db, /* Database handle to operate on */
|
||||
const char *zDbArg, /* "main", "temp" etc. */
|
||||
sqlite3_intck **ppOut /* OUT: New integrity-check handle */
|
||||
){
|
||||
sqlite3_intck *pNew = 0;
|
||||
int rc = SQLITE_OK;
|
||||
const char *zDb = zDbArg ? zDbArg : "main";
|
||||
int nDb = strlen(zDb);
|
||||
|
||||
pNew = (sqlite3_intck*)sqlite3_malloc(sizeof(*pNew) + nDb + 1);
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->db = db;
|
||||
pNew->zDb = (const char*)&pNew[1];
|
||||
memcpy(&pNew[1], zDb, nDb+1);
|
||||
rc = sqlite3_create_function(db, "parse_create_index",
|
||||
2, SQLITE_UTF8, 0, intckParseCreateIndexFunc, 0, 0
|
||||
);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_intck_close(pNew);
|
||||
pNew = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*ppOut = pNew;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the integrity-check object.
|
||||
*/
|
||||
void sqlite3_intck_close(sqlite3_intck *p){
|
||||
if( p ){
|
||||
sqlite3_finalize(p->pCheck);
|
||||
sqlite3_create_function(
|
||||
p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0
|
||||
);
|
||||
sqlite3_free(p->zObj);
|
||||
sqlite3_free(p->zKey);
|
||||
sqlite3_free(p->zTestSql);
|
||||
sqlite3_free(p->zErr);
|
||||
sqlite3_free(p->zMessage);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Step the integrity-check object.
|
||||
*/
|
||||
int sqlite3_intck_step(sqlite3_intck *p){
|
||||
if( p->rc==SQLITE_OK ){
|
||||
|
||||
if( p->zMessage ){
|
||||
sqlite3_free(p->zMessage);
|
||||
p->zMessage = 0;
|
||||
}
|
||||
|
||||
if( p->bCorruptSchema ){
|
||||
p->rc = SQLITE_DONE;
|
||||
}else
|
||||
if( p->pCheck==0 ){
|
||||
intckFindObject(p);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( p->zObj ){
|
||||
char *zSql = 0;
|
||||
zSql = intckCheckObjectSql(p, p->zObj, p->zKey, &p->nKeyVal);
|
||||
p->pCheck = intckPrepare(p, zSql);
|
||||
sqlite3_free(zSql);
|
||||
sqlite3_free(p->zKey);
|
||||
p->zKey = 0;
|
||||
}else{
|
||||
p->rc = SQLITE_DONE;
|
||||
}
|
||||
}else if( p->rc==SQLITE_CORRUPT ){
|
||||
p->rc = SQLITE_OK;
|
||||
p->zMessage = intckMprintf(p, "%s",
|
||||
"corruption found while reading database schema"
|
||||
);
|
||||
p->bCorruptSchema = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( p->pCheck ){
|
||||
assert( p->rc==SQLITE_OK );
|
||||
if( sqlite3_step(p->pCheck)==SQLITE_ROW ){
|
||||
/* Normal case, do nothing. */
|
||||
}else{
|
||||
intckFinalize(p, p->pCheck);
|
||||
p->pCheck = 0;
|
||||
p->nKeyVal = 0;
|
||||
if( p->rc==SQLITE_CORRUPT ){
|
||||
p->rc = SQLITE_OK;
|
||||
p->zMessage = intckMprintf(p,
|
||||
"corruption found while scanning database object %s", p->zObj
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p->rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a message describing the corruption encountered by the most recent
|
||||
** call to sqlite3_intck_step(), or NULL if no corruption was encountered.
|
||||
*/
|
||||
const char *sqlite3_intck_message(sqlite3_intck *p){
|
||||
assert( p->pCheck==0 || p->zMessage==0 );
|
||||
if( p->zMessage ){
|
||||
return p->zMessage;
|
||||
}
|
||||
if( p->pCheck ){
|
||||
return (const char*)sqlite3_column_text(p->pCheck, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the error code and message.
|
||||
*/
|
||||
int sqlite3_intck_error(sqlite3_intck *p, const char **pzErr){
|
||||
if( pzErr ) *pzErr = p->zErr;
|
||||
return (p->rc==SQLITE_DONE ? SQLITE_OK : p->rc);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close any read transaction the integrity-check object is holding open
|
||||
** on the database.
|
||||
*/
|
||||
int sqlite3_intck_unlock(sqlite3_intck *p){
|
||||
if( p->rc==SQLITE_OK && p->pCheck ){
|
||||
assert( p->zKey==0 && p->nKeyVal>0 );
|
||||
intckSaveKey(p);
|
||||
intckFinalize(p, p->pCheck);
|
||||
p->pCheck = 0;
|
||||
}
|
||||
return p->rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the SQL statement used to check object zObj. Or, if zObj is
|
||||
** NULL, the current SQL statement.
|
||||
*/
|
||||
const char *sqlite3_intck_test_sql(sqlite3_intck *p, const char *zObj){
|
||||
sqlite3_free(p->zTestSql);
|
||||
if( zObj ){
|
||||
p->zTestSql = intckCheckObjectSql(p, zObj, 0, 0);
|
||||
}else{
|
||||
if( p->zObj ){
|
||||
p->zTestSql = intckCheckObjectSql(p, p->zObj, p->zKey, 0);
|
||||
}else{
|
||||
sqlite3_free(p->zTestSql);
|
||||
p->zTestSql = 0;
|
||||
}
|
||||
}
|
||||
return p->zTestSql;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
** 2024-02-08
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
** Incremental Integrity-Check Extension
|
||||
** -------------------------------------
|
||||
**
|
||||
** This module contains code to check whether or not an SQLite database
|
||||
** is well-formed or corrupt. This is the same task as performed by SQLite's
|
||||
** built-in "PRAGMA integrity_check" command. This module differs from
|
||||
** "PRAGMA integrity_check" in that:
|
||||
**
|
||||
** + It is less thorough - this module does not detect certain types
|
||||
** of corruption that are detected by the PRAGMA command. However,
|
||||
** it does detect all kinds of corruption that are likely to cause
|
||||
** errors in SQLite applications.
|
||||
**
|
||||
** + It is slower. Sometimes up to three times slower.
|
||||
**
|
||||
** + It allows integrity-check operations to be split into multiple
|
||||
** transactions, so that the database does not need to be read-locked
|
||||
** for the duration of the integrity-check.
|
||||
**
|
||||
** One way to use the API to run integrity-check on the "main" database
|
||||
** of handle db is:
|
||||
**
|
||||
** int rc = SQLITE_OK;
|
||||
** sqlite3_intck *p = 0;
|
||||
**
|
||||
** sqlite3_intck_open(db, "main", &p);
|
||||
** while( SQLITE_OK==sqlite3_intck_step(p) ){
|
||||
** const char *zMsg = sqlite3_intck_message(p);
|
||||
** if( zMsg ) printf("corruption: %s\n", zMsg);
|
||||
** }
|
||||
** rc = sqlite3_intck_error(p, &zErr);
|
||||
** if( rc!=SQLITE_OK ){
|
||||
** printf("error occured (rc=%d), (errmsg=%s)\n", rc, zErr);
|
||||
** }
|
||||
** sqlite3_intck_close(p);
|
||||
**
|
||||
** Usually, the sqlite3_intck object opens a read transaction within the
|
||||
** first call to sqlite3_intck_step() and holds it open until the
|
||||
** integrity-check is complete. However, if sqlite3_intck_unlock() is
|
||||
** called, the read transaction is ended and a new read transaction opened
|
||||
** by the subsequent call to sqlite3_intck_step().
|
||||
*/
|
||||
|
||||
#ifndef _SQLITE_INTCK_H
|
||||
#define _SQLITE_INTCK_H
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** An ongoing incremental integrity-check operation is represented by an
|
||||
** opaque pointer of the following type.
|
||||
*/
|
||||
typedef struct sqlite3_intck sqlite3_intck;
|
||||
|
||||
/*
|
||||
** Open a new incremental integrity-check object. If successful, populate
|
||||
** output variable (*ppOut) with the new object handle and return SQLITE_OK.
|
||||
** Or, if an error occurs, set (*ppOut) to NULL and return an SQLite error
|
||||
** code (e.g. SQLITE_NOMEM).
|
||||
**
|
||||
** The integrity-check will be conducted on database zDb (which must be "main",
|
||||
** "temp", or the name of an attached database) of database handle db. Once
|
||||
** this function has been called successfully, the caller should not use
|
||||
** database handle db until the integrity-check object has been destroyed
|
||||
** using sqlite3_intck_close().
|
||||
*/
|
||||
int sqlite3_intck_open(
|
||||
sqlite3 *db, /* Database handle */
|
||||
const char *zDb, /* Database name ("main", "temp" etc.) */
|
||||
sqlite3_intck **ppOut /* OUT: New sqlite3_intck handle */
|
||||
);
|
||||
|
||||
/*
|
||||
** Close and release all resources associated with a handle opened by an
|
||||
** earlier call to sqlite3_intck_open(). The results of using an
|
||||
** integrity-check handle after it has been passed to this function are
|
||||
** undefined.
|
||||
*/
|
||||
void sqlite3_intck_close(sqlite3_intck *pCk);
|
||||
|
||||
/*
|
||||
** Do the next step of the integrity-check operation specified by the handle
|
||||
** passed as the only argument. This function returns SQLITE_DONE if the
|
||||
** integrity-check operation is finished, or an SQLite error code if
|
||||
** an error occurs, or SQLITE_OK if no error occurs but the integrity-check
|
||||
** is not finished. It is not considered an error if database corruption
|
||||
** is encountered.
|
||||
**
|
||||
** Following a successful call to sqlite3_intck_step() (one that returns
|
||||
** SQLITE_OK), sqlite3_intck_message() returns a non-NULL value if
|
||||
** corruption was detected in the db.
|
||||
**
|
||||
** If an error occurs and a value other than SQLITE_OK or SQLITE_DONE is
|
||||
** returned, then the integrity-check handle is placed in an error state.
|
||||
** In this state all subsequent calls to sqlite3_intck_step() or
|
||||
** sqlite3_intck_unlock() will immediately return the same error. The
|
||||
** sqlite3_intck_error() method may be used to obtain an English language
|
||||
** error message in this case.
|
||||
*/
|
||||
int sqlite3_intck_step(sqlite3_intck *pCk);
|
||||
|
||||
/*
|
||||
** If the previous call to sqlite3_intck_step() encountered corruption
|
||||
** within the database, then this function returns a pointer to a buffer
|
||||
** containing a nul-terminated string describing the corruption in
|
||||
** English. If the previous call to sqlite3_intck_step() did not encounter
|
||||
** corruption, or if there was no previous call, this function returns
|
||||
** NULL.
|
||||
*/
|
||||
const char *sqlite3_intck_message(sqlite3_intck *pCk);
|
||||
|
||||
/*
|
||||
** Close any read-transaction opened by an earlier call to
|
||||
** sqlite3_intck_step(). Any subsequent call to sqlite3_intck_step() will
|
||||
** open a new transaction. Return SQLITE_OK if successful, or an SQLite error
|
||||
** code otherwise.
|
||||
**
|
||||
** If an error occurs, then the integrity-check handle is placed in an error
|
||||
** state. In this state all subsequent calls to sqlite3_intck_step() or
|
||||
** sqlite3_intck_unlock() will immediately return the same error. The
|
||||
** sqlite3_intck_error() method may be used to obtain an English language
|
||||
** error message in this case.
|
||||
*/
|
||||
int sqlite3_intck_unlock(sqlite3_intck *pCk);
|
||||
|
||||
/*
|
||||
** If an error has occurred in an earlier call to sqlite3_intck_step()
|
||||
** or sqlite3_intck_unlock(), then this method returns the associated
|
||||
** SQLite error code. Additionally, if pzErr is not NULL, then (*pzErr)
|
||||
** may be set to point to a nul-terminated string containing an English
|
||||
** language error message. Or, if no error message is available, to
|
||||
** NULL.
|
||||
**
|
||||
** If no error has occurred within sqlite3_intck_step() or
|
||||
** sqlite_intck_unlock() calls on the handle passed as the first argument,
|
||||
** then SQLITE_OK is returned and (*pzErr) set to NULL.
|
||||
*/
|
||||
int sqlite3_intck_error(sqlite3_intck *pCk, const char **pzErr);
|
||||
|
||||
/*
|
||||
** This API is used for testing only. It returns the full-text of an SQL
|
||||
** statement used to test object zObj, which may be a table or index.
|
||||
** The returned buffer is valid until the next call to either this function
|
||||
** or sqlite3_intck_close() on the same sqlite3_intck handle.
|
||||
*/
|
||||
const char *sqlite3_intck_test_sql(sqlite3_intck *pCk, const char *zObj);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#endif /* ifndef _SQLITE_INTCK_H */
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
** 2010 August 28
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
** Code for testing all sorts of SQLite interfaces. This code
|
||||
** is not included in the SQLite library.
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "sqlite3intck.h"
|
||||
|
||||
#if defined(INCLUDE_SQLITE_TCL_H)
|
||||
# include "sqlite_tcl.h"
|
||||
#else
|
||||
# include "tcl.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* In test1.c */
|
||||
int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
const char *sqlite3ErrName(int);
|
||||
|
||||
typedef struct TestIntck TestIntck;
|
||||
struct TestIntck {
|
||||
sqlite3_intck *intck;
|
||||
};
|
||||
|
||||
static int testIntckCmd(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
struct Subcmd {
|
||||
const char *zName;
|
||||
int nArg;
|
||||
const char *zExpect;
|
||||
} aCmd[] = {
|
||||
{"close", 0, ""}, /* 0 */
|
||||
{"step", 0, ""}, /* 1 */
|
||||
{"message", 0, ""}, /* 2 */
|
||||
{"error", 0, ""}, /* 3 */
|
||||
{"unlock", 0, ""}, /* 4 */
|
||||
{"test_sql", 1, ""}, /* 5 */
|
||||
{0 , 0}
|
||||
};
|
||||
int rc = TCL_OK;
|
||||
int iIdx = -1;
|
||||
TestIntck *p = (TestIntck*)clientData;
|
||||
|
||||
if( objc<2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = Tcl_GetIndexFromObjStruct(
|
||||
interp, objv[1], aCmd, sizeof(aCmd[0]), "SUB-COMMAND", 0, &iIdx
|
||||
);
|
||||
if( rc ) return rc;
|
||||
|
||||
if( objc!=2+aCmd[iIdx].nArg ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, aCmd[iIdx].zExpect);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
switch( iIdx ){
|
||||
case 0: assert( 0==strcmp("close", aCmd[iIdx].zName) ); {
|
||||
Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: assert( 0==strcmp("step", aCmd[iIdx].zName) ); {
|
||||
int rc = sqlite3_intck_step(p->intck);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: assert( 0==strcmp("message", aCmd[iIdx].zName) ); {
|
||||
const char *z = sqlite3_intck_message(p->intck);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(z ? z : "", -1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: assert( 0==strcmp("error", aCmd[iIdx].zName) ); {
|
||||
const char *zErr = 0;
|
||||
int rc = sqlite3_intck_error(p->intck, 0);
|
||||
Tcl_Obj *pRes = Tcl_NewObj();
|
||||
Tcl_ListObjAppendElement(
|
||||
interp, pRes, Tcl_NewStringObj(sqlite3ErrName(rc), -1)
|
||||
);
|
||||
sqlite3_intck_error(p->intck, &zErr);
|
||||
Tcl_ListObjAppendElement(
|
||||
interp, pRes, Tcl_NewStringObj(zErr ? zErr : 0, -1)
|
||||
);
|
||||
Tcl_SetObjResult(interp, pRes);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: assert( 0==strcmp("unlock", aCmd[iIdx].zName) ); {
|
||||
int rc = sqlite3_intck_unlock(p->intck);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: assert( 0==strcmp("test_sql", aCmd[iIdx].zName) ); {
|
||||
const char *zObj = Tcl_GetString(objv[2]);
|
||||
const char *zSql = sqlite3_intck_test_sql(p->intck, zObj[0] ? zObj : 0);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(zSql, -1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for commands created by test_sqlite3_intck().
|
||||
*/
|
||||
static void testIntckFree(void *clientData){
|
||||
TestIntck *p = (TestIntck*)clientData;
|
||||
sqlite3_intck_close(p->intck);
|
||||
ckfree(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_intck DB DBNAME
|
||||
*/
|
||||
static int test_sqlite3_intck(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
char zName[64];
|
||||
int iName = 0;
|
||||
Tcl_CmdInfo info;
|
||||
TestIntck *p = 0;
|
||||
sqlite3 *db = 0;
|
||||
const char *zDb = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
p = (TestIntck*)ckalloc(sizeof(TestIntck));
|
||||
memset(p, 0, sizeof(TestIntck));
|
||||
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
if( zDb[0]=='\0' ) zDb = 0;
|
||||
|
||||
rc = sqlite3_intck_open(db, zDb, &p->intck);
|
||||
if( rc!=SQLITE_OK ){
|
||||
ckfree(p);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errstr(rc), -1));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
do {
|
||||
sprintf(zName, "intck%d", iName++);
|
||||
}while( Tcl_GetCommandInfo(interp, zName, &info)!=0 );
|
||||
Tcl_CreateObjCommand(interp, zName, testIntckCmd, (void*)p, testIntckFree);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(zName, -1));
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: test_do_intck DB DBNAME
|
||||
*/
|
||||
static int test_do_intck(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db = 0;
|
||||
const char *zDb = 0;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_intck *pCk = 0;
|
||||
Tcl_Obj *pRet = 0;
|
||||
const char *zErr = 0;
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
|
||||
pRet = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pRet);
|
||||
|
||||
rc = sqlite3_intck_open(db, zDb, &pCk);
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_intck_step(pCk)==SQLITE_OK ){
|
||||
const char *zMsg = sqlite3_intck_message(pCk);
|
||||
if( zMsg ){
|
||||
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zMsg, -1));
|
||||
}
|
||||
}
|
||||
rc = sqlite3_intck_error(pCk, &zErr);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( zErr ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
|
||||
}else{
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||
}
|
||||
}else{
|
||||
Tcl_SetObjResult(interp, pRet);
|
||||
}
|
||||
Tcl_DecrRefCount(pRet);
|
||||
sqlite3_intck_close(pCk);
|
||||
sqlite3_intck_close(0);
|
||||
return rc ? TCL_ERROR : TCL_OK;
|
||||
}
|
||||
|
||||
int Sqlitetestintck_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_intck", test_sqlite3_intck, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "test_do_intck", test_do_intck, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
+11
-12
@@ -694,11 +694,9 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
|
||||
** Clear the Rtree.pNodeBlob object
|
||||
*/
|
||||
static void nodeBlobReset(Rtree *pRtree){
|
||||
if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
|
||||
sqlite3_blob *pBlob = pRtree->pNodeBlob;
|
||||
pRtree->pNodeBlob = 0;
|
||||
sqlite3_blob_close(pBlob);
|
||||
}
|
||||
sqlite3_blob *pBlob = pRtree->pNodeBlob;
|
||||
pRtree->pNodeBlob = 0;
|
||||
sqlite3_blob_close(pBlob);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -742,7 +740,6 @@ static int nodeAcquire(
|
||||
&pRtree->pNodeBlob);
|
||||
}
|
||||
if( rc ){
|
||||
nodeBlobReset(pRtree);
|
||||
*ppNode = 0;
|
||||
/* If unable to open an sqlite3_blob on the desired row, that can only
|
||||
** be because the shadow tables hold erroneous data. */
|
||||
@@ -802,6 +799,7 @@ static int nodeAcquire(
|
||||
}
|
||||
*ppNode = pNode;
|
||||
}else{
|
||||
nodeBlobReset(pRtree);
|
||||
if( pNode ){
|
||||
pRtree->nNodeRef--;
|
||||
sqlite3_free(pNode);
|
||||
@@ -1055,9 +1053,9 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
int rc;
|
||||
char *zCreate = sqlite3_mprintf(
|
||||
"DROP TABLE '%q'.'%q_node';"
|
||||
"DROP TABLE '%q'.'%q_rowid';"
|
||||
"DROP TABLE '%q'.'%q_parent';",
|
||||
"DROP TABLE '%q'.'%q_node',"
|
||||
"'%q'.'%q_rowid',"
|
||||
"'%q'.'%q_parent';",
|
||||
pRtree->zDb, pRtree->zName,
|
||||
pRtree->zDb, pRtree->zName,
|
||||
pRtree->zDb, pRtree->zName
|
||||
@@ -1136,7 +1134,9 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
|
||||
sqlite3_finalize(pCsr->pReadAux);
|
||||
sqlite3_free(pCsr);
|
||||
pRtree->nCursor--;
|
||||
nodeBlobReset(pRtree);
|
||||
if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){
|
||||
nodeBlobReset(pRtree);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -3226,7 +3226,7 @@ constraint:
|
||||
static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
assert( pRtree->inWrTrans==0 );
|
||||
pRtree->inWrTrans++;
|
||||
pRtree->inWrTrans = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -3241,7 +3241,6 @@ static int rtreeEndTransaction(sqlite3_vtab *pVtab){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static int rtreeRollback(sqlite3_vtab *pVtab){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
return rtreeEndTransaction(pVtab);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ if {![info exists testdir]} {
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
set testprefix rtreeJ
|
||||
ifcapable !rtree { finish_test ; return }
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2);
|
||||
|
||||
@@ -92,7 +92,7 @@ do_test 2.1 {
|
||||
} {}
|
||||
|
||||
do_execsql_test -db db2 2.2 {
|
||||
SELECT * FROM sqlite_stat1
|
||||
SELECT * FROM sqlite_stat1 ORDER BY tbl, idx
|
||||
} {
|
||||
t1 sqlite_autoindex_t1_1 {32 1}
|
||||
t1 t1b {32 4}
|
||||
@@ -104,7 +104,7 @@ do_test 2.3 {
|
||||
} {}
|
||||
|
||||
do_execsql_test -db db2 2.4 {
|
||||
SELECT * FROM sqlite_stat1
|
||||
SELECT * FROM sqlite_stat1 ORDER BY tbl, idx;
|
||||
} {
|
||||
t1 sqlite_autoindex_t1_1 {32 1}
|
||||
t1 t1b {32 4}
|
||||
|
||||
@@ -1137,8 +1137,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
existing content. Throws if the pool has no available file slots,
|
||||
on I/O error, or if the input does not appear to be a
|
||||
database. In the latter case, only a cursory examination is made.
|
||||
Note that this routine is _only_ for importing database files,
|
||||
not arbitrary files, the reason being that this VFS will
|
||||
Results are undefined if the given db name refers to an opened
|
||||
db. Note that this routine is _only_ for importing database
|
||||
files, not arbitrary files, the reason being that this VFS will
|
||||
automatically clean up any non-database files so importing them
|
||||
is pointless.
|
||||
|
||||
|
||||
@@ -1193,16 +1193,18 @@ const installOpfsVfs = function callee(options){
|
||||
Asynchronously imports the given bytes (a byte array or
|
||||
ArrayBuffer) into the given database file.
|
||||
|
||||
Results are undefined if the given db name refers to an opened
|
||||
db.
|
||||
|
||||
If passed a function for its second argument, its behaviour
|
||||
changes to async and it imports its data in chunks fed to it by
|
||||
the given callback function. It calls the callback (which may
|
||||
be async) repeatedly, expecting either a Uint8Array or
|
||||
ArrayBuffer (to denote new input) or undefined (to denote
|
||||
EOF). For so long as the callback continues to return
|
||||
non-undefined, it will append incoming data to the given
|
||||
VFS-hosted database file. When called this way, the resolved
|
||||
value of the returned Promise is the number of bytes written to
|
||||
the target file.
|
||||
changes: imports its data in chunks fed to it by the given
|
||||
callback function. It calls the callback (which may be async)
|
||||
repeatedly, expecting either a Uint8Array or ArrayBuffer (to
|
||||
denote new input) or undefined (to denote EOF). For so long as
|
||||
the callback continues to return non-undefined, it will append
|
||||
incoming data to the given VFS-hosted database file. When
|
||||
called this way, the resolved value of the returned Promise is
|
||||
the number of bytes written to the target file.
|
||||
|
||||
It very specifically requires the input to be an SQLite3
|
||||
database and throws if that's not the case. It does so in
|
||||
|
||||
@@ -230,7 +230,6 @@ SRC += \
|
||||
SRC += \
|
||||
$(TOP)/ext/misc/stmt.c
|
||||
|
||||
|
||||
# FTS5 things
|
||||
#
|
||||
FTS5_HDR = \
|
||||
@@ -375,7 +374,9 @@ TESTSRC += \
|
||||
$(TOP)/ext/rtree/test_rtreedoc.c \
|
||||
$(TOP)/ext/recover/sqlite3recover.c \
|
||||
$(TOP)/ext/recover/dbdata.c \
|
||||
$(TOP)/ext/recover/test_recover.c
|
||||
$(TOP)/ext/recover/test_recover.c \
|
||||
$(TOP)/ext/intck/test_intck.c \
|
||||
$(TOP)/ext/intck/sqlite3intck.c
|
||||
|
||||
|
||||
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c
|
||||
@@ -659,7 +660,7 @@ target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl fts5.c
|
||||
touch target_source
|
||||
|
||||
sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl src-verify
|
||||
tclsh $(TOP)/tool/mksqlite3c.tcl
|
||||
tclsh $(TOP)/tool/mksqlite3c.tcl $(EXTRA_SRC)
|
||||
cp tsrc/sqlite3ext.h .
|
||||
cp $(TOP)/ext/session/sqlite3session.h .
|
||||
echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
|
||||
@@ -671,7 +672,7 @@ sqlite3ext.h: target_source
|
||||
cp tsrc/sqlite3ext.h .
|
||||
|
||||
sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl src-verify
|
||||
tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros=1
|
||||
tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros=1 $(EXTRA_SRC)
|
||||
echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
|
||||
cat sqlite3.c >>tclsqlite3.c
|
||||
echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
C Return\sSQLITE_ABORT\sif\sthe\sunderlying\sshadow\stables\schange\sin\sthe\smiddle\sof\san\srtree\squery\sin\ssuch\sa\sway\sas\sto\sinvalidate\san\srtree\sinternal\spriority\squeue\sentry.
|
||||
D 2024-02-05T17:35:36.153
|
||||
C The\sability\sto\sDROP\smultiple\stables\s(or\sviews\sor\sindexes\sor\striggers)\sat\sonce,\nas\simplemented\sby\sthis\sbranch,\sappears\sto\swork.\s\sHowever,\sthis\sbranch\sadds\sover\n1000\sbytes\sto\sthe\scode\sfootprint.\s\sAnd\sthe\schanges\sis\ssignificant,\sadding\srisk.\nThe\sbenefit\sof\sbeing\sable\sto\sdrop\smultiple\stables\sin\sa\ssingle\sstatement\sis\snot\nseen\sto\sbe\senough\sto\sovercome\sthose\sdownsides,\sand\sso\sthere\sare\sno\simmediate\nplans\sto\smerge\sthis\sbranch.
|
||||
D 2024-03-04T18:02:36.966
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 24be65ae641c5727bbc247d60286a15ecc24fb80f14f8fb2d32533bf0ec96e79
|
||||
F Makefile.in 3c4f4879b2301e5486939f68cc64f84430861d246ac11430ff1a1d7347ed5b8c
|
||||
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
|
||||
F Makefile.msc df56c06ef05add5ebcdcc9d4823fb2ec66ac16b06acb6971a7420859025886fa
|
||||
F Makefile.msc 15a875f6016c4200e7093db92365fabb8b32eb09f9e40e1aadeedeecad4050d5
|
||||
F README.md 6358805260a03ebead84e168bbf3740ddf3f683b477e478567186aa7afb490d3
|
||||
F VERSION c84541c6a9e8426462176fbb1f9ecb5cfd7d1bb56228053ff7eeba8841673eb6
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am adedc1324b6a87fdd1265ddd336d2fb7d4f36a0e77b86ea553ae7cc4ea239347
|
||||
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
|
||||
F autoconf/Makefile.msc ac338c36a338f6b49475da71930f45145a181d6b551578d5a7a64f113ef27b2c
|
||||
F autoconf/Makefile.msc 7ac6c331fc3b8aa57b6782db995b8c0e49230352decd4e2662fd07c06a9ed623
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 42cfd21d0b19dc7d5d85fb5c405c5f3c6a4c923021c39128f6ba685355d8fd56
|
||||
F autoconf/configure.ac ec7fa914c5e74ff212fe879f9bb6918e1234497e05facfb641f30c4d5893b277
|
||||
@@ -97,7 +99,7 @@ F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70
|
||||
F ext/fts5/fts5_config.c 8072a207034b51ae9b7694121d1b5715c794e94b275e088f70ae532378ca5cdf
|
||||
F ext/fts5/fts5_expr.c e91156ebdcc08d837f4f324168f69f3c0d7fdef0e521fd561efb48ef3297b696
|
||||
F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1
|
||||
F ext/fts5/fts5_index.c bb1965c3965f6fe5f64160bf1c0694a9684a790a783f293a76da1d38d319b258
|
||||
F ext/fts5/fts5_index.c ee0f4d50bc0c58a7c5ef7d645e7e38e1e59315b8ea9d722ae00c5f949ee65379
|
||||
F ext/fts5/fts5_main.c d68bd9533d5a638b7f6fae61c3cb0a15257dcdcccedaf3d0b3c9f55940c85048
|
||||
F ext/fts5/fts5_storage.c f9e31b0d155e9b2c92d5d3a09ad7a56b937fbf1c7f962e10f4ca6281349f3934
|
||||
F ext/fts5/fts5_tcl.c fdf7e2bb9a9186cfcaf2d2ce11d338309342b7a7593c2812bc54455db53da5d2
|
||||
@@ -171,7 +173,7 @@ F ext/fts5/test/fts5faultD.test e7ed7895abfe6bc98a5e853826f6b74956e7ba7f594f1860
|
||||
F ext/fts5/test/fts5faultE.test 844586ce71dab4be85bb86880e87b624d089f851654cd22e4710c77eb8ce7075
|
||||
F ext/fts5/test/fts5faultF.test 4abef99f86e99d9f0c6460dd68c586a766b6b9f1f660ada55bf2e8266bd1bbc1
|
||||
F ext/fts5/test/fts5faultG.test d2e5a4d9a34e08dcaadcaeafef74d10cbc2abdd11aa2659a18af0294bf2812d3
|
||||
F ext/fts5/test/fts5faultH.test 57f53c87ffd59be0265840f2b54a16811f9cb9012db86aad9b41d0d14d85dfe3
|
||||
F ext/fts5/test/fts5faultH.test b5c3b62642b7d321504a0a4f424eb80b4f6927969173334c8ca20df388557622
|
||||
F ext/fts5/test/fts5first.test 3fcf2365c00a15fc9704233674789a3b95131d12de18a9b996159f6909dc8079
|
||||
F ext/fts5/test/fts5full.test e1701a112354e0ff9a1fdffb0c940c576530c33732ee20ac5e8361777070d717
|
||||
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
|
||||
@@ -248,6 +250,15 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
||||
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
|
||||
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
|
||||
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
|
||||
F ext/intck/intck1.test 8a879640c90fdff5e91e6c2c41d509485ee634e8077fe0ca9f76be4cbd441fa3
|
||||
F ext/intck/intck2.test 47afb44681d13d11072cd8906e6aa877c967e65be788b01f6139922fd91474ef
|
||||
F ext/intck/intck_common.tcl 9e51458126576783f11051ac0fd25bea3f6b17f570a55884223737f3200b214b
|
||||
F ext/intck/intckbusy.test 0732fe3efbb9e0a53ffdcc240073f6ff2777ea82c3e08812b16494f650763fe1
|
||||
F ext/intck/intckcorrupt.test 3211ef68ac53e83951b6c8f6a8d2396506d123fe5898f97f848a25837744ec56
|
||||
F ext/intck/intckfault.test ba0213c9c8dce08d519d5251268a3bab076a184b4d07acdea23b65e89c9ae03c
|
||||
F ext/intck/sqlite3intck.c 52381a627637504a49e93400814b36e99afa0b972a9a24ef1732b8268bb27fa8
|
||||
F ext/intck/sqlite3intck.h 2b40c38e7063ab822c974c0bd4aed97dabb579ccfe2e180a4639bb3bbef0f1c9
|
||||
F ext/intck/test_intck.c d63f1707432802f5db125ee40b794923af77d4686869bd8d3a7eb43332344267
|
||||
F ext/jni/GNUmakefile 59eb05f2a363bdfac8d15d66bed624bfe1ff289229184f3861b95f98a19cf4b2
|
||||
F ext/jni/README.md d899789a9082a07b99bf30b1bbb6204ae57c060efcaa634536fa669323918f42
|
||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||
@@ -495,7 +506,7 @@ F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c3350
|
||||
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/geopoly.c 0dd4775e896cee6067979d67aff7c998e75c2c9d9cd8d62a1a790c09cde7adca
|
||||
F ext/rtree/rtree.c d96c5d34eafcd46bc4b7645c26a4bcc3169d9e70e9df707ef91c2e90870d00d9
|
||||
F ext/rtree/rtree.c c65a133bb697d20c0ac60ac09dc3a1cbf55500bfd6e9e730d2469aa6113480ed
|
||||
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
|
||||
F ext/rtree/rtree1.test 2b5b8c719c6a4abe377f57766f428a49af36a93061cb146cccfdc3b30000c0a4
|
||||
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
|
||||
@@ -515,7 +526,7 @@ F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd
|
||||
F ext/rtree/rtreeG.test 1b9ca6e3effb48f4161edaa463ddeaa8fca4b2526d084f9cbf5dbe4e0184939c
|
||||
F ext/rtree/rtreeH.test 0885151ee8429242625600ae47142cca935332c70a06737f35af53a7bd7aaf90
|
||||
F ext/rtree/rtreeI.test 608e77f7fde9be5a12eae316baef640fffaafcfa90a3d67443e78123e19c4ca4
|
||||
F ext/rtree/rtreeJ.test ba4e25c409ebed4b96bf1270e72760c1344d0a464478d221dbe91e8471ac9ac6
|
||||
F ext/rtree/rtreeJ.test 93227ccd4d6c328f5ac46a902b8880041509dd2d68f6ce71560f0d8ab5bb507a
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 202ca70df1f0645ef9d5a2170e62d378a28098d9407f0569e85c9c1cf1bd020a
|
||||
F ext/rtree/rtreecheck.test 934546ad9b563e090ee0c5cbdc69ad014189ad76e5df7320526797a9a345661f
|
||||
@@ -567,7 +578,7 @@ F ext/session/sessionnoop2.test de4672dce88464396ec9f30ed08c6c01643a69c53ae540fa
|
||||
F ext/session/sessionrebase.test 702378bdcb5062f1106e74457beca8797d09c113a81768734a58b197b5b334e2
|
||||
F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a80600a44396f7363
|
||||
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
|
||||
F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c
|
||||
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
|
||||
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
||||
F ext/session/sqlite3session.c 829d468f0f3d2710aace56b0116a7ca3f414683ce78e3125ae5e21547a895078
|
||||
F ext/session/sqlite3session.h 4cf19a51975746d7cff2fdd74db8b769c570958e1c3639ac150d824ac1553b3e
|
||||
@@ -601,8 +612,8 @@ F ext/wasm/api/sqlite3-api-worker1.js 8d9c0562831f62218170a3373468d8a0b7a6503b59
|
||||
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
|
||||
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 595953994aa3ae2287c889c4da39ab3d6f17b6461ecf4bec334b7a3faafddb02
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js ebf6c7e997cd8948b35b3afc550b0503dd53febd9d2b56354efd11d985e5f0f2
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 5a430874906ff3f4a6ca69aadf0c2aaedc1bb45489b8365bff7e955a83a8d42a
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js fe427645e1499618f5fa7bc670af850577d8bcc132df982078690c9bf8400baa
|
||||
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js a2fcbc3fecdd0eea229283584ebc122f29d98194083675dbe5cb2cf3a17fe309
|
||||
F ext/wasm/api/sqlite3-wasm.c d33a16495ca871781e78812d3a18fed78b797468fffee657b8d7199b277ff359
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js e8135b44a568badfe197e2379f6b42899f2240b5c3a77fa044331110f7ce8e50
|
||||
@@ -659,7 +670,7 @@ F ext/wasm/wasmfs.make 8a4955882aaa0783b3f60a9484a1f0f3d8b6f775c0fcd17c082f31966
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk ef8d6b0e76b27d2b32d7b71ea30a2b2626b668f998a4f32f6171c9623a310a53
|
||||
F main.mk 2c8b556ba7a4a15f5440663f7b05da221355d1921d5c75298bb50e2bb8081d79
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
|
||||
@@ -672,16 +683,16 @@ F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
|
||||
F src/alter.c 30c2333b8bb3af71e4eb9adeadee8aa20edb15917ed44b8422e5cd15f3dfcddc
|
||||
F src/analyze.c 0f15753308c3bca7674f31fa7e0807ffcb8b120c36eef7d00b62b33079ddc854
|
||||
F src/analyze.c a3df28274e2565ba5656577d7e3fd262169a213e6eb0bd47890e0f0729a4031c
|
||||
F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39
|
||||
F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
|
||||
F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
|
||||
F src/btree.c bf659f4b1622c120ec6a863ba96c63f1861595ca21124950d977cec1477dd922
|
||||
F src/btree.h 03e3356f5208bcab8eed4e094240fdac4a7f9f5ddf5e91045ce589f67d47c240
|
||||
F src/btreeInt.h 3e2589726c4f105e653461814f65857465da68be1fac688de340c43b873f4062
|
||||
F src/build.c 05c9eb387638982092988d2ef4c00a91b0c29baa1b85923f082ce0cf2903ea7e
|
||||
F src/btree.c 285b493d843e7ba8ef78b6ae7d31238e904901dbc0c484f7904de4cf18fd8802
|
||||
F src/btree.h 55066f513eb095db935169dab1dc2f7c7a747ef223c533f5d4ad4dfed346cbd0
|
||||
F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6
|
||||
F src/build.c 7ee3616b8a25577f2fb715d91eaa27f62a34e6ee6d0130cc8b9644c07875b759
|
||||
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
|
||||
@@ -689,21 +700,21 @@ F src/date.c 90df32c2d8b2a38dd2e83d32e47802629305c4882fb2ec75c9ecdcd75b68bcb2
|
||||
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
|
||||
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
|
||||
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
|
||||
F src/expr.c 3381ee4c9aa7ccde22a2a7f35ce343925a7a25d96bdc943649131f9decdebad2
|
||||
F src/expr.c 2803f5e7e3458ced24c0de48ec3640cd7a68ec61350d99c9f30b1bcd6640bd61
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
|
||||
F src/func.c c71b81223e165722cd81fa71fb869a235de5998c4c5142a5dfa2725d6331f539
|
||||
F src/fkey.c 0592046ed7598625234298211cc1fe611efb3fe7870a3f1938038fd9092c82f9
|
||||
F src/func.c 4204c56196847faefef57fa14e43b8e4d65eb8d7e65318abe463472e3fd148cb
|
||||
F src/global.c 765a0656d6cbf043cb272ff0ae38f39cc46713539ffe6793258ed3eb4b188b52
|
||||
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
|
||||
F src/json.c ae8847ccf8e212650d8a79277750f2123a03ae040d21d96ff5010114bd5b1040
|
||||
F src/json.c 3b4e2778d95d923d6d77e8a5efd51a6265017b466782d597303f5f094fcd68af
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
||||
F src/main.c 438b95162acfa17b7d218f586f5bde11d6ae82bcf030c9611fc537556870ad6b
|
||||
F src/malloc.c c31472af77e3421d993b69c93f07890277afd94247da4290e1b290ffc0d1f404
|
||||
F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
|
||||
@@ -723,28 +734,28 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
|
||||
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
|
||||
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
|
||||
F src/os_unix.c fa9b81b642e60e77ffaf98bd1a2e5fde16c1c2317614ec178bf3bd5864772356
|
||||
F src/os_unix.c 8d7533b3b4d0d2d6ddd34d1ebc92f50a91f04e722a3a9295a000bc3c25128e2f
|
||||
F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd
|
||||
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
|
||||
F src/parse.y bfd6da46fc895cd8237400ff485d04ab0b32e47eb56de20982bb7f53e56c1f42
|
||||
F src/parse.y 9a77520c83950ced6e8b981c7826ebfd8e4a5c6e4b5d9743639e357910180c94
|
||||
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
|
||||
F src/pragma.c f9b6bb9a044a0dfda1f31c2d1523c7970f850688b450f06e61e23672d70adac0
|
||||
F src/pragma.c e8221d6310c9923c80f6fa6d09b7ea7c5263a671f53db8d0894df23efcdb617b
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c
|
||||
F src/printf.c 18fbdf028345c8fbe6044f5f5bfda5a10d48d6287afef088cc21b0ca57985640
|
||||
F src/printf.c 10e8bad30042f8bd6114a013b4afc229ec8ad255ab27518d7d9f52e8cbc5cd0a
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 0ed10ebb70d15dcf3f1882051931ccfaf9c3f4debe67dbd114047d9e2adb9523
|
||||
F src/resolve.c d77c6160bc8f249c2196fdd3e75f66a1dd70e37aa25c39aedc7b1f93c42b7c6d
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c f1a81ff4f8e9e76c224e2ab3a4baa799add0db22158c7fcede65d8cc4a6fa2da
|
||||
F src/shell.c.in c6cb773b7703d76677529de19d1c40584520701966422c33da3e9334498a7099
|
||||
F src/sqlite.h.in 61a60b4ea04db8ead15e1579b20b64cb56e9f55d52c5f9f9694de630110593a3
|
||||
F src/select.c 43fabfc01bf87addd15e39f112f1e2ade15b19594835ab8a9e5bd50839d4e1b1
|
||||
F src/shell.c.in 2ec564ed3ff0147036be313efeb47b3dbfb8753d5eb5ea0e90636427c6b3a365
|
||||
F src/sqlite.h.in 19a2db3995a699bd7f6dfb423856242bfceb7ec849a93c91d241d19fc28d9f0f
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
|
||||
F src/sqliteInt.h 5013ac1f5642df4c0b76314f507f4c7b6f8efee0e1d7c2e93bf8b445ceea29bb
|
||||
F src/sqliteInt.h 532224eec9f53245c8450c662c2a9d06a1aec22cb28e5fc4cdfd0f67239e9049
|
||||
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
|
||||
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -790,7 +801,7 @@ F src/test_schema.c cbfd7a9a9b6b40d4377d0c76a6c5b2a58387385977f26edab4e77eb5f90a
|
||||
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
|
||||
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
|
||||
F src/test_syscall.c 9fdb13b1df05e639808d44fcb8f6064aaded32b6565c00b215cfd05a060d1aca
|
||||
F src/test_tclsh.c 3ff5d188a72f00807425954ea3b493dfd3a4b890ecc6700ea83bad2fd1332ecf
|
||||
F src/test_tclsh.c aaf0d1de4a518a8db5ad38e5262be3e48b4a74ad1909f2dba753cecb30979d5d
|
||||
F src/test_tclvar.c 3273f9d59395b336e381b53cfc68ec6ebdaada4e93106a2e976ffb0550504e1c
|
||||
F src/test_thread.c 7ddcf0c8b79fa3c1d172f82f322302c963d923cdb503c6171f3c8081586d0b01
|
||||
F src/test_vdbecov.c f60c6f135ec42c0de013a1d5136777aa328a776d33277f92abac648930453d43
|
||||
@@ -801,30 +812,30 @@ F src/test_windirent.h da2e5b73c32d09905fbdd00f27cd802212a32a58ead882736fe4f5eb7
|
||||
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 23d9f4539880b40226254ad9072f4ecf12eb1902e62aea47aac29928afafcfd5
|
||||
F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68
|
||||
F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70ee
|
||||
F src/trigger.c 0905b96b04bb6658509f711a8207287f1315cdbc3df1a1b13ba6483c8e341c81
|
||||
F src/trigger.c 15ca35f491c03197c3ccd5a0b3c5b926719cbe4e185b73da0507dbeb84a52d0e
|
||||
F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92
|
||||
F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242
|
||||
F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
|
||||
F src/util.c 078f040366d5bd5f47658d045f901c768c1c636c6eaea121f3a1cbd63c3edb5b
|
||||
F src/util.c 0765014847e2a06c952dd64aef0bea5144cd5b335a161eb0768ebe4f63dfe216
|
||||
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
|
||||
F src/vdbe.c dd340f5add924a8397401f7fe4faf2304ffd49ab5853d32ffc1736093b9c5080
|
||||
F src/vdbe.h 88e19a982df9027ec1c177c793d1a5d34dc23d8f06e3b2d997f43688b05ee0eb
|
||||
F src/vdbe.c 523a88b3df328810fbcbb407738c352dd9d5163b7af4c953e6e9887a4b582859
|
||||
F src/vdbe.h c2d78d15112c3fc5ab87f5e8e0b75d2db1c624409de2e858c3d1aafb1650bb4f
|
||||
F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
|
||||
F src/vdbeapi.c 8f57d60c89da0b60e6d4e272358c511f6bae4e24330bdb11f8b42f986d1bf21b
|
||||
F src/vdbeaux.c c5a471b34e9c4cfc0295a3e10734fd197670ffaebcb742f284c8e17e8026ceea
|
||||
F src/vdbeaux.c 66161ba75c4a2d86aab124fe3cbcc2a752d8e4b1fc8c1fc6e00625db4798168c
|
||||
F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5
|
||||
F src/vdbemem.c 3e37dab421b74e9ce55c1e88fbc7bc6fead590b5ab258bc684f8b70abb1d6e71
|
||||
F src/vdbesort.c 00c1fb15171205063556c2f1cf454e24c0b41c1effb0c876b850dce91f21bc64
|
||||
F src/vdbemem.c 213bf303826c0ef702e3a2a69dab2309d84b8381b822c6787885859fd7cd4c4e
|
||||
F src/vdbesort.c 237840ca1947511fa59bd4e18b9eeae93f2af2468c34d2427b059f896230a547
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbevtab.c 2143db7db0ceed69b21422581f434baffc507a08d831565193a7a02882a1b6a7
|
||||
F src/vtab.c 11948e105f56e84099ca17f1f434b1944539ea84de26d0d767eadfbc670ce1ea
|
||||
F src/vtab.c 38fcf63832f7e606755fa47b028c2eb6d6cd5facb40e280d66fbda4ed9a52188
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
|
||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
|
||||
F src/where.c 0a6492afeb75f8d2a50e26b993eb78e9623b142e637cd3f2cdb85e896931d51d
|
||||
F src/where.c 33eaaeef3aef10c2b9e82096e70a174d6636e35cb0b180321b8ddf804590e5cd
|
||||
F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
|
||||
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
|
||||
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
|
||||
@@ -834,14 +845,14 @@ F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867d
|
||||
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
|
||||
F test/aggnested.test 610b0ce2c3e8f3daee25f9752800ee8d785db10da4aa1fbeea0ea1aabaf1d704
|
||||
F test/aggorderby.test cc3abf5de64d46ff66395ca8c2346b66c2576d5aedb7bffc5b0742508856e3bf
|
||||
F test/aggnested.test 4dfdbfab105cec5750a1eeb59284ffffc3b37a32aaaf09143df3f549e28e2081
|
||||
F test/aggorderby.test af1e07766e8f752d54dd317aa1d956e8e896671a70ddb20228e8cdf9391023b1
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
|
||||
F test/alter.test 3c00eff1e2036b9f93e9cd0f3d3e63750ac87ecb5bc71b9d7bd07cbf2ac4c494
|
||||
F test/alter2.test 7e3d26ab409df52df887b366a63902c3429b935c41cb962fd58ffc25784f2f19
|
||||
F test/alter3.test ffc4ab29ce78a3517a66afd69b2730667e3471622509c283b2bd4c46f680fba3
|
||||
F test/alter4.test 716caa071dd8a3c6d57225778d15d3c3cbf5e34b2e84ae44199aeb2bbf50a707
|
||||
F test/alter3.test 0663df0cb3b9558ccc21abe642b792d4e2e747164156208e2a44ce88c09fe09b
|
||||
F test/alter4.test 0ef8e62259bbc17495456d19e33a97b14cc2f634ef67bfdfb6a3f826eb9cfbc1
|
||||
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
|
||||
F test/alterauth2.test 48967abae0494d9a300d1c92473d99fcb66edfcc23579c89322f033f49410adc
|
||||
F test/altercol.test 29fed774747777fbbaacdd865b4413ed2d0844a4c824f8af531b5c7d4a832087
|
||||
@@ -859,7 +870,7 @@ F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5
|
||||
F test/altertab3.test 6c432fbb9963e0bd6549bf1422f6861d744ee5a80cb3298564e81e556481df16
|
||||
F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b
|
||||
F test/analyze.test e8ab7a3fa8b0294dd72c6d0acd822c3b69fd4ab9392789b29dd29daaa8601b4c
|
||||
F test/analyze3.test 03f4b3d794760cf15da2d85a52df9bae300e51c8fefe9c36cfae1f86dc10d23f
|
||||
F test/analyze4.test 68bd069f3ac7ac1e652ddd9f04f57d5606ddb4208450f5297005db7aa0dd707d
|
||||
F test/analyze5.test fa5131952303ac4146aba101b116b9c8cb89e2637531c334a6df7f7d19dddc0d
|
||||
@@ -887,7 +898,7 @@ F test/attach2.test 6d1e3a457ce260d6fc8e5945c07fba6c76dc2aa90e1c701f067b50ee88f7
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test 00e754484859998d124d144de6d114d920f2ed6ca2f961e6a7f4183c714f885e
|
||||
F test/attachmalloc.test 67309af95c6b765c13e7d2279d7fccbef78e6eb0565d75d51cefd5dc88784549
|
||||
F test/auth.test 5b8558a40571ebc55c1581cb7cec3b2348a699542a0a51b83ef21c6a953d95e3
|
||||
F test/auth.test 8d4152a8dca10e6dbe15b0c6dfcc183d5e9a7f6f983d9ae6e05f70e947aed7c3
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
@@ -947,7 +958,7 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
||||
F test/btree01.test fef17d9e999ac4f04095948e3438fbe674f4e07bb2c63bb1cad41d87baee077f
|
||||
F test/btree02.test 7555a5440453d900410160a52554fe6478af4faf53098f7235f1f443d5a1d6cc
|
||||
F test/btreefault.test a82a23b0578bc587afbf9a622c8f54a54f63762f062ba8a35613cfee38ab42f9
|
||||
F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727
|
||||
F test/busy.test caff7164c16ce06a53af51f9e4c2753d4cc64250e00790a5e48b9c4f4be37597
|
||||
F test/busy2.test 20823a5d7c42fb257d9f108c66312d90b1bb4ec3d80ba6b4e371073727560f98
|
||||
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
|
||||
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
|
||||
@@ -999,7 +1010,7 @@ F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85
|
||||
F test/corruptA.test 112f4b2ae0b95ebf3ea63718642fb969a93acea557ace3a307234d19c245989b
|
||||
F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec
|
||||
F test/corruptC.test 9cf32275dae3ca33f645afe5d1d3f5ba5ac2af2b0833dfb5282f9dccb6fb81bb
|
||||
F test/corruptD.test a828c788535946a372a56a750b242cd96287cd823657abe5a73c5e51b91bdd28
|
||||
F test/corruptD.test 614320aa519f6bf6c7dd2f581f9513ff7b6826954180cca1a606d0e25ea084a3
|
||||
F test/corruptE.test 4143791f2dfb443aec5b7fabfa5821e6063eccc3b49b06f212c2f014715fd476
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
|
||||
@@ -1058,6 +1069,7 @@ F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test 691c9e850b0d0b56b66e7e235453198cb4cf0760e324b7403d3c5abbeab0a014
|
||||
F test/distinct2.test bb71cc7b5e58e895787f9910a788c254f679928d324732d063fe9bc202ecbe71
|
||||
F test/distinctagg.test 40d7169ae5846caaf62c6e307d2ca3c333daf9b6f7cde888956a339a97afe85f
|
||||
F test/drop-many.test 30dd091a4fd0a04b1a38e70c93f69c55749e62a3d895ac5e09277cd97caa5bbf
|
||||
F test/e_blobbytes.test 4c01dfe4f12087b92b20705a3fdfded45dc4ed16d5a211fed4e1d2786ba68a52
|
||||
F test/e_blobclose.test 692fc02a058476c2222a63d97e3f3b2b809c1842e5525ded7f854d540ac2e075
|
||||
F test/e_blobopen.test 29f6055ee453b8e679fe9570c4d3acfedbef821622c5dad16875148c5952ef50
|
||||
@@ -1071,7 +1083,7 @@ F test/e_expr.test b950818a48269506d75a41c819003bd77a0893bc4a4f2fdee191bc74109c1
|
||||
F test/e_fkey.test feeba6238aeff9d809fb6236b351da8df4ae9bda89e088e54526b31a0cbfeec5
|
||||
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
|
||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
|
||||
F test/e_reindex.test 027bb13d2c7e9e865886eed6349f126a273f8037899b636bf5fb53c7fc815921
|
||||
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
|
||||
F test/e_select.test 327a15f14068bbd6f647cedc67210f8680fcb2f05e481a0a855fccd2abfa1292
|
||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
@@ -1108,7 +1120,7 @@ F test/filter1.test 590f8ba9a0cd0823b80d89ac75c5ce72276189cef9225d2436adaf1ee87f
|
||||
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
|
||||
F test/filter2.test 3cc20eaea2ea1ab245197cc4a62468deb460b78f5aa9bd7d5d3353c2fe569bae
|
||||
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
|
||||
F test/fkey1.test e563bcb4cb108ce3f40363cda4f84009dc89a39e2973076e5057ba99fca35378
|
||||
F test/fkey1.test 6cf3fb520def0950799499b5bd0c6f22517cf7b6aee07523cbb52c1496aa8d00
|
||||
F test/fkey2.test 1063d65e5923c054cfb8f0555a92a3ae0fa8c067275a33ee1715bd856cdb304c
|
||||
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
@@ -1217,7 +1229,7 @@ F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f75
|
||||
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
|
||||
F test/fts4upfrom.test f25835162c989dffd5e2ef91ec24c4848cc9973093e2d492d1c7b32afac1b49d
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test da1332f6ab70338b83f5e2d594e72c7aa438c9b68406915e5a54618d601c09ee
|
||||
F test/func.test 504d202650c7940b5aa98364dd68f242df87f39f829e51074a55d79fc7bc7414
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a
|
||||
F test/func4.test e8ef9b2bd6a192a213cbd5cf31a3b35e25cd6ff2fdaeea0b58d63be31b03d220
|
||||
@@ -1233,7 +1245,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
|
||||
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
|
||||
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
|
||||
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
|
||||
F test/fuzzcheck.c 7e1bcc242dc4b42e43e4708c8140fe268db83a6901fbc681d150c77aa185e328
|
||||
F test/fuzzcheck.c e6a40f53ac5624aa5b7c4f31c385f09ba088d524cecc4512fd3057caeed8f530
|
||||
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
|
||||
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
@@ -1337,7 +1349,7 @@ F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd286
|
||||
F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
|
||||
F test/json/json-speed-check.sh 912ee03e700a65c827ee0c7b4752c21ec5ef69cf7679d2f482ca817042bead52 x
|
||||
F test/json/jsonb-q1.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7
|
||||
F test/json101.test 70587d7d35ef9e2126364ba70f0c951f70827cfbd28649d779ff3df7e8f87547
|
||||
F test/json101.test 30db5b055b103ccabc53a29cfe6cda3345d07e171aeb25403dafa04f19e98b19
|
||||
F test/json102.test 557a46e16df1aa9bdbc4076a71a45814ea0e7503d6621d87d42a8c04cbc2b0ef
|
||||
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
|
||||
F test/json104.test 1b844a70cddcfa2e4cd81a5db0657b2e61e7f00868310f24f56a9ba0114348c1
|
||||
@@ -1357,7 +1369,9 @@ F test/like2.test d3be15fefee3e02fc88942a9b98f26c5339bbdef7783c90023c092c4955fe3
|
||||
F test/like3.test a76e5938fadbe6d32807284c796bafd869974a961057bc5fc5a28e06de98745c
|
||||
F test/limit.test 350f5d03c29e7dff9a2cde016f84f8d368d40bcd02fa2b2a52fa10c4bf3cbfaf
|
||||
F test/limit2.test 9409b033284642a859fafc95f29a5a6a557bd57c1f0d7c3f554bd64ed69df77e
|
||||
F test/literal.test d0a72ab5afe525da7b5f0d2e11df7a369e8021f98de90da4352b8634dba9ccaf
|
||||
F test/literal.test a65dca9fef86e51b8e45544268e37abbd4bb94ba35fd65f6fdcab2f288cd8f79
|
||||
F test/literal2.tcl 1499037beaf661aeecdbe48801220a181d805372a64c6128d5f26bb6a4a8f0ce
|
||||
F test/literal2.test b149e16b5fc9ee6249069a8858ed41052f222014fe0ba7ad43c2fb989c2dada2
|
||||
F test/loadext.test faa4f6eed07a5aac35d57fdd7bc07f8fc82464cfd327567c10cf0ba3c86cde04
|
||||
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
|
||||
F test/lock.test be4fe08118fb988fed741f429b7dd5d65e1c90db
|
||||
@@ -1410,7 +1424,7 @@ F test/minmax.test fe638b55d77d2375531a8f549b338eafcd9adfbd2f72df37ed77d9b26ca0a
|
||||
F test/minmax2.test cf9311babb6f0518d04e42fd6a42c619531c4309a9dd790a2c4e9b3bc595e0de
|
||||
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
|
||||
F test/minmax4.test 272ca395257f05937dc96441c9dde4bc9fbf116a8d4fa02baeb0d13d50e36c87
|
||||
F test/misc1.test 8d138a4926ab90617c1aa29ce26e7785ae2b83a4d3a195d543b7374e05589dd1
|
||||
F test/misc1.test e3e36262aff1bd9b8b9bf1eeb3af04adb3fc1e23f0a92dbff708bba9e939ace1
|
||||
F test/misc2.test 71e746af479119386ac2ed7ab7d81d99970e75b49ffd3e8efffee100b4b5f350
|
||||
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
|
||||
F test/misc4.test 10cd6addb2fa9093df4751a1b92b50440175dd5468a6ec84d0386e78f087db0e
|
||||
@@ -1480,16 +1494,17 @@ F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/pendingrace.test 6aa33756b950c4529f79c4f3817a9a1e4025bd0d9961571a05c0279bd183d9c6
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test f7caf8dd5c7b1da74842a48df116f7f193399c656d4ffc805cd0d9658568c675
|
||||
F test/permutations.test 405542f1d659942994a6b38a9e024cf5cfd23eaa68c806aeb24a72d7c9186e80
|
||||
F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f
|
||||
F test/pragma.test 57a36226218c03cfb381019fe43234b2cefbd8a1f12825514f906a17ccf7991e
|
||||
F test/pragma.test 8bb6d3992c1c31ff6d5553d1e0693d642f7e19015648c6ae7034cb497d26bbd4
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 92a46bbea12322dd94a404f49edcfbfc913a2c98115f0d030a7459bb4712ef31
|
||||
F test/pragma4.test ca5e4dfc46adfe490f75d73734f70349d95a199e6510973899e502eef2c8b1f8
|
||||
F test/pragma4.test 9559cf5173864bf47c0431873d158fbeb72f920a59905b1f46069d8543eccdab
|
||||
F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d9102
|
||||
F test/pragma6.test fc3b670ab8ed985b2e5faa870f0f81aba1bfd5c3877ef3214e2df88592ccd3e5
|
||||
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
|
||||
F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
|
||||
F test/printf.test 512152dca7f2f578f045a5a732e7bee08e4f47a8a212f83ce46791b518eba70f
|
||||
F test/printf.test 685fec5a0c5af2490ab0632775a301554361d674211d690f5bee0a97b05333de
|
||||
F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
@@ -1627,13 +1642,13 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
|
||||
F test/speedtest1.c f9505ad6f9c2c3c488a370a2d193e9603a030e51126ef3ecfeb056d21f0e7ad5
|
||||
F test/speedtest1.c 19c9b60908d25502d2831f97efee8b81006c356ab8c08327e25d24a4144f2131
|
||||
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
|
||||
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
|
||||
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
|
||||
F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae6a41fb
|
||||
F test/sqldiff1.test 1b7ab4f312442c5cc6b3a5f299fa8ca051416d1dd173cb1126fd51bf64f2c3fb
|
||||
F test/sqllimits1.test b28e5cc8d337aaf290614d96a47e8fbfb720bb7ad35620c9d5432996fd413ac4
|
||||
F test/sqllimits1.test 5880a2f107185744ba4d93637f44c78d17706a9899a38b694d50f209735c81cc
|
||||
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
|
||||
F test/startup.c 1beb5ca66fcc0fce95c3444db9d1674f90fc605499a574ae2434dcfc10d22805
|
||||
F test/stat.test 123212a20ceb496893d5254a5f6c76442ce549fdc08d1702d8288a2bbaac8408
|
||||
@@ -2093,7 +2108,7 @@ F tool/mkshellc.tcl b7adf08b82de60811d2cb6af05ff59fc17e5cd6f3e98743c14eaaa3f8971
|
||||
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
|
||||
F tool/mksqlite3c.tcl 2c760ab786cb509b47f00c96fea82994866cb99f5e046df81c768288f57897b4
|
||||
F tool/mksqlite3c.tcl c6acfdf4e4ef93478ff3ce3cd593e17abb03f446036ce710c3156bcfa18665e0
|
||||
F tool/mksqlite3h.tcl d391cff7cad0a372ee1406faee9ccc7dad9cb80a0c95cae0f73d10dd26e06762
|
||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||
F tool/mktoolzip.tcl c7a9b685f5131d755e7d941cec50cee7f34178b9e34c9a89811eeb08617f8423
|
||||
@@ -2115,7 +2130,7 @@ F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c
|
||||
F tool/showwal.c 11eca547980a066b081f512636151233350ac679f29ecf4ebfce7f4530230b3d
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/spaceanal.tcl 70c87c04cfd2e77b3e6f21c33ca768296aa8f67d4ab4874786ac8fbb28433477
|
||||
F tool/speed-check.sh 72dc85b2c0484af971ee3e7d10775f72b4e771e27e162c2099b3bf25517c25fb
|
||||
F tool/speed-check.sh e8d20cc2eb9c85ec1ba562226de144435456dcdff4ee618de49603c6958f6116
|
||||
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
|
||||
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
|
||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
@@ -2162,11 +2177,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 26f848e5e0ac34e545d2f27cf33abc46eac13e04ed9cd71084b0f7d47136ff97
|
||||
R ac07ea666046dd35038bc77784e8d419
|
||||
T *branch * rtree-fix
|
||||
T *sym-rtree-fix *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 6f11e0396699443c7473bed77f9c3651
|
||||
P 26272590691aee8569a1ea9c233f9b0e55ece63ed167696cc1ecfe3ca2548ba1
|
||||
R ffcb677589cb061417252fbc7f9600de
|
||||
U drh
|
||||
Z 148d8810a6ba162cbd3b9cd95d027cbb
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
478280ef67efed854988ab4f740a38ae1937204c0434ad8da11f1869a12a6d06
|
||||
1a49788afd90fa4415c6aae4b6bbad68f9306c1df1026762a9d88bcb40e4cd8f
|
||||
+44
-31
@@ -872,7 +872,7 @@ static void statGet(
|
||||
if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
|
||||
sqlite3_str_appendf(&sStat, " %llu", iVal);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
assert( p->current.anEq[i] );
|
||||
assert( p->current.anEq[i] || p->nRow==0 );
|
||||
#endif
|
||||
}
|
||||
sqlite3ResultStrAccum(context, &sStat);
|
||||
@@ -1057,7 +1057,7 @@ static void analyzeOneTable(
|
||||
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int nCol; /* Number of columns in pIdx. "N" */
|
||||
int addrRewind; /* Address of "OP_Rewind iIdxCur" */
|
||||
int addrGotoEnd; /* Address of "OP_Rewind iIdxCur" */
|
||||
int addrNextRow; /* Address of "next_row:" */
|
||||
const char *zIdxName; /* Name of the index */
|
||||
int nColTest; /* Number of columns to test for changes */
|
||||
@@ -1081,9 +1081,14 @@ static void analyzeOneTable(
|
||||
/*
|
||||
** Pseudo-code for loop that calls stat_push():
|
||||
**
|
||||
** Rewind csr
|
||||
** if eof(csr) goto end_of_scan;
|
||||
** regChng = 0
|
||||
** Rewind csr
|
||||
** if eof(csr){
|
||||
** stat_init() with count = 0;
|
||||
** goto end_of_scan;
|
||||
** }
|
||||
** count()
|
||||
** stat_init()
|
||||
** goto chng_addr_0;
|
||||
**
|
||||
** next_row:
|
||||
@@ -1122,41 +1127,36 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
|
||||
/* Invoke the stat_init() function. The arguments are:
|
||||
**
|
||||
/* Implementation of the following:
|
||||
**
|
||||
** regChng = 0
|
||||
** Rewind csr
|
||||
** if eof(csr){
|
||||
** stat_init() with count = 0;
|
||||
** goto end_of_scan;
|
||||
** }
|
||||
** count()
|
||||
** stat_init()
|
||||
** goto chng_addr_0;
|
||||
*/
|
||||
assert( regTemp2==regStat+4 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
|
||||
|
||||
/* Arguments to stat_init():
|
||||
** (1) the number of columns in the index including the rowid
|
||||
** (or for a WITHOUT ROWID table, the number of PK columns),
|
||||
** (2) the number of columns in the key without the rowid/pk
|
||||
** (3) estimated number of rows in the index,
|
||||
*/
|
||||
** (3) estimated number of rows in the index. */
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
|
||||
assert( regRowid==regStat+2 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( OptimizationEnabled(db, SQLITE_Stat4) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
|
||||
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
||||
VdbeCoverage(v);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
|
||||
}
|
||||
assert( regTemp2==regStat+4 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
|
||||
sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp,
|
||||
OptimizationDisabled(db, SQLITE_Stat4));
|
||||
sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
|
||||
&statInitFuncdef, 0);
|
||||
addrGotoEnd = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
||||
VdbeCoverage(v);
|
||||
|
||||
/* Implementation of the following:
|
||||
**
|
||||
** Rewind csr
|
||||
** if eof(csr) goto end_of_scan;
|
||||
** regChng = 0
|
||||
** goto next_push_0;
|
||||
**
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
|
||||
addrNextRow = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
@@ -1263,6 +1263,12 @@ static void analyzeOneTable(
|
||||
}
|
||||
|
||||
/* Add the entry to the stat1 table. */
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
/* Partial indexes might get a zero-entry in sqlite_stat1. But
|
||||
** an empty table is omitted from sqlite_stat1. */
|
||||
sqlite3VdbeJumpHere(v, addrGotoEnd);
|
||||
addrGotoEnd = 0;
|
||||
}
|
||||
callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
|
||||
assert( "BBB"[0]==SQLITE_AFF_TEXT );
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
|
||||
@@ -1286,6 +1292,13 @@ static void analyzeOneTable(
|
||||
int addrIsNull;
|
||||
u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
|
||||
|
||||
/* No STAT4 data is generated if the number of rows is zero */
|
||||
if( addrGotoEnd==0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Cast, regStat1, SQLITE_AFF_INTEGER);
|
||||
addrGotoEnd = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
if( doOnce ){
|
||||
int mxCol = nCol;
|
||||
Index *pX;
|
||||
@@ -1338,7 +1351,7 @@ static void analyzeOneTable(
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/* End of analysis */
|
||||
sqlite3VdbeJumpHere(v, addrRewind);
|
||||
if( addrGotoEnd ) sqlite3VdbeJumpHere(v, addrGotoEnd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+35
-16
@@ -5128,9 +5128,12 @@ static int accessPayload(
|
||||
if( pCur->aOverflow==0
|
||||
|| nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow)
|
||||
){
|
||||
Pgno *aNew = (Pgno*)sqlite3Realloc(
|
||||
pCur->aOverflow, nOvfl*2*sizeof(Pgno)
|
||||
);
|
||||
Pgno *aNew;
|
||||
if( sqlite3FaultSim(413) ){
|
||||
aNew = 0;
|
||||
}else{
|
||||
aNew = (Pgno*)sqlite3Realloc(pCur->aOverflow, nOvfl*2*sizeof(Pgno));
|
||||
}
|
||||
if( aNew==0 ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}else{
|
||||
@@ -6179,10 +6182,10 @@ i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
|
||||
/* Currently this interface is only called by the OP_IfSmaller
|
||||
** opcode, and it that case the cursor will always be valid and
|
||||
** will always point to a leaf node. */
|
||||
if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
|
||||
/* Currently this interface is only called by the OP_IfSizeBetween
|
||||
** opcode and the OP_Count opcode with P3=1. In either case,
|
||||
** the cursor will always be valid unless the btree is empty. */
|
||||
if( pCur->eState!=CURSOR_VALID ) return 0;
|
||||
if( NEVER(pCur->pPage->leaf==0) ) return -1;
|
||||
|
||||
n = pCur->pPage->nCell;
|
||||
@@ -7004,7 +7007,10 @@ static int fillInCell(
|
||||
n = nHeader + nPayload;
|
||||
testcase( n==3 );
|
||||
testcase( n==4 );
|
||||
if( n<4 ) n = 4;
|
||||
if( n<4 ){
|
||||
n = 4;
|
||||
pPayload[nPayload] = 0;
|
||||
}
|
||||
*pnSize = n;
|
||||
assert( nSrc<=nPayload );
|
||||
testcase( nSrc<nPayload );
|
||||
@@ -9450,7 +9456,10 @@ int sqlite3BtreeInsert(
|
||||
if( flags & BTREE_PREFORMAT ){
|
||||
rc = SQLITE_OK;
|
||||
szNew = p->pBt->nPreformatSize;
|
||||
if( szNew<4 ) szNew = 4;
|
||||
if( szNew<4 ){
|
||||
szNew = 4;
|
||||
newCell[3] = 0;
|
||||
}
|
||||
if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
|
||||
CellInfo info;
|
||||
pPage->xParseCell(pPage, newCell, &info);
|
||||
@@ -10791,6 +10800,9 @@ static int checkTreePage(
|
||||
** number of cells on the page. */
|
||||
nCell = get2byte(&data[hdr+3]);
|
||||
assert( pPage->nCell==nCell );
|
||||
if( pPage->leaf || pPage->intKey==0 ){
|
||||
pCheck->nRow += nCell;
|
||||
}
|
||||
|
||||
/* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
|
||||
** immediately follows the b-tree page header. */
|
||||
@@ -10902,6 +10914,7 @@ static int checkTreePage(
|
||||
btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
|
||||
}
|
||||
}
|
||||
assert( heap!=0 );
|
||||
/* Add the freeblocks to the min-heap
|
||||
**
|
||||
** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
|
||||
@@ -11001,6 +11014,7 @@ int sqlite3BtreeIntegrityCheck(
|
||||
sqlite3 *db, /* Database connection that is running the check */
|
||||
Btree *p, /* The btree to be checked */
|
||||
Pgno *aRoot, /* An array of root pages numbers for individual trees */
|
||||
Mem *aCnt, /* Memory cells to write counts for each tree to */
|
||||
int nRoot, /* Number of entries in aRoot[] */
|
||||
int mxErr, /* Stop reporting errors after this many */
|
||||
int *pnErr, /* OUT: Write number of errors seen to this variable */
|
||||
@@ -11014,7 +11028,9 @@ int sqlite3BtreeIntegrityCheck(
|
||||
int bPartial = 0; /* True if not checking all btrees */
|
||||
int bCkFreelist = 1; /* True to scan the freelist */
|
||||
VVA_ONLY( int nRef );
|
||||
|
||||
assert( nRoot>0 );
|
||||
assert( aCnt!=0 );
|
||||
|
||||
/* aRoot[0]==0 means this is a partial check */
|
||||
if( aRoot[0]==0 ){
|
||||
@@ -11087,15 +11103,18 @@ int sqlite3BtreeIntegrityCheck(
|
||||
testcase( pBt->db->flags & SQLITE_CellSizeCk );
|
||||
pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
|
||||
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
|
||||
i64 notUsed;
|
||||
if( aRoot[i]==0 ) continue;
|
||||
sCheck.nRow = 0;
|
||||
if( aRoot[i] ){
|
||||
i64 notUsed;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
|
||||
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
|
||||
}
|
||||
if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
|
||||
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
|
||||
}
|
||||
#endif
|
||||
sCheck.v0 = aRoot[i];
|
||||
checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64);
|
||||
sCheck.v0 = aRoot[i];
|
||||
checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64);
|
||||
}
|
||||
sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow);
|
||||
}
|
||||
pBt->db->flags = savedDbFlags;
|
||||
|
||||
|
||||
@@ -331,6 +331,7 @@ int sqlite3BtreeIntegrityCheck(
|
||||
sqlite3 *db, /* Database connection that is running the check */
|
||||
Btree *p, /* The btree to be checked */
|
||||
Pgno *aRoot, /* An array of root pages numbers for individual trees */
|
||||
sqlite3_value *aCnt, /* OUT: entry counts for each btree in aRoot[] */
|
||||
int nRoot, /* Number of entries in aRoot[] */
|
||||
int mxErr, /* Stop reporting errors after this many */
|
||||
int *pnErr, /* OUT: Write number of errors seen to this variable */
|
||||
|
||||
@@ -707,6 +707,7 @@ struct IntegrityCk {
|
||||
StrAccum errMsg; /* Accumulate the error message text here */
|
||||
u32 *heap; /* Min-heap used for analyzing cell coverage */
|
||||
sqlite3 *db; /* Database connection running the check */
|
||||
i64 nRow; /* Number of rows visited in current tree */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+294
-196
@@ -2923,11 +2923,11 @@ void sqlite3EndTable(
|
||||
/* Test for cycles in generated columns and illegal expressions
|
||||
** in CHECK constraints and in DEFAULT clauses. */
|
||||
if( p->tabFlags & TF_HasGenerated ){
|
||||
sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
|
||||
sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0,
|
||||
sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"",
|
||||
db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
|
||||
sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0,
|
||||
sqlite3MPrintf(db, "PRAGMA \"%w\".integrity_check(%Q)",
|
||||
db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
|
||||
}
|
||||
@@ -3260,84 +3260,129 @@ void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Write code to erase the table with root-page iTable from database iDb.
|
||||
** Also write code to modify the sqlite_schema table and internal schema
|
||||
** if a root-page of another table is moved by the btree-layer whilst
|
||||
** erasing iTable (this can happen with an auto-vacuum database).
|
||||
** The RootStack object holds a list (really a Heap) of btree root pages
|
||||
** and schema numbers that need to be deleted using OP_Destroy.
|
||||
**
|
||||
** OP_Destroy opcodes must be issued in order of decreasing root page
|
||||
** numbers in order to avoid having auto-vacuum disrupt subsequent
|
||||
** OP_Destroy opcodes. For that reason, all pending OP_Destroy calls
|
||||
** are accumulated in an instance of this object. Then at the end of
|
||||
** code generation, this object is used to generate the OP_Destroy opcodes
|
||||
** in decreasing order.
|
||||
**
|
||||
** The data structure is a max-heap. Each rootpage/schema-number combo
|
||||
** is stored as a 64-bit integer, with the schema-number in the upper 32
|
||||
** bits and the page number in the lower 32-bits. The root of the heap
|
||||
** (RootStack.a[0]) is the largest entry in the heap. The children of
|
||||
** heap entry i are i*2+1 and i*2+2. The heap always stays balanced by
|
||||
** ensuring that a parent entry is larger than both children.
|
||||
**
|
||||
*/
|
||||
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema");
|
||||
sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
|
||||
sqlite3MayAbort(pParse);
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
/* OP_Destroy stores an in integer r1. If this integer
|
||||
** is non-zero, then it is the root page number of a table moved to
|
||||
** location iTable. The following code modifies the sqlite_schema table to
|
||||
** reflect this.
|
||||
**
|
||||
** The "#NNN" in the SQL is a special constant that means whatever value
|
||||
** is in register NNN. See grammar rules associated with the TK_REGISTER
|
||||
** token for additional information.
|
||||
*/
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q." LEGACY_SCHEMA_TABLE
|
||||
" SET rootpage=%d WHERE #%d AND rootpage=#%d",
|
||||
pParse->db->aDb[iDb].zDbSName, iTable, r1, r1);
|
||||
#endif
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
typedef struct RootStack RootStack;
|
||||
struct RootStack {
|
||||
u32 nAlloc; /* Slots allocated for a[] */
|
||||
u32 nUsed; /* Slots used for in a[] */
|
||||
u64 *a; /* Sorting heap. Each entry has iDb in the upper 32 bits and
|
||||
** a page number in the lower 32 bits */
|
||||
};
|
||||
|
||||
/*
|
||||
** Add a new Pgno and iDb to the RootStack in question.
|
||||
**
|
||||
** The new entry is inserted at the of the heap (most distant child)
|
||||
** and then the heap is rebalanced.
|
||||
*/
|
||||
static void rootStackPush(Parse *pParse, RootStack *p, Pgno pgno, int iDb){
|
||||
u64 iNew;
|
||||
int i, j;
|
||||
if( p->nAlloc<p->nUsed+1 ){
|
||||
p->nAlloc = p->nAlloc*2 + 12;
|
||||
p->a = sqlite3DbRealloc(pParse->db, p->a, sizeof(Pgno)*p->nAlloc);
|
||||
if( p->a==0 ){
|
||||
p->nAlloc = p->nUsed = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert( pgno>0 || CORRUPT_DB );
|
||||
assert( iDb>=0 && iDb<pParse->db->nDb );
|
||||
iNew = (((u64)iDb)<<32) | pgno;
|
||||
i = p->nUsed++;
|
||||
p->a[i] = iNew;
|
||||
while( i>=1 && p->a[j = (i-1)/2]<p->a[i] ){
|
||||
u64 tmp = p->a[i];
|
||||
p->a[i] = p->a[j];
|
||||
p->a[j] = tmp;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Write VDBE code to erase table pTab and all associated indices on disk.
|
||||
** Code to update the sqlite_schema tables and internal schema definitions
|
||||
** in case a root-page belonging to another table is moved by the btree layer
|
||||
** is also added (this can happen with an auto-vacuum database).
|
||||
** Remove the largest entry from the RootStack heap. Rebalance the
|
||||
** heap and then return that largest entry.
|
||||
*/
|
||||
static void destroyTable(Parse *pParse, Table *pTab){
|
||||
/* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
|
||||
** is not defined), then it is important to call OP_Destroy on the
|
||||
** table and index root-pages in order, starting with the numerically
|
||||
** largest root-page number. This guarantees that none of the root-pages
|
||||
** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
|
||||
** following were coded:
|
||||
**
|
||||
** OP_Destroy 4 0
|
||||
** ...
|
||||
** OP_Destroy 5 0
|
||||
**
|
||||
** and root page 5 happened to be the largest root-page number in the
|
||||
** database, then root page 5 would be moved to page 4 by the
|
||||
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
|
||||
** a free-list page.
|
||||
*/
|
||||
Pgno iTab = pTab->tnum;
|
||||
Pgno iDestroyed = 0;
|
||||
|
||||
while( 1 ){
|
||||
Index *pIdx;
|
||||
Pgno iLargest = 0;
|
||||
|
||||
if( iDestroyed==0 || iTab<iDestroyed ){
|
||||
iLargest = iTab;
|
||||
}
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
Pgno iIdx = pIdx->tnum;
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
|
||||
iLargest = iIdx;
|
||||
}
|
||||
}
|
||||
if( iLargest==0 ){
|
||||
return;
|
||||
}else{
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
assert( iDb>=0 && iDb<pParse->db->nDb );
|
||||
destroyRootPage(pParse, iLargest, iDb);
|
||||
iDestroyed = iLargest;
|
||||
}
|
||||
static u64 rootStackPop(RootStack *p){
|
||||
u64 iMax;
|
||||
int i, j;
|
||||
assert( p->nUsed>0 );
|
||||
assert( p->a!=0 );
|
||||
iMax = p->a[0];
|
||||
p->a[0] = p->a[--p->nUsed];
|
||||
i = 0;
|
||||
while( (j = i*2+1)<p->nUsed ){
|
||||
u64 tmp;
|
||||
if( j+1<p->nUsed && p->a[j+1]>p->a[j] ) j++;
|
||||
if( p->a[i]>p->a[j] ) break;
|
||||
tmp = p->a[i];
|
||||
p->a[i] = p->a[j];
|
||||
p->a[j] = tmp;
|
||||
i = j;
|
||||
}
|
||||
return iMax;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate OP_Destroy opcodes for every btree named in the given
|
||||
** RootStack object. Issue these OP_Destroy opcodes in order of decreasing
|
||||
** root page number. Then clean up any memory used by the RootStack.
|
||||
*/
|
||||
static void rootStackCode(Parse *pParse, RootStack *p){
|
||||
int iLastDb = -1;
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
int r2 = sqlite3GetTempReg(pParse);
|
||||
int regReturn = sqlite3GetTempReg(pParse);
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int addrSub = 0;
|
||||
while( pParse->nErr==0 && p->nUsed>0 ){
|
||||
u64 iNext = rootStackPop(p);
|
||||
Pgno pgno = iNext & 0xffffffff;
|
||||
int iDb = (iNext>>32)&0xffff;
|
||||
if( pgno<2 ) sqlite3ErrorMsg(pParse, "corrupt schema");
|
||||
sqlite3MayAbort(pParse);
|
||||
if( iDb!=iLastDb ){
|
||||
/* Code a subroutine to that will update the schema table when
|
||||
** a root page number changes. The old root page is in register r1.
|
||||
** Root page is moved to the value in register r2. */
|
||||
iLastDb = iDb;
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrSub = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q." LEGACY_SCHEMA_TABLE
|
||||
" SET rootpage=#%d WHERE rootpage=#%d",
|
||||
pParse->db->aDb[iDb].zDbSName, r2, r1);
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrSub-1);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Destroy, pgno, r1, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_IfNot, r1, sqlite3VdbeCurrentAddr(v)+3);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pgno, r2);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, addrSub);
|
||||
}
|
||||
if( pParse->nErr==0 ){
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempReg(pParse, regReturn);
|
||||
}
|
||||
sqlite3DbFree(pParse->db, p->a);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3367,7 +3412,12 @@ static void sqlite3ClearStatTables(
|
||||
/*
|
||||
** Generate code to drop a table.
|
||||
*/
|
||||
void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
||||
static void sqlite3CodeDropTable(
|
||||
Parse *pParse, /* Parsing context */
|
||||
RootStack *pStack, /* List of pending OP_Destroys */
|
||||
Table *pTab, /* Table to be dropped */
|
||||
int iDb /* Schema holding pTab */
|
||||
){
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
Trigger *pTrigger;
|
||||
@@ -3420,8 +3470,13 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
||||
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE
|
||||
" WHERE tbl_name=%Q and type!='trigger'",
|
||||
pDb->zDbSName, pTab->zName);
|
||||
if( !isView && !IsVirtual(pTab) ){
|
||||
destroyTable(pParse, pTab);
|
||||
if( IsOrdinaryTable(pTab) ){
|
||||
Index *pIdx;
|
||||
rootStackPush(pParse, pStack, pTab->tnum, iDb);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->tnum==pTab->tnum ) continue;
|
||||
rootStackPush(pParse, pStack, pIdx->tnum, iDb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the table entry from SQLite's internal schema and modify
|
||||
@@ -3477,106 +3532,134 @@ static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){
|
||||
*/
|
||||
void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
Table *pTab;
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb;
|
||||
int ii, jj;
|
||||
RootStack rootStack;
|
||||
|
||||
if( db->mallocFailed ){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
assert( pParse->nErr==0 );
|
||||
assert( pName->nSrc==1 );
|
||||
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
||||
if( noErr ) db->suppressErr++;
|
||||
assert( isView==0 || isView==LOCATE_VIEW );
|
||||
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
|
||||
if( noErr ) db->suppressErr--;
|
||||
memset(&rootStack, 0, sizeof(rootStack));
|
||||
(void)sqlite3GetVdbe(pParse);
|
||||
sqlite3ReadSchema(pParse);
|
||||
assert( pName!=0 || pParse->nErr!=0 );
|
||||
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
|
||||
if( noErr ) db->suppressErr++;
|
||||
assert( isView==0 || isView==LOCATE_VIEW );
|
||||
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[ii]);
|
||||
if( noErr ) db->suppressErr--;
|
||||
|
||||
if( pTab==0 ){
|
||||
if( noErr ){
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
if( pTab==0 ){
|
||||
if( noErr ){
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[ii].zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
}
|
||||
testcase( ii+1<pName->nSrc );
|
||||
continue;
|
||||
}
|
||||
goto exit_drop_table;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
|
||||
/* If pTab is a virtual table, call ViewGetColumnNames() to ensure
|
||||
** it is initialized.
|
||||
*/
|
||||
if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
/* If pTab is a virtual table, call ViewGetColumnNames() to ensure
|
||||
** it is initialized.
|
||||
*/
|
||||
if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zArg2 = 0;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
if( isView ){
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
code = SQLITE_DROP_TEMP_VIEW;
|
||||
}else{
|
||||
code = SQLITE_DROP_VIEW;
|
||||
{
|
||||
int code;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zArg2 = 0;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
if( isView ){
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
code = SQLITE_DROP_TEMP_VIEW;
|
||||
}else{
|
||||
code = SQLITE_DROP_VIEW;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
}else if( IsVirtual(pTab) ){
|
||||
code = SQLITE_DROP_VTABLE;
|
||||
zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
|
||||
}else if( IsVirtual(pTab) ){
|
||||
code = SQLITE_DROP_VTABLE;
|
||||
zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
|
||||
#endif
|
||||
}else{
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
code = SQLITE_DROP_TEMP_TABLE;
|
||||
}else{
|
||||
code = SQLITE_DROP_TABLE;
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
code = SQLITE_DROP_TEMP_TABLE;
|
||||
}else{
|
||||
code = SQLITE_DROP_TABLE;
|
||||
}
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( tableMayNotBeDropped(db, pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
||||
goto exit_drop_table;
|
||||
}
|
||||
if( tableMayNotBeDropped(db, pTab) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
|
||||
** on a table.
|
||||
*/
|
||||
if( isView && !IsView(pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
|
||||
goto exit_drop_table;
|
||||
}
|
||||
if( !isView && IsView(pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
|
||||
goto exit_drop_table;
|
||||
}
|
||||
/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
|
||||
** on a table.
|
||||
*/
|
||||
if( isView && !IsView(pTab) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
|
||||
break;
|
||||
}
|
||||
if( !isView && IsView(pTab) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* If this table or view has appeared previously in the list of tables
|
||||
** or views to be dropped, then the prior appearance is sufficient so
|
||||
** skip this one. */
|
||||
for(jj=ii-1; jj>=0 && pName->a[jj].pTab!=pTab; jj--){}
|
||||
if( jj>=0 ) continue;
|
||||
|
||||
/* Generate code to remove the table from the schema table
|
||||
** on disk.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
/* Remember the table for use in the second pass */
|
||||
pName->a[ii].pTab = pTab;
|
||||
pTab->nTabRef++;
|
||||
|
||||
/* Generate code to clear this table from sqlite_statN and to
|
||||
** cascade foreign key constraints.
|
||||
*/
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
if( !isView ){
|
||||
if( IsOrdinaryTable(pTab) ){
|
||||
sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
|
||||
sqlite3FkDropTable(pParse, pName, pTab);
|
||||
}
|
||||
sqlite3CodeDropTable(pParse, pTab, iDb, isView);
|
||||
}
|
||||
|
||||
exit_drop_table:
|
||||
/* Generate code to actually delete the tables/views in a second pass.
|
||||
** Btrees must be deleted largest root page first, to avoid problems
|
||||
** caused by autovacuum page reordering. */
|
||||
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
|
||||
pTab = pName->a[ii].pTab;
|
||||
if( pTab==0 ) continue;
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3CodeDropTable(pParse, &rootStack, pTab, iDb);
|
||||
}
|
||||
sqlite3SrcListDelete(db, pName);
|
||||
rootStackCode(pParse, &rootStack);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4576,67 +4659,82 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
*/
|
||||
void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
||||
Index *pIndex;
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
Vdbe *v;
|
||||
int iDb;
|
||||
int ii, jj;
|
||||
RootStack rootStack;
|
||||
|
||||
if( db->mallocFailed ){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
|
||||
assert( pName->nSrc==1 );
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
|
||||
if( pIndex==0 ){
|
||||
if( !ifExists ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
memset(&rootStack, 0, sizeof(rootStack));
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
sqlite3ReadSchema(pParse);
|
||||
assert( pName!=0 || pParse->nErr!=0 );
|
||||
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
|
||||
pName->a[ii].regReturn = 0;
|
||||
pIndex = sqlite3FindIndex(db, pName->a[ii].zName, pName->a[ii].zDatabase);
|
||||
if( pIndex==0 ){
|
||||
if( !ifExists ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a+ii);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[ii].zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
continue;
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
goto exit_drop_index;
|
||||
}
|
||||
if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
|
||||
sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
|
||||
"or PRIMARY KEY constraint cannot be dropped", 0);
|
||||
goto exit_drop_index;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
|
||||
sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
|
||||
"or PRIMARY KEY constraint cannot be dropped", 0);
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_INDEX;
|
||||
Table *pTab = pIndex->pTable;
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
||||
goto exit_drop_index;
|
||||
{
|
||||
int code = SQLITE_DROP_INDEX;
|
||||
Table *pTab = pIndex->pTable;
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
|
||||
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
|
||||
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code to remove the index and from the schema table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
/* Skip over redundant DROP INDEXes */
|
||||
for(jj=ii-1; jj>=0 && pName->a[jj].u2.pIdx!=pIndex; jj--){}
|
||||
if( jj>=0 ) continue;
|
||||
|
||||
/* Record that this index needs to be dropped. */
|
||||
pName->a[ii].u2.pIdx = pIndex;
|
||||
|
||||
/* Generate code to remove the index and from the schema table and
|
||||
** from sqlite_statN tables */
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
sqlite3NestedParse(pParse,
|
||||
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'",
|
||||
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE
|
||||
" WHERE name=%Q AND type='index'",
|
||||
db->aDb[iDb].zDbSName, pIndex->zName
|
||||
);
|
||||
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
|
||||
|
||||
rootStackPush(pParse, &rootStack, pIndex->tnum, iDb);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
destroyRootPage(pParse, pIndex->tnum, iDb);
|
||||
sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);
|
||||
}
|
||||
|
||||
exit_drop_index:
|
||||
sqlite3SrcListDelete(db, pName);
|
||||
rootStackCode(pParse, &rootStack);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+6
-5
@@ -914,11 +914,12 @@ void sqlite3ExprSetErrorOffset(Expr *pExpr, int iOfst){
|
||||
** appear to be quoted. If the quotes were of the form "..." (double-quotes)
|
||||
** then the EP_DblQuoted flag is set on the expression node.
|
||||
**
|
||||
** Special case: If op==TK_INTEGER and pToken points to a string that
|
||||
** can be translated into a 32-bit integer, then the token is not
|
||||
** stored in u.zToken. Instead, the integer values is written
|
||||
** into u.iValue and the EP_IntValue flag is set. No extra storage
|
||||
** Special case (tag-20240227-a): If op==TK_INTEGER and pToken points to
|
||||
** a string that can be translated into a 32-bit integer, then the token is
|
||||
** not stored in u.zToken. Instead, the integer values is written
|
||||
** into u.iValue and the EP_IntValue flag is set. No extra storage
|
||||
** is allocated to hold the integer text and the dequote flag is ignored.
|
||||
** See also tag-20240227-b.
|
||||
*/
|
||||
Expr *sqlite3ExprAlloc(
|
||||
sqlite3 *db, /* Handle for sqlite3DbMallocRawNN() */
|
||||
@@ -934,7 +935,7 @@ Expr *sqlite3ExprAlloc(
|
||||
if( pToken ){
|
||||
if( op!=TK_INTEGER || pToken->z==0
|
||||
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
|
||||
nExtra = pToken->n+1;
|
||||
nExtra = pToken->n+1; /* tag-20240227-a */
|
||||
assert( iValue>=0 );
|
||||
}
|
||||
}
|
||||
|
||||
+25
-6
@@ -718,8 +718,9 @@ void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
|
||||
/*
|
||||
** This function is called to generate code that runs when table pTab is
|
||||
** being dropped from the database. The SrcList passed as the second argument
|
||||
** to this function contains a single entry guaranteed to resolve to
|
||||
** table pTab.
|
||||
** to this function contains entries for every table that is being dropped,
|
||||
** with the SrcItem.pTab line being set to the table being dropped. pTab
|
||||
** will be one of those tables.
|
||||
**
|
||||
** Normally, no code is required. However, if either
|
||||
**
|
||||
@@ -728,15 +729,23 @@ void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
|
||||
** determined at runtime that there are outstanding deferred FK
|
||||
** constraint violations in the database,
|
||||
**
|
||||
** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
|
||||
** the table from the database. Triggers are disabled while running this
|
||||
** DELETE, but foreign key actions are not.
|
||||
** then the equivalent of "DELETE FROM <tbl>" is executed for every table
|
||||
** being dropped, in the order specified in the DROP TABLE statement, which
|
||||
** is the same as the order in which these tables appear in pName.
|
||||
** Triggers are disabled while running these DELETEs, but foreign key
|
||||
** actions are not.
|
||||
**
|
||||
** This routine sets the SrcList.addrFillSub value for all pName entries
|
||||
** for which DELETE FROM has been run. This prevents the DELETE FROM
|
||||
** from being run multiple times.
|
||||
*/
|
||||
void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){
|
||||
int iSkip = 0;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
SrcList *pSrc;
|
||||
int ii;
|
||||
|
||||
assert( v ); /* VDBE has already been allocated */
|
||||
assert( IsOrdinaryTable(pTab) );
|
||||
@@ -756,7 +765,17 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
}
|
||||
|
||||
pParse->disableTriggers = 1;
|
||||
sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0);
|
||||
for(ii=0; ii<pName->nSrc; ii++){
|
||||
if( pName->a[ii].pTab==0 ) continue;
|
||||
if( pName->a[ii].addrFillSub ) continue;
|
||||
pName->a[ii].addrFillSub = 1;
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pSrc ){
|
||||
pSrc->a[0].zDatabase = sqlite3DbStrDup(db, pName->a[ii].zDatabase);
|
||||
pSrc->a[0].zName = sqlite3DbStrDup(db, pName->a[ii].zName);
|
||||
sqlite3DeleteFrom(pParse, pSrc, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
pParse->disableTriggers = 0;
|
||||
|
||||
/* If the DELETE has generated immediate foreign key constraint
|
||||
|
||||
+2
-2
@@ -1101,13 +1101,13 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
|
||||
double r1, r2;
|
||||
const char *zVal;
|
||||
r1 = sqlite3_value_double(pValue);
|
||||
sqlite3_str_appendf(pStr, "%!.15g", r1);
|
||||
sqlite3_str_appendf(pStr, "%!0.15g", r1);
|
||||
zVal = sqlite3_str_value(pStr);
|
||||
if( zVal ){
|
||||
sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
|
||||
if( r1!=r2 ){
|
||||
sqlite3_str_reset(pStr);
|
||||
sqlite3_str_appendf(pStr, "%!.20e", r1);
|
||||
sqlite3_str_appendf(pStr, "%!0.20e", r1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+10
-1
@@ -1623,6 +1623,7 @@ json_parse_restart:
|
||||
case '[': {
|
||||
/* Parse array */
|
||||
iThis = pParse->nBlob;
|
||||
assert( i<=(u32)pParse->nJson );
|
||||
jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0);
|
||||
iStart = pParse->nBlob;
|
||||
if( pParse->oom ) return -1;
|
||||
@@ -2027,6 +2028,10 @@ static void jsonReturnStringAsBlob(JsonString *pStr){
|
||||
JsonParse px;
|
||||
memset(&px, 0, sizeof(px));
|
||||
jsonStringTerminate(pStr);
|
||||
if( pStr->eErr ){
|
||||
sqlite3_result_error_nomem(pStr->pCtx);
|
||||
return;
|
||||
}
|
||||
px.zJson = pStr->zBuf;
|
||||
px.nJson = pStr->nUsed;
|
||||
px.db = sqlite3_context_db_handle(pStr->pCtx);
|
||||
@@ -3359,8 +3364,9 @@ rebuild_from_cache:
|
||||
}
|
||||
p->zJson = (char*)sqlite3_value_text(pArg);
|
||||
p->nJson = sqlite3_value_bytes(pArg);
|
||||
if( db->mallocFailed ) goto json_pfa_oom;
|
||||
if( p->nJson==0 ) goto json_pfa_malformed;
|
||||
if( NEVER(p->zJson==0) ) goto json_pfa_oom;
|
||||
assert( p->zJson!=0 );
|
||||
if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){
|
||||
if( flgs & JSON_KEEPERROR ){
|
||||
p->nErr = 1;
|
||||
@@ -4938,6 +4944,9 @@ static int jsonEachColumn(
|
||||
case JEACH_VALUE: {
|
||||
u32 i = jsonSkipLabel(p);
|
||||
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
|
||||
if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){
|
||||
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JEACH_TYPE: {
|
||||
|
||||
+4
-4
@@ -228,9 +228,9 @@ static void sqlite3MallocAlarm(int nByte){
|
||||
** code debuggers when working on out-of-memory conditions, for example
|
||||
** caused by PRAGMA hard_heap_limit=N.
|
||||
*/
|
||||
static SQLITE_NOINLINE void test_oom_breakpoint(void){
|
||||
static SQLITE_NOINLINE void test_oom_breakpoint(u64 n){
|
||||
static u64 nOomFault = 0;
|
||||
nOomFault++;
|
||||
nOomFault += n;
|
||||
/* The assert() is never reached in a human lifetime. It is here mostly
|
||||
** to prevent code optimizers from optimizing out this function. */
|
||||
assert( (nOomFault>>32) < 0xffffffff );
|
||||
@@ -265,7 +265,7 @@ static void mallocWithAlarm(int n, void **pp){
|
||||
if( mem0.hardLimit ){
|
||||
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
||||
if( nUsed >= mem0.hardLimit - nFull ){
|
||||
test_oom_breakpoint();
|
||||
test_oom_breakpoint(1);
|
||||
*pp = 0;
|
||||
return;
|
||||
}
|
||||
@@ -554,7 +554,7 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
|
||||
sqlite3MallocAlarm(nDiff);
|
||||
if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
|
||||
sqlite3_mutex_leave(mem0.mutex);
|
||||
test_oom_breakpoint();
|
||||
test_oom_breakpoint(1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -1295,8 +1295,12 @@ static int unixLogErrorAtLine(
|
||||
** available, the error message will often be an empty string. Not a
|
||||
** huge problem. Incorrectly concluding that the GNU version is available
|
||||
** could lead to a segfault though.
|
||||
**
|
||||
** Forum post 3f13857fa4062301 reports that the Android SDK may use
|
||||
** int-type return, depending on its version.
|
||||
*/
|
||||
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
|
||||
#if (defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)) \
|
||||
&& !defined(ANDROID) && !defined(__ANDROID__)
|
||||
zErr =
|
||||
# endif
|
||||
strerror_r(iErrno, aErr, sizeof(aErr)-1);
|
||||
|
||||
+22
-4
@@ -471,7 +471,7 @@ resolvetype(A) ::= REPLACE. {A = OE_Replace;}
|
||||
|
||||
////////////////////////// The DROP TABLE /////////////////////////////////////
|
||||
//
|
||||
cmd ::= DROP TABLE ifexists(E) fullname(X). {
|
||||
cmd ::= DROP TABLE ifexists(E) fullnamelist(X). {
|
||||
sqlite3DropTable(pParse, X, 0, E);
|
||||
}
|
||||
%type ifexists {int}
|
||||
@@ -485,7 +485,7 @@ cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C)
|
||||
AS select(S). {
|
||||
sqlite3CreateView(pParse, &X, &Y, &Z, C, S, T, E);
|
||||
}
|
||||
cmd ::= DROP VIEW ifexists(E) fullname(X). {
|
||||
cmd ::= DROP VIEW ifexists(E) fullnamelist(X). {
|
||||
sqlite3DropTable(pParse, X, 1, E);
|
||||
}
|
||||
%endif SQLITE_OMIT_VIEW
|
||||
@@ -774,6 +774,18 @@ fullname(A) ::= nm(X) DOT nm(Y). {
|
||||
if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y);
|
||||
}
|
||||
|
||||
%type fullnamelist {SrcList*}
|
||||
%destructor fullnamelist {sqlite3SrcListDelete(pParse->db, $$);}
|
||||
fullnamelist(A) ::= fullname(A).
|
||||
fullnamelist(A) ::= fullnamelist(L) COMMA nm(X). {
|
||||
A = sqlite3SrcListAppend(pParse,L,&X,0);
|
||||
assert( !IN_RENAME_OBJECT ); /* Used only by DROP, which cannot be part of schema */
|
||||
}
|
||||
fullnamelist(A) ::= fullnamelist(L) COMMA nm(X) DOT nm(Y). {
|
||||
A = sqlite3SrcListAppend(pParse,L,&X,&Y);
|
||||
assert( !IN_RENAME_OBJECT ); /* Used only by DROP, which cannot be part of schema */
|
||||
}
|
||||
|
||||
%type xfullname {SrcList*}
|
||||
%destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);}
|
||||
xfullname(A) ::= nm(X).
|
||||
@@ -1504,7 +1516,7 @@ collate(C) ::= COLLATE ids. {C = 1;}
|
||||
|
||||
///////////////////////////// The DROP INDEX command /////////////////////////
|
||||
//
|
||||
cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
|
||||
cmd ::= DROP INDEX ifexists(E) fullnamelist(X). {sqlite3DropIndex(pParse, X, E);}
|
||||
|
||||
///////////////////////////// The VACUUM command /////////////////////////////
|
||||
//
|
||||
@@ -1661,7 +1673,7 @@ raisetype(A) ::= FAIL. {A = OE_Fail;}
|
||||
|
||||
//////////////////////// DROP TRIGGER statement //////////////////////////////
|
||||
%ifndef SQLITE_OMIT_TRIGGER
|
||||
cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
|
||||
cmd ::= DROP TRIGGER ifexists(NOERR) fullnamelist(X). {
|
||||
sqlite3DropTrigger(pParse,X,NOERR);
|
||||
}
|
||||
%endif !SQLITE_OMIT_TRIGGER
|
||||
@@ -1935,6 +1947,12 @@ filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
|
||||
SPAN /* The span operator */
|
||||
ERROR /* An expression containing an error */
|
||||
.
|
||||
|
||||
term(A) ::= QNUMBER(X). {
|
||||
A=tokenExpr(pParse,@X,X);
|
||||
sqlite3DequoteNumber(pParse, A);
|
||||
}
|
||||
|
||||
/* There must be no more than 255 tokens defined above. If this grammar
|
||||
** is extended with new rules and tokens, they must either be so few in
|
||||
** number that TK_SPAN is no more than 255, or else the new tokens must
|
||||
|
||||
+187
-58
@@ -30,6 +30,34 @@
|
||||
** ../tool/mkpragmatab.tcl. */
|
||||
#include "pragma.h"
|
||||
|
||||
/*
|
||||
** When the 0x10 bit of PRAGMA optimize is set, any ANALYZE commands
|
||||
** will be run with an analysis_limit set to the lessor of the value of
|
||||
** the following macro or to the actual analysis_limit if it is non-zero,
|
||||
** in order to prevent PRAGMA optimize from running for too long.
|
||||
**
|
||||
** The value of 2000 is chosen emperically so that the worst-case run-time
|
||||
** for PRAGMA optimize does not exceed 100 milliseconds against a variety
|
||||
** of test databases on a RaspberryPI-4 compiled using -Os and without
|
||||
** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of
|
||||
** this paragraph, "worst-case" means that ANALYZE ends up being
|
||||
** run on every table in the database. The worst case typically only
|
||||
** happens if PRAGMA optimize is run on a database file for which ANALYZE
|
||||
** has not been previously run and the 0x10000 flag is included so that
|
||||
** all tables are analyzed. The usual case for PRAGMA optimize is that
|
||||
** no ANALYZE commands will be run at all, or if any ANALYZE happens it
|
||||
** will be against a single table, so that expected timing for PRAGMA
|
||||
** optimize on a PI-4 is more like 1 millisecond or less with the 0x10000
|
||||
** flag or less than 100 microseconds without the 0x10000 flag.
|
||||
**
|
||||
** An analysis limit of 2000 is almost always sufficient for the query
|
||||
** planner to fully characterize an index. The additional accuracy from
|
||||
** a larger analysis is not usually helpful.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_OPTIMIZE_LIMIT
|
||||
# define SQLITE_DEFAULT_OPTIMIZE_LIMIT 2000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Interpret the given string as a safety level. Return 0 for OFF,
|
||||
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
|
||||
@@ -1692,7 +1720,6 @@ void sqlite3Pragma(
|
||||
Hash *pTbls; /* Set of all tables in the schema */
|
||||
int *aRoot; /* Array of root page numbers of all btrees */
|
||||
int cnt = 0; /* Number of entries in aRoot[] */
|
||||
int mxIdx = 0; /* Maximum number of indexes for any table */
|
||||
|
||||
if( OMIT_TEMPDB && i==1 ) continue;
|
||||
if( iDb>=0 && i!=iDb ) continue;
|
||||
@@ -1714,7 +1741,6 @@ void sqlite3Pragma(
|
||||
if( pObjTab && pObjTab!=pTab ) continue;
|
||||
if( HasRowid(pTab) ) cnt++;
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
|
||||
if( nIdx>mxIdx ) mxIdx = nIdx;
|
||||
}
|
||||
if( cnt==0 ) continue;
|
||||
if( pObjTab ) cnt++;
|
||||
@@ -1734,11 +1760,11 @@ void sqlite3Pragma(
|
||||
aRoot[0] = cnt;
|
||||
|
||||
/* Make sure sufficient number of registers have been allocated */
|
||||
sqlite3TouchRegister(pParse, 8+mxIdx);
|
||||
sqlite3TouchRegister(pParse, 8+cnt);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
|
||||
/* Do the b-tree integrity checks */
|
||||
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
|
||||
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
|
||||
sqlite3VdbeChangeP5(v, (u8)i);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||
@@ -1748,6 +1774,36 @@ void sqlite3Pragma(
|
||||
integrityCheckResultRow(v);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
/* Check that the indexes all have the right number of rows */
|
||||
cnt = pObjTab ? 1 : 0;
|
||||
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
int iTab = 0;
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
if( pObjTab && pObjTab!=pTab ) continue;
|
||||
if( HasRowid(pTab) ){
|
||||
iTab = cnt++;
|
||||
}else{
|
||||
iTab = cnt;
|
||||
for(pIdx=pTab->pIndex; ALWAYS(pIdx); pIdx=pIdx->pNext){
|
||||
if( IsPrimaryKeyIndex(pIdx) ) break;
|
||||
iTab++;
|
||||
}
|
||||
}
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->pPartIdxWhere==0 ){
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+cnt, 0, 8+iTab);
|
||||
VdbeCoverageNeverNull(v);
|
||||
sqlite3VdbeLoadString(v, 4, pIdx->zName);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
|
||||
integrityCheckResultRow(v);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure all the indices are constructed correctly.
|
||||
*/
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
@@ -1897,6 +1953,7 @@ void sqlite3Pragma(
|
||||
** is REAL, we have to load the actual data using OP_Column
|
||||
** to reliably determine if the value is a NULL. */
|
||||
sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
|
||||
sqlite3ColumnDefault(v, pTab, j, 3);
|
||||
jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
@@ -2070,21 +2127,9 @@ void sqlite3Pragma(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
if( !isQuick ){
|
||||
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
if( pPk==pIdx ) continue;
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
||||
sqlite3VdbeLoadString(v, 4, pIdx->zName);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
|
||||
integrityCheckResultRow(v);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
if( pPk ){
|
||||
sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
|
||||
}
|
||||
if( pPk ){
|
||||
assert( !isQuick );
|
||||
sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2116,10 +2161,9 @@ void sqlite3Pragma(
|
||||
a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
|
||||
integrityCheckResultRow(v);
|
||||
sqlite3VdbeJumpHere(v, a1);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
{
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
@@ -2383,44 +2427,63 @@ void sqlite3Pragma(
|
||||
**
|
||||
** The optional argument is a bitmask of optimizations to perform:
|
||||
**
|
||||
** 0x0001 Debugging mode. Do not actually perform any optimizations
|
||||
** but instead return one line of text for each optimization
|
||||
** that would have been done. Off by default.
|
||||
** 0x00001 Debugging mode. Do not actually perform any optimizations
|
||||
** but instead return one line of text for each optimization
|
||||
** that would have been done. Off by default.
|
||||
**
|
||||
** 0x0002 Run ANALYZE on tables that might benefit. On by default.
|
||||
** See below for additional information.
|
||||
** 0x00002 Run ANALYZE on tables that might benefit. On by default.
|
||||
** See below for additional information.
|
||||
**
|
||||
** 0x0004 (Not yet implemented) Record usage and performance
|
||||
** information from the current session in the
|
||||
** database file so that it will be available to "optimize"
|
||||
** pragmas run by future database connections.
|
||||
** 0x00010 Run all ANALYZE operations using an analysis_limit that
|
||||
** is the lessor of the current analysis_limit and the
|
||||
** SQLITE_DEFAULT_OPTIMIZE_LIMIT compile-time option.
|
||||
** The default value of SQLITE_DEFAULT_OPTIMIZE_LIMIT is
|
||||
** currently (2024-02-19) set to 2000, which is such that
|
||||
** the worst case run-time for PRAGMA optimize on a 100MB
|
||||
** database will usually be less than 100 milliseconds on
|
||||
** a RaspberryPI-4 class machine. On by default.
|
||||
**
|
||||
** 0x0008 (Not yet implemented) Create indexes that might have
|
||||
** been helpful to recent queries
|
||||
** 0x10000 Look at tables to see if they need to be reanalyzed
|
||||
** due to growth or shrinkage even if they have not been
|
||||
** queried during the current connection. Off by default.
|
||||
**
|
||||
** The default MASK is and always shall be 0xfffe. 0xfffe means perform all
|
||||
** of the optimizations listed above except Debug Mode, including new
|
||||
** optimizations that have not yet been invented. If new optimizations are
|
||||
** ever added that should be off by default, those off-by-default
|
||||
** optimizations will have bitmasks of 0x10000 or larger.
|
||||
** The default MASK is and always shall be 0x0fffe. In the current
|
||||
** implementation, the default mask only covers the 0x00002 optimization,
|
||||
** though additional optimizations that are covered by 0x0fffe might be
|
||||
** added in the future. Optimizations that are off by default and must
|
||||
** be explicitly requested have masks of 0x10000 or greater.
|
||||
**
|
||||
** DETERMINATION OF WHEN TO RUN ANALYZE
|
||||
**
|
||||
** In the current implementation, a table is analyzed if only if all of
|
||||
** the following are true:
|
||||
**
|
||||
** (1) MASK bit 0x02 is set.
|
||||
** (1) MASK bit 0x00002 is set.
|
||||
**
|
||||
** (2) The query planner used sqlite_stat1-style statistics for one or
|
||||
** more indexes of the table at some point during the lifetime of
|
||||
** the current connection.
|
||||
** (2) The table is an ordinary table, not a virtual table or view.
|
||||
**
|
||||
** (3) One or more indexes of the table are currently unanalyzed OR
|
||||
** the number of rows in the table has increased by 25 times or more
|
||||
** since the last time ANALYZE was run.
|
||||
** (3) The table name does not begin with "sqlite_".
|
||||
**
|
||||
** (4) One or more of the following is true:
|
||||
** (4a) The 0x10000 MASK bit is set.
|
||||
** (4b) One or more indexes on the table lacks an entry
|
||||
** in the sqlite_stat1 table.
|
||||
** (4c) The query planner used sqlite_stat1-style statistics for one
|
||||
** or more indexes of the table at some point during the lifetime
|
||||
** of the current connection.
|
||||
**
|
||||
** (5) One or more of the following is true:
|
||||
** (5a) One or more indexes on the table lacks an entry
|
||||
** in the sqlite_stat1 table. (Same as 4a)
|
||||
** (5b) The number of rows in the table has increased or decreased by
|
||||
** 10-fold. In other words, the current size of the table is
|
||||
** 10 times larger than the size in sqlite_stat1 or else the
|
||||
** current size is less than 1/10th the size in sqlite_stat1.
|
||||
**
|
||||
** The rules for when tables are analyzed are likely to change in
|
||||
** future releases.
|
||||
** future releases. Future versions of SQLite might accept a string
|
||||
** literal argument to this pragma that contains a mnemonic description
|
||||
** of the options rather than a bitmap.
|
||||
*/
|
||||
case PragTyp_OPTIMIZE: {
|
||||
int iDbLast; /* Loop termination point for the schema loop */
|
||||
@@ -2432,6 +2495,10 @@ void sqlite3Pragma(
|
||||
LogEst szThreshold; /* Size threshold above which reanalysis needed */
|
||||
char *zSubSql; /* SQL statement for the OP_SqlExec opcode */
|
||||
u32 opMask; /* Mask of operations to perform */
|
||||
int nLimit; /* Analysis limit to use */
|
||||
int nCheck = 0; /* Number of tables to be optimized */
|
||||
int nBtree = 0; /* Number of btrees to scan */
|
||||
int nIndex; /* Number of indexes on the current table */
|
||||
|
||||
if( zRight ){
|
||||
opMask = (u32)sqlite3Atoi(zRight);
|
||||
@@ -2439,6 +2506,14 @@ void sqlite3Pragma(
|
||||
}else{
|
||||
opMask = 0xfffe;
|
||||
}
|
||||
if( (opMask & 0x10)==0 ){
|
||||
nLimit = 0;
|
||||
}else if( db->nAnalysisLimit>0
|
||||
&& db->nAnalysisLimit<SQLITE_DEFAULT_OPTIMIZE_LIMIT ){
|
||||
nLimit = 0;
|
||||
}else{
|
||||
nLimit = SQLITE_DEFAULT_OPTIMIZE_LIMIT;
|
||||
}
|
||||
iTabCur = pParse->nTab++;
|
||||
for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
|
||||
if( iDb==1 ) continue;
|
||||
@@ -2447,23 +2522,61 @@ void sqlite3Pragma(
|
||||
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
pTab = (Table*)sqliteHashData(k);
|
||||
|
||||
/* If table pTab has not been used in a way that would benefit from
|
||||
** having analysis statistics during the current session, then skip it.
|
||||
** This also has the effect of skipping virtual tables and views */
|
||||
if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
|
||||
/* This only works for ordinary tables */
|
||||
if( !IsOrdinaryTable(pTab) ) continue;
|
||||
|
||||
/* Reanalyze if the table is 25 times larger than the last analysis */
|
||||
szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 );
|
||||
/* Do not scan system tables */
|
||||
if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ) continue;
|
||||
|
||||
/* Find the size of the table as last recorded in sqlite_stat1.
|
||||
** If any index is unanalyzed, then the threshold is -1 to
|
||||
** indicate a new, unanalyzed index
|
||||
*/
|
||||
szThreshold = pTab->nRowLogEst;
|
||||
nIndex = 0;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
nIndex++;
|
||||
if( !pIdx->hasStat1 ){
|
||||
szThreshold = 0; /* Always analyze if any index lacks statistics */
|
||||
break;
|
||||
szThreshold = -1; /* Always analyze if any index lacks statistics */
|
||||
}
|
||||
}
|
||||
if( szThreshold ){
|
||||
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
|
||||
sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
|
||||
sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
|
||||
|
||||
/* If table pTab has not been used in a way that would benefit from
|
||||
** having analysis statistics during the current session, then skip it,
|
||||
** unless the 0x10000 MASK bit is set. */
|
||||
if( (pTab->tabFlags & TF_MaybeReanalyze)!=0 ){
|
||||
/* Check for size change if stat1 has been used for a query */
|
||||
}else if( opMask & 0x10000 ){
|
||||
/* Check for size change if 0x10000 is set */
|
||||
}else if( pTab->pIndex!=0 && szThreshold<0 ){
|
||||
/* Do analysis if unanalyzed indexes exists */
|
||||
}else{
|
||||
/* Otherwise, we can skip this table */
|
||||
continue;
|
||||
}
|
||||
|
||||
nCheck++;
|
||||
if( nCheck==2 ){
|
||||
/* If ANALYZE might be invoked two or more times, hold a write
|
||||
** transaction for efficiency */
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
}
|
||||
nBtree += nIndex+1;
|
||||
|
||||
/* Reanalyze if the table is 10 times larger or smaller than
|
||||
** the last analysis. Unconditional reanalysis if there are
|
||||
** unanalyzed indexes. */
|
||||
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
|
||||
if( szThreshold>=0 ){
|
||||
const LogEst iRange = 33; /* 10x size change */
|
||||
sqlite3VdbeAddOp4Int(v, OP_IfSizeBetween, iTabCur,
|
||||
sqlite3VdbeCurrentAddr(v)+2+(opMask&1),
|
||||
szThreshold>=iRange ? szThreshold-iRange : -1,
|
||||
szThreshold+iRange);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iTabCur,
|
||||
sqlite3VdbeCurrentAddr(v)+2+(opMask&1));
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
|
||||
@@ -2473,11 +2586,27 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp4(v, OP_SqlExec, nLimit ? 0x02 : 00, nLimit, 0,
|
||||
zSubSql, P4_DYNAMIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
|
||||
/* In a schema with a large number of tables and indexes, scale back
|
||||
** the analysis_limit to avoid excess run-time in the worst case.
|
||||
*/
|
||||
if( !db->mallocFailed && nLimit>0 && nBtree>100 ){
|
||||
int iAddr, iEnd;
|
||||
VdbeOp *aOp;
|
||||
nLimit = 100*nLimit/nBtree;
|
||||
if( nLimit<100 ) nLimit = 100;
|
||||
aOp = sqlite3VdbeGetOp(v, 0);
|
||||
iEnd = sqlite3VdbeCurrentAddr(v);
|
||||
for(iAddr=0; iAddr<iEnd; iAddr++){
|
||||
if( aOp[iAddr].opcode==OP_SqlExec ) aOp[iAddr].p2 = nLimit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -498,6 +498,7 @@ void sqlite3_str_vappendf(
|
||||
if( xtype==etFLOAT ){
|
||||
iRound = -precision;
|
||||
}else if( xtype==etGENERIC ){
|
||||
if( precision==0 ) precision = 1;
|
||||
iRound = precision;
|
||||
}else{
|
||||
iRound = precision+1;
|
||||
@@ -533,13 +534,14 @@ void sqlite3_str_vappendf(
|
||||
}
|
||||
|
||||
exp = s.iDP-1;
|
||||
if( xtype==etGENERIC && precision>0 ) precision--;
|
||||
|
||||
/*
|
||||
** If the field type is etGENERIC, then convert to either etEXP
|
||||
** or etFLOAT, as appropriate.
|
||||
*/
|
||||
if( xtype==etGENERIC ){
|
||||
assert( precision>0 );
|
||||
precision--;
|
||||
flag_rtz = !flag_alternateform;
|
||||
if( exp<-4 || exp>precision ){
|
||||
xtype = etEXP;
|
||||
|
||||
@@ -79,6 +79,8 @@ static void resolveAlias(
|
||||
assert( iCol>=0 && iCol<pEList->nExpr );
|
||||
pOrig = pEList->a[iCol].pExpr;
|
||||
assert( pOrig!=0 );
|
||||
assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) );
|
||||
if( pExpr->pAggInfo ) return;
|
||||
db = pParse->db;
|
||||
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||
if( db->mallocFailed ){
|
||||
|
||||
@@ -6444,6 +6444,8 @@ void sqlite3SelectPrep(
|
||||
*/
|
||||
static void printAggInfo(AggInfo *pAggInfo){
|
||||
int ii;
|
||||
sqlite3DebugPrintf("AggInfo %d/%p:\n",
|
||||
pAggInfo->selId, pAggInfo);
|
||||
for(ii=0; ii<pAggInfo->nColumn; ii++){
|
||||
struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
|
||||
sqlite3DebugPrintf(
|
||||
@@ -8546,6 +8548,12 @@ select_end:
|
||||
sqlite3ExprListDelete(db, pMinMaxOrderBy);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pAggInfo && !db->mallocFailed ){
|
||||
#if TREETRACE_ENABLED
|
||||
if( sqlite3TreeTrace & 0x20 ){
|
||||
TREETRACE(0x20,pParse,p,("Finished with AggInfo\n"));
|
||||
printAggInfo(pAggInfo);
|
||||
}
|
||||
#endif
|
||||
for(i=0; i<pAggInfo->nColumn; i++){
|
||||
Expr *pExpr = pAggInfo->aCol[i].pCExpr;
|
||||
if( pExpr==0 ) continue;
|
||||
|
||||
+157
-5
@@ -268,6 +268,9 @@ INCLUDE ../ext/consio/console_io.c
|
||||
* setOutputStream(FILE *pf)
|
||||
* This is normally the stream that CLI normal output goes to.
|
||||
* For the stand-alone CLI, it is stdout with no .output redirect.
|
||||
*
|
||||
* The ?putz(z) forms are required for the Fiddle builds for string literal
|
||||
* output, in aid of enforcing format string to argument correspondence.
|
||||
*/
|
||||
# define sputz(s,z) fPutsUtf8(z,s)
|
||||
# define sputf fPrintfUtf8
|
||||
@@ -279,12 +282,18 @@ INCLUDE ../ext/consio/console_io.c
|
||||
|
||||
#else
|
||||
/* For Fiddle, all console handling and emit redirection is omitted. */
|
||||
# define sputz(fp,z) fputs(z,fp)
|
||||
# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
|
||||
# define oputz(z) fputs(z,stdout)
|
||||
/* These next 3 macros are for emitting formatted output. When complaints
|
||||
* from the WASM build are issued for non-formatted output, (when a mere
|
||||
* string literal is to be emitted, the ?putz(z) forms should be used.
|
||||
* (This permits compile-time checking of format string / argument mismatch.)
|
||||
*/
|
||||
# define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
|
||||
# define eputz(z) fputs(z,stderr)
|
||||
# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
|
||||
# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
|
||||
/* These next 3 macros are for emitting simple string literals. */
|
||||
# define oputz(z) fputs(z,stdout)
|
||||
# define eputz(z) fputs(z,stderr)
|
||||
# define sputz(fp,z) fputs(z,fp)
|
||||
# define oputb(buf,na) fwrite(buf,1,na,stdout)
|
||||
#endif
|
||||
|
||||
@@ -1213,6 +1222,9 @@ INCLUDE ../ext/misc/sqlar.c
|
||||
INCLUDE ../ext/expert/sqlite3expert.h
|
||||
INCLUDE ../ext/expert/sqlite3expert.c
|
||||
|
||||
INCLUDE ../ext/intck/sqlite3intck.h
|
||||
INCLUDE ../ext/intck/sqlite3intck.c
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
#define SQLITE_SHELL_HAVE_RECOVER 1
|
||||
#else
|
||||
@@ -4732,6 +4744,7 @@ static const char *(azHelp[]) = {
|
||||
".indexes ?TABLE? Show names of indexes",
|
||||
" If TABLE is specified, only show indexes for",
|
||||
" tables matching TABLE using the LIKE operator.",
|
||||
".intck ?STEPS_PER_UNLOCK? Run an incremental integrity check on the db",
|
||||
#ifdef SQLITE_ENABLE_IOTRACE
|
||||
",iotrace FILE Enable I/O diagnostic logging to FILE",
|
||||
#endif
|
||||
@@ -7641,6 +7654,40 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
}
|
||||
#endif /* SQLITE_SHELL_HAVE_RECOVER */
|
||||
|
||||
/*
|
||||
** Implementation of ".intck STEPS_PER_UNLOCK" command.
|
||||
*/
|
||||
static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
|
||||
sqlite3_intck *p = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
rc = sqlite3_intck_open(pState->db, "main", &p);
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 nStep = 0;
|
||||
i64 nError = 0;
|
||||
const char *zErr = 0;
|
||||
while( SQLITE_OK==sqlite3_intck_step(p) ){
|
||||
const char *zMsg = sqlite3_intck_message(p);
|
||||
if( zMsg ){
|
||||
oputf("%s\n", zMsg);
|
||||
nError++;
|
||||
}
|
||||
nStep++;
|
||||
if( nStepPerUnlock && (nStep % nStepPerUnlock)==0 ){
|
||||
sqlite3_intck_unlock(p);
|
||||
}
|
||||
}
|
||||
rc = sqlite3_intck_error(p, &zErr);
|
||||
if( zErr ){
|
||||
eputf("%s\n", zErr);
|
||||
}
|
||||
sqlite3_intck_close(p);
|
||||
|
||||
oputf("%lld steps, %lld errors\n", nStep, nError);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
|
||||
@@ -7884,6 +7931,38 @@ static int outputDumpWarning(ShellState *p, const char *zLike){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Fault-Simulator state and logic.
|
||||
*/
|
||||
static struct {
|
||||
int iId; /* ID that triggers a simulated fault. -1 means "any" */
|
||||
int iErr; /* The error code to return on a fault */
|
||||
int iCnt; /* Trigger the fault only if iCnt is already zero */
|
||||
int iInterval; /* Reset iCnt to this value after each fault */
|
||||
int eVerbose; /* When to print output */
|
||||
} faultsim_state = {-1, 0, 0, 0, 0};
|
||||
|
||||
/*
|
||||
** This is the fault-sim callback
|
||||
*/
|
||||
static int faultsim_callback(int iArg){
|
||||
if( faultsim_state.iId>0 && faultsim_state.iId!=iArg ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( faultsim_state.iCnt>0 ){
|
||||
faultsim_state.iCnt--;
|
||||
if( faultsim_state.eVerbose>=2 ){
|
||||
oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( faultsim_state.eVerbose>=1 ){
|
||||
oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
|
||||
}
|
||||
faultsim_state.iCnt = faultsim_state.iInterval;
|
||||
return faultsim_state.iErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** If an input line begins with "." then invoke this routine to
|
||||
** process that line.
|
||||
@@ -9099,6 +9178,21 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
|
||||
|
||||
if( c=='i' && cli_strncmp(azArg[0], "intck", n)==0 ){
|
||||
i64 iArg = 0;
|
||||
if( nArg==2 ){
|
||||
iArg = integerValue(azArg[1]);
|
||||
if( iArg==0 ) iArg = -1;
|
||||
}
|
||||
if( (nArg!=1 && nArg!=2) || iArg<0 ){
|
||||
eputf("%s","Usage: .intck STEPS_PER_UNLOCK\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
open_db(p, 0);
|
||||
rc = intckDatabaseCmd(p, iArg);
|
||||
}else
|
||||
|
||||
#ifdef SQLITE_ENABLE_IOTRACE
|
||||
if( c=='i' && cli_strncmp(azArg[0], "iotrace", n)==0 ){
|
||||
SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
|
||||
@@ -10772,7 +10866,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
/*{"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/
|
||||
{"byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" },
|
||||
{"extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" },
|
||||
/*{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/
|
||||
{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"args..." },
|
||||
{"fk_no_action", SQLITE_TESTCTRL_FK_NO_ACTION, 0, "BOOLEAN" },
|
||||
{"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
|
||||
{"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" },
|
||||
@@ -11005,6 +11099,64 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
sqlite3_test_control(testctrl, &rc2);
|
||||
break;
|
||||
case SQLITE_TESTCTRL_FAULT_INSTALL: {
|
||||
int kk;
|
||||
int bShowHelp = nArg<=2;
|
||||
isOk = 3;
|
||||
for(kk=2; kk<nArg; kk++){
|
||||
const char *z = azArg[kk];
|
||||
if( z[0]=='-' && z[1]=='-' ) z++;
|
||||
if( cli_strcmp(z,"off")==0 ){
|
||||
sqlite3_test_control(testctrl, 0);
|
||||
}else if( cli_strcmp(z,"on")==0 ){
|
||||
faultsim_state.iCnt = faultsim_state.iInterval;
|
||||
if( faultsim_state.iErr==0 ) faultsim_state.iErr = 1;
|
||||
sqlite3_test_control(testctrl, faultsim_callback);
|
||||
}else if( cli_strcmp(z,"reset")==0 ){
|
||||
faultsim_state.iCnt = faultsim_state.iInterval;
|
||||
}else if( cli_strcmp(z,"status")==0 ){
|
||||
oputf("faultsim.iId: %d\n", faultsim_state.iId);
|
||||
oputf("faultsim.iErr: %d\n", faultsim_state.iErr);
|
||||
oputf("faultsim.iCnt: %d\n", faultsim_state.iCnt);
|
||||
oputf("faultsim.iInterval: %d\n", faultsim_state.iInterval);
|
||||
oputf("faultsim.eVerbose: %d\n", faultsim_state.eVerbose);
|
||||
}else if( cli_strcmp(z,"-v")==0 ){
|
||||
if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
|
||||
}else if( cli_strcmp(z,"-q")==0 ){
|
||||
if( faultsim_state.eVerbose>0 ) faultsim_state.eVerbose--;
|
||||
}else if( cli_strcmp(z,"-id")==0 && kk+1<nArg ){
|
||||
faultsim_state.iId = atoi(azArg[++kk]);
|
||||
}else if( cli_strcmp(z,"-errcode")==0 && kk+1<nArg ){
|
||||
faultsim_state.iErr = atoi(azArg[++kk]);
|
||||
}else if( cli_strcmp(z,"-interval")==0 && kk+1<nArg ){
|
||||
faultsim_state.iInterval = atoi(azArg[++kk]);
|
||||
}else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
|
||||
bShowHelp = 1;
|
||||
}else{
|
||||
eputf("Unrecognized fault_install argument: \"%s\"\n",
|
||||
azArg[kk]);
|
||||
rc = 1;
|
||||
bShowHelp = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( bShowHelp ){
|
||||
oputz(
|
||||
"Usage: .testctrl fault_install ARGS\n"
|
||||
"Possible arguments:\n"
|
||||
" off Disable faultsim\n"
|
||||
" on Activate faultsim\n"
|
||||
" reset Reset the trigger counter\n"
|
||||
" status Show current status\n"
|
||||
" -v Increase verbosity\n"
|
||||
" -q Decrease verbosity\n"
|
||||
" --errcode N When triggered, return N as error code\n"
|
||||
" --id ID Trigger only for the ID specified\n"
|
||||
" --interval N Trigger only after every N-th call\n"
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( isOk==0 && iCtrl>=0 ){
|
||||
|
||||
+4
-2
@@ -420,6 +420,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
||||
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
|
||||
** <li> The application must not modify the SQL statement text passed into
|
||||
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
|
||||
** <li> The application must not dereference the arrays or string pointers
|
||||
** passed as the 3rd and 4th callback parameters after it returns.
|
||||
** </ul>
|
||||
*/
|
||||
int sqlite3_exec(
|
||||
@@ -762,11 +764,11 @@ struct sqlite3_file {
|
||||
** </ul>
|
||||
** xLock() upgrades the database file lock. In other words, xLock() moves the
|
||||
** database file lock in the direction NONE toward EXCLUSIVE. The argument to
|
||||
** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
|
||||
** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
|
||||
** SQLITE_LOCK_NONE. If the database file lock is already at or above the
|
||||
** requested lock, then the call to xLock() is a no-op.
|
||||
** xUnlock() downgrades the database file lock to either SHARED or NONE.
|
||||
* If the lock is already at or below the requested lock state, then the call
|
||||
** If the lock is already at or below the requested lock state, then the call
|
||||
** to xUnlock() is a no-op.
|
||||
** The xCheckReservedLock() method checks whether any database connection,
|
||||
** either in this process or in some other process, is holding a RESERVED,
|
||||
|
||||
+7
-4
@@ -609,6 +609,8 @@
|
||||
# define SQLITE_OMIT_ALTERTABLE
|
||||
#endif
|
||||
|
||||
#define SQLITE_DIGIT_SEPARATOR '_'
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if the input is an integer that is too large
|
||||
** to fit in 32-bits. This macro is used inside of various testcase()
|
||||
@@ -2476,8 +2478,7 @@ struct Table {
|
||||
#define TF_HasStored 0x00000040 /* Has one or more STORED columns */
|
||||
#define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */
|
||||
#define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */
|
||||
#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by
|
||||
** Index.aiRowLogEst[] values */
|
||||
#define TF_MaybeReanalyze 0x00000100 /* Maybe run ANALYZE on this table */
|
||||
#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */
|
||||
#define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */
|
||||
#define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */
|
||||
@@ -3313,6 +3314,8 @@ struct SrcItem {
|
||||
union {
|
||||
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
||||
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
|
||||
Trigger *pTrig; /* Trigger in argument list of DROP TRIGGER */
|
||||
Index *pIdx; /* Index in argument list to DROP INDEX */
|
||||
} u2;
|
||||
};
|
||||
|
||||
@@ -4796,6 +4799,7 @@ int sqlite3ErrorToParser(sqlite3*,int);
|
||||
void sqlite3Dequote(char*);
|
||||
void sqlite3DequoteExpr(Expr*);
|
||||
void sqlite3DequoteToken(Token*);
|
||||
void sqlite3DequoteNumber(Parse*, Expr*);
|
||||
void sqlite3TokenInit(Token*,char*);
|
||||
int sqlite3KeywordCode(const unsigned char*, int);
|
||||
int sqlite3RunParser(Parse*, const char*);
|
||||
@@ -4924,7 +4928,6 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
|
||||
int sqlite3DbMaskAllZero(yDbMask);
|
||||
#endif
|
||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||
void sqlite3CodeDropTable(Parse*, Table*, int, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
void sqlite3DeleteTableGeneric(sqlite3*, void*);
|
||||
void sqlite3FreeIndex(sqlite3*, Index*);
|
||||
@@ -5572,7 +5575,7 @@ const char *sqlite3JournalModename(int);
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
void sqlite3FkCheck(Parse*, Table*, int, int, int*, int);
|
||||
void sqlite3FkDropTable(Parse*, SrcList *, Table*);
|
||||
void sqlite3FkDropTable(Parse*, SrcList*, Table*);
|
||||
void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int);
|
||||
int sqlite3FkRequired(Parse*, Table*, int*, int);
|
||||
u32 sqlite3FkOldmask(Parse*, Table*);
|
||||
|
||||
@@ -108,6 +108,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
|
||||
extern int Sqlitetest_window_Init(Tcl_Interp *);
|
||||
extern int Sqlitetestvdbecov_Init(Tcl_Interp *);
|
||||
extern int TestRecover_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestintck_Init(Tcl_Interp*);
|
||||
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
|
||||
@@ -175,6 +176,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
|
||||
Sqlitetest_window_Init(interp);
|
||||
Sqlitetestvdbecov_Init(interp);
|
||||
TestRecover_Init(interp);
|
||||
Sqlitetestintck_Init(interp);
|
||||
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
|
||||
|
||||
+54
-20
@@ -437,27 +437,58 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
*tokenType = TK_INTEGER;
|
||||
#ifndef SQLITE_OMIT_HEX_INTEGER
|
||||
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
|
||||
for(i=3; sqlite3Isxdigit(z[i]); i++){}
|
||||
return i;
|
||||
}
|
||||
for(i=3; 1; i++){
|
||||
if( sqlite3Isxdigit(z[i])==0 ){
|
||||
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
|
||||
*tokenType = TK_QNUMBER;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
for(i=0; sqlite3Isdigit(z[i]); i++){}
|
||||
{
|
||||
for(i=0; 1; i++){
|
||||
if( sqlite3Isdigit(z[i])==0 ){
|
||||
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
|
||||
*tokenType = TK_QNUMBER;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( z[i]=='.' ){
|
||||
i++;
|
||||
while( sqlite3Isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
if( (z[i]=='e' || z[i]=='E') &&
|
||||
( sqlite3Isdigit(z[i+1])
|
||||
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
|
||||
)
|
||||
){
|
||||
i += 2;
|
||||
while( sqlite3Isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
if( z[i]=='.' ){
|
||||
if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
|
||||
for(i++; 1; i++){
|
||||
if( sqlite3Isdigit(z[i])==0 ){
|
||||
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
|
||||
*tokenType = TK_QNUMBER;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( (z[i]=='e' || z[i]=='E') &&
|
||||
( sqlite3Isdigit(z[i+1])
|
||||
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
|
||||
)
|
||||
){
|
||||
if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
|
||||
for(i+=2; 1; i++){
|
||||
if( sqlite3Isdigit(z[i])==0 ){
|
||||
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
|
||||
*tokenType = TK_QNUMBER;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
while( IdChar(z[i]) ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
i++;
|
||||
@@ -622,10 +653,13 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
if( tokenType>=TK_WINDOW ){
|
||||
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|
||||
|| tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
|
||||
|| tokenType==TK_QNUMBER
|
||||
);
|
||||
#else
|
||||
if( tokenType>=TK_SPACE ){
|
||||
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
|
||||
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL
|
||||
|| tokenType==TK_QNUMBER
|
||||
);
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
if( AtomicLoad(&db->u1.isInterrupted) ){
|
||||
pParse->rc = SQLITE_INTERRUPT;
|
||||
@@ -658,7 +692,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
assert( n==6 );
|
||||
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
}else{
|
||||
}else if( tokenType!=TK_QNUMBER ){
|
||||
Token x;
|
||||
x.z = zSql;
|
||||
x.n = n;
|
||||
|
||||
+30
-26
@@ -624,35 +624,39 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
|
||||
const char *zDb;
|
||||
const char *zName;
|
||||
sqlite3 *db = pParse->db;
|
||||
int ii, jj;
|
||||
|
||||
if( db->mallocFailed ) goto drop_trigger_cleanup;
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
|
||||
assert( pName->nSrc==1 );
|
||||
zDb = pName->a[0].zDatabase;
|
||||
zName = pName->a[0].zName;
|
||||
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
|
||||
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
if( !pTrigger ){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, zDb);
|
||||
sqlite3ReadSchema(pParse);
|
||||
assert( pName!=0 || pParse->nErr!=0 );
|
||||
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
|
||||
zDb = pName->a[ii].zDatabase;
|
||||
zName = pName->a[ii].zName;
|
||||
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
|
||||
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
goto drop_trigger_cleanup;
|
||||
pName->a[ii].u2.pTrig = pTrigger;
|
||||
if( !pTrigger ){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a+ii);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, zDb);
|
||||
}
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
pParse->checkSchema = 1;
|
||||
continue;
|
||||
}
|
||||
for(jj=ii-1; jj>=0; jj--){
|
||||
if( pName->a[jj].u2.pTrig==pTrigger ) break;
|
||||
}
|
||||
if( jj>=0 ) continue;
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
}
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
|
||||
drop_trigger_cleanup:
|
||||
sqlite3SrcListDelete(db, pName);
|
||||
}
|
||||
|
||||
|
||||
+39
-1
@@ -311,6 +311,44 @@ void sqlite3DequoteExpr(Expr *p){
|
||||
sqlite3Dequote(p->u.zToken);
|
||||
}
|
||||
|
||||
/*
|
||||
** Expression p is a QNUMBER (quoted number). Dequote the value in p->u.zToken
|
||||
** and set the type to INTEGER or FLOAT. "Quoted" integers or floats are those
|
||||
** that contain '_' characters that must be removed before further processing.
|
||||
*/
|
||||
void sqlite3DequoteNumber(Parse *pParse, Expr *p){
|
||||
assert( p!=0 || pParse->db->mallocFailed );
|
||||
if( p ){
|
||||
const char *pIn = p->u.zToken;
|
||||
char *pOut = p->u.zToken;
|
||||
int bHex = (pIn[0]=='0' && (pIn[1]=='x' || pIn[1]=='X'));
|
||||
int iValue;
|
||||
assert( p->op==TK_QNUMBER );
|
||||
p->op = TK_INTEGER;
|
||||
do {
|
||||
if( *pIn!=SQLITE_DIGIT_SEPARATOR ){
|
||||
*pOut++ = *pIn;
|
||||
if( *pIn=='e' || *pIn=='E' || *pIn=='.' ) p->op = TK_FLOAT;
|
||||
}else{
|
||||
if( (bHex==0 && (!sqlite3Isdigit(pIn[-1]) || !sqlite3Isdigit(pIn[1])))
|
||||
|| (bHex==1 && (!sqlite3Isxdigit(pIn[-1]) || !sqlite3Isxdigit(pIn[1])))
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "unrecognized token: \"%s\"", p->u.zToken);
|
||||
}
|
||||
}
|
||||
}while( *pIn++ );
|
||||
if( bHex ) p->op = TK_INTEGER;
|
||||
|
||||
/* tag-20240227-a: If after dequoting, the number is an integer that
|
||||
** fits in 32 bits, then it must be converted into EP_IntValue. Other
|
||||
** parts of the code expect this. See also tag-20240227-b. */
|
||||
if( p->op==TK_INTEGER && sqlite3GetInt32(p->u.zToken, &iValue) ){
|
||||
p->u.iValue = iValue;
|
||||
p->flags |= EP_IntValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If the input token p is quoted, try to adjust the token to remove
|
||||
** the quotes. This is not always possible:
|
||||
@@ -1069,7 +1107,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
|
||||
assert( p->n>0 );
|
||||
assert( p->n<sizeof(p->zBuf) );
|
||||
p->iDP = p->n + exp;
|
||||
if( iRound<0 ){
|
||||
if( iRound<=0 ){
|
||||
iRound = p->iDP - iRound;
|
||||
if( iRound==0 && p->zBuf[i+1]>='5' ){
|
||||
iRound = 1;
|
||||
|
||||
+46
-22
@@ -2086,7 +2086,7 @@ case OP_RealAffinity: { /* in1 */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE)
|
||||
/* Opcode: Cast P1 P2 * * *
|
||||
** Synopsis: affinity(r[P1])
|
||||
**
|
||||
@@ -6192,28 +6192,37 @@ case OP_Last: { /* jump, ncycle */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IfSmaller P1 P2 P3 * *
|
||||
/* Opcode: IfSizeBetween P1 P2 P3 P4 *
|
||||
**
|
||||
** Estimate the number of rows in the table P1. Jump to P2 if that
|
||||
** estimate is less than approximately 2**(0.1*P3).
|
||||
** Let N be the approximate number of rows in the table or index
|
||||
** with cursor P1 and let X be 10*log2(N) if N is positive or -1
|
||||
** if N is zero. Thus X will be within the range of -1 to 640, inclusive
|
||||
** Jump to P2 if X is in between P3 and P4, inclusive.
|
||||
*/
|
||||
case OP_IfSmaller: { /* jump */
|
||||
case OP_IfSizeBetween: { /* jump */
|
||||
VdbeCursor *pC;
|
||||
BtCursor *pCrsr;
|
||||
int res;
|
||||
i64 sz;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( pOp->p4type==P4_INT32 );
|
||||
assert( pOp->p3>=-1 && pOp->p3<=640 );
|
||||
assert( pOp->p4.i>=-1 && pOp->p4.i<=640 );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr );
|
||||
rc = sqlite3BtreeFirst(pCrsr, &res);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( res==0 ){
|
||||
if( res!=0 ){
|
||||
sz = -1; /* -Infinity encoding */
|
||||
}else{
|
||||
sz = sqlite3BtreeRowCountEst(pCrsr);
|
||||
if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
|
||||
assert( sz>0 );
|
||||
sz = sqlite3LogEst((u64)sz);
|
||||
}
|
||||
res = sz>=pOp->p3 && sz<=pOp->p4.i;
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ) goto jump_to_p2;
|
||||
break;
|
||||
@@ -6913,11 +6922,18 @@ case OP_CreateBtree: { /* out2 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SqlExec * * * P4 *
|
||||
/* Opcode: SqlExec P1 P2 * P4 *
|
||||
**
|
||||
** Run the SQL statement or statements specified in the P4 string.
|
||||
** Disable Auth and Trace callbacks while those statements are running if
|
||||
** P1 is true.
|
||||
**
|
||||
** The P1 parameter is a bitmask of options:
|
||||
**
|
||||
** 0x0001 Disable Auth and Trace callbacks while the statements
|
||||
** in P4 are running.
|
||||
**
|
||||
** 0x0002 Set db->nAnalysisLimit to P2 while the statements in
|
||||
** P4 are running.
|
||||
**
|
||||
*/
|
||||
case OP_SqlExec: {
|
||||
char *zErr;
|
||||
@@ -6925,6 +6941,7 @@ case OP_SqlExec: {
|
||||
sqlite3_xauth xAuth;
|
||||
#endif
|
||||
u8 mTrace;
|
||||
int savedAnalysisLimit;
|
||||
|
||||
sqlite3VdbeIncrWriteCounter(p, 0);
|
||||
db->nSqlExec++;
|
||||
@@ -6933,18 +6950,23 @@ case OP_SqlExec: {
|
||||
xAuth = db->xAuth;
|
||||
#endif
|
||||
mTrace = db->mTrace;
|
||||
if( pOp->p1 ){
|
||||
savedAnalysisLimit = db->nAnalysisLimit;
|
||||
if( pOp->p1 & 0x0001 ){
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
db->xAuth = 0;
|
||||
#endif
|
||||
db->mTrace = 0;
|
||||
}
|
||||
if( pOp->p1 & 0x0002 ){
|
||||
db->nAnalysisLimit = pOp->p2;
|
||||
}
|
||||
rc = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr);
|
||||
db->nSqlExec--;
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
db->xAuth = xAuth;
|
||||
#endif
|
||||
db->mTrace = mTrace;
|
||||
db->nAnalysisLimit = savedAnalysisLimit;
|
||||
if( zErr || rc ){
|
||||
sqlite3VdbeError(p, "%s", zErr);
|
||||
sqlite3_free(zErr);
|
||||
@@ -7096,13 +7118,13 @@ case OP_DropTrigger: {
|
||||
/* Opcode: IntegrityCk P1 P2 P3 P4 P5
|
||||
**
|
||||
** Do an analysis of the currently open database. Store in
|
||||
** register P1 the text of an error message describing any problems.
|
||||
** If no problems are found, store a NULL in register P1.
|
||||
** register (P1+1) the text of an error message describing any problems.
|
||||
** If no problems are found, store a NULL in register (P1+1).
|
||||
**
|
||||
** The register P3 contains one less than the maximum number of allowed errors.
|
||||
** At most reg(P3) errors will be reported.
|
||||
** In other words, the analysis stops as soon as reg(P3) errors are
|
||||
** seen. Reg(P3) is updated with the number of errors remaining.
|
||||
** The register (P1) contains one less than the maximum number of allowed
|
||||
** errors. At most reg(P1) errors will be reported.
|
||||
** In other words, the analysis stops as soon as reg(P1) errors are
|
||||
** seen. Reg(P1) is updated with the number of errors remaining.
|
||||
**
|
||||
** The root page numbers of all tables in the database are integers
|
||||
** stored in P4_INTARRAY argument.
|
||||
@@ -7120,19 +7142,21 @@ case OP_IntegrityCk: {
|
||||
Mem *pnErr; /* Register keeping track of errors remaining */
|
||||
|
||||
assert( p->bIsReader );
|
||||
assert( pOp->p4type==P4_INTARRAY );
|
||||
nRoot = pOp->p2;
|
||||
aRoot = pOp->p4.ai;
|
||||
assert( nRoot>0 );
|
||||
assert( aRoot!=0 );
|
||||
assert( aRoot[0]==(Pgno)nRoot );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pnErr = &aMem[pOp->p3];
|
||||
assert( pOp->p1>0 && (pOp->p1+1)<=(p->nMem+1 - p->nCursor) );
|
||||
pnErr = &aMem[pOp->p1];
|
||||
assert( (pnErr->flags & MEM_Int)!=0 );
|
||||
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
pIn1 = &aMem[pOp->p1+1];
|
||||
assert( pOp->p5<db->nDb );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p5) );
|
||||
rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
|
||||
(int)pnErr->u.i+1, &nErr, &z);
|
||||
rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1],
|
||||
&aMem[pOp->p3], nRoot, (int)pnErr->u.i+1, &nErr, &z);
|
||||
sqlite3VdbeMemSetNull(pIn1);
|
||||
if( nErr==0 ){
|
||||
assert( z==0 );
|
||||
|
||||
@@ -296,6 +296,8 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
|
||||
void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
|
||||
int sqlite3VdbeHasSubProgram(Vdbe*);
|
||||
|
||||
void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val);
|
||||
|
||||
int sqlite3NotPureFunc(sqlite3_context*);
|
||||
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
||||
int sqlite3VdbeBytecodeVtabInit(sqlite3*);
|
||||
|
||||
+36
-10
@@ -4060,6 +4060,23 @@ static void serialGet(
|
||||
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
|
||||
}
|
||||
}
|
||||
static int serialGet7(
|
||||
const unsigned char *buf, /* Buffer to deserialize from */
|
||||
Mem *pMem /* Memory cell to write value into */
|
||||
){
|
||||
u64 x = FOUR_BYTE_UINT(buf);
|
||||
u32 y = FOUR_BYTE_UINT(buf+4);
|
||||
x = (x<<32) + y;
|
||||
assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
|
||||
swapMixedEndianFloat(x);
|
||||
memcpy(&pMem->u.r, &x, sizeof(x));
|
||||
if( IsNaN(x) ){
|
||||
pMem->flags = MEM_Null;
|
||||
return 1;
|
||||
}
|
||||
pMem->flags = MEM_Real;
|
||||
return 0;
|
||||
}
|
||||
void sqlite3VdbeSerialGet(
|
||||
const unsigned char *buf, /* Buffer to deserialize from */
|
||||
u32 serial_type, /* Serial type to deserialize */
|
||||
@@ -4499,17 +4516,15 @@ int sqlite3IntFloatCompare(i64 i, double r){
|
||||
return (x<r) ? -1 : (x>r);
|
||||
}else{
|
||||
i64 y;
|
||||
double s;
|
||||
if( r<-9223372036854775808.0 ) return +1;
|
||||
if( r>=9223372036854775808.0 ) return -1;
|
||||
y = (i64)r;
|
||||
if( i<y ) return -1;
|
||||
if( i>y ) return +1;
|
||||
s = (double)i;
|
||||
testcase( doubleLt(s,r) );
|
||||
testcase( doubleLt(r,s) );
|
||||
testcase( doubleEq(r,s) );
|
||||
return (s<r) ? -1 : (s>r);
|
||||
testcase( doubleLt(((double)i),r) );
|
||||
testcase( doubleLt(r,((double)i)) );
|
||||
testcase( doubleEq(r,((double)i)) );
|
||||
return (((double)i)<r) ? -1 : (((double)i)>r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4739,7 +4754,7 @@ int sqlite3VdbeRecordCompareWithSkip(
|
||||
}else if( serial_type==0 ){
|
||||
rc = -1;
|
||||
}else if( serial_type==7 ){
|
||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
||||
serialGet7(&aKey1[d1], &mem1);
|
||||
rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
|
||||
}else{
|
||||
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
|
||||
@@ -4764,14 +4779,18 @@ int sqlite3VdbeRecordCompareWithSkip(
|
||||
}else if( serial_type==0 ){
|
||||
rc = -1;
|
||||
}else{
|
||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
||||
if( serial_type==7 ){
|
||||
if( mem1.u.r<pRhs->u.r ){
|
||||
if( serialGet7(&aKey1[d1], &mem1) ){
|
||||
rc = -1; /* mem1 is a NaN */
|
||||
}else if( mem1.u.r<pRhs->u.r ){
|
||||
rc = -1;
|
||||
}else if( mem1.u.r>pRhs->u.r ){
|
||||
rc = +1;
|
||||
}else{
|
||||
assert( rc==0 );
|
||||
}
|
||||
}else{
|
||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
||||
rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
|
||||
}
|
||||
}
|
||||
@@ -4841,7 +4860,14 @@ int sqlite3VdbeRecordCompareWithSkip(
|
||||
/* RHS is null */
|
||||
else{
|
||||
serial_type = aKey1[idx1];
|
||||
rc = (serial_type!=0 && serial_type!=10);
|
||||
if( serial_type==0
|
||||
|| serial_type==10
|
||||
|| (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0)
|
||||
){
|
||||
assert( rc==0 );
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=0 ){
|
||||
|
||||
@@ -943,6 +943,13 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the iIdx'th entry of array aMem[] to contain integer value val.
|
||||
*/
|
||||
void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val){
|
||||
sqlite3VdbeMemSetInt64(&aMem[iIdx], val);
|
||||
}
|
||||
|
||||
/* A no-op destructor */
|
||||
void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
|
||||
|
||||
|
||||
+1
-1
@@ -1290,7 +1290,7 @@ static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
|
||||
sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize);
|
||||
sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte);
|
||||
sqlite3OsFetch(pFd, 0, (int)nByte, &p);
|
||||
if( NEVER(p) ) sqlite3OsUnfetch(pFd, 0, p);
|
||||
if( p ) sqlite3OsUnfetch(pFd, 0, p);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
+3
-1
@@ -611,6 +611,8 @@ static int vtabCallConstructor(
|
||||
db->pVtabCtx = &sCtx;
|
||||
pTab->nTabRef++;
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
|
||||
assert( pTab!=0 );
|
||||
assert( pTab->nTabRef>1 || rc!=SQLITE_OK );
|
||||
sqlite3DeleteTable(db, pTab);
|
||||
db->pVtabCtx = sCtx.pPrior;
|
||||
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
|
||||
@@ -633,7 +635,7 @@ static int vtabCallConstructor(
|
||||
pVTable->nRef = 1;
|
||||
if( sCtx.bDeclared==0 ){
|
||||
const char *zFormat = "vtable constructor did not declare schema: %s";
|
||||
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
|
||||
*pzErr = sqlite3MPrintf(db, zFormat, zModuleName);
|
||||
sqlite3VtabUnlock(pVTable);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
|
||||
+5
-3
@@ -2975,7 +2975,9 @@ static int whereLoopAddBtreeIndex(
|
||||
}
|
||||
if( pProbe->bUnordered || pProbe->bLowQual ){
|
||||
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
|
||||
if( pProbe->bLowQual ) opMask &= ~(WO_EQ|WO_IN|WO_IS);
|
||||
if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){
|
||||
opMask &= ~(WO_EQ|WO_IN|WO_IS);
|
||||
}
|
||||
}
|
||||
|
||||
assert( pNew->u.btree.nEq<pProbe->nColumn );
|
||||
@@ -3970,7 +3972,7 @@ static int whereLoopAddBtree(
|
||||
** unique index is used (making the index functionally non-unique)
|
||||
** then the sqlite_stat1 data becomes important for scoring the
|
||||
** plan */
|
||||
pTab->tabFlags |= TF_StatsUsed;
|
||||
pTab->tabFlags |= TF_MaybeReanalyze;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3Stat4ProbeFree(pBuilder->pRec);
|
||||
@@ -5805,7 +5807,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
|
||||
SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
|
||||
Table *pTab = pItem->pTab;
|
||||
if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
|
||||
pTab->tabFlags |= TF_StatsUsed;
|
||||
pTab->tabFlags |= TF_MaybeReanalyze;
|
||||
if( i>=1
|
||||
&& (pLoop->wsFlags & reqFlags)==reqFlags
|
||||
/* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
|
||||
|
||||
+6
-12
@@ -117,8 +117,7 @@ do_test aggnested-3.0 {
|
||||
#
|
||||
do_test aggnested-3.1 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (
|
||||
id1 INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value1 INTEGER
|
||||
@@ -150,8 +149,7 @@ do_test aggnested-3.1-rj {
|
||||
|
||||
do_test aggnested-3.2 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (
|
||||
id1 INTEGER,
|
||||
value1 INTEGER,
|
||||
@@ -178,8 +176,7 @@ do_test aggnested-3.2 {
|
||||
} {1 0}
|
||||
do_test aggnested-3.3 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1(id1, value1);
|
||||
INSERT INTO t1 VALUES(4469,2),(4469,1);
|
||||
CREATE TABLE t2 (value2);
|
||||
@@ -249,8 +246,7 @@ do_test aggnested-3.16 {
|
||||
# Problem found by dbsqlfuzz
|
||||
#
|
||||
do_execsql_test aggnested-4.1 {
|
||||
DROP TABLE IF EXISTS aa;
|
||||
DROP TABLE IF EXISTS bb;
|
||||
DROP TABLE IF EXISTS aa, bb;
|
||||
CREATE TABLE aa(x INT); INSERT INTO aa(x) VALUES(123);
|
||||
CREATE TABLE bb(y INT); INSERT INTO bb(y) VALUES(456);
|
||||
SELECT (SELECT sum(x+(SELECT y)) FROM bb) FROM aa;
|
||||
@@ -259,8 +255,7 @@ do_execsql_test aggnested-4.2 {
|
||||
SELECT (SELECT sum(x+y) FROM bb) FROM aa;
|
||||
} {579}
|
||||
do_execsql_test aggnested-4.3 {
|
||||
DROP TABLE IF EXISTS tx;
|
||||
DROP TABLE IF EXISTS ty;
|
||||
DROP TABLE IF EXISTS tx, ty;
|
||||
CREATE TABLE tx(x INT);
|
||||
INSERT INTO tx VALUES(1),(2),(3),(4),(5);
|
||||
CREATE TABLE ty(y INT);
|
||||
@@ -477,8 +472,7 @@ do_execsql_test 9.5 {
|
||||
# https://bugs.chromium.org/p/chromium/issues/detail?id=1511689
|
||||
#
|
||||
do_execsql_test 10.1 {
|
||||
DROP TABLE IF EXISTS t0;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t0, t1;
|
||||
CREATE TABLE t0(c1, c2); INSERT INTO t0 VALUES(1,2);
|
||||
CREATE TABLE t1(c3, c4); INSERT INTO t1 VALUES(3,4);
|
||||
SELECT * FROM t0 WHERE EXISTS (SELECT 1 FROM t1 GROUP BY c3 HAVING ( SELECT count(*) FROM (SELECT 1 UNION ALL SELECT sum(DISTINCT c1) ) ) ) BETWEEN 1 AND 1;
|
||||
|
||||
@@ -60,8 +60,7 @@ do_execsql_test aggorderby-4.1 {
|
||||
|
||||
|
||||
do_execsql_test aggorderby-5.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t3;
|
||||
DROP TABLE IF EXISTS t1, t3;
|
||||
CREATE TABLE t1(a TEXT); INSERT INTO t1 VALUES('aaa'),('bbb');
|
||||
CREATE TABLE t3(d TEXT); INSERT INTO t3 VALUES('/'),('-');
|
||||
SELECT (SELECT string_agg(a,d) FROM t3) FROM t1;
|
||||
|
||||
+2
-5
@@ -105,9 +105,7 @@ do_test alter3-1.99 {
|
||||
DROP TABLE t2;
|
||||
}
|
||||
execsql {
|
||||
DROP TABLE abc;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t3;
|
||||
DROP TABLE abc, t1, t3;
|
||||
}
|
||||
} {}
|
||||
|
||||
@@ -296,8 +294,7 @@ ifcapable attach {
|
||||
} {1 one 2 two}
|
||||
do_test alter3-5.99 {
|
||||
execsql {
|
||||
DROP TABLE aux.t1;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE aux.t1, main.t1;
|
||||
}
|
||||
} {}
|
||||
}
|
||||
|
||||
+1
-3
@@ -114,9 +114,7 @@ do_test alter4-1.99 {
|
||||
DROP TABLE t2;
|
||||
}
|
||||
execsql {
|
||||
DROP TABLE abc;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t3;
|
||||
DROP TABLE abc, t1, t3;
|
||||
}
|
||||
} {}
|
||||
|
||||
|
||||
+1
-2
@@ -195,8 +195,7 @@ do_test analyze-3.8 {
|
||||
CREATE INDEX t3i1 ON t3(a);
|
||||
CREATE INDEX t3i2 ON t3(a,b,c,d);
|
||||
CREATE INDEX t3i3 ON t3(d,b,c,a);
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1, t2;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
}
|
||||
} {}
|
||||
|
||||
+5
-5
@@ -216,7 +216,7 @@ do_test auth-1.21.1 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP TABLE t2}
|
||||
catchsql {DROP TABLE IF EXISTS none1, none2, t2, none3}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.21.2 {
|
||||
set ::authargs
|
||||
@@ -483,7 +483,7 @@ do_test auth-1.63 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP TABLE t2}
|
||||
catchsql {DROP TABLE IF EXISTS none1, t2, none2}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.64 {
|
||||
execsql {SELECT name FROM sqlite_master}
|
||||
@@ -726,7 +726,7 @@ do_test auth-1.101 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP VIEW v2}
|
||||
catchsql {DROP VIEW IF EXISTS none1, v2, none2}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.102 {
|
||||
set ::authargs
|
||||
@@ -1090,7 +1090,7 @@ do_test auth-1.153 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP TRIGGER r2}
|
||||
catchsql {DROP TRIGGER IF EXISTS none1, r2, none2}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.154 {
|
||||
set ::authargs
|
||||
@@ -1389,7 +1389,7 @@ do_test auth-1.205 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP INDEX i2}
|
||||
catchsql {DROP INDEX IF EXISTS none1, i2, none2}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.205a {
|
||||
set ::authargs
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ do_test 3.4 {
|
||||
proc busy_handler {n} { return 1 }
|
||||
do_test 3.5 {
|
||||
catchsql { PRAGMA optimize }
|
||||
} {0 {}}
|
||||
} {1 {database is locked}}
|
||||
|
||||
do_test 3.6 {
|
||||
execsql { COMMIT } db2
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ do_test corruptD-1.1.1 {
|
||||
hexio_write test.db [expr 1024+1] FFFF
|
||||
catchsql { PRAGMA quick_check }
|
||||
} {0 {{*** in database main ***
|
||||
Tree 2 page 2: free space corruption}}}
|
||||
Tree 2 page 2: free space corruption} {wrong # of entries in index i1}}}
|
||||
do_test corruptD-1.1.2 {
|
||||
incr_change_counter
|
||||
hexio_write test.db [expr 1024+1] [hexio_render_int32 1021]
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
# 2024-02-29
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for DROP TABLE, DROP INDEX, DROP TRIGGER, and DROP VIEW that
|
||||
# list multiple objects to be dropped.
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix drop-many
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(a);
|
||||
CREATE TABLE t2(b, c UNIQUE);
|
||||
CREATE TABLE t3(d TEXT PRIMARY KEY, e);
|
||||
CREATE INDEX t3e ON t3(e);
|
||||
ATTACH ':memory:' AS aux1;
|
||||
CREATE TABLE aux1.t4(f INT, g INT, h INT PRIMARY KEY) WITHOUT ROWID;
|
||||
CREATE INDEX aux1.t4g ON t4(g);
|
||||
CREATE INDEX t2b ON t2(b);
|
||||
CREATE VIEW v5 AS SELECT 1,2,3;
|
||||
CREATE VIEW v6 AS SELECT * FROM t3;
|
||||
CREATE VIEW aux1.v7 AS SELECT 'hello';
|
||||
CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT 'this is trigger r1'; END;
|
||||
CREATE TRIGGER r2 BEFORE DELETE ON t2 BEGIN INSERT INTO t1 VALUES(old.b); END;
|
||||
CREATE TRIGGER aux1.r3 AFTER UPDATE ON t4 BEGIN SELECT 'trigger r3'; END;
|
||||
CREATE TRIGGER aux1.r4 INSTEAD OF UPDATE ON v7 BEGIN SELECT NULL; END;
|
||||
} {}
|
||||
do_execsql_test 1.2 {
|
||||
BEGIN;
|
||||
DROP TABLE t2, t4, t3, t1;
|
||||
SELECT name FROM sqlite_schema WHERE type='table'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='table'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 1.3.1 {
|
||||
DROP TABLE t2, t4, t3, t05, t1;
|
||||
} {1 {no such table: t05}}
|
||||
do_execsql_test 1.3.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='table'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='table'
|
||||
ORDER BY name;
|
||||
} {t1 t2 t3 t4}
|
||||
do_execsql_test 1.4 {
|
||||
BEGIN;
|
||||
DROP TABLE IF EXISTS t01, t2, t02, t4, t03, t3, t04, t1, t05;
|
||||
SELECT name FROM sqlite_schema WHERE type='table'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='table'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 1.5.1 {
|
||||
DROP TABLE IF EXISTS t2, t4, t3, v7, t1;
|
||||
} {1 {use DROP VIEW to delete view v7}}
|
||||
do_execsql_test 1.5.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='table'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='table'
|
||||
ORDER BY name;
|
||||
} {t1 t2 t3 t4}
|
||||
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
BEGIN;
|
||||
DROP VIEW v5, v6, v7;
|
||||
SELECT name FROM sqlite_schema WHERE type='view'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='view'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 2.2.1 {
|
||||
DROP VIEW v5, v6, v8, v7;
|
||||
} {1 {no such view: v8}}
|
||||
do_execsql_test 2.2.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='view'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='view'
|
||||
ORDER BY name;
|
||||
} {v5 v6 v7}
|
||||
do_catchsql_test 2.3.1 {
|
||||
DROP VIEW v5, v6, t1, v7;
|
||||
} {1 {use DROP TABLE to delete table t1}}
|
||||
do_execsql_test 2.3.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='view'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='view'
|
||||
ORDER BY name;
|
||||
} {v5 v6 v7}
|
||||
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
BEGIN;
|
||||
DROP INDEX t2b, aux1.t4g, main.t3e;
|
||||
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='index'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 3.2.1 {
|
||||
DROP INDEX t2b, aux1.t4g, t1, main.t3e;
|
||||
} {1 {no such index: t1}}
|
||||
do_execsql_test 3.2.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='index'
|
||||
ORDER BY name;
|
||||
} {t2b t3e t4g}
|
||||
do_execsql_test 3.3 {
|
||||
BEGIN;
|
||||
DROP INDEX IF EXISTS aux1.none, t2b, none2, aux1.t4g, main.t3e, none3;
|
||||
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='index'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
BEGIN;
|
||||
DROP TRIGGER main.r1, r2, r3, aux1.r4;
|
||||
SELECT name FROM sqlite_schema WHERE type='trigger'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='trigger'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 4.2.1 {
|
||||
DROP TRIGGER main.r1, r2, r3, main.t1, aux1.r4;
|
||||
} {1 {no such trigger: main.t1}}
|
||||
do_execsql_test 4.2.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='trigger'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='trigger'
|
||||
ORDER BY name;
|
||||
} {r1 r2 r3 r4}
|
||||
do_execsql_test 4.3 {
|
||||
BEGIN;
|
||||
DROP TRIGGER IF EXISTS none1, main.r1, r2, aux1.none2, r3, aux1.r4;
|
||||
SELECT name FROM sqlite_schema WHERE type='trigger'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='trigger'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
+3
-3
@@ -73,12 +73,12 @@ sqlite3 db test.db
|
||||
do_execsql_test e_reindex-1.3 {
|
||||
PRAGMA integrity_check;
|
||||
} [list \
|
||||
{wrong # of entries in index i2} \
|
||||
{wrong # of entries in index i1} \
|
||||
{row 3 missing from index i2} \
|
||||
{row 3 missing from index i1} \
|
||||
{row 4 missing from index i2} \
|
||||
{row 4 missing from index i1} \
|
||||
{wrong # of entries in index i2} \
|
||||
{wrong # of entries in index i1}
|
||||
{row 4 missing from index i1}
|
||||
]
|
||||
|
||||
do_execsql_test e_reindex-1.4 {
|
||||
|
||||
@@ -71,6 +71,17 @@ do_test fkey1-2.1 {
|
||||
DROP TABLE t10;
|
||||
}
|
||||
} {}
|
||||
do_test fkey1-2.2 {
|
||||
execsql {
|
||||
CREATE TABLE t5(x references t4);
|
||||
CREATE TABLE t6(x references t4);
|
||||
CREATE TABLE t7(x references t4);
|
||||
CREATE TABLE t8(x references t4);
|
||||
CREATE TABLE t9(x references t4);
|
||||
CREATE TABLE t10(x references t4);
|
||||
DROP TABLE t7, t9, t5, t8, t6, t10;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test fkey1-3.1 {
|
||||
execsql {
|
||||
|
||||
@@ -786,6 +786,11 @@ do_test func-16.1 {
|
||||
}
|
||||
} {X'616263' NULL}
|
||||
|
||||
# Test the quote function for +Inf and -Inf
|
||||
do_execsql_test func-16.2 {
|
||||
SELECT quote(4.2e+859), quote(-7.8e+904);
|
||||
} {9.0e+999 -9.0e+999}
|
||||
|
||||
# Correctly handle function error messages that include %. Ticket #1354
|
||||
#
|
||||
do_test func-17.1 {
|
||||
|
||||
+2
-2
@@ -161,8 +161,8 @@ static struct GlobalVars {
|
||||
/*
|
||||
** Include the external vt02.c and randomjson.c modules.
|
||||
*/
|
||||
extern int sqlite3_vt02_init(sqlite3*,char***,void*);
|
||||
extern int sqlite3_randomjson_init(sqlite3*,char***,void*);
|
||||
extern int sqlite3_vt02_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_randomjson_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -378,6 +378,20 @@ do_execsql_test json101-5.8 {
|
||||
WHERE jx.value<>jx.atom AND type NOT IN ('array','object');
|
||||
} {}
|
||||
|
||||
# 2024-02-16 https://sqlite.org/forum/forumpost/ecb94cd210
|
||||
# Regression in json_tree()/json_each(). The value column
|
||||
# should have the "J" subtype if the value is an array or
|
||||
# object.
|
||||
#
|
||||
do_execsql_test json101-5.10 {
|
||||
SELECT json_insert('{}','$.a',value) FROM json_tree('[1,2,3]') WHERE atom IS NULL;
|
||||
} {{{"a":[1,2,3]}}}
|
||||
# ^^^^^^^--- In double-quotes, a string literal, prior to bug fix
|
||||
|
||||
do_execsql_test json101-5.11 {
|
||||
SELECT json_insert('{}','$.a',value) FROM json_tree('"[1,2,3]"');
|
||||
} {{{"a":"[1,2,3]"}}}
|
||||
|
||||
do_execsql_test json101-6.1 {
|
||||
SELECT json_valid('{"a":55,"b":72,}');
|
||||
} {0}
|
||||
|
||||
+42
-1
@@ -37,6 +37,10 @@ proc test_literal {tn lit type val} {
|
||||
" [list $type $val]
|
||||
}
|
||||
|
||||
proc test_literal_error {tn lit unrec} {
|
||||
do_catchsql_test $tn "SELECT $lit" "1 {unrecognized token: \"$unrec\"}"
|
||||
}
|
||||
|
||||
|
||||
test_literal 1.0 45 integer 45
|
||||
test_literal 1.1 0xFF integer 255
|
||||
@@ -51,7 +55,6 @@ test_literal 1.10 -45 integer -45
|
||||
test_literal 1.11 '0xFF' text 0xFF
|
||||
test_literal 1.12 '-0xFF' text -0xFF
|
||||
test_literal 1.13 -'0xFF' integer 0
|
||||
|
||||
test_literal 1.14 -9223372036854775808 integer -9223372036854775808
|
||||
|
||||
test_literal 2.1 1e12 real 1000000000000.0
|
||||
@@ -59,4 +62,42 @@ test_literal 2.2 1.0 real 1.0
|
||||
test_literal 2.3 1e1000 real Inf
|
||||
test_literal 2.4 -1e1000 real -Inf
|
||||
|
||||
test_literal 3.1 1_000 integer 1000
|
||||
test_literal 3.2 1.1_1 real 1.11
|
||||
test_literal 3.3 1_0.1_1 real 10.11
|
||||
test_literal 3.4 1e1_000 real Inf
|
||||
test_literal 3.5 12_3_456.7_8_9 real 123456.789
|
||||
test_literal 3.6 9_223_372_036_854_775_807 integer 9223372036854775807
|
||||
test_literal 3.7 9_223_372_036_854_775_808 real 9.22337203685478e+18
|
||||
test_literal 3.8 -9_223_372_036_854_775_808 integer -9223372036854775808
|
||||
|
||||
foreach {tn lit unrec} {
|
||||
0 123a456 123a456
|
||||
1 1_ 1_
|
||||
2 1_.4 1_.4
|
||||
3 1e_4 1e_4
|
||||
4 1_e4 1_e4
|
||||
5 1.4_e4 1.4_e4
|
||||
6 1.4e+_4 1.4e
|
||||
7 1.4e-_4 1.4e
|
||||
8 1.4e4_ 1.4e4_
|
||||
9 1.4_e4 1.4_e4
|
||||
10 1.4e_4 1.4e_4
|
||||
11 12__34 12__34
|
||||
12 1234_ 1234_
|
||||
13 12._34 12._34
|
||||
14 12_.34 12_.34
|
||||
15 12.34_ 12.34_
|
||||
16 1.0e1_______2 1.0e1_______2
|
||||
} {
|
||||
test_literal_error 4.$tn $lit $unrec
|
||||
}
|
||||
|
||||
# dbsqlfuzz e3186a9e7826e9cd7f4085aa4452f8696485f9e1
|
||||
# See tag-20240224-a and -b
|
||||
#
|
||||
do_catchsql_test 5.1 {
|
||||
SELECT 1 ORDER BY 2_3;
|
||||
} {1 {1st ORDER BY term out of range - should be between 1 and 1}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# 2018 May 19
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname $argv0] pg_common.tcl]
|
||||
|
||||
#=========================================================================
|
||||
|
||||
|
||||
start_test literal2 "2024 Jan 23"
|
||||
|
||||
execsql_test 1.0 { SELECT 123_456 }
|
||||
errorsql_test 1.1 { SELECT 123__456 }
|
||||
|
||||
execsql_float_test 2.1 { SELECT 1.0e1_2 }
|
||||
|
||||
|
||||
execsql_test 3.0.0 { SELECT 0xFF_FF }
|
||||
execsql_test 3.0.1 { SELECT 0xFF_EF }
|
||||
errorsql_test 3.0.2 { SELECT 0xFF__EF }
|
||||
# errorsql_test 3.0.3 { SELECT 0x_FFEF }
|
||||
errorsql_test 3.0.4 { SELECT 0xFFEF_ }
|
||||
|
||||
execsql_test 3.1.0 { SELECT 0XFF_FF }
|
||||
execsql_test 3.1.1 { SELECT 0XFF_EF }
|
||||
errorsql_test 3.1.2 { SELECT 0XFF__EF }
|
||||
# errorsql_test 3.1.3 { SELECT 0X_FFEF }
|
||||
errorsql_test 3.1.4 { SELECT 0XFFEF_ }
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# 2024 Jan 23
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
####################################################
|
||||
# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
|
||||
####################################################
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix literal2
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
SELECT 123_456
|
||||
} {123456}
|
||||
|
||||
# PG says ERROR: trailing junk after numeric literal at or near "123_"
|
||||
do_test 1.1 { catch { execsql {
|
||||
SELECT 123__456
|
||||
} } } 1
|
||||
|
||||
|
||||
do_test 2.1 {
|
||||
set myres {}
|
||||
foreach r [db eval {SELECT 1.0e1_2}] {
|
||||
lappend myres [format %.4f [set r]]
|
||||
}
|
||||
set res2 {1000000000000.0000}
|
||||
set i 0
|
||||
foreach r [set myres] r2 [set res2] {
|
||||
if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} {
|
||||
error "list element [set i] does not match: got=[set r] expected=[set r2]"
|
||||
}
|
||||
incr i
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
|
||||
do_execsql_test 3.0.0 {
|
||||
SELECT 0xFF_FF
|
||||
} {65535}
|
||||
|
||||
do_execsql_test 3.0.1 {
|
||||
SELECT 0xFF_EF
|
||||
} {65519}
|
||||
|
||||
# PG says ERROR: trailing junk after numeric literal at or near "0xFF_"
|
||||
do_test 3.0.2 { catch { execsql {
|
||||
SELECT 0xFF__EF
|
||||
} } } 1
|
||||
|
||||
# PG says ERROR: trailing junk after numeric literal at or near "0xFFEF_"
|
||||
do_test 3.0.4 { catch { execsql {
|
||||
SELECT 0xFFEF_
|
||||
} } } 1
|
||||
|
||||
do_execsql_test 3.1.0 {
|
||||
SELECT 0XFF_FF
|
||||
} {65535}
|
||||
|
||||
do_execsql_test 3.1.1 {
|
||||
SELECT 0XFF_EF
|
||||
} {65519}
|
||||
|
||||
# PG says ERROR: trailing junk after numeric literal at or near "0XFF_"
|
||||
do_test 3.1.2 { catch { execsql {
|
||||
SELECT 0XFF__EF
|
||||
} } } 1
|
||||
|
||||
# PG says ERROR: trailing junk after numeric literal at or near "0XFFEF_"
|
||||
do_test 3.1.4 { catch { execsql {
|
||||
SELECT 0XFFEF_
|
||||
} } } 1
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -654,7 +654,7 @@ do_catchsql_test misc1-21.1 {
|
||||
} {1 {near "#0": syntax error}}
|
||||
do_catchsql_test misc1-21.2 {
|
||||
VALUES(0,0x0MATCH#0;
|
||||
} {1 {near ";": syntax error}}
|
||||
} {1 {unrecognized token: "0x0MATCH"}}
|
||||
|
||||
# 2015-04-15
|
||||
do_execsql_test misc1-22.1 {
|
||||
|
||||
@@ -95,6 +95,7 @@ foreach f [glob -nocomplain \
|
||||
$testdir/../ext/lsm1/test/*.test \
|
||||
$testdir/../ext/recover/*.test \
|
||||
$testdir/../ext/rbu/*.test \
|
||||
$testdir/../ext/intck/*.test \
|
||||
] {
|
||||
lappend alltests $f
|
||||
}
|
||||
|
||||
+31
-16
@@ -372,27 +372,27 @@ ifcapable attach {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql {PRAGMA integrity_check}
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
do_test pragma-3.3 {
|
||||
execsql {PRAGMA integrity_check=1}
|
||||
} {{row 1 missing from index i2}}
|
||||
} {{wrong # of entries in index i2}}
|
||||
do_test pragma-3.4 {
|
||||
execsql {
|
||||
ATTACH DATABASE 'test.db' AS t2;
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
do_test pragma-3.5 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=4
|
||||
}
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}}
|
||||
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
do_catchsql_test pragma-3.6 {
|
||||
PRAGMA integrity_check=xyz
|
||||
} {1 {no such table: xyz}}
|
||||
do_catchsql_test pragma-3.6b {
|
||||
PRAGMA integrity_check=t2
|
||||
} {0 {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}}
|
||||
} {0 {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}}
|
||||
do_catchsql_test pragma-3.6c {
|
||||
PRAGMA integrity_check=sqlite_schema
|
||||
} {0 ok}
|
||||
@@ -400,7 +400,7 @@ ifcapable attach {
|
||||
execsql {
|
||||
PRAGMA integrity_check=0
|
||||
}
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
|
||||
# Add additional corruption by appending unused pages to the end of
|
||||
# the database file testerr.db
|
||||
@@ -435,10 +435,10 @@ ifcapable attach {
|
||||
} {{*** in database t2 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
do_execsql_test pragma-3.9b {
|
||||
PRAGMA t2.integrity_check=t2;
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
do_execsql_test pragma-3.9c {
|
||||
PRAGMA t2.integrity_check=sqlite_schema;
|
||||
} {ok}
|
||||
@@ -455,7 +455,7 @@ Page 4: never used}}
|
||||
} {{*** in database t2 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2}}
|
||||
do_test pragma-3.12 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=4
|
||||
@@ -463,7 +463,7 @@ Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
} {{*** in database t2 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2}}
|
||||
Page 6: never used} {wrong # of entries in index i2}}
|
||||
do_test pragma-3.13 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=3
|
||||
@@ -487,10 +487,10 @@ Page 5: never used}}
|
||||
} {{*** in database t2 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
do_test pragma-3.16 {
|
||||
execsql {
|
||||
PRAGMA integrity_check(10)
|
||||
@@ -498,10 +498,10 @@ Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}
|
||||
} {{*** in database t2 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2}}
|
||||
Page 6: never used} {wrong # of entries in index i2}}
|
||||
do_test pragma-3.17 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=8
|
||||
@@ -509,7 +509,7 @@ Page 6: never used} {row 1 missing from index i2}}
|
||||
} {{*** in database t2 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
|
||||
Page 4: never used
|
||||
Page 5: never used}}
|
||||
do_test pragma-3.18 {
|
||||
@@ -519,7 +519,7 @@ Page 5: never used}}
|
||||
} {{*** in database t2 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2}}
|
||||
Page 6: never used} {wrong # of entries in index i2}}
|
||||
}
|
||||
do_test pragma-3.19 {
|
||||
catch {db close}
|
||||
@@ -556,6 +556,21 @@ ifcapable altertable {
|
||||
do_execsql_test pragma-3.23 {
|
||||
PRAGMA integrity_check(1);
|
||||
} {{non-unique entry in index t1a}}
|
||||
|
||||
# forum post https://sqlite.org/forum/forumpost/ee4f6fa5ab
|
||||
do_execsql_test pragma-3.24 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES (1);
|
||||
ALTER TABLE t1 ADD COLUMN b NOT NULL DEFAULT 0.25;
|
||||
SELECT * FROM t1;
|
||||
PRAGMA integrity_check(t1);
|
||||
} {1 0.25 ok}
|
||||
do_execsql_test pragma-3.25 {
|
||||
ALTER TABLE t1 ADD COLUMN c CHECK (1);
|
||||
SELECT * FROM t1;
|
||||
PRAGMA integrity_check(t1);
|
||||
} {1 0.25 {} ok}
|
||||
}
|
||||
|
||||
# PRAGMA integrity check (or more specifically the sqlite3BtreeCount()
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ do_test pragma4-2.100 {
|
||||
}
|
||||
string map {\[ x \] x \173 {} \175 {}} \
|
||||
[db eval {EXPLAIN PRAGMA integrity_check}]
|
||||
} {/ IntegrityCk 2 2 1 x[0-9]+,1x /}
|
||||
} {/ IntegrityCk 1 2 8 x[0-9]+,1x /}
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# 2024 February 27
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements tests for PRAGMAs quick_check and integrity_check.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix pragma6
|
||||
|
||||
database_may_be_corrupt
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_test 1.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 12288 pagesize 4096 filename crash-540f4c1eb1e7ac.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 03 .....@ ........
|
||||
| 32: 00 bb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 02 0f 7f 00 0f c3 0f 7f ................
|
||||
| 3952: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B
|
||||
| 3968: 02 06 17 11 11 01 71 74 61 62 6c 65 74 32 74 32 ......qtablet2t2
|
||||
| 3984: 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32 .CREATE TABLE t2
|
||||
| 4000: 28 61 20 49 4e 54 2c 20 62 20 41 53 20 28 61 2a (a INT, b AS (a*
|
||||
| 4016: 32 29 20 53 54 4f 52 45 44 20 4e 4f 54 20 4e 55 2) STORED NOT NU
|
||||
| 4032: 4c 4c 29 3b 01 06 17 11 11 01 63 74 61 62 6c 65 LL);......ctable
|
||||
| 4048: 74 31 74 31 02 43 52 45 41 54 45 20 54 41 42 4c t1t1.CREATE TABL
|
||||
| 4064: 45 20 74 31 28 61 20 49 4e 54 2c 20 62 20 41 53 E t1(a INT, b AS
|
||||
| 4080: 20 28 61 2a 32 29 20 4e 4f 54 20 4e 55 4c 4c 29 (a*2) NOT NULL)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 00 00 00 05 0f e7 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 00 00 00 00 00 00 03 05 02 01 05 03 04 02 ................
|
||||
| 4080: 01 04 03 03 02 01 03 03 02 02 01 02 02 01 02 09 ................
|
||||
| page 3 offset 8192
|
||||
| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 05 ................
|
||||
| 4064: 03 01 01 05 0a 05 04 03 01 01 04 08 05 03 03 01 ................
|
||||
| 4080: 01 03 06 05 02 03 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| end crash-540f4c1eb1e7ac.db
|
||||
}]
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TEMP TABLE t2(
|
||||
a t1 PRIMARY KEY default 27,
|
||||
b default(current_timestamp),
|
||||
d TEXT UNIQUE DEFAULT 'ch`arlie',
|
||||
c TEXT UNIQUE DEFAULT 084,
|
||||
UNIQUE(c,b,b,a,b)
|
||||
) WITHOUT ROWID;
|
||||
INSERT INTO t1(a) VALUES(zeroblob(40000));
|
||||
}
|
||||
|
||||
do_test 1.2 {
|
||||
execsql { PRAGMA integrity_check; }
|
||||
execsql { PRAGMA quick_check; }
|
||||
set {} {}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
@@ -3833,4 +3833,21 @@ do_execsql_test printf-18.1 {
|
||||
SELECT length( format('%,.249f', -5.0e-300) );
|
||||
} {252}
|
||||
|
||||
# 2024-02-16
|
||||
# https://sqlite.org/forum/info/393708f4a8
|
||||
#
|
||||
# The problem introduced by on 2023-07-03 by
|
||||
# https://sqlite.org/src/info/32befb224b254639
|
||||
#
|
||||
do_execsql_test printf-19.1 {
|
||||
SELECT format('%0.0f %0.0g %0.0g', 0.9, 0.09, 1.9);
|
||||
} {{1 0.09 2}}
|
||||
do_execsql_test printf-19.2 {
|
||||
SELECT format('%0.0f %#0.0f',0.0, 0.0);
|
||||
} {{0 0.}}
|
||||
do_execsql_test printf-19.3 {
|
||||
SELECT format('%,.0f %,.0f',12345e+10, 12345e+11);
|
||||
} {{123,450,000,000,000 1,234,500,000,000,000}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -2150,6 +2150,50 @@ void testset_debug1(void){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This testset focuses on the speed of parsing numeric literals (integers
|
||||
** and real numbers). This was added to test the impact of allowing "_"
|
||||
** characters to appear in numeric SQL literals to make them easier to read.
|
||||
** For example, "SELECT 1_000_000;" instead of "SELECT 1000000;".
|
||||
*/
|
||||
void testset_parsenumber(void){
|
||||
const char *zSql1 = "SELECT 1, 12, 123, 1234, 12345, 123456";
|
||||
const char *zSql2 = "SELECT 8227256643844975616, 7932208612563860480, "
|
||||
"2010730661871032832, 9138463067404021760, "
|
||||
"2557616153664746496, 2557616153664746496";
|
||||
const char *zSql3 = "SELECT 1.0, 1.2, 1.23, 123.4, 1.2345, 1.23456";
|
||||
const char *zSql4 = "SELECT 8.227256643844975616, 7.932208612563860480, "
|
||||
"2.010730661871032832, 9.138463067404021760, "
|
||||
"2.557616153664746496, 2.557616153664746496";
|
||||
|
||||
const int NROW = 100*g.szTest;
|
||||
int ii;
|
||||
|
||||
speedtest1_begin_test(100, "parsing small integers");
|
||||
for(ii=0; ii<NROW; ii++){
|
||||
sqlite3_exec(g.db, zSql1, 0, 0, 0);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(110, "parsing large integers");
|
||||
for(ii=0; ii<NROW; ii++){
|
||||
sqlite3_exec(g.db, zSql2, 0, 0, 0);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(200, "parsing small reals");
|
||||
for(ii=0; ii<NROW; ii++){
|
||||
sqlite3_exec(g.db, zSql3, 0, 0, 0);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(210, "parsing large reals");
|
||||
for(ii=0; ii<NROW; ii++){
|
||||
sqlite3_exec(g.db, zSql4, 0, 0, 0);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@@ -2557,6 +2601,8 @@ int main(int argc, char **argv){
|
||||
testset_fp();
|
||||
}else if( strcmp(zThisTest,"trigger")==0 ){
|
||||
testset_trigger();
|
||||
}else if( strcmp(zThisTest,"parsenumber")==0 ){
|
||||
testset_parsenumber();
|
||||
}else if( strcmp(zThisTest,"rtree")==0 ){
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
testset_rtree(6, 147);
|
||||
|
||||
@@ -707,6 +707,7 @@ if {$SQLITE_MAX_EXPR_DEPTH==0} {
|
||||
}]
|
||||
} "1 {Expression tree is too large (maximum depth $::SQLITE_MAX_EXPR_DEPTH)}"
|
||||
|
||||
if 0 {
|
||||
# Attempting to beat the expression depth limit using nested SELECT
|
||||
# queries causes a parser stack overflow.
|
||||
do_test sqllimits1-9.2 {
|
||||
@@ -718,7 +719,6 @@ if {$SQLITE_MAX_EXPR_DEPTH==0} {
|
||||
catchsql [subst { $expr }]
|
||||
} "1 {parser stack overflow}"
|
||||
|
||||
if 0 {
|
||||
do_test sqllimits1-9.3 {
|
||||
execsql {
|
||||
PRAGMA max_page_count = 1000000; -- 1 GB
|
||||
|
||||
+24
-3
@@ -17,7 +17,7 @@
|
||||
# After the "tsrc" directory has been created and populated, run
|
||||
# this script:
|
||||
#
|
||||
# tclsh mksqlite3c.tcl
|
||||
# tclsh mksqlite3c.tcl [flags] [extra source files]
|
||||
#
|
||||
# The amalgamated SQLite code will be written into sqlite3.c
|
||||
#
|
||||
@@ -42,6 +42,7 @@ set linemacros 0
|
||||
set useapicall 0
|
||||
set enable_recover 0
|
||||
set srcdir tsrc
|
||||
set extrasrc [list]
|
||||
|
||||
for {set i 0} {$i<[llength $argv]} {incr i} {
|
||||
set x [lindex $argv $i]
|
||||
@@ -63,8 +64,10 @@ for {set i 0} {$i<[llength $argv]} {incr i} {
|
||||
} elseif {[regexp {^-?-((help)|\?)$} $x]} {
|
||||
puts $help
|
||||
exit 0
|
||||
} else {
|
||||
} elseif {[regexp {^-?-} $x]} {
|
||||
error "unknown command-line option: $x"
|
||||
} else {
|
||||
lappend extrasrc $x
|
||||
}
|
||||
}
|
||||
set in [open $srcdir/sqlite3.h]
|
||||
@@ -349,6 +352,21 @@ proc copy_file {filename} {
|
||||
section_comment "End of $tail"
|
||||
}
|
||||
|
||||
# Read the source file named $filename and write it into the
|
||||
# sqlite3.c output file. The only transformation is the trimming
|
||||
# of EOL whitespace.
|
||||
#
|
||||
proc copy_file_verbatim {filename} {
|
||||
global out
|
||||
set in [open $filename r]
|
||||
set tail [file tail $filename]
|
||||
section_comment "Begin EXTRA_SRC file $tail"
|
||||
while {![eof $in]} {
|
||||
set line [string trimright [gets $in]]
|
||||
puts $out $line
|
||||
}
|
||||
section_comment "End of EXTRA_SRC $tail"
|
||||
}
|
||||
|
||||
# Process the source files. Process files containing commonly
|
||||
# used subroutines first in order to help the compiler find
|
||||
@@ -470,13 +488,16 @@ set flist {
|
||||
sqlite3session.c
|
||||
fts5.c
|
||||
stmt.c
|
||||
}
|
||||
}
|
||||
if {$enable_recover} {
|
||||
lappend flist sqlite3recover.c dbdata.c
|
||||
}
|
||||
foreach file $flist {
|
||||
copy_file $srcdir/$file
|
||||
}
|
||||
foreach file $extrasrc {
|
||||
copy_file_verbatim $file
|
||||
}
|
||||
|
||||
puts $out \
|
||||
"/* Return the source-id for this library */
|
||||
|
||||
@@ -161,6 +161,9 @@ while test "$1" != ""; do
|
||||
--fp)
|
||||
SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset fp"
|
||||
;;
|
||||
--parsenumber)
|
||||
SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset parsenumber"
|
||||
;;
|
||||
--stmtscanstatus)
|
||||
SPEEDTEST_OPTS="$SPEEDTEST_OPTS --stmtscanstatus"
|
||||
;;
|
||||
|
||||
Reference in New Issue
Block a user