Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea933f07b0 | |||
| ea99a31c59 | |||
| 378a2da91e | |||
| ac306682df | |||
| 4522c3e8d1 | |||
| e79522633a | |||
| 7f32dc94a3 | |||
| 140a59874b | |||
| 2f69b5c5d0 | |||
| b80bb6ce88 | |||
| e882551935 | |||
| 7490128240 | |||
| 222a384a06 | |||
| 9341916ed5 | |||
| 5d6374fa39 | |||
| c3649417fe | |||
| b0225bc52d | |||
| fef37760da | |||
| fd908888d3 | |||
| b556f26145 | |||
| 6ccbd2787b | |||
| 7083a487ad | |||
| eee0861155 | |||
| 38630ae1de | |||
| 6cbb4c936c | |||
| a1fd4b520b | |||
| 0b3b0dd1b1 | |||
| c7bf57168a | |||
| 142066d4b0 | |||
| f710345303 | |||
| 77f3f40292 | |||
| e6fcd1d5de | |||
| 7999cc434e | |||
| a57aac262f | |||
| a1a7e112fe | |||
| f5e8e31399 | |||
| 1e80ace47a | |||
| 8ff21f47f0 | |||
| 19dc4d40e7 | |||
| a546ef219e | |||
| 51a6b19337 | |||
| 491d4c89f5 | |||
| 8f0c712a1f | |||
| fd4b72853a | |||
| 2c885d0575 | |||
| a5ef149c4e | |||
| d4fc49f735 | |||
| e4984a2bf4 | |||
| bfead59b3b | |||
| 5d764ac9e6 | |||
| 287fa17b78 | |||
| cf0343b699 | |||
| e33f6e7c91 | |||
| 8f26da6c5b | |||
| 6ea9a7282a | |||
| 8be47a7e86 | |||
| 7a606e1ab2 | |||
| 683b0fffee | |||
| f213b33c37 | |||
| 8bf6d705f3 | |||
| b775104357 | |||
| b07db116e7 | |||
| 7fee0bfad2 | |||
| d736829e8b | |||
| f607bec749 | |||
| 6b4b88208e | |||
| 7262ca94cb | |||
| 9f607e9c23 | |||
| d2ac43ea38 | |||
| 9592320b91 |
@@ -0,0 +1,87 @@
|
||||
|
||||
SQLite's OS layer contains the following definitions used in F2FS related
|
||||
calls:
|
||||
|
||||
#define F2FS_IOCTL_MAGIC 0xf5
|
||||
#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
|
||||
#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
|
||||
#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
|
||||
#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
|
||||
#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32)
|
||||
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
|
||||
|
||||
After opening a database file on Linux (including Android), SQLite determines
|
||||
whether or not a file supports F2FS atomic commits as follows:
|
||||
|
||||
u32 flags = 0;
|
||||
rc = ioctl(fd, F2FS_IOC_GET_FEATURES, &flags);
|
||||
if( rc==0 && (flags & F2FS_FEATURE_ATOMIC_WRITE) ){
|
||||
/* File supports F2FS atomic commits */
|
||||
}else{
|
||||
/* File does NOT support F2FS atomic commits */
|
||||
}
|
||||
|
||||
where "fd" is the file-descriptor open on the database file.
|
||||
|
||||
Usually, when writing to a database file that supports atomic commits, SQLite
|
||||
accumulates the entire transaction in heap memory, deferring all writes to the
|
||||
db file until the transaction is committed.
|
||||
|
||||
When it is time to commit a transaction on a file that supports atomic
|
||||
commits, SQLite does:
|
||||
|
||||
/* Take an F_WRLCK lock on the database file. This prevents any other
|
||||
** SQLite clients from reading or writing the file until the lock
|
||||
** is released. */
|
||||
rc = fcntl(fd, F_SETLK, ...);
|
||||
if( rc!=0 ) goto failed;
|
||||
|
||||
rc = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE);
|
||||
if( rc!=0 ) goto fallback_to_legacy_journal_commit;
|
||||
|
||||
foreach (dirty page){
|
||||
rc = write(fd, ...dirty page...);
|
||||
if( rc!=0 ){
|
||||
ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
|
||||
goto fallback_to_legacy_journal_commit;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE);
|
||||
if( rc!=0 ){
|
||||
ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
|
||||
goto fallback_to_legacy_journal_commit;
|
||||
}
|
||||
|
||||
/* If we get there, the transaction has been successfully
|
||||
** committed to persistent storage. The following call
|
||||
** relinquishes the F_WRLCK lock. */
|
||||
fcntl(fd, F_SETLK, ...);
|
||||
|
||||
Assumptions:
|
||||
|
||||
1. After either of the F2FS_IOC_ABORT_VOLATILE_WRITE calls return,
|
||||
the database file is in the state that it was in before
|
||||
F2FS_IOC_START_ATOMIC_WRITE was invoked. Even if the ioctl()
|
||||
fails - we're ignoring the return code.
|
||||
|
||||
This is true regardless of the type of error that occurred in
|
||||
ioctl() or write().
|
||||
|
||||
2. If the system fails before the F2FS_IOC_COMMIT_ATOMIC_WRITE is
|
||||
completed, then following a reboot the database file is in the
|
||||
state that it was in before F2FS_IOC_START_ATOMIC_WRITE was invoked.
|
||||
Or, if the write was commited right before the system failed, in a
|
||||
state indicating that all write() calls were successfully committed
|
||||
to persistent storage before the failure occurred.
|
||||
|
||||
3. If the process crashes before the F2FS_IOC_COMMIT_ATOMIC_WRITE is
|
||||
completed then the file is automatically restored to the state that
|
||||
it was in before F2FS_IOC_START_ATOMIC_WRITE was called. This occurs
|
||||
before the posix advisory lock is automatically dropped - there is
|
||||
no chance that another client will be able to read the file in a
|
||||
half-committed state before the rollback operation occurs.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -529,6 +529,263 @@ proc print_fold {zFunc} {
|
||||
puts "\}"
|
||||
}
|
||||
|
||||
proc code {txt} {
|
||||
set txt [string trimright $txt]
|
||||
set txt [string trimleft $txt "\n"]
|
||||
set n [expr {[string length $txt] - [string length [string trim $txt]]}]
|
||||
set ret ""
|
||||
foreach L [split $txt "\n"] {
|
||||
append ret "[string range $L $n end]\n"
|
||||
}
|
||||
return [uplevel "subst -nocommands {$ret}"]
|
||||
}
|
||||
|
||||
proc intarray {lInt} {
|
||||
set ret ""
|
||||
set n [llength $lInt]
|
||||
for {set i 0} {$i < $n} {incr i 10} {
|
||||
append ret "\n "
|
||||
foreach int [lrange $lInt $i [expr $i+9]] {
|
||||
append ret [format "%-7s" "$int, "]
|
||||
}
|
||||
}
|
||||
append ret "\n "
|
||||
set ret
|
||||
}
|
||||
|
||||
proc categories_switch {Cvar first lSecond} {
|
||||
upvar $Cvar C
|
||||
set ret ""
|
||||
append ret "case '$first':\n"
|
||||
append ret " switch( zCat\[1\] ){\n"
|
||||
foreach s $lSecond {
|
||||
append ret " case '$s': aArray\[$C($first$s)\] = 1; break;\n"
|
||||
}
|
||||
append ret " case '*': \n"
|
||||
foreach s $lSecond {
|
||||
append ret " aArray\[$C($first$s)\] = 1;\n"
|
||||
}
|
||||
append ret " break;\n"
|
||||
append ret " default: return 1;"
|
||||
append ret " }\n"
|
||||
append ret " break;\n"
|
||||
}
|
||||
|
||||
# Argument is a list. Each element of which is itself a list of two elements:
|
||||
#
|
||||
# * the codepoint
|
||||
# * the category
|
||||
#
|
||||
# List elements are sorted in order of codepoint.
|
||||
#
|
||||
proc print_categories {lMap} {
|
||||
set categories {
|
||||
Cc Cf Cn Cs
|
||||
Ll Lm Lo Lt Lu
|
||||
Mc Me Mn
|
||||
Nd Nl No
|
||||
Pc Pd Pe Pf Pi Po Ps
|
||||
Sc Sk Sm So
|
||||
Zl Zp Zs
|
||||
|
||||
LC Co
|
||||
}
|
||||
|
||||
for {set i 0} {$i < [llength $categories]} {incr i} {
|
||||
set C([lindex $categories $i]) [expr 1+$i]
|
||||
}
|
||||
|
||||
set caseC [categories_switch C C {c f n s o}]
|
||||
set caseL [categories_switch C L {l m o t u C}]
|
||||
set caseM [categories_switch C M {c e n}]
|
||||
set caseN [categories_switch C N {d l o}]
|
||||
set caseP [categories_switch C P {c d e f i o s}]
|
||||
set caseS [categories_switch C S {c k m o}]
|
||||
set caseZ [categories_switch C Z {l p s}]
|
||||
|
||||
set nCat [expr [llength [array names C]] + 1]
|
||||
puts [code {
|
||||
int sqlite3Fts5UnicodeNCat(void) {
|
||||
return $nCat;
|
||||
}
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
||||
aArray[0] = 1;
|
||||
switch( zCat[0] ){
|
||||
$caseC
|
||||
$caseL
|
||||
$caseM
|
||||
$caseN
|
||||
$caseP
|
||||
$caseS
|
||||
$caseZ
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}]
|
||||
|
||||
set nRepeat 0
|
||||
set first [lindex $lMap 0 0]
|
||||
set class [lindex $lMap 0 1]
|
||||
set prev -1
|
||||
|
||||
set CASE(0) "Lu"
|
||||
set CASE(1) "Ll"
|
||||
|
||||
foreach m $lMap {
|
||||
foreach {codepoint cl} $m {}
|
||||
set codepoint [expr "0x$codepoint"]
|
||||
if {$codepoint>=(1<<20)} continue
|
||||
|
||||
set bNew 0
|
||||
if {$codepoint!=($prev+1)} {
|
||||
set bNew 1
|
||||
} elseif {
|
||||
$cl==$class || ($class=="LC" && $cl==$CASE([expr $nRepeat & 0x01]))
|
||||
} {
|
||||
incr nRepeat
|
||||
} elseif {$class=="Lu" && $nRepeat==1 && $cl=="Ll"} {
|
||||
set class LC
|
||||
incr nRepeat
|
||||
} else {
|
||||
set bNew 1
|
||||
}
|
||||
if {$bNew} {
|
||||
lappend lEntries [list $first $class $nRepeat]
|
||||
set nRepeat 1
|
||||
set first $codepoint
|
||||
set class $cl
|
||||
}
|
||||
set prev $codepoint
|
||||
}
|
||||
if {$nRepeat>0} {
|
||||
lappend lEntries [list $first $class $nRepeat]
|
||||
}
|
||||
|
||||
set aBlock [list 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
||||
set aMap [list]
|
||||
foreach e $lEntries {
|
||||
foreach {cp class nRepeat} $e {}
|
||||
set block [expr ($cp>>16)]
|
||||
if {$block>0 && [lindex $aBlock $block]==0} {
|
||||
for {set i 1} {$i<=$block} {incr i} {
|
||||
if {[lindex $aBlock $i]==0} {
|
||||
lset aBlock $i [llength $aMap]
|
||||
}
|
||||
}
|
||||
}
|
||||
lappend aMap [expr {$cp & 0xFFFF}]
|
||||
lappend aData [expr {($nRepeat << 5) + $C($class)}]
|
||||
}
|
||||
for {set i 1} {$i<[llength $aBlock]} {incr i} {
|
||||
if {[lindex $aBlock $i]==0} {
|
||||
lset aBlock $i [llength $aMap]
|
||||
}
|
||||
}
|
||||
|
||||
set aBlockArray [intarray $aBlock]
|
||||
set aMapArray [intarray $aMap]
|
||||
set aDataArray [intarray $aData]
|
||||
puts [code {
|
||||
static u16 aFts5UnicodeBlock[] = {$aBlockArray};
|
||||
static u16 aFts5UnicodeMap[] = {$aMapArray};
|
||||
static u16 aFts5UnicodeData[] = {$aDataArray};
|
||||
|
||||
int sqlite3Fts5UnicodeCategory(int iCode) {
|
||||
int iRes = -1;
|
||||
int iHi;
|
||||
int iLo;
|
||||
int ret;
|
||||
u16 iKey;
|
||||
|
||||
if( iCode>=(1<<20) ){
|
||||
return 0;
|
||||
}
|
||||
iLo = aFts5UnicodeBlock[(iCode>>16)];
|
||||
iHi = aFts5UnicodeBlock[1+(iCode>>16)];
|
||||
iKey = (iCode & 0xFFFF);
|
||||
while( iHi>iLo ){
|
||||
int iTest = (iHi + iLo) / 2;
|
||||
assert( iTest>=iLo && iTest<iHi );
|
||||
if( iKey>=aFts5UnicodeMap[iTest] ){
|
||||
iRes = iTest;
|
||||
iLo = iTest+1;
|
||||
}else{
|
||||
iHi = iTest;
|
||||
}
|
||||
}
|
||||
|
||||
if( iRes<0 ) return 0;
|
||||
if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0;
|
||||
ret = aFts5UnicodeData[iRes] & 0x1F;
|
||||
if( ret!=$C(LC) ) return ret;
|
||||
return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? $C(Ll) : $C(Lu);
|
||||
}
|
||||
|
||||
void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
|
||||
int i = 0;
|
||||
int iTbl = 0;
|
||||
while( i<128 ){
|
||||
int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
|
||||
int n = (aFts5UnicodeData[iTbl] >> 5) + i;
|
||||
for(; i<128 && i<n; i++){
|
||||
aAscii[i] = bToken;
|
||||
}
|
||||
iTbl++;
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
proc print_test_categories {lMap} {
|
||||
|
||||
set lCP [list]
|
||||
foreach e $lMap {
|
||||
foreach {cp cat} $e {}
|
||||
if {[expr 0x$cp] < (1<<20)} {
|
||||
lappend lCP "{0x$cp, \"$cat\"}, "
|
||||
}
|
||||
}
|
||||
|
||||
set aCP "\n"
|
||||
for {set i 0} {$i < [llength $lCP]} {incr i 4} {
|
||||
append aCP " [join [lrange $lCP $i $i+3]]\n"
|
||||
}
|
||||
|
||||
|
||||
puts [code {
|
||||
static int categories_test (int *piCode){
|
||||
struct Codepoint {
|
||||
int iCode;
|
||||
const char *zCat;
|
||||
} aCP[] = {$aCP};
|
||||
int i;
|
||||
int iCP = 0;
|
||||
|
||||
for(i=0; i<1000000; i++){
|
||||
u8 aArray[40];
|
||||
int cat = 0;
|
||||
int c = 0;
|
||||
memset(aArray, 0, sizeof(aArray));
|
||||
if( aCP[iCP].iCode==i ){
|
||||
sqlite3Fts5UnicodeCatParse(aCP[iCP].zCat, aArray);
|
||||
iCP++;
|
||||
}else{
|
||||
aArray[0] = 1;
|
||||
}
|
||||
|
||||
c = sqlite3Fts5UnicodeCategory(i);
|
||||
if( aArray[c]==0 ){
|
||||
*piCode = i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
proc print_fold_test {zFunc mappings} {
|
||||
global tl_lookup_table
|
||||
|
||||
@@ -605,15 +862,21 @@ proc print_test_main {} {
|
||||
puts "#include <stdio.h>"
|
||||
puts ""
|
||||
puts "int main(int argc, char **argv)\{"
|
||||
puts " int r1, r2;"
|
||||
puts " int r1, r2, r3;"
|
||||
puts " int code;"
|
||||
puts " r3 = 0;"
|
||||
puts " r1 = isalnum_test(&code);"
|
||||
puts " if( r1 ) printf(\"isalnum(): Problem with code %d\\n\",code);"
|
||||
puts " else printf(\"isalnum(): test passed\\n\");"
|
||||
puts " r2 = fold_test(&code);"
|
||||
puts " if( r2 ) printf(\"fold(): Problem with code %d\\n\",code);"
|
||||
puts " else printf(\"fold(): test passed\\n\");"
|
||||
puts " return (r1 || r2);"
|
||||
if {$::generate_fts5_code} {
|
||||
puts " r3 = categories_test(&code);"
|
||||
puts " if( r3 ) printf(\"categories(): Problem with code %d\\n\",code);"
|
||||
puts " else printf(\"categories(): test passed\\n\");"
|
||||
}
|
||||
puts " return (r1 || r2 || r3);"
|
||||
puts "\}"
|
||||
}
|
||||
|
||||
@@ -651,10 +914,18 @@ for {set i 0} {$i < [llength $argv]-2} {incr i} {
|
||||
|
||||
print_fileheader
|
||||
|
||||
if {$::generate_test_code} {
|
||||
puts "typedef unsigned short int u16;"
|
||||
puts "typedef unsigned char u8;"
|
||||
puts "#include <string.h>"
|
||||
}
|
||||
|
||||
# Print the isalnum() function to stdout.
|
||||
#
|
||||
set lRange [an_load_separator_ranges]
|
||||
print_isalnum ${function_prefix}UnicodeIsalnum $lRange
|
||||
if {$generate_fts5_code==0} {
|
||||
print_isalnum ${function_prefix}UnicodeIsalnum $lRange
|
||||
}
|
||||
|
||||
# Leave a gap between the two generated C functions.
|
||||
#
|
||||
@@ -677,12 +948,21 @@ puts ""
|
||||
#
|
||||
print_fold ${function_prefix}UnicodeFold
|
||||
|
||||
if {$generate_fts5_code} {
|
||||
puts ""
|
||||
puts ""
|
||||
print_categories [cc_load_unicodedata_text ${unicodedata.txt}]
|
||||
}
|
||||
|
||||
# Print the test routines and main() function to stdout, if -test
|
||||
# was specified.
|
||||
#
|
||||
if {$::generate_test_code} {
|
||||
print_test_isalnum ${function_prefix}UnicodeIsalnum $lRange
|
||||
if {$generate_fts5_code==0} {
|
||||
print_test_isalnum ${function_prefix}UnicodeIsalnum $lRange
|
||||
}
|
||||
print_fold_test ${function_prefix}UnicodeFold $mappings
|
||||
print_test_categories [cc_load_unicodedata_text ${unicodedata.txt}]
|
||||
print_test_main
|
||||
}
|
||||
|
||||
|
||||
@@ -143,4 +143,40 @@ proc tl_load_casefolding_txt {zName} {
|
||||
}
|
||||
}
|
||||
|
||||
proc cc_load_unicodedata_text {zName} {
|
||||
set fd [open $zName]
|
||||
set lField {
|
||||
code
|
||||
character_name
|
||||
general_category
|
||||
canonical_combining_classes
|
||||
bidirectional_category
|
||||
character_decomposition_mapping
|
||||
decimal_digit_value
|
||||
digit_value
|
||||
numeric_value
|
||||
mirrored
|
||||
unicode_1_name
|
||||
iso10646_comment_field
|
||||
uppercase_mapping
|
||||
lowercase_mapping
|
||||
titlecase_mapping
|
||||
}
|
||||
set lRet [list]
|
||||
|
||||
while { ![eof $fd] } {
|
||||
set line [gets $fd]
|
||||
if {$line == ""} continue
|
||||
|
||||
set fields [split $line ";"]
|
||||
if {[llength $fields] != [llength $lField]} { error "parse error: $line" }
|
||||
foreach $lField $fields {}
|
||||
|
||||
lappend lRet [list $code $general_category]
|
||||
}
|
||||
|
||||
close $fd
|
||||
set lRet
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-1
@@ -784,9 +784,12 @@ int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
|
||||
/**************************************************************************
|
||||
** Interface to automatically generated code in fts5_unicode2.c.
|
||||
*/
|
||||
int sqlite3Fts5UnicodeIsalnum(int c);
|
||||
int sqlite3Fts5UnicodeIsdiacritic(int c);
|
||||
int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char*, u8*);
|
||||
int sqlite3Fts5UnicodeCategory(int iCode);
|
||||
void sqlite3Fts5UnicodeAscii(u8*, u8*);
|
||||
/*
|
||||
** End of interface to code in fts5_unicode2.c.
|
||||
**************************************************************************/
|
||||
|
||||
+10
-2
@@ -36,6 +36,7 @@ void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*);
|
||||
#include <stdio.h>
|
||||
void sqlite3Fts5ParserTrace(FILE*, char*);
|
||||
#endif
|
||||
int sqlite3Fts5ParserFallback(int);
|
||||
|
||||
|
||||
struct Fts5Expr {
|
||||
@@ -2540,14 +2541,19 @@ static void fts5ExprIsAlnum(
|
||||
sqlite3_value **apVal /* Function arguments */
|
||||
){
|
||||
int iCode;
|
||||
u8 aArr[32];
|
||||
if( nArg!=1 ){
|
||||
sqlite3_result_error(pCtx,
|
||||
"wrong number of arguments to function fts5_isalnum", -1
|
||||
);
|
||||
return;
|
||||
}
|
||||
memset(aArr, 0, sizeof(aArr));
|
||||
sqlite3Fts5UnicodeCatParse("L*", aArr);
|
||||
sqlite3Fts5UnicodeCatParse("N*", aArr);
|
||||
sqlite3Fts5UnicodeCatParse("Co", aArr);
|
||||
iCode = sqlite3_value_int(apVal[0]);
|
||||
sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode));
|
||||
sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]);
|
||||
}
|
||||
|
||||
static void fts5ExprFold(
|
||||
@@ -2591,10 +2597,12 @@ int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
|
||||
rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
|
||||
}
|
||||
|
||||
/* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */
|
||||
/* Avoid warnings indicating that sqlite3Fts5ParserTrace() and
|
||||
** sqlite3Fts5ParserFallback() are unused */
|
||||
#ifndef NDEBUG
|
||||
(void)sqlite3Fts5ParserTrace;
|
||||
#endif
|
||||
(void)sqlite3Fts5ParserFallback;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -237,6 +237,8 @@ struct Unicode61Tokenizer {
|
||||
int bRemoveDiacritic; /* True if remove_diacritics=1 is set */
|
||||
int nException;
|
||||
int *aiException;
|
||||
|
||||
unsigned char aCategory[32]; /* True for token char categories */
|
||||
};
|
||||
|
||||
static int fts5UnicodeAddExceptions(
|
||||
@@ -261,7 +263,7 @@ static int fts5UnicodeAddExceptions(
|
||||
if( iCode<128 ){
|
||||
p->aTokenChar[iCode] = (unsigned char)bTokenChars;
|
||||
}else{
|
||||
bToken = sqlite3Fts5UnicodeIsalnum(iCode);
|
||||
bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)];
|
||||
assert( (bToken==0 || bToken==1) );
|
||||
assert( (bTokenChars==0 || bTokenChars==1) );
|
||||
if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
|
||||
@@ -322,6 +324,21 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
|
||||
return;
|
||||
}
|
||||
|
||||
static int unicodeSetCategories(Unicode61Tokenizer *p, const char *zCat){
|
||||
const char *z = zCat;
|
||||
|
||||
while( *z ){
|
||||
while( *z==' ' || *z=='\t' ) z++;
|
||||
if( *z && sqlite3Fts5UnicodeCatParse(z, p->aCategory) ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
while( *z!=' ' && *z!='\t' && *z!='\0' ) z++;
|
||||
}
|
||||
|
||||
sqlite3Fts5UnicodeAscii(p->aCategory, p->aTokenChar);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a "unicode61" tokenizer.
|
||||
*/
|
||||
@@ -340,15 +357,28 @@ static int fts5UnicodeCreate(
|
||||
}else{
|
||||
p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer));
|
||||
if( p ){
|
||||
const char *zCat = "L* N* Co";
|
||||
int i;
|
||||
memset(p, 0, sizeof(Unicode61Tokenizer));
|
||||
memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
|
||||
|
||||
p->bRemoveDiacritic = 1;
|
||||
p->nFold = 64;
|
||||
p->aFold = sqlite3_malloc(p->nFold * sizeof(char));
|
||||
if( p->aFold==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
/* Search for a "categories" argument */
|
||||
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
||||
if( 0==sqlite3_stricmp(azArg[i], "categories") ){
|
||||
zCat = azArg[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = unicodeSetCategories(p, zCat);
|
||||
}
|
||||
|
||||
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
||||
const char *zArg = azArg[i+1];
|
||||
if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
|
||||
@@ -362,10 +392,14 @@ static int fts5UnicodeCreate(
|
||||
}else
|
||||
if( 0==sqlite3_stricmp(azArg[i], "separators") ){
|
||||
rc = fts5UnicodeAddExceptions(p, zArg, 0);
|
||||
}else
|
||||
if( 0==sqlite3_stricmp(azArg[i], "categories") ){
|
||||
/* no-op */
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -384,8 +418,10 @@ static int fts5UnicodeCreate(
|
||||
** character (not a separator).
|
||||
*/
|
||||
static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
|
||||
assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
|
||||
return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode);
|
||||
return (
|
||||
p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]
|
||||
^ fts5UnicodeIsException(p, iCode)
|
||||
);
|
||||
}
|
||||
|
||||
static int fts5UnicodeTokenize(
|
||||
|
||||
+533
-129
@@ -18,135 +18,6 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
** Return true if the argument corresponds to a unicode codepoint
|
||||
** classified as either a letter or a number. Otherwise false.
|
||||
**
|
||||
** The results are undefined if the value passed to this function
|
||||
** is less than zero.
|
||||
*/
|
||||
int sqlite3Fts5UnicodeIsalnum(int c){
|
||||
/* Each unsigned integer in the following array corresponds to a contiguous
|
||||
** range of unicode codepoints that are not either letters or numbers (i.e.
|
||||
** codepoints for which this function should return 0).
|
||||
**
|
||||
** The most significant 22 bits in each 32-bit value contain the first
|
||||
** codepoint in the range. The least significant 10 bits are used to store
|
||||
** the size of the range (always at least 1). In other words, the value
|
||||
** ((C<<22) + N) represents a range of N codepoints starting with codepoint
|
||||
** C. It is not possible to represent a range larger than 1023 codepoints
|
||||
** using this format.
|
||||
*/
|
||||
static const unsigned int aEntry[] = {
|
||||
0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07,
|
||||
0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01,
|
||||
0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401,
|
||||
0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01,
|
||||
0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01,
|
||||
0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802,
|
||||
0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F,
|
||||
0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401,
|
||||
0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804,
|
||||
0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403,
|
||||
0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812,
|
||||
0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001,
|
||||
0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802,
|
||||
0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805,
|
||||
0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401,
|
||||
0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03,
|
||||
0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807,
|
||||
0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001,
|
||||
0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01,
|
||||
0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804,
|
||||
0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001,
|
||||
0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802,
|
||||
0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01,
|
||||
0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06,
|
||||
0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007,
|
||||
0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006,
|
||||
0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417,
|
||||
0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14,
|
||||
0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07,
|
||||
0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01,
|
||||
0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001,
|
||||
0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802,
|
||||
0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F,
|
||||
0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002,
|
||||
0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802,
|
||||
0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006,
|
||||
0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D,
|
||||
0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802,
|
||||
0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027,
|
||||
0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403,
|
||||
0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805,
|
||||
0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04,
|
||||
0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401,
|
||||
0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005,
|
||||
0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B,
|
||||
0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A,
|
||||
0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001,
|
||||
0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59,
|
||||
0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807,
|
||||
0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01,
|
||||
0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E,
|
||||
0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100,
|
||||
0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10,
|
||||
0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402,
|
||||
0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804,
|
||||
0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012,
|
||||
0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
|
||||
0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002,
|
||||
0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803,
|
||||
0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07,
|
||||
0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02,
|
||||
0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802,
|
||||
0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013,
|
||||
0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06,
|
||||
0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003,
|
||||
0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01,
|
||||
0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403,
|
||||
0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009,
|
||||
0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003,
|
||||
0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003,
|
||||
0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E,
|
||||
0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046,
|
||||
0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401,
|
||||
0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401,
|
||||
0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F,
|
||||
0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C,
|
||||
0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002,
|
||||
0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025,
|
||||
0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6,
|
||||
0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46,
|
||||
0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060,
|
||||
0x380400F0,
|
||||
};
|
||||
static const unsigned int aAscii[4] = {
|
||||
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
|
||||
};
|
||||
|
||||
if( (unsigned int)c<128 ){
|
||||
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
|
||||
}else if( (unsigned int)c<(1<<22) ){
|
||||
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
|
||||
int iRes = 0;
|
||||
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
|
||||
int iLo = 0;
|
||||
while( iHi>=iLo ){
|
||||
int iTest = (iHi + iLo) / 2;
|
||||
if( key >= aEntry[iTest] ){
|
||||
iRes = iTest;
|
||||
iLo = iTest+1;
|
||||
}else{
|
||||
iHi = iTest-1;
|
||||
}
|
||||
}
|
||||
assert( aEntry[0]<key );
|
||||
assert( key>=aEntry[iRes] );
|
||||
return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF)));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -358,3 +229,536 @@ int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int sqlite3Fts5UnicodeNCat(void) {
|
||||
return 32;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
||||
aArray[0] = 1;
|
||||
switch( zCat[0] ){
|
||||
case 'C':
|
||||
switch( zCat[1] ){
|
||||
case 'c': aArray[1] = 1; break;
|
||||
case 'f': aArray[2] = 1; break;
|
||||
case 'n': aArray[3] = 1; break;
|
||||
case 's': aArray[4] = 1; break;
|
||||
case 'o': aArray[31] = 1; break;
|
||||
case '*':
|
||||
aArray[1] = 1;
|
||||
aArray[2] = 1;
|
||||
aArray[3] = 1;
|
||||
aArray[4] = 1;
|
||||
aArray[31] = 1;
|
||||
break;
|
||||
default: return 1; }
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
switch( zCat[1] ){
|
||||
case 'l': aArray[5] = 1; break;
|
||||
case 'm': aArray[6] = 1; break;
|
||||
case 'o': aArray[7] = 1; break;
|
||||
case 't': aArray[8] = 1; break;
|
||||
case 'u': aArray[9] = 1; break;
|
||||
case 'C': aArray[30] = 1; break;
|
||||
case '*':
|
||||
aArray[5] = 1;
|
||||
aArray[6] = 1;
|
||||
aArray[7] = 1;
|
||||
aArray[8] = 1;
|
||||
aArray[9] = 1;
|
||||
aArray[30] = 1;
|
||||
break;
|
||||
default: return 1; }
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
switch( zCat[1] ){
|
||||
case 'c': aArray[10] = 1; break;
|
||||
case 'e': aArray[11] = 1; break;
|
||||
case 'n': aArray[12] = 1; break;
|
||||
case '*':
|
||||
aArray[10] = 1;
|
||||
aArray[11] = 1;
|
||||
aArray[12] = 1;
|
||||
break;
|
||||
default: return 1; }
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
switch( zCat[1] ){
|
||||
case 'd': aArray[13] = 1; break;
|
||||
case 'l': aArray[14] = 1; break;
|
||||
case 'o': aArray[15] = 1; break;
|
||||
case '*':
|
||||
aArray[13] = 1;
|
||||
aArray[14] = 1;
|
||||
aArray[15] = 1;
|
||||
break;
|
||||
default: return 1; }
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
switch( zCat[1] ){
|
||||
case 'c': aArray[16] = 1; break;
|
||||
case 'd': aArray[17] = 1; break;
|
||||
case 'e': aArray[18] = 1; break;
|
||||
case 'f': aArray[19] = 1; break;
|
||||
case 'i': aArray[20] = 1; break;
|
||||
case 'o': aArray[21] = 1; break;
|
||||
case 's': aArray[22] = 1; break;
|
||||
case '*':
|
||||
aArray[16] = 1;
|
||||
aArray[17] = 1;
|
||||
aArray[18] = 1;
|
||||
aArray[19] = 1;
|
||||
aArray[20] = 1;
|
||||
aArray[21] = 1;
|
||||
aArray[22] = 1;
|
||||
break;
|
||||
default: return 1; }
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
switch( zCat[1] ){
|
||||
case 'c': aArray[23] = 1; break;
|
||||
case 'k': aArray[24] = 1; break;
|
||||
case 'm': aArray[25] = 1; break;
|
||||
case 'o': aArray[26] = 1; break;
|
||||
case '*':
|
||||
aArray[23] = 1;
|
||||
aArray[24] = 1;
|
||||
aArray[25] = 1;
|
||||
aArray[26] = 1;
|
||||
break;
|
||||
default: return 1; }
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
switch( zCat[1] ){
|
||||
case 'l': aArray[27] = 1; break;
|
||||
case 'p': aArray[28] = 1; break;
|
||||
case 's': aArray[29] = 1; break;
|
||||
case '*':
|
||||
aArray[27] = 1;
|
||||
aArray[28] = 1;
|
||||
aArray[29] = 1;
|
||||
break;
|
||||
default: return 1; }
|
||||
break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 aFts5UnicodeBlock[] = {
|
||||
0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760,
|
||||
1760, 1760, 1760, 1760, 1760, 1763, 1765,
|
||||
};
|
||||
static u16 aFts5UnicodeMap[] = {
|
||||
0, 32, 33, 36, 37, 40, 41, 42, 43, 44,
|
||||
45, 46, 48, 58, 60, 63, 65, 91, 92, 93,
|
||||
94, 95, 96, 97, 123, 124, 125, 126, 127, 160,
|
||||
161, 162, 166, 167, 168, 169, 170, 171, 172, 173,
|
||||
174, 175, 176, 177, 178, 180, 181, 182, 184, 185,
|
||||
186, 187, 188, 191, 192, 215, 216, 223, 247, 248,
|
||||
256, 312, 313, 329, 330, 377, 383, 385, 387, 388,
|
||||
391, 394, 396, 398, 402, 403, 405, 406, 409, 412,
|
||||
414, 415, 417, 418, 423, 427, 428, 431, 434, 436,
|
||||
437, 440, 442, 443, 444, 446, 448, 452, 453, 454,
|
||||
455, 456, 457, 458, 459, 460, 461, 477, 478, 496,
|
||||
497, 498, 499, 500, 503, 505, 506, 564, 570, 572,
|
||||
573, 575, 577, 580, 583, 584, 592, 660, 661, 688,
|
||||
706, 710, 722, 736, 741, 748, 749, 750, 751, 768,
|
||||
880, 884, 885, 886, 890, 891, 894, 900, 902, 903,
|
||||
904, 908, 910, 912, 913, 931, 940, 975, 977, 978,
|
||||
981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072,
|
||||
1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369,
|
||||
1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473,
|
||||
1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545,
|
||||
1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611,
|
||||
1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758,
|
||||
1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791,
|
||||
1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984,
|
||||
1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075,
|
||||
2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210,
|
||||
2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369,
|
||||
2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416,
|
||||
2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482,
|
||||
2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519,
|
||||
2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561,
|
||||
2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622,
|
||||
2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677,
|
||||
2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749,
|
||||
2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790,
|
||||
2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869,
|
||||
2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902,
|
||||
2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947,
|
||||
2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006,
|
||||
3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059,
|
||||
3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134,
|
||||
3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199,
|
||||
3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263,
|
||||
3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302,
|
||||
3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402,
|
||||
3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458,
|
||||
3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544,
|
||||
3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655,
|
||||
3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737,
|
||||
3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773,
|
||||
3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860,
|
||||
3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896,
|
||||
3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967,
|
||||
3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046,
|
||||
4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153,
|
||||
4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190,
|
||||
4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229,
|
||||
4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295,
|
||||
4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704,
|
||||
4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888,
|
||||
4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743,
|
||||
5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906,
|
||||
5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068,
|
||||
6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107,
|
||||
6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160,
|
||||
6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435,
|
||||
6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480,
|
||||
6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679,
|
||||
6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754,
|
||||
6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824,
|
||||
6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978,
|
||||
6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043,
|
||||
7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098,
|
||||
7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168,
|
||||
7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288,
|
||||
7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406,
|
||||
7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616,
|
||||
7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976,
|
||||
7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033,
|
||||
8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118,
|
||||
8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141,
|
||||
8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184,
|
||||
8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219,
|
||||
8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249,
|
||||
8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275,
|
||||
8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317,
|
||||
8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413,
|
||||
8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459,
|
||||
8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484,
|
||||
8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500,
|
||||
8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523,
|
||||
8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597,
|
||||
8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623,
|
||||
8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972,
|
||||
8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180,
|
||||
9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665,
|
||||
9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091,
|
||||
10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101,
|
||||
10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217,
|
||||
10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627,
|
||||
10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637,
|
||||
10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647,
|
||||
10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750,
|
||||
11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365,
|
||||
11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393,
|
||||
11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520,
|
||||
11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696,
|
||||
11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780,
|
||||
11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800,
|
||||
11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812,
|
||||
11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904,
|
||||
11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296,
|
||||
12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306,
|
||||
12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317,
|
||||
12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347,
|
||||
12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449,
|
||||
12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736,
|
||||
12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938,
|
||||
12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981,
|
||||
40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528,
|
||||
42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624,
|
||||
42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800,
|
||||
42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912,
|
||||
43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043,
|
||||
43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136,
|
||||
43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264,
|
||||
43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395,
|
||||
43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472,
|
||||
43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588,
|
||||
43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643,
|
||||
43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713,
|
||||
43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762,
|
||||
43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003,
|
||||
44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203,
|
||||
55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112,
|
||||
64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320,
|
||||
64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020,
|
||||
65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075,
|
||||
65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086,
|
||||
65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097,
|
||||
65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118,
|
||||
65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279,
|
||||
65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294,
|
||||
65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343,
|
||||
65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378,
|
||||
65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490,
|
||||
65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529,
|
||||
65532, 0, 13, 40, 60, 63, 80, 128, 256, 263,
|
||||
311, 320, 373, 377, 394, 400, 464, 509, 640, 672,
|
||||
768, 800, 816, 833, 834, 842, 896, 927, 928, 968,
|
||||
976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103,
|
||||
2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432,
|
||||
2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623,
|
||||
2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912,
|
||||
2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178,
|
||||
4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285,
|
||||
4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416,
|
||||
4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760,
|
||||
5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216,
|
||||
9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248,
|
||||
53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637,
|
||||
53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298,
|
||||
54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441,
|
||||
54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541,
|
||||
54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662,
|
||||
54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922,
|
||||
54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062,
|
||||
55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178,
|
||||
55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961,
|
||||
60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003,
|
||||
61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028,
|
||||
61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099,
|
||||
61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744,
|
||||
61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368,
|
||||
62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971,
|
||||
63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488,
|
||||
1, 32, 256, 0, 65533,
|
||||
};
|
||||
static u16 aFts5UnicodeData[] = {
|
||||
1025, 61, 117, 55, 117, 54, 50, 53, 57, 53,
|
||||
49, 85, 333, 85, 121, 85, 841, 54, 53, 50,
|
||||
56, 48, 56, 837, 54, 57, 50, 57, 1057, 61,
|
||||
53, 151, 58, 53, 56, 58, 39, 52, 57, 34,
|
||||
58, 56, 58, 57, 79, 56, 37, 85, 56, 47,
|
||||
39, 51, 111, 53, 745, 57, 233, 773, 57, 261,
|
||||
1822, 37, 542, 37, 1534, 222, 69, 73, 37, 126,
|
||||
126, 73, 69, 137, 37, 73, 37, 105, 101, 73,
|
||||
37, 73, 37, 190, 158, 37, 126, 126, 73, 37,
|
||||
126, 94, 37, 39, 94, 69, 135, 41, 40, 37,
|
||||
41, 40, 37, 41, 40, 37, 542, 37, 606, 37,
|
||||
41, 40, 37, 126, 73, 37, 1886, 197, 73, 37,
|
||||
73, 69, 126, 105, 37, 286, 2181, 39, 869, 582,
|
||||
152, 390, 472, 166, 248, 38, 56, 38, 568, 3596,
|
||||
158, 38, 56, 94, 38, 101, 53, 88, 41, 53,
|
||||
105, 41, 73, 37, 553, 297, 1125, 94, 37, 105,
|
||||
101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541,
|
||||
1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38,
|
||||
213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76,
|
||||
53, 76, 53, 44, 871, 103, 85, 162, 121, 85,
|
||||
55, 85, 90, 364, 53, 85, 1031, 38, 327, 684,
|
||||
333, 149, 71, 44, 3175, 53, 39, 236, 34, 58,
|
||||
204, 70, 76, 58, 140, 71, 333, 103, 90, 39,
|
||||
469, 34, 39, 44, 967, 876, 2855, 364, 39, 333,
|
||||
1063, 300, 70, 58, 117, 38, 711, 140, 38, 300,
|
||||
38, 108, 38, 172, 501, 807, 108, 53, 39, 359,
|
||||
876, 108, 42, 1735, 44, 42, 44, 39, 106, 268,
|
||||
138, 44, 74, 39, 236, 327, 76, 85, 333, 53,
|
||||
38, 199, 231, 44, 74, 263, 71, 711, 231, 39,
|
||||
135, 44, 39, 106, 140, 74, 74, 44, 39, 42,
|
||||
71, 103, 76, 333, 71, 87, 207, 58, 55, 76,
|
||||
42, 199, 71, 711, 231, 71, 71, 71, 44, 106,
|
||||
76, 76, 108, 44, 135, 39, 333, 76, 103, 44,
|
||||
76, 42, 295, 103, 711, 231, 71, 167, 44, 39,
|
||||
106, 172, 76, 42, 74, 44, 39, 71, 76, 333,
|
||||
53, 55, 44, 74, 263, 71, 711, 231, 71, 167,
|
||||
44, 39, 42, 44, 42, 140, 74, 74, 44, 44,
|
||||
42, 71, 103, 76, 333, 58, 39, 207, 44, 39,
|
||||
199, 103, 135, 71, 39, 71, 71, 103, 391, 74,
|
||||
44, 74, 106, 106, 44, 39, 42, 333, 111, 218,
|
||||
55, 58, 106, 263, 103, 743, 327, 167, 39, 108,
|
||||
138, 108, 140, 76, 71, 71, 76, 333, 239, 58,
|
||||
74, 263, 103, 743, 327, 167, 44, 39, 42, 44,
|
||||
170, 44, 74, 74, 76, 74, 39, 71, 76, 333,
|
||||
71, 74, 263, 103, 1319, 39, 106, 140, 106, 106,
|
||||
44, 39, 42, 71, 76, 333, 207, 58, 199, 74,
|
||||
583, 775, 295, 39, 231, 44, 106, 108, 44, 266,
|
||||
74, 53, 1543, 44, 71, 236, 55, 199, 38, 268,
|
||||
53, 333, 85, 71, 39, 71, 39, 39, 135, 231,
|
||||
103, 39, 39, 71, 135, 44, 71, 204, 76, 39,
|
||||
167, 38, 204, 333, 135, 39, 122, 501, 58, 53,
|
||||
122, 76, 218, 333, 335, 58, 44, 58, 44, 58,
|
||||
44, 54, 50, 54, 50, 74, 263, 1159, 460, 42,
|
||||
172, 53, 76, 167, 364, 1164, 282, 44, 218, 90,
|
||||
181, 154, 85, 1383, 74, 140, 42, 204, 42, 76,
|
||||
74, 76, 39, 333, 213, 199, 74, 76, 135, 108,
|
||||
39, 106, 71, 234, 103, 140, 423, 44, 74, 76,
|
||||
202, 44, 39, 42, 333, 106, 44, 90, 1225, 41,
|
||||
41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319,
|
||||
135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151,
|
||||
108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551,
|
||||
61, 839, 54, 50, 2407, 117, 110, 423, 135, 108,
|
||||
583, 108, 85, 583, 76, 423, 103, 76, 1671, 76,
|
||||
42, 236, 266, 44, 74, 364, 117, 38, 117, 55,
|
||||
39, 44, 333, 335, 213, 49, 149, 108, 61, 333,
|
||||
1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138,
|
||||
76, 106, 74, 44, 202, 108, 58, 85, 333, 967,
|
||||
167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76,
|
||||
106, 85, 1703, 42, 44, 42, 236, 44, 42, 44,
|
||||
74, 268, 202, 332, 44, 333, 333, 245, 38, 213,
|
||||
140, 42, 1511, 44, 42, 172, 42, 44, 170, 44,
|
||||
74, 231, 333, 245, 346, 300, 314, 76, 42, 967,
|
||||
42, 140, 74, 76, 42, 44, 74, 71, 333, 1415,
|
||||
44, 42, 76, 106, 44, 42, 108, 74, 149, 1159,
|
||||
266, 268, 74, 76, 181, 333, 103, 333, 967, 198,
|
||||
85, 277, 108, 53, 428, 42, 236, 135, 44, 135,
|
||||
74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260,
|
||||
140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265,
|
||||
261, 265, 197, 201, 261, 41, 41, 41, 94, 229,
|
||||
265, 453, 261, 264, 261, 264, 261, 264, 165, 69,
|
||||
137, 40, 56, 37, 120, 101, 69, 137, 40, 120,
|
||||
133, 69, 137, 120, 261, 169, 120, 101, 69, 137,
|
||||
40, 88, 381, 162, 209, 85, 52, 51, 54, 84,
|
||||
51, 54, 52, 277, 59, 60, 162, 61, 309, 52,
|
||||
51, 149, 80, 117, 57, 54, 50, 373, 57, 53,
|
||||
48, 341, 61, 162, 194, 47, 38, 207, 121, 54,
|
||||
50, 38, 335, 121, 54, 50, 422, 855, 428, 139,
|
||||
44, 107, 396, 90, 41, 154, 41, 90, 37, 105,
|
||||
69, 105, 37, 58, 41, 90, 57, 169, 218, 41,
|
||||
58, 41, 58, 41, 58, 137, 58, 37, 137, 37,
|
||||
135, 37, 90, 69, 73, 185, 94, 101, 58, 57,
|
||||
90, 37, 58, 527, 1134, 94, 142, 47, 185, 186,
|
||||
89, 154, 57, 90, 57, 90, 57, 250, 57, 1018,
|
||||
89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666,
|
||||
89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217,
|
||||
602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57,
|
||||
1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50,
|
||||
54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
|
||||
975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50,
|
||||
54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54,
|
||||
50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
|
||||
50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
|
||||
50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281,
|
||||
1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69,
|
||||
254, 105, 37, 94, 37, 94, 165, 70, 105, 37,
|
||||
3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221,
|
||||
37, 37, 1799, 38, 53, 44, 743, 231, 231, 231,
|
||||
231, 231, 231, 231, 231, 1036, 85, 52, 51, 52,
|
||||
51, 117, 52, 51, 53, 52, 51, 309, 49, 85,
|
||||
49, 53, 52, 51, 85, 52, 51, 54, 50, 54,
|
||||
50, 54, 50, 54, 50, 181, 38, 341, 81, 858,
|
||||
2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54,
|
||||
50, 54, 50, 54, 50, 54, 50, 54, 50, 90,
|
||||
54, 50, 54, 50, 54, 50, 54, 50, 49, 54,
|
||||
82, 58, 302, 140, 74, 49, 166, 90, 110, 38,
|
||||
39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887,
|
||||
53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178,
|
||||
519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274,
|
||||
495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38,
|
||||
36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333,
|
||||
71, 1502, 39, 44, 107, 53, 332, 53, 38, 798,
|
||||
44, 2247, 334, 76, 213, 760, 294, 88, 478, 69,
|
||||
2014, 38, 261, 190, 350, 38, 88, 158, 158, 382,
|
||||
70, 37, 231, 44, 103, 44, 135, 44, 743, 74,
|
||||
76, 42, 154, 207, 90, 55, 58, 1671, 149, 74,
|
||||
1607, 522, 44, 85, 333, 588, 199, 117, 39, 333,
|
||||
903, 268, 85, 743, 364, 74, 53, 935, 108, 42,
|
||||
1511, 44, 74, 140, 74, 44, 138, 437, 38, 333,
|
||||
85, 1319, 204, 74, 76, 74, 76, 103, 44, 263,
|
||||
44, 42, 333, 149, 519, 38, 199, 122, 39, 42,
|
||||
1543, 44, 39, 108, 71, 76, 167, 76, 39, 44,
|
||||
39, 71, 38, 85, 359, 42, 76, 74, 85, 39,
|
||||
70, 42, 44, 199, 199, 199, 231, 231, 1127, 74,
|
||||
44, 74, 44, 74, 53, 42, 44, 333, 39, 39,
|
||||
743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399,
|
||||
229, 165, 39, 44, 327, 57, 423, 167, 39, 71,
|
||||
71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55,
|
||||
58, 524, 245, 54, 50, 53, 236, 53, 81, 80,
|
||||
54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
|
||||
54, 50, 54, 50, 54, 50, 85, 54, 50, 149,
|
||||
112, 117, 149, 49, 54, 50, 54, 50, 54, 50,
|
||||
117, 57, 49, 121, 53, 55, 85, 167, 4327, 34,
|
||||
117, 55, 117, 54, 50, 53, 57, 53, 49, 85,
|
||||
333, 85, 121, 85, 841, 54, 53, 50, 56, 48,
|
||||
56, 837, 54, 57, 50, 57, 54, 50, 53, 54,
|
||||
50, 85, 327, 38, 1447, 70, 999, 199, 199, 199,
|
||||
103, 87, 57, 56, 58, 87, 58, 153, 90, 98,
|
||||
90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455,
|
||||
314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575,
|
||||
999, 143, 551, 46, 263, 46, 967, 53, 1159, 263,
|
||||
53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71,
|
||||
39, 743, 53, 271, 711, 207, 53, 839, 53, 1799,
|
||||
71, 39, 108, 76, 140, 135, 103, 871, 108, 44,
|
||||
271, 309, 935, 79, 53, 1735, 245, 711, 271, 615,
|
||||
271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655,
|
||||
333, 76, 42, 1447, 106, 140, 74, 76, 85, 34,
|
||||
149, 807, 333, 108, 1159, 172, 42, 268, 333, 149,
|
||||
76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383,
|
||||
44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182,
|
||||
149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898,
|
||||
1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236,
|
||||
986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837,
|
||||
841, 229, 581, 841, 837, 41, 73, 41, 73, 137,
|
||||
265, 133, 37, 229, 357, 841, 837, 73, 137, 265,
|
||||
233, 837, 73, 137, 169, 41, 233, 837, 841, 837,
|
||||
841, 837, 841, 837, 841, 837, 841, 837, 841, 901,
|
||||
809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
|
||||
809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
|
||||
809, 57, 805, 57, 197, 94, 1613, 135, 871, 71,
|
||||
39, 39, 327, 135, 39, 39, 39, 39, 39, 39,
|
||||
103, 71, 39, 39, 39, 39, 39, 39, 71, 39,
|
||||
135, 231, 135, 135, 39, 327, 551, 103, 167, 551,
|
||||
89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946,
|
||||
1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210,
|
||||
186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266,
|
||||
378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351,
|
||||
34, 3074, 7692, 63, 63,
|
||||
};
|
||||
|
||||
int sqlite3Fts5UnicodeCategory(int iCode) {
|
||||
int iRes = -1;
|
||||
int iHi;
|
||||
int iLo;
|
||||
int ret;
|
||||
u16 iKey;
|
||||
|
||||
if( iCode>=(1<<20) ){
|
||||
return 0;
|
||||
}
|
||||
iLo = aFts5UnicodeBlock[(iCode>>16)];
|
||||
iHi = aFts5UnicodeBlock[1+(iCode>>16)];
|
||||
iKey = (iCode & 0xFFFF);
|
||||
while( iHi>iLo ){
|
||||
int iTest = (iHi + iLo) / 2;
|
||||
assert( iTest>=iLo && iTest<iHi );
|
||||
if( iKey>=aFts5UnicodeMap[iTest] ){
|
||||
iRes = iTest;
|
||||
iLo = iTest+1;
|
||||
}else{
|
||||
iHi = iTest;
|
||||
}
|
||||
}
|
||||
|
||||
if( iRes<0 ) return 0;
|
||||
if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0;
|
||||
ret = aFts5UnicodeData[iRes] & 0x1F;
|
||||
if( ret!=30 ) return ret;
|
||||
return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? 5 : 9;
|
||||
}
|
||||
|
||||
void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
|
||||
int i = 0;
|
||||
int iTbl = 0;
|
||||
while( i<128 ){
|
||||
int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
|
||||
int n = (aFts5UnicodeData[iTbl] >> 5) + i;
|
||||
for(; i<128 && i<n; i++){
|
||||
aAscii[i] = bToken;
|
||||
}
|
||||
iTbl++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# 2016 Jan 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
ifcapable !fts5 { finish_test ; return }
|
||||
set ::testprefix fts5cat
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize="unicode61 categories 'L*'");
|
||||
INSERT INTO t1 VALUES ('Unlike1option2values3and4column5names');
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT rowid FROM t1('option');
|
||||
} {1}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(x);
|
||||
CREATE VIRTUAL TABLE t2t USING fts5vocab(t2, row);
|
||||
|
||||
CREATE VIRTUAL TABLE t3 USING fts5(
|
||||
x, tokenize="unicode61 categories 'L* N* Co Mn'"
|
||||
);
|
||||
CREATE VIRTUAL TABLE t3t USING fts5vocab(t3, row);
|
||||
|
||||
CREATE VIRTUAL TABLE t4 USING fts5(
|
||||
x, tokenize="unicode61 categories 'L* N* Co M*'"
|
||||
);
|
||||
CREATE VIRTUAL TABLE t4t USING fts5vocab(t4, row);
|
||||
|
||||
INSERT INTO t2 VALUES ('สนามกีฬา');
|
||||
INSERT INTO t3 VALUES ('สนามกีฬา');
|
||||
INSERT INTO t4 VALUES ('สนามกีฬา');
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT * FROM t2t
|
||||
} {สนามก 1 1 ฬา 1 1}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT * FROM t3t
|
||||
} {สนามกีฬา 1 1}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
SELECT * FROM t4t
|
||||
} {สนามกีฬา 1 1}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -274,6 +274,7 @@ static void doDataTest1(
|
||||
int rc = LSM_OK;
|
||||
Datasource *pData;
|
||||
TestDb *pDb;
|
||||
int iToggle = 0;
|
||||
|
||||
/* Start the test case, open a database and allocate the datasource. */
|
||||
pDb = testOpen(zSystem, 1, &rc);
|
||||
@@ -287,8 +288,11 @@ static void doDataTest1(
|
||||
testWriteDatasourceRange(pDb, pData, i, p->nVerify, &rc);
|
||||
i += p->nVerify;
|
||||
|
||||
if( iToggle ) testBegin(pDb, 1, &rc);
|
||||
/* Check that the db content is correct. */
|
||||
testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
|
||||
if( iToggle ) testCommit(pDb, 0, &rc);
|
||||
iToggle = (iToggle+1)%2;
|
||||
|
||||
if( bRecover ){
|
||||
testReopenRecover(&pDb, &rc);
|
||||
|
||||
@@ -617,8 +617,12 @@ static int test_lsm_fetch(
|
||||
|
||||
if( pKey==0 ) return LSM_OK;
|
||||
|
||||
rc = lsm_csr_open(pDb->db, &csr);
|
||||
if( rc!=LSM_OK ) return rc;
|
||||
if( pDb->pCsr==0 ){
|
||||
rc = lsm_csr_open(pDb->db, &csr);
|
||||
if( rc!=LSM_OK ) return rc;
|
||||
}else{
|
||||
csr = pDb->pCsr;
|
||||
}
|
||||
|
||||
rc = lsm_csr_seek(csr, pKey, nKey, LSM_SEEK_EQ);
|
||||
if( rc==LSM_OK ){
|
||||
@@ -638,7 +642,9 @@ static int test_lsm_fetch(
|
||||
*pnVal = -1;
|
||||
}
|
||||
}
|
||||
lsm_csr_close(csr);
|
||||
if( pDb->pCsr==0 ){
|
||||
lsm_csr_close(csr);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -652,10 +658,28 @@ static int test_lsm_scan(
|
||||
){
|
||||
LsmDb *pDb = (LsmDb *)pTestDb;
|
||||
lsm_cursor *csr;
|
||||
lsm_cursor *csr2 = 0;
|
||||
int rc;
|
||||
|
||||
rc = lsm_csr_open(pDb->db, &csr);
|
||||
if( rc!=LSM_OK ) return rc;
|
||||
if( pDb->pCsr==0 ){
|
||||
rc = lsm_csr_open(pDb->db, &csr);
|
||||
if( rc!=LSM_OK ) return rc;
|
||||
}else{
|
||||
rc = LSM_OK;
|
||||
csr = pDb->pCsr;
|
||||
}
|
||||
|
||||
/* To enhance testing, if both pLast and pFirst are defined, seek the
|
||||
** cursor to the "end" boundary here. Then the next block seeks it to
|
||||
** the "start" ready for the scan. The point is to test that cursors
|
||||
** can be reused. */
|
||||
if( pLast && pFirst ){
|
||||
if( bReverse ){
|
||||
rc = lsm_csr_seek(csr, pFirst, nFirst, LSM_SEEK_LE);
|
||||
}else{
|
||||
rc = lsm_csr_seek(csr, pLast, nLast, LSM_SEEK_GE);
|
||||
}
|
||||
}
|
||||
|
||||
if( bReverse ){
|
||||
if( pLast ){
|
||||
@@ -696,7 +720,9 @@ static int test_lsm_scan(
|
||||
}
|
||||
}
|
||||
|
||||
lsm_csr_close(csr);
|
||||
if( pDb->pCsr==0 ){
|
||||
lsm_csr_close(csr);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -762,6 +788,7 @@ static void xWorkHook(lsm_db *db, void *pArg){
|
||||
#define TEST_MT_MIN_CKPT -4
|
||||
#define TEST_MT_MAX_CKPT -5
|
||||
|
||||
|
||||
int test_lsm_config_str(
|
||||
LsmDb *pLsm,
|
||||
lsm_db *db,
|
||||
|
||||
@@ -1922,6 +1922,7 @@ static int seekInLevel(
|
||||
** is not a composite level and there is no split-key). Search the
|
||||
** left-hand-side of the level in this case. */
|
||||
if( res<0 ){
|
||||
int i;
|
||||
int iPtr = 0;
|
||||
if( nRhs==0 ) iPtr = (int)*piPgno;
|
||||
|
||||
@@ -1931,12 +1932,16 @@ static int seekInLevel(
|
||||
if( rc==LSM_OK && nRhs>0 && eSeek==LSM_SEEK_GE && aPtr[0].pPg==0 ){
|
||||
res = 0;
|
||||
}
|
||||
for(i=1; i<=nRhs; i++){
|
||||
segmentPtrReset(&aPtr[i], LSM_SEGMENTPTR_FREE_THRESHOLD);
|
||||
}
|
||||
}
|
||||
|
||||
if( res>=0 ){
|
||||
int bHit = 0; /* True if at least one rhs is not EOF */
|
||||
int iPtr = (int)*piPgno;
|
||||
int i;
|
||||
segmentPtrReset(&aPtr[0], LSM_SEGMENTPTR_FREE_THRESHOLD);
|
||||
for(i=1; rc==LSM_OK && i<=nRhs && bStop==0; i++){
|
||||
SegmentPtr *pPtr = &aPtr[i];
|
||||
iOut = 0;
|
||||
@@ -2868,7 +2873,7 @@ static int multiCursorEnd(MultiCursor *pCsr, int bLast){
|
||||
int rc = LSM_OK;
|
||||
int i;
|
||||
|
||||
pCsr->flags &= ~(CURSOR_NEXT_OK | CURSOR_PREV_OK);
|
||||
pCsr->flags &= ~(CURSOR_NEXT_OK | CURSOR_PREV_OK | CURSOR_SEEK_EQ);
|
||||
pCsr->flags |= (bLast ? CURSOR_PREV_OK : CURSOR_NEXT_OK);
|
||||
pCsr->iFree = 0;
|
||||
|
||||
|
||||
+72
-8
@@ -1802,7 +1802,7 @@ static void jsonArrayStep(
|
||||
jsonAppendValue(pStr, argv[0]);
|
||||
}
|
||||
}
|
||||
static void jsonArrayFinal(sqlite3_context *ctx){
|
||||
static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
|
||||
JsonString *pStr;
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
if( pStr ){
|
||||
@@ -1811,16 +1811,66 @@ static void jsonArrayFinal(sqlite3_context *ctx){
|
||||
if( pStr->bErr ){
|
||||
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
|
||||
assert( pStr->bStatic );
|
||||
}else{
|
||||
}else if( isFinal ){
|
||||
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
|
||||
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
|
||||
pStr->bStatic = 1;
|
||||
}else{
|
||||
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT);
|
||||
pStr->nUsed--;
|
||||
}
|
||||
}else{
|
||||
sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
|
||||
}
|
||||
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||
}
|
||||
static void jsonArrayValue(sqlite3_context *ctx){
|
||||
jsonArrayCompute(ctx, 0);
|
||||
}
|
||||
static void jsonArrayFinal(sqlite3_context *ctx){
|
||||
jsonArrayCompute(ctx, 1);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/*
|
||||
** This method works for both json_group_array() and json_group_object().
|
||||
** It works by removing the first element of the group by searching forward
|
||||
** to the first comma (",") that is not within a string and deleting all
|
||||
** text through that comma.
|
||||
*/
|
||||
static void jsonGroupInverse(
|
||||
sqlite3_context *ctx,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int i;
|
||||
int inStr = 0;
|
||||
char *z;
|
||||
JsonString *pStr;
|
||||
UNUSED_PARAM(argc);
|
||||
UNUSED_PARAM(argv);
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
#ifdef NEVER
|
||||
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
|
||||
** always have been called to initalize it */
|
||||
if( NEVER(!pStr) ) return;
|
||||
#endif
|
||||
z = pStr->zBuf;
|
||||
for(i=1; z[i]!=',' || inStr; i++){
|
||||
assert( i<pStr->nUsed );
|
||||
if( z[i]=='"' ){
|
||||
inStr = !inStr;
|
||||
}else if( z[i]=='\\' ){
|
||||
i++;
|
||||
}
|
||||
}
|
||||
pStr->nUsed -= i;
|
||||
memmove(&z[1], &z[i+1], pStr->nUsed-1);
|
||||
}
|
||||
#else
|
||||
# define jsonGroupInverse 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** json_group_obj(NAME,VALUE)
|
||||
@@ -1852,7 +1902,7 @@ static void jsonObjectStep(
|
||||
jsonAppendValue(pStr, argv[1]);
|
||||
}
|
||||
}
|
||||
static void jsonObjectFinal(sqlite3_context *ctx){
|
||||
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
|
||||
JsonString *pStr;
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
if( pStr ){
|
||||
@@ -1860,16 +1910,26 @@ static void jsonObjectFinal(sqlite3_context *ctx){
|
||||
if( pStr->bErr ){
|
||||
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
|
||||
assert( pStr->bStatic );
|
||||
}else{
|
||||
}else if( isFinal ){
|
||||
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
|
||||
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
|
||||
pStr->bStatic = 1;
|
||||
}else{
|
||||
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT);
|
||||
pStr->nUsed--;
|
||||
}
|
||||
}else{
|
||||
sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
|
||||
}
|
||||
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||
}
|
||||
static void jsonObjectValue(sqlite3_context *ctx){
|
||||
jsonObjectCompute(ctx, 0);
|
||||
}
|
||||
static void jsonObjectFinal(sqlite3_context *ctx){
|
||||
jsonObjectCompute(ctx, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
@@ -2377,9 +2437,12 @@ int sqlite3Json1Init(sqlite3 *db){
|
||||
int nArg;
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
|
||||
void (*xFinal)(sqlite3_context*);
|
||||
void (*xValue)(sqlite3_context*);
|
||||
} aAgg[] = {
|
||||
{ "json_group_array", 1, jsonArrayStep, jsonArrayFinal },
|
||||
{ "json_group_object", 2, jsonObjectStep, jsonObjectFinal },
|
||||
{ "json_group_array", 1,
|
||||
jsonArrayStep, jsonArrayFinal, jsonArrayValue },
|
||||
{ "json_group_object", 2,
|
||||
jsonObjectStep, jsonObjectFinal, jsonObjectValue },
|
||||
};
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
static const struct {
|
||||
@@ -2397,9 +2460,10 @@ int sqlite3Json1Init(sqlite3 *db){
|
||||
aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_function(db, aAgg[i].zName, aAgg[i].nArg,
|
||||
rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
|
||||
0, aAgg[i].xStep, aAgg[i].xFinal);
|
||||
aAgg[i].xStep, aAgg[i].xFinal,
|
||||
aAgg[i].xValue, jsonGroupInverse, 0);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Fix\sa\sminor\sproblem\sin\sthe\scode\sfor\sdetermining\swhether\sor\snot\san\sSQL\nstatement\sis\sSQLITE_TOOBIG.
|
||||
D 2018-06-30T20:00:35.632
|
||||
C Experimental\sfix\sfor\sresetting\sdatabases\sthat\shave\sbeen\sdeemed\sread-only\sdue\nto\sa\scorrupt\s"read-version"\sheader\sfield.
|
||||
D 2018-07-19T11:44:02.889
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
||||
@@ -36,6 +36,7 @@ F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure a46cba271ae08d635a1f331384c04563bdd37adb3d63cbdcffb1d91babfb64f5 x
|
||||
F configure.ac 18c93e8bbeec8254832c4ea90eb06e7187fd150ef098baed02467eeb374afb17
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/lemon.html ac63db056bce24b7368e29319cd1a7eb5f1798cc85922d96a80b6c3a4ff9f51b
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
@@ -104,15 +105,15 @@ F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87
|
||||
F ext/fts3/tool/fts3view.c 202801a2056995b763864d60c2dee744d46f1677
|
||||
F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
|
||||
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
|
||||
F ext/fts3/unicode/mkunicode.tcl ab0543a3b2399092ea2dd75df1bef333405b0d7f6b8c4951a0fbb60e780cb69f
|
||||
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
|
||||
F ext/fts3/unicode/mkunicode.tcl 0069320b64db6ee269c5e95f1f150d070fbf0a863fc7b3549d7e52bd068fb118
|
||||
F ext/fts3/unicode/parseunicode.tcl 024ae0bdd96309d7b8fc479148191e9b3001dc74017a3f65f9a27de3b3ff968b
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7
|
||||
F ext/fts5/fts5Int.h eda28e3a0a5d87c412e8355fe35da875b04cb389908c8eb0d867ad662adbc491
|
||||
F ext/fts5/fts5Int.h 39f12034b598df4e0f59bbe6cf03af03a905a534b04f182d155641a04e1eb797
|
||||
F ext/fts5/fts5_aux.c ca666a3bbe07c5a3bbe9fffaea19c935a1efaf337333e28bad7bdd1971ffd093
|
||||
F ext/fts5/fts5_buffer.c 1dd1ec0446b3acfc2d7d407eb894762a461613e2695273f48e449bfd13e973ff
|
||||
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c c23a2e4c14c401a147c4a730460e5b37057627bf4be95515ee281cd87f4d277c
|
||||
F ext/fts5/fts5_expr.c 5aef080ba3c8947e22f38ce1ff9fe548e4a740e72b77241f35ed941ae128d2c7
|
||||
F ext/fts5/fts5_hash.c 32be400cf761868c9db33efe81a06eb19a17c5402ad477ee9efb51301546dd55
|
||||
F ext/fts5/fts5_index.c 22b71d0e9e4b3ddd123a39ae27174e0012da2806f91b64087a68584f13f189de
|
||||
F ext/fts5/fts5_main.c da46761a7e9b582083fcb9f5a3ee50086205fb91f4e68d984a9946e64218e297
|
||||
@@ -120,8 +121,8 @@ F ext/fts5/fts5_storage.c 4bec8a1b3905978b22a67bca5f4a3cfdb94af234cf51efb36f4f2d
|
||||
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
|
||||
F ext/fts5/fts5_test_mi.c 65864ba1e5c34a61d409c4c587e0bbe0466eb4f8f478d85dc42a92caad1338e6
|
||||
F ext/fts5/fts5_test_tok.c ffd657dd67e7fcdb31bf63fb60b6d867299a581d0f46e97086abacd66c2a9b26
|
||||
F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
|
||||
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
|
||||
F ext/fts5/fts5_tokenize.c ebd13d034f3dc7c841e1c32c364a4fca5cc2e05a0b91682a93fa1e6defcd4292
|
||||
F ext/fts5/fts5_unicode2.c f074475acb251e9deb2fd4c72b2fe175f596ff25cf330fb044f869cf742da644
|
||||
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
|
||||
F ext/fts5/fts5_vocab.c 1cd79854cb21543e66507b25b0578bc1b20aa6a1349b7feceb8e8fed0e7a77a6
|
||||
F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05
|
||||
@@ -145,6 +146,7 @@ F ext/fts5/test/fts5aux.test 8e7f9c96f8570f48402f2fd7b74e1ccfadd319fa56ef6773218
|
||||
F ext/fts5/test/fts5auxdata.test eacc97ff04892f1a5f3d4df5a73f8bcbc3955ea1d12c9f24137eb1fc079e7611
|
||||
F ext/fts5/test/fts5bigpl.test 6466c89b38439f0aba26ac09e232a6b963f29b1cbe1304f6a664fe1e7a8f5fd3
|
||||
F ext/fts5/test/fts5bigtok.test 541119e616c637caea925a8c028c37c2c29e94383e00aa2f9198d530724b6e36
|
||||
F ext/fts5/test/fts5cat.test daba0b80659460b0cb60bd1f40b402478a761fe7ea414c3c94c2be25568cc33a
|
||||
F ext/fts5/test/fts5colset.test a30473451321bbf0b6218af62e96b4ae5fa99931cfdb210b5ecc804623b30f75
|
||||
F ext/fts5/test/fts5columnsize.test 45459ce4dd9fd853b6044cdc9674921bff89e3d840f348ca8c1630f9edbf5482
|
||||
F ext/fts5/test/fts5config.test 60094712debc59286c59aef0e6cf511c37d866802776a825ce437d26afe0817f
|
||||
@@ -225,7 +227,7 @@ F ext/lsm1/Makefile 98b0a24b45e248283d6bea4b6cb3e58d7b394edd8e96a0ac28c5fa510481
|
||||
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
|
||||
F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86
|
||||
F ext/lsm1/lsm-test/lsmtest.h cf58528ffe0cfe535e91b44584e2ec5fb1caacdabecef0d8dcf83bf83168bf28
|
||||
F ext/lsm1/lsm-test/lsmtest1.c 33158978327f800e82b6a47c09b86ace809f56a9ff10b0162273ec1186cc3153
|
||||
F ext/lsm1/lsm-test/lsmtest1.c ae6ba48a0851b39be69a7d0eb220bfb9521a526e926223d5014bd385df10abb3
|
||||
F ext/lsm1/lsm-test/lsmtest2.c 188b09aec776516aeedcfd13b9c6faf85ba16b3671a0897a2c740ee00a5dc4f8
|
||||
F ext/lsm1/lsm-test/lsmtest3.c 9ab87528a36dbf4a61d7c8ad954f5ee368c0878c127b84b942b2e2abe522de26
|
||||
F ext/lsm1/lsm-test/lsmtest4.c d258d6a245db5d8eaede096e2368d23f859c5e92c80ab9122463f708514fe10c
|
||||
@@ -243,7 +245,7 @@ F ext/lsm1/lsm-test/lsmtest_mem.c 4e63c764345ab1df59d4f13a77980c6f3643798210b10d
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb.c 618a8619183fda4f5540fcde15f9068293c5e3180e1a246e34409b0c148758b3
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb.h 8733eee249b12956a9df8322994b43d19bd8c02ad2e8b0bb5164db4d6ccc1735
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb2.cc 99ea7f2dd9c7536c8fb9bdd329e4cfeb76899f3ddf6f48bdd3926e016922b715
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb3.c b4e46b1d2fec553fe4efb44e341b43abd20556fde610db0cfffdc2300b72defe
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb3.c 7a7ccae189f5bb25bcd1ec3bbd740529706eded7f6729a5a0a9eeaeb57785320
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb4.c 47e8bb5eba266472d690fb8264f1855ebdba0ae5a0e541e35fcda61ebf1d277f
|
||||
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
|
||||
F ext/lsm1/lsm-test/lsmtest_win32.c 0e0a224674c4d3170631c41b026b56c7e1672b151f5261e1b4cc19068641da2d
|
||||
@@ -256,7 +258,7 @@ F ext/lsm1/lsm_main.c b5703f8042e71d3a2d65e671f6832e077e79e89e9975818f67f9699226
|
||||
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
|
||||
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
|
||||
F ext/lsm1/lsm_shared.c 76adfc1ed9ffebaf92746dde4b370ccc48143ca8b05b563816eadd2aadf1c525
|
||||
F ext/lsm1/lsm_sorted.c df7b393d9e4b85e6ad07181c6434d58a69a9145ee925d89c3ee1d2a210adaf9a
|
||||
F ext/lsm1/lsm_sorted.c 6f7d8cf7a7d3d3f1ab5d9ba6347e8f39f3d73c00ec48afcd0c4bcbefd806f9b8
|
||||
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
|
||||
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
|
||||
F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
|
||||
@@ -281,7 +283,7 @@ F ext/misc/eval.c 6ea9b22a5fa0dd973b67ca4e53555be177bc0b7b263aadf1024429457c82c0
|
||||
F ext/misc/fileio.c 48c7751c78fc4cdd29d8c862fd2f3f98bbfefa2a3cf1ca1496df4bf02eb8cded
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c 02f5f0d9c131df79f4ee168d2b426f0f0d273b7771fc0bb5293c4e7692d9a2ee
|
||||
F ext/misc/json1.c 933ace99a1880e014f35fbf6444fb24e3cf9920c3a6a75e9aa70f0caf683e3fe
|
||||
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
|
||||
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
@@ -430,16 +432,16 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 6beb476095a4cfeb95ebedb2e5e17894d1687b24fddd5b8761a4de120e0392c6
|
||||
F src/analyze.c 41f0b8d638fc2a7309477904ac38e535f2aabea3256da3251e529730e099df77
|
||||
F src/analyze.c 91b5e7c0f4a08dbb1f7a24b24e7ab49be8b0a2fd1906a35add62a855d1c0ceb9
|
||||
F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a
|
||||
F src/auth.c a38f3c63c974787ecf75e3213f8cac6568b9a7af7591fb0372ec0517dd16dca8
|
||||
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c bb23e5470ec0c9b9ae8e17c86cb686bc4112642d8f457bd42b3b3727d5ef78be
|
||||
F src/btree.c 4b91880ab0f6595c52f13b17f3ef269062073341c254311b3c38925db5b89b9a
|
||||
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
||||
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
||||
F src/build.c 3b3bfa88800739e1f11313dcecfba5ef8e4757b6c929cdf7de9fcfc01002b81f
|
||||
F src/build.c d8f6ac1e9e484eb3f3921a8336d3dc6c87273d9db8729702162ef045997a1463
|
||||
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 849d4cebe008cfc6e4799b034a172b4eaf8856b100739632a852732ba66eee48
|
||||
@@ -447,19 +449,19 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
|
||||
F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
|
||||
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
|
||||
F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f
|
||||
F src/expr.c 7e257eeffe9553c10a6ac0a1f0177bf740c4da834e7d6e2cbb7d3ebaa3d7f3e1
|
||||
F src/expr.c bb148f4c45b6e53b5b58a912974253547e8862685cb001fbdfaef0ab24812e6f
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee
|
||||
F src/func.c d2c66d8ec930d53e9ecd0d6cbe210c1a70f0427bfc49624516fb97aae2f5cfe8
|
||||
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
|
||||
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
|
||||
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c bcacf6a0d277f8fa0e4f9ffecda544a2330ca4478f904cd89564c2dd86d0b16b
|
||||
F src/insert.c 8613af9c5ba1503bc68f4e9432c6c024e0fdafdc791575c50f380f73ec91189f
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
|
||||
F src/main.c 0087639013e4b62ce16a92e4b0cb6127876224fadeea72016396626078dc8736
|
||||
F src/main.c 9c8ef68bd3779d493d632946b3a65156b2e636ad2c7a1b7cd1450e87dc0c6a7d
|
||||
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -482,9 +484,9 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c c230a7a24766320d8414afd087edcd43e499fb45e86361f6f4f464f343d965a9
|
||||
F src/os_win.c ac29c25cde4cfb4adacc59cdec4aa45698ca0e29164ea127859585ccd9faa354
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 1bb6a57fa0465296a4d6109a1a64610a0e7adde1f3acf3ef539a9d972908ce8f
|
||||
F src/pager.c 29c48653efacf4f3a0b0e193515b789a1e9eee7d232816704cef95216906baa3
|
||||
F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
|
||||
F src/parse.y 9b57f1d0d3d7578ab2917e07ff5d8def4b0aac571113dd7b7cb8108e7194d025
|
||||
F src/parse.y 3bd43415ea974b9921b0ff2c0bd3e9100f6e501ede0b6d3b90cca2ab6af25485
|
||||
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
|
||||
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||
@@ -493,19 +495,19 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
|
||||
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c d8359c59c683fc33324c3a0abe0d393304861f05dd2e0d47e5974a501bcf4682
|
||||
F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 82aa95aa1cfeadef5ecae1126afff1efca64c49050bbf7116425a8a1d4fc5e6c
|
||||
F src/shell.c.in 8578421c5fb2a972461b2a996f7173646e55e0dbd2a2eee30c8f5dc7d3dbadfd
|
||||
F src/sqlite.h.in 243e0b1d302c237372c06002fe84f731fd22587eccd142d15de834a5296514ff
|
||||
F src/select.c 2e9661d4424f43ccf595c4a7b4acdf32db523c0f6b31cbd62e6e5a2f43118981
|
||||
F src/shell.c.in 239aee5570703fcbf9e6bec176a3ba7704bf327515f9f0dbd2498f00746e82b6
|
||||
F src/sqlite.h.in 6203acde410e38d96ffb24e9b6349f87eb80914ba5676466ac5d8478b6b8f144
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
||||
F src/sqliteInt.h c14c850bf0c4dd3860cc5092f140ae9faf93b77737b3febf38454088e1ab3988
|
||||
F src/sqliteInt.h c2ceebe60d1d2e11674b90c8b55fdffd91386ce8d7ae38613fbcc61659b8fcac
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 916a92de77ec5cbe27818ca194d8cf0c58aa7ad5b87527098f6aa5a6068800ce
|
||||
F src/test1.c b5e21f2ec8386cabb67346c9399603ddb33f76094a0941f280b403aa93631717
|
||||
F src/test1.c 335740ddc632c0b54765b6fd373da7f76a397adde3ded3592390dd1e5fb0dd55
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
@@ -551,28 +553,28 @@ F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
|
||||
F src/test_tclsh.c 06317648b0d85a85fd823f7973b55535c59a3156c1ef59394fe511f932cfa78d
|
||||
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
|
||||
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
|
||||
F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
|
||||
F src/test_vfs.c 112f1f9271c33c211812e0e681830a84262dac065da58579ff49f9cefec97d4f
|
||||
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_windirent.c a895e2c068a06644eef91a7f0a32182445a893b9a0f33d0cdb4283dca2486ac1
|
||||
F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a90484215
|
||||
F src/test_window.c add59ee68568868129516999f30a68e8ab2afd276e272aba4f633c9fc52c1bb1
|
||||
F src/test_window.c 0d19b33e7a262d3b55e85bc0fb84a70f503686cbd769939176162fe866ce7f9e
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c e0a90f3d594e3db842581543abf157c8e63617655c91ad35d77e339a1bc36ce0
|
||||
F src/treeview.c 2c5c4bc0a443401db5fd621542150452ddf5055d38edd4eef868bc2b6bfb0260
|
||||
F src/tokenize.c 01e96d1b639c3eb0b9ef90616e766d453935c554f1f7aa86b6db937b79554b97
|
||||
F src/treeview.c 462346b82a892316a62291791c77e3dd5f1927745fe4a44b846ab4fd16eb28c3
|
||||
F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995
|
||||
F src/update.c 46dc24c6158446aaab45caee09b6d99327cb479268b83ffeb5b701823da3b67b
|
||||
F src/update.c 7b7c768dc415a8d2eb9fd2cea8b524cb29cf354f319700e22f94f262d3f507cb
|
||||
F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
|
||||
F src/vdbe.c 37b942ccdd224dd51bd80312b8d236f27c7c728e76c3f425c50e9d8ecff3b7b4
|
||||
F src/vdbe.h 847735b3e083285aa225d2bf1fe97107a0a2b8942c80d643cdb764990705820d
|
||||
F src/vdbe.c 9933ec035072c72fc26c5439f6c8a1eef902ce9132916d5a05e8733b0266eb67
|
||||
F src/vdbe.h d93abdc8bc9295e0a256e582c19f548c545dc498319d108bbc9dd29de31c48a2
|
||||
F src/vdbeInt.h 6b5cbd338dc9aaad343fb11b455e47463b0474d9f79710f50e647158941146e0
|
||||
F src/vdbeapi.c e35f813312b0f6e8e2835b357f121e0d1da6d3013bac3e367fe4efd518e7a2ec
|
||||
F src/vdbeapi.c af4a3de00d1851bcbc55b85dfbe52849aa2b1e17b4a5a1f3d9c257df7af361ff
|
||||
F src/vdbeaux.c c2d65c763b0811afe409e02e9d0d1f300c6e97892474fc94eec3da71955cd418
|
||||
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
|
||||
F src/vdbemem.c 87b48c0bd68041a61fb3f4e18a1a696f5339d65e572d288a266a602a01863f1a
|
||||
F src/vdbemem.c a699a1d7ccc3f94cdff69ddf35d5f7540dbf52ca44cf040eda3c87520e67858c
|
||||
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
|
||||
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
|
||||
F src/vtab.c 10ea07dec111de6fb0a4fc87a7ffa4c65fdc088a19dbfaf7d6f2b128f2e8eb7b
|
||||
@@ -580,11 +582,11 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c d44a0811afd2155b1157c38b33141d4ac028fda6232485bed664015bb05819ca
|
||||
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||
F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4
|
||||
F src/where.c 0bcbf9e191ca07f9ea2008aa80e70ded46bcdffd26560c83397da501f00aece6
|
||||
F src/where.c cd6710e24d3d5c29d6890df93865c22d896453907eb83988c505a3098e90179f
|
||||
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
|
||||
F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
|
||||
F src/whereexpr.c 19cf35cdd9bf6d5589d8a5c960d99259761136187a2319a6e14d11cf1abe14c2
|
||||
F src/window.c 4403ae36b9645f105ad8ae16d986929c6db5f3bc7d3d3db43f5fa51c6bbfcbe8
|
||||
F src/wherecode.c fe23a55294b4c94bf658d2a6eb7996170dd563bf33af4c3e5d71aff3483e4b08
|
||||
F src/whereexpr.c 571618c67a3eb5ce0f1158c2792c1aee9b4a4a264392fc4fb1b35467f80abf9a
|
||||
F src/window.c c61434ce7e35b7d76b3321dec39e10e79061c10eed1e3d7976c87dbdd77aefb5
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||
@@ -620,6 +622,7 @@ F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
|
||||
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
|
||||
F test/atof1.test ff0b0156fd705b67c506e1f2bfe9e26102bea9bd
|
||||
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
|
||||
F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da
|
||||
F test/attach.test f4b8918ba2f3e88e6883b8452340545f10a1388af808343c37fc5c577be8281c
|
||||
F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
@@ -746,6 +749,7 @@ F test/csv01.test 6e1445b3207d574cff22fc41a8e549dfcf2466ee90546ada97d22a90fa89eb
|
||||
F test/ctime.test 78749e6c9a5f0010d67985be80788f841e3cd2da18114e2ed6010399a7d807f3
|
||||
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
|
||||
F test/cursorhint2.test 0078ae1ded4afcf5eb80d06e3a72b6e1c3f1a646aab26eeb583b0a9ec6f0d56e
|
||||
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
@@ -1028,7 +1032,7 @@ F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd7
|
||||
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/json101.test b40a9f5395d8e669b0bc3eb550ad2ae9e5ada01fbce23c446c2a30a305a6d575
|
||||
F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
|
||||
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
|
||||
F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f67e3b
|
||||
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
|
||||
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
|
||||
F test/kvtest.c 94da54bb66aae7a54e47cf7e4ea4acecc0f217560f79ad3abfcc0361d6d557ba
|
||||
@@ -1151,7 +1155,7 @@ F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test 5c2167e03dc55ff697e11bb3abf10c66ba452e4afb2dbd85a2b144048355300e
|
||||
F test/pg_common.tcl 3bf36b30d7b09e5896a1fb0268ace22f2ebfa91d07a422d8ffbf57551d9ce0dc
|
||||
F test/pg_common.tcl 301ac19c1a52fd55166d26db929b3b89165c634d52b5f8ad76ea8cb06960db30
|
||||
F test/pragma.test 7c8cfc328a1717a95663cf8edb06c52ddfeaf97bb0aee69ae7457132e8d39e7d
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
@@ -1177,7 +1181,7 @@ F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.tcl 769892f81050b3f59c66f274d478d855159b474ea27019dec82f1215c0b91ef7 x
|
||||
F test/resetdb.test 2107b34a8c437183f48eb833905df43818160a55f4ac69bbaf54f356fb2b27bd
|
||||
F test/resetdb.test b7df373608a56b1fc7a9ed942e8d91fa3ad25b87b63bdb36c88811ad1d0a9c90
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
|
||||
F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6
|
||||
@@ -1211,6 +1215,7 @@ F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
|
||||
F test/schema4.test 3b26c9fa916abb6dadf894137adcf41b7796f7b9
|
||||
F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e
|
||||
F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce1f9b
|
||||
F test/schemafault.test 1936bceca55ac82c5efbcc9fc91a1933e45c8d1e1d106b9a7e56c972a5a2a51e
|
||||
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
|
||||
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test 2e760bab8f3658b3b97debcf52860d0d2e20aa6cbe8b40e678ddb99871a15491
|
||||
@@ -1225,7 +1230,7 @@ F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test b8a590f6493cad5b0bb4dfe1709bf7dcda0b6c40bb4caf32d1e36a89eebc8fc5
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test e25243f8ca503e06f252eb0218976d07cfeceac3
|
||||
F test/selectD.test cfa9f27dbdbeaf2d021d26c79b6c790d8f26e5506d50117c7696d3e136d6d9e7
|
||||
F test/selectD.test fc20452847a01775710090383cfb4423275d2f745fed61f34fbf37573ac0d214
|
||||
F test/selectE.test a8730ca330fcf40ace158f134f4fe0eb00c7edbf
|
||||
F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3
|
||||
F test/selectG.test 089f7d3d7e6db91566f00b036cb353107a2cca6220eb1cb264085a836dae8840
|
||||
@@ -1257,7 +1262,7 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test 8ab5d2c7c5cd3fe7f172d366e6e74e887cb33cb4
|
||||
F test/skipscan1.test 3ea1cccca8f1b0e1cf3e73a63b43dd796f34d4aaee815e641f0d2ebb3fa448d4
|
||||
F test/skipscan2.test ef143c6e4a5ba4f19c1d1e3f517811f7942bdf2142736cc568feb34e0b5fb763
|
||||
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
|
||||
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
|
||||
@@ -1323,7 +1328,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl aa7558f20fcf7dd9151325f849d9103bd450235093bc078073bf0f080991e3c4
|
||||
F test/tester.tcl d5138d226cc2aaacb6934cdd79acaa5edd17cad862482895b833bbf62c49aca0
|
||||
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1518,7 +1523,7 @@ F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
|
||||
F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981
|
||||
F test/update.test 1148de8d913e9817717990603aadeca07aab9ddbb10a30f167cbfd8d3a3ccb60
|
||||
F test/update2.test 5e67667e1c54017d964e626db765cf8bedcf87483c184f4c575bdb8c1dd2313e
|
||||
F test/upsert1.test d587db593f131e112a98a05685c418e0eacc28df5905403e4ca04cd74c39a3fc
|
||||
F test/upsert1.test ecd8f69e20183f298464992762fee24750508b3cbefc5badba8a259a3fc887ec
|
||||
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
|
||||
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
|
||||
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
|
||||
@@ -1583,6 +1588,7 @@ F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
|
||||
F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03
|
||||
F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6
|
||||
F test/walprotocol.test a112aba0b79e3adeaa485fed09484b32c654e97df58e454aa8489ac2cd57bf84
|
||||
F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131
|
||||
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
|
||||
F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768
|
||||
F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
|
||||
@@ -1621,13 +1627,13 @@ F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
||||
F test/window1.test 7cb260079cd88d6d6177b0f592686f2bbbc2d10f4f415c8a37cd153eb83c87ca
|
||||
F test/window2.tcl 9bfa842d8a62b0d36dc8c1b5972206393c43847433c6d75940b87fec93ce3143
|
||||
F test/window2.test 8e6d2a1b9f54dfebee1cde961c8590cd87b4db45c50f44947a211e1b63c2a05e
|
||||
F test/window3.tcl 9b82055c8977bdcab164fb4f71dabf86c511c9010c44f958352b610d313182c3
|
||||
F test/window3.test 47884c240d0d5234ad9c6da65452cfec1bfa69ec6f9c4158cd9750c3d88d3a25
|
||||
F test/window4.tcl 7cec7e578aa9f78b7265bff8d552cda17a1d8d89f0449d0e74970a527b8846f5
|
||||
F test/window4.test dcd8767869988e0d23d56bc3f8b46ec116de23127b81b5f66fd48d5529072ed1
|
||||
F test/window5.test a4835b96d30eb3b81a1dbc683e333e57a614645eb6f2ae476a7ed2addf0b0f1f
|
||||
F test/window6.test fb4e464993630c3d6023e906aa6705667062600a8341085b7fd8c201f4c2f411
|
||||
F test/windowfault.test 97d5fc404308edb579a5a183e294ed874c844ecf01f0a28ba46df3141ebaee1f
|
||||
F test/window3.tcl 577a3b1ff913208e5248c04dab9df17fd760ce159a752789e26d0cb4a5f91823
|
||||
F test/window3.test e274b7f8952ca4ed25996e0e45c047192b066e0aaff2a822d4293c8c4f1d8d98
|
||||
F test/window4.tcl 871364059b7d320d556ec6ef804d604a4e8cc1547a3102c5d56067371bb200af
|
||||
F test/window4.test 323b118eb592932036388643ca6dcaead87f699bbea2984bbca49ba4ad6c2509
|
||||
F test/window5.test 8187f46597c90b73e8f96659e893353cbda337479cc582f7a488eab351ba08d3
|
||||
F test/window6.test 7574778c79cae89f1781df237bf9ff5063886deca91a36efc53934315f0e7612
|
||||
F test/windowfault.test 23abad97b72c6f609002255ddd41ef5c8922408f918f9b98ad6005ab316e482f
|
||||
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
|
||||
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
|
||||
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
|
||||
@@ -1664,7 +1670,7 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
|
||||
F tool/lemon.c 33892e2a243865f73e6c6e7cecce3c6eb4bb95db4a3d9d86d146c8064feb92fd
|
||||
F tool/lempar.c 6f64bc81160495f93d0f2ae27c787cb7cf4d5c7f5d2abf3823bc878ded6d6293
|
||||
F tool/lempar.c 428a050780425be2d699e939605fcbc54a161c20884f11b476b2eea961394bbe
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
|
||||
@@ -1744,7 +1750,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P aad718fb1afacf1c921966796ab1e149207c31b16409c5672f0371f4fb9d6565
|
||||
R 6cfae24b0260985fdb1b9447231b1548
|
||||
P a5087c5c87ad65f92e3bc96bbc84afb43faf10ab6b9ed3ba16304b5c60ad069f
|
||||
R cc038e87dc659a807799369c4759d0af
|
||||
T *branch * exp-dbreset-fix
|
||||
T *sym-exp-dbreset-fix *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 6c2f201187f4c45767b497733a8a927a
|
||||
Z c2723926c6d15ad4b82159593e2d431c
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
763e6c9e2bbc0a6ef8d8361069bf7160790c9064f24f0e336b7ed85668735da9
|
||||
e2394002d02754bb45d56e805df9bc5a2ef0d14e5d94262c1f8ab7643bc27c8f
|
||||
+1
-4
@@ -1274,10 +1274,7 @@ static void analyzeOneTable(
|
||||
callStatGet(v, regStat4, STAT_GET_NLT, regLt);
|
||||
callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
|
||||
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
|
||||
/* We know that the regSampleRowid row exists because it was read by
|
||||
** the previous loop. Thus the not-found jump of seekOp will never
|
||||
** be taken */
|
||||
VdbeCoverageNeverTaken(v);
|
||||
VdbeCoverage(v);
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
|
||||
#else
|
||||
|
||||
+15
-2
@@ -3316,6 +3316,12 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
||||
}
|
||||
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
|
||||
|
||||
if( (p->db->flags & SQLITE_ResetDatabase)
|
||||
&& sqlite3PagerIsreadonly(pBt->pPager)==0
|
||||
){
|
||||
pBt->btsFlags &= ~BTS_READ_ONLY;
|
||||
}
|
||||
|
||||
/* Write transactions are not possible on a read-only database */
|
||||
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
|
||||
rc = SQLITE_READONLY;
|
||||
@@ -3375,6 +3381,11 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
||||
rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = newDatabase(pBt);
|
||||
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
|
||||
/* if there was no transaction opened when this function was
|
||||
** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
|
||||
** code to SQLITE_BUSY. */
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3426,7 +3437,6 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trans_begun:
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pSchemaVersion ){
|
||||
@@ -5192,7 +5202,10 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
void sqlite3BtreeSkipNext(BtCursor *pCur){
|
||||
if( pCur->eState==CURSOR_VALID ){
|
||||
/* We believe that the cursor must always be in the valid state when
|
||||
** this routine is called, but the proof is difficult, so we add an
|
||||
** ALWaYS() test just in case we are wrong. */
|
||||
if( ALWAYS(pCur->eState==CURSOR_VALID) ){
|
||||
pCur->eState = CURSOR_SKIPNEXT;
|
||||
pCur->skipNext = 1;
|
||||
}
|
||||
|
||||
+6
-1
@@ -1788,7 +1788,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
assert( pParse->pNewTable==pTab );
|
||||
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
|
||||
SQLITE_IDXTYPE_PRIMARYKEY);
|
||||
if( db->mallocFailed ) return;
|
||||
if( db->mallocFailed || pParse->nErr ) return;
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
pTab->iPKey = -1;
|
||||
}else{
|
||||
@@ -2319,6 +2319,11 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
nErr++;
|
||||
}
|
||||
pTable->pSchema->schemaFlags |= DB_UnresetViews;
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DeleteColumnNames(db, pTable);
|
||||
pTable->aCol = 0;
|
||||
pTable->nCol = 0;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIEW */
|
||||
return nErr;
|
||||
}
|
||||
|
||||
+16
-1
@@ -1487,7 +1487,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
|
||||
pNew->pWin = 0;
|
||||
pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
|
||||
#endif
|
||||
sqlite3SelectSetName(pNew, p->zSelName);
|
||||
pNew->selId = p->selId;
|
||||
*pp = pNew;
|
||||
pp = &pNew->pPrior;
|
||||
pNext = pNew;
|
||||
@@ -4951,6 +4951,21 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
|
||||
if( pA->iTable!=pB->iTable
|
||||
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/* Justification for the assert():
|
||||
** window functions have p->op==TK_FUNCTION but aggregate functions
|
||||
** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate
|
||||
** function and a window function should have failed before reaching
|
||||
** this point. And, it is not possible to have a window function and
|
||||
** a scalar function with the same name and number of arguments. So
|
||||
** if we reach this point, either A and B both window functions or
|
||||
** neither are a window functions. */
|
||||
assert( (pA->pWin==0)==(pB->pWin==0) );
|
||||
|
||||
if( pA->pWin!=0 ){
|
||||
if( sqlite3WindowCompare(pParse,pA->pWin,pB->pWin)!=0 ) return 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+41
-16
@@ -1505,7 +1505,7 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
i64 v = sqlite3_value_int64(argv[0]);
|
||||
p->rSum += v;
|
||||
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
|
||||
p->overflow = 1;
|
||||
p->approx = p->overflow = 1;
|
||||
}
|
||||
}else{
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
@@ -1521,17 +1521,18 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
UNUSED_PARAMETER(argc);
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
type = sqlite3_value_numeric_type(argv[0]);
|
||||
if( p && type!=SQLITE_NULL ){
|
||||
/* p is always non-NULL because sumStep() will have been called first
|
||||
** to initialize it */
|
||||
if( ALWAYS(p) && type!=SQLITE_NULL ){
|
||||
assert( p->cnt>0 );
|
||||
p->cnt--;
|
||||
if( type==SQLITE_INTEGER ){
|
||||
assert( type==SQLITE_INTEGER || p->approx );
|
||||
if( type==SQLITE_INTEGER && p->approx==0 ){
|
||||
i64 v = sqlite3_value_int64(argv[0]);
|
||||
p->rSum -= v;
|
||||
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, -1*v) ){
|
||||
p->overflow = 1;
|
||||
}
|
||||
p->iSum -= v;
|
||||
}else{
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
p->approx = 1;
|
||||
p->rSum -= sqlite3_value_double(argv[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1572,6 +1573,9 @@ static void totalFinalize(sqlite3_context *context){
|
||||
typedef struct CountCtx CountCtx;
|
||||
struct CountCtx {
|
||||
i64 n;
|
||||
#ifdef SQLITE_DEBUG
|
||||
int bInverse; /* True if xInverse() ever called */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1589,7 +1593,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
** sure it still operates correctly, verify that its count agrees with our
|
||||
** internal count when using count(*) and when the total count can be
|
||||
** expressed as a 32-bit integer. */
|
||||
assert( argc==1 || p==0 || p->n>0x7fffffff
|
||||
assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse
|
||||
|| p->n==sqlite3_aggregate_count(context) );
|
||||
#endif
|
||||
}
|
||||
@@ -1598,6 +1602,21 @@ static void countFinalize(sqlite3_context *context){
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
sqlite3_result_int64(context, p ? p->n : 0);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){
|
||||
CountCtx *p;
|
||||
p = sqlite3_aggregate_context(ctx, sizeof(*p));
|
||||
/* p is always non-NULL since countStep() will have been called first */
|
||||
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){
|
||||
p->n--;
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->bInverse = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define countInverse 0
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
/*
|
||||
** Routines to implement min() and max() aggregate functions.
|
||||
@@ -1652,13 +1671,13 @@ static void minMaxValueFinalize(sqlite3_context *context, int bValue){
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
static void minMaxValue(sqlite3_context *context){
|
||||
return minMaxValueFinalize(context, 1);
|
||||
minMaxValueFinalize(context, 1);
|
||||
}
|
||||
#else
|
||||
# define minMaxValue 0
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
static void minMaxFinalize(sqlite3_context *context){
|
||||
return minMaxValueFinalize(context, 0);
|
||||
minMaxValueFinalize(context, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1703,16 +1722,20 @@ static void groupConcatInverse(
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int n;
|
||||
assert( argc==1 || argc==2 );
|
||||
StrAccum *pAccum;
|
||||
assert( argc==1 || argc==2 );
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
|
||||
if( pAccum ){
|
||||
/* pAccum is always non-NULL since groupConcatStep() will have always
|
||||
** run frist to initialize it */
|
||||
if( ALWAYS(pAccum) ){
|
||||
n = sqlite3_value_bytes(argv[0]);
|
||||
if( argc==2 ){
|
||||
n += sqlite3_value_bytes(argv[1]);
|
||||
}else{
|
||||
n++;
|
||||
}
|
||||
if( n>=pAccum->nChar ){
|
||||
if( n>=(int)pAccum->nChar ){
|
||||
pAccum->nChar = 0;
|
||||
}else{
|
||||
pAccum->nChar -= n;
|
||||
@@ -1943,8 +1966,10 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
|
||||
WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
|
||||
WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
|
||||
AGGREGATE2(count, 0,0,0, countStep, countFinalize, SQLITE_FUNC_COUNT ),
|
||||
WAGGREGATE(count, 1,0,0, countStep, countFinalize, 0, 0, 0 ),
|
||||
WAGGREGATE(count, 0,0,0, countStep,
|
||||
countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ),
|
||||
WAGGREGATE(count, 1,0,0, countStep,
|
||||
countFinalize, countFinalize, countInverse, 0 ),
|
||||
WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep,
|
||||
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
|
||||
WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
|
||||
|
||||
+4
-4
@@ -1632,6 +1632,10 @@ void sqlite3GenerateConstraintChecks(
|
||||
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
|
||||
|
||||
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
||||
if( bAffinityDone==0 ){
|
||||
sqlite3TableAffinity(v, pTab, regNewData+1);
|
||||
bAffinityDone = 1;
|
||||
}
|
||||
if( pUpIdx==pIdx ){
|
||||
addrUniqueOk = sAddr.upsertBtm;
|
||||
upsertBypass = sqlite3VdbeGoto(v, 0);
|
||||
@@ -1641,10 +1645,6 @@ void sqlite3GenerateConstraintChecks(
|
||||
addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
||||
}
|
||||
VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
|
||||
if( bAffinityDone==0 ){
|
||||
sqlite3TableAffinity(v, pTab, regNewData+1);
|
||||
bAffinityDone = 1;
|
||||
}
|
||||
iThisCur = iIdxCur+ix;
|
||||
|
||||
|
||||
|
||||
+15
-10
@@ -1291,7 +1291,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
sqlite3VtabRollback(db);
|
||||
sqlite3EndBenignMalloc();
|
||||
|
||||
if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){
|
||||
if( schemaChange ){
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
}
|
||||
@@ -1692,13 +1692,14 @@ int sqlite3CreateFunc(
|
||||
int extraFlags;
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
if( zFunctionName==0 ||
|
||||
(xSFunc && (xFinal || xStep)) ||
|
||||
(!xSFunc && (xFinal && !xStep)) ||
|
||||
(!xSFunc && (!xFinal && xStep)) ||
|
||||
((xValue || xInverse) && (!xStep || !xFinal || !xValue || !xInverse)) ||
|
||||
(nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
|
||||
(255<(nName = sqlite3Strlen30( zFunctionName))) ){
|
||||
assert( xValue==0 || xSFunc==0 );
|
||||
if( zFunctionName==0 /* Must have a valid name */
|
||||
|| (xSFunc!=0 && xFinal!=0) /* Not both xSFunc and xFinal */
|
||||
|| ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */
|
||||
|| ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */
|
||||
|| (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
|
||||
|| (255<(nName = sqlite3Strlen30( zFunctionName)))
|
||||
){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
|
||||
@@ -1739,7 +1740,7 @@ int sqlite3CreateFunc(
|
||||
** operation to continue but invalidate all precompiled statements.
|
||||
*/
|
||||
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
|
||||
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
|
||||
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){
|
||||
if( db->nVdbeActive ){
|
||||
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
|
||||
"unable to delete/modify user-function due to active statements");
|
||||
@@ -3710,6 +3711,9 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
}else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
|
||||
*(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
|
||||
rc = SQLITE_OK;
|
||||
}else if( op==SQLITE_FCNTL_DATA_VERSION ){
|
||||
*(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = sqlite3OsFileControl(fd, op, pArg);
|
||||
}
|
||||
@@ -3973,7 +3977,8 @@ int sqlite3_test_control(int op, ...){
|
||||
*/
|
||||
case SQLITE_TESTCTRL_VDBE_COVERAGE: {
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
typedef void (*branch_callback)(void*,int,u8,u8);
|
||||
typedef void (*branch_callback)(void*,unsigned int,
|
||||
unsigned char,unsigned char);
|
||||
sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback);
|
||||
sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
|
||||
#endif
|
||||
|
||||
+31
-18
@@ -1764,7 +1764,6 @@ static void pager_reset(Pager *pPager){
|
||||
** Return the pPager->iDataVersion value
|
||||
*/
|
||||
u32 sqlite3PagerDataVersion(Pager *pPager){
|
||||
assert( pPager->eState>PAGER_OPEN );
|
||||
return pPager->iDataVersion;
|
||||
}
|
||||
|
||||
@@ -6382,9 +6381,10 @@ int sqlite3PagerCommitPhaseOne(
|
||||
** backup in progress needs to be restarted. */
|
||||
sqlite3BackupRestart(pPager->pBackup);
|
||||
}else{
|
||||
PgHdr *pList;
|
||||
if( pagerUseWal(pPager) ){
|
||||
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
|
||||
PgHdr *pPageOne = 0;
|
||||
pList = sqlite3PcacheDirtyList(pPager->pPCache);
|
||||
if( pList==0 ){
|
||||
/* Must have at least one page for the WAL commit flag.
|
||||
** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
|
||||
@@ -6405,14 +6405,14 @@ int sqlite3PagerCommitPhaseOne(
|
||||
** should be used. No rollback journal is created if batch-atomic-write
|
||||
** is enabled.
|
||||
*/
|
||||
sqlite3_file *fd = pPager->fd;
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
|
||||
sqlite3_file *fd = pPager->fd;
|
||||
int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
|
||||
&& (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
|
||||
&& !pPager->noSync
|
||||
&& sqlite3JournalIsInMemory(pPager->jfd);
|
||||
#else
|
||||
# define bBatch 0
|
||||
# define bBatch 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
@@ -6464,15 +6464,16 @@ int sqlite3PagerCommitPhaseOne(
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#else /* SQLITE_ENABLE_ATOMIC_WRITE */
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
if( zMaster ){
|
||||
rc = sqlite3JournalCreate(pPager->jfd);
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
assert( bBatch==0 );
|
||||
}
|
||||
#endif
|
||||
rc = pager_incr_changecounter(pPager, 0);
|
||||
#endif
|
||||
#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
|
||||
/* Write the master journal name into the journal file. If a master
|
||||
@@ -6496,23 +6497,35 @@ int sqlite3PagerCommitPhaseOne(
|
||||
rc = syncJournal(pPager, 0);
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
|
||||
pList = sqlite3PcacheDirtyList(pPager->pPCache);
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
if( bBatch ){
|
||||
/* The pager is now in DBMOD state. But regardless of what happens
|
||||
** next, attempting to play the journal back into the database would
|
||||
** be unsafe. Close it now to make sure that does not happen. */
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
}
|
||||
rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
|
||||
if( bBatch ){
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
|
||||
rc = pager_write_pagelist(pPager, pList);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
|
||||
|
||||
if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){
|
||||
rc = sqlite3JournalCreate(pPager->jfd);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
}
|
||||
bBatch = 0;
|
||||
}else{
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
|
||||
|
||||
if( bBatch==0 && rc==SQLITE_OK ){
|
||||
rc = pager_write_pagelist(pPager, pList);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( rc!=SQLITE_IOERR_BLOCKED );
|
||||
|
||||
+34
-54
@@ -531,15 +531,12 @@ multiselect_op(A) ::= UNION(OP). {A = @OP; /*A-overwrites-OP*/}
|
||||
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
|
||||
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP; /*A-overwrites-OP*/}
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
groupby_opt(P) having_opt(Q)
|
||||
%ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
windowdefn_opt(R)
|
||||
%endif
|
||||
orderby_opt(Z) limit_opt(L). {
|
||||
#if SELECTTRACE_ENABLED
|
||||
Token s = S; /*A-overwrites-S*/
|
||||
#endif
|
||||
A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( A ){
|
||||
@@ -547,30 +544,7 @@ oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
}else{
|
||||
sqlite3WindowListDelete(pParse->db, R);
|
||||
}
|
||||
#endif // SQLITE_OMIT_WINDOWFUNC
|
||||
#if SELECTTRACE_ENABLED
|
||||
/* Populate the Select.zSelName[] string that is used to help with
|
||||
** query planner debugging, to differentiate between multiple Select
|
||||
** objects in a complex query.
|
||||
**
|
||||
** If the SELECT keyword is immediately followed by a C-style comment
|
||||
** then extract the first few alphanumeric characters from within that
|
||||
** comment to be the zSelName value. Otherwise, the label is #N where
|
||||
** is an integer that is incremented with each SELECT statement seen.
|
||||
*/
|
||||
if( A!=0 ){
|
||||
const char *z = s.z+6;
|
||||
int i;
|
||||
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName,"#%d",++pParse->nSelect);
|
||||
while( z[0]==' ' ) z++;
|
||||
if( z[0]=='/' && z[1]=='*' ){
|
||||
z += 2;
|
||||
while( z[0]==' ' ) z++;
|
||||
for(i=0; sqlite3Isalnum(z[i]); i++){}
|
||||
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "%.*s", i, z);
|
||||
}
|
||||
}
|
||||
#endif /* SELECTRACE_ENABLED */
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
}
|
||||
oneselect(A) ::= values(A).
|
||||
|
||||
@@ -1028,10 +1002,10 @@ expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP
|
||||
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
|
||||
}
|
||||
A = sqlite3ExprFunction(pParse, Y, &X);
|
||||
sqlite3WindowAttach(pParse, A, Z);
|
||||
if( D==SF_Distinct && A ){
|
||||
A->flags |= EP_Distinct;
|
||||
}
|
||||
sqlite3WindowAttach(pParse, A, Z);
|
||||
}
|
||||
expr(A) ::= id(X) LP STAR RP
|
||||
%ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
@@ -1605,17 +1579,18 @@ wqlist(A) ::= wqlist(A) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
|
||||
//
|
||||
%ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
%type windowdefn_list {Window*}
|
||||
%destructor windowdefn_list {sqlite3WindowDelete(pParse->db, $$);}
|
||||
%destructor windowdefn_list {sqlite3WindowListDelete(pParse->db, $$);}
|
||||
windowdefn_list(A) ::= windowdefn(Z). { A = Z; }
|
||||
windowdefn_list(A) ::= windowdefn_list(Y) COMMA windowdefn(Z). {
|
||||
if( Z ) Z->pNextWin = Y;
|
||||
assert( Z!=0 );
|
||||
Z->pNextWin = Y;
|
||||
A = Z;
|
||||
}
|
||||
|
||||
%type windowdefn {Window*}
|
||||
%destructor windowdefn {sqlite3WindowDelete(pParse->db, $$);}
|
||||
windowdefn(A) ::= nm(X) AS window(Y). {
|
||||
if( Y ){
|
||||
if( ALWAYS(Y) ){
|
||||
Y->zName = sqlite3DbStrNDup(pParse->db, X.z, X.n);
|
||||
}
|
||||
A = Y;
|
||||
@@ -1627,10 +1602,6 @@ windowdefn(A) ::= nm(X) AS window(Y). {
|
||||
%type frame_opt {Window*}
|
||||
%destructor frame_opt {sqlite3WindowDelete(pParse->db, $$);}
|
||||
|
||||
%type window_or_nm {Window*}
|
||||
%destructor window_or_nm {
|
||||
sqlite3WindowDelete(pParse->db, $$);}
|
||||
|
||||
%type part_opt {ExprList*}
|
||||
%destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);}
|
||||
|
||||
@@ -1641,18 +1612,14 @@ sqlite3WindowDelete(pParse->db, $$);}
|
||||
|
||||
%type frame_bound {struct FrameBound}
|
||||
%destructor frame_bound {sqlite3ExprDelete(pParse->db, $$.pExpr);}
|
||||
|
||||
window_or_nm(A) ::= window(Z). {A = Z;}
|
||||
window_or_nm(A) ::= nm(Z). {
|
||||
A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
||||
if( A ){
|
||||
A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n);
|
||||
}
|
||||
}
|
||||
%type frame_bound_s {struct FrameBound}
|
||||
%destructor frame_bound_s {sqlite3ExprDelete(pParse->db, $$.pExpr);}
|
||||
%type frame_bound_e {struct FrameBound}
|
||||
%destructor frame_bound_e {sqlite3ExprDelete(pParse->db, $$.pExpr);}
|
||||
|
||||
window(A) ::= LP part_opt(X) orderby_opt(Y) frame_opt(Z) RP. {
|
||||
A = Z;
|
||||
if( A ){
|
||||
if( ALWAYS(A) ){
|
||||
A->pPartition = X;
|
||||
A->pOrderBy = Y;
|
||||
}
|
||||
@@ -1664,36 +1631,49 @@ part_opt(A) ::= . { A = 0; }
|
||||
frame_opt(A) ::= . {
|
||||
A = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0);
|
||||
}
|
||||
frame_opt(A) ::= range_or_rows(X) frame_bound(Y). {
|
||||
frame_opt(A) ::= range_or_rows(X) frame_bound_s(Y). {
|
||||
A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, TK_CURRENT, 0);
|
||||
}
|
||||
frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound(Y) AND frame_bound(Z). {
|
||||
frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound_s(Y) AND frame_bound_e(Z). {
|
||||
A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, Z.eType, Z.pExpr);
|
||||
}
|
||||
|
||||
range_or_rows(A) ::= RANGE. { A = TK_RANGE; }
|
||||
range_or_rows(A) ::= ROWS. { A = TK_ROWS; }
|
||||
|
||||
frame_bound(A) ::= UNBOUNDED PRECEDING. { A.eType = TK_UNBOUNDED; A.pExpr = 0; }
|
||||
|
||||
frame_bound_s(A) ::= frame_bound(X). { A = X; }
|
||||
frame_bound_s(A) ::= UNBOUNDED PRECEDING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;}
|
||||
frame_bound_e(A) ::= frame_bound(X). { A = X; }
|
||||
frame_bound_e(A) ::= UNBOUNDED FOLLOWING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;}
|
||||
|
||||
frame_bound(A) ::= expr(X) PRECEDING. { A.eType = TK_PRECEDING; A.pExpr = X; }
|
||||
frame_bound(A) ::= CURRENT ROW. { A.eType = TK_CURRENT ; A.pExpr = 0; }
|
||||
frame_bound(A) ::= expr(X) FOLLOWING. { A.eType = TK_FOLLOWING; A.pExpr = X; }
|
||||
frame_bound(A) ::= UNBOUNDED FOLLOWING. { A.eType = TK_UNBOUNDED; A.pExpr = 0; }
|
||||
|
||||
%type windowdefn_opt {Window*}
|
||||
%destructor windowdefn_opt {sqlite3WindowDelete(pParse->db, $$);}
|
||||
%destructor windowdefn_opt {sqlite3WindowListDelete(pParse->db, $$);}
|
||||
windowdefn_opt(A) ::= . { A = 0; }
|
||||
windowdefn_opt(A) ::= WINDOW windowdefn_list(B). { A = B; }
|
||||
|
||||
%type over_opt {Window*}
|
||||
%destructor over_opt {sqlite3WindowDelete(pParse->db, $$);}
|
||||
over_opt(A) ::= . { A = 0; }
|
||||
over_opt(A) ::= filter_opt(W) OVER window_or_nm(Z). {
|
||||
over_opt(A) ::= filter_opt(W) OVER window(Z). {
|
||||
A = Z;
|
||||
if( A ) A->pFilter = W;
|
||||
assert( A!=0 );
|
||||
A->pFilter = W;
|
||||
}
|
||||
over_opt(A) ::= filter_opt(W) OVER nm(Z). {
|
||||
A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
||||
if( A ){
|
||||
A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n);
|
||||
A->pFilter = W;
|
||||
}else{
|
||||
sqlite3ExprDelete(pParse->db, W);
|
||||
}
|
||||
}
|
||||
|
||||
filter_opt(A) ::= . { A = 0; }
|
||||
filter_opt(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
|
||||
%endif // SQLITE_OMIT_WINDOWFUNC
|
||||
|
||||
%endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
+18
-1
@@ -758,7 +758,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( is_agg==0 && pExpr->pWin ){
|
||||
assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
|
||||
|| (pDef->xValue==0 && pDef->xInverse==0)
|
||||
|| (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
|
||||
);
|
||||
if( pDef && pDef->xValue==0 && pExpr->pWin ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%.*s() may not be used as a window function", nId, zId
|
||||
);
|
||||
@@ -1239,6 +1243,19 @@ static int resolveOrderGroupBy(
|
||||
}
|
||||
for(j=0; j<pSelect->pEList->nExpr; j++){
|
||||
if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( pE->pWin ){
|
||||
/* Since this window function is being changed into a reference
|
||||
** to the same window function the result set, remove the instance
|
||||
** of this window function from the Select.pWin list. */
|
||||
Window **pp;
|
||||
for(pp=&pSelect->pWin; *pp; pp=&(*pp)->pNextWin){
|
||||
if( *pp==pE->pWin ){
|
||||
*pp = (*pp)->pNextWin;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pItem->u.x.iOrderByCol = j+1;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-25
@@ -21,7 +21,7 @@
|
||||
/***/ int sqlite3SelectTrace = 0;
|
||||
# define SELECTTRACE(K,P,S,X) \
|
||||
if(sqlite3SelectTrace&(K)) \
|
||||
sqlite3DebugPrintf("%s/%d/%p: ",(S)->zSelName,(P)->addrExplain,(S)),\
|
||||
sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
|
||||
sqlite3DebugPrintf X
|
||||
#else
|
||||
# define SELECTTRACE(K,P,S,X)
|
||||
@@ -151,9 +151,7 @@ Select *sqlite3SelectNew(
|
||||
pNew->selFlags = selFlags;
|
||||
pNew->iLimit = 0;
|
||||
pNew->iOffset = 0;
|
||||
#if SELECTTRACE_ENABLED
|
||||
pNew->zSelName[0] = 0;
|
||||
#endif
|
||||
pNew->selId = ++pParse->nSelect;
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->nSelectRow = 0;
|
||||
@@ -181,17 +179,6 @@ Select *sqlite3SelectNew(
|
||||
return pNew;
|
||||
}
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
/*
|
||||
** Set the name of a Select object
|
||||
*/
|
||||
void sqlite3SelectSetName(Select *p, const char *zName){
|
||||
if( p && zName ){
|
||||
sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Delete the given Select structure and all of its substructures.
|
||||
@@ -3838,8 +3825,8 @@ static int flattenSubquery(
|
||||
assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
|
||||
|
||||
/***** If we reach this point, flattening is permitted. *****/
|
||||
SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
|
||||
pSub->zSelName, pSub, iFrom));
|
||||
SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
|
||||
pSub->selId, pSub, iFrom));
|
||||
|
||||
/* Authorize the subquery */
|
||||
pParse->zAuthContext = pSubitem->zName;
|
||||
@@ -3890,7 +3877,6 @@ static int flattenSubquery(
|
||||
p->pPrior = 0;
|
||||
p->pLimit = 0;
|
||||
pNew = sqlite3SelectDup(db, p, 0);
|
||||
sqlite3SelectSetName(pNew, pSub->zSelName);
|
||||
p->pLimit = pLimit;
|
||||
p->pOrderBy = pOrderBy;
|
||||
p->pSrc = pSrc;
|
||||
@@ -3903,7 +3889,7 @@ static int flattenSubquery(
|
||||
pNew->pNext = p;
|
||||
p->pPrior = pNew;
|
||||
SELECTTRACE(2,pParse,p,("compound-subquery flattener"
|
||||
" creates %s.%p as peer\n",pNew->zSelName, pNew));
|
||||
" creates %u as peer\n",pNew->selId));
|
||||
}
|
||||
if( db->mallocFailed ) return 1;
|
||||
}
|
||||
@@ -4157,7 +4143,7 @@ static int pushDownWhereTerms(
|
||||
if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( pSubq->pWin ) return 0;
|
||||
if( pSubq->pWin ) return 0; /* restriction (6) */
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -4623,7 +4609,7 @@ int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){
|
||||
if( pFrom->zAlias ){
|
||||
pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
|
||||
}else{
|
||||
pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%p", (void*)pTab);
|
||||
pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId);
|
||||
}
|
||||
while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
||||
sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
|
||||
@@ -4729,7 +4715,6 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
|
||||
assert( pFrom->pSelect==0 );
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
|
||||
sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
|
||||
nCol = pTab->nCol;
|
||||
pTab->nCol = -1;
|
||||
sqlite3WalkSelect(pWalker, pFrom->pSelect);
|
||||
@@ -5187,7 +5172,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
||||
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
|
||||
sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem);
|
||||
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)nArg);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
|
||||
@@ -5721,7 +5706,7 @@ int sqlite3Select(
|
||||
VdbeComment((v, "%s", pItem->pTab->zName));
|
||||
pItem->addrFillSub = addrTop;
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
ExplainQueryPlan((pParse, 1, "CO-ROUTINE 0x%p", pSub));
|
||||
ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId));
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
pItem->fg.viaCoroutine = 1;
|
||||
@@ -5760,7 +5745,7 @@ int sqlite3Select(
|
||||
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
||||
}else{
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
ExplainQueryPlan((pParse, 1, "MATERIALIZE 0x%p", pSub));
|
||||
ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
}
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
@@ -5940,9 +5925,11 @@ int sqlite3Select(
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
|
||||
sqlite3VdbeResolveLabel(v, addrGosub);
|
||||
VdbeNoopComment((v, "inner-loop subroutine"));
|
||||
selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak);
|
||||
sqlite3VdbeResolveLabel(v, iCont);
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regGosub);
|
||||
VdbeComment((v, "end inner-loop subroutine"));
|
||||
sqlite3VdbeResolveLabel(v, iBreak);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
+6
-1
@@ -4354,6 +4354,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
||||
"SELECT total(length(sql)) FROM %s" },
|
||||
};
|
||||
int i;
|
||||
unsigned iDataVersion;
|
||||
char *zSchemaTab;
|
||||
char *zDb = nArg>=2 ? azArg[1] : "main";
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
@@ -4406,6 +4407,8 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
||||
utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
|
||||
}
|
||||
sqlite3_free(zSchemaTab);
|
||||
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
|
||||
utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5862,7 +5865,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
const char *zLike = 0;
|
||||
int i;
|
||||
int savedShowHeader = p->showHeader;
|
||||
ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines);
|
||||
int savedShellFlags = p->shellFlgs;
|
||||
ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo);
|
||||
for(i=1; i<nArg; i++){
|
||||
if( azArg[i][0]=='-' ){
|
||||
const char *z = azArg[i]+1;
|
||||
@@ -5944,6 +5948,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
|
||||
raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
|
||||
p->showHeader = savedShowHeader;
|
||||
p->shellFlgs = savedShellFlags;
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
|
||||
|
||||
+61
-9
@@ -1073,6 +1073,25 @@ struct sqlite3_io_methods {
|
||||
** a file lock using the xLock or xShmLock methods of the VFS to wait
|
||||
** for up to M milliseconds before failing, where M is the single
|
||||
** unsigned integer parameter.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
|
||||
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
|
||||
** a database file. The argument is a pointer to a 32-bit unsigned integer.
|
||||
** The "data version" for the pager is written into the pointer. The
|
||||
** "data version" changes whenever any change occurs to the corresponding
|
||||
** database file, either through SQL statements on the same database
|
||||
** connection, or through transactions committed by separate database
|
||||
** connections possibly in other processes. The [sqlite3_total_changes()]
|
||||
** interface can be used to find if any database on the connection has changed,
|
||||
** but that interface response to changes on TEMP as well as MAIN and does
|
||||
** not provide a mechanism to detect changes to MAIN only. Also, the
|
||||
** [sqlite3_total_changes()] interface response to internal changes only and
|
||||
** omits changes made by other database connections. The
|
||||
** [PRAGMA data_version] command provide a mechanism to detect changes to
|
||||
** a single attached database that occur due to other database connections,
|
||||
** but omits changes implemented by the database connection for which it is
|
||||
** called. This file control is the only mechanism to detect changes that
|
||||
** happen either internally or externally on a single database.
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
@@ -1108,6 +1127,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
|
||||
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
|
||||
#define SQLITE_FCNTL_LOCK_TIMEOUT 34
|
||||
#define SQLITE_FCNTL_DATA_VERSION 35
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@@ -2122,6 +2142,12 @@ struct sqlite3_mem_methods {
|
||||
** with no schema and no content. The following process works even for
|
||||
** a badly corrupted database file:
|
||||
** <ol>
|
||||
** <li> If the database connection is newly opened, make sure it has read the
|
||||
** database schema by preparing then discarding some query against the
|
||||
** database, or calling sqlite3_table_column_metadata(), ignoring any
|
||||
** errors. This step is only necessary if the application desires to keep
|
||||
** the database in WAL mode after the reset if it was in WAL mode before
|
||||
** the reset.
|
||||
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
|
||||
** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
|
||||
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
|
||||
@@ -2270,12 +2296,17 @@ void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
||||
** program, the value returned reflects the number of rows modified by the
|
||||
** previous INSERT, UPDATE or DELETE statement within the same trigger.
|
||||
**
|
||||
** See also the [sqlite3_total_changes()] interface, the
|
||||
** [count_changes pragma], and the [changes() SQL function].
|
||||
**
|
||||
** If a separate thread makes changes on the same database connection
|
||||
** while [sqlite3_changes()] is running then the value returned
|
||||
** is unpredictable and not meaningful.
|
||||
**
|
||||
** See also:
|
||||
** <ul>
|
||||
** <li> the [sqlite3_total_changes()] interface
|
||||
** <li> the [count_changes pragma]
|
||||
** <li> the [changes() SQL function]
|
||||
** <li> the [data_version pragma]
|
||||
** </ul>
|
||||
*/
|
||||
int sqlite3_changes(sqlite3*);
|
||||
|
||||
@@ -2293,13 +2324,26 @@ int sqlite3_changes(sqlite3*);
|
||||
** count, but those made as part of REPLACE constraint resolution are
|
||||
** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
|
||||
** are not counted.
|
||||
**
|
||||
** See also the [sqlite3_changes()] interface, the
|
||||
** [count_changes pragma], and the [total_changes() SQL function].
|
||||
**
|
||||
** This the [sqlite3_total_changes(D)] interface only reports the number
|
||||
** of rows that changed due to SQL statement run against database
|
||||
** connection D. Any changes by other database connections are ignored.
|
||||
** To detect changes against a database file from other database
|
||||
** connections use the [PRAGMA data_version] command or the
|
||||
** [SQLITE_FCNTL_DATA_VERSION] [file control].
|
||||
**
|
||||
** If a separate thread makes changes on the same database connection
|
||||
** while [sqlite3_total_changes()] is running then the value
|
||||
** returned is unpredictable and not meaningful.
|
||||
**
|
||||
** See also:
|
||||
** <ul>
|
||||
** <li> the [sqlite3_changes()] interface
|
||||
** <li> the [count_changes pragma]
|
||||
** <li> the [changes() SQL function]
|
||||
** <li> the [data_version pragma]
|
||||
** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
|
||||
** </ul>
|
||||
*/
|
||||
int sqlite3_total_changes(sqlite3*);
|
||||
|
||||
@@ -7071,6 +7115,7 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
||||
/*
|
||||
** CAPI3REF: Low-Level Control Of Database Files
|
||||
** METHOD: sqlite3
|
||||
** KEYWORDS: {file control}
|
||||
**
|
||||
** ^The [sqlite3_file_control()] interface makes a direct call to the
|
||||
** xFileControl method for the [sqlite3_io_methods] object associated
|
||||
@@ -7085,11 +7130,18 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
||||
** the xFileControl method. ^The return value of the xFileControl
|
||||
** method becomes the return value of this routine.
|
||||
**
|
||||
** A few opcodes for [sqlite3_file_control()] are handled directly
|
||||
** by the SQLite core and never invoke the
|
||||
** sqlite3_io_methods.xFileControl method.
|
||||
** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
|
||||
** a pointer to the underlying [sqlite3_file] object to be written into
|
||||
** the space pointed to by the 4th parameter. ^The [SQLITE_FCNTL_FILE_POINTER]
|
||||
** case is a short-circuit path which does not actually invoke the
|
||||
** underlying sqlite3_io_methods.xFileControl method.
|
||||
** the space pointed to by the 4th parameter. The
|
||||
** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns
|
||||
** the [sqlite3_file] object associated with the journal file instead of
|
||||
** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns
|
||||
** a pointer to the underlying [sqlite3_vfs] object for the file.
|
||||
** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter
|
||||
** from the pager.
|
||||
**
|
||||
** ^If the second parameter (zDbName) does not match the name of any
|
||||
** open database file, then SQLITE_ERROR is returned. ^This error
|
||||
|
||||
+29
-23
@@ -1583,6 +1583,7 @@ struct sqlite3 {
|
||||
/* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */
|
||||
#define SQLITE_PushDown 0x1000 /* The push-down optimization */
|
||||
#define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */
|
||||
#define SQLITE_SkipScan 0x4000 /* Skip-scans */
|
||||
#define SQLITE_AllOpts 0xffff /* All optimizations */
|
||||
|
||||
/*
|
||||
@@ -2808,9 +2809,7 @@ struct Select {
|
||||
LogEst nSelectRow; /* Estimated number of result rows */
|
||||
u32 selFlags; /* Various SF_* values */
|
||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||
#if SELECTTRACE_ENABLED
|
||||
char zSelName[12]; /* Symbolic name of this SELECT use for debugging */
|
||||
#endif
|
||||
u32 selId; /* Unique identifier number for this SELECT */
|
||||
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
|
||||
SrcList *pSrc; /* The FROM clause */
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
@@ -3071,9 +3070,7 @@ struct Parse {
|
||||
int regRowid; /* Register holding rowid of CREATE TABLE entry */
|
||||
int regRoot; /* Register holding root page number for new objects */
|
||||
int nMaxArg; /* Max args passed to user function by sub-program */
|
||||
#if SELECTTRACE_ENABLED
|
||||
int nSelect; /* Number of SELECT statements seen */
|
||||
#endif
|
||||
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
int nTableLock; /* Number of locks in aTableLock */
|
||||
TableLock *aTableLock; /* Required table locks for shared-cache mode */
|
||||
@@ -3387,7 +3384,7 @@ struct Sqlite3Config {
|
||||
/* The following callback (if not NULL) is invoked on every VDBE branch
|
||||
** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE.
|
||||
*/
|
||||
void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */
|
||||
void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */
|
||||
void *pVdbeBranchArg; /* 1st argument */
|
||||
#endif
|
||||
#ifndef SQLITE_UNTESTABLE
|
||||
@@ -3490,8 +3487,22 @@ struct TreeView {
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Object used to encode the OVER() clause attached to a window-function
|
||||
** invocation. And some fields used while generating VM code for the same.
|
||||
** This object is used in varioius ways, all related to window functions
|
||||
**
|
||||
** (1) A single instance of this structure is attached to the
|
||||
** the Expr.pWin field for each window function in an expression tree.
|
||||
** This object holds the information contained in the OVER clause,
|
||||
** plus additional fields used during code generation.
|
||||
**
|
||||
** (2) All window functions in a single SELECT form a linked-list
|
||||
** attached to Select.pWin. The Window.pFunc and Window.pExpr
|
||||
** fields point back to the expression that is the window function.
|
||||
**
|
||||
** (3) The terms of the WINDOW clause of a SELECT are instances of this
|
||||
** object on a linked list attached to Select.pWinDefn.
|
||||
**
|
||||
** The uses (1) and (2) are really the same Window object that just happens
|
||||
** to be accessible in two different ways. Use (3) is are separate objects.
|
||||
*/
|
||||
struct Window {
|
||||
char *zName; /* Name of window (may be NULL) */
|
||||
@@ -3502,20 +3513,16 @@ struct Window {
|
||||
u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
|
||||
Expr *pStart; /* Expression for "<expr> PRECEDING" */
|
||||
Expr *pEnd; /* Expression for "<expr> FOLLOWING" */
|
||||
|
||||
Window *pNextWin; /* Next window function belonging to this SELECT */
|
||||
|
||||
Expr *pFilter;
|
||||
FuncDef *pFunc;
|
||||
|
||||
int iEphCsr; /* Temp table used by this window */
|
||||
Expr *pFilter; /* The FILTER expression */
|
||||
FuncDef *pFunc; /* The function */
|
||||
int iEphCsr; /* Partition buffer or Peer buffer */
|
||||
int regAccum;
|
||||
int regResult;
|
||||
|
||||
int csrApp; /* Function cursor (used by min/max) */
|
||||
int regApp; /* Function register (also used by min/max) */
|
||||
|
||||
int regPart;
|
||||
int regPart; /* First in a set of registers holding PARTITION BY
|
||||
** and ORDER BY values for the window */
|
||||
Expr *pOwner; /* Expression object this window is attached to */
|
||||
int nBufferCol; /* Number of columns in buffer table */
|
||||
int iArgCol; /* Offset of first argument for this function */
|
||||
@@ -3755,6 +3762,10 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
|
||||
void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
|
||||
void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
|
||||
void sqlite3TreeViewWith(TreeView*, const With*, u8);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
void sqlite3TreeViewWindow(TreeView*, const Window*, u8);
|
||||
void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -4010,11 +4021,6 @@ ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
|
||||
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
|
||||
IdList *sqlite3IdListDup(sqlite3*,IdList*);
|
||||
Select *sqlite3SelectDup(sqlite3*,Select*,int);
|
||||
#if SELECTTRACE_ENABLED
|
||||
void sqlite3SelectSetName(Select*,const char*);
|
||||
#else
|
||||
# define sqlite3SelectSetName(A,B)
|
||||
#endif
|
||||
void sqlite3InsertBuiltinFuncs(FuncDef*,int);
|
||||
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
|
||||
void sqlite3RegisterBuiltinFunctions(void);
|
||||
|
||||
+40
@@ -5684,6 +5684,44 @@ static int SQLITE_TCLAPI file_control_lasterrno_test(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_data_version DB DBNAME
|
||||
**
|
||||
** This TCL command runs the sqlite3_file_control with the
|
||||
** SQLITE_FCNTL_DATA_VERSION opcode, returning the result.
|
||||
*/
|
||||
static int SQLITE_TCLAPI file_control_data_version(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
unsigned int iVers; /* data version */
|
||||
char *zDb; /* Db name ("main", "temp" etc.) */
|
||||
sqlite3 *db; /* Database handle */
|
||||
int rc; /* file_control() return code */
|
||||
char zBuf[100];
|
||||
|
||||
if( objc!=3 && objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB [DBNAME]");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zDb = objc==3 ? Tcl_GetString(objv[2]) : NULL;
|
||||
|
||||
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_DATA_VERSION, (void *)&iVers);
|
||||
if( rc ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zBuf),zBuf,"%u",iVers);
|
||||
Tcl_SetResult(interp, (char *)zBuf, TCL_VOLATILE);
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_chunksize_test DB DBNAME SIZE
|
||||
**
|
||||
@@ -6954,6 +6992,7 @@ static int SQLITE_TCLAPI optimization_control(
|
||||
{ "omit-noop-join", SQLITE_OmitNoopJoin },
|
||||
{ "stat3", SQLITE_Stat34 },
|
||||
{ "stat4", SQLITE_Stat34 },
|
||||
{ "skip-scan", SQLITE_SkipScan },
|
||||
};
|
||||
|
||||
if( objc!=4 ){
|
||||
@@ -7699,6 +7738,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
|
||||
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
|
||||
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
|
||||
{ "file_control_data_version", file_control_data_version, 0 },
|
||||
#if SQLITE_OS_WIN
|
||||
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
|
||||
{ "file_control_win32_get_handle", file_control_win32_get_handle, 0 },
|
||||
|
||||
+30
-4
@@ -133,8 +133,9 @@ struct Testvfs {
|
||||
#define TESTVFS_UNLOCK_MASK 0x00020000
|
||||
#define TESTVFS_LOCK_MASK 0x00040000
|
||||
#define TESTVFS_CKLOCK_MASK 0x00080000
|
||||
#define TESTVFS_FCNTL_MASK 0x00100000
|
||||
|
||||
#define TESTVFS_ALL_MASK 0x000FFFFF
|
||||
#define TESTVFS_ALL_MASK 0x001FFFFF
|
||||
|
||||
|
||||
#define TESTVFS_MAX_PAGES 1024
|
||||
@@ -517,7 +518,8 @@ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
** File control method. For custom operations on an tvfs-file.
|
||||
*/
|
||||
static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
TestvfsFd *p = tvfsGetFd(pFile);
|
||||
TestvfsFd *pFd = tvfsGetFd(pFile);
|
||||
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||
if( op==SQLITE_FCNTL_PRAGMA ){
|
||||
char **argv = (char**)pArg;
|
||||
if( sqlite3_stricmp(argv[1],"error")==0 ){
|
||||
@@ -535,11 +537,34 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
return rc;
|
||||
}
|
||||
if( sqlite3_stricmp(argv[1], "filename")==0 ){
|
||||
argv[0] = sqlite3_mprintf("%s", p->zFilename);
|
||||
argv[0] = sqlite3_mprintf("%s", pFd->zFilename);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return sqlite3OsFileControl(p->pReal, op, pArg);
|
||||
if( p->pScript && (p->mask&TESTVFS_FCNTL_MASK) ){
|
||||
struct Fcntl {
|
||||
int iFnctl;
|
||||
const char *zFnctl;
|
||||
} aF[] = {
|
||||
{ SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, "BEGIN_ATOMIC_WRITE" },
|
||||
{ SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, "COMMIT_ATOMIC_WRITE" },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aF)/sizeof(aF[0]); i++){
|
||||
if( op==aF[i].iFnctl ) break;
|
||||
}
|
||||
if( i<sizeof(aF)/sizeof(aF[0]) ){
|
||||
int rc = 0;
|
||||
tvfsExecTcl(p, "xFileControl",
|
||||
Tcl_NewStringObj(pFd->zFilename, -1),
|
||||
Tcl_NewStringObj(aF[i].zFnctl, -1),
|
||||
0, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
}
|
||||
return sqlite3OsFileControl(pFd->pReal, op, pArg);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1160,6 +1185,7 @@ static int SQLITE_TCLAPI testvfs_obj_cmd(
|
||||
{ "xUnlock", TESTVFS_UNLOCK_MASK },
|
||||
{ "xLock", TESTVFS_LOCK_MASK },
|
||||
{ "xCheckReservedLock", TESTVFS_CKLOCK_MASK },
|
||||
{ "xFileControl", TESTVFS_FCNTL_MASK },
|
||||
};
|
||||
Tcl_Obj **apElem = 0;
|
||||
int nElem = 0;
|
||||
|
||||
@@ -302,6 +302,32 @@ static int SQLITE_TCLAPI test_create_sumint(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int SQLITE_TCLAPI test_override_sum(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3_create_function(db, "sum", -1, SQLITE_UTF8, 0,
|
||||
0, sumintStep, sumintFinal
|
||||
);
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
int Sqlitetest_window_Init(Tcl_Interp *interp){
|
||||
static struct {
|
||||
char *zName;
|
||||
@@ -311,6 +337,7 @@ int Sqlitetest_window_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_create_window_function", test_create_window, 0 },
|
||||
{ "test_create_window_function_misuse", test_create_window_misuse, 0 },
|
||||
{ "test_create_sumint", test_create_sumint, 0 },
|
||||
{ "test_override_sum", test_override_sum, 0 },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
|
||||
+3
-3
@@ -264,7 +264,7 @@ static int analyzeFilterKeyword(const unsigned char *z, int lastToken){
|
||||
}
|
||||
return TK_ID;
|
||||
}
|
||||
#endif // SQLITE_OMIT_WINDOWFUNC
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
/*
|
||||
** Return the length (in bytes) of the token that begins at z[0].
|
||||
@@ -604,7 +604,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
#else
|
||||
if( tokenType>=TK_SPACE ){
|
||||
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
|
||||
#endif // SQLITE_OMIT_WINDOWFUNC
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
if( db->u1.isInterrupted ){
|
||||
pParse->rc = SQLITE_INTERRUPT;
|
||||
break;
|
||||
@@ -634,7 +634,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
}else if( tokenType==TK_FILTER ){
|
||||
assert( n==6 );
|
||||
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
|
||||
#endif // SQLITE_OMIT_WINDOWFUNC
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
|
||||
break;
|
||||
|
||||
+117
-11
@@ -139,21 +139,13 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
sqlite3TreeViewPush(pView, 1);
|
||||
}
|
||||
do{
|
||||
#if SELECTTRACE_ENABLED
|
||||
sqlite3TreeViewLine(pView,
|
||||
"SELECT%s%s (%s/%p) selFlags=0x%x nSelectRow=%d",
|
||||
"SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d",
|
||||
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
|
||||
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
|
||||
p->zSelName, p, p->selFlags,
|
||||
p->selId, p, p->selFlags,
|
||||
(int)p->nSelectRow
|
||||
);
|
||||
#else
|
||||
sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
|
||||
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
|
||||
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
|
||||
(int)p->nSelectRow
|
||||
);
|
||||
#endif
|
||||
if( cnt++ ) sqlite3TreeViewPop(pView);
|
||||
if( p->pPrior ){
|
||||
n = 1000;
|
||||
@@ -165,8 +157,23 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
if( p->pHaving ) n++;
|
||||
if( p->pOrderBy ) n++;
|
||||
if( p->pLimit ) n++;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( p->pWin ) n++;
|
||||
if( p->pWinDefn ) n++;
|
||||
#endif
|
||||
}
|
||||
sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( p->pWin ){
|
||||
Window *pX;
|
||||
pView = sqlite3TreeViewPush(pView, (n--)>0);
|
||||
sqlite3TreeViewLine(pView, "window-functions");
|
||||
for(pX=p->pWin; pX; pX=pX->pNextWin){
|
||||
sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
#endif
|
||||
if( p->pSrc && p->pSrc->nSrc ){
|
||||
int i;
|
||||
pView = sqlite3TreeViewPush(pView, (n--)>0);
|
||||
@@ -216,6 +223,16 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
sqlite3TreeViewExpr(pView, p->pHaving, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( p->pWinDefn ){
|
||||
Window *pX;
|
||||
sqlite3TreeViewItem(pView, "WINDOW", (n--)>0);
|
||||
for(pX=p->pWinDefn; pX; pX=pX->pNextWin){
|
||||
sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
#endif
|
||||
if( p->pOrderBy ){
|
||||
sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
|
||||
}
|
||||
@@ -243,6 +260,83 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/*
|
||||
** Generate a description of starting or stopping bounds
|
||||
*/
|
||||
void sqlite3TreeViewBound(
|
||||
TreeView *pView, /* View context */
|
||||
u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */
|
||||
Expr *pExpr, /* Value for PRECEDING or FOLLOWING */
|
||||
u8 moreToFollow /* True if more to follow */
|
||||
){
|
||||
switch( eBound ){
|
||||
case TK_UNBOUNDED: {
|
||||
sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow);
|
||||
sqlite3TreeViewPop(pView);
|
||||
break;
|
||||
}
|
||||
case TK_CURRENT: {
|
||||
sqlite3TreeViewItem(pView, "CURRENT", moreToFollow);
|
||||
sqlite3TreeViewPop(pView);
|
||||
break;
|
||||
}
|
||||
case TK_PRECEDING: {
|
||||
sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow);
|
||||
sqlite3TreeViewExpr(pView, pExpr, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
break;
|
||||
}
|
||||
case TK_FOLLOWING: {
|
||||
sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow);
|
||||
sqlite3TreeViewExpr(pView, pExpr, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/*
|
||||
** Generate a human-readable explanation for a Window object
|
||||
*/
|
||||
void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
pView = sqlite3TreeViewPush(pView, more);
|
||||
if( pWin->zName ){
|
||||
sqlite3TreeViewLine(pView, "OVER %s", pWin->zName);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "OVER");
|
||||
}
|
||||
if( pWin->pPartition ){
|
||||
sqlite3TreeViewExprList(pView, pWin->pPartition, 1, "PARTITION-BY");
|
||||
}
|
||||
if( pWin->pOrderBy ){
|
||||
sqlite3TreeViewExprList(pView, pWin->pOrderBy, 1, "ORDER-BY");
|
||||
}
|
||||
if( pWin->eType ){
|
||||
sqlite3TreeViewItem(pView, pWin->eType==TK_RANGE ? "RANGE" : "ROWS", 0);
|
||||
sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
|
||||
sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/*
|
||||
** Generate a human-readable explanation for a Window Function object
|
||||
*/
|
||||
void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
|
||||
pView = sqlite3TreeViewPush(pView, more);
|
||||
sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
|
||||
pWin->pFunc->zName, pWin->pFunc->nArg);
|
||||
sqlite3TreeViewWindow(pView, pWin, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
/*
|
||||
** Generate a human-readable explanation of an expression tree.
|
||||
*/
|
||||
@@ -393,10 +487,17 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pFarg; /* List of function arguments */
|
||||
Window *pWin;
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
||||
pFarg = 0;
|
||||
pWin = 0;
|
||||
}else{
|
||||
pFarg = pExpr->x.pList;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
pWin = pExpr->pWin;
|
||||
#else
|
||||
pWin = 0;
|
||||
#endif
|
||||
}
|
||||
if( pExpr->op==TK_AGG_FUNCTION ){
|
||||
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
|
||||
@@ -405,8 +506,13 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
|
||||
}
|
||||
if( pFarg ){
|
||||
sqlite3TreeViewExprList(pView, pFarg, 0, 0);
|
||||
sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
|
||||
}
|
||||
#ifndef SQLITe_OMIT_WINDOWFUNC
|
||||
if( pWin ){
|
||||
sqlite3TreeViewWindow(pView, pWin, 0);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
|
||||
+1
-1
@@ -523,7 +523,7 @@ void sqlite3Update(
|
||||
if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
|
||||
assert( pPk );
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey);
|
||||
VdbeCoverageNeverTaken(v);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
if( eOnePass!=ONEPASS_SINGLE ){
|
||||
labelContinue = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
+103
-34
@@ -134,32 +134,56 @@ int sqlite3_found_count = 0;
|
||||
** feature is used for test suite validation only and does not appear an
|
||||
** production builds.
|
||||
**
|
||||
** M is an integer, 2 or 3, that indices how many different ways the
|
||||
** branch can go. It is usually 2. "I" is the direction the branch
|
||||
** goes. 0 means falls through. 1 means branch is taken. 2 means the
|
||||
** second alternative branch is taken.
|
||||
** M is an integer between 2 and 4. 2 indicates a ordinary two-way
|
||||
** branch (I=0 means fall through and I=1 means taken). 3 indicates
|
||||
** a 3-way branch where the third way is when one of the operands is
|
||||
** NULL. 4 indicates the OP_Jump instruction which has three destinations
|
||||
** depending on whether the first operand is less than, equal to, or greater
|
||||
** than the second.
|
||||
**
|
||||
** iSrcLine is the source code line (from the __LINE__ macro) that
|
||||
** generated the VDBE instruction. This instrumentation assumes that all
|
||||
** source code is in a single file (the amalgamation). Special values 1
|
||||
** and 2 for the iSrcLine parameter mean that this particular branch is
|
||||
** always taken or never taken, respectively.
|
||||
** generated the VDBE instruction combined with flag bits. The source
|
||||
** code line number is in the lower 24 bits of iSrcLine and the upper
|
||||
** 8 bytes are flags. The lower three bits of the flags indicate
|
||||
** values for I that should never occur. For example, if the branch is
|
||||
** always taken, the flags should be 0x05 since the fall-through and
|
||||
** alternate branch are never taken. If a branch is never taken then
|
||||
** flags should be 0x06 since only the fall-through approach is allowed.
|
||||
**
|
||||
** Bit 0x04 of the flags indicates an OP_Jump opcode that is only
|
||||
** interested in equal or not-equal. In other words, I==0 and I==2
|
||||
** should be treated the same.
|
||||
**
|
||||
** Since only a line number is retained, not the filename, this macro
|
||||
** only works for amalgamation builds. But that is ok, since these macros
|
||||
** should be no-ops except for special builds used to measure test coverage.
|
||||
*/
|
||||
#if !defined(SQLITE_VDBE_COVERAGE)
|
||||
# define VdbeBranchTaken(I,M)
|
||||
#else
|
||||
# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M)
|
||||
static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){
|
||||
if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){
|
||||
M = iSrcLine;
|
||||
/* Assert the truth of VdbeCoverageAlwaysTaken() and
|
||||
** VdbeCoverageNeverTaken() */
|
||||
assert( (M & I)==I );
|
||||
}else{
|
||||
if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/
|
||||
sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg,
|
||||
iSrcLine,I,M);
|
||||
static void vdbeTakeBranch(u32 iSrcLine, u8 I, u8 M){
|
||||
u8 mNever;
|
||||
assert( I<=2 ); /* 0: fall through, 1: taken, 2: alternate taken */
|
||||
assert( M<=4 ); /* 2: two-way branch, 3: three-way branch, 4: OP_Jump */
|
||||
assert( I<M ); /* I can only be 2 if M is 3 or 4 */
|
||||
/* Transform I from a integer [0,1,2] into a bitmask of [1,2,4] */
|
||||
I = 1<<I;
|
||||
/* The upper 8 bits of iSrcLine are flags. The lower three bits of
|
||||
** the flags indicate directions that the branch can never go. If
|
||||
** a branch really does go in one of those directions, assert right
|
||||
** away. */
|
||||
mNever = iSrcLine >> 24;
|
||||
assert( (I & mNever)==0 );
|
||||
if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/
|
||||
I |= mNever;
|
||||
if( M==2 ) I |= 0x04;
|
||||
if( M==4 ){
|
||||
I |= 0x08;
|
||||
if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/
|
||||
}
|
||||
sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg,
|
||||
iSrcLine&0xffffff, I, M);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1155,6 +1179,9 @@ case OP_Null: { /* out2 */
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
|
||||
pOut->n = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pOut->uTemp = 0;
|
||||
#endif
|
||||
while( cnt>0 ){
|
||||
pOut++;
|
||||
memAboutToChange(p, pOut);
|
||||
@@ -2159,11 +2186,11 @@ case OP_Compare: {
|
||||
*/
|
||||
case OP_Jump: { /* jump */
|
||||
if( iCompare<0 ){
|
||||
VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1];
|
||||
VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
|
||||
}else if( iCompare==0 ){
|
||||
VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1];
|
||||
VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1];
|
||||
}else{
|
||||
VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1];
|
||||
VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -6288,18 +6315,29 @@ case OP_DecrJumpZero: { /* jump, in1 */
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: AggStep0 P1 P2 P3 P4 P5
|
||||
/* Opcode: AggStep * P2 P3 P4 P5
|
||||
** Synopsis: accum=r[P3] step(r[P2@P5])
|
||||
**
|
||||
** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an
|
||||
** aggregate. The function has P5 arguments. P4 is a pointer to the
|
||||
** Execute the xStep function for an aggregate.
|
||||
** The function has P5 arguments. P4 is a pointer to the
|
||||
** FuncDef structure that specifies the function. Register P3 is the
|
||||
** accumulator.
|
||||
**
|
||||
** The P5 arguments are taken from register P2 and its
|
||||
** successors.
|
||||
*/
|
||||
/* Opcode: AggStep P1 P2 P3 P4 P5
|
||||
/* Opcode: AggInverse * P2 P3 P4 P5
|
||||
** Synopsis: accum=r[P3] inverse(r[P2@P5])
|
||||
**
|
||||
** Execute the xInverse function for an aggregate.
|
||||
** The function has P5 arguments. P4 is a pointer to the
|
||||
** FuncDef structure that specifies the function. Register P3 is the
|
||||
** accumulator.
|
||||
**
|
||||
** The P5 arguments are taken from register P2 and its
|
||||
** successors.
|
||||
*/
|
||||
/* Opcode: AggStep1 P1 P2 P3 P4 P5
|
||||
** Synopsis: accum=r[P3] step(r[P2@P5])
|
||||
**
|
||||
** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an
|
||||
@@ -6316,7 +6354,8 @@ case OP_DecrJumpZero: { /* jump, in1 */
|
||||
** sqlite3_context only happens once, instead of on each call to the
|
||||
** step function.
|
||||
*/
|
||||
case OP_AggStep0: {
|
||||
case OP_AggInverse:
|
||||
case OP_AggStep: {
|
||||
int n;
|
||||
sqlite3_context *pCtx;
|
||||
|
||||
@@ -6339,10 +6378,14 @@ case OP_AggStep0: {
|
||||
pCtx->argc = n;
|
||||
pOp->p4type = P4_FUNCCTX;
|
||||
pOp->p4.pCtx = pCtx;
|
||||
pOp->opcode = OP_AggStep;
|
||||
|
||||
/* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */
|
||||
assert( pOp->p1==(pOp->opcode==OP_AggInverse) );
|
||||
|
||||
pOp->opcode = OP_AggStep1;
|
||||
/* Fall through into OP_AggStep */
|
||||
}
|
||||
case OP_AggStep: {
|
||||
case OP_AggStep1: {
|
||||
int i;
|
||||
sqlite3_context *pCtx;
|
||||
Mem *pMem;
|
||||
@@ -6351,6 +6394,17 @@ case OP_AggStep: {
|
||||
pCtx = pOp->p4.pCtx;
|
||||
pMem = &aMem[pOp->p3];
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pOp->p1 ){
|
||||
/* This is an OP_AggInverse call. Verify that xStep has always
|
||||
** been called at least once prior to any xInverse call. */
|
||||
assert( pMem->uTemp==0x1122e0e3 );
|
||||
}else{
|
||||
/* This is an OP_AggStep call. Mark it as such. */
|
||||
pMem->uTemp = 0x1122e0e3;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If this function is inside of a trigger, the register array in aMem[]
|
||||
** might change from one evaluation to the next. The next block of code
|
||||
** checks to see if the register array has changed, and if so it
|
||||
@@ -6399,24 +6453,37 @@ case OP_AggStep: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: AggFinal P1 P2 P3 P4 *
|
||||
/* Opcode: AggFinal P1 P2 * P4 *
|
||||
** Synopsis: accum=r[P1] N=P2
|
||||
**
|
||||
** P1 is the memory location that is the accumulator for an aggregate
|
||||
** or window function. If P3 is zero, then execute the finalizer function
|
||||
** for an aggregate and store the result in P1. Or, if P3 is non-zero,
|
||||
** invoke the xValue() function and store the result in register P3.
|
||||
** or window function. Execute the finalizer function
|
||||
** for an aggregate and store the result in P1.
|
||||
**
|
||||
** P2 is the number of arguments that the step function takes and
|
||||
** P4 is a pointer to the FuncDef for this function. The P2
|
||||
** argument is not used by this opcode. It is only there to disambiguate
|
||||
** functions that can take varying numbers of arguments. The
|
||||
** P4 argument is only needed for the degenerate case where
|
||||
** P4 argument is only needed for the case where
|
||||
** the step function was not previously called.
|
||||
*/
|
||||
/* Opcode: AggValue * P2 P3 P4 *
|
||||
** Synopsis: r[P3]=value N=P2
|
||||
**
|
||||
** Invoke the xValue() function and store the result in register P3.
|
||||
**
|
||||
** P2 is the number of arguments that the step function takes and
|
||||
** P4 is a pointer to the FuncDef for this function. The P2
|
||||
** argument is not used by this opcode. It is only there to disambiguate
|
||||
** functions that can take varying numbers of arguments. The
|
||||
** P4 argument is only needed for the case where
|
||||
** the step function was not previously called.
|
||||
*/
|
||||
case OP_AggValue:
|
||||
case OP_AggFinal: {
|
||||
Mem *pMem;
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
assert( pOp->p3==0 || pOp->opcode==OP_AggValue );
|
||||
pMem = &aMem[pOp->p1];
|
||||
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
@@ -6425,7 +6492,9 @@ case OP_AggFinal: {
|
||||
pMem = &aMem[pOp->p3];
|
||||
}else
|
||||
#endif
|
||||
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
|
||||
{
|
||||
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
|
||||
}
|
||||
|
||||
if( rc ){
|
||||
sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
|
||||
|
||||
+33
-4
@@ -73,7 +73,8 @@ struct VdbeOp {
|
||||
u64 cycles; /* Total time spent executing this instruction */
|
||||
#endif
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
int iSrcLine; /* Source-code line that generated this opcode */
|
||||
u32 iSrcLine; /* Source-code line that generated this opcode
|
||||
** with flags in the upper 8 bits */
|
||||
#endif
|
||||
};
|
||||
typedef struct VdbeOp VdbeOp;
|
||||
@@ -243,7 +244,6 @@ void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3VdbeAssertMayAbort(Vdbe *, int);
|
||||
int sqlite3VdbeAssertAggContext(sqlite3_context*);
|
||||
#endif
|
||||
void sqlite3VdbeResetStepResult(Vdbe*);
|
||||
void sqlite3VdbeRewind(Vdbe*);
|
||||
@@ -318,23 +318,52 @@ int sqlite3NotPureFunc(sqlite3_context*);
|
||||
**
|
||||
** VdbeCoverageNeverTaken(v) // Previous branch is never taken
|
||||
**
|
||||
** VdbeCoverageNeverNull(v) // Previous three-way branch is only
|
||||
** // taken on the first two ways. The
|
||||
** // NULL option is not possible
|
||||
**
|
||||
** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested
|
||||
** // in distingishing equal and not-equal.
|
||||
**
|
||||
** Every VDBE branch operation must be tagged with one of the macros above.
|
||||
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
|
||||
** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch()
|
||||
** routine in vdbe.c, alerting the developer to the missed tag.
|
||||
**
|
||||
** During testing, the test application will invoke
|
||||
** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
|
||||
** routine that is invoked as each bytecode branch is taken. The callback
|
||||
** contains the sqlite3.c source line number ov the VdbeCoverage macro and
|
||||
** flags to indicate whether or not the branch was taken. The test application
|
||||
** is responsible for keeping track of this and reporting byte-code branches
|
||||
** that are never taken.
|
||||
**
|
||||
** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the
|
||||
** vdbe.c source file for additional information.
|
||||
*/
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
void sqlite3VdbeSetLineNumber(Vdbe*,int);
|
||||
# define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__)
|
||||
# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__)
|
||||
# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2);
|
||||
# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1);
|
||||
# define VdbeCoverageAlwaysTaken(v) \
|
||||
sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000);
|
||||
# define VdbeCoverageNeverTaken(v) \
|
||||
sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000);
|
||||
# define VdbeCoverageNeverNull(v) \
|
||||
sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
|
||||
# define VdbeCoverageNeverNullIf(v,x) \
|
||||
if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
|
||||
# define VdbeCoverageEqNe(v) \
|
||||
sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000);
|
||||
# define VDBE_OFFSET_LINENO(x) (__LINE__+x)
|
||||
#else
|
||||
# define VdbeCoverage(v)
|
||||
# define VdbeCoverageIf(v,x)
|
||||
# define VdbeCoverageAlwaysTaken(v)
|
||||
# define VdbeCoverageNeverTaken(v)
|
||||
# define VdbeCoverageNeverNull(v)
|
||||
# define VdbeCoverageNeverNullIf(v,x)
|
||||
# define VdbeCoverageEqNe(v)
|
||||
# define VDBE_OFFSET_LINENO(x) 0
|
||||
#endif
|
||||
|
||||
|
||||
@@ -824,18 +824,6 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is only used within assert() statements to check that the
|
||||
** aggregate context has already been allocated. i.e.:
|
||||
**
|
||||
** assert( sqlite3VdbeAssertAggContext(p) );
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3VdbeAssertAggContext(sqlite3_context *p){
|
||||
return ((p->pMem->flags & MEM_Agg)!=0);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Return the auxiliary data pointer, if any, for the iArg'th argument to
|
||||
** the user-function defined by pCtx.
|
||||
|
||||
@@ -435,6 +435,7 @@ int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.flags = MEM_Null;
|
||||
t.db = pAccum->db;
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
ctx.pOut = pOut;
|
||||
ctx.pMem = pAccum;
|
||||
ctx.pFunc = pFunc;
|
||||
|
||||
+2
-1
@@ -810,7 +810,7 @@ static void constructAutomaticIndex(
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
|
||||
VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
|
||||
}else{
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
|
||||
}
|
||||
@@ -2672,6 +2672,7 @@ static int whereLoopAddBtreeIndex(
|
||||
if( saved_nEq==saved_nSkip
|
||||
&& saved_nEq+1<pProbe->nKeyCol
|
||||
&& pProbe->noSkipScan==0
|
||||
&& OptimizationEnabled(db, SQLITE_SkipScan)
|
||||
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
|
||||
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
|
||||
){
|
||||
|
||||
+2
-2
@@ -150,7 +150,7 @@ int sqlite3WhereExplainOneScan(
|
||||
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
|
||||
sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN");
|
||||
if( pItem->pSelect ){
|
||||
sqlite3_str_appendf(&str, " SUBQUERY 0x%p", pItem->pSelect);
|
||||
sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId);
|
||||
}else{
|
||||
sqlite3_str_appendf(&str, " TABLE %s", pItem->zName);
|
||||
}
|
||||
@@ -1242,7 +1242,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
|
||||
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
|
||||
VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
|
||||
pLevel->op = OP_Goto;
|
||||
}else
|
||||
|
||||
|
||||
+6
-4
@@ -256,11 +256,13 @@ static int isLikeOrGlob(
|
||||
|
||||
/* The optimization is possible only if (1) the pattern does not begin
|
||||
** with a wildcard and if (2) the non-wildcard prefix does not end with
|
||||
** an (illegal 0xff) character. The second condition is necessary so
|
||||
** an (illegal 0xff) character, or (3) the pattern does not consist of
|
||||
** a single escape character. The second condition is necessary so
|
||||
** that we can increment the prefix key to find an upper bound for the
|
||||
** range search.
|
||||
*/
|
||||
if( cnt!=0 && 255!=(u8)z[cnt-1] ){
|
||||
** range search. The third is because the caller assumes that the pattern
|
||||
** consists of at least one character after all escapes have been
|
||||
** removed. */
|
||||
if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
|
||||
Expr *pPrefix;
|
||||
|
||||
/* A "complete" match if the pattern ends with "*" or "%" */
|
||||
|
||||
+304
-170
@@ -151,12 +151,8 @@ static void row_numberStepFunc(
|
||||
){
|
||||
i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( p ) (*p)++;
|
||||
}
|
||||
static void row_numberInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
UNUSED_PARAMETER(nArg);
|
||||
UNUSED_PARAMETER(apArg);
|
||||
}
|
||||
static void row_numberValueFunc(sqlite3_context *pCtx){
|
||||
i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
@@ -187,12 +183,8 @@ static void dense_rankStepFunc(
|
||||
struct CallCount *p;
|
||||
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( p ) p->nStep = 1;
|
||||
}
|
||||
static void dense_rankInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
UNUSED_PARAMETER(nArg);
|
||||
UNUSED_PARAMETER(apArg);
|
||||
}
|
||||
static void dense_rankValueFunc(sqlite3_context *pCtx){
|
||||
struct CallCount *p;
|
||||
@@ -225,12 +217,8 @@ static void rankStepFunc(
|
||||
p->nValue = p->nStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void rankInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
UNUSED_PARAMETER(nArg);
|
||||
UNUSED_PARAMETER(apArg);
|
||||
}
|
||||
static void rankValueFunc(sqlite3_context *pCtx){
|
||||
struct CallCount *p;
|
||||
@@ -253,11 +241,10 @@ static void percent_rankStepFunc(
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
struct CallCount *p;
|
||||
assert( nArg==1 );
|
||||
UNUSED_PARAMETER(nArg); assert( nArg==1 );
|
||||
|
||||
assert( sqlite3VdbeAssertAggContext(pCtx) );
|
||||
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( ALWAYS(p) ){
|
||||
if( p ){
|
||||
if( p->nTotal==0 ){
|
||||
p->nTotal = sqlite3_value_int64(apArg[0]);
|
||||
}
|
||||
@@ -267,12 +254,6 @@ static void percent_rankStepFunc(
|
||||
}
|
||||
}
|
||||
}
|
||||
static void percent_rankInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
}
|
||||
static void percent_rankValueFunc(sqlite3_context *pCtx){
|
||||
struct CallCount *p;
|
||||
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
@@ -299,23 +280,16 @@ static void cume_distStepFunc(
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
struct CallCount *p;
|
||||
assert( nArg==1 );
|
||||
assert( nArg==1 ); UNUSED_PARAMETER(nArg);
|
||||
|
||||
assert( sqlite3VdbeAssertAggContext(pCtx) );
|
||||
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( ALWAYS(p) ){
|
||||
if( p ){
|
||||
if( p->nTotal==0 ){
|
||||
p->nTotal = sqlite3_value_int64(apArg[0]);
|
||||
}
|
||||
p->nStep++;
|
||||
}
|
||||
}
|
||||
static void cume_distInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
}
|
||||
static void cume_distValueFunc(sqlite3_context *pCtx){
|
||||
struct CallCount *p;
|
||||
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
@@ -346,7 +320,7 @@ static void ntileStepFunc(
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
struct NtileCtx *p;
|
||||
assert( nArg==2 );
|
||||
assert( nArg==2 ); UNUSED_PARAMETER(nArg);
|
||||
p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( p ){
|
||||
if( p->nTotal==0 ){
|
||||
@@ -361,12 +335,6 @@ static void ntileStepFunc(
|
||||
p->iRow++;
|
||||
}
|
||||
}
|
||||
static void ntileInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
}
|
||||
static void ntileValueFunc(sqlite3_context *pCtx){
|
||||
struct NtileCtx *p;
|
||||
p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
@@ -407,6 +375,7 @@ static void last_valueStepFunc(
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
struct LastValueCtx *p;
|
||||
UNUSED_PARAMETER(nArg);
|
||||
p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( p ){
|
||||
sqlite3_value_free(p->pVal);
|
||||
@@ -424,6 +393,8 @@ static void last_valueInvFunc(
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
struct LastValueCtx *p;
|
||||
UNUSED_PARAMETER(nArg);
|
||||
UNUSED_PARAMETER(apArg);
|
||||
p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( ALWAYS(p) ){
|
||||
p->nVal--;
|
||||
@@ -451,50 +422,92 @@ static void last_valueFinalizeFunc(sqlite3_context *pCtx){
|
||||
}
|
||||
|
||||
/*
|
||||
** No-op implementations of nth_value(), first_value(), lead() and lag().
|
||||
** These are all implemented inline using VDBE instructions.
|
||||
** Static names for the built-in window function names. These static
|
||||
** names are used, rather than string literals, so that FuncDef objects
|
||||
** can be associated with a particular window function by direct
|
||||
** comparison of the zName pointer. Example:
|
||||
**
|
||||
** if( pFuncDef->zName==row_valueName ){ ... }
|
||||
*/
|
||||
static void nth_valueStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **a){}
|
||||
static void nth_valueInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
|
||||
static void nth_valueValueFunc(sqlite3_context *pCtx){}
|
||||
static void first_valueStepFunc(sqlite3_context *p, int n, sqlite3_value **ap){}
|
||||
static void first_valueInvFunc(sqlite3_context *p, int n, sqlite3_value **ap){}
|
||||
static void first_valueValueFunc(sqlite3_context *pCtx){}
|
||||
static void leadStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
|
||||
static void leadInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
|
||||
static void leadValueFunc(sqlite3_context *pCtx){}
|
||||
static void lagStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
|
||||
static void lagInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
|
||||
static void lagValueFunc(sqlite3_context *pCtx){}
|
||||
static const char row_numberName[] = "row_number";
|
||||
static const char dense_rankName[] = "dense_rank";
|
||||
static const char rankName[] = "rank";
|
||||
static const char percent_rankName[] = "percent_rank";
|
||||
static const char cume_distName[] = "cume_dist";
|
||||
static const char ntileName[] = "ntile";
|
||||
static const char last_valueName[] = "last_value";
|
||||
static const char nth_valueName[] = "nth_value";
|
||||
static const char first_valueName[] = "first_value";
|
||||
static const char leadName[] = "lead";
|
||||
static const char lagName[] = "lag";
|
||||
|
||||
#define WINDOWFUNC(name,nArg,extra) { \
|
||||
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
||||
name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \
|
||||
name ## InvFunc, #name \
|
||||
}
|
||||
/*
|
||||
** No-op implementations of xStep() and xFinalize(). Used as place-holders
|
||||
** for built-in window functions that never call those interfaces.
|
||||
**
|
||||
** The noopValueFunc() is called but is expected to do nothing. The
|
||||
** noopStepFunc() is never called, and so it is marked with NO_TEST to
|
||||
** let the test coverage routine know not to expect this function to be
|
||||
** invoked.
|
||||
*/
|
||||
static void noopStepFunc( /*NO_TEST*/
|
||||
sqlite3_context *p, /*NO_TEST*/
|
||||
int n, /*NO_TEST*/
|
||||
sqlite3_value **a /*NO_TEST*/
|
||||
){ /*NO_TEST*/
|
||||
UNUSED_PARAMETER(p); /*NO_TEST*/
|
||||
UNUSED_PARAMETER(n); /*NO_TEST*/
|
||||
UNUSED_PARAMETER(a); /*NO_TEST*/
|
||||
assert(0); /*NO_TEST*/
|
||||
} /*NO_TEST*/
|
||||
static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ }
|
||||
|
||||
#define WINDOWFUNCF(name,nArg,extra) { \
|
||||
/* Window functions that use all window interfaces: xStep, xFinal,
|
||||
** xValue, and xInverse */
|
||||
#define WINDOWFUNCALL(name,nArg,extra) { \
|
||||
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
||||
name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \
|
||||
name ## InvFunc, #name \
|
||||
name ## InvFunc, name ## Name, {0} \
|
||||
}
|
||||
|
||||
/* Window functions that are implemented using bytecode and thus have
|
||||
** no-op routines for their methods */
|
||||
#define WINDOWFUNCNOOP(name,nArg,extra) { \
|
||||
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
||||
noopStepFunc, noopValueFunc, noopValueFunc, \
|
||||
noopStepFunc, name ## Name, {0} \
|
||||
}
|
||||
|
||||
/* Window functions that use all window interfaces: xStep, the
|
||||
** same routine for xFinalize and xValue and which never call
|
||||
** xInverse. */
|
||||
#define WINDOWFUNCX(name,nArg,extra) { \
|
||||
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
||||
name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \
|
||||
noopStepFunc, name ## Name, {0} \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Register those built-in window functions that are not also aggregates.
|
||||
*/
|
||||
void sqlite3WindowFunctions(void){
|
||||
static FuncDef aWindowFuncs[] = {
|
||||
WINDOWFUNC(row_number, 0, 0),
|
||||
WINDOWFUNC(dense_rank, 0, 0),
|
||||
WINDOWFUNC(rank, 0, 0),
|
||||
WINDOWFUNC(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE),
|
||||
WINDOWFUNC(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE),
|
||||
WINDOWFUNC(ntile, 1, SQLITE_FUNC_WINDOW_SIZE),
|
||||
WINDOWFUNCF(last_value, 1, 0),
|
||||
WINDOWFUNC(nth_value, 2, 0),
|
||||
WINDOWFUNC(first_value, 1, 0),
|
||||
WINDOWFUNC(lead, 1, 0), WINDOWFUNC(lead, 2, 0), WINDOWFUNC(lead, 3, 0),
|
||||
WINDOWFUNC(lag, 1, 0), WINDOWFUNC(lag, 2, 0), WINDOWFUNC(lag, 3, 0),
|
||||
WINDOWFUNCX(row_number, 0, 0),
|
||||
WINDOWFUNCX(dense_rank, 0, 0),
|
||||
WINDOWFUNCX(rank, 0, 0),
|
||||
WINDOWFUNCX(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE),
|
||||
WINDOWFUNCX(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE),
|
||||
WINDOWFUNCX(ntile, 1, SQLITE_FUNC_WINDOW_SIZE),
|
||||
WINDOWFUNCALL(last_value, 1, 0),
|
||||
WINDOWFUNCNOOP(nth_value, 2, 0),
|
||||
WINDOWFUNCNOOP(first_value, 1, 0),
|
||||
WINDOWFUNCNOOP(lead, 1, 0),
|
||||
WINDOWFUNCNOOP(lead, 2, 0),
|
||||
WINDOWFUNCNOOP(lead, 3, 0),
|
||||
WINDOWFUNCNOOP(lag, 1, 0),
|
||||
WINDOWFUNCNOOP(lag, 2, 0),
|
||||
WINDOWFUNCNOOP(lag, 3, 0),
|
||||
};
|
||||
sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs));
|
||||
}
|
||||
@@ -546,7 +559,7 @@ void sqlite3WindowUpdate(
|
||||
"FILTER clause may only be used with aggregate window functions"
|
||||
);
|
||||
}else
|
||||
if( pFunc->xSFunc==row_numberStepFunc || pFunc->xSFunc==ntileStepFunc ){
|
||||
if( pFunc->zName==row_numberName || pFunc->zName==ntileName ){
|
||||
sqlite3ExprDelete(db, pWin->pStart);
|
||||
sqlite3ExprDelete(db, pWin->pEnd);
|
||||
pWin->pStart = pWin->pEnd = 0;
|
||||
@@ -555,8 +568,8 @@ void sqlite3WindowUpdate(
|
||||
pWin->eEnd = TK_CURRENT;
|
||||
}else
|
||||
|
||||
if( pFunc->xSFunc==dense_rankStepFunc || pFunc->xSFunc==rankStepFunc
|
||||
|| pFunc->xSFunc==percent_rankStepFunc || pFunc->xSFunc==cume_distStepFunc
|
||||
if( pFunc->zName==dense_rankName || pFunc->zName==rankName
|
||||
|| pFunc->zName==percent_rankName || pFunc->zName==cume_distName
|
||||
){
|
||||
sqlite3ExprDelete(db, pWin->pStart);
|
||||
sqlite3ExprDelete(db, pWin->pEnd);
|
||||
@@ -576,7 +589,9 @@ void sqlite3WindowUpdate(
|
||||
typedef struct WindowRewrite WindowRewrite;
|
||||
struct WindowRewrite {
|
||||
Window *pWin;
|
||||
SrcList *pSrc;
|
||||
ExprList *pSub;
|
||||
Select *pSubSelect; /* Current sub-select, if any */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -588,6 +603,24 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
struct WindowRewrite *p = pWalker->u.pRewrite;
|
||||
Parse *pParse = pWalker->pParse;
|
||||
|
||||
/* If this function is being called from within a scalar sub-select
|
||||
** that used by the SELECT statement being processed, only process
|
||||
** TK_COLUMN expressions that refer to it (the outer SELECT). Do
|
||||
** not process aggregates or window functions at all, as they belong
|
||||
** to the scalar sub-select. */
|
||||
if( p->pSubSelect ){
|
||||
if( pExpr->op!=TK_COLUMN ){
|
||||
return WRC_Continue;
|
||||
}else{
|
||||
int nSrc = p->pSrc->nSrc;
|
||||
int i;
|
||||
for(i=0; i<nSrc; i++){
|
||||
if( pExpr->iTable==p->pSrc->a[i].iCursor ) break;
|
||||
}
|
||||
if( i==nSrc ) return WRC_Continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch( pExpr->op ){
|
||||
|
||||
case TK_FUNCTION:
|
||||
@@ -630,6 +663,15 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Continue;
|
||||
}
|
||||
static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
|
||||
struct WindowRewrite *p = pWalker->u.pRewrite;
|
||||
Select *pSave = p->pSubSelect;
|
||||
if( pSave==pSelect ){
|
||||
return WRC_Continue;
|
||||
}else{
|
||||
p->pSubSelect = pSelect;
|
||||
sqlite3WalkSelect(pWalker, pSelect);
|
||||
p->pSubSelect = pSave;
|
||||
}
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
@@ -640,7 +682,7 @@ static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
|
||||
** * TK_COLUMN,
|
||||
** * aggregate function, or
|
||||
** * window function with a Window object that is not a member of the
|
||||
** linked list passed as the second argument (pWin)
|
||||
** Window list passed as the second argument (pWin).
|
||||
**
|
||||
** Append the node to output expression-list (*ppSub). And replace it
|
||||
** with a TK_COLUMN that reads the (N-1)th element of table
|
||||
@@ -650,6 +692,7 @@ static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
|
||||
static void selectWindowRewriteEList(
|
||||
Parse *pParse,
|
||||
Window *pWin,
|
||||
SrcList *pSrc,
|
||||
ExprList *pEList, /* Rewrite expressions in this list */
|
||||
ExprList **ppSub /* IN/OUT: Sub-select expression-list */
|
||||
){
|
||||
@@ -661,6 +704,7 @@ static void selectWindowRewriteEList(
|
||||
|
||||
sRewrite.pSub = *ppSub;
|
||||
sRewrite.pWin = pWin;
|
||||
sRewrite.pSrc = pSrc;
|
||||
|
||||
sWalker.pParse = pParse;
|
||||
sWalker.xExprCallback = selectWindowRewriteExprCb;
|
||||
@@ -738,8 +782,8 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
** many columns the table will have. */
|
||||
pMWin->iEphCsr = pParse->nTab++;
|
||||
|
||||
selectWindowRewriteEList(pParse, pMWin, p->pEList, &pSublist);
|
||||
selectWindowRewriteEList(pParse, pMWin, p->pOrderBy, &pSublist);
|
||||
selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist);
|
||||
selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist);
|
||||
pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0);
|
||||
|
||||
/* Append the PARTITION BY and ORDER BY expressions to the to the
|
||||
@@ -829,29 +873,85 @@ void sqlite3WindowListDelete(sqlite3 *db, Window *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate and return a new Window object.
|
||||
** The argument expression is an PRECEDING or FOLLOWING offset. The
|
||||
** value should be a non-negative integer. If the value is not a
|
||||
** constant, change it to NULL. The fact that it is then a non-negative
|
||||
** integer will be caught later. But it is important not to leave
|
||||
** variable values in the expression tree.
|
||||
*/
|
||||
static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
|
||||
if( 0==sqlite3ExprIsConstant(pExpr) ){
|
||||
sqlite3ExprDelete(pParse->db, pExpr);
|
||||
pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate and return a new Window object describing a Window Definition.
|
||||
*/
|
||||
Window *sqlite3WindowAlloc(
|
||||
Parse *pParse,
|
||||
int eType,
|
||||
int eStart, Expr *pStart,
|
||||
int eEnd, Expr *pEnd
|
||||
Parse *pParse, /* Parsing context */
|
||||
int eType, /* Frame type. TK_RANGE or TK_ROWS */
|
||||
int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */
|
||||
Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */
|
||||
int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */
|
||||
Expr *pEnd /* End window size if TK_FOLLOWING or PRECEDING */
|
||||
){
|
||||
Window *pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
||||
Window *pWin = 0;
|
||||
|
||||
if( pWin ){
|
||||
assert( eType );
|
||||
pWin->eType = eType;
|
||||
pWin->eStart = eStart;
|
||||
pWin->eEnd = eEnd;
|
||||
pWin->pEnd = pEnd;
|
||||
pWin->pStart = pStart;
|
||||
}else{
|
||||
sqlite3ExprDelete(pParse->db, pEnd);
|
||||
sqlite3ExprDelete(pParse->db, pStart);
|
||||
/* Parser assures the following: */
|
||||
assert( eType==TK_RANGE || eType==TK_ROWS );
|
||||
assert( eStart==TK_CURRENT || eStart==TK_PRECEDING
|
||||
|| eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING );
|
||||
assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING
|
||||
|| eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING );
|
||||
assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) );
|
||||
assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) );
|
||||
|
||||
|
||||
/* If a frame is declared "RANGE" (not "ROWS"), then it may not use
|
||||
** either "<expr> PRECEDING" or "<expr> FOLLOWING".
|
||||
*/
|
||||
if( eType==TK_RANGE && (pStart!=0 || pEnd!=0) ){
|
||||
sqlite3ErrorMsg(pParse, "RANGE must use only UNBOUNDED or CURRENT ROW");
|
||||
goto windowAllocErr;
|
||||
}
|
||||
|
||||
/* Additionally, the
|
||||
** starting boundary type may not occur earlier in the following list than
|
||||
** the ending boundary type:
|
||||
**
|
||||
** UNBOUNDED PRECEDING
|
||||
** <expr> PRECEDING
|
||||
** CURRENT ROW
|
||||
** <expr> FOLLOWING
|
||||
** UNBOUNDED FOLLOWING
|
||||
**
|
||||
** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending
|
||||
** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting
|
||||
** frame boundary.
|
||||
*/
|
||||
if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING)
|
||||
|| (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT))
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "unsupported frame delimiter for ROWS");
|
||||
goto windowAllocErr;
|
||||
}
|
||||
|
||||
pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
||||
if( pWin==0 ) goto windowAllocErr;
|
||||
pWin->eType = eType;
|
||||
pWin->eStart = eStart;
|
||||
pWin->eEnd = eEnd;
|
||||
pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd);
|
||||
pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart);
|
||||
return pWin;
|
||||
|
||||
windowAllocErr:
|
||||
sqlite3ExprDelete(pParse->db, pEnd);
|
||||
sqlite3ExprDelete(pParse->db, pStart);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -859,8 +959,14 @@ Window *sqlite3WindowAlloc(
|
||||
*/
|
||||
void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
|
||||
if( p ){
|
||||
p->pWin = pWin;
|
||||
if( pWin ) pWin->pOwner = p;
|
||||
if( pWin ){
|
||||
p->pWin = pWin;
|
||||
pWin->pOwner = p;
|
||||
if( p->flags & EP_Distinct ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"DISTINCT is not supported for window functions");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3WindowDelete(pParse->db, pWin);
|
||||
}
|
||||
@@ -921,7 +1027,7 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
|
||||
sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
|
||||
}
|
||||
else if( p->xSFunc==nth_valueStepFunc || p->xSFunc==first_valueStepFunc ){
|
||||
else if( p->zName==nth_valueName || p->zName==first_valueName ){
|
||||
/* Allocate two registers at pWin->regApp. These will be used to
|
||||
** store the start and end index of the current frame. */
|
||||
assert( pMWin->iEphCsr );
|
||||
@@ -930,7 +1036,7 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
|
||||
pParse->nMem += 2;
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr);
|
||||
}
|
||||
else if( p->xSFunc==leadStepFunc || p->xSFunc==lagStepFunc ){
|
||||
else if( p->zName==leadName || p->zName==lagName ){
|
||||
assert( pMWin->iEphCsr );
|
||||
pWin->csrApp = pParse->nTab++;
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr);
|
||||
@@ -939,24 +1045,33 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
|
||||
}
|
||||
|
||||
/*
|
||||
** A "PRECEDING <expr>" (bEnd==0) or "FOLLOWING <expr>" (bEnd==1) has just
|
||||
** been evaluated and the result left in register reg. This function generates
|
||||
** VM code to check that the value is a non-negative integer and throws
|
||||
** an exception if it is not.
|
||||
** A "PRECEDING <expr>" (eCond==0) or "FOLLOWING <expr>" (eCond==1) or the
|
||||
** value of the second argument to nth_value() (eCond==2) has just been
|
||||
** evaluated and the result left in register reg. This function generates VM
|
||||
** code to check that the value is a non-negative integer and throws an
|
||||
** exception if it is not.
|
||||
*/
|
||||
static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){
|
||||
static void windowCheckIntValue(Parse *pParse, int reg, int eCond){
|
||||
static const char *azErr[] = {
|
||||
"frame starting offset must be a non-negative integer",
|
||||
"frame ending offset must be a non-negative integer"
|
||||
"frame ending offset must be a non-negative integer",
|
||||
"second argument to nth_value must be a positive integer"
|
||||
};
|
||||
static int aOp[] = { OP_Ge, OP_Ge, OP_Gt };
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int regZero = sqlite3GetTempReg(pParse);
|
||||
assert( eCond==0 || eCond==1 || eCond==2 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero);
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3VdbeAddOp3(v, OP_Ge, regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageIf(v, eCond==0);
|
||||
VdbeCoverageIf(v, eCond==1);
|
||||
VdbeCoverageIf(v, eCond==2);
|
||||
sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
|
||||
VdbeCoverageNeverNullIf(v, eCond==0);
|
||||
VdbeCoverageNeverNullIf(v, eCond==1);
|
||||
VdbeCoverageNeverNullIf(v, eCond==2);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
|
||||
sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
|
||||
sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC);
|
||||
sqlite3ReleaseTempReg(pParse, regZero);
|
||||
}
|
||||
|
||||
@@ -980,7 +1095,7 @@ static int windowArgCount(Window *pWin){
|
||||
** the first register in an array of registers guaranteed to be large
|
||||
** enough to hold the array of arguments for each function. In this case
|
||||
** the arguments are extracted from the current row of csr into the
|
||||
** array of registers before invoking OP_AggStep.
|
||||
** array of registers before invoking OP_AggStep or OP_AggInverse
|
||||
**
|
||||
** Or, if csr is less than zero, then the array of registers at reg is
|
||||
** already populated with all columns from the current row of the sub-query.
|
||||
@@ -1025,6 +1140,8 @@ static void windowAggStep(
|
||||
if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
||||
&& pWin->eStart!=TK_UNBOUNDED
|
||||
){
|
||||
int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg);
|
||||
VdbeCoverage(v);
|
||||
if( bInverse==0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp);
|
||||
@@ -1032,25 +1149,27 @@ static void windowAggStep(
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageNeverTaken(v);
|
||||
sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp);
|
||||
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addrIsNull);
|
||||
}else if( pWin->regApp ){
|
||||
assert( pWin->pFunc->xSFunc==nth_valueStepFunc
|
||||
|| pWin->pFunc->xSFunc==first_valueStepFunc
|
||||
assert( pWin->pFunc->zName==nth_valueName
|
||||
|| pWin->pFunc->zName==first_valueName
|
||||
);
|
||||
assert( bInverse==0 || bInverse==1 );
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
|
||||
}else if( pWin->pFunc->xSFunc==leadStepFunc
|
||||
|| pWin->pFunc->xSFunc==lagStepFunc
|
||||
}else if( pWin->pFunc->zName==leadName
|
||||
|| pWin->pFunc->zName==lagName
|
||||
){
|
||||
/* no-op */
|
||||
}else{
|
||||
int addrIf = 0;
|
||||
if( pWin->pFilter ){
|
||||
int regTmp;
|
||||
assert( nArg==pWin->pOwner->x.pList->nExpr );
|
||||
assert( nArg==0 || nArg==pWin->pOwner->x.pList->nExpr );
|
||||
assert( nArg || pWin->pOwner->x.pList==0 );
|
||||
if( csr>0 ){
|
||||
regTmp = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
|
||||
@@ -1065,10 +1184,12 @@ static void windowAggStep(
|
||||
}
|
||||
if( pWin->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
||||
CollSeq *pColl;
|
||||
assert( nArg>0 );
|
||||
pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr);
|
||||
sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_AggStep0, bInverse, regArg, pWin->regAccum);
|
||||
sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep,
|
||||
bInverse, regArg, pWin->regAccum);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)nArg);
|
||||
if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
|
||||
@@ -1100,16 +1221,15 @@ static void windowAggFinal(Parse *pParse, Window *pMWin, int bFinal){
|
||||
}
|
||||
}else if( pWin->regApp ){
|
||||
}else{
|
||||
if( bFinal==0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin));
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
if( bFinal ){
|
||||
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin));
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
|
||||
}else{
|
||||
sqlite3VdbeChangeP3(v, -1, pWin->regResult);
|
||||
sqlite3VdbeAddOp3(v, OP_AggValue, pWin->regAccum, windowArgCount(pWin),
|
||||
pWin->regResult);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1141,8 +1261,8 @@ static void windowPartitionCache(
|
||||
*pRegSize = regRowid;
|
||||
pParse->nMem += nSub + 2;
|
||||
|
||||
/* Martial the row returned by the sub-select into an array of
|
||||
** registers. */
|
||||
/* Load the column values for the row returned by the sub-select
|
||||
** into an array of registers starting at reg. */
|
||||
for(k=0; k<nSub; k++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
|
||||
}
|
||||
@@ -1160,9 +1280,10 @@ static void windowPartitionCache(
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
|
||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||
sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageEqNe(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart);
|
||||
VdbeComment((v, "call flush_partition"));
|
||||
}
|
||||
|
||||
/* Buffer the current row in the ephemeral table. */
|
||||
@@ -1174,6 +1295,7 @@ static void windowPartitionCache(
|
||||
|
||||
/* Invoke "flush_partition" to deal with the final (or only) partition */
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart);
|
||||
VdbeComment((v, "call flush_partition"));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1199,29 +1321,30 @@ static void windowReturnOneRow(
|
||||
Window *pWin;
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
FuncDef *pFunc = pWin->pFunc;
|
||||
if( pFunc->xSFunc==nth_valueStepFunc
|
||||
|| pFunc->xSFunc==first_valueStepFunc
|
||||
if( pFunc->zName==nth_valueName
|
||||
|| pFunc->zName==first_valueName
|
||||
){
|
||||
int csr = pWin->csrApp;
|
||||
int lbl = sqlite3VdbeMakeLabel(v);
|
||||
int tmpReg = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
||||
|
||||
if( pFunc->xSFunc==nth_valueStepFunc ){
|
||||
if( pFunc->zName==nth_valueName ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg);
|
||||
windowCheckIntValue(pParse, tmpReg, 2);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg);
|
||||
sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageNeverNull(v);
|
||||
sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg);
|
||||
VdbeCoverageNeverTaken(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult);
|
||||
sqlite3VdbeResolveLabel(v, lbl);
|
||||
sqlite3ReleaseTempReg(pParse, tmpReg);
|
||||
}
|
||||
else if( pFunc->xSFunc==leadStepFunc || pFunc->xSFunc==lagStepFunc ){
|
||||
else if( pFunc->zName==leadName || pFunc->zName==lagName ){
|
||||
int nArg = pWin->pOwner->x.pList->nExpr;
|
||||
int iEph = pMWin->iEphCsr;
|
||||
int csr = pWin->csrApp;
|
||||
@@ -1235,10 +1358,10 @@ static void windowReturnOneRow(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg);
|
||||
if( nArg<2 ){
|
||||
int val = (pFunc->xSFunc==leadStepFunc ? 1 : -1);
|
||||
int val = (pFunc->zName==leadName ? 1 : -1);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val);
|
||||
}else{
|
||||
int op = (pFunc->xSFunc==leadStepFunc ? OP_Add : OP_Subtract);
|
||||
int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract);
|
||||
int tmpReg2 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2);
|
||||
sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg);
|
||||
@@ -1265,7 +1388,7 @@ static void windowReturnOneRow(
|
||||
** regCtr--;
|
||||
** windowReturnOneRow()
|
||||
** if( bInverse ){
|
||||
** AggStep (xInverse)
|
||||
** AggInverse
|
||||
** }
|
||||
** Next (Window.iEphCsr)
|
||||
** }
|
||||
@@ -1309,8 +1432,8 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
||||
FuncDef *pFunc = pWin->pFunc;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
|
||||
nArg = MAX(nArg, windowArgCount(pWin));
|
||||
if( pFunc->xSFunc==nth_valueStepFunc
|
||||
|| pFunc->xSFunc==first_valueStepFunc
|
||||
if( pFunc->zName==nth_valueName
|
||||
|| pFunc->zName==first_valueName
|
||||
){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
|
||||
@@ -1359,7 +1482,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
||||
** Gosub addrGosub
|
||||
** Next(csr) // if EOF goto flush_partition_done
|
||||
** if( (regStart--)<=0 ){
|
||||
** AggStep (csrStart, xInverse)
|
||||
** AggInverse (csrStart)
|
||||
** Next(csrStart)
|
||||
** }
|
||||
** }
|
||||
@@ -1387,7 +1510,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
||||
** Gosub addrGosub
|
||||
** Next(csr) // if EOF goto flush_partition_done
|
||||
** if( (regStart--)<=0 ){
|
||||
** AggStep (csrStart, xInverse)
|
||||
** AggInverse (csrStart)
|
||||
** Next(csrStart)
|
||||
** }
|
||||
** }
|
||||
@@ -1410,7 +1533,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
||||
** if( new peer ) break;
|
||||
** }
|
||||
** while( (regPeer--)>0 ){
|
||||
** AggStep (csrStart, xInverse)
|
||||
** AggInverse (csrStart)
|
||||
** Next(csrStart)
|
||||
** }
|
||||
** }
|
||||
@@ -1427,7 +1550,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
||||
** Gosub addrGosub
|
||||
** Next(csr) // if EOF goto flush_partition_done
|
||||
** }
|
||||
** AggStep (csrStart, xInverse)
|
||||
** AggInverse (csrStart)
|
||||
** Next (csrStart)
|
||||
** }
|
||||
**
|
||||
@@ -1443,7 +1566,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
||||
** Gosub addrGosub
|
||||
** Next(csr) // if EOF goto flush_partition_done
|
||||
** if( (regStart--)<=0 ){
|
||||
** AggStep (csr2, xInverse)
|
||||
** AggInverse (csr2)
|
||||
** Next (csr2)
|
||||
** }
|
||||
**
|
||||
@@ -1469,8 +1592,8 @@ static void windowCodeRowExprStep(
|
||||
int regEnd; /* Value of <expr> FOLLOWING */
|
||||
int addrGoto;
|
||||
int addrTop;
|
||||
int addrIfPos1;
|
||||
int addrIfPos2;
|
||||
int addrIfPos1 = 0;
|
||||
int addrIfPos2 = 0;
|
||||
int regSize = 0;
|
||||
|
||||
assert( pMWin->eStart==TK_PRECEDING
|
||||
@@ -1500,6 +1623,7 @@ static void windowCodeRowExprStep(
|
||||
sqlite3VdbeResolveLabel(v, lblFlushPart);
|
||||
sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "Flush_partition subroutine"));
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr);
|
||||
|
||||
@@ -1507,11 +1631,11 @@ static void windowCodeRowExprStep(
|
||||
** an exception. */
|
||||
if( pMWin->pStart ){
|
||||
sqlite3ExprCode(pParse, pMWin->pStart, regStart);
|
||||
windowCheckFrameValue(pParse, regStart, 0);
|
||||
windowCheckIntValue(pParse, regStart, 0);
|
||||
}
|
||||
if( pMWin->pEnd ){
|
||||
sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
|
||||
windowCheckFrameValue(pParse, regEnd, 1);
|
||||
windowCheckIntValue(pParse, regEnd, 1);
|
||||
}
|
||||
|
||||
/* If this is "ROWS <expr1> FOLLOWING AND ROWS <expr2> FOLLOWING", do:
|
||||
@@ -1522,18 +1646,20 @@ static void windowCodeRowExprStep(
|
||||
** }
|
||||
** regEnd = regEnd - regStart;
|
||||
*/
|
||||
if( pMWin->pEnd && pMWin->pStart && pMWin->eStart==TK_FOLLOWING ){
|
||||
if( pMWin->pEnd && pMWin->eStart==TK_FOLLOWING ){
|
||||
assert( pMWin->pStart!=0 );
|
||||
assert( pMWin->eEnd==TK_FOLLOWING );
|
||||
sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageNeverNull(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
|
||||
sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd);
|
||||
}
|
||||
|
||||
if( pMWin->pEnd && pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){
|
||||
if( pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){
|
||||
assert( pMWin->pEnd!=0 );
|
||||
assert( pMWin->eStart==TK_PRECEDING );
|
||||
sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageNeverNull(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd);
|
||||
}
|
||||
@@ -1594,17 +1720,21 @@ static void windowCodeRowExprStep(
|
||||
|| pMWin->eStart==TK_PRECEDING
|
||||
|| pMWin->eStart==TK_FOLLOWING
|
||||
){
|
||||
int addrJumpHere = 0;
|
||||
int lblSkipInverse = sqlite3VdbeMakeLabel(v);;
|
||||
if( pMWin->eStart==TK_PRECEDING ){
|
||||
addrJumpHere = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0 , 1);
|
||||
sqlite3VdbeAddOp3(v, OP_IfPos, regStart, lblSkipInverse, 1);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
|
||||
VdbeCoverage(v);
|
||||
windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize);
|
||||
if( addrJumpHere ){
|
||||
sqlite3VdbeJumpHere(v, addrJumpHere);
|
||||
if( pMWin->eStart==TK_FOLLOWING ){
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, lblSkipInverse);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
|
||||
VdbeCoverageAlwaysTaken(v);
|
||||
}
|
||||
windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize);
|
||||
sqlite3VdbeResolveLabel(v, lblSkipInverse);
|
||||
}
|
||||
if( pMWin->eEnd==TK_FOLLOWING ){
|
||||
sqlite3VdbeJumpHere(v, addrIfPos1);
|
||||
@@ -1615,6 +1745,7 @@ static void windowCodeRowExprStep(
|
||||
sqlite3VdbeResolveLabel(v, lblFlushDone);
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
|
||||
VdbeComment((v, "end flush_partition subroutine"));
|
||||
|
||||
/* Jump to here to skip over flush_partition */
|
||||
sqlite3VdbeJumpHere(v, addrGoto);
|
||||
@@ -1670,7 +1801,7 @@ static void windowCodeRowExprStep(
|
||||
**
|
||||
** for(i=0; i<ctr; i++){
|
||||
** Gosub addrGosub
|
||||
** AggStep (xInverse, iEphCsr)
|
||||
** AggInverse (iEphCsr)
|
||||
** Next iEphCsr
|
||||
** }
|
||||
**
|
||||
@@ -1703,7 +1834,7 @@ static void windowCodeRowExprStep(
|
||||
** AggFinal (xValue)
|
||||
** for(i=0; i<ctr; i++){
|
||||
** Gosub addrGosub
|
||||
** AggStep (xInverse, iEphCsr)
|
||||
** AggInverse (iEphCsr)
|
||||
** Next iEphCsr
|
||||
** }
|
||||
** Integer ctr 0
|
||||
@@ -1784,9 +1915,9 @@ static void windowCodeCacheStep(
|
||||
VdbeCoverageNeverTaken(v);
|
||||
|
||||
if( bReverse ){
|
||||
int addr = sqlite3VdbeCurrentAddr(v);
|
||||
int addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csrLead, addr);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csrLead, addr2);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty);
|
||||
VdbeCoverageNeverTaken(v);
|
||||
@@ -1903,8 +2034,8 @@ static void windowCodeDefaultStep(
|
||||
|
||||
pParse->nMem += nSub + 2;
|
||||
|
||||
/* Martial the row returned by the sub-select into an array of
|
||||
** registers. */
|
||||
/* Load the individual column values of the row returned by
|
||||
** the sub-select into an array of registers. */
|
||||
for(k=0; k<nSub; k++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
|
||||
}
|
||||
@@ -1922,7 +2053,7 @@ static void windowCodeDefaultStep(
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
|
||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageEqNe(v);
|
||||
windowAggFinal(pParse, pMWin, 1);
|
||||
if( pOrderBy ){
|
||||
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
@@ -2081,6 +2212,7 @@ void sqlite3WindowCodeStep(
|
||||
if( pMWin->eType==TK_ROWS
|
||||
&& (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy)
|
||||
){
|
||||
VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()"));
|
||||
windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
|
||||
}else{
|
||||
Window *pWin;
|
||||
@@ -2092,10 +2224,10 @@ void sqlite3WindowCodeStep(
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
FuncDef *pFunc = pWin->pFunc;
|
||||
if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)
|
||||
|| (pFunc->xSFunc==nth_valueStepFunc)
|
||||
|| (pFunc->xSFunc==first_valueStepFunc)
|
||||
|| (pFunc->xSFunc==leadStepFunc)
|
||||
|| (pFunc->xSFunc==lagStepFunc)
|
||||
|| (pFunc->zName==nth_valueName)
|
||||
|| (pFunc->zName==first_valueName)
|
||||
|| (pFunc->zName==leadName)
|
||||
|| (pFunc->zName==lagName)
|
||||
){
|
||||
bCache = 1;
|
||||
break;
|
||||
@@ -2105,8 +2237,10 @@ void sqlite3WindowCodeStep(
|
||||
|
||||
/* Otherwise, call windowCodeDefaultStep(). */
|
||||
if( bCache ){
|
||||
VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()"));
|
||||
windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub);
|
||||
}else{
|
||||
VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()"));
|
||||
windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# 2018-07-15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing that if an IO error is encountered
|
||||
# as part of an atomic F2FS commit, an attempt is made to commit the
|
||||
# transaction using a legacy journal commit.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set ::testprefix atomic2
|
||||
|
||||
db close
|
||||
if {[atomic_batch_write test.db]==0} {
|
||||
puts "No f2fs atomic-batch-write support. Skipping tests..."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
reset_db
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE INDEX i1x ON t1(x);
|
||||
CREATE INDEX i2x ON t1(y);
|
||||
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 )
|
||||
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s;
|
||||
}
|
||||
|
||||
set setup [list \
|
||||
-injectstart at_injectstart \
|
||||
-injectstop at_injectstop \
|
||||
]
|
||||
|
||||
set ::at_fail 0
|
||||
set ::at_nfail 0
|
||||
|
||||
proc at_injectstart {iFail} {
|
||||
set ::at_fail $iFail
|
||||
set ::at_nfail 0
|
||||
}
|
||||
proc at_injectstop {} {
|
||||
set ::at_fail 0
|
||||
return $::at_nfail
|
||||
}
|
||||
|
||||
proc at_vfs_callback {method file z args} {
|
||||
if {$::at_fail>0} {
|
||||
incr ::at_fail -1
|
||||
if {$::at_fail==0} {
|
||||
incr ::at_nfail
|
||||
return SQLITE_IOERR
|
||||
} elseif {$method=="xFileControl" && $z=="COMMIT_ATOMIC_WRITE"} {
|
||||
set ::at_fail 0
|
||||
}
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
testvfs tvfs -default 1
|
||||
tvfs script at_vfs_callback
|
||||
tvfs filter {xFileControl xWrite}
|
||||
|
||||
faultsim_save_and_close
|
||||
|
||||
do_one_faultsim_test 2.0 {*}$setup -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 )
|
||||
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
|
||||
set res [execsql {SELECT count(*) FROM t1; PRAGMA integrity_check}]
|
||||
if {$res!="200 ok"} {
|
||||
error "expected {200 ok}, got $res"
|
||||
}
|
||||
}
|
||||
|
||||
db close
|
||||
tvfs delete
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,87 @@
|
||||
# 2018-07-18
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test case for SQLITE_FCNTL_DATA_VERSION
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Construct a database and get its initial data version
|
||||
sqlite3 db test.db
|
||||
do_test dataversion1-100 {
|
||||
db eval {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1(x) VALUES(99);
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {99}
|
||||
set dv1 [file_control_data_version db main]
|
||||
|
||||
# The data version does not change by ATTACH or by changes to
|
||||
# other schemas within the same connection.
|
||||
#
|
||||
do_test dataversion1-101 {
|
||||
db eval {
|
||||
ATTACH ':memory:' AS aux1;
|
||||
CREATE TABLE aux1.t2(y);
|
||||
CREATE TEMP TABLE t3(z);
|
||||
}
|
||||
file_control_data_version db main
|
||||
} $dv1
|
||||
|
||||
# The data version does change when SQL modifies the table
|
||||
do_test dataversion1-110 {
|
||||
db eval {
|
||||
UPDATE t1 SET x=x+1;
|
||||
}
|
||||
set dv2 [file_control_data_version db]
|
||||
expr {$::dv1==$dv2}
|
||||
} {0}
|
||||
|
||||
# But the data version is constant if there are changes to other
|
||||
# schemas
|
||||
set dv1 [file_control_data_version db main]
|
||||
do_test dataversion1-120 {
|
||||
db eval {
|
||||
UPDATE t2 SET y=y+1;
|
||||
}
|
||||
file_control_data_version db
|
||||
} $dv1
|
||||
|
||||
# Changes to the database via another connection are not detected
|
||||
# until there is a read transaction.
|
||||
#
|
||||
sqlite3 db2 test.db
|
||||
do_test dataversion1-130 {
|
||||
db2 eval {
|
||||
SELECT * FROM t1
|
||||
}
|
||||
} {100}
|
||||
do_test dataversion1-131 {
|
||||
file_control_data_version db
|
||||
} $dv1
|
||||
do_test dataversion1-132 {
|
||||
db2 eval {
|
||||
UPDATE t1 SET x=x+1;
|
||||
}
|
||||
set dv2 [file_control_data_version db]
|
||||
expr {$::dv1==$dv2}
|
||||
} {1}
|
||||
do_test dataversion1-133 {
|
||||
db eval {SELECT * FROM t1}
|
||||
set dv2 [file_control_data_version db]
|
||||
expr {$::dv1==$dv2}
|
||||
} {0}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -75,4 +75,24 @@ do_execsql_test json103-300 {
|
||||
FROM t1;
|
||||
} {{[1,"abc"]} {[{"x":1},{"x":"abc"}]}}
|
||||
|
||||
# json_group_array() and json_group_object() work as window functions.
|
||||
#
|
||||
ifcapable windowfunc {
|
||||
do_execsql_test json103-400 {
|
||||
CREATE TABLE t4(x);
|
||||
INSERT INTO t4 VALUES
|
||||
(1),
|
||||
('a,b'),
|
||||
(3),
|
||||
('x"y'),
|
||||
(5),
|
||||
(6),
|
||||
(7);
|
||||
SELECT json_group_array(x) OVER (ROWS 2 PRECEDING) FROM t4;
|
||||
} {{[1]} {[1,"a,b"]} {[1,"a,b",3]} {["a,b",3,"x\"y"]} {[3,"x\"y",5]} {["x\"y",5,6]} {[5,6,7]}}
|
||||
do_execsql_test json103-410 {
|
||||
SELECT json_group_object(rowid, x) OVER (ROWS 2 PRECEDING) FROM t4;
|
||||
} {{{"1":1}} {{"1":1,"2":"a,b"}} {{"1":1,"2":"a,b","3":3}} {{"2":"a,b","3":3,"4":"x\"y"}} {{"3":3,"4":"x\"y","5":5}} {{"4":"x\"y","5":5,"6":6}} {{"5":5,"6":6,"7":7}}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+18
-9
@@ -71,7 +71,8 @@ proc execsql_test {tn sql} {
|
||||
# with two decimal points.
|
||||
#
|
||||
proc execsql_float_test {tn sql} {
|
||||
set F "%.2f"
|
||||
set F "%.4f"
|
||||
set T 0.0001
|
||||
set res [execsql $sql]
|
||||
set res2 [list]
|
||||
foreach r $res {
|
||||
@@ -79,14 +80,22 @@ proc execsql_float_test {tn sql} {
|
||||
lappend res2 $r
|
||||
}
|
||||
|
||||
puts $::fd "do_test $tn {"
|
||||
puts $::fd " set myres {}"
|
||||
puts $::fd " foreach r \[db eval {[string trim $sql]}\] {"
|
||||
puts $::fd " lappend myres \[format $F \[set r\]\]"
|
||||
puts $::fd " }"
|
||||
puts $::fd " set myres"
|
||||
puts $::fd "} {$res2}"
|
||||
puts $::fd ""
|
||||
set sql [string trim $sql]
|
||||
puts $::fd [subst -nocommands {
|
||||
do_test $tn {
|
||||
set myres {}
|
||||
foreach r [db eval {$sql}] {
|
||||
lappend myres [format $F [set r]]
|
||||
}
|
||||
set res2 {$res2}
|
||||
foreach r [set myres] r2 [set res2] {
|
||||
if {[set r]<([set r2]-$T) || [set r]>([set r2]+$T)} {
|
||||
error "list element [set i] does not match: got=[set r] expected=[set r2]"
|
||||
}
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
}]
|
||||
}
|
||||
|
||||
proc start_test {name date} {
|
||||
|
||||
@@ -154,5 +154,92 @@ do_test 400 {
|
||||
} {0 {1 8192 wal ok}}
|
||||
db2 close
|
||||
|
||||
# Reset the database yet again. This time immediately after it is closed
|
||||
# and reopened. So that the VACUUM is the first statement run.
|
||||
#
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_test 500 {
|
||||
sqlite3_finalize [
|
||||
sqlite3_prepare db "SELECT 1 FROM sqlite_master LIMIT 1" -1 tail
|
||||
]
|
||||
sqlite3_db_config db RESET_DB 1
|
||||
db eval VACUUM
|
||||
sqlite3_db_config db RESET_DB 0
|
||||
sqlite3 db2 test.db
|
||||
catchsql {
|
||||
PRAGMA page_count;
|
||||
PRAGMA page_size;
|
||||
PRAGMA journal_mode;
|
||||
PRAGMA quick_check;
|
||||
} db2
|
||||
} {0 {1 8192 wal ok}}
|
||||
db2 close
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
sqlite3 db2 test.db
|
||||
do_execsql_test 600 {
|
||||
PRAGMA journal_mode = wal;
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(1), (2), (3), (4);
|
||||
} {wal}
|
||||
|
||||
do_execsql_test -db db2 610 {
|
||||
SELECT * FROM t1
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test 620 {
|
||||
set res [list]
|
||||
db2 eval {SELECT a FROM t1} {
|
||||
lappend res $a
|
||||
if {$a==3} {
|
||||
sqlite3_db_config db RESET_DB 1
|
||||
db eval VACUUM
|
||||
sqlite3_db_config db RESET_DB 0
|
||||
}
|
||||
}
|
||||
|
||||
set res
|
||||
} {1 2 3 4}
|
||||
|
||||
do_execsql_test -db db2 630 {
|
||||
SELECT * FROM sqlite_master
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 700 {
|
||||
PRAGMA page_size=512;
|
||||
CREATE TABLE t1(a,b,c);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
CREATE INDEX t1bc ON t1(b,c);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10)
|
||||
INSERT INTO t1(a,b,c) SELECT x, randomblob(100),randomblob(100) FROM c;
|
||||
PRAGMA page_count;
|
||||
PRAGMA integrity_check;
|
||||
} {19 ok}
|
||||
|
||||
do_execsql_test 710 {
|
||||
UPDATE sqlite_dbpage SET data=
|
||||
X'53514C69746520666F726D61742033000200030100402020000000000000001300000000000000000000000300000004000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000D00000003017C0001D801AC017C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E03061715110145696E6465787431626374310443524541544520494E4445582074316263204F4E20743128622C63292A0206171311013F696E64657874316174310343524541544520494E44455820743161204F4E20743128612926010617111101397461626C657431743102435245415445205441424C4520743128612C622C6329' WHERE pgno=1;
|
||||
}
|
||||
|
||||
do_execsql_test 720 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
do_test 730 {
|
||||
sqlite3_db_config db RESET_DB 1
|
||||
db eval VACUUM
|
||||
sqlite3_db_config db RESET_DB 0
|
||||
} {0}
|
||||
|
||||
do_execsql_test 740 {
|
||||
PRAGMA page_count;
|
||||
PRAGMA integrity_check;
|
||||
} {1 ok}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# 2018-08-19
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Test OOM injection in schema-related operations.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix schemafault
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t2(aaa INTTT);
|
||||
CREATE VIEW v2(xxx , yyy) AS SELECT aaa, aaa+1 FROM t2;
|
||||
}
|
||||
|
||||
do_faultsim_test 1 -faults oom-* -prep {
|
||||
} -body {
|
||||
execsql { SELECT * FROM v2 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -169,6 +169,6 @@ do_execsql_test selectD-4.1 {
|
||||
WHERE x1.d>5
|
||||
GROUP BY x1.d) AS x2
|
||||
ON t41.b=x2.d;
|
||||
} {/*SEARCH SUBQUERY 0x* AS x2 USING AUTOMATIC*/}
|
||||
} {/*SEARCH SUBQUERY * AS x2 USING AUTOMATIC*/}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -337,4 +337,12 @@ do_execsql_test skipscan1-9.2 {
|
||||
SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5);
|
||||
} {/USING INDEX t9a_ab .ANY.a. AND b=./}
|
||||
|
||||
|
||||
optimization_control db skip-scan 0
|
||||
do_execsql_test skipscan1-9.3 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5);
|
||||
} {/{SCAN TABLE t9a}/}
|
||||
optimization_control db skip-scan 1
|
||||
|
||||
finish_test
|
||||
|
||||
+3
-1
@@ -974,7 +974,9 @@ proc query_plan_graph {sql} {
|
||||
}
|
||||
set a "\n QUERY PLAN\n"
|
||||
append a [append_graph " " dx cx 0]
|
||||
return [regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx}]
|
||||
regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx} a
|
||||
regsub -all {(MATERIALIZE|CO-ROUTINE|SUBQUERY) \d+\y} $a {\1 xxxxxx} a
|
||||
return $a
|
||||
}
|
||||
|
||||
# Helper routine for [query_plan_graph SQL]:
|
||||
|
||||
@@ -112,4 +112,20 @@ do_execsql_test upsert1-500 {
|
||||
SELECT * FROM t1;
|
||||
} {1 2}
|
||||
|
||||
# 2018-07-11
|
||||
# Ticket https://sqlite.org/src/tktview/79cad5e4b2e219dd197242e9e5f4
|
||||
# UPSERT leads to a corrupt index.
|
||||
#
|
||||
do_execsql_test upsert1-600 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(b UNIQUE, a INT PRIMARY KEY) WITHOUT ROWID;
|
||||
INSERT OR IGNORE INTO t1(a) VALUES('1') ON CONFLICT(a) DO NOTHING;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
do_execsql_test upsert1-610 {
|
||||
DELETE FROM t1;
|
||||
INSERT OR IGNORE INTO t1(a) VALUES('1'),(1) ON CONFLICT(a) DO NOTHING;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# 2018 July 4
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
ifcapable !wal {finish_test ; return }
|
||||
|
||||
set testprefix walprotocol2
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# When recovering the contents of a WAL file, a process obtains the WRITER
|
||||
# lock, then locks all other bytes before commencing recovery. If it fails
|
||||
# to lock all other bytes (because some other process is holding a read
|
||||
# lock) it should retry up to 100 times. Then return SQLITE_PROTOCOL to the
|
||||
# caller. Test this (test case 1.3).
|
||||
#
|
||||
# Also test the effect of hitting an SQLITE_BUSY while attempting to obtain
|
||||
# the WRITER lock (should be the same). Test case 1.4.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA journal_mode = wal;
|
||||
CREATE TABLE x(y);
|
||||
INSERT INTO x VALUES('z');
|
||||
} {wal}
|
||||
|
||||
db close
|
||||
|
||||
proc lock_callback {method filename handle lock} {
|
||||
# puts "$method $filename $handle $lock"
|
||||
}
|
||||
testvfs T
|
||||
T filter xShmLock
|
||||
T script lock_callback
|
||||
|
||||
sqlite3 db test.db -vfs T
|
||||
sqlite3 db2 test.db -vfs T
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
SELECT * FROM x;
|
||||
} {z}
|
||||
do_execsql_test -db db2 2.1 {
|
||||
SELECT * FROM x;
|
||||
} {z}
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Attempt a "BEGIN EXCLUSIVE" using connection handle [db]. This
|
||||
# causes SQLite to open a read transaction, then a write transaction.
|
||||
# Rig the xShmLock() callback so that just before the EXCLUSIVE lock
|
||||
# for the write transaction is taken, connection [db2] jumps in and
|
||||
# modifies the database. This causes the "BEGIN EXCLUSIVE" to throw
|
||||
# an SQLITE_BUSY_SNAPSHOT error.
|
||||
#
|
||||
proc lock_callback {method filename handle lock} {
|
||||
if {$lock=="0 1 lock exclusive"} {
|
||||
proc lock_callback {method filename handle lock} {}
|
||||
db2 eval { INSERT INTO x VALUES('y') }
|
||||
}
|
||||
}
|
||||
do_catchsql_test 2.2 {
|
||||
BEGIN EXCLUSIVE;
|
||||
} {1 {database is locked}}
|
||||
do_test 2.3 {
|
||||
sqlite3_extended_errcode db
|
||||
} {SQLITE_BUSY}
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Same again, but with a busy-handler. This time, following the
|
||||
# SQLITE_BUSY_SNAPSHOT error the busy-handler is invoked and then the
|
||||
# whole thing retried from the beginning. This time it succeeds.
|
||||
#
|
||||
proc lock_callback {method filename handle lock} {
|
||||
if {$lock=="0 1 lock exclusive"} {
|
||||
proc lock_callback {method filename handle lock} {}
|
||||
db2 eval { INSERT INTO x VALUES('x') }
|
||||
}
|
||||
}
|
||||
db timeout 10
|
||||
do_catchsql_test 2.4 {
|
||||
BEGIN EXCLUSIVE;
|
||||
} {0 {}}
|
||||
do_execsql_test 2.5 {
|
||||
SELECT * FROM x;
|
||||
COMMIT;
|
||||
} {z y x}
|
||||
|
||||
finish_test
|
||||
+13
-8
@@ -308,24 +308,29 @@ foreach {tn window} {
|
||||
"
|
||||
|
||||
execsql_test 1.$tn.15.1 "
|
||||
SELECT string_agg(CAST(b AS TEXT), '.')
|
||||
FILTER (WHERE a%2=0) OVER (ORDER BY a $window) FROM t2
|
||||
SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.')
|
||||
FILTER (WHERE a%2=0) OVER win FROM t2
|
||||
WINDOW win AS (ORDER BY a $window)
|
||||
"
|
||||
|
||||
execsql_test 1.$tn.15.2 "
|
||||
SELECT string_agg(CAST(b AS TEXT), '.')
|
||||
FILTER (WHERE 0=1) OVER (ORDER BY a $window) FROM t2
|
||||
SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.')
|
||||
FILTER (WHERE 0=1) OVER win FROM t2
|
||||
WINDOW win AS (ORDER BY a $window)
|
||||
"
|
||||
|
||||
execsql_test 1.$tn.15.3 "
|
||||
SELECT string_agg(CAST(b AS TEXT), '.')
|
||||
FILTER (WHERE 1=0) OVER (PARTITION BY (a%10) ORDER BY a $window) FROM t2
|
||||
SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.')
|
||||
FILTER (WHERE 1=0) OVER win FROM t2
|
||||
WINDOW win AS (PARTITION BY (a%10) ORDER BY a $window)
|
||||
"
|
||||
|
||||
execsql_test 1.$tn.15.4 "
|
||||
SELECT string_agg(CAST(b AS TEXT), '.')
|
||||
FILTER (WHERE a%2=0) OVER (PARTITION BY (a%10) ORDER BY a $window) FROM t2
|
||||
SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.')
|
||||
FILTER (WHERE a%2=0) OVER win FROM t2
|
||||
WINDOW win AS (PARTITION BY (a%10) ORDER BY a $window)
|
||||
"
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+4422
-2093
File diff suppressed because one or more lines are too long
@@ -332,5 +332,33 @@ execsql_test 9.5 {
|
||||
SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2
|
||||
}
|
||||
|
||||
execsql_float_test 9.6 {
|
||||
SELECT percent_rank() OVER () FROM t1
|
||||
}
|
||||
|
||||
execsql_float_test 9.7 {
|
||||
SELECT cume_dist() OVER () FROM t1
|
||||
}
|
||||
|
||||
execsql_test 10.0 {
|
||||
DROP TABLE IF EXISTS t7;
|
||||
CREATE TABLE t7(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER);
|
||||
INSERT INTO t7(id, a, b) VALUES
|
||||
(1, 1, 2), (2, 1, NULL), (3, 1, 4),
|
||||
(4, 3, NULL), (5, 3, 8), (6, 3, 1);
|
||||
}
|
||||
execsql_test 10.1 {
|
||||
SELECT id, min(b) OVER (PARTITION BY a ORDER BY id) FROM t7;
|
||||
}
|
||||
|
||||
execsql_test 10.2 {
|
||||
SELECT id, lead(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
|
||||
}
|
||||
execsql_test 10.3 {
|
||||
SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -1233,4 +1233,40 @@ do_execsql_test 9.5 {
|
||||
SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2
|
||||
} {1 1 4 4 6 6 7 7}
|
||||
|
||||
do_test 9.6 {
|
||||
set myres {}
|
||||
foreach r [db eval {SELECT percent_rank() OVER () FROM t1}] {
|
||||
lappend myres [format %.2f [set r]]
|
||||
}
|
||||
set myres
|
||||
} {0.00 0.00 0.00}
|
||||
|
||||
do_test 9.7 {
|
||||
set myres {}
|
||||
foreach r [db eval {SELECT cume_dist() OVER () FROM t1}] {
|
||||
lappend myres [format %.2f [set r]]
|
||||
}
|
||||
set myres
|
||||
} {1.00 1.00 1.00}
|
||||
|
||||
do_execsql_test 10.0 {
|
||||
DROP TABLE IF EXISTS t7;
|
||||
CREATE TABLE t7(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER);
|
||||
INSERT INTO t7(id, a, b) VALUES
|
||||
(1, 1, 2), (2, 1, NULL), (3, 1, 4),
|
||||
(4, 3, NULL), (5, 3, 8), (6, 3, 1);
|
||||
} {}
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
SELECT id, min(b) OVER (PARTITION BY a ORDER BY id) FROM t7;
|
||||
} {1 2 2 2 3 2 4 {} 5 8 6 1}
|
||||
|
||||
do_execsql_test 10.2 {
|
||||
SELECT id, lead(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
|
||||
} {1 {} 2 2 3 {} 4 {} 5 {} 6 8}
|
||||
|
||||
do_execsql_test 10.3 {
|
||||
SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
|
||||
} {1 {} 2 4 3 {} 4 8 5 1 6 {}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -82,6 +82,16 @@ do_execsql_test 2.1 {
|
||||
SELECT sumint(a) OVER (ORDER BY rowid ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t1 ORDER BY rowid;
|
||||
} {10 11 12 8 10 5}
|
||||
|
||||
test_override_sum db
|
||||
do_catchsql_test 3.0 {
|
||||
SELECT sum(a) OVER
|
||||
(ORDER BY b ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
|
||||
FROM t1;
|
||||
} {1 {sum() may not be used as a window function}}
|
||||
do_execsql_test 3.1 {
|
||||
SELECT sum(a) FROM t1;
|
||||
} {21}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -139,5 +139,201 @@ do_execsql_test 5.4 {
|
||||
SELECT sum(window) OVER window window FROM window window window window AS (ORDER BY window);
|
||||
} {2 6 12}
|
||||
|
||||
do_execsql_test 5.5 {
|
||||
SELECT count(*) OVER win FROM over
|
||||
WINDOW win AS (ORDER BY x ROWS BETWEEN +2 FOLLOWING AND +3 FOLLOWING)
|
||||
} {1 0 0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
do_execsql_test 6.0 {
|
||||
SELECT LIKE('!', '', '!') x WHERE x;
|
||||
} {}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
SELECT LIKE("!","","!")""WHeRE"";
|
||||
} {}
|
||||
|
||||
do_catchsql_test 6.2 {
|
||||
SELECT LIKE("!","","!")""window"";
|
||||
} {1 {near "window": syntax error}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE t1(x TEXT);
|
||||
CREATE INDEX i1 ON t1(x COLLATE nocase);
|
||||
INSERT INTO t1 VALUES('');
|
||||
}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
SELECT count(*) FROM t1 WHERE x LIKE '!' ESCAPE '!';
|
||||
} {0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 8.0 {
|
||||
CREATE TABLE IF NOT EXISTS "sample" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"counter" INTEGER NOT NULL,
|
||||
"value" REAL NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "sample" (counter, value)
|
||||
VALUES (1, 10.), (1, 20.), (2, 1.), (2, 3.), (3, 100.);
|
||||
}
|
||||
|
||||
do_execsql_test 8.1 {
|
||||
SELECT "counter", "value", RANK() OVER w AS "rank"
|
||||
FROM "sample"
|
||||
WINDOW w AS (PARTITION BY "counter" ORDER BY "value" DESC)
|
||||
ORDER BY "counter", RANK() OVER w
|
||||
} {
|
||||
1 20.0 1 1 10.0 2 2 3.0 1 2 1.0 2 3 100.0 1
|
||||
}
|
||||
|
||||
do_execsql_test 8.2 {
|
||||
SELECT "counter", "value", SUM("value") OVER
|
||||
(ORDER BY "id" ROWS 2 PRECEDING)
|
||||
FROM "sample"
|
||||
ORDER BY "id"
|
||||
} {
|
||||
1 10.0 10.0 1 20.0 30.0 2 1.0 31.0 2 3.0 24.0 3 100.0 104.0
|
||||
}
|
||||
|
||||
do_execsql_test 8.3 {
|
||||
SELECT SUM("value") OVER
|
||||
(ORDER BY "id" ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
|
||||
FROM "sample"
|
||||
ORDER BY "id"
|
||||
} {
|
||||
10.0 30.0 31.0 24.0 104.0
|
||||
}
|
||||
|
||||
do_execsql_test 9.0 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT x, group_concat(x) OVER (ORDER BY x ROWS 2 PRECEDING)
|
||||
FROM c;
|
||||
} {
|
||||
1 1 2 1,2 3 1,2,3 4 2,3,4 5 3,4,5
|
||||
}
|
||||
do_catchsql_test 9.1 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT x, group_concat(x) OVER (ORDER BY x RANGE 2 PRECEDING)
|
||||
FROM c;
|
||||
} {1 {RANGE must use only UNBOUNDED or CURRENT ROW}}
|
||||
|
||||
do_catchsql_test 9.2 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT x, group_concat(x) OVER (ORDER BY x RANGE BETWEEN UNBOUNDED PRECEDING AND 2 FOLLOWING)
|
||||
FROM c;
|
||||
} {1 {RANGE must use only UNBOUNDED or CURRENT ROW}}
|
||||
|
||||
do_catchsql_test 9.3 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT count(DISTINCT x) OVER (ORDER BY x) FROM c;
|
||||
} {1 {DISTINCT is not supported for window functions}}
|
||||
|
||||
do_catchsql_test 9.4 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT count() OVER (ORDER BY x RANGE UNBOUNDED FOLLOWING) FROM c;
|
||||
} {1 {near "FOLLOWING": syntax error}}
|
||||
|
||||
do_catchsql_test 9.5 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT count() OVER (ORDER BY x RANGE BETWEEN UNBOUNDED FOLLOWING AND UNBOUNDED FOLLOWING) FROM c;
|
||||
} {1 {near "FOLLOWING": syntax error}}
|
||||
|
||||
do_catchsql_test 9.6 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT count() OVER (ORDER BY x RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED PRECEDING) FROM c;
|
||||
} {1 {near "PRECEDING": syntax error}}
|
||||
|
||||
foreach {tn frame} {
|
||||
1 "BETWEEN CURRENT ROW AND 4 PRECEDING"
|
||||
2 "4 FOLLOWING"
|
||||
3 "BETWEEN 4 FOLLOWING AND CURRENT ROW"
|
||||
4 "BETWEEN 4 FOLLOWING AND 2 PRECEDING"
|
||||
} {
|
||||
do_catchsql_test 9.7.$tn "
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT count() OVER (
|
||||
ORDER BY x ROWS $frame
|
||||
) FROM c;
|
||||
" {1 {unsupported frame delimiter for ROWS}}
|
||||
}
|
||||
|
||||
do_catchsql_test 9.8.1 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT count() OVER (
|
||||
ORDER BY x ROWS BETWEEN a PRECEDING AND 2 FOLLOWING
|
||||
) FROM c;
|
||||
} {1 {frame starting offset must be a non-negative integer}}
|
||||
do_catchsql_test 9.8.2 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
|
||||
SELECT count() OVER (
|
||||
ORDER BY x ROWS BETWEEN 2 PRECEDING AND a FOLLOWING
|
||||
) FROM c;
|
||||
} {1 {frame ending offset must be a non-negative integer}}
|
||||
|
||||
do_execsql_test 10.0 {
|
||||
WITH t1(a,b) AS (VALUES(1,2))
|
||||
SELECT count() FILTER (where b<>5) OVER w1
|
||||
FROM t1
|
||||
WINDOW w1 AS (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
|
||||
} {1}
|
||||
|
||||
foreach {tn stmt} {
|
||||
1 "SELECT nth_value(b, 0) OVER (ORDER BY a) FROM t1"
|
||||
2 "SELECT nth_value(b, -1) OVER (ORDER BY a) FROM t1"
|
||||
3 "SELECT nth_value(b, '4ab') OVER (ORDER BY a) FROM t1"
|
||||
4 "SELECT nth_value(b, NULL) OVER (ORDER BY a) FROM t1"
|
||||
5 "SELECT nth_value(b, 8.5) OVER (ORDER BY a) FROM t1"
|
||||
} {
|
||||
do_catchsql_test 10.1.$tn "
|
||||
WITH t1(a,b) AS ( VALUES(1, 2), (2, 3), (3, 4) )
|
||||
$stmt
|
||||
" {1 {second argument to nth_value must be a positive integer}}
|
||||
}
|
||||
|
||||
foreach {tn stmt res} {
|
||||
1 "SELECT nth_value(b, 1) OVER (ORDER BY a) FROM t1" {2 2 2}
|
||||
2 "SELECT nth_value(b, 2) OVER (ORDER BY a) FROM t1" {{} 3 3}
|
||||
3 "SELECT nth_value(b, '2') OVER (ORDER BY a) FROM t1" {{} 3 3}
|
||||
4 "SELECT nth_value(b, 2.0) OVER (ORDER BY a) FROM t1" {{} 3 3}
|
||||
5 "SELECT nth_value(b, '2.0') OVER (ORDER BY a) FROM t1" {{} 3 3}
|
||||
6 "SELECT nth_value(b, 10000000) OVER (ORDER BY a) FROM t1" {{} {} {}}
|
||||
} {
|
||||
do_execsql_test 10.2.$tn "
|
||||
WITH t1(a,b) AS ( VALUES(1, 2), (2, 3), (3, 4) )
|
||||
$stmt
|
||||
" $res
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.0 {
|
||||
CREATE TABLE t1(a INT);
|
||||
INSERT INTO t1 VALUES(10),(15),(20),(20),(25),(30),(30),(50);
|
||||
CREATE TABLE t3(x INT, y VARCHAR);
|
||||
INSERT INTO t3(x,y) VALUES(10,'ten'),('15','fifteen'),(30,'thirty');
|
||||
}
|
||||
|
||||
do_execsql_test 11.1 {
|
||||
SELECT a, (SELECT y FROM t3 WHERE x=a) FROM t1 ORDER BY a;
|
||||
} {
|
||||
10 ten 15 fifteen 20 {} 20 {} 25 {} 30 thirty 30 thirty 50 {}
|
||||
}
|
||||
|
||||
do_execsql_test 11.2 {
|
||||
SELECT a, (SELECT y FROM t3 WHERE x=a), sum(a) OVER (ORDER BY a)
|
||||
FROM t1 ORDER BY a;
|
||||
} {
|
||||
10 ten 10 15 fifteen 25 20 {} 65 20 {} 65
|
||||
25 {} 90 30 thirty 150 30 thirty 150 50 {} 200
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -129,5 +129,38 @@ do_faultsim_test 5 -start 1 -faults oom-* -prep {
|
||||
faultsim_test_result {0 {5 1 9 5 9 9}}
|
||||
}
|
||||
|
||||
do_faultsim_test 6 -faults oom-* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT percent_rank() OVER (), cume_dist() OVER () FROM t1
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {0.0 1.0 0.0 1.0 0.0 1.0}}
|
||||
}
|
||||
|
||||
do_faultsim_test 7 -faults oom-* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT percent_rank() OVER (), cume_dist() OVER () FROM t1
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {0.0 1.0 0.0 1.0 0.0 1.0}}
|
||||
}
|
||||
|
||||
do_faultsim_test 8 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT a, sum(b) OVER win1 FROM t1
|
||||
WINDOW win1 AS (PARTITION BY a ),
|
||||
win2 AS (PARTITION BY b )
|
||||
ORDER BY a;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 5 6 9 10}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+4
-1
@@ -550,6 +550,7 @@ static YYACTIONTYPE yy_find_shift_action(
|
||||
#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
|
||||
j<YY_ACTTAB_COUNT &&
|
||||
#endif
|
||||
j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) &&
|
||||
yy_lookahead[j]==YYWILDCARD && iLookAhead>0
|
||||
){
|
||||
#ifndef NDEBUG
|
||||
@@ -1065,9 +1066,11 @@ void Parse(
|
||||
*/
|
||||
int ParseFallback(int iToken){
|
||||
#ifdef YYFALLBACK
|
||||
if( iToken<sizeof(yyFallback)/sizeof(yyFallback[0]) ){
|
||||
if( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ){
|
||||
return yyFallback[iToken];
|
||||
}
|
||||
#else
|
||||
(void)iToken;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user