Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0cb576f306 | |||
| 6d27844bbe | |||
| 03f13d77a5 | |||
| 445fbc61c8 | |||
| eb0cb3f53b | |||
| 5239e69fb1 | |||
| 20d93e16d7 | |||
| c409eaaf14 | |||
| 2e01416762 | |||
| ff8a0895d6 | |||
| a2f78f665c | |||
| c4cedd7ffe | |||
| 00c6eca32c | |||
| be2242d2ee | |||
| 2dd3b4a646 | |||
| 4570aeb7bc | |||
| 1283969f26 | |||
| 772ea2f01c | |||
| d4af925e34 | |||
| 61d3bc8ddc | |||
| f9a3b78561 | |||
| f855727e45 | |||
| 3d58f022a8 | |||
| 7e9eaf3c1f | |||
| 0944b3efad | |||
| f3f194c385 | |||
| 183a73c352 | |||
| 53197b7940 | |||
| f1f1784f4b | |||
| 814f592cf0 | |||
| 9b805c6248 | |||
| 3c2ccd2903 | |||
| 7bf4d708dc | |||
| 5239e821e8 | |||
| a217a4af09 | |||
| 3e3c31ff0e | |||
| dc32016ee0 | |||
| 5700f8c471 | |||
| 80b88b2482 | |||
| 8e7f122c7d | |||
| dfd31e158c | |||
| cc19c1dafd | |||
| 99571bf3c3 | |||
| 3c1f727603 | |||
| d9e70f2b90 | |||
| 4c78799bb0 | |||
| 958b6a52e5 | |||
| f62cff6a9e | |||
| f163bfba4e | |||
| b0a4b69b95 | |||
| bd580270a5 | |||
| de4ef2dc70 | |||
| 0cb7603d4c | |||
| 28cfb1e4a7 | |||
| 915a55444b | |||
| 58012b85b0 | |||
| a2d80200b1 | |||
| 08eb5e9e51 | |||
| b425ebdd4f | |||
| ac53ce155a | |||
| 5a6772eaa5 | |||
| acc213b42f | |||
| 345bc91673 | |||
| 1539575e05 | |||
| f0648f6924 | |||
| 15a3b2d4e1 | |||
| 765ff2189a | |||
| 3ca448dee5 | |||
| 3f2d7d4aaa | |||
| 00989bcd9f | |||
| 362b9cecdb | |||
| f4e6483cda | |||
| ae2820ab28 | |||
| bdbad43f33 | |||
| d6965b1dab | |||
| ccf2babd42 | |||
| 2953e950c8 | |||
| 8736da94bc | |||
| b302c4d39c | |||
| 022f2f96bc | |||
| 5a73386511 | |||
| 1c1f7c259e | |||
| cf93c51790 | |||
| 4cc023bd01 | |||
| f6308e68ff | |||
| 066a5bcdd7 | |||
| b2006499c7 | |||
| bf057073c3 | |||
| d21413adcb | |||
| 061459bf76 |
@@ -2627,6 +2627,12 @@ smoketest: $(TESTPROGS)
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
|
||||
|
||||
# Measure the performance of floating-point conversions.
|
||||
#
|
||||
fp-speed-test: fp-speed-1.exe fp-speed-2.exe
|
||||
fp-speed-1 1000000
|
||||
fp-speed-2 1000000
|
||||
|
||||
shelltest:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl release shell
|
||||
|
||||
@@ -2719,6 +2725,14 @@ speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\speedtest1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fp-speed-1.exe: $(TOP)\test\fp-speed-1.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\fp-speed-1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fp-speed-2.exe: $(TOP)\test\fp-speed-2.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\fp-speed-2.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
kvtest.exe: $(TOP)\test\kvtest.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(KV_COMPILE_OPTS) \
|
||||
$(TOP)\test\kvtest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
@@ -2908,6 +2922,7 @@ clean:
|
||||
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL
|
||||
del /Q changeset.exe 2>NUL
|
||||
del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
|
||||
del /Q fp-speed-1.exe fp-speed-2.exe 2>NUL
|
||||
del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
|
||||
del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL
|
||||
del /Q sqlite3rc.h 2>NUL
|
||||
|
||||
+45
-20
@@ -517,7 +517,7 @@ static void fts5SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
|
||||
if( sqlite3_libversion_number()>=3008002 )
|
||||
#endif
|
||||
{
|
||||
pIdxInfo->estimatedRows = nRow;
|
||||
pIdxInfo->estimatedRows = MAX(1, nRow);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -586,19 +586,30 @@ static int fts5UsePatternMatch(
|
||||
** a) If a MATCH operator is present, the cost depends on the other
|
||||
** constraints also present. As follows:
|
||||
**
|
||||
** * No other constraints: cost=1000.0
|
||||
** * One rowid range constraint: cost=750.0
|
||||
** * Both rowid range constraints: cost=500.0
|
||||
** * An == rowid constraint: cost=100.0
|
||||
** * No other constraints: cost=50000.0
|
||||
** * One rowid range constraint: cost=37500.0
|
||||
** * Both rowid range constraints: cost=30000.0
|
||||
** * An == rowid constraint: cost=25000.0
|
||||
**
|
||||
** b) Otherwise, if there is no MATCH:
|
||||
**
|
||||
** * No other constraints: cost=1000000.0
|
||||
** * One rowid range constraint: cost=750000.0
|
||||
** * Both rowid range constraints: cost=250000.0
|
||||
** * An == rowid constraint: cost=10.0
|
||||
** * No other constraints: cost=3000000.0
|
||||
** * One rowid range constraints: cost=2250000.0
|
||||
** * Both rowid range constraint: cost=750000.0
|
||||
** * An == rowid constraint: cost=25.0
|
||||
**
|
||||
** Costs are not modified by the ORDER BY clause.
|
||||
**
|
||||
** The ratios used in case (a) are based on informal results obtained from
|
||||
** the tool/fts5cost.tcl script. The "MATCH and ==" combination has the
|
||||
** cost set quite high because the query may be a prefix query. Unless
|
||||
** there is a prefix index, prefix queries with rowid constraints are much
|
||||
** more expensive than non-prefix queries with rowid constraints.
|
||||
**
|
||||
** The estimated rows returned is set to the cost/40. For simple queries,
|
||||
** experimental results show that cost/4 might be about right. But for
|
||||
** more complex queries that use multiple terms the number of rows might
|
||||
** be far fewer than this. So we compromise and use cost/40.
|
||||
*/
|
||||
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
Fts5Table *pTab = (Fts5Table*)pVTab;
|
||||
@@ -724,21 +735,35 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
|
||||
/* Calculate the estimated cost based on the flags set in idxFlags. */
|
||||
if( bSeenEq ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 1000.0 : 25.0;
|
||||
fts5SetUniqueFlag(pInfo);
|
||||
pInfo->estimatedCost = nSeenMatch ? 25000.0 : 25.0;
|
||||
fts5SetEstimatedRows(pInfo, 1);
|
||||
fts5SetUniqueFlag(pInfo);
|
||||
}else{
|
||||
if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 5000.0 : 750000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 7500.0 : 2250000.0;
|
||||
i64 nEstRows;
|
||||
if( nSeenMatch ){
|
||||
if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = 50000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = 37500.0;
|
||||
}else{
|
||||
pInfo->estimatedCost = 50000.0;
|
||||
}
|
||||
nEstRows = (i64)(pInfo->estimatedCost / 40.0);
|
||||
for(i=1; i<nSeenMatch; i++){
|
||||
pInfo->estimatedCost *= 2.5;
|
||||
nEstRows = nEstRows / 2;
|
||||
}
|
||||
}else{
|
||||
pInfo->estimatedCost = nSeenMatch ? 10000.0 : 3000000.0;
|
||||
if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = 750000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = 2250000.0;
|
||||
}else{
|
||||
pInfo->estimatedCost = 3000000.0;
|
||||
}
|
||||
nEstRows = (i64)(pInfo->estimatedCost / 4.0);
|
||||
}
|
||||
for(i=1; i<nSeenMatch; i++){
|
||||
pInfo->estimatedCost *= 0.4;
|
||||
}
|
||||
fts5SetEstimatedRows(pInfo, (i64)(pInfo->estimatedCost / 4.0));
|
||||
fts5SetEstimatedRows(pInfo, nEstRows);
|
||||
}
|
||||
|
||||
pInfo->idxNum = idxFlags;
|
||||
|
||||
@@ -65,5 +65,14 @@ do_eqp_test 1.4 {
|
||||
`--SCAN vt VIRTUAL TABLE INDEX 0:=
|
||||
}
|
||||
|
||||
do_eqp_test 1.5 {
|
||||
SELECT * FROM vt, t1
|
||||
WHERE vt.rowid = t1.rowid AND vt MATCH ? AND b = ?
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN vt VIRTUAL TABLE INDEX 0:M1
|
||||
`--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
#
|
||||
# 2026 March 20
|
||||
#
|
||||
# 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 script extracts the documentation for the API used by fts5 auxiliary
|
||||
# functions from header file fts5.h. It outputs html text on stdout that
|
||||
# is included in the documentation on the web.
|
||||
#
|
||||
|
||||
|
||||
sqlite3 db fts5cost.db
|
||||
|
||||
# Create an IPK table with 1,000,000 entries. Short records.
|
||||
#
|
||||
set res [list [catch { db eval {SELECT count(*) FROM t1} } msg] $msg]
|
||||
if {$res!="0 1000000"} {
|
||||
db eval {
|
||||
PRAGMA mmap_size = 1000000000; -- 1GB
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
|
||||
)
|
||||
INSERT INTO t1 SELECT i, hex(randomblob(8)) FROM s;
|
||||
}
|
||||
}
|
||||
|
||||
# Create an FTS5 table with 1,000,000 entries. Each row contains a single
|
||||
# column containing a document of 100 terms chosen pseudo-randomly from
|
||||
# a vocabularly of 2000.
|
||||
set res [list [catch { db eval {SELECT count(*) FROM f1} } msg] $msg]
|
||||
if {$res!="0 1000000"} {
|
||||
set nVocab 2000
|
||||
set nTerm 100
|
||||
db eval {
|
||||
BEGIN;
|
||||
DROP TABLE IF EXISTS vocab1;
|
||||
CREATE TABLE vocab1(w);
|
||||
}
|
||||
for {set ii 0} {$ii<$nVocab} {incr ii} {
|
||||
set word [format %06x [expr {int(abs(rand()) * 0xFFFFFF)}]]
|
||||
db eval { INSERT INTO vocab1 VALUES($word) }
|
||||
lappend lVocab $word
|
||||
}
|
||||
db func doc doc
|
||||
proc doc {} {
|
||||
for {set ii 0} {$ii<$::nTerm} {incr ii} {
|
||||
lappend ret [lindex $::lVocab [expr int(abs(rand())*$::nVocab)]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS f1;
|
||||
CREATE VIRTUAL TABLE f1 USING fts5(x);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
|
||||
)
|
||||
INSERT INTO f1(rowid, x) SELECT i, doc() FROM s;
|
||||
COMMIT;
|
||||
}
|
||||
} else {
|
||||
set lVocab [db eval { SELECT * FROM vocab1 }]
|
||||
set nVocab [llength $lVocab]
|
||||
}
|
||||
|
||||
proc rowid_query {n} {
|
||||
set rowid 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
db eval { SELECT b FROM t1 WHERE a = $rowid }
|
||||
set rowid [expr {($rowid + 7717) % 1000000}]
|
||||
}
|
||||
}
|
||||
|
||||
proc rowid_query_fts {n} {
|
||||
set rowid 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
db eval { SELECT * FROM f1 WHERE rowid = $rowid }
|
||||
set rowid [expr {($rowid + 7717) % 1000000}]
|
||||
}
|
||||
}
|
||||
|
||||
proc match_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match [lrange $::lVocab $idx $idx+1]
|
||||
db eval { SELECT * FROM f1($match) }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc prefix_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]*"
|
||||
db eval { SELECT * FROM f1($match) }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc match_rowid_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]"
|
||||
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc prefix_rowid_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]*"
|
||||
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
proc mytime {cmd div} {
|
||||
set tm [time $cmd]
|
||||
expr {[lindex $tm 0] / $div}
|
||||
}
|
||||
|
||||
#set us [mytime { match_rowid_query_fts 1000 } 1000]
|
||||
#puts "1000 match/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
|
||||
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { match_query_fts 10 } 10]
|
||||
puts "10 match queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_query_fts 10 } 10]
|
||||
puts "10 prefix queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
|
||||
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { rowid_query 10000 } 10000]
|
||||
puts "10000 by-rowid queries on normal table: ${us} per query"
|
||||
|
||||
set us [mytime { rowid_query_fts 10000 } 10000]
|
||||
puts "10000 by-rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
|
||||
+7
-6
@@ -64,6 +64,7 @@ SQLITE_EXTENSION_INIT1
|
||||
|
||||
#ifndef SQLITEINT_H
|
||||
typedef sqlite3_int64 i64;
|
||||
typedef sqlite3_uint64 u64;
|
||||
#endif
|
||||
|
||||
/* Max size of the error message in a CsvReader */
|
||||
@@ -221,7 +222,7 @@ static char *csv_read_one_field(CsvReader *p){
|
||||
}
|
||||
if( c=='"' ){
|
||||
int pc, ppc;
|
||||
int startLine = p->nLine;
|
||||
i64 startLine = p->nLine;
|
||||
pc = ppc = 0;
|
||||
while( 1 ){
|
||||
c = csv_getc(p);
|
||||
@@ -325,7 +326,7 @@ typedef struct CsvCursor {
|
||||
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
||||
CsvReader rdr; /* The CsvReader object */
|
||||
char **azVal; /* Value of the current row */
|
||||
int *aLen; /* Length of each entry */
|
||||
i64 *aLen; /* Length of each entry */
|
||||
sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */
|
||||
} CsvCursor;
|
||||
|
||||
@@ -497,7 +498,7 @@ static int csvtabConnect(
|
||||
CsvTable *pNew = 0; /* The CsvTable object to construct */
|
||||
int bHeader = -1; /* header= flags. -1 means not seen yet */
|
||||
int rc = SQLITE_OK; /* Result code from this routine */
|
||||
int i, j; /* Loop counters */
|
||||
u64 i, j; /* Loop counters */
|
||||
#ifdef SQLITE_TEST
|
||||
int tstFlags = 0; /* Value for testflags=N parameter */
|
||||
#endif
|
||||
@@ -516,7 +517,7 @@ static int csvtabConnect(
|
||||
assert( sizeof(azPValue)==sizeof(azParam) );
|
||||
memset(&sRdr, 0, sizeof(sRdr));
|
||||
memset(azPValue, 0, sizeof(azPValue));
|
||||
for(i=3; i<argc; i++){
|
||||
for(i=3; i<(u64)argc; i++){
|
||||
const char *z = argv[i];
|
||||
const char *zValue;
|
||||
for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){
|
||||
@@ -709,12 +710,12 @@ static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
CsvTable *pTab = (CsvTable*)p;
|
||||
CsvCursor *pCur;
|
||||
size_t nByte;
|
||||
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol;
|
||||
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(i64))*pTab->nCol;
|
||||
pCur = sqlite3_malloc64( nByte );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, nByte);
|
||||
pCur->azVal = (char**)&pCur[1];
|
||||
pCur->aLen = (int*)&pCur->azVal[pTab->nCol];
|
||||
pCur->aLen = (i64*)&pCur->azVal[pTab->nCol];
|
||||
*ppCursor = &pCur->base;
|
||||
if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){
|
||||
csv_xfer_error(pTab, &pCur->rdr);
|
||||
|
||||
+1
-1
@@ -828,7 +828,6 @@ static void re_bytecode_func(
|
||||
int i;
|
||||
int n;
|
||||
char *z;
|
||||
(void)argc;
|
||||
static const char *ReOpName[] = {
|
||||
"EOF",
|
||||
"MATCH",
|
||||
@@ -851,6 +850,7 @@ static void re_bytecode_func(
|
||||
"ATSTART",
|
||||
};
|
||||
|
||||
(void)argc;
|
||||
zPattern = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zPattern==0 ) return;
|
||||
zErr = re_compile(&pRe, zPattern, re_maxnfa(re_maxlen(context)),
|
||||
|
||||
+22
-9
@@ -115,6 +115,7 @@ struct sqlite3_qrf_spec {
|
||||
short int nScreenWidth; /* Maximum overall table width */
|
||||
short int nLineLimit; /* Maximum number of lines for any row */
|
||||
short int nTitleLimit; /* Maximum number of characters in a title */
|
||||
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
|
||||
int nCharLimit; /* Maximum number of characters in a cell */
|
||||
int nWidth; /* Number of entries in aWidth[] */
|
||||
int nAlign; /* Number of entries in aAlignment[] */
|
||||
@@ -381,7 +382,16 @@ can improve readability. The nTitleLimit setting currently only
|
||||
works for **Box**, **Column**, **Line**, **Markdown**, and **Table**
|
||||
styles, though that limitation might change in future releases.
|
||||
|
||||
### 2.9 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
|
||||
### 2.9 Multiple Tuples Per INSERT In QRF_STYLE_Insert (nMultiInsert)
|
||||
|
||||
If the sqlite3_qrf_spec.nMultiInsert value is positive, then the
|
||||
QRF_STYLE_Insert output mode will generate multiple tuples in
|
||||
each INSERT statement until the total number of bytes in the
|
||||
statement exceeds nMultiInsert. A value of a few thousand is
|
||||
recommended here, in order to generate SQL output that is parsed
|
||||
and inserted at maximum speed by SQLite.
|
||||
|
||||
### 2.10 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
|
||||
|
||||
When using columnar formatting modes (QRF_STYLE_Box, QRF_STYLE_Column,
|
||||
QRF_STYLE_Markdown, or QRF_STYLE_Table), the formatter attempts to limit
|
||||
@@ -400,7 +410,7 @@ anywhere, including in the middle of a word.
|
||||
For narrow columns and wide words, it might sometimes be necessary to split
|
||||
a column in the middle of a word, even when bWordWrap is QRF_Yes.
|
||||
|
||||
### 2.10 Helping The Output To Fit On The Terminal (nScreenWidth)
|
||||
### 2.11 Helping The Output To Fit On The Terminal (nScreenWidth)
|
||||
|
||||
The sqlite3_qrf_spec.nScreenWidth field can be set the number of
|
||||
characters that will fit on one line on the viewer output device.
|
||||
@@ -420,7 +430,7 @@ The nScreenWidth field currently only makes a difference in
|
||||
columnar styles (**Box**, **Column**, **Markdown**, and **Table**)
|
||||
and in the **Line** style.
|
||||
|
||||
### 2.11 Individual Column Width (nWidth and aWidth)
|
||||
### 2.12 Individual Column Width (nWidth and aWidth)
|
||||
|
||||
The sqlite3_qrf_spec.aWidth field is a pointer to an array of
|
||||
signed 16-bit integers that control the width of individual columns
|
||||
@@ -458,7 +468,7 @@ Again, negative values for aWidth\[\] entries are supported for
|
||||
backwards compatibility only, and are not recommended for new
|
||||
applications.
|
||||
|
||||
### 2.12 Alignment (nAlignment, aAlignment, eDfltAlign, eTitleAlign)
|
||||
### 2.13 Alignment (nAlignment, aAlignment, eDfltAlign, eTitleAlign)
|
||||
|
||||
Some cells in a display table might contain a lot of text and thus
|
||||
be wide, or they might contain newline characters or be wrapped by
|
||||
@@ -537,7 +547,7 @@ specify a vertical alignment, then values are top-aligned
|
||||
The vertical alignment settings are currently ignored and
|
||||
the vertical alignment is always QRF_ALIGN_Top.*
|
||||
|
||||
### 2.13 Row and Column Separator Strings
|
||||
### 2.14 Row and Column Separator Strings
|
||||
|
||||
The sqlite3_qrf_spec.zColumnSep and sqlite3_qrf_spec.zRowSep strings
|
||||
are alternative column and row separator character sequences. If not
|
||||
@@ -545,18 +555,18 @@ specified (if these pointers are left as NULL) then appropriate defaults
|
||||
are used. Some output styles have hard-coded column and row separators
|
||||
and these settings are ignored for those styles.
|
||||
|
||||
### 2.14 The Output Table Name
|
||||
### 2.15 The Output Table Name
|
||||
|
||||
The sqlite3_qrf_spec.zTableName value is the name of the output table
|
||||
when eStyle is QRF_STYLE_Insert.
|
||||
|
||||
### 2.15 The Rendering Of NULL (zNull)
|
||||
### 2.16 The Rendering Of NULL (zNull)
|
||||
|
||||
If a value is NULL then show the NULL using the string
|
||||
found in sqlite3_qrf_spec.zNull. If zNull is itself a NULL pointer
|
||||
then NULL values are rendered as an empty string.
|
||||
|
||||
### 2.16 Optional Value Rendering Callback
|
||||
### 2.17 Optional Value Rendering Callback
|
||||
|
||||
If the sqlite3_qrf_spec.xRender field is not NULL, then each
|
||||
sqlite3_value coming out of the query is first passed to the
|
||||
@@ -709,7 +719,10 @@ the `<TABLE>..</TABLE>` around the outside.
|
||||
The **Insert** style generates a series of SQL "INSERT" statements
|
||||
that will inserts the data that is output into a table whose name is defined
|
||||
by the zTableName field of `sqlite3_qrf_spec`. If zTableName is NULL,
|
||||
then a substitute name is used.
|
||||
then a substitute name is used. If nMultiInsert is positive, then the
|
||||
output will add multiple rows to each INSERT statement until the size
|
||||
of the INSERT statement exceeds nMultiInsert bytes before starting
|
||||
a new INSERT statement.
|
||||
|
||||
The **Json** and **JObject** styles generates JSON text for the query result.
|
||||
The **Json** style produces a JSON array of structures with one
|
||||
|
||||
+2
-2
@@ -2564,7 +2564,7 @@ static void qrfOneSimpleRow(Qrf *p){
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Insert: {
|
||||
unsigned int mxIns = p->spec.iVersion>=2 ? p->spec.nMultiInsert : 0;
|
||||
unsigned int mxIns = p->spec.nMultiInsert;
|
||||
int szStart = sqlite3_str_length(p->pOut);
|
||||
if( p->u.nIns==0 || p->u.nIns>=mxIns ){
|
||||
if( p->u.nIns ){
|
||||
@@ -2712,7 +2712,7 @@ static void qrfInitialize(
|
||||
size_t sz; /* Size of pSpec[], based on pSpec->iVersion */
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->pzErr = pzErr;
|
||||
if( pSpec->iVersion>2 ){
|
||||
if( pSpec->iVersion>1 ){
|
||||
qrfError(p, SQLITE_ERROR,
|
||||
"unusable sqlite3_qrf_spec.iVersion (%d)",
|
||||
pSpec->iVersion);
|
||||
|
||||
+1
-2
@@ -42,6 +42,7 @@ struct sqlite3_qrf_spec {
|
||||
short int nScreenWidth; /* Maximum overall table width */
|
||||
short int nLineLimit; /* Maximum number of lines for any row */
|
||||
short int nTitleLimit; /* Maximum number of characters in a title */
|
||||
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
|
||||
int nCharLimit; /* Maximum number of characters in a cell */
|
||||
int nWidth; /* Number of entries in aWidth[] */
|
||||
int nAlign; /* Number of entries in aAlignment[] */
|
||||
@@ -56,8 +57,6 @@ struct sqlite3_qrf_spec {
|
||||
void *pRenderArg; /* First argument to the xRender callback */
|
||||
void *pWriteArg; /* First argument to the xWrite callback */
|
||||
char **pzOutput; /* Storage location for output string */
|
||||
/* Fields below are only available if iVersion>=2 */
|
||||
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
|
||||
/* Additional fields may be added in the future */
|
||||
};
|
||||
|
||||
|
||||
+13
-12
@@ -1037,7 +1037,17 @@ static void rtreeRelease(Rtree *pRtree){
|
||||
pRtree->inWrTrans = 0;
|
||||
assert( pRtree->nCursor==0 );
|
||||
nodeBlobReset(pRtree);
|
||||
assert( pRtree->nNodeRef==0 || pRtree->bCorrupt );
|
||||
if( pRtree->nNodeRef ){
|
||||
int i;
|
||||
assert( pRtree->bCorrupt );
|
||||
for(i=0; i<HASHSIZE; i++){
|
||||
while( pRtree->aHash[i] ){
|
||||
RtreeNode *pNext = pRtree->aHash[i]->pNext;
|
||||
sqlite3_free(pRtree->aHash[i]);
|
||||
pRtree->aHash[i] = pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pRtree->pWriteNode);
|
||||
sqlite3_finalize(pRtree->pDeleteNode);
|
||||
sqlite3_finalize(pRtree->pReadRowid);
|
||||
@@ -2329,7 +2339,7 @@ static int AdjustTree(
|
||||
int iCell;
|
||||
|
||||
cnt++;
|
||||
if( NEVER(cnt>100) ){
|
||||
if( cnt>100 ){
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
@@ -2687,15 +2697,6 @@ static int SplitNode(
|
||||
rc = updateMapping(pRtree, pCell->iRowid, pLeft, iHeight);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = nodeRelease(pRtree, pRight);
|
||||
pRight = 0;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = nodeRelease(pRtree, pLeft);
|
||||
pLeft = 0;
|
||||
}
|
||||
|
||||
splitnode_out:
|
||||
nodeRelease(pRtree, pRight);
|
||||
nodeRelease(pRtree, pLeft);
|
||||
@@ -2880,7 +2881,7 @@ static int rtreeInsertCell(
|
||||
rc = SplitNode(pRtree, pNode, pCell, iHeight);
|
||||
}else{
|
||||
rc = AdjustTree(pRtree, pNode, pCell);
|
||||
if( ALWAYS(rc==SQLITE_OK) ){
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iHeight==0 ){
|
||||
rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
|
||||
}else{
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
Links for various testing options: <ul id='testlinks'></ul>
|
||||
</p>
|
||||
<div class='input-wrapper'>
|
||||
<input type='checkbox' id='cb-log-reverse'>
|
||||
<label for='cb-log-reverse'>Reverse log order?</label>
|
||||
<button id='gogogo'><strong>Start test</strong></button>
|
||||
<label><input type='checkbox' id='cb-log-reverse'>Reverse log order?</label>
|
||||
</div>
|
||||
<div id='test-output'></div>
|
||||
<script>(function(){
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
(async function(self){
|
||||
const btnGo = document.querySelector('#gogogo');
|
||||
|
||||
const logCss = (function(){
|
||||
const mapToString = (v)=>{
|
||||
@@ -92,6 +93,7 @@
|
||||
logCss('tests-pass',"All",workers.length,"workers finished in",
|
||||
calcTime(new Date()),"ms");
|
||||
}
|
||||
logCss("Reload page to run the test again.");
|
||||
};
|
||||
|
||||
workers.onmessage = function(msg){
|
||||
@@ -158,25 +160,28 @@
|
||||
a.innerText = args;
|
||||
}
|
||||
|
||||
stdout("Launching",options.workerCount,"workers. Options:",options);
|
||||
workers.uri = (
|
||||
'worker.js?'
|
||||
+ 'sqlite3.dir='+options.sqlite3Dir
|
||||
+ '&vfs='+options.vfs
|
||||
+ '&interval='+options.interval
|
||||
+ '&iterations='+options.iterations
|
||||
+ '&opfs-verbose='+options.opfsVerbose
|
||||
+ '&opfs-unlock-asap='+options.unlockAsap
|
||||
);
|
||||
for(let i = 0; i < options.workerCount; ++i){
|
||||
stdout("Launching worker...", i, );
|
||||
workers.push(new Worker(
|
||||
workers.uri+'&workerId='+(i+1)+(
|
||||
(i || options.noUnlink) ? '' : '&unlink-db'
|
||||
)
|
||||
));
|
||||
}
|
||||
// Have to delay onmessage assignment until after the loop
|
||||
// to avoid that early workers get an undue head start.
|
||||
workers.forEach((w)=>w.onmessage = workers.onmessage);
|
||||
btnGo.addEventListener('click', ()=>{
|
||||
btnGo.remove();
|
||||
stdout("Launching",options.workerCount,"workers. Options:",options);
|
||||
workers.uri = (
|
||||
'worker.js?'
|
||||
+ 'sqlite3.dir='+options.sqlite3Dir
|
||||
+ '&vfs='+options.vfs
|
||||
+ '&interval='+options.interval
|
||||
+ '&iterations='+options.iterations
|
||||
+ '&opfs-verbose='+options.opfsVerbose
|
||||
+ '&opfs-unlock-asap='+options.unlockAsap
|
||||
);
|
||||
for(let i = 0; i < options.workerCount; ++i){
|
||||
stdout("Launching worker...", i, );
|
||||
workers.push(new Worker(
|
||||
workers.uri+'&workerId='+(i+1)+(
|
||||
(i || options.noUnlink) ? '' : '&unlink-db'
|
||||
)
|
||||
));
|
||||
}
|
||||
// Have to delay onmessage assignment until after the loop
|
||||
// to avoid that early workers get an undue head start.
|
||||
workers.forEach((w)=>w.onmessage = workers.onmessage);
|
||||
});
|
||||
})(globalThis);
|
||||
|
||||
@@ -1920,6 +1920,12 @@ smoketest: $(TESTPROGS) fuzzcheck$(T.exe)
|
||||
shelltest:
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl release shell
|
||||
|
||||
# Test performance of floating-point conversions.
|
||||
#
|
||||
fp-speed-test: fp-speed-1$(T.exe) fp-speed-2$(T.exe)
|
||||
./fp-speed-1 1000000
|
||||
./fp-speed-2 1000000
|
||||
|
||||
#
|
||||
# sqlite3_analyzer.c build depends on $(LINK_TOOLS_DYNAMICALLY).
|
||||
#
|
||||
@@ -2037,6 +2043,14 @@ speedtest1$(T.exe): $(TOP)/test/speedtest1.c sqlite3.c Makefile
|
||||
$(LDFLAGS.libsqlite3)
|
||||
xbin: speedtest1$(T.exe)
|
||||
|
||||
fp-speed-1$(T.exe): $(TOP)/test/fp-speed-1.c sqlite3.o Makefile
|
||||
$(T.link) $(ST_OPT) -o $@ $(TOP)/test/fp-speed-1.c sqlite3.o \
|
||||
$(LDFLAGS.libsqlite3)
|
||||
|
||||
fp-speed-2$(T.exe): $(TOP)/test/fp-speed-2.c sqlite3.o Makefile
|
||||
$(T.link) $(ST_OPT) -o $@ $(TOP)/test/fp-speed-2.c sqlite3.o \
|
||||
$(LDFLAGS.libsqlite3)
|
||||
|
||||
startup$(T.exe): $(TOP)/test/startup.c sqlite3.c
|
||||
$(T.link) -Os -g -USQLITE_THREADSAFE -DSQLITE_THREADSAFE=0 \
|
||||
-o $@ $(TOP)/test/startup.c sqlite3.c $(LDFLAGS.libsqlite3)
|
||||
@@ -2482,6 +2496,7 @@ tidy:
|
||||
rm -f tclsqlite3$(T.exe) $(TESTPROGS)
|
||||
rm -f LogEst$(T.exe) fts3view$(T.exe) rollback-test$(T.exe) showdb$(T.exe)
|
||||
rm -f showjournal$(T.exe) showstat4$(T.exe) showwal$(T.exe) speedtest1$(T.exe)
|
||||
rm -f fp-speed-1$(T.exe) fp-speed-2$(T.exe)
|
||||
rm -f wordcount$(T.exe) changeset$(T.exe) version-info$(T.exe)
|
||||
rm -f *.exp *.vsix pkgIndex.tcl
|
||||
rm -f sqlite3_analyzer$(T.exe) sqlite3_rsync$(T.exe) sqlite3_expert$(T.exe)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Include\sthe\sfloat-point\stable\sgenerator\sutility\sin\sthe\stools\sdirectory.
|
||||
D 2026-03-17T09:45:47.412
|
||||
C Fix\sharmless\scompiler\swarnings\sabout\sunused\svariable\sassignments.
|
||||
D 2026-03-29T22:41:12.963
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d
|
||||
F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b
|
||||
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
|
||||
F Makefile.msc bee487191dcc9394d0e38854aa311b79d4488e0b877cc1a1a61ba5ad8ef225a6
|
||||
F Makefile.msc 92391304cf70f4c178b127aa83b88637abd28d1b83ede451616144037ea1d3dd
|
||||
F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec
|
||||
F VERSION 31435e19ded2aae3c1c67dacf06a995a37fd1b253baec5899b78d64cd29db4f7
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
@@ -114,7 +114,7 @@ F ext/fts5/fts5_config.c bfba970fe1e4eed18ee57c8d51458e226db9a960ddf775c5e50e3d7
|
||||
F ext/fts5/fts5_expr.c 71d48e8cf0358deace4949276647d317ff7665db6db09f40b81e2e7fe6664c7c
|
||||
F ext/fts5/fts5_hash.c d5871df92ce3fa210a650cf419ee916b87c29977e86084d06612edf772bff6f5
|
||||
F ext/fts5/fts5_index.c f8cfa37bb7397e5ede20242e4c9cb030bc8b4584ce3f23a5e2495038c0ae64bd
|
||||
F ext/fts5/fts5_main.c 6889f1373c469d515e792fb3d783c2218e63c560433ebd66edc0f740ab086c1b
|
||||
F ext/fts5/fts5_main.c b0fed47b3b4420ba6810373480a75bc28a9c0b7d16478d19a396436fb3ff17d7
|
||||
F ext/fts5/fts5_storage.c 19bc7c4cbe1e6a2dd9849ef7d84b5ca1fcbf194cefc3e386b901e00e08bf05c2
|
||||
F ext/fts5/fts5_tcl.c 2be6cc14f9448f720fd4418339cd202961a0801ea9424cb3d9de946f8f5a051c
|
||||
F ext/fts5/fts5_test_mi.c 4308d5658cb1f5eee5998dcbaac7d5bdf7a2ef43c8192ca6e0c843f856ccee26
|
||||
@@ -202,7 +202,7 @@ F ext/fts5/test/fts5hash.test fd3e0367fbf0b0944d6936fdb22696350f57b9871069c67662
|
||||
F ext/fts5/test/fts5integrity.test 613efcebe16b2d7a4096f03bcfb164f79a000b3354420ceda4a6f3e035090789
|
||||
F ext/fts5/test/fts5integrity2.test 4c3636615c0201232c44a8105d5cb14fd5499fd0ee3014d7ffd7e83aac76ece8
|
||||
F ext/fts5/test/fts5interrupt.test af7834ac6c2e71c05aea42d92f272eef3655e89b7a14a5620a2cd9de35e2e8ea
|
||||
F ext/fts5/test/fts5join.test 48b7ed36956948c5b8456c8bcaa5b087808d99000675918a43c4f51a925f1514
|
||||
F ext/fts5/test/fts5join.test 3791e30d034050281191cd8141d969849f6c060135f1e3938fea3eea955f9da9
|
||||
F ext/fts5/test/fts5lastrowid.test f36298a1fb9f988bde060a274a7ce638faa9c38a31400f8d2d27ea9373e0c4a1
|
||||
F ext/fts5/test/fts5leftjoin.test 1c14b51f4d1344a89e488160882f05a2246dd7e70c5cf077c8fb473e03c66338
|
||||
F ext/fts5/test/fts5limits.test 8ab67cf5d311c124b6ceb0062d0297767176df4572d955fce79fa43004dff01c
|
||||
@@ -271,6 +271,7 @@ F ext/fts5/test/fts5update2.test c5baa76799ac605ebb8e5e21035db2014b396cef25c903e
|
||||
F ext/fts5/test/fts5version.test 44ab35566267b7618c090443de2d9ad84f633df5d20bf72e9bad199ae5fced84
|
||||
F ext/fts5/test/fts5vocab.test 2a2bdb60d0998fa3124d541b6d30b019504918dc43a6584645b63a24be72f992
|
||||
F ext/fts5/test/fts5vocab2.test 4265137a3747b27deb1e2e2bde5654120c6de72bfed3238e67806d85af60fc4c
|
||||
F ext/fts5/tool/fts5cost.tcl 188a802e69422619c526698b92f0e5935f7d00b964e155bf4d5b4d4094989f60
|
||||
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
|
||||
F ext/fts5/tool/fts5txt2db.tcl c0d43c8590656f8240e622b00957b3a0facc49482411a9fdc2870b45c0c82f9f
|
||||
F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
|
||||
@@ -368,7 +369,7 @@ F ext/misc/cksumvfs.c 9d7d0cf1a8893ac5d48922bfe9f3f217b4a61a6265f559263a02bb2001
|
||||
F ext/misc/closure.c 5559daf1daf742228431db929d1aa86dd535a4224cc634a81d2fd0d1e6ad7839
|
||||
F ext/misc/completion.c fd94e8231bb286a2eef7225368938565162daa72a8e8d06f946cc30ce15bf600
|
||||
F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565
|
||||
F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf
|
||||
F ext/misc/csv.c 256ee522fcf505d6eeaee0a891be9decd8df53c7d8d6a3629c52e6e803adf5f7
|
||||
F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680
|
||||
F ext/misc/decimal.c b64911bcc77ed86e40075a6a51a9efb48520720f289b9be544adf6e2587094d5
|
||||
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
|
||||
@@ -388,7 +389,7 @@ F ext/misc/percentile.c 72e05a21db20a2fa85264b99515941f00ae698824c9db82d7edfbb16
|
||||
F ext/misc/prefixes.c 82645f79229877afab08c8b08ca1e7fa31921280906b90a61c294e4f540cd2a6
|
||||
F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47cc06c
|
||||
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
|
||||
F ext/misc/regexp.c 69bd45f6931bdc6801c1059b65a3e8b15ba88255e6abe387a34b653ce17e8908
|
||||
F ext/misc/regexp.c fa2d4c479e8bfe8c228d57dd4dde8e4aecb5b0abee70713853dcaa3c52d3fd8a
|
||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
|
||||
@@ -418,10 +419,10 @@ F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f6
|
||||
F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
|
||||
F ext/misc/zipfile.c c8ee04e1b349270b5df401ad732f5d7c387146e69b33c02fa90322760cc6fee0
|
||||
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
|
||||
F ext/qrf/README.md e6e0ce2700acf6fd06312b42726a8f08ca240f30e1b122bff87c71c602046352
|
||||
F ext/qrf/README.md 9e644615d7d7b77ef7e9db798765679e50c5ed12eda48bce21c9ef9eb4715e9d
|
||||
F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
|
||||
F ext/qrf/qrf.c 668456bdcfa1ad7914f21ee3846404494efbdfc8b6b6557a2ec27a17e1f92b29
|
||||
F ext/qrf/qrf.h 2b27cb8079131ac3af2134e9e2ee9621b41d97bcb546fead41b9e1a12a3567a7
|
||||
F ext/qrf/qrf.c 7334c688296f818f99c0cf37318b279ef62982a4860762096158237981fecb06
|
||||
F ext/qrf/qrf.h 751fc5b102fa7e19aa4f1e2e75012fdc477bf6af7409dff36f9de5a9f3f6cf22
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
|
||||
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
|
||||
@@ -490,7 +491,7 @@ F ext/recover/sqlite3recover.h 011c799f02deb70ab685916f6f538e6bb32c4e0025e79bfd0
|
||||
F ext/recover/test_recover.c 3d0fb1df7823f5bc22a0b93955034d16a2dfa2eb1e443e9a0123a77f120599a3
|
||||
F ext/rtree/README 734aa36238bcd2dee91db5dba107d5fcbdb02396612811377a8ad50f1272b1c1
|
||||
F ext/rtree/geopoly.c bd1971479184d559499ff3087c37f2823977d7b0ec80916141ae66f70345c88d
|
||||
F ext/rtree/rtree.c 9331997a76b88a9bc04e156bdfd6e2fe35c0aa93bc338ebc6aa0ae470fe4a852
|
||||
F ext/rtree/rtree.c 44abdd5df278ca1901daf29c82cce6785f0ee82ce59e28160ee988c17a9a185b
|
||||
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
|
||||
F ext/rtree/rtree1.test e0608db762b2aadca0ecb6f97396cf66244490adc3ba88f2a292b27be3e1da3e
|
||||
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
|
||||
@@ -645,8 +646,8 @@ F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f80
|
||||
F ext/wasm/tester1-worker.c-pp.html 7171022e7f4da8f46e5f50ea81dd6ce840b9235c47653a5deeb3764ccc2fe472
|
||||
F ext/wasm/tester1.c-pp.html bd927ccf51ddd65e924660a0487add99e1b044afe03950e49d87ccf44efdddb6
|
||||
F ext/wasm/tester1.c-pp.js 581be6f3228351bc77512ba743912d1ad52f40dde1fef1a943fd568b0cfc51b1
|
||||
F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226
|
||||
F ext/wasm/tests/opfs/concurrency/test.js 46c772bc18abb0fcbb058d57b5aaee9e7938f948ecdd802c6ca0850ad3519f92
|
||||
F ext/wasm/tests/opfs/concurrency/index.html 706eab6308343c04ac2360aba6001af4ffaf46d8f33a0ccd02c64d93e3216a43
|
||||
F ext/wasm/tests/opfs/concurrency/test.js 6919778fceaac1b7cc78caf41d796f545d2c4433b31188aa9689f05b5ad28828
|
||||
F ext/wasm/tests/opfs/concurrency/worker.js 704d82c5e287e47f612349e027765943a58ad967dcf178fb5a1c3a8eaafb09af
|
||||
F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79
|
||||
F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8
|
||||
@@ -654,7 +655,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk 64479b612d66a3f1a3ab498a3a40607937f614168987d8cda8320fa8be517fac
|
||||
F main.mk 0ed98e9faa3a8e2ce40ec5b55781101048c13c6970bc50d456d4c2834e74f4ea
|
||||
F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -675,28 +676,28 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c fb350c445316c1cc0529703c0b76450770a1de0ab0440641a56b19f05d6fefbe
|
||||
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
|
||||
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
|
||||
F src/build.c b993e4adef4c4cdfd7abf62e2676c467bb1923f25f40c3c7ab2a7bfbace3de7f
|
||||
F src/build.c f370ed7458c1c3258bf8d83abf4af7130b2ba3a76536022e2b4d42973c53f70e
|
||||
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
|
||||
F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
|
||||
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
|
||||
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
|
||||
F src/delete.c 901499bed747c3b4b2be45be1abe912ba50a3f6a40ba88cc006ccf279f2d0e97
|
||||
F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
|
||||
F src/expr.c 51e9c77ff5d9a21439e611fe6571a3cd50387e526e13c5614fd407e5b8571930
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c fb0f74c57d19a2d3f113f3476826919d68feda7ff334abfdb479a9a6353b9fcd
|
||||
F src/func.c 6e7de3551ae0f8205006e5109f025223246edd20186d54d90746dee7c1c5c093
|
||||
F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08
|
||||
F src/func.c 706ac012bf87d8ad7416a56a1d2b1f19e5dea03506a4606a01aa9d3bacf392c7
|
||||
F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b
|
||||
F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca
|
||||
F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
|
||||
F src/hwtime.h 21c2cf1f736e7b97502c3674d0c386db3f06870d6f10d0cf8174e2a4b8cb726e
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
|
||||
F src/json.c 06cc944d51ecbdde04f465ea220034cab76dcce4e20b95d2201f6f3e2c89a854
|
||||
F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9
|
||||
F src/main.c 31a13302193fbd51279c7e69cdfa0320d0de7629f9151e0964c1d320e8bdd7a4
|
||||
F src/main.c 387bb9d0216d6d35b221481ba8e661d94ad043060cd89581b6422c269ce680a0
|
||||
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@@ -726,22 +727,22 @@ F src/parse.y 3b784d6083380a950e3b1b32ce5ddd303e8c7c209d8ab788df2c62aaf9ee8eb3
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
|
||||
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
|
||||
F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f
|
||||
F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d
|
||||
F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d
|
||||
F src/printf.c 9cff219dba73b1aa9a8113e83e962f03f7bea8b6eb51cefb25bc468d5a69fb2d
|
||||
F src/printf.c 9abec48ffb0fc1aac72a461e2ca456b5284a39c84cddc932c86822311e059882
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
|
||||
F src/shell.c.in 5bfc926b756d5816fcaf56a30c3a363ba09ac09a9f6a5a7eef1b27c8bac8f6c4
|
||||
F src/sqlite.h.in 4d657846d68a58b028f0c4c331b9d3b4a79306f25c3b0d04fb56060343f73d85
|
||||
F src/shell.c.in 91ee40ec3f75192362cbaa0ad85316140b8dde00a184113d73a837fb6173dbcc
|
||||
F src/sqlite.h.in e7acbb01518f05c5a342149ec1eeb1afcdccf9b90a6e9770a4893ae9a3c756ae
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
|
||||
F src/sqliteInt.h 9716721fb57e32938a1d30a84560ce7633c63860a2209e188c87afad15d4b464
|
||||
F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e
|
||||
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
|
||||
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 71230da35d81b7234c5e4dc3747ca2302390884b051052956deb3dbf680a6ed4
|
||||
F src/tclsqlite.c 7401c73c917a4d1b380c896a324c8d8eb533a999559d9e339d479596553bebfd
|
||||
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
|
||||
F src/test1.c 3e3b013f59ffcb57dce00c90d55907072d71d4e970cb0a590cb261efe11bae9c
|
||||
F src/test2.c 2b9ab96bba63a1c369d5769390475259ad210f144a877805f2e32e563f9e93c1
|
||||
@@ -791,21 +792,21 @@ F src/test_vfs.c b4135c1308516adf0dfd494e6d6c33114e03732be899eace0502919b674586b
|
||||
F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 85d8b9f05f78211c61e3739ab5db761d7118766d1916ae7f2764735106bc4e13
|
||||
F src/tokenize.c 2bbf16801d8c59aaf5435b066364da9e39ec3a379084b8a697881e7e52733c63
|
||||
F src/tokenize.c e9d52d9f7374d82dadcd11726bea8a597d43709d6672704f3f0375bf1d726912
|
||||
F src/treeview.c feaa59f14db4f7b5aacca9c5ad5aeb562c1f98262c1ffd74371f4186ade91fc5
|
||||
F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20
|
||||
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
|
||||
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
|
||||
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
|
||||
F src/util.c cf91389b58590edfb5978199ef59488ef8e3723e1ba1aa0ff15c62f8a658b95f
|
||||
F src/util.c f264a84eda716ae009089f1d788b55718062810792b0bfa331e7899f2add39c6
|
||||
F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
|
||||
F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f
|
||||
F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9
|
||||
F src/vdbeInt.h 42488247a80cd9d300627833c6c85ace067ae5011a99e7614e2358130d62feea
|
||||
F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
|
||||
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
|
||||
F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
|
||||
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
|
||||
F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c
|
||||
F src/vdbeaux.c 81687c55682b9f4d942186695f4f7fa4743c564a985e0889def52eded9076d61
|
||||
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
|
||||
F src/vdbemem.c 317ec5e870ddb16951b606c9fe8be22baef22ecbe46f58fdefc259662238afb7
|
||||
F src/vdbemem.c 5af6cf1253ac2aed0612b85138a1faf43f30ad38777d554db6c85b7281fa79fb
|
||||
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
|
||||
F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41
|
||||
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
|
||||
@@ -814,7 +815,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab
|
||||
F src/wal.c 88d94fd15a75f6eda831fa32d1148a267ea37bf0a4b69829a73dfde06244b08f
|
||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
|
||||
F src/where.c 406d9ec8d12f646c28c4b4a645ea20329eb343b19cfa3dcd8aab938066c4ae66
|
||||
F src/where.c bffca5e4ef20d0bfbdc24f1dc13fd3f955284225a8ad25a4454635f6be39aad0
|
||||
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
|
||||
F src/wherecode.c 676cb6cb02878643e817d9917a2d3522b83a3736b2cedd3dc8a01d7bb92af6c2
|
||||
F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6
|
||||
@@ -875,7 +876,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 2a01bf5bf3a0f10adf8ae3a3fd2c05af8a8c1b7a52fae227adb4ccd931915b5c
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
@@ -1102,6 +1103,7 @@ F test/expr.test db981f8a85520e99ae20aab7ad2e9b5b0437ed09159b57ced434c672075d2e6
|
||||
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
|
||||
F test/exprfault.test da33606d799718e2f8e34efd0e5858884a1ad87f608774c552a7f5517cc27181
|
||||
F test/exprfault2.test c49e84273898969af5dbc4fe6a3f4335f14639799f343590336c9ddf84425965
|
||||
F test/expridx1.test b464520126e1d781a7800f8540621c82e8bbc526f089ff8b0b57ffc51feea6b7
|
||||
F test/extension01.test 5de412c66276105901c370770175003381fdcb0c4da7054fa43cf4a31e0bfa3a
|
||||
F test/external_reader.test 6fdec43eeca23eb32faad1e95a4d1abc402bc8b3db70df12d6fc08a637f4a2b5
|
||||
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
|
||||
@@ -1119,14 +1121,15 @@ F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 6727452e163a427147e84e739da18713da553d79f9783559b04fdcd36d5c7421
|
||||
F test/fkey6.test 668a7299e75899b0a3342c36df655be57f76a05aca3544bda939a6e676e2f000
|
||||
F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d031
|
||||
F test/fkey8.test 51deda7f1a1448bca95875e4a6e1a3a75b4bd7215e924e845bd60de60e4d84bf
|
||||
F test/fkey8.test 00ecfcaba529d4d9ef608551714e6a4d1e9d7083406f65e2f108c539aff6e8e3
|
||||
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
|
||||
F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958fdde5c
|
||||
F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63edb
|
||||
F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
|
||||
F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d
|
||||
F test/fp-speed-1.c 34a2fe8dc30d0b24bb3e7c16efca0a30452287da6caff7dde86eef882db155a4
|
||||
F test/fp-speed-2.c 15830b061832bb51f68f0985cf7a06f4f5d49eb25cc399854f1ff60d6a878ee9
|
||||
F test/fpconv1.test 63f352682fa65601a326563ad633086df6ab194e6ed5e7366786f38a525a7fd7
|
||||
F test/fptest01.sql 210562ad8d5a7895f26273dd3be56561a41bcb51d78a28a337af0f1ceaa3bb8d
|
||||
F test/fptest01.sql 3d84f10bb1cc220b59207354c887d720289903adeb9972a29d6bfcb3fec0df95
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
|
||||
F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a
|
||||
@@ -1559,7 +1562,7 @@ F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087
|
||||
F test/rowvalue7.test 06ec0aca725bf683313d03793aa2943bc7f45a901848c7056a9665b769c8fc38
|
||||
F test/rowvalue8.test 5900eddad9e2c3c2e26f1a95f74aafc1232ee5e0
|
||||
F test/rowvalue9.test 7499a8fd7ca3a3f0e19d94e135355439aa2b596f86b775ca8de79672da2ca378
|
||||
F test/rowvalueA.test 1c5ed13f3b0641452ae35e6488d6ecc16cefce99f2adf7c07c513530e2aac6b7
|
||||
F test/rowvalueA.test 7d28bf6c2f8a2af8adbba2c4eda9136a4dd36250b8966ba05b34c0954f78efd7
|
||||
F test/rowvaluefault.test 963ae9cdaed30a85a29668dd514e639f3556cae903ee9f172ea972d511c54fff
|
||||
F test/rowvaluevtab.test cd9747bb3f308086944c07968f547ad6b05022e698d80b9ffbdfe09ce0b8da6f
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
@@ -1615,7 +1618,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
|
||||
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test d714be78c063cfb5f0933dcf2b5d9df62ef57f8eaf8848bbd0026a9d252d4db5
|
||||
F test/shell1.test eda2e527435f139224dda67db6bbd2466597408d4fe5883d647d67fa32d88f7c
|
||||
F test/shell2.test dc541d2681503e55466a24d35a4cbf8ca5b90b8fcdef37fc4db07373a67d31d3
|
||||
F test/shell3.test 91efdd545097a61a1f72cf79c9ad5b49da080f3f10282eaf4c3c272cd1012db2
|
||||
F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
|
||||
@@ -1625,7 +1628,7 @@ F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d
|
||||
F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192
|
||||
F test/shell9.test c0e8871061a92151450b3332279a893b516fa73a6c46d4f51a0998407cbf8c89
|
||||
F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480
|
||||
F test/shellB.test 7123d231158588401f332bf278754687b83ba5fc5b352ec8679fb19edfb4cc0a
|
||||
F test/shellB.test 31df04230f6062069bb7c5d0e5c5439ca44448fa9da1a55aa461a4b872fe6bd9
|
||||
F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@@ -2081,7 +2084,7 @@ F test/with1.test 31db84788e0429885b63995149fab57d32e26196b752a3a926249ae74c0add
|
||||
F test/with2.test 181674a6cc86a601ca2ac052741cdfad5b529e07e870435d2f6cdb92d589ff17
|
||||
F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65
|
||||
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
|
||||
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
|
||||
F test/with5.test 0e5e141fee75aa170289467542a2ffd71933d4fb006bfb135275b1787bdc8fbe
|
||||
F test/with6.test 281e4861b5e517f6c3c2f08517a520c1e2ee7c11966545d3901f258a4fe8ef76
|
||||
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
|
||||
F test/without_rowid1.test f6e75e32821eb423ac3812434d12bdd8098f17e3b2206da61575e1db77f82428
|
||||
@@ -2135,7 +2138,7 @@ F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f00591
|
||||
F tool/mkautoconfamal.sh 06fbe090b81c24e592c1f22b404334f805ba74d482a9260f2ac81e6f3d3386d8
|
||||
F tool/mkccode.tcl c42a8f8cf78f92e83795d5447460dbce7aaf78a3bbf9082f1507dc71a3665f3c x
|
||||
F tool/mkcombo.tcl 2a5189b219c4a495e1ff7fc980bd568d3cfb82ae9d50c84e77f7a161e96fc132
|
||||
F tool/mkctimec.tcl 3fb5cad05922f5da61262cb6bcd5868a34e94a49ca8833ae2d7796e7df075576 x
|
||||
F tool/mkctimec.tcl 68f3ee9e2e6a06524b25d79b5b61a883053466080a39da59e0a0697f0c4d9a3b x
|
||||
F tool/mkfptab.c 24ea40113f96584caca3f6dd06b4ad5adffa0f39023910cb83fa7ef2ffa9b0ba
|
||||
F tool/mkkeywordhash.c 82d5af1d0e677900739fba59155cddac172d8c712c2d91ab73d6e6bcb30060f0
|
||||
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
|
||||
@@ -2190,11 +2193,11 @@ F tool/vdbe-compress.tcl fa2f37ab39b2a0087fafb6a7f3ce19503e25e624ffa8ed9951717ab
|
||||
F tool/vdbe_profile.tcl 3ac5a4a9449f4baf77059358ea050db3e34395ccf59c5464d29b91746d5b961e
|
||||
F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6ddf2700c
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
|
||||
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P 23ad656edb3a63e7e6602770e1f2c4a5ef1f3d41565e7f13408b5305619dfa3d
|
||||
R 0212d90b78d20068a702d7e70e4b68de
|
||||
P 9fa9cd11f8f5f7591168870c6e41121221b58a4a3094e708e3fa5bab1502f190
|
||||
R 3d9d1b868f679fc05545d2cf5aa8e36a
|
||||
U drh
|
||||
Z a52753c1b6f0991d0a121a4d3cb8bc3e
|
||||
Z e2629b4a210900f82e89295566df240e
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
branch fp-accuracy
|
||||
tag fp-accuracy
|
||||
branch direct-printf
|
||||
tag direct-printf
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
4ab10b251d870af8297b9e505452393f6000f83784c822ff128e7aec06f8c72f
|
||||
afe7e9fd1c476c7cdcefab0adf0191a8dc3283811f72a685fff3eb6539b72dcc
|
||||
|
||||
+80
-88
@@ -2494,9 +2494,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
if( !hasColumn(pPk->aiColumn, j, i)
|
||||
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
|
||||
){
|
||||
const char *zColl = sqlite3ColumnColl(&pTab->aCol[i]);
|
||||
assert( j<pPk->nColumn );
|
||||
pPk->aiColumn[j] = i;
|
||||
pPk->azColl[j] = sqlite3StrBINARY;
|
||||
pPk->azColl[j] = zColl ? zColl : sqlite3StrBINARY;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
@@ -5522,8 +5523,7 @@ void sqlite3RowidConstraint(
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if pIndex uses the collating sequence pColl. Return
|
||||
** true if it does and false if it does not.
|
||||
** Return true if any column of pIndex uses the zColl collation
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
static int collationMatch(const char *zColl, Index *pIndex){
|
||||
@@ -5531,8 +5531,8 @@ static int collationMatch(const char *zColl, Index *pIndex){
|
||||
assert( zColl!=0 );
|
||||
for(i=0; i<pIndex->nColumn; i++){
|
||||
const char *z = pIndex->azColl[i];
|
||||
assert( z!=0 || pIndex->aiColumn[i]<0 );
|
||||
if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){
|
||||
assert( z!=0 );
|
||||
if( 0==sqlite3StrICmp(z, zColl) ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -5540,73 +5540,40 @@ static int collationMatch(const char *zColl, Index *pIndex){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Recompute all indices of pTab that use the collating sequence pColl.
|
||||
** If pColl==0 then recompute all indices of pTab.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
|
||||
if( !IsVirtual(pTab) ){
|
||||
Index *pIndex; /* An index associated with pTab */
|
||||
|
||||
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
|
||||
if( zColl==0 || collationMatch(zColl, pIndex) ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3RefillIndex(pParse, pIndex, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Recompute all indices of all tables in all databases where the
|
||||
** indices use the collating sequence pColl. If pColl==0 then recompute
|
||||
** all indices everywhere.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
static void reindexDatabases(Parse *pParse, char const *zColl){
|
||||
Db *pDb; /* A single database */
|
||||
int iDb; /* The database index number */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
HashElem *k; /* For looping over tables in pDb */
|
||||
Table *pTab; /* A table in the database */
|
||||
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */
|
||||
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
|
||||
assert( pDb!=0 );
|
||||
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
pTab = (Table*)sqliteHashData(k);
|
||||
reindexTable(pParse, pTab, zColl);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Generate code for the REINDEX command.
|
||||
**
|
||||
** REINDEX -- 1
|
||||
** REINDEX <collation> -- 2
|
||||
** REINDEX ?<database>.?<tablename> -- 3
|
||||
** REINDEX ?<database>.?<indexname> -- 4
|
||||
** REINDEX ?<database>.?<indexname> -- 3
|
||||
** REINDEX ?<database>.?<tablename> -- 4
|
||||
** REINDEX EXPRESSIONS -- 5
|
||||
**
|
||||
** Form 1 causes all indices in all attached databases to be rebuilt.
|
||||
** Form 2 rebuilds all indices in all databases that use the named
|
||||
** Form 1 causes all indexes in all attached databases to be rebuilt.
|
||||
** Form 2 rebuilds all indexes in all databases that use the named
|
||||
** collating function. Forms 3 and 4 rebuild the named index or all
|
||||
** indices associated with the named table.
|
||||
** indexes associated with the named table, respectively. Form 5
|
||||
** rebuilds all expression indexes in addition to all collations,
|
||||
** indexes, or tables named "EXPRESSIONS".
|
||||
**
|
||||
** If the name is ambiguous such that it matches two or more of
|
||||
** forms 2 through 5, then rebuild the union of all matching indexes,
|
||||
** taken care to avoid rebuilding the same index more than once.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
|
||||
CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */
|
||||
char *z; /* Name of a table or index */
|
||||
const char *zDb; /* Name of the database */
|
||||
Table *pTab; /* A table in the database */
|
||||
Index *pIndex; /* An index associated with pTab */
|
||||
int iDb; /* The database index number */
|
||||
char *z = 0; /* Name of a table or index or collation */
|
||||
const char *zDb = 0; /* Name of the database */
|
||||
int iReDb = -1; /* The database index number */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
Token *pObjName; /* Name of the table or index to be reindexed */
|
||||
int bMatch = 0; /* At least one name match */
|
||||
const char *zColl = 0; /* Rebuild indexes using this collation */
|
||||
Table *pReTab = 0; /* Rebuild all indexes of this table */
|
||||
Index *pReIndex = 0; /* Rebuild this index */
|
||||
int isExprIdx = 0; /* Rebuild all expression indexes */
|
||||
int bAll = 0; /* Rebuild all indexes */
|
||||
|
||||
/* Read the database schema. If an error occurs, leave an error message
|
||||
** and code in pParse and return NULL. */
|
||||
@@ -5615,41 +5582,66 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
|
||||
}
|
||||
|
||||
if( pName1==0 ){
|
||||
reindexDatabases(pParse, 0);
|
||||
return;
|
||||
/* rebuild all indexes */
|
||||
bMatch = 1;
|
||||
bAll = 1;
|
||||
}else if( NEVER(pName2==0) || pName2->z==0 ){
|
||||
char *zColl;
|
||||
assert( pName1->z );
|
||||
zColl = sqlite3NameFromToken(pParse->db, pName1);
|
||||
if( !zColl ) return;
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
|
||||
if( pColl ){
|
||||
reindexDatabases(pParse, zColl);
|
||||
sqlite3DbFree(db, zColl);
|
||||
return;
|
||||
z = sqlite3NameFromToken(pParse->db, pName1);
|
||||
if( z==0 ) return;
|
||||
}else{
|
||||
iReDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
|
||||
if( iReDb<0 ) return;
|
||||
z = sqlite3NameFromToken(db, pObjName);
|
||||
if( z==0 ) return;
|
||||
zDb = db->aDb[iReDb].zDbSName;
|
||||
}
|
||||
if( !bAll ){
|
||||
if( zDb==0 && sqlite3StrICmp(z, "expressions")==0 ){
|
||||
isExprIdx = 1;
|
||||
bMatch = 1;
|
||||
}
|
||||
if( zDb==0 && (pColl = sqlite3FindCollSeq(db, ENC(db), z, 0))!=0 ){
|
||||
zColl = z;
|
||||
bMatch = 1;
|
||||
}
|
||||
if( zColl==0 && (pReTab = sqlite3FindTable(db, z, zDb))!=0 ){
|
||||
bMatch = 1;
|
||||
}
|
||||
if( zColl==0 && (pReIndex = sqlite3FindIndex(db, z, zDb))!=0 ){
|
||||
bMatch = 1;
|
||||
}
|
||||
sqlite3DbFree(db, zColl);
|
||||
}
|
||||
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
|
||||
if( iDb<0 ) return;
|
||||
z = sqlite3NameFromToken(db, pObjName);
|
||||
if( z==0 ) return;
|
||||
zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
|
||||
pTab = sqlite3FindTable(db, z, zDb);
|
||||
if( pTab ){
|
||||
reindexTable(pParse, pTab, 0);
|
||||
sqlite3DbFree(db, z);
|
||||
return;
|
||||
if( bMatch ){
|
||||
int iDb;
|
||||
HashElem *k;
|
||||
Table *pTab;
|
||||
Index *pIdx;
|
||||
Db *pDb;
|
||||
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
|
||||
assert( pDb!=0 );
|
||||
if( iReDb>=0 && iReDb!=iDb ) continue;
|
||||
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
pTab = (Table*)sqliteHashData(k);
|
||||
if( IsVirtual(pTab) ) continue;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( bAll
|
||||
|| pTab==pReTab
|
||||
|| pIdx==pReIndex
|
||||
|| (isExprIdx && pIdx->bHasExpr)
|
||||
|| (zColl!=0 && collationMatch(zColl,pIdx))
|
||||
){
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3RefillIndex(pParse, pIdx, -1);
|
||||
}
|
||||
} /* End loop over indexes of pTab */
|
||||
} /* End loop over tables of iDb */
|
||||
} /* End loop over databases */
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
|
||||
}
|
||||
pIndex = sqlite3FindIndex(db, z, zDb);
|
||||
sqlite3DbFree(db, z);
|
||||
if( pIndex ){
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3RefillIndex(pParse, pIndex, -1);
|
||||
return;
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+3
-1
@@ -923,7 +923,9 @@ void sqlite3GenerateRowIndexDelete(
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
|
||||
&iPartIdxLabel, pPrior, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn
|
||||
);
|
||||
sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX);
|
||||
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
||||
pPrior = pIdx;
|
||||
}
|
||||
|
||||
+8
-6
@@ -1326,7 +1326,6 @@ static Trigger *fkActionTrigger(
|
||||
nFrom = sqlite3Strlen30(zFrom);
|
||||
|
||||
if( action==OE_Restrict ){
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
SrcList *pSrc;
|
||||
Expr *pRaise;
|
||||
|
||||
@@ -1337,10 +1336,10 @@ static Trigger *fkActionTrigger(
|
||||
}
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pSrc ){
|
||||
assert( pSrc->nSrc==1 );
|
||||
pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
|
||||
assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 );
|
||||
pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
||||
SrcItem *pItem = &pSrc->a[0];
|
||||
pItem->zName = sqlite3DbStrDup(db, zFrom);
|
||||
pItem->fg.fixedSchema = 1;
|
||||
pItem->u4.pSchema = pTab->pSchema;
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pParse,
|
||||
sqlite3ExprListAppend(pParse, 0, pRaise),
|
||||
@@ -1362,7 +1361,10 @@ static Trigger *fkActionTrigger(
|
||||
pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
|
||||
pStep->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pStep->pSrc ){
|
||||
pStep->pSrc->a[0].zName = sqlite3DbStrNDup(db, zFrom, nFrom);
|
||||
SrcItem *pItem = &pStep->pSrc->a[0];
|
||||
pItem->zName = sqlite3DbStrNDup(db, zFrom, nFrom);
|
||||
pItem->u4.pSchema = pTab->pSchema;
|
||||
pItem->fg.fixedSchema = 1;
|
||||
}
|
||||
pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
|
||||
|
||||
+5
-12
@@ -1098,18 +1098,11 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){
|
||||
|
||||
switch( sqlite3_value_type(pValue) ){
|
||||
case SQLITE_FLOAT: {
|
||||
double r1, r2;
|
||||
const char *zVal;
|
||||
r1 = sqlite3_value_double(pValue);
|
||||
sqlite3_str_appendf(pStr, "%!0.15g", r1);
|
||||
zVal = sqlite3_str_value(pStr);
|
||||
if( zVal ){
|
||||
sqlite3AtoF(zVal, &r2);
|
||||
if( r1!=r2 ){
|
||||
sqlite3_str_reset(pStr);
|
||||
sqlite3_str_appendf(pStr, "%!0.20e", r1);
|
||||
}
|
||||
}
|
||||
/* ,--- Show infinity as 9.0e+999
|
||||
** |
|
||||
** | ,--- 17 precision guarantees round-trip
|
||||
** v v */
|
||||
sqlite3_str_appendf(pStr, "%!0.17g", sqlite3_value_double(pValue));
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
|
||||
+83
-38
@@ -313,7 +313,8 @@ struct JsonString {
|
||||
/* Allowed values for JsonString.eErr */
|
||||
#define JSTRING_OOM 0x01 /* Out of memory */
|
||||
#define JSTRING_MALFORMED 0x02 /* Malformed JSONB */
|
||||
#define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */
|
||||
#define JSTRING_TOODEEP 0x04 /* JSON nested too deep */
|
||||
#define JSTRING_ERR 0x08 /* Error already sent to sqlite3_result */
|
||||
|
||||
/* The "subtype" set for text JSON values passed through using
|
||||
** sqlite3_result_subtype() and sqlite3_value_subtype().
|
||||
@@ -403,7 +404,7 @@ struct JsonParse {
|
||||
**************************************************************************/
|
||||
static void jsonReturnStringAsBlob(JsonString*);
|
||||
static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p);
|
||||
static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
|
||||
static u32 jsonTranslateBlobToText(JsonParse*,u32,JsonString*);
|
||||
static void jsonReturnParse(sqlite3_context*,JsonParse*);
|
||||
static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
|
||||
static void jsonParseFree(JsonParse*);
|
||||
@@ -561,6 +562,15 @@ static void jsonStringOom(JsonString *p){
|
||||
jsonStringReset(p);
|
||||
}
|
||||
|
||||
/* Report JSON nested too deep
|
||||
*/
|
||||
static void jsonStringTooDeep(JsonString *p){
|
||||
p->eErr |= JSTRING_TOODEEP;
|
||||
assert( p->pCtx!=0 );
|
||||
sqlite3_result_error(p->pCtx, "JSON nested too deep", -1);
|
||||
jsonStringReset(p);
|
||||
}
|
||||
|
||||
/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
|
||||
** Return zero on success. Return non-zero on an OOM error
|
||||
*/
|
||||
@@ -850,6 +860,7 @@ static void jsonReturnString(
|
||||
){
|
||||
assert( (pParse!=0)==(ctx!=0) );
|
||||
assert( ctx==0 || ctx==p->pCtx );
|
||||
jsonStringTerminate(p);
|
||||
if( p->eErr==0 ){
|
||||
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx));
|
||||
if( flags & JSON_BLOB ){
|
||||
@@ -857,7 +868,7 @@ static void jsonReturnString(
|
||||
}else if( p->bStatic ){
|
||||
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
|
||||
SQLITE_TRANSIENT, SQLITE_UTF8);
|
||||
}else if( jsonStringTerminate(p) ){
|
||||
}else{
|
||||
if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){
|
||||
int rc;
|
||||
pParse->zJson = sqlite3RCStrRef(p->zBuf);
|
||||
@@ -873,11 +884,11 @@ static void jsonReturnString(
|
||||
sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed,
|
||||
sqlite3RCStrUnref,
|
||||
SQLITE_UTF8);
|
||||
}else{
|
||||
sqlite3_result_error_nomem(p->pCtx);
|
||||
}
|
||||
}else if( p->eErr & JSTRING_OOM ){
|
||||
sqlite3_result_error_nomem(p->pCtx);
|
||||
}else if( p->eErr & JSTRING_TOODEEP ){
|
||||
/* error already in p->pCtx */
|
||||
}else if( p->eErr & JSTRING_MALFORMED ){
|
||||
sqlite3_result_error(p->pCtx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -2088,12 +2099,8 @@ static int jsonConvertTextToBlob(
|
||||
*/
|
||||
static void jsonReturnStringAsBlob(JsonString *pStr){
|
||||
JsonParse px;
|
||||
assert( pStr->eErr==0 );
|
||||
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);
|
||||
@@ -2183,7 +2190,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
|
||||
** The pOut->eErr JSTRING_OOM flag is set on a OOM.
|
||||
*/
|
||||
static u32 jsonTranslateBlobToText(
|
||||
const JsonParse *pParse, /* the complete parse of the JSON */
|
||||
JsonParse *pParse, /* the complete parse of the JSON */
|
||||
u32 i, /* Start rendering at this index */
|
||||
JsonString *pOut /* Write JSON here */
|
||||
){
|
||||
@@ -2365,10 +2372,14 @@ static u32 jsonTranslateBlobToText(
|
||||
jsonAppendChar(pOut, '[');
|
||||
j = i+n;
|
||||
iEnd = j+sz;
|
||||
if( ++pParse->iDepth > JSON_MAX_DEPTH ){
|
||||
jsonStringTooDeep(pOut);
|
||||
}
|
||||
while( j<iEnd && pOut->eErr==0 ){
|
||||
j = jsonTranslateBlobToText(pParse, j, pOut);
|
||||
jsonAppendChar(pOut, ',');
|
||||
}
|
||||
pParse->iDepth--;
|
||||
if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
|
||||
if( sz>0 ) jsonStringTrimOneChar(pOut);
|
||||
jsonAppendChar(pOut, ']');
|
||||
@@ -2379,10 +2390,14 @@ static u32 jsonTranslateBlobToText(
|
||||
jsonAppendChar(pOut, '{');
|
||||
j = i+n;
|
||||
iEnd = j+sz;
|
||||
if( ++pParse->iDepth > JSON_MAX_DEPTH ){
|
||||
jsonStringTooDeep(pOut);
|
||||
}
|
||||
while( j<iEnd && pOut->eErr==0 ){
|
||||
j = jsonTranslateBlobToText(pParse, j, pOut);
|
||||
jsonAppendChar(pOut, (x++ & 1) ? ',' : ':');
|
||||
}
|
||||
pParse->iDepth--;
|
||||
if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
|
||||
if( sz>0 ) jsonStringTrimOneChar(pOut);
|
||||
jsonAppendChar(pOut, '}');
|
||||
@@ -2439,7 +2454,7 @@ static u32 jsonTranslateBlobToPrettyText(
|
||||
u32 i /* Start rendering at this index */
|
||||
){
|
||||
u32 sz, n, j, iEnd;
|
||||
const JsonParse *pParse = pPretty->pParse;
|
||||
JsonParse *pParse = pPretty->pParse;
|
||||
JsonString *pOut = pPretty->pOut;
|
||||
n = jsonbPayloadSize(pParse, i, &sz);
|
||||
if( n==0 ){
|
||||
@@ -2454,6 +2469,9 @@ static u32 jsonTranslateBlobToPrettyText(
|
||||
if( j<iEnd ){
|
||||
jsonAppendChar(pOut, '\n');
|
||||
pPretty->nIndent++;
|
||||
if( pPretty->nIndent >= JSON_MAX_DEPTH ){
|
||||
jsonStringTooDeep(pOut);
|
||||
}
|
||||
while( pOut->eErr==0 ){
|
||||
jsonPrettyIndent(pPretty);
|
||||
j = jsonTranslateBlobToPrettyText(pPretty, j);
|
||||
@@ -2475,6 +2493,10 @@ static u32 jsonTranslateBlobToPrettyText(
|
||||
if( j<iEnd ){
|
||||
jsonAppendChar(pOut, '\n');
|
||||
pPretty->nIndent++;
|
||||
if( pPretty->nIndent >= JSON_MAX_DEPTH ){
|
||||
jsonStringTooDeep(pOut);
|
||||
}
|
||||
pParse->iDepth = pPretty->nIndent;
|
||||
while( pOut->eErr==0 ){
|
||||
jsonPrettyIndent(pPretty);
|
||||
j = jsonTranslateBlobToText(pParse, j, pOut);
|
||||
@@ -2876,7 +2898,8 @@ static int jsonLabelCompare(
|
||||
#define JSON_LOOKUP_ERROR 0xffffffff
|
||||
#define JSON_LOOKUP_NOTFOUND 0xfffffffe
|
||||
#define JSON_LOOKUP_NOTARRAY 0xfffffffd
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffc
|
||||
#define JSON_LOOKUP_TOODEEP 0xfffffffc
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffb
|
||||
#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
|
||||
|
||||
/* Forward declaration */
|
||||
@@ -2923,7 +2946,12 @@ static u32 jsonCreateEditSubstructure(
|
||||
pIns->eEdit = pParse->eEdit;
|
||||
pIns->nIns = pParse->nIns;
|
||||
pIns->aIns = pParse->aIns;
|
||||
pIns->iDepth = pParse->iDepth+1;
|
||||
if( pIns->iDepth >= JSON_MAX_DEPTH ){
|
||||
return JSON_LOOKUP_TOODEEP;
|
||||
}
|
||||
rc = jsonLookupStep(pIns, 0, zTail, 0);
|
||||
pParse->iDepth--;
|
||||
pParse->oom |= pIns->oom;
|
||||
}
|
||||
return rc; /* Error code only */
|
||||
@@ -3029,7 +3057,11 @@ static u32 jsonLookupStep(
|
||||
n = jsonbPayloadSize(pParse, v, &sz);
|
||||
if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR;
|
||||
assert( j>0 );
|
||||
if( ++pParse->iDepth >= JSON_MAX_DEPTH ){
|
||||
return JSON_LOOKUP_TOODEEP;
|
||||
}
|
||||
rc = jsonLookupStep(pParse, v, &zPath[i], j);
|
||||
pParse->iDepth--;
|
||||
if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
|
||||
return rc;
|
||||
}
|
||||
@@ -3115,7 +3147,11 @@ static u32 jsonLookupStep(
|
||||
iEnd = j+sz;
|
||||
while( j<iEnd ){
|
||||
if( kk==0 ){
|
||||
if( ++pParse->iDepth >= JSON_MAX_DEPTH ){
|
||||
return JSON_LOOKUP_TOODEEP;
|
||||
}
|
||||
rc = jsonLookupStep(pParse, j, &zPath[i+1], 0);
|
||||
pParse->iDepth--;
|
||||
if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
|
||||
return rc;
|
||||
}
|
||||
@@ -3447,7 +3483,16 @@ static int jsonFunctionArgToBlob(
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a bad path error.
|
||||
** Generate a path error.
|
||||
**
|
||||
** The specifics of the error are determined by the rc argument.
|
||||
**
|
||||
** rc error
|
||||
** ----------------- ----------------------
|
||||
** JSON_LOOKUP_ARRAY "not an array"
|
||||
** JSON_LOOKUP_TOODEEP "JSON nested too deep"
|
||||
** JSON_LOOKUP_ERROR "malformed JSON"
|
||||
** otherwise... "bad JSON path"
|
||||
**
|
||||
** If ctx is not NULL then push the error message into ctx and return NULL.
|
||||
** If ctx is NULL, then return the text of the error message.
|
||||
@@ -3460,6 +3505,10 @@ static char *jsonBadPathError(
|
||||
char *zMsg;
|
||||
if( rc==(int)JSON_LOOKUP_NOTARRAY ){
|
||||
zMsg = sqlite3_mprintf("not an array element: %Q", zPath);
|
||||
}else if( rc==(int)JSON_LOOKUP_ERROR ){
|
||||
zMsg = sqlite3_mprintf("malformed JSON");
|
||||
}else if( rc==(int)JSON_LOOKUP_TOODEEP ){
|
||||
zMsg = sqlite3_mprintf("JSON path too deep");
|
||||
}else{
|
||||
zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
|
||||
}
|
||||
@@ -3522,6 +3571,7 @@ static void jsonInsertIntoBlob(
|
||||
p->nIns = ax.nBlob;
|
||||
p->aIns = ax.aBlob;
|
||||
p->delta = 0;
|
||||
p->iDepth = 0;
|
||||
rc = jsonLookupStep(p, 0, zPath+1, 0);
|
||||
}
|
||||
jsonParseReset(&ax);
|
||||
@@ -3534,11 +3584,7 @@ static void jsonInsertIntoBlob(
|
||||
|
||||
jsonInsertIntoBlob_patherror:
|
||||
jsonParseFree(p);
|
||||
if( rc==JSON_LOOKUP_ERROR ){
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
}
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3978,10 +4024,8 @@ static void jsonArrayLengthFunc(
|
||||
if( JSON_LOOKUP_ISERROR(i) ){
|
||||
if( i==JSON_LOOKUP_NOTFOUND ){
|
||||
/* no-op */
|
||||
}else if( i==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
jsonBadPathError(ctx, zPath, i);
|
||||
}
|
||||
eErr = 1;
|
||||
i = 0;
|
||||
@@ -4115,11 +4159,8 @@ static void jsonExtractFunc(
|
||||
jsonAppendSeparator(&jx);
|
||||
jsonAppendRawNZ(&jx, "null", 4);
|
||||
}
|
||||
}else if( j==JSON_LOOKUP_ERROR ){
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
goto json_extract_error;
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
jsonBadPathError(ctx, zPath, j);
|
||||
goto json_extract_error;
|
||||
}
|
||||
}
|
||||
@@ -4143,6 +4184,7 @@ json_extract_error:
|
||||
#define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */
|
||||
#define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */
|
||||
#define JSON_MERGE_OOM 3 /* Out-of-memory condition */
|
||||
#define JSON_MERGE_TOODEEP 4 /* Nested too deep */
|
||||
|
||||
/*
|
||||
** RFC-7396 MergePatch for two JSONB blobs.
|
||||
@@ -4194,7 +4236,8 @@ static int jsonMergePatch(
|
||||
JsonParse *pTarget, /* The JSON parser that contains the TARGET */
|
||||
u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */
|
||||
const JsonParse *pPatch, /* The PATCH */
|
||||
u32 iPatch /* Index of PATCH in pPatch->aBlob[] */
|
||||
u32 iPatch, /* Index of PATCH in pPatch->aBlob[] */
|
||||
u32 iDepth /* Nesting depth */
|
||||
){
|
||||
u8 x; /* Type of a single node */
|
||||
u32 n, sz=0; /* Return values from jsonbPayloadSize() */
|
||||
@@ -4303,7 +4346,8 @@ static int jsonMergePatch(
|
||||
/* Algorithm line 12 */
|
||||
int rc, savedDelta = pTarget->delta;
|
||||
pTarget->delta = 0;
|
||||
rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue);
|
||||
if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP;
|
||||
rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue, iDepth+1);
|
||||
if( rc ) return rc;
|
||||
pTarget->delta += savedDelta;
|
||||
}
|
||||
@@ -4324,7 +4368,8 @@ static int jsonMergePatch(
|
||||
pTarget->aBlob[iTEnd+szNew] = 0x00;
|
||||
savedDelta = pTarget->delta;
|
||||
pTarget->delta = 0;
|
||||
rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue);
|
||||
if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP;
|
||||
rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue,iDepth+1);
|
||||
if( rc ) return rc;
|
||||
pTarget->delta += savedDelta;
|
||||
}
|
||||
@@ -4355,11 +4400,13 @@ static void jsonPatchFunc(
|
||||
if( pTarget==0 ) return;
|
||||
pPatch = jsonParseFuncArg(ctx, argv[1], 0);
|
||||
if( pPatch ){
|
||||
rc = jsonMergePatch(pTarget, 0, pPatch, 0);
|
||||
rc = jsonMergePatch(pTarget, 0, pPatch, 0, 0);
|
||||
if( rc==JSON_MERGE_OK ){
|
||||
jsonReturnParse(ctx, pTarget);
|
||||
}else if( rc==JSON_MERGE_OOM ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
}else if( rc==JSON_MERGE_TOODEEP ){
|
||||
sqlite3_result_error(ctx, "JSON nested too deep", -1);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -4447,10 +4494,8 @@ static void jsonRemoveFunc(
|
||||
if( JSON_LOOKUP_ISERROR(rc) ){
|
||||
if( rc==JSON_LOOKUP_NOTFOUND ){
|
||||
continue; /* No-op */
|
||||
}else if( rc==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
}
|
||||
goto json_remove_done;
|
||||
}
|
||||
@@ -4547,10 +4592,8 @@ static void jsonTypeFunc(
|
||||
if( JSON_LOOKUP_ISERROR(i) ){
|
||||
if( i==JSON_LOOKUP_NOTFOUND ){
|
||||
/* no-op */
|
||||
}else if( i==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
jsonBadPathError(ctx, zPath, i);
|
||||
}
|
||||
goto json_type_done;
|
||||
}
|
||||
@@ -4808,7 +4851,8 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
if( pStr ){
|
||||
pStr->pCtx = ctx;
|
||||
jsonAppendChar(pStr, ']');
|
||||
jsonAppendRawNZ(pStr, "]", 2);
|
||||
jsonStringTrimOneChar(pStr);
|
||||
if( pStr->eErr ){
|
||||
jsonReturnString(pStr, 0, 0);
|
||||
return;
|
||||
@@ -4931,7 +4975,8 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
|
||||
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
if( pStr ){
|
||||
jsonAppendChar(pStr, '}');
|
||||
jsonAppendRawNZ(pStr, "}", 2);
|
||||
jsonStringTrimOneChar(pStr);
|
||||
pStr->pCtx = ctx;
|
||||
if( pStr->eErr ){
|
||||
jsonReturnString(pStr, 0, 0);
|
||||
|
||||
+11
@@ -4716,6 +4716,17 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_ATOF, const char *z, double *p);
|
||||
**
|
||||
** Test access to the sqlite3AtoF() routine.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_ATOF: {
|
||||
const char *z = va_arg(ap,const char*);
|
||||
double *pR = va_arg(ap,double*);
|
||||
rc = sqlite3AtoF(z,pR);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
|
||||
**
|
||||
|
||||
+14
-2
@@ -2067,8 +2067,20 @@ void sqlite3Pragma(
|
||||
pPrior = pIdx;
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */
|
||||
/* Verify that an index entry exists for the current table row */
|
||||
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
|
||||
pIdx->nColumn); VdbeCoverage(v);
|
||||
jmp2 = sqlite3VdbeAddOp3(v, OP_IFindKey, iIdxCur+j, ckUniq, r1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||
sqlite3MPrintf(db, "index %s stores an imprecise floating-point "
|
||||
"value for row ", pIdx->zName),
|
||||
P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
||||
integrityCheckResultRow(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ckUniq);
|
||||
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeLoadString(v, 3, "row ");
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
||||
sqlite3VdbeLoadString(v, 4, " missing from index ");
|
||||
@@ -2076,7 +2088,7 @@ void sqlite3Pragma(
|
||||
jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
||||
jmp4 = integrityCheckResultRow(v);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeResolveLabel(v, ckUniq);
|
||||
|
||||
/* The OP_IdxRowid opcode is an optimized version of OP_Column
|
||||
** that extracts the rowid off the end of the index record.
|
||||
|
||||
+76
-39
@@ -496,9 +496,11 @@ void sqlite3_str_vappendf(
|
||||
}while( longvalue>0 );
|
||||
}
|
||||
length = (int)(&zOut[nOut-1]-bufpt);
|
||||
while( precision>length ){
|
||||
*(--bufpt) = '0'; /* Zero pad */
|
||||
length++;
|
||||
if( precision>length ){ /* zero pad */
|
||||
int nn = precision-length;
|
||||
bufpt -= nn;
|
||||
memset(bufpt,'0',nn);
|
||||
length = precision;
|
||||
}
|
||||
if( cThousand ){
|
||||
int nn = (length - 1)/3; /* Number of "," to insert */
|
||||
@@ -529,6 +531,7 @@ void sqlite3_str_vappendf(
|
||||
FpDecode s;
|
||||
int iRound;
|
||||
int j;
|
||||
i64 szBufNeeded; /* Size needed to hold the output */
|
||||
|
||||
if( bArgList ){
|
||||
realvalue = getDoubleArg(pArgList);
|
||||
@@ -617,17 +620,15 @@ void sqlite3_str_vappendf(
|
||||
}else{
|
||||
e2 = s.iDP - 1;
|
||||
}
|
||||
bufpt = buf;
|
||||
{
|
||||
i64 szBufNeeded; /* Size of a temporary buffer needed */
|
||||
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
|
||||
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
|
||||
if( szBufNeeded > etBUFSIZE ){
|
||||
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
|
||||
if( bufpt==0 ) return;
|
||||
}
|
||||
|
||||
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+8;
|
||||
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
|
||||
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, szBufNeeded) ){
|
||||
width = length = 0;
|
||||
break;
|
||||
}
|
||||
zOut = bufpt;
|
||||
bufpt = zOut = pAccum->zText + pAccum->nChar;
|
||||
|
||||
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
|
||||
/* The sign in front of the number */
|
||||
if( prefix ){
|
||||
@@ -635,12 +636,24 @@ void sqlite3_str_vappendf(
|
||||
}
|
||||
/* Digits prior to the decimal point */
|
||||
j = 0;
|
||||
assert( s.n>0 );
|
||||
if( e2<0 ){
|
||||
*(bufpt++) = '0';
|
||||
}else{
|
||||
}else if( cThousand ){
|
||||
for(; e2>=0; e2--){
|
||||
*(bufpt++) = j<s.n ? s.z[j++] : '0';
|
||||
if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
|
||||
if( (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
|
||||
}
|
||||
}else{
|
||||
j = e2+1;
|
||||
if( j>s.n ) j = s.n;
|
||||
memcpy(bufpt, s.z, j);
|
||||
bufpt += j;
|
||||
e2 -= j;
|
||||
if( e2>=0 ){
|
||||
memset(bufpt, '0', e2+1);
|
||||
bufpt += e2+1;
|
||||
e2 = -1;
|
||||
}
|
||||
}
|
||||
/* The decimal point */
|
||||
@@ -649,12 +662,26 @@ void sqlite3_str_vappendf(
|
||||
}
|
||||
/* "0" digits after the decimal point but before the first
|
||||
** significant digit of the number */
|
||||
for(e2++; e2<0 && precision>0; precision--, e2++){
|
||||
*(bufpt++) = '0';
|
||||
if( e2<(-1) && precision>0 ){
|
||||
int nn = -1-e2;
|
||||
if( nn>precision ) nn = precision;
|
||||
memset(bufpt, '0', nn);
|
||||
bufpt += nn;
|
||||
precision -= nn;
|
||||
}
|
||||
/* Significant digits after the decimal point */
|
||||
while( (precision--)>0 ){
|
||||
*(bufpt++) = j<s.n ? s.z[j++] : '0';
|
||||
if( precision>0 ){
|
||||
int nn = s.n - j;
|
||||
if( NEVER(nn>precision) ) nn = precision;
|
||||
if( nn>0 ){
|
||||
memcpy(bufpt, s.z+j, nn);
|
||||
bufpt += nn;
|
||||
precision -= nn;
|
||||
}
|
||||
if( precision>0 && !flag_rtz ){
|
||||
memset(bufpt, '0', precision);
|
||||
bufpt += precision;
|
||||
}
|
||||
}
|
||||
/* Remove trailing zeros and the "." if no digits follow the "." */
|
||||
if( flag_rtz && flag_dp ){
|
||||
@@ -684,27 +711,31 @@ void sqlite3_str_vappendf(
|
||||
*(bufpt++) = (char)(exp/10+'0'); /* 10's digit */
|
||||
*(bufpt++) = (char)(exp%10+'0'); /* 1's digit */
|
||||
}
|
||||
*bufpt = 0;
|
||||
|
||||
/* The converted number is in buf[] and zero terminated. Output it.
|
||||
** Note that the number is in the usual order, not reversed as with
|
||||
** integer conversions. */
|
||||
length = (int)(bufpt-zOut);
|
||||
bufpt = zOut;
|
||||
|
||||
/* Special case: Add leading zeros if the flag_zeropad flag is
|
||||
** set and we are not left justified */
|
||||
if( flag_zeropad && !flag_leftjustify && length < width){
|
||||
int i;
|
||||
int nPad = width - length;
|
||||
for(i=width; i>=nPad; i--){
|
||||
bufpt[i] = bufpt[i-nPad];
|
||||
assert( length <= szBufNeeded );
|
||||
if( length<width ){
|
||||
i64 nPad = width - length;
|
||||
if( flag_leftjustify ){
|
||||
memset(bufpt, ' ', nPad);
|
||||
}else if( !flag_zeropad ){
|
||||
memmove(zOut+nPad, zOut, length);
|
||||
memset(zOut, ' ', nPad);
|
||||
}else{
|
||||
int adj = prefix!=0;
|
||||
memmove(zOut+nPad+adj, zOut+adj, length-adj);
|
||||
memset(zOut+adj, '0', nPad);
|
||||
}
|
||||
i = prefix!=0;
|
||||
while( nPad-- ) bufpt[i++] = '0';
|
||||
length = width;
|
||||
}
|
||||
break;
|
||||
pAccum->nChar += length;
|
||||
zOut[length] = 0;
|
||||
|
||||
/* Floating point conversions render directly into the output
|
||||
** buffer. Hence, don't just break out of the switch(). Bypass the
|
||||
** output buffer writing that occurs after the switch() by continuing
|
||||
** to the next character in the format string. */
|
||||
continue;
|
||||
}
|
||||
case etSIZE:
|
||||
if( !bArgList ){
|
||||
@@ -748,11 +779,10 @@ void sqlite3_str_vappendf(
|
||||
i64 nCopyBytes;
|
||||
if( nPrior > precision-1 ) nPrior = precision - 1;
|
||||
nCopyBytes = length*nPrior;
|
||||
if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){
|
||||
sqlite3StrAccumEnlarge(pAccum, nCopyBytes);
|
||||
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, nCopyBytes) ){
|
||||
break;
|
||||
}
|
||||
if( pAccum->accError ) break;
|
||||
sqlite3_str_append(pAccum,
|
||||
sqlite3_str_append(pAccum,
|
||||
&pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
|
||||
precision -= nPrior;
|
||||
nPrior *= 2;
|
||||
@@ -1098,6 +1128,13 @@ int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){
|
||||
return (int)N;
|
||||
}
|
||||
|
||||
int sqlite3StrAccumEnlargeIfNeeded(StrAccum *p, i64 N){
|
||||
if( N + p->nChar >= p->nAlloc ){
|
||||
sqlite3StrAccumEnlarge(p, N);
|
||||
}
|
||||
return p->accError;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append N copies of character c to the given string buffer.
|
||||
*/
|
||||
|
||||
+879
-805
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -1290,6 +1290,12 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
|
||||
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
|
||||
|
||||
/* reserved file-control numbers:
|
||||
** 101
|
||||
** 102
|
||||
** 103
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Mutex Handle
|
||||
@@ -8357,13 +8363,6 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
|
||||
** and Windows.
|
||||
**
|
||||
** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
|
||||
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
|
||||
** implementation is included with the library. In this case the
|
||||
** application must supply a custom mutex implementation using the
|
||||
** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
|
||||
** before calling sqlite3_initialize() or any other public sqlite3_
|
||||
** function that calls sqlite3_initialize().
|
||||
**
|
||||
** ^The sqlite3_mutex_alloc() routine allocates a new
|
||||
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
|
||||
@@ -8718,6 +8717,7 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_TUNE 32
|
||||
#define SQLITE_TESTCTRL_LOGEST 33
|
||||
#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
|
||||
#define SQLITE_TESTCTRL_ATOF 34
|
||||
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
|
||||
|
||||
/*
|
||||
|
||||
+12
-6
@@ -4828,17 +4828,22 @@ struct PrintfArguments {
|
||||
sqlite3_value **apArg; /* The argument values */
|
||||
};
|
||||
|
||||
/*
|
||||
** Maxium number of base-10 digits in an unsigned 64-bit integer
|
||||
*/
|
||||
#define SQLITE_U64_DIGITS 20
|
||||
|
||||
/*
|
||||
** An instance of this object receives the decoding of a floating point
|
||||
** value into an approximate decimal representation.
|
||||
*/
|
||||
struct FpDecode {
|
||||
int n; /* Significant digits in the decode */
|
||||
int iDP; /* Location of the decimal point */
|
||||
char *z; /* Start of significant digits */
|
||||
char zBuf[20]; /* Storage for significant digits */
|
||||
char sign; /* '+' or '-' */
|
||||
char isSpecial; /* 1: Infinity 2: NaN */
|
||||
int n; /* Significant digits in the decode */
|
||||
int iDP; /* Location of the decimal point */
|
||||
char *z; /* Start of significant digits */
|
||||
char zBuf[SQLITE_U64_DIGITS+1]; /* Storage for significant digits */
|
||||
char sign; /* '+' or '-' */
|
||||
char isSpecial; /* 1: Infinity 2: NaN */
|
||||
};
|
||||
|
||||
void sqlite3FpDecode(FpDecode*,double,int,int);
|
||||
@@ -5526,6 +5531,7 @@ char *sqlite3RCStrResize(char*,u64);
|
||||
|
||||
void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
|
||||
int sqlite3StrAccumEnlarge(StrAccum*, i64);
|
||||
int sqlite3StrAccumEnlargeIfNeeded(StrAccum*, i64);
|
||||
char *sqlite3StrAccumFinish(StrAccum*);
|
||||
void sqlite3StrAccumSetError(StrAccum*, u8);
|
||||
void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
|
||||
|
||||
@@ -232,6 +232,10 @@
|
||||
# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
|
||||
# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
|
||||
#endif
|
||||
#if SQLITE_MAX_DEFAULT_PAGE_SIZE<SQLITE_DEFAULT_PAGE_SIZE
|
||||
# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
|
||||
# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_DEFAULT_PAGE_SIZE
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -2136,7 +2136,7 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
|
||||
};
|
||||
|
||||
memset(&qrf, 0, sizeof(qrf));
|
||||
qrf.iVersion = 2;
|
||||
qrf.iVersion = 1;
|
||||
qrf.pzOutput = &zResult;
|
||||
for(i=2; i<objc; i++){
|
||||
const char *zArg = Tcl_GetString(objv[i]);
|
||||
|
||||
+1
-1
@@ -734,7 +734,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
}
|
||||
if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){
|
||||
if( pParse->zErrMsg==0 ){
|
||||
pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
|
||||
pParse->zErrMsg = sqlite3DbStrDup(db, sqlite3ErrStr(pParse->rc));
|
||||
}
|
||||
if( (pParse->prepFlags & SQLITE_PREPARE_DONT_LOG)==0 ){
|
||||
sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
|
||||
|
||||
+244
-121
@@ -465,11 +465,12 @@ u8 sqlite3StrIHash(const char *z){
|
||||
*/
|
||||
static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv))
|
||||
__uint128_t r = (__int128_t)a * b;
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
|
||||
&& !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
__uint128_t r = (__uint128_t)a * b;
|
||||
*pLo = (u64)r;
|
||||
return (u64)(r>>64);
|
||||
#elif defined(_MSC_VER) && defined(_M_X64)
|
||||
#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
*pLo = a*b;
|
||||
return __umulh(a, b);
|
||||
#else
|
||||
@@ -499,6 +500,22 @@ static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
|
||||
** The lower 64 bits of A*B are discarded.
|
||||
*/
|
||||
static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
|
||||
&& !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
__uint128_t r = (__uint128_t)a * b;
|
||||
r += ((__uint128_t)aLo * b) >> 32;
|
||||
*pLo = (r>>32)&0xffffffff;
|
||||
return r>>64;
|
||||
#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
u64 r1_hi = __umulh(a,b);
|
||||
u64 r1_lo = a*b;
|
||||
u64 r2 = (__umulh((u64)aLo,b)<<32) + ((aLo*b)>>32);
|
||||
u64 t = r1_lo + r2;
|
||||
if( t<r1_lo ) r1_hi++;
|
||||
*pLo = t>>32;
|
||||
return r1_hi;
|
||||
#else
|
||||
u64 x2 = a>>32;
|
||||
u64 x1 = a&0xffffffff;
|
||||
u64 x0 = aLo;
|
||||
@@ -520,6 +537,7 @@ static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
|
||||
r3 += r2>>32;
|
||||
*pLo = r2&0xffffffff;
|
||||
return (r4<<32) + r3;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -707,7 +725,8 @@ static int pwr2to10(int p){ return (p*78913) >> 18; }
|
||||
** Count leading zeros for a 64-bit unsigned integer.
|
||||
*/
|
||||
static int countLeadingZeros(u64 m){
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
return __builtin_clzll(m);
|
||||
#else
|
||||
int n = 0;
|
||||
@@ -749,46 +768,50 @@ static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){
|
||||
|
||||
/*
|
||||
** Return an IEEE754 floating point value that approximates d*pow(10,p).
|
||||
**
|
||||
** The (current) algorithm is adapted from the work of Ross Cox at
|
||||
** https://github.com/rsc/fpfmt
|
||||
*/
|
||||
static double sqlite3Fp10Convert2(u64 d, int p){
|
||||
int b, lp, e, adj, s;
|
||||
u32 pwr10l, mid1;
|
||||
u64 pwr10h, x, hi, lo, sticky, u, m;
|
||||
double r;
|
||||
if( p<POWERSOF10_FIRST ) return 0.0;
|
||||
if( p>POWERSOF10_LAST ) return INFINITY;
|
||||
int b = 64 - countLeadingZeros(d);
|
||||
int lp = pwr10to2(p);
|
||||
int e = 53 - b - lp;
|
||||
b = 64 - countLeadingZeros(d);
|
||||
lp = pwr10to2(p);
|
||||
e = 53 - b - lp;
|
||||
if( e > 1074 ){
|
||||
if( e>=1130 ) return 0.0;
|
||||
e = 1074;
|
||||
}
|
||||
int s = -(e-(64-b) + lp + 3);
|
||||
u32 pwr10l;
|
||||
u64 pwr10h = powerOfTen(p, &pwr10l);
|
||||
s = -(e-(64-b) + lp + 3);
|
||||
pwr10h = powerOfTen(p, &pwr10l);
|
||||
if( pwr10l!=0 ){
|
||||
pwr10h++;
|
||||
pwr10l = ~pwr10l;
|
||||
}
|
||||
u64 x = d<<(64-b);
|
||||
u64 lo;
|
||||
u64 hi = sqlite3Multiply128(x,pwr10h,&lo);
|
||||
u32 mid1 = lo>>32;
|
||||
u64 sticky = 1;
|
||||
x = d<<(64-b);
|
||||
hi = sqlite3Multiply128(x,pwr10h,&lo);
|
||||
mid1 = lo>>32;
|
||||
sticky = 1;
|
||||
if( (hi & (U64_BIT(s)-1))==0 ) {
|
||||
u32 mid2 = sqlite3Multiply128(x,((u64)pwr10l)<<32,&lo)>>32;
|
||||
sticky = (mid1-mid2 > 1);
|
||||
hi -= mid1 < mid2;
|
||||
}
|
||||
u64 u = (hi>>s) | sticky;
|
||||
int adj = (u >= U64_BIT(55)-2);
|
||||
u = (hi>>s) | sticky;
|
||||
adj = (u >= U64_BIT(55)-2);
|
||||
if( adj ){
|
||||
u = (u>>adj) | (u&1);
|
||||
e -= adj;
|
||||
}
|
||||
u64 m = (u + 1 + ((u>>2)&1)) >> 2;
|
||||
m = (u + 1 + ((u>>2)&1)) >> 2;
|
||||
if( e<=(-972) ) return INFINITY;
|
||||
if((m & U64_BIT(52)) != 0){
|
||||
m = (m & ~U64_BIT(52)) | ((u64)(1075-e)<<52);
|
||||
}
|
||||
double r;
|
||||
memcpy(&r,&m,8);
|
||||
return r;
|
||||
}
|
||||
@@ -799,134 +822,161 @@ static double sqlite3Fp10Convert2(u64 d, int p){
|
||||
**
|
||||
** z[] must be UTF-8 and zero-terminated.
|
||||
**
|
||||
** Return TRUE if the result is a valid real number (or integer) and FALSE
|
||||
** if the string is empty or contains extraneous text. More specifically
|
||||
** return
|
||||
** 1 => The input string is a pure integer
|
||||
** 2 or more => The input has a decimal point or eNNN clause
|
||||
** 0 or less => The input string is not a valid number
|
||||
** -1 => Not a valid number, but has a valid prefix which
|
||||
** includes a decimal point and/or an eNNN clause
|
||||
** Return positive if the result is a valid real number (or integer) and
|
||||
** zero or negative if the string is empty or contains extraneous text.
|
||||
** Lower bits of the return value contain addition information about the
|
||||
** parse:
|
||||
**
|
||||
** Valid numbers are in one of these formats:
|
||||
** bit 0 => Set for any valid input
|
||||
** bit 1 => Input contains a decimal point or eNNN clause
|
||||
** This bit is zero if the input is an integer
|
||||
** bit 2 => The input is exactly 0.0, not an underflow from
|
||||
** some value near zero
|
||||
** bit 3 => More than 19 significant digits in the input
|
||||
**
|
||||
** If the input contains a syntax error but begins with text that might
|
||||
** be a valid number of some kind, then the result is negative. The
|
||||
** result is only zero if no prefix of the input could be interpreted as
|
||||
** a number.
|
||||
**
|
||||
** Leading and trailing whitespace is ignored. Valid numbers are in
|
||||
** one of the formats below:
|
||||
**
|
||||
** [+-]digits[E[+-]digits]
|
||||
** [+-]digits.[digits][E[+-]digits]
|
||||
** [+-].digits[E[+-]digits]
|
||||
**
|
||||
** Leading and trailing whitespace is ignored for the purpose of determining
|
||||
** validity.
|
||||
**
|
||||
** If some prefix of the input string is a valid number, this routine
|
||||
** returns FALSE but it still converts the prefix and writes the result
|
||||
** into *pResult.
|
||||
** Algorithm sketch: Compute an unsigned 64-bit integer s and a base-10
|
||||
** exponent d such that the value encoding by the input is s*pow(10,d).
|
||||
** Then invoke sqlite3Fp10Convert2() to calculated the closest possible
|
||||
** IEEE754 double. The sign is added back afterwards, if the input string
|
||||
** starts with a "-". The use of an unsigned 64-bit s mantissa means that
|
||||
** only about the first 19 significant digits of the input can contribute
|
||||
** to the result. This can result in suboptimal rounding decisions when
|
||||
** correct rounding requires more than 19 input digits. For example,
|
||||
** this routine renders "3500000000000000.2500001" as
|
||||
** 3500000000000000.0 instead of 3500000000000000.5 because the decision
|
||||
** to round up instead of using banker's rounding to round down is determined
|
||||
** by the 23rd significant digit, which this routine ignores. It is not
|
||||
** possible to do better without some kind of BigNum.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable : 4756)
|
||||
#endif
|
||||
int sqlite3AtoF(const char *z, double *pResult){
|
||||
int sqlite3AtoF(const char *zIn, double *pResult){
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/* sign * significand * (10 ^ (esign * exponent)) */
|
||||
int neg = 0; /* True for a negative value */
|
||||
u64 s = 0; /* mantissa */
|
||||
int d = 0; /* Value is s * pow(10,d) */
|
||||
int nDigit = 0; /* Number of digits processed */
|
||||
int eType = 1; /* 1: pure integer, 2+: fractional */
|
||||
const unsigned char *z = (const unsigned char*)zIn;
|
||||
int neg = 0; /* True for a negative value */
|
||||
u64 s = 0; /* mantissa */
|
||||
int d = 0; /* Value is s * pow(10,d) */
|
||||
int mState = 0; /* 1: digit seen 2: fp 4: hard-zero */
|
||||
unsigned v; /* Value of a single digit */
|
||||
|
||||
*pResult = 0.0; /* Default return value, in case of an error */
|
||||
|
||||
/* skip leading spaces */
|
||||
while( sqlite3Isspace(*z) ) z++;
|
||||
|
||||
/* get sign of significand */
|
||||
if( *z=='-' ){
|
||||
start_of_text:
|
||||
if( (v = (unsigned)z[0] - '0')<10 ){
|
||||
parse_integer_part:
|
||||
mState = 1;
|
||||
s = v;
|
||||
z++;
|
||||
while( (v = (unsigned)z[0] - '0')<10 ){
|
||||
s = s*10 + v;
|
||||
z++;
|
||||
if( s>=(LARGEST_UINT64-9)/10 ){
|
||||
mState = 9;
|
||||
while( sqlite3Isdigit(z[0]) ){ z++; d++; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if( z[0]=='-' ){
|
||||
neg = 1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part;
|
||||
}else if( z[0]=='+' ){
|
||||
z++;
|
||||
}
|
||||
|
||||
/* copy max significant digits to significand */
|
||||
while( sqlite3Isdigit(*z) ){
|
||||
s = s*10 + (*z - '0');
|
||||
z++; nDigit++;
|
||||
if( s>=((LARGEST_INT64-9)/10) ){
|
||||
/* skip non-significant significand digits
|
||||
** (increase exponent by d to shift decimal left) */
|
||||
while( sqlite3Isdigit(*z) ){ z++; d++; }
|
||||
}
|
||||
if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part;
|
||||
}else if( sqlite3Isspace(z[0]) ){
|
||||
do{ z++; }while( sqlite3Isspace(z[0]) );
|
||||
goto start_of_text;
|
||||
}else{
|
||||
s = 0;
|
||||
}
|
||||
|
||||
/* if decimal point is present */
|
||||
if( *z=='.' ){
|
||||
z++;
|
||||
eType++;
|
||||
/* copy digits from after decimal to significand
|
||||
** (decrease exponent by d to shift decimal right) */
|
||||
while( sqlite3Isdigit(*z) ){
|
||||
if( s<((LARGEST_INT64-9)/10) ){
|
||||
s = s*10 + (*z - '0');
|
||||
d--;
|
||||
nDigit++;
|
||||
}
|
||||
z++;
|
||||
if( sqlite3Isdigit(z[0]) ){
|
||||
mState |= 1;
|
||||
do{
|
||||
if( s<(LARGEST_UINT64-9)/10 ){
|
||||
s = s*10 + z[0] - '0';
|
||||
d--;
|
||||
}else{
|
||||
mState = 11;
|
||||
}
|
||||
}while( sqlite3Isdigit(*++z) );
|
||||
}else if( mState==0 ){
|
||||
*pResult = 0.0;
|
||||
return 0;
|
||||
}
|
||||
mState |= 2;
|
||||
}else if( mState==0 ){
|
||||
*pResult = 0.0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if exponent is present */
|
||||
if( *z=='e' || *z=='E' ){
|
||||
int esign = 1; /* sign of exponent */
|
||||
int esign;
|
||||
z++;
|
||||
eType++;
|
||||
|
||||
|
||||
/* get sign of exponent */
|
||||
if( *z=='-' ){
|
||||
esign = -1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
z++;
|
||||
}else{
|
||||
esign = +1;
|
||||
if( *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
}
|
||||
/* copy digits to exponent */
|
||||
if( sqlite3Isdigit(*z) ){
|
||||
int exp = *z - '0';
|
||||
if( (v = (unsigned)z[0] - '0')<10 ){
|
||||
int exp = v;
|
||||
z++;
|
||||
while( sqlite3Isdigit(*z) ){
|
||||
exp = exp<10000 ? (exp*10 + (*z - '0')) : 10000;
|
||||
mState |= 2;
|
||||
while( (v = (unsigned)z[0] - '0')<10 ){
|
||||
exp = exp<10000 ? (exp*10 + v) : 10000;
|
||||
z++;
|
||||
}
|
||||
d += esign*exp;
|
||||
}else{
|
||||
eType = -1;
|
||||
z--; /* Leave z[0] at 'e' or '+' or '-',
|
||||
** so that the return is 0 or -1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* skip trailing spaces */
|
||||
while( sqlite3Isspace(*z) ) z++;
|
||||
|
||||
/* Zero is a special case */
|
||||
/* Convert s*pow(10,d) into real */
|
||||
if( s==0 ){
|
||||
*pResult = neg ? -0.0 : +0.0;
|
||||
*pResult = 0.0;
|
||||
mState |= 4;
|
||||
}else{
|
||||
*pResult = sqlite3Fp10Convert2(s,d);
|
||||
if( neg ) *pResult = -*pResult;
|
||||
assert( !sqlite3IsNaN(*pResult) );
|
||||
}
|
||||
if( neg ) *pResult = -*pResult;
|
||||
assert( !sqlite3IsNaN(*pResult) );
|
||||
|
||||
/* return true if number and no extra non-whitespace characters after */
|
||||
if( z[0]==0 && nDigit>0 ){
|
||||
return eType;
|
||||
}else if( eType>=2 && nDigit>0 ){
|
||||
return -1;
|
||||
}else{
|
||||
return 0;
|
||||
if( z[0]==0 ){
|
||||
return mState;
|
||||
}
|
||||
if( sqlite3Isspace(z[0]) ){
|
||||
do{ z++; }while( sqlite3Isspace(*z) );
|
||||
if( z[0]==0 ){
|
||||
return mState;
|
||||
}
|
||||
}
|
||||
return 0xfffffff0 | mState;
|
||||
#else
|
||||
return !sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8);
|
||||
return sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8)==0;
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(default : 4756)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Digit pairs used to convert a U64 or I64 into text, two digits
|
||||
@@ -948,6 +998,69 @@ static const union {
|
||||
"90919293949596979899"
|
||||
};
|
||||
|
||||
/*
|
||||
** ARMv6, ARMv7, PPC32 are known to not support hardware u64 division.
|
||||
*/
|
||||
#if (defined(__arm__) && !defined(__aarch64__)) || \
|
||||
(defined(__ppc__) && !defined(__ppc64__))
|
||||
# define SQLITE_AVOID_U64_DIVIDE 1
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_AVOID_U64_DIVIDE
|
||||
/*
|
||||
** Render an unsigned 64-bit integer as text onto the end of a 2-byte
|
||||
** aligned buffer that is SQLITE_U64_DIGIT+1 bytes long. The last byte
|
||||
** of the buffer will be filled with a \000 byte.
|
||||
**
|
||||
** Return the index into the buffer of the first byte.
|
||||
**
|
||||
** This routine is used on platforms where u64-division is slow because
|
||||
** it is not available in hardware and has to be emulated in software.
|
||||
** It seeks to minimize the number of u64 divisions and use u32 divisions
|
||||
** instead. It is slower on platforms that have hardware u64 division,
|
||||
** but much faster on platforms that do not.
|
||||
*/
|
||||
static int sqlite3UInt64ToText(u64 v, char *zOut){
|
||||
u32 x32, kk;
|
||||
int i;
|
||||
zOut[SQLITE_U64_DIGITS] = 0;
|
||||
i = SQLITE_U64_DIGITS;
|
||||
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[0]) );
|
||||
assert( TWO_BYTE_ALIGNMENT(zOut) );
|
||||
while( (v>>32)!=0 ){
|
||||
u32 y, x0, x1, y0, y1;
|
||||
x32 = v % 100000000;
|
||||
v = v / 100000000;
|
||||
y = x32 % 10000;
|
||||
x32 /= 10000;
|
||||
x1 = x32 / 100;
|
||||
x0 = x32 % 100;
|
||||
y1 = y / 100;
|
||||
y0 = y % 100;
|
||||
assert( i>=8 );
|
||||
i -= 8;
|
||||
*(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[x1*2];
|
||||
*(u16*)(&zOut[i+2]) = *(u16*)&sqlite3DigitPairs.a[x0*2];
|
||||
*(u16*)(&zOut[i+4]) = *(u16*)&sqlite3DigitPairs.a[y1*2];
|
||||
*(u16*)(&zOut[i+6]) = *(u16*)&sqlite3DigitPairs.a[y0*2];
|
||||
}
|
||||
x32 = v;
|
||||
while( x32>=10 ){
|
||||
kk = x32 % 100;
|
||||
x32 = x32 / 100;
|
||||
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk*2]) );
|
||||
assert( i>=2 );
|
||||
i -= 2;
|
||||
assert( TWO_BYTE_ALIGNMENT(&zOut[i]) );
|
||||
*(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[kk*2];
|
||||
}
|
||||
if( x32 ){
|
||||
assert( i>0 );
|
||||
zOut[--i] = x32 + '0';
|
||||
}
|
||||
return i;
|
||||
}
|
||||
#endif /* defined(SQLITE_AVOID_U64_DIVIDE) */
|
||||
|
||||
/*
|
||||
** Render an signed 64-bit integer as text. Store the result in zOut[] and
|
||||
@@ -961,7 +1074,7 @@ int sqlite3Int64ToText(i64 v, char *zOut){
|
||||
int i;
|
||||
u64 x;
|
||||
union {
|
||||
char a[23];
|
||||
char a[SQLITE_U64_DIGITS+1];
|
||||
u16 forceAlignment;
|
||||
} u;
|
||||
if( v>0 ){
|
||||
@@ -973,6 +1086,9 @@ int sqlite3Int64ToText(i64 v, char *zOut){
|
||||
}else{
|
||||
x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
|
||||
}
|
||||
#ifdef SQLITE_AVOID_U64_DIVIDE
|
||||
i = sqlite3UInt64ToText(x, u.a);
|
||||
#else
|
||||
i = sizeof(u.a)-1;
|
||||
u.a[i] = 0;
|
||||
while( x>=10 ){
|
||||
@@ -986,6 +1102,7 @@ int sqlite3Int64ToText(i64 v, char *zOut){
|
||||
if( x ){
|
||||
u.a[--i] = x + '0';
|
||||
}
|
||||
#endif /* SQLITE_AVOID_U64_DIVIDE */
|
||||
if( v<0 ) u.a[--i] = '-';
|
||||
memcpy(zOut, &u.a[i], sizeof(u.a)-i);
|
||||
return sizeof(u.a)-1-i;
|
||||
@@ -1042,8 +1159,8 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
int incr;
|
||||
u64 u = 0;
|
||||
int neg = 0; /* assume positive */
|
||||
int i;
|
||||
int c = 0;
|
||||
int i, j;
|
||||
unsigned int c = 0;
|
||||
int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
|
||||
int rc; /* Baseline return code */
|
||||
const char *zStart;
|
||||
@@ -1071,8 +1188,8 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
}
|
||||
zStart = zNum;
|
||||
while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
|
||||
for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
|
||||
u = u*10 + c - '0';
|
||||
for(i=0; &zNum[i]<zEnd && (c=(unsigned)zNum[i]-'0')<=9; i+=incr){
|
||||
u = u*10 + c;
|
||||
}
|
||||
testcase( i==18*incr );
|
||||
testcase( i==19*incr );
|
||||
@@ -1109,14 +1226,14 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
return rc;
|
||||
}else{
|
||||
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
|
||||
c = i>19*incr ? 1 : compare2pow63(zNum, incr);
|
||||
if( c<0 ){
|
||||
j = i>19*incr ? 1 : compare2pow63(zNum, incr);
|
||||
if( j<0 ){
|
||||
/* zNum is less than 9223372036854775808 so it fits */
|
||||
assert( u<=LARGEST_INT64 );
|
||||
return rc;
|
||||
}else{
|
||||
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
|
||||
if( c>0 ){
|
||||
if( j>0 ){
|
||||
/* zNum is greater than 9223372036854775808 so it overflows */
|
||||
return 2;
|
||||
}else{
|
||||
@@ -1305,37 +1422,43 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
|
||||
/* Extract significant digits, start at the right-most slot in p->zBuf
|
||||
** and working back to the right. "i" keeps track of the next slot in
|
||||
** which to store a digit. */
|
||||
i = sizeof(p->zBuf)-1;
|
||||
zBuf = p->zBuf;
|
||||
assert( sizeof(p->zBuf)==SQLITE_U64_DIGITS+1 );
|
||||
assert( v>0 );
|
||||
zBuf = p->zBuf;
|
||||
#ifdef SQLITE_AVOID_U64_DIVIDE
|
||||
i = sqlite3UInt64ToText(v, zBuf);
|
||||
#else
|
||||
i = SQLITE_U64_DIGITS;
|
||||
while( v>=10 ){
|
||||
int kk = (v%100)*2;
|
||||
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) );
|
||||
assert( TWO_BYTE_ALIGNMENT(&zBuf[i-1]) );
|
||||
*(u16*)(&zBuf[i-1]) = *(u16*)&sqlite3DigitPairs.a[kk];
|
||||
assert( TWO_BYTE_ALIGNMENT(&zBuf[i]) );
|
||||
assert( i-2>=0 );
|
||||
*(u16*)(&zBuf[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk];
|
||||
i -= 2;
|
||||
v /= 100;
|
||||
}
|
||||
if( v ){
|
||||
assert( v<10 );
|
||||
zBuf[i--] = v + '0';
|
||||
assert( i>0 );
|
||||
zBuf[--i] = v + '0';
|
||||
}
|
||||
assert( i>=0 && i<sizeof(p->zBuf)-1 );
|
||||
n = sizeof(p->zBuf) - 1 - i; /* Total number of digits extracted */
|
||||
#endif /* SQLITE_AVOID_U64_DIVIDE */
|
||||
assert( i>=0 && i<SQLITE_U64_DIGITS );
|
||||
n = SQLITE_U64_DIGITS - i; /* Total number of digits extracted */
|
||||
assert( n>0 );
|
||||
assert( n<sizeof(p->zBuf) );
|
||||
testcase( n==sizeof(p->zBuf)-1 );
|
||||
assert( n<=SQLITE_U64_DIGITS );
|
||||
p->iDP = n + exp;
|
||||
if( iRound<=0 ){
|
||||
iRound = p->iDP - iRound;
|
||||
if( iRound==0 && zBuf[i+1]>='5' ){
|
||||
if( iRound==0 && zBuf[i]>='5' ){
|
||||
iRound = 1;
|
||||
zBuf[i--] = '0';
|
||||
zBuf[--i] = '0';
|
||||
n++;
|
||||
p->iDP++;
|
||||
}
|
||||
}
|
||||
z = &zBuf[i+1]; /* z points to the first digit */
|
||||
z = &zBuf[i]; /* z points to the first digit */
|
||||
if( iRound>0 && (iRound<n || n>mxRound) ){
|
||||
if( iRound>mxRound ) iRound = mxRound;
|
||||
if( iRound==17 ){
|
||||
@@ -1362,7 +1485,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
|
||||
int jj, kk;
|
||||
u64 v2;
|
||||
assert( z[0]!='0' );
|
||||
for(jj=14; z[jj-1]=='0'; jj--){}
|
||||
for(jj=13; z[jj-1]=='0'; jj--){}
|
||||
v2 = z[0] - '0';
|
||||
for(kk=1; kk<jj; kk++) v2 = (v2*10) + z[kk] - '0';
|
||||
if( r==sqlite3Fp10Convert2(v2, exp + n - jj) ){
|
||||
|
||||
+75
-12
@@ -355,9 +355,9 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
|
||||
double rValue;
|
||||
int rc;
|
||||
assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str );
|
||||
rValue = sqlite3MemRealValueRC(pRec, &rc);
|
||||
rc = sqlite3MemRealValueRC(pRec, &rValue);
|
||||
if( rc<=0 ) return;
|
||||
if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){
|
||||
if( (rc&2)==0 && alsoAnInt(pRec, rValue, &pRec->u.i) ){
|
||||
pRec->flags |= MEM_Int;
|
||||
}else{
|
||||
pRec->u.r = rValue;
|
||||
@@ -473,15 +473,15 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
|
||||
pMem->u.i = 0;
|
||||
return MEM_Int;
|
||||
}
|
||||
pMem->u.r = sqlite3MemRealValueRC(pMem, &rc);
|
||||
rc = sqlite3MemRealValueRC(pMem, &pMem->u.r);
|
||||
if( rc<=0 ){
|
||||
if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){
|
||||
if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){
|
||||
pMem->u.i = ix;
|
||||
return MEM_Int;
|
||||
}else{
|
||||
return MEM_Real;
|
||||
}
|
||||
}else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){
|
||||
}else if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){
|
||||
pMem->u.i = ix;
|
||||
return MEM_Int;
|
||||
}
|
||||
@@ -6622,13 +6622,15 @@ case OP_SorterInsert: { /* in2 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IdxDelete P1 P2 P3 * *
|
||||
/* Opcode: IdxDelete P1 P2 P3 P4 *
|
||||
** Synopsis: key=r[P2@P3]
|
||||
**
|
||||
** The content of P3 registers starting at register P2 form
|
||||
** an unpacked index key. This opcode removes that entry from the
|
||||
** index opened by cursor P1.
|
||||
**
|
||||
** P4 is a pointer to an Index structure.
|
||||
**
|
||||
** Raise an SQLITE_CORRUPT_INDEX error if no matching index entry is found
|
||||
** and not in writable_schema mode.
|
||||
*/
|
||||
@@ -6653,13 +6655,22 @@ case OP_IdxDelete: {
|
||||
r.aMem = &aMem[pOp->p2];
|
||||
rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( res==0 ){
|
||||
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
}else if( !sqlite3WritableSchema(db) ){
|
||||
rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption");
|
||||
goto abort_due_to_error;
|
||||
if( res!=0 ){
|
||||
rc = sqlite3VdbeFindIndexKey(pCrsr, pOp->p4.pIdx, &r, &res, 0);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
if( res!=0 ){
|
||||
if( !sqlite3WritableSchema(db) ){
|
||||
rc = sqlite3ReportError(
|
||||
SQLITE_CORRUPT_INDEX, __LINE__, "index corruption");
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->seekResult = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
assert( pC->deferredMoveto==0 );
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->seekResult = 0;
|
||||
@@ -7286,6 +7297,58 @@ case OP_IntegrityCk: {
|
||||
sqlite3VdbeChangeEncoding(pIn1, encoding);
|
||||
goto check_for_interrupt;
|
||||
}
|
||||
|
||||
/* Opcode: IFindKey P1 P2 P3 P4 *
|
||||
**
|
||||
** This instruction always follows an OP_Found with the same P1, P2 and P3
|
||||
** values as this instruction and a non-zero P4 value. The P4 value to
|
||||
** this opcode is of type P4_INDEX and contains a pointer to the Index
|
||||
** object of for the index being searched.
|
||||
**
|
||||
** This opcode uses sqlite3VdbeFindIndexKey() to search around the current
|
||||
** cursor location for an index key that exactly matches all fields that
|
||||
** are not indexed expressions or references to VIRTUAL generated columns,
|
||||
** and either exactly match or are real numbers that are within 2 ULPs of
|
||||
** each other if the don't match.
|
||||
**
|
||||
** To put it another way, this opcode looks for nearby index entries that
|
||||
** are very close to the search key, but which might have small differences
|
||||
** in floating-point values that come via an expression.
|
||||
**
|
||||
** If no nearby alternative entry is found in cursor P1, then jump to P2.
|
||||
** But if a close match is found, fall through.
|
||||
**
|
||||
** This opcode is used by PRAGMA integrity_check to help distinguish
|
||||
** between truely corrupt indexes and expression indexes that are holding
|
||||
** floating-point values that are off by one or two ULPs.
|
||||
*/
|
||||
case OP_IFindKey: { /* jump, in3 */
|
||||
VdbeCursor *pC;
|
||||
int res;
|
||||
UnpackedRecord r;
|
||||
|
||||
assert( pOp[-1].opcode==OP_Found );
|
||||
assert( pOp[-1].p1==pOp->p1 );
|
||||
assert( pOp[-1].p3==pOp->p3 );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pOp->p4type==P4_INDEX );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable==0 );
|
||||
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.aMem = &aMem[pOp->p3];
|
||||
r.nField = pOp->p4.pIdx->nColumn;
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
|
||||
rc = sqlite3VdbeFindIndexKey(pC->uc.pCursor, pOp->p4.pIdx, &r, &res, 1);
|
||||
if( rc || res!=0 ){
|
||||
rc = SQLITE_OK;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
pC->nullRow = 0;
|
||||
break;
|
||||
};
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
|
||||
/* Opcode: RowSetAdd P1 P2 * * *
|
||||
|
||||
+15
-13
@@ -75,6 +75,7 @@ struct VdbeOp {
|
||||
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
|
||||
Table *pTab; /* Used when p4type is P4_TABLE */
|
||||
SubrtnSig *pSubrtnSig; /* Used when p4type is P4_SUBRTNSIG */
|
||||
Index *pIdx; /* Used when p4type is P4_INDEX */
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
Expr *pExpr; /* Used when p4type is P4_EXPR */
|
||||
#endif
|
||||
@@ -129,20 +130,21 @@ typedef struct VdbeOpList VdbeOpList;
|
||||
#define P4_INT32 (-3) /* P4 is a 32-bit signed integer */
|
||||
#define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */
|
||||
#define P4_TABLE (-5) /* P4 is a pointer to a Table structure */
|
||||
#define P4_INDEX (-6) /* P4 is a pointer to an Index structure */
|
||||
/* Above do not own any resources. Must free those below */
|
||||
#define P4_FREE_IF_LE (-6)
|
||||
#define P4_DYNAMIC (-6) /* Pointer to memory from sqliteMalloc() */
|
||||
#define P4_FUNCDEF (-7) /* P4 is a pointer to a FuncDef structure */
|
||||
#define P4_KEYINFO (-8) /* P4 is a pointer to a KeyInfo structure */
|
||||
#define P4_EXPR (-9) /* P4 is a pointer to an Expr tree */
|
||||
#define P4_MEM (-10) /* P4 is a pointer to a Mem* structure */
|
||||
#define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */
|
||||
#define P4_REAL (-12) /* P4 is a 64-bit floating point value */
|
||||
#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
|
||||
#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
|
||||
#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */
|
||||
#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */
|
||||
#define P4_SUBRTNSIG (-17) /* P4 is a SubrtnSig pointer */
|
||||
#define P4_FREE_IF_LE (-7)
|
||||
#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */
|
||||
#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */
|
||||
#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */
|
||||
#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */
|
||||
#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */
|
||||
#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */
|
||||
#define P4_REAL (-13) /* P4 is a 64-bit floating point value */
|
||||
#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */
|
||||
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
|
||||
#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */
|
||||
#define P4_TABLEREF (-17) /* Like P4_TABLE, but reference counted */
|
||||
#define P4_SUBRTNSIG (-18) /* P4 is a SubrtnSig pointer */
|
||||
|
||||
/* Error message codes for OP_Halt */
|
||||
#define P5_ConstraintNotNull 1
|
||||
|
||||
+2
-1
@@ -656,7 +656,7 @@ int sqlite3IntFloatCompare(i64,double);
|
||||
i64 sqlite3VdbeIntValue(const Mem*);
|
||||
int sqlite3VdbeMemIntegerify(Mem*);
|
||||
double sqlite3VdbeRealValue(Mem*);
|
||||
SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem*, int*);
|
||||
int sqlite3MemRealValueRC(Mem*, double*);
|
||||
int sqlite3VdbeBooleanValue(Mem*, int ifNull);
|
||||
void sqlite3VdbeIntegerAffinity(Mem*);
|
||||
int sqlite3VdbeMemRealify(Mem*);
|
||||
@@ -687,6 +687,7 @@ void sqlite3VdbePreUpdateHook(
|
||||
Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int);
|
||||
#endif
|
||||
int sqlite3VdbeTransferError(Vdbe *p);
|
||||
int sqlite3VdbeFindIndexKey(BtCursor*, Index*, UnpackedRecord*, int*, int);
|
||||
|
||||
int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
|
||||
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
|
||||
|
||||
+221
@@ -2003,6 +2003,10 @@ char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
|
||||
zP4 = pOp->p4.pTab->zName;
|
||||
break;
|
||||
}
|
||||
case P4_INDEX: {
|
||||
zP4 = pOp->p4.pIdx->zName;
|
||||
break;
|
||||
}
|
||||
case P4_SUBRTNSIG: {
|
||||
SubrtnSig *pSig = pOp->p4.pSubrtnSig;
|
||||
sqlite3_str_appendf(&x, "subrtnsig:%d,%s", pSig->selId, pSig->zAff);
|
||||
@@ -5393,6 +5397,223 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper function for vdbeIsMatchingIndexKey(). Return true if column
|
||||
** iCol should be ignored when comparing a record with a record from
|
||||
** an index on disk. The field should be ignored if:
|
||||
**
|
||||
** * the corresponding bit in mask is set, and
|
||||
** * either:
|
||||
** - bIntegrity is false, or
|
||||
** - the two Mem values are both real values that differ by
|
||||
** BTREE_ULPDISTORTION or fewer ULPs.
|
||||
*/
|
||||
static int vdbeSkipField(
|
||||
Bitmask mask, /* Mask of indexed expression fields */
|
||||
int iCol, /* Column of index being considered */
|
||||
Mem *pMem1, /* Expected index value */
|
||||
Mem *pMem2, /* Actual indexed value */
|
||||
int bIntegrity /* True if running PRAGMA integrity_check */
|
||||
){
|
||||
#define BTREE_ULPDISTORTION 2
|
||||
if( iCol>=BMS || (mask & MASKBIT(iCol))==0 ) return 0;
|
||||
if( bIntegrity==0 ) return 1;
|
||||
if( (pMem1->flags & MEM_Real) && (pMem2->flags & MEM_Real) ){
|
||||
u64 m1, m2;
|
||||
memcpy(&m1,&pMem1->u.r,8);
|
||||
memcpy(&m2,&pMem2->u.r,8);
|
||||
if( (m1<m2 ? m2-m1 : m1-m2) <= BTREE_ULPDISTORTION ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function compares the unpacked record with the current key that
|
||||
** cursor pCur points to. If bInt is false, all fields for which the
|
||||
** corresponding bit in parameter "mask" is set are ignored. Or, if
|
||||
** bInt is true, then a difference of BTREE_ULPDISTORTION or fewer ULPs
|
||||
** in real values is overlooked for fields with the corresponding bit
|
||||
** set in mask.
|
||||
**
|
||||
** Return the usual less than zero, zero, or greater than zero if the
|
||||
** remaining fields of the cursor cursor key are less than, equal to or
|
||||
** greater than those in (*p).
|
||||
*/
|
||||
static int vdbeIsMatchingIndexKey(
|
||||
BtCursor *pCur, /* Cursor open on index */
|
||||
int bInt, /* True for integrity_check-style search */
|
||||
Bitmask mask, /* Mask of columns to skip */
|
||||
UnpackedRecord *p, /* Index key being deleted */
|
||||
int *piRes /* 0 for a match, non-zero for not a match */
|
||||
){
|
||||
u8 *aRec = 0;
|
||||
u32 nRec = 0;
|
||||
Mem mem;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
mem.enc = p->pKeyInfo->enc;
|
||||
mem.db = p->pKeyInfo->db;
|
||||
nRec = sqlite3BtreePayloadSize(pCur);
|
||||
if( nRec>0x7fffffff ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
/* Allocate 5 extra bytes at the end of the buffer. This allows the
|
||||
** getVarint32() call below to read slightly past the end of the buffer
|
||||
** if the record is corrupt. */
|
||||
aRec = sqlite3MallocZero(nRec+5);
|
||||
if( aRec==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
}else{
|
||||
rc = sqlite3BtreePayload(pCur, 0, nRec, aRec);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
u32 szHdr = 0; /* Size of record header in bytes */
|
||||
u32 idxHdr = 0; /* Current index in header */
|
||||
|
||||
idxHdr = getVarint32(aRec, szHdr);
|
||||
if( szHdr>98307 ){
|
||||
rc = SQLITE_CORRUPT;
|
||||
}else{
|
||||
int res = 0; /* Result of this function call */
|
||||
u32 idxRec = szHdr; /* Index of next field in record body */
|
||||
int ii = 0; /* Iterator variable */
|
||||
|
||||
int nCol = p->pKeyInfo->nAllField;
|
||||
for(ii=0; ii<nCol && rc==SQLITE_OK; ii++){
|
||||
u32 iSerial = 0;
|
||||
int nSerial = 0;
|
||||
|
||||
if( idxHdr>=szHdr ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
break;
|
||||
}
|
||||
idxHdr += getVarint32(&aRec[idxHdr], iSerial);
|
||||
nSerial = sqlite3VdbeSerialTypeLen(iSerial);
|
||||
if( (idxRec+nSerial)>nRec ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &mem);
|
||||
if( vdbeSkipField(mask, ii, &p->aMem[ii], &mem, bInt)==0 ){
|
||||
res = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]);
|
||||
if( res!=0 ) break;
|
||||
}
|
||||
}
|
||||
idxRec += sqlite3VdbeSerialTypeLen(iSerial);
|
||||
}
|
||||
|
||||
*piRes = res;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(aRec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called when the record in (*p) should be found in the index
|
||||
** opened by cursor pCur, but was not. This may happen as part of a DELETE
|
||||
** operation or an integrity check.
|
||||
**
|
||||
** One reason that an exact match was not found may be the EIIB bug - that
|
||||
** a text-to-float conversion may have caused a real value in record (*p)
|
||||
** to be slightly different from its counterpart on disk. This function
|
||||
** attempts to find the right index record. If it does find the right
|
||||
** record, it leaves *pCur pointing to it and sets (*pRes) to 0 before
|
||||
** returning. Otherwise, (*pRes) is set to non-zero and an SQLite error
|
||||
** code returned.
|
||||
**
|
||||
** The algorithm used to find the correct record is:
|
||||
**
|
||||
** * Scan up to BTREE_FDK_RANGE entries either side of the current entry.
|
||||
** If parameter bIntegrity is false, then all fields that are indexed
|
||||
** expressions or virtual table columns are omitted from the comparison.
|
||||
** If bIntegrity is true, then small differences in real values in
|
||||
** such fields are overlooked, but they are not omitted from the comparison
|
||||
** altogether.
|
||||
**
|
||||
** * If the above fails to find an entry and bIntegrity is false, search
|
||||
** the entire index.
|
||||
*/
|
||||
int sqlite3VdbeFindIndexKey(
|
||||
BtCursor *pCur,
|
||||
Index *pIdx,
|
||||
UnpackedRecord *p,
|
||||
int *pRes,
|
||||
int bIntegrity
|
||||
){
|
||||
#define BTREE_FDK_RANGE 10
|
||||
int nStep = 0;
|
||||
int res = 1;
|
||||
int rc = SQLITE_OK;
|
||||
int ii = 0;
|
||||
|
||||
/* Calculate a mask based on the first 64 columns of the index. The mask
|
||||
** bit is set if the corresponding index field is either an expression
|
||||
** or a virtual column of the table. */
|
||||
Bitmask mask = 0;
|
||||
for(ii=0; ii<MIN(pIdx->nColumn, BMS); ii++){
|
||||
int iCol = pIdx->aiColumn[ii];
|
||||
if( (iCol==XN_EXPR)
|
||||
|| (iCol>=0 && (pIdx->pTable->aCol[iCol].colFlags & COLFLAG_VIRTUAL))
|
||||
){
|
||||
mask |= MASKBIT(ii);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the mask is 0 at this point, then the index contains no expressions
|
||||
** or virtual columns. So do not search for a match - return so that the
|
||||
** caller may declare the db corrupt immediately. Or, if mask is non-zero,
|
||||
** proceed. */
|
||||
if( mask!=0 ){
|
||||
|
||||
/* Move the cursor back BTREE_FDK_RANGE entries. If this hits an EOF,
|
||||
** position the cursor at the first entry in the index and set nStep
|
||||
** to -1 so that the first loop below scans the entire index. Otherwise,
|
||||
** set nStep to BTREE_FDK_RANGE*2 so that the first loop below scans
|
||||
** just that many entries. */
|
||||
for(ii=0; sqlite3BtreeEof(pCur)==0 && ii<BTREE_FDK_RANGE; ii++){
|
||||
rc = sqlite3BtreePrevious(pCur, 0);
|
||||
}
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = sqlite3BtreeFirst(pCur, &res);
|
||||
nStep = -1;
|
||||
}else{
|
||||
nStep = BTREE_FDK_RANGE*2;
|
||||
}
|
||||
|
||||
/* This loop runs at most twice to search for a key with matching PK
|
||||
** fields in the index. The second iteration always searches the entire
|
||||
** index. The first iteration searches nStep entries starting with the
|
||||
** current cursor entry if (nStep>=0), or the entire index if (nStep<0). */
|
||||
while( sqlite3BtreeCursorIsValidNN(pCur) ){
|
||||
for(ii=0; rc==SQLITE_OK && (ii<nStep || nStep<0); ii++){
|
||||
rc = vdbeIsMatchingIndexKey(pCur, bIntegrity, mask, p, &res);
|
||||
if( res==0 || rc!=SQLITE_OK ) break;
|
||||
rc = sqlite3BtreeNext(pCur, 0);
|
||||
}
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
assert( res!=0 );
|
||||
}
|
||||
if( nStep<0 || rc!=SQLITE_OK || res==0 || bIntegrity ) break;
|
||||
|
||||
/* The first, non-exhaustive, search failed to find an entry with
|
||||
** matching PK fields. So restart for an exhaustive search of the
|
||||
** entire index. */
|
||||
nStep = -1;
|
||||
rc = sqlite3BtreeFirst(pCur, &res);
|
||||
}
|
||||
}
|
||||
|
||||
*pRes = res;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_DATETIME_FUNCS
|
||||
/*
|
||||
** Cause a function to throw an error if it was call from OP_PureFunc
|
||||
|
||||
+73
-26
@@ -657,32 +657,36 @@ i64 sqlite3VdbeIntValue(const Mem *pMem){
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke sqlite3AtoF() on the text value of pMem and return the
|
||||
** double result. If sqlite3AtoF() returns an error code, write
|
||||
** that code into *pRC if (*pRC)!=NULL.
|
||||
** This routine implements the uncommon and slower path for
|
||||
** sqlite3MemRealValueRC() that has to deal with input strings
|
||||
** that are not UTF8 or that are not zero-terminated. It is
|
||||
** broken out into a separate no-inline routine so that the
|
||||
** main sqlite3MemRealValueRC() routine can avoid unnecessary
|
||||
** stack pushes.
|
||||
**
|
||||
** The caller must ensure that pMem->db!=0 and that pMem is in
|
||||
** mode MEM_Str or MEM_Blob.
|
||||
** A text->float translation of pMem->z is written into *pValue.
|
||||
**
|
||||
** Result code invariants:
|
||||
**
|
||||
** rc==0 => ERROR: Input string not well-formed, or OOM
|
||||
** rc<0 => Some prefix of the input is well-formed
|
||||
** rc>0 => All of the input is well-formed
|
||||
** (rc&2)==0 => The number is expressed as an integer, with no
|
||||
** decimal point or eNNN suffix.
|
||||
*/
|
||||
SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem *pMem, int *pRC){
|
||||
double val = (double)0;
|
||||
int rc = 0;
|
||||
assert( pMem->db!=0 );
|
||||
assert( pMem->flags & (MEM_Str|MEM_Blob) );
|
||||
if( pMem->z==0 ){
|
||||
/* no-op */
|
||||
}else if( pMem->enc==SQLITE_UTF8
|
||||
&& ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem))
|
||||
){
|
||||
rc = sqlite3AtoF(pMem->z, &val);
|
||||
}else if( pMem->n==0 ){
|
||||
/* no-op */
|
||||
}else if( pMem->enc==SQLITE_UTF8 ){
|
||||
static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath(
|
||||
Mem *pMem,
|
||||
double *pValue
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
*pValue = 0.0;
|
||||
if( pMem->enc==SQLITE_UTF8 ){
|
||||
char *zCopy = sqlite3DbStrNDup(pMem->db, pMem->z, pMem->n);
|
||||
if( zCopy ){
|
||||
rc = sqlite3AtoF(zCopy, &val);
|
||||
rc = sqlite3AtoF(zCopy, pValue);
|
||||
sqlite3DbFree(pMem->db, zCopy);
|
||||
}
|
||||
return rc;
|
||||
}else{
|
||||
int n, i, j;
|
||||
char *zCopy;
|
||||
@@ -705,13 +709,56 @@ SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem *pMem, int *pRC){
|
||||
}
|
||||
assert( j<=n/2 );
|
||||
zCopy[j] = 0;
|
||||
rc = sqlite3AtoF(zCopy, &val);
|
||||
rc = sqlite3AtoF(zCopy, pValue);
|
||||
if( i<n ) rc = -100;
|
||||
sqlite3DbFree(pMem->db, zCopy);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
if( pRC ) *pRC = rc;
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke sqlite3AtoF() on the text value of pMem. Write the
|
||||
** translation of the text input into *pValue.
|
||||
**
|
||||
** The caller must ensure that pMem->db!=0 and that pMem is in
|
||||
** mode MEM_Str or MEM_Blob.
|
||||
**
|
||||
** Result code invariants:
|
||||
**
|
||||
** rc==0 => ERROR: Input string not well-formed, or OOM
|
||||
** rc<0 => Some prefix of the input is well-formed
|
||||
** rc>0 => All of the input is well-formed
|
||||
** (rc&2)==0 => The number is expressed as an integer, with no
|
||||
** decimal point or eNNN suffix.
|
||||
*/
|
||||
int sqlite3MemRealValueRC(Mem *pMem, double *pValue){
|
||||
assert( pMem->db!=0 );
|
||||
assert( pMem->flags & (MEM_Str|MEM_Blob) );
|
||||
if( pMem->z==0 ){
|
||||
*pValue = 0.0;
|
||||
return 0;
|
||||
}else if( pMem->enc==SQLITE_UTF8
|
||||
&& ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem))
|
||||
){
|
||||
return sqlite3AtoF(pMem->z, pValue);
|
||||
}else if( pMem->n==0 ){
|
||||
*pValue = 0.0;
|
||||
return 0;
|
||||
}else{
|
||||
return sqlite3MemRealValueRCSlowPath(pMem, pValue);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine acts as a bridge from sqlite3VdbeRealValue() to
|
||||
** sqlite3VdbeRealValueRC, allowing sqlite3VdbeRealValue() to avoid
|
||||
** stuffing values onto the stack.
|
||||
*/
|
||||
static SQLITE_NOINLINE double sqlite3MemRealValueNoRC(Mem *pMem){
|
||||
double r;
|
||||
(void)sqlite3MemRealValueRC(pMem, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -730,7 +777,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
||||
testcase( pMem->flags & MEM_IntReal );
|
||||
return (double)pMem->u.i;
|
||||
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
return sqlite3MemRealValueRC(pMem, 0);
|
||||
return sqlite3MemRealValueNoRC(pMem);
|
||||
}else{
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
return (double)0;
|
||||
@@ -854,8 +901,8 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
|
||||
sqlite3_int64 ix;
|
||||
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
pMem->u.r = sqlite3MemRealValueRC(pMem, &rc);
|
||||
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
|
||||
rc = sqlite3MemRealValueRC(pMem, &pMem->u.r);
|
||||
if( ((rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<2)
|
||||
|| sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r)))
|
||||
){
|
||||
pMem->u.i = ix;
|
||||
|
||||
+15
-5
@@ -2449,11 +2449,16 @@ void sqlite3WhereClausePrint(WhereClause *pWC){
|
||||
void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
|
||||
WhereInfo *pWInfo;
|
||||
if( pWC ){
|
||||
int nb;
|
||||
SrcItem *pItem;
|
||||
Table *pTab;
|
||||
Bitmask mAll;
|
||||
|
||||
pWInfo = pWC->pWInfo;
|
||||
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
|
||||
Table *pTab = pItem->pSTab;
|
||||
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
pItem = pWInfo->pTabList->a + p->iTab;
|
||||
pTab = pItem->pSTab;
|
||||
mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
|
||||
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
|
||||
sqlite3DebugPrintf(" %12s",
|
||||
@@ -4167,7 +4172,12 @@ static int whereLoopAddBtree(
|
||||
whereLoopOutputAdjust(pWC, pNew, rSize);
|
||||
if( pSrc->fg.isSubquery ){
|
||||
if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
|
||||
pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
|
||||
/* Do not set btree.pOrderBy for a recursive CTE. In this case
|
||||
** the ORDER BY clause does not determine the overall order that
|
||||
** rows are emitted from the CTE in. */
|
||||
if( (pSrc->u4.pSubq->pSelect->selFlags & SF_Recursive)==0 ){
|
||||
pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
|
||||
}
|
||||
}else if( pSrc->fg.fromExists ){
|
||||
pNew->nOut = 0;
|
||||
}
|
||||
|
||||
+4
-4
@@ -1922,8 +1922,8 @@ do_test auth-1.283 {
|
||||
execsql {
|
||||
REINDEX BINARY;
|
||||
}
|
||||
set ::authargs
|
||||
} {t3_idx1 {} main {} sqlite_autoindex_t3_1 {} main {}}
|
||||
lsort -unique $::authargs
|
||||
} {{} main sqlite_autoindex_t3_1 t3_idx1 t3_idx2}
|
||||
do_test auth-1.284 {
|
||||
set ::authargs {}
|
||||
execsql {
|
||||
@@ -1963,8 +1963,8 @@ ifcapable tempdb {
|
||||
execsql {
|
||||
REINDEX BINARY;
|
||||
}
|
||||
set ::authargs
|
||||
} {t3_idx1 {} temp {} sqlite_autoindex_t3_1 {} temp {}}
|
||||
lsort -unique $::authargs
|
||||
} {{} sqlite_autoindex_t3_1 t3_idx1 t3_idx2 temp}
|
||||
do_test auth-1.290 {
|
||||
set ::authargs {}
|
||||
execsql {
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
# 2026-03-16
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains test cases for handling stale expression indexes -
|
||||
# expression indexes for which the value of the expression is different
|
||||
# from (though usually very close to) the value stored on disk.
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix expridx1
|
||||
|
||||
# Check that OP_IdxDelete works when:
|
||||
#
|
||||
# 1.1.* The real value in the index is greater than that in the table,
|
||||
# 1.2.* The real value in the index is smaller than that in the table,
|
||||
# 1.3.* Duplicate distorted real values.
|
||||
#
|
||||
|
||||
do_execsql_test 1.0.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b REAL);
|
||||
INSERT INTO t1 VALUES(10, 10.0);
|
||||
INSERT INTO t1 VALUES(15, 15.0);
|
||||
INSERT INTO t1 VALUES(20, 20.0);
|
||||
INSERT INTO t1 VALUES(25, 25.0);
|
||||
INSERT INTO t1 VALUES(30, 30.0);
|
||||
CREATE INDEX i1 ON t1((b+0.0));
|
||||
}
|
||||
|
||||
# Return a list of rowids from table t1 for which there is no exact
|
||||
# match in the index.
|
||||
set idxcheck {
|
||||
SELECT rowid FROM t1 AS o NOT INDEXED
|
||||
WHERE NOT EXISTS (SELECT 1 FROM t1 WHERE +a=o.a AND b+0.0=o.b+0.0)
|
||||
}
|
||||
|
||||
set root [db one {SELECT rootpage FROM sqlite_schema WHERE name='i1'}]
|
||||
|
||||
do_test 1.0.2 {
|
||||
# Create an imposter table for index i1
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $root
|
||||
db eval {
|
||||
CREATE TABLE x1(b, rowid, PRIMARY KEY(b, rowid)) WITHOUT ROWID;
|
||||
}
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
|
||||
db one { PRAGMA integrity_check }
|
||||
} ok
|
||||
|
||||
do_execsql_test 1.1.1 {
|
||||
UPDATE x1 SET b=21.0 WHERE rowid=20;
|
||||
}
|
||||
do_execsql_test 1.1.1b {
|
||||
PRAGMA integrity_check;
|
||||
} {{row 3 missing from index i1}}
|
||||
do_execsql_test 1.1.1c $idxcheck {20}
|
||||
|
||||
do_execsql_test 1.1.2 {
|
||||
DELETE FROM t1 WHERE a=20;
|
||||
} {}
|
||||
do_execsql_test 1.1.3 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
do_execsql_test 1.1.4 $idxcheck {}
|
||||
|
||||
do_execsql_test 1.2.1 {
|
||||
UPDATE x1 SET b=26.0 WHERE rowid=25;
|
||||
PRAGMA integrity_check;
|
||||
} {
|
||||
{row 3 missing from index i1}
|
||||
}
|
||||
do_execsql_test 1.2.2 $idxcheck {25}
|
||||
|
||||
do_execsql_test 1.2.3 {
|
||||
DELETE FROM t1 WHERE a=25;
|
||||
} {}
|
||||
do_execsql_test 1.2.4 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
do_execsql_test 1.2.5 $idxcheck {}
|
||||
|
||||
do_execsql_test 1.3.1 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES(5, 15.0);
|
||||
INSERT INTO t1 VALUES(10, 20.0);
|
||||
INSERT INTO t1 VALUES(15, 20.0);
|
||||
INSERT INTO t1 VALUES(20, 20.0);
|
||||
INSERT INTO t1 VALUES(25, 20.0);
|
||||
INSERT INTO t1 VALUES(30, 20.0);
|
||||
INSERT INTO t1 VALUES(35, 25.0);
|
||||
|
||||
UPDATE x1 SET b=19.0 WHERE b=20.0;
|
||||
PRAGMA integrity_check;
|
||||
} {
|
||||
{row 2 missing from index i1}
|
||||
{row 3 missing from index i1}
|
||||
{row 4 missing from index i1}
|
||||
{row 5 missing from index i1}
|
||||
{row 6 missing from index i1}
|
||||
}
|
||||
|
||||
do_execsql_test 1.3.2 $idxcheck {10 15 20 25 30}
|
||||
|
||||
foreach {tn a} {
|
||||
1 15 2 30 3 20 4 10 5 25
|
||||
} {
|
||||
do_execsql_test 1.3.3.$tn {
|
||||
DELETE FROM t1 WHERE a=$a
|
||||
}
|
||||
}
|
||||
do_execsql_test 1.3.4 {
|
||||
PRAGMA integrity_check
|
||||
} {ok}
|
||||
do_execsql_test 1.3.5 $idxcheck {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
set nRow [expr 1000]
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$nRow
|
||||
)
|
||||
INSERT INTO t1 SELECT i, random(), hex(randomblob(50)) FROM s;
|
||||
CREATE INDEX t1c ON t1(+c);
|
||||
}
|
||||
|
||||
set idxcheck {
|
||||
SELECT a, b FROM t1 AS o NOT INDEXED
|
||||
WHERE NOT EXISTS (SELECT 1 FROM t1 WHERE +a=o.a AND +b=o.b AND +c=o.c)
|
||||
}
|
||||
|
||||
set root [db one {SELECT rootpage FROM sqlite_schema WHERE name='t1c'}]
|
||||
|
||||
do_test 2.1 {
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $root
|
||||
db eval {
|
||||
CREATE TABLE x1(a, b, c, PRIMARY KEY(c, a, b)) WITHOUT ROWID;
|
||||
}
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
UPDATE x1 SET c=hex(randomblob(50)) WHERE (a%2)!=0
|
||||
}
|
||||
|
||||
do_execsql_test 2.3 "
|
||||
SELECT count(*) FROM ( $idxcheck )
|
||||
" [expr $nRow/2]
|
||||
|
||||
do_test 2.4 {
|
||||
for {set ii 1} {$ii<$nRow} {incr ii 2} {
|
||||
execsql { DELETE FROM t1 WHERE a=$ii }
|
||||
}
|
||||
execsql {PRAGMA integrity_check}
|
||||
} {ok}
|
||||
|
||||
do_execsql_test 2.5 "
|
||||
SELECT count(*) FROM ( $idxcheck )
|
||||
" 0
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE y1(a, b, c GENERATED ALWAYS AS (a*b) VIRTUAL);
|
||||
CREATE INDEX i1 ON y1(c);
|
||||
INSERT INTO y1 VALUES(2, 3);
|
||||
INSERT INTO y1 VALUES(4, 5);
|
||||
}
|
||||
|
||||
set idxcheck {
|
||||
SELECT rowid FROM y1 AS o NOT INDEXED
|
||||
WHERE NOT EXISTS (SELECT 1 FROM y1 WHERE +rowid=o.rowid AND c=o.c)
|
||||
}
|
||||
|
||||
set root [db one {SELECT rootpage FROM sqlite_schema WHERE name='i1'}]
|
||||
|
||||
do_test 3.1 {
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $root
|
||||
db eval { CREATE TABLE x1(c, rowid, PRIMARY KEY(c, rowid)) WITHOUT ROWID; }
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
} {}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
UPDATE x1 SET c=19 WHERE rowid=2;
|
||||
}
|
||||
|
||||
do_execsql_test 3.3 $idxcheck 2
|
||||
|
||||
do_execsql_test 3.4 {
|
||||
DELETE FROM y1 WHERE a=4;
|
||||
}
|
||||
do_execsql_test 3.5 $idxcheck {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE z1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE INDEX z1b ON z1(b+0.0);
|
||||
INSERT INTO z1 VALUES(1, 1.0);
|
||||
INSERT INTO z1 VALUES(2, 4.0);
|
||||
INSERT INTO z1 VALUES(3, 4.0);
|
||||
INSERT INTO z1 VALUES(4, 4.0);
|
||||
INSERT INTO z1 VALUES(5, 4.0);
|
||||
INSERT INTO z1 VALUES(6, 4.0);
|
||||
INSERT INTO z1 VALUES(7, 4.0);
|
||||
INSERT INTO z1 VALUES(8, 1.0);
|
||||
}
|
||||
|
||||
set root [db one {SELECT rootpage FROM sqlite_schema WHERE name='z1b'}]
|
||||
do_test 4.1 {
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $root
|
||||
db eval { CREATE TABLE x1(b, a, PRIMARY KEY(b, a)) WITHOUT ROWID; }
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
} {}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
UPDATE x1 SET b=4.000000000000001 WHERE a=2; -- 1 ULP
|
||||
UPDATE x1 SET b=4.000000000000002 WHERE a=3; -- 2 ULP
|
||||
UPDATE x1 SET b=4.000000000000003 WHERE a=4; -- 3 ULP
|
||||
UPDATE x1 SET b=3.9999999999999996 WHERE a=5; -- -1 ULP
|
||||
UPDATE x1 SET b=3.9999999999999992 WHERE a=6; -- -2 ULP
|
||||
UPDATE x1 SET b=3.9999999999999988 WHERE a=7; -- -3 ULP
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
PRAGMA integrity_check
|
||||
} {
|
||||
{index z1b stores an imprecise floating-point value for row 2}
|
||||
{index z1b stores an imprecise floating-point value for row 3}
|
||||
{row 4 missing from index z1b}
|
||||
{index z1b stores an imprecise floating-point value for row 5}
|
||||
{index z1b stores an imprecise floating-point value for row 6}
|
||||
{row 7 missing from index z1b}
|
||||
}
|
||||
|
||||
do_execsql_test 4.4 {
|
||||
UPDATE z1 SET b=-4.0 WHERE b=4.0;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
do_execsql_test 4.5 {
|
||||
UPDATE x1 SET b=-4.000000000000001 WHERE a=2; -- -1 ULP
|
||||
UPDATE x1 SET b=-4.000000000000002 WHERE a=3; -- -2 ULP
|
||||
UPDATE x1 SET b=-4.000000000000003 WHERE a=4; -- -3 ULP
|
||||
UPDATE x1 SET b=-3.9999999999999996 WHERE a=5; -- 1 ULP
|
||||
UPDATE x1 SET b=-3.9999999999999992 WHERE a=6; -- 2 ULP
|
||||
UPDATE x1 SET b=-3.9999999999999988 WHERE a=7; -- 3 ULP
|
||||
}
|
||||
|
||||
do_execsql_test 4.6 {
|
||||
PRAGMA integrity_check
|
||||
} {
|
||||
{index z1b stores an imprecise floating-point value for row 2}
|
||||
{index z1b stores an imprecise floating-point value for row 3}
|
||||
{row 4 missing from index z1b}
|
||||
{index z1b stores an imprecise floating-point value for row 5}
|
||||
{index z1b stores an imprecise floating-point value for row 6}
|
||||
{row 7 missing from index z1b}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -249,5 +249,45 @@ do_execsql_test 6.3 {
|
||||
DELETE FROM aux.p1 WHERE a=123;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Forum: https://sqlite.org/forum/forumpost/636bd0180a
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
PRAGMA foreign_keys = ON;
|
||||
CREATE TABLE p1 (pid PRIMARY KEY);
|
||||
CREATE TABLE c1 (cid PRIMARY KEY,
|
||||
pid REFERENCES p1(pid) ON UPDATE CASCADE
|
||||
);
|
||||
}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
ATTACH ':memory:' AS aux;
|
||||
CREATE TABLE aux.p1 (pid PRIMARY KEY);
|
||||
CREATE TABLE aux.c1 (cid PRIMARY KEY,
|
||||
pid REFERENCES p1(pid) ON UPDATE CASCADE);
|
||||
|
||||
INSERT INTO aux.p1 VALUES (10);
|
||||
INSERT INTO aux.p1 VALUES (20);
|
||||
|
||||
INSERT INTO aux.c1 VALUES(11, 10);
|
||||
INSERT INTO aux.c1 VALUES(12, 10);
|
||||
INSERT INTO aux.c1 VALUES(21, 20);
|
||||
INSERT INTO aux.c1 VALUES(22, 20);
|
||||
}
|
||||
|
||||
do_catchsql_test 7.2 {
|
||||
UPDATE aux.p1 SET pid = pid * 10;
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 7.3 {
|
||||
SELECT * FROM aux.p1;
|
||||
} {100 200}
|
||||
|
||||
do_execsql_test 7.4 {
|
||||
SELECT * FROM aux.c1;
|
||||
} {11 100 12 100 21 200 22 200}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+78
-25
@@ -2,6 +2,9 @@
|
||||
** Performance testing of floating-point binary-to-decimal conversion for
|
||||
** SQLite versus the standard library.
|
||||
**
|
||||
** This module compares library sprintf() against SQLite's sqlite3_snprintf().
|
||||
** To go the other direction (decimal-to-binary) see fp-speed-2.c.
|
||||
**
|
||||
** To compile:
|
||||
**
|
||||
** make sqlite3.c
|
||||
@@ -10,9 +13,17 @@
|
||||
**
|
||||
** To run the test:
|
||||
**
|
||||
** time ./a.out 0 10000000 <-- standard library
|
||||
** time ./a.out 1 10000000 <-- SQLite
|
||||
** ./a.out 10000000
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static double aVal[] = {
|
||||
-1.0163830486285643089e+063,
|
||||
+0.0049243807391586981e-019,
|
||||
@@ -117,38 +128,80 @@ static double aVal[] = {
|
||||
};
|
||||
#define NN (sizeof(aVal)/sizeof(aVal[0]))
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
/* Return the current wall-clock time in microseconds since the
|
||||
** Unix epoch (1970-01-01T00:00:00Z)
|
||||
*/
|
||||
static sqlite3_int64 timeOfDay(void){
|
||||
#if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
||||
sqlite3_uint64 t;
|
||||
FILETIME tm;
|
||||
GetSystemTimePreciseAsFileTime(&tm);
|
||||
t = ((sqlite3_uint64)tm.dwHighDateTime<<32) |
|
||||
(sqlite3_uint64)tm.dwLowDateTime;
|
||||
t += 116444736000000000LL;
|
||||
t /= 10;
|
||||
return t;
|
||||
#elif defined(_WIN32)
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
if( clockVfs==0 ) return 0; /* Never actually happens */
|
||||
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
|
||||
clockVfs->xCurrentTimeInt64(clockVfs, &t);
|
||||
}else{
|
||||
double r;
|
||||
clockVfs->xCurrentTime(clockVfs, &r);
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t*1000;
|
||||
#else
|
||||
struct timeval sNow;
|
||||
(void)gettimeofday(&sNow,0);
|
||||
return ((sqlite3_int64)sNow.tv_sec)*1000000 + sNow.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int i;
|
||||
int cnt;
|
||||
int fg;
|
||||
static const char *zFmt = "%.17g";
|
||||
sqlite3_int64 tm1, tm2;
|
||||
char zBuf[1000];
|
||||
|
||||
if( argc!=3 ){
|
||||
fprintf(stderr, "Usage: %s FLAG COUNT\n", argv[0]);
|
||||
if( argc!=2 ){
|
||||
printf("Usage: %s COUNT\n", argv[0]);
|
||||
printf("Suggested value for COUNT is 10 million\n");
|
||||
return 1;
|
||||
}
|
||||
cnt = atoi(argv[1]);
|
||||
if( cnt<100 ){
|
||||
printf("Minimum COUNT value is 100");
|
||||
return 1;
|
||||
}
|
||||
cnt = atoi(argv[2]);
|
||||
fg = atoi(argv[1]);
|
||||
|
||||
switch( fg % 3 ){
|
||||
case 0: {
|
||||
printf("Doing %d calls to C-lib sprintf()\n", cnt);
|
||||
for(i=0; i<cnt; i++){
|
||||
sprintf(zBuf, "%.26g", aVal[i%NN]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
printf("Doing %d calls to sqlite3_snprintf()\n", cnt);
|
||||
for(i=0; i<cnt; i++){
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.26g", aVal[i%NN]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
printf("C-library sprintf(\"%s\"): ", zFmt);
|
||||
fflush(stdout);
|
||||
tm1 = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
sprintf(zBuf, zFmt, aVal[i%NN]);
|
||||
}
|
||||
tm1 = timeOfDay() - tm1;
|
||||
printf("%6.1f ns/call, %9.6f sec total\n", tm1*1.0e+3/(double)cnt,tm1*1.0e-6);
|
||||
|
||||
printf("sqlite3_snprintf(\"%s\"): ", zFmt);
|
||||
tm2 = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, zFmt, aVal[i%NN]);
|
||||
}
|
||||
tm2 = timeOfDay() - tm2;
|
||||
printf("%6.1f ns/call, %9.6f sec total\n", tm2*1.0e+3/(double)cnt,tm2*1.0e-6);
|
||||
|
||||
if( tm1 < tm2 ){
|
||||
printf("sprintf() is about %g times faster than sqlite3_snprintf()\n",
|
||||
(double)tm2/(double)tm1);
|
||||
}else{
|
||||
printf("sqlite3_snprintf() is about %g times faster than sprintf()\n",
|
||||
(double)tm1/(double)tm2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
** Performance testing of floating-point decimal-to-binary conversion for
|
||||
** SQLite versus the standard library.
|
||||
**
|
||||
** This module compares library atof() against SQLite's sqlite3AtoF().
|
||||
** To go the other direction (binary-to-decimal) see fp-speed-1.c.
|
||||
**
|
||||
** To compile:
|
||||
**
|
||||
** make sqlite3.c
|
||||
** gcc -Os -c sqlite3.c
|
||||
** gcc -I. -Os test/fp-speed-2.c sqlite3.o -ldl -lm -lpthread
|
||||
**
|
||||
** To run the test:
|
||||
**
|
||||
** ./a.out 10000000
|
||||
**
|
||||
** Notes:
|
||||
**
|
||||
** * A first loop is run to measure the testing overhead. This
|
||||
** overhead is then subtracted from the times of subsequent loops
|
||||
** so that the estimates are for the calls to atof() or
|
||||
** sqlite3AtoF() only.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static const char *aVal[] = {
|
||||
"-1.01638304862856430",
|
||||
"+0.00492438073915869",
|
||||
"+7.38187324073439948",
|
||||
"+7.06785952192257171",
|
||||
"+9.28072663198500256",
|
||||
"+5.88710508619333946",
|
||||
"-2.29980236212596628",
|
||||
"-1.59035819249108474",
|
||||
"+2.43134418168449782",
|
||||
"-3.82909873289453990",
|
||||
"+1.87879140627440013",
|
||||
"+0.72706535604871466",
|
||||
"+0.06395776979131836",
|
||||
"+5.22923388793158619",
|
||||
"+6.37476826728722313",
|
||||
"+8.69723395383291069",
|
||||
"-9.50744860515976919",
|
||||
"-8.64802578453687530",
|
||||
"-3.56575957757974703",
|
||||
"-7.83231061797317613",
|
||||
"+7.78138752741208003",
|
||||
"-1.87397189283601965",
|
||||
"+8.68981459155933572",
|
||||
"+6.05667663598778378",
|
||||
"+4.17033792171481606",
|
||||
"+2.12838712887466515",
|
||||
"-6.83952360838918106",
|
||||
"-6.21142997639395291",
|
||||
"-2.07535257426146373",
|
||||
"+5.87274598039442902",
|
||||
"+8.58889910620021018",
|
||||
"+6.86244610313559176",
|
||||
"-3.30539867566709051",
|
||||
"-4.35968431527634449",
|
||||
"+0.08341395201040996",
|
||||
"-8.85819865489042224",
|
||||
"-3.66220954287276982",
|
||||
"-6.69658522970250632",
|
||||
"+1.82041693474064884",
|
||||
"+6.52345080386490003",
|
||||
"+1.59230060182190114",
|
||||
"+1.73625552916563894",
|
||||
"+7.28754319768547858",
|
||||
"+1.28358801059589267",
|
||||
"+8.05162533203208194",
|
||||
"+6.63246333993811454",
|
||||
"-1.71265000702800620",
|
||||
"+1.69957383415837123",
|
||||
"+7.60487669237386637",
|
||||
"+0.61591172354494550",
|
||||
"+5.75448943554159432",
|
||||
"+8.29702285926905818",
|
||||
"-6.55319253601630674",
|
||||
"+5.83213346061870300",
|
||||
"+5.65571665095718917",
|
||||
"+0.33227897084384087",
|
||||
"-7.12106487766986866",
|
||||
"-9.67212625267063433",
|
||||
"-3.45839165713773950",
|
||||
"+4.78960943232147507",
|
||||
"-9.69260280400041378",
|
||||
"+7.06838482753813854",
|
||||
"-5.29701141821629619",
|
||||
"-4.42870212009053932",
|
||||
"+0.07288911557328087",
|
||||
"-9.18554620258794474",
|
||||
"+3.72941262341310077",
|
||||
"+2.68574218827927192",
|
||||
"-4.70706073336246853",
|
||||
"+7.21758207682793342",
|
||||
"-8.36784125342611634",
|
||||
"+2.21748443042418221",
|
||||
"+0.19498245886068610",
|
||||
"-9.73340529556720719",
|
||||
"-9.77938877669369998",
|
||||
"-5.15611645874169315",
|
||||
"-7.50489935777651747",
|
||||
"+7.35560765686877845",
|
||||
"-5.06816285755335998",
|
||||
"+1.52097056420277478",
|
||||
"-7.59897825350482960",
|
||||
"+1.36541372033897758",
|
||||
"-1.64417205546513720",
|
||||
"-4.90424331961411259",
|
||||
"-7.70636119616491307",
|
||||
"+0.16994274609307662",
|
||||
"+8.33743178495722168",
|
||||
"-5.23553304804695800",
|
||||
"-3.85100459421941479",
|
||||
"-6.35136225443263398",
|
||||
"+2.38693034844544289",
|
||||
"+3.83527158716203602",
|
||||
"-3.12631204931368879",
|
||||
"-5.57947970025564908",
|
||||
"-8.81098744795956043",
|
||||
"-4.37273601202032169",
|
||||
"-3.11099511896685399",
|
||||
"-9.48418780317042682",
|
||||
"-3.73984516683044072",
|
||||
"+4.89840420089159599",
|
||||
};
|
||||
#define NN (sizeof(aVal)/sizeof(aVal[0]))
|
||||
|
||||
/* Return the current wall-clock time in microseconds since the
|
||||
** Unix epoch (1970-01-01T00:00:00Z)
|
||||
*/
|
||||
static sqlite3_int64 timeOfDay(void){
|
||||
#if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
||||
sqlite3_uint64 t;
|
||||
FILETIME tm;
|
||||
GetSystemTimePreciseAsFileTime(&tm);
|
||||
t = ((sqlite3_uint64)tm.dwHighDateTime<<32) |
|
||||
(sqlite3_uint64)tm.dwLowDateTime;
|
||||
t += 116444736000000000LL;
|
||||
t /= 10;
|
||||
return t;
|
||||
#elif defined(_WIN32)
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
if( clockVfs==0 ) return 0; /* Never actually happens */
|
||||
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
|
||||
clockVfs->xCurrentTimeInt64(clockVfs, &t);
|
||||
}else{
|
||||
double r;
|
||||
clockVfs->xCurrentTime(clockVfs, &r);
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t*1000;
|
||||
#else
|
||||
struct timeval sNow;
|
||||
(void)gettimeofday(&sNow,0);
|
||||
return ((sqlite3_int64)sNow.tv_sec)*1000000 + sNow.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate text of the i-th test floating-point literal.
|
||||
*/
|
||||
static int fpLiteral(int i, char *z){
|
||||
int e, ex, len, ix;
|
||||
ex = i%401;
|
||||
e = ex - 200;
|
||||
len = (i/401)%16 + 4;
|
||||
ix = (i/(401*16))%NN;
|
||||
memcpy(z, aVal[ix], len);
|
||||
z[len++] = 'e';
|
||||
if( e<0 ){
|
||||
z[len++] = '-';
|
||||
e = -e;
|
||||
}else{
|
||||
z[len++] = '+';
|
||||
}
|
||||
z[len++] = e/100 + '0';
|
||||
z[len++] = (e/10)%10 + '0';
|
||||
z[len++] = e%10 + '0';
|
||||
z[len] = 0;
|
||||
return ex;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int i;
|
||||
int cnt;
|
||||
sqlite3_int64 tm[3];
|
||||
double arSum[401];
|
||||
char z[1000];
|
||||
|
||||
if( argc!=2 ){
|
||||
printf("Usage: %s COUNT\n", argv[0]);
|
||||
printf("Suggested value for COUNT is 10 million\n");
|
||||
return 1;
|
||||
}
|
||||
cnt = atoi(argv[1]);
|
||||
if( cnt<100 ){
|
||||
printf("Minimum COUNT value is 100");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("test-overhead: ");
|
||||
fflush(stdout);
|
||||
memset(arSum, 0, sizeof(arSum));
|
||||
tm[2] = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
double r = (double)i;
|
||||
int ex = fpLiteral(i,z);
|
||||
arSum[ex] += r;
|
||||
}
|
||||
tm[2] = timeOfDay() - tm[2];
|
||||
for(i=1; i<=400; i++) arSum[0] += arSum[i];
|
||||
printf("%6.1f ns/test, %9.6f sec total\n", tm[2]*1e3/cnt, tm[2]*1e-6);
|
||||
|
||||
printf("C-lib atof(): ");
|
||||
fflush(stdout);
|
||||
memset(arSum, 0, sizeof(arSum));
|
||||
tm[0] = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
int ex = fpLiteral(i,z);
|
||||
arSum[ex] += atof(z);
|
||||
}
|
||||
tm[0] = timeOfDay() - tm[0] - tm[2];
|
||||
for(i=1; i<=400; i++) arSum[0] += arSum[i];
|
||||
printf("%6.1f ns/test, %9.6f sec net", tm[0]*1e3/cnt, tm[0]*1e-6);
|
||||
printf(", cksum: %g\n", arSum[0]);
|
||||
|
||||
printf("sqlite3AtoF(): ");
|
||||
fflush(stdout);
|
||||
memset(arSum, 0, sizeof(arSum));
|
||||
tm[1] = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
double r = 0.0;
|
||||
int ex = fpLiteral(i,z);
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_ATOF, z, &r);
|
||||
arSum[ex] += r;
|
||||
}
|
||||
tm[1] = timeOfDay() - tm[1] - tm[2];
|
||||
for(i=1; i<=400; i++) arSum[0] += arSum[i];
|
||||
printf("%6.1f ns/test, %9.6f sec net", tm[1]*1e3/cnt, tm[1]*1e-6);
|
||||
printf(", cksum: %g\n", arSum[0]);
|
||||
|
||||
if( tm[0] < tm[1] ){
|
||||
printf("atof() is about %g times faster than sqlite3AtoF()\n",
|
||||
(double)tm[1]/(double)tm[0]);
|
||||
}else{
|
||||
printf("sqlite3AtoF() is about %g times faster than atof()\n",
|
||||
(double)tm[0]/(double)tm[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+111
-1
@@ -11,7 +11,21 @@
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Floating-point to text conversions
|
||||
# Floating-point <-> text conversions
|
||||
#
|
||||
# FAILURES IN THIS SCRIPT ARE NOT NECESSARILY THE FAULT OF SQLITE.
|
||||
#
|
||||
# Some of the tests below use the system strtod() function as
|
||||
# an oracle of truth. These tests assume that the system strtod()
|
||||
# is always correct. That is the case for Win11, Macs, most Linux
|
||||
# boxes and so forth. But it possible to find a machine for which
|
||||
# is not true. (One example, is Macs from around 2005.) On such
|
||||
# machines, some of these tests might fail.
|
||||
#
|
||||
# So, in other words, a failure in any of the tests below does not
|
||||
# necessarily mean that SQLite is wrong. It might mean that the
|
||||
# strtod() function in the standard library of the machine on which
|
||||
# the test is running is wrong.
|
||||
#
|
||||
|
||||
# Verify that binary64 -> text -> binary64 conversions round-trip
|
||||
@@ -74,3 +88,99 @@ WITH
|
||||
fp(r) AS (SELECT ieee754_from_int(n) FROM fpint)
|
||||
SELECT r FROM fp WHERE r<>strtod(r||'');
|
||||
.check ''
|
||||
|
||||
# Comparing SQLite's text-to-double conversion against strtod()
|
||||
# for 200,000 random floating-point literals.
|
||||
#
|
||||
.param set $N 50_000
|
||||
.testcase 300
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
VALUES(1,'1234.5789')
|
||||
UNION ALL
|
||||
SELECT n+1, format('%.*s.%.*se%+d',
|
||||
(n%3)+1,
|
||||
random()%1000,
|
||||
abs(random()%16)+1,
|
||||
abs(random()),
|
||||
random()%308)
|
||||
FROM fp WHERE n<$N
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 301
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
VALUES(1,'1234.5789')
|
||||
UNION ALL
|
||||
SELECT n+1, format('%.*s.%.*s',
|
||||
(n%3)+1,
|
||||
random()%1000,
|
||||
abs(random()%16)+1,
|
||||
abs(random()))
|
||||
FROM fp WHERE n<$N
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 302
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
VALUES(1,'1234.5789')
|
||||
UNION ALL
|
||||
SELECT n+1, format('%.*s.%.*s',
|
||||
abs(random()%7)+1,
|
||||
random(),
|
||||
abs(random()%10)+1,
|
||||
abs(random()))
|
||||
FROM fp WHERE n<$N
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 303
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
VALUES(1,'1234.5789')
|
||||
UNION ALL
|
||||
SELECT n+1, format('%de%+03d',
|
||||
random(),
|
||||
random()%308)
|
||||
FROM fp WHERE n<$N
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
|
||||
# Another 500,000 comparisions between SQLite and strtod() from completely
|
||||
# random floating point literals.
|
||||
#
|
||||
.testcase 310
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 311
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 312
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 313
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 314
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
|
||||
@@ -96,6 +96,30 @@ do_execsql_test 3.3 {
|
||||
SELECT * FROM x2 CROSS JOIN x1 WHERE (1234, x2.y) > (x1.a, x1.b);
|
||||
} {1234 abc 1234 ABCD}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the fix for forum post https://sqlite.org/forum/forumpost/7a308e933d
|
||||
#
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1 (a PRIMARY KEY, b COLLATE NOCASE) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES ('BBB', 'a');
|
||||
}
|
||||
do_execsql_test 4.1 {
|
||||
SELECT * FROM t1 WHERE (t1.a, t1.b) <= ('BBB', 'CCC');
|
||||
} {BBB a}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t0 (c0);
|
||||
INSERT INTO t0 VALUES ('True');
|
||||
|
||||
CREATE TABLE t1 (c0 COLLATE NOCASE, c1 PRIMARY KEY) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES ('a', 1);
|
||||
INSERT INTO t1 VALUES ('a', 'True');
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
SELECT * FROM t0, t1 WHERE (t1.c1, t1.c0) <= (t0.c0, t0.c0);
|
||||
} {True a 1 True a True}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-1
@@ -445,7 +445,8 @@ do_test shell1-3.12.2-legacy {
|
||||
do_test shell1-3.12.3 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".indexes FOO BAD"
|
||||
} {1 {Usage: .indexes ?LIKE-PATTERN?}}
|
||||
} {1 {line 1: .indexes FOO BAD
|
||||
line 1: ^--- unknown argument}}
|
||||
|
||||
# .mode MODE ?TABLE? Set output mode where MODE is one of:
|
||||
# ascii Columns/rows delimited by 0x1F and 0x1E
|
||||
|
||||
+1
-1
@@ -43,8 +43,8 @@ do_clitest dblwidth-a.sql
|
||||
do_clitest vt100-a.sql
|
||||
do_clitest regexp1.sql
|
||||
do_clitest imposter1.sql
|
||||
do_clitest dotcmd01.sql
|
||||
ifcapable vtab {
|
||||
do_clitest dotcmd01.sql
|
||||
do_clitest import01.sql
|
||||
do_clitest intck01.sql
|
||||
}
|
||||
|
||||
@@ -190,5 +190,26 @@ do_execsql_test 220 {
|
||||
SELECT x FROM closure ORDER BY +x;
|
||||
} {1 2 3 4 5 6 7 8 9 11 13}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Forum: https://sqlite.org/forum/forumpost/deb1eadf4d677bd5
|
||||
#
|
||||
# For a recursive CTE, do not assume rows are delivered in the order
|
||||
# specified by the ORDER BY clause. In this case ORDER BY governs the
|
||||
# order in which the queue is processed, not the overall order in which
|
||||
# rows are emitted by the CTE.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 300 {
|
||||
CREATE TABLE tree(id INTEGER PRIMARY KEY, parent INTEGER);
|
||||
INSERT INTO tree VALUES(3, 1);
|
||||
INSERT INTO tree VALUES(2, 3);
|
||||
}
|
||||
|
||||
do_execsql_test 310 {
|
||||
WITH RECURSIVE tt(ii) AS (
|
||||
VALUES(1) UNION ALL SELECT id FROM tree, tt WHERE parent=ii ORDER BY id
|
||||
)
|
||||
SELECT * FROM tt ORDER BY ii;
|
||||
} {1 2 3}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -276,6 +276,7 @@ set boolean_defnil_options {
|
||||
SQLITE_SECURE_DELETE
|
||||
SQLITE_SMALL_STACK
|
||||
SQLITE_SOUNDEX
|
||||
SQLITE_STRICT_SUBTYPE
|
||||
SQLITE_SUBSTR_COMPATIBILITY
|
||||
SQLITE_TCL
|
||||
SQLITE_TEST
|
||||
|
||||
@@ -68,6 +68,7 @@ gcc -c $WARNING_OPTS -std=c99 \
|
||||
echo '**** Optimized -O3. Includes FTS4/5, GEOPOLY, JSON1 ******'
|
||||
echo '****' $WARNING_OPTS
|
||||
gcc -O3 -c $WARNING_OPTS -std=c99 \
|
||||
-Wdeclaration-after-statement \
|
||||
-DHAVE_STDINT_H \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_ENABLE_FTS5 \
|
||||
|
||||
Reference in New Issue
Block a user