Compare commits
131 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 239c38dc23 | |||
| 32291526a2 | |||
| af03b5b7a5 | |||
| 1f2e0e0a4b | |||
| 84fec12c28 | |||
| 7ae5530f63 | |||
| 10df23fe4f | |||
| 72cd360caf | |||
| 60c4249fcc | |||
| eaa544d44d | |||
| 15707ac992 | |||
| 4f69540b71 | |||
| 82452480ea | |||
| 5729c31daf | |||
| ddb2b4a310 | |||
| cb620b4797 | |||
| eb2329bed3 | |||
| d38a2e2511 | |||
| cc47eac005 | |||
| c5412d533c | |||
| 231ee68808 | |||
| 997de998a8 | |||
| 848b190e40 | |||
| 3767026113 | |||
| d7564865ad | |||
| 527b0435fa | |||
| c5e7f94494 | |||
| 0a2f2b546a | |||
| 3bfa7e82b6 | |||
| 0b98207c5b | |||
| 13969f5af0 | |||
| 6737aab5cf | |||
| 4567beefac | |||
| 6369bc3fbb | |||
| f5268268b7 | |||
| 3c6707f72b | |||
| d260dd3534 | |||
| f68521c4e6 | |||
| 80fbee092e | |||
| 8d2f41ccd2 | |||
| b7c9659db3 | |||
| ef480d37dc | |||
| 544c6b8e1b | |||
| 3cdce92c38 | |||
| 9f6168b6a3 | |||
| b6eb666264 | |||
| 9bccde3d03 | |||
| f27d737b88 | |||
| fce07fb944 | |||
| febfe02300 | |||
| f11737fcc8 | |||
| 49aed58b7f | |||
| 1e8dae0e43 | |||
| cf9bce34ab | |||
| bb9b5f2608 | |||
| eea627da9e | |||
| 789780d8f6 | |||
| fe485c0e56 | |||
| 860443da10 | |||
| b99185f278 | |||
| 108e5a9a6c | |||
| 9493cafe6f | |||
| 790b151e19 | |||
| e42195b044 | |||
| 762e32bcfa | |||
| de845c2f5a | |||
| 0e80e50984 | |||
| 1b9f2141a7 | |||
| c9460ab989 | |||
| 4b058dd4d1 | |||
| db8d320d63 | |||
| f71a366407 | |||
| e459bd4986 | |||
| 377ba38429 | |||
| f55fb6615b | |||
| 4ef07708df | |||
| 3f77389bb4 | |||
| 892ffcc7fc | |||
| 32f57d4c37 | |||
| c5db1d4b4c | |||
| 98968b22c5 | |||
| b7b91068ee | |||
| 0ff47e9e1b | |||
| 82f525406a | |||
| 089555c8e9 | |||
| a580936383 | |||
| 10ac13ae3b | |||
| 4a8a646723 | |||
| 05586c3284 | |||
| 7da56b4f65 | |||
| af3906a798 | |||
| 7bd6b49a3e | |||
| de503eb166 | |||
| 0d71eaa368 | |||
| e500f65a2c | |||
| bea14132cf | |||
| d5704a8961 | |||
| 7d85774da8 | |||
| 5cf98f101e | |||
| e8c20120ce | |||
| ffbb02a361 | |||
| e1f1ffa55a | |||
| 811f17bac0 | |||
| a0ca3bc854 | |||
| 1bb85f3ed3 | |||
| ecdf20d3a4 | |||
| 6459ca0b8c | |||
| 4dbc65b29a | |||
| 57ebc84a6e | |||
| 69c355bd9a | |||
| ab8aa11b96 | |||
| 90730c9e68 | |||
| 7c621fb967 | |||
| bacbbccd16 | |||
| c5644346b6 | |||
| d93b2b840d | |||
| 769b4c95ca | |||
| c1fb2b87bd | |||
| 2f1e02e8a7 | |||
| 273021d71a | |||
| d1cca3b721 | |||
| 3349d9bea9 | |||
| c629e63a55 | |||
| 7ed4020890 | |||
| 33b104af08 | |||
| 15d36c603d | |||
| d0b8b664bd | |||
| 9219bf9839 | |||
| c7dbce0f2a | |||
| e45216fd9d | |||
| 86151e8905 |
@@ -271,6 +271,8 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
#
|
||||
!IFNDEF EXT_FEATURE_FLAGS
|
||||
!IF $(FOR_WIN10)!=0
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_STAT4=1
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_OMIT_LOCALTIME=1
|
||||
|
||||
@@ -6,8 +6,9 @@ libsqlite3_la_SOURCES = sqlite3.c
|
||||
libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
|
||||
|
||||
bin_PROGRAMS = sqlite3
|
||||
sqlite3_SOURCES = shell.c sqlite3.c sqlite3.h
|
||||
sqlite3_LDADD = @READLINE_LIBS@
|
||||
sqlite3_SOURCES = shell.c sqlite3.h
|
||||
EXTRA_sqlite3_SOURCES = sqlite3.c
|
||||
sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
|
||||
sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
|
||||
sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
|
||||
|
||||
@@ -256,6 +256,8 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
#
|
||||
!IFNDEF EXT_FEATURE_FLAGS
|
||||
!IF $(FOR_WIN10)!=0
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_STAT4=1
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1
|
||||
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_OMIT_LOCALTIME=1
|
||||
|
||||
@@ -130,7 +130,7 @@ AC_ARG_ENABLE(static-shell, [AS_HELP_STRING(
|
||||
[statically link libsqlite3 into shell tool [default=yes]])],
|
||||
[], [enable_static_shell=yes])
|
||||
if test x"$enable_static_shell" == "xyes"; then
|
||||
EXTRA_SHELL_OBJ=sqlite3.$OBJEXT
|
||||
EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT
|
||||
else
|
||||
EXTRA_SHELL_OBJ=libsqlite3.la
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.12.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.12.1.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -726,8 +726,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.12.0'
|
||||
PACKAGE_STRING='sqlite 3.12.0'
|
||||
PACKAGE_VERSION='3.12.1'
|
||||
PACKAGE_STRING='sqlite 3.12.1'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1460,7 +1460,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.12.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.12.1 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1525,7 +1525,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.12.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.12.1:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1646,7 +1646,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.12.0
|
||||
sqlite configure 3.12.1
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2065,7 +2065,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.12.0, which was
|
||||
It was created by sqlite $as_me 3.12.1, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -12079,7 +12079,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.12.0, which was
|
||||
This file was extended by sqlite $as_me 3.12.1, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12145,7 +12145,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.12.0
|
||||
sqlite config.status 3.12.1
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+183
-96
@@ -5,14 +5,17 @@
|
||||
<body bgcolor=white>
|
||||
<h1 align=center>The Lemon Parser Generator</h1>
|
||||
|
||||
<p>Lemon is an LALR(1) parser generator for C or C++.
|
||||
It does the same job as ``bison'' and ``yacc''.
|
||||
But lemon is not another bison or yacc clone. It
|
||||
<p>Lemon is an LALR(1) parser generator for C.
|
||||
It does the same job as "bison" and "yacc".
|
||||
But lemon is not a bison or yacc clone. Lemon
|
||||
uses a different grammar syntax which is designed to
|
||||
reduce the number of coding errors. Lemon also uses a more
|
||||
sophisticated parsing engine that is faster than yacc and
|
||||
bison and which is both reentrant and thread-safe.
|
||||
Furthermore, Lemon implements features that can be used
|
||||
reduce the number of coding errors. Lemon also uses a
|
||||
parsing engine that is faster than yacc and
|
||||
bison and which is both reentrant and threadsafe.
|
||||
(Update: Since the previous sentence was written, bison
|
||||
has also been updated so that it too can generate a
|
||||
reentrant and threadsafe parser.)
|
||||
Lemon also implements features that can be used
|
||||
to eliminate resource leaks, making is suitable for use
|
||||
in long-running programs such as graphical user interfaces
|
||||
or embedded controllers.</p>
|
||||
@@ -44,18 +47,18 @@ one and three files of outputs.
|
||||
automaton.
|
||||
</ul>
|
||||
By default, all three of these output files are generated.
|
||||
The header file is suppressed if the ``-m'' command-line option is
|
||||
used and the report file is omitted when ``-q'' is selected.</p>
|
||||
The header file is suppressed if the "-m" command-line option is
|
||||
used and the report file is omitted when "-q" is selected.</p>
|
||||
|
||||
<p>The grammar specification file uses a ``.y'' suffix, by convention.
|
||||
<p>The grammar specification file uses a ".y" suffix, by convention.
|
||||
In the examples used in this document, we'll assume the name of the
|
||||
grammar file is ``gram.y''. A typical use of Lemon would be the
|
||||
grammar file is "gram.y". A typical use of Lemon would be the
|
||||
following command:
|
||||
<pre>
|
||||
lemon gram.y
|
||||
</pre>
|
||||
This command will generate three output files named ``gram.c'',
|
||||
``gram.h'' and ``gram.out''.
|
||||
This command will generate three output files named "gram.c",
|
||||
"gram.h" and "gram.out".
|
||||
The first is C code to implement the parser. The second
|
||||
is the header file that defines numerical values for all
|
||||
terminal symbols, and the last is the report that explains
|
||||
@@ -71,39 +74,35 @@ with a brief explanation of what each does by typing
|
||||
</pre>
|
||||
As of this writing, the following command-line options are supported:
|
||||
<ul>
|
||||
<li><tt>-b</tt>
|
||||
<li><tt>-c</tt>
|
||||
<li><tt>-g</tt>
|
||||
<li><tt>-m</tt>
|
||||
<li><tt>-q</tt>
|
||||
<li><tt>-s</tt>
|
||||
<li><tt>-x</tt>
|
||||
<li><b>-b</b>
|
||||
Show only the basis for each parser state in the report file.
|
||||
<li><b>-c</b>
|
||||
Do not compress the generated action tables.
|
||||
<li><b>-D<i>name</i></b>
|
||||
Define C preprocessor macro <i>name</i>. This macro is useable by
|
||||
"%ifdef" lines in the grammar file.
|
||||
<li><b>-g</b>
|
||||
Do not generate a parser. Instead write the input grammar to standard
|
||||
output with all comments, actions, and other extraneous text removed.
|
||||
<li><b>-l</b>
|
||||
Omit "#line" directives int the generated parser C code.
|
||||
<li><b>-m</b>
|
||||
Cause the output C source code to be compatible with the "makeheaders"
|
||||
program.
|
||||
<li><b>-p</b>
|
||||
Display all conflicts that are resolved by
|
||||
<a href='#precrules'>precedence rules</a>.
|
||||
<li><b>-q</b>
|
||||
Suppress generation of the report file.
|
||||
<li><b>-r</b>
|
||||
Do not sort or renumber the parser states as part of optimization.
|
||||
<li><b>-s</b>
|
||||
Show parser statistics before existing.
|
||||
<li><b>-T<i>file</i></b>
|
||||
Use <i>file</i> as the template for the generated C-code parser implementation.
|
||||
<li><b>-x</b>
|
||||
Print the Lemon version number.
|
||||
</ul>
|
||||
The ``-b'' option reduces the amount of text in the report file by
|
||||
printing only the basis of each parser state, rather than the full
|
||||
configuration.
|
||||
The ``-c'' option suppresses action table compression. Using -c
|
||||
will make the parser a little larger and slower but it will detect
|
||||
syntax errors sooner.
|
||||
The ``-g'' option causes no output files to be generated at all.
|
||||
Instead, the input grammar file is printed on standard output but
|
||||
with all comments, actions and other extraneous text deleted. This
|
||||
is a useful way to get a quick summary of a grammar.
|
||||
The ``-m'' option causes the output C source file to be compatible
|
||||
with the ``makeheaders'' program.
|
||||
Makeheaders is a program that automatically generates header files
|
||||
from C source code. When the ``-m'' option is used, the header
|
||||
file is not output since the makeheaders program will take care
|
||||
of generated all header files automatically.
|
||||
The ``-q'' option suppresses the report file.
|
||||
Using ``-s'' causes a brief summary of parser statistics to be
|
||||
printed. Like this:
|
||||
<pre>
|
||||
Parser statistics: 74 terminals, 70 nonterminals, 179 rules
|
||||
340 states, 2026 parser table entries, 0 conflicts
|
||||
</pre>
|
||||
Finally, the ``-x'' option causes Lemon to print its version number
|
||||
and then stops without attempting to read the grammar or generate a parser.</p>
|
||||
|
||||
<h3>The Parser Interface</h3>
|
||||
|
||||
@@ -121,12 +120,12 @@ A new parser is created as follows:
|
||||
</pre>
|
||||
The ParseAlloc() routine allocates and initializes a new parser and
|
||||
returns a pointer to it.
|
||||
The actual data structure used to represent a parser is opaque --
|
||||
The actual data structure used to represent a parser is opaque —
|
||||
its internal structure is not visible or usable by the calling routine.
|
||||
For this reason, the ParseAlloc() routine returns a pointer to void
|
||||
rather than a pointer to some particular structure.
|
||||
The sole argument to the ParseAlloc() routine is a pointer to the
|
||||
subroutine used to allocate memory. Typically this means ``malloc()''.</p>
|
||||
subroutine used to allocate memory. Typically this means malloc().</p>
|
||||
|
||||
<p>After a program is finished using a parser, it can reclaim all
|
||||
memory allocated by that parser by calling
|
||||
@@ -151,13 +150,13 @@ type of the next token in the data stream.
|
||||
There is one token type for each terminal symbol in the grammar.
|
||||
The gram.h file generated by Lemon contains #define statements that
|
||||
map symbolic terminal symbol names into appropriate integer values.
|
||||
(A value of 0 for the second argument is a special flag to the
|
||||
parser to indicate that the end of input has been reached.)
|
||||
A value of 0 for the second argument is a special flag to the
|
||||
parser to indicate that the end of input has been reached.
|
||||
The third argument is the value of the given token. By default,
|
||||
the type of the third argument is integer, but the grammar will
|
||||
usually redefine this type to be some kind of structure.
|
||||
Typically the second argument will be a broad category of tokens
|
||||
such as ``identifier'' or ``number'' and the third argument will
|
||||
such as "identifier" or "number" and the third argument will
|
||||
be the name of the identifier or the value of the number.</p>
|
||||
|
||||
<p>The Parse() function may have either three or four arguments,
|
||||
@@ -193,7 +192,7 @@ following:
|
||||
</pre>
|
||||
This example shows a user-written routine that parses a file of
|
||||
text and returns a pointer to the parse tree.
|
||||
(We've omitted all error-handling from this example to keep it
|
||||
(All error-handling code is omitted from this example to keep it
|
||||
simple.)
|
||||
We assume the existence of some kind of tokenizer which is created
|
||||
using TokenizerCreate() on line 8 and deleted by TokenizerFree()
|
||||
@@ -287,7 +286,7 @@ tokens) and it honors the same commenting conventions as C and C++.</p>
|
||||
<h3>Terminals and Nonterminals</h3>
|
||||
|
||||
<p>A terminal symbol (token) is any string of alphanumeric
|
||||
and underscore characters
|
||||
and/or underscore characters
|
||||
that begins with an upper case letter.
|
||||
A terminal can contain lowercase letters after the first character,
|
||||
but the usual convention is to make terminals all upper case.
|
||||
@@ -314,7 +313,7 @@ must have alphanumeric names.</p>
|
||||
<p>The main component of a Lemon grammar file is a sequence of grammar
|
||||
rules.
|
||||
Each grammar rule consists of a nonterminal symbol followed by
|
||||
the special symbol ``::='' and then a list of terminals and/or nonterminals.
|
||||
the special symbol "::=" and then a list of terminals and/or nonterminals.
|
||||
The rule is terminated by a period.
|
||||
The list of terminals and nonterminals on the right-hand side of the
|
||||
rule can be empty.
|
||||
@@ -330,9 +329,9 @@ A typical sequence of grammar rules might look something like this:
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>There is one non-terminal in this example, ``expr'', and five
|
||||
terminal symbols or tokens: ``PLUS'', ``TIMES'', ``LPAREN'',
|
||||
``RPAREN'' and ``VALUE''.</p>
|
||||
<p>There is one non-terminal in this example, "expr", and five
|
||||
terminal symbols or tokens: "PLUS", "TIMES", "LPAREN",
|
||||
"RPAREN" and "VALUE".</p>
|
||||
|
||||
<p>Like yacc and bison, Lemon allows the grammar to specify a block
|
||||
of C code that will be executed whenever a grammar rule is reduced
|
||||
@@ -348,15 +347,15 @@ For example:
|
||||
|
||||
<p>In order to be useful, grammar actions must normally be linked to
|
||||
their associated grammar rules.
|
||||
In yacc and bison, this is accomplished by embedding a ``$$'' in the
|
||||
In yacc and bison, this is accomplished by embedding a "$$" in the
|
||||
action to stand for the value of the left-hand side of the rule and
|
||||
symbols ``$1'', ``$2'', and so forth to stand for the value of
|
||||
symbols "$1", "$2", and so forth to stand for the value of
|
||||
the terminal or nonterminal at position 1, 2 and so forth on the
|
||||
right-hand side of the rule.
|
||||
This idea is very powerful, but it is also very error-prone. The
|
||||
single most common source of errors in a yacc or bison grammar is
|
||||
to miscount the number of symbols on the right-hand side of a grammar
|
||||
rule and say ``$7'' when you really mean ``$8''.</p>
|
||||
rule and say "$7" when you really mean "$8".</p>
|
||||
|
||||
<p>Lemon avoids the need to count grammar symbols by assigning symbolic
|
||||
names to each symbol in a grammar rule and then using those symbolic
|
||||
@@ -386,7 +385,7 @@ For example, the rule
|
||||
<pre>
|
||||
expr(A) ::= expr(B) PLUS expr(C). { A = B; }
|
||||
</pre>
|
||||
will generate an error because the linking symbol ``C'' is used
|
||||
will generate an error because the linking symbol "C" is used
|
||||
in the grammar rule but not in the reduce action.</p>
|
||||
|
||||
<p>The Lemon notation for linking grammar rules to reduce actions
|
||||
@@ -394,6 +393,7 @@ also facilitates the use of destructors for reclaiming memory
|
||||
allocated by the values of terminals and nonterminals on the
|
||||
right-hand side of a rule.</p>
|
||||
|
||||
<a name='precrules'></a>
|
||||
<h3>Precedence Rules</h3>
|
||||
|
||||
<p>Lemon resolves parsing ambiguities in exactly the same way as
|
||||
@@ -405,7 +405,10 @@ whichever rule comes first in the grammar file.</p>
|
||||
yacc and bison, Lemon allows a measure of control
|
||||
over the resolution of paring conflicts using precedence rules.
|
||||
A precedence value can be assigned to any terminal symbol
|
||||
using the %left, %right or %nonassoc directives. Terminal symbols
|
||||
using the
|
||||
<a href='#pleft'>%left</a>,
|
||||
<a href='#pright'>%right</a> or
|
||||
<a href='#pnonassoc'>%nonassoc</a> directives. Terminal symbols
|
||||
mentioned in earlier directives have a lower precedence that
|
||||
terminal symbols mentioned in later directives. For example:</p>
|
||||
|
||||
@@ -525,7 +528,11 @@ other than that, the order of directives in Lemon is arbitrary.</p>
|
||||
<li><tt>%default_destructor</tt>
|
||||
<li><tt>%default_type</tt>
|
||||
<li><tt>%destructor</tt>
|
||||
<li><tt>%endif</tt>
|
||||
<li><tt>%extra_argument</tt>
|
||||
<li><tt>%fallback</tt>
|
||||
<li><tt>%ifdef</tt>
|
||||
<li><tt>%ifndef</tt>
|
||||
<li><tt>%include</tt>
|
||||
<li><tt>%left</tt>
|
||||
<li><tt>%name</tt>
|
||||
@@ -537,49 +544,57 @@ other than that, the order of directives in Lemon is arbitrary.</p>
|
||||
<li><tt>%stack_size</tt>
|
||||
<li><tt>%start_symbol</tt>
|
||||
<li><tt>%syntax_error</tt>
|
||||
<li><tt>%token_class</tt>
|
||||
<li><tt>%token_destructor</tt>
|
||||
<li><tt>%token_prefix</tt>
|
||||
<li><tt>%token_type</tt>
|
||||
<li><tt>%type</tt>
|
||||
<li><tt>%wildcard</tt>
|
||||
</ul>
|
||||
Each of these directives will be described separately in the
|
||||
following sections:</p>
|
||||
|
||||
<a name='pcode'></a>
|
||||
<h4>The <tt>%code</tt> directive</h4>
|
||||
|
||||
<p>The %code directive is used to specify addition C/C++ code that
|
||||
<p>The %code directive is used to specify addition C code that
|
||||
is added to the end of the main output file. This is similar to
|
||||
the %include directive except that %include is inserted at the
|
||||
beginning of the main output file.</p>
|
||||
the <a href='#pinclude'>%include</a> directive except that %include
|
||||
is inserted at the beginning of the main output file.</p>
|
||||
|
||||
<p>%code is typically used to include some action routines or perhaps
|
||||
a tokenizer as part of the output file.</p>
|
||||
a tokenizer or even the "main()" function
|
||||
as part of the output file.</p>
|
||||
|
||||
<a name='default_destructor'></a>
|
||||
<h4>The <tt>%default_destructor</tt> directive</h4>
|
||||
|
||||
<p>The %default_destructor directive specifies a destructor to
|
||||
use for non-terminals that do not have their own destructor
|
||||
specified by a separate %destructor directive. See the documentation
|
||||
on the %destructor directive below for additional information.</p>
|
||||
on the <a name='#destructor'>%destructor</a> directive below for
|
||||
additional information.</p>
|
||||
|
||||
<p>In some grammers, many different non-terminal symbols have the
|
||||
same datatype and hence the same destructor. This directive is
|
||||
a convenience way to specify the same destructor for all those
|
||||
non-terminals using a single statement.</p>
|
||||
|
||||
<a name='default_type'></a>
|
||||
<h4>The <tt>%default_type</tt> directive</h4>
|
||||
|
||||
<p>The %default_type directive specifies the datatype of non-terminal
|
||||
symbols that do no have their own datatype defined using a separate
|
||||
%type directive. See the documentation on %type below for addition
|
||||
information.</p>
|
||||
<a href='#ptype'>%type</a> directive.
|
||||
</p>
|
||||
|
||||
<a name='destructor'></a>
|
||||
<h4>The <tt>%destructor</tt> directive</h4>
|
||||
|
||||
<p>The %destructor directive is used to specify a destructor for
|
||||
a non-terminal symbol.
|
||||
(See also the %token_destructor directive which is used to
|
||||
specify a destructor for terminal symbols.)</p>
|
||||
(See also the <a href='#token_destructor'>%token_destructor</a>
|
||||
directive which is used to specify a destructor for terminal symbols.)</p>
|
||||
|
||||
<p>A non-terminal's destructor is called to dispose of the
|
||||
non-terminal's value whenever the non-terminal is popped from
|
||||
@@ -602,26 +617,25 @@ or other resources held by that non-terminal.</p>
|
||||
</pre>
|
||||
This example is a bit contrived but it serves to illustrate how
|
||||
destructors work. The example shows a non-terminal named
|
||||
``nt'' that holds values of type ``void*''. When the rule for
|
||||
an ``nt'' reduces, it sets the value of the non-terminal to
|
||||
"nt" that holds values of type "void*". When the rule for
|
||||
an "nt" reduces, it sets the value of the non-terminal to
|
||||
space obtained from malloc(). Later, when the nt non-terminal
|
||||
is popped from the stack, the destructor will fire and call
|
||||
free() on this malloced space, thus avoiding a memory leak.
|
||||
(Note that the symbol ``$$'' in the destructor code is replaced
|
||||
(Note that the symbol "$$" in the destructor code is replaced
|
||||
by the value of the non-terminal.)</p>
|
||||
|
||||
<p>It is important to note that the value of a non-terminal is passed
|
||||
to the destructor whenever the non-terminal is removed from the
|
||||
stack, unless the non-terminal is used in a C-code action. If
|
||||
the non-terminal is used by C-code, then it is assumed that the
|
||||
C-code will take care of destroying it if it should really
|
||||
be destroyed. More commonly, the value is used to build some
|
||||
C-code will take care of destroying it.
|
||||
More commonly, the value is used to build some
|
||||
larger structure and we don't want to destroy it, which is why
|
||||
the destructor is not called in this circumstance.</p>
|
||||
|
||||
<p>By appropriate use of destructors, it is possible to
|
||||
build a parser using Lemon that can be used within a long-running
|
||||
program, such as a GUI, that will not leak memory or other resources.
|
||||
<p>Destructors help avoid memory leaks by automatically freeing
|
||||
allocated objects when they go out of scope.
|
||||
To do the same using yacc or bison is much more difficult.</p>
|
||||
|
||||
<a name="extraarg"></a>
|
||||
@@ -638,17 +652,66 @@ and so forth. For example, if the grammar file contains:</p>
|
||||
</pre></p>
|
||||
|
||||
<p>Then the Parse() function generated will have an 4th parameter
|
||||
of type ``MyStruct*'' and all action routines will have access to
|
||||
a variable named ``pAbc'' that is the value of the 4th parameter
|
||||
of type "MyStruct*" and all action routines will have access to
|
||||
a variable named "pAbc" that is the value of the 4th parameter
|
||||
in the most recent call to Parse().</p>
|
||||
|
||||
<a name='pfallback'></a>
|
||||
<h4>The <tt>%fallback</tt> directive</h4>
|
||||
|
||||
<p>The %fallback directive specifies an alternative meaning for one
|
||||
or more tokens. The alternative meaning is tried if the original token
|
||||
would have generated a syntax error.
|
||||
|
||||
<p>The %fallback directive was added to support robust parsing of SQL
|
||||
syntax in <a href="https://www.sqlite.org/">SQLite</a>.
|
||||
The SQL language contains a large assortment of keywords, each of which
|
||||
appears as a different token to the language parser. SQL contains so
|
||||
many keywords, that it can be difficult for programmers to keep up with
|
||||
them all. Programmers will, therefore, sometimes mistakenly use an
|
||||
obscure language keyword for an identifier. The %fallback directive
|
||||
provides a mechanism to tell the parser: "If you are unable to parse
|
||||
this keyword, try treating it as an identifier instead."
|
||||
|
||||
<p>The syntax of %fallback is as follows:
|
||||
|
||||
<blockquote>
|
||||
<tt>%fallback</tt> <i>ID</i> <i>TOKEN...</i> <b>.</b>
|
||||
</blockquote>
|
||||
|
||||
<p>In words, the %fallback directive is followed by a list of token names
|
||||
terminated by a period. The first token name is the fallback token - the
|
||||
token to which all the other tokens fall back to. The second and subsequent
|
||||
arguments are tokens which fall back to the token identified by the first
|
||||
argument.
|
||||
|
||||
<a name='pifdef'></a>
|
||||
<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives.</h4>
|
||||
|
||||
<p>The %ifdef, %ifndef, and %endif directives are similar to
|
||||
#ifdef, #ifndef, and #endif in the C-preprocessor, just not as general.
|
||||
Each of these directives must begin at the left margin. No whitespace
|
||||
is allowed between the "%" and the directive name.
|
||||
|
||||
<p>Grammar text in between "%ifdef MACRO" and the next nested "%endif" is
|
||||
ignored unless the "-DMACRO" command-line option is used. Grammar text
|
||||
betwen "%ifndef MACRO" and the next nested "%endif" is included except when
|
||||
the "-DMACRO" command-line option is used.
|
||||
|
||||
<p>Note that the argument to %ifdef and %ifndef must be a single
|
||||
preprocessor symbol name, not a general expression. There is no "%else"
|
||||
directive.
|
||||
|
||||
|
||||
<a name='pinclude'></a>
|
||||
<h4>The <tt>%include</tt> directive</h4>
|
||||
|
||||
<p>The %include directive specifies C code that is included at the
|
||||
top of the generated parser. You can include any text you want --
|
||||
the Lemon parser generator copies it blindly. If you have multiple
|
||||
%include directives in your grammar file the value of the last
|
||||
%include directive overwrites all the others.</p.
|
||||
%include directives in your grammar file, their values are concatenated
|
||||
so that all %include code ultimately appears near the top of the
|
||||
generated parser, in the same order as it appeared in the grammer.</p>
|
||||
|
||||
<p>The %include directive is very handy for getting some extra #include
|
||||
preprocessor statements at the beginning of the generated parser.
|
||||
@@ -661,12 +724,13 @@ For example:</p>
|
||||
<p>This might be needed, for example, if some of the C actions in the
|
||||
grammar call functions that are prototyed in unistd.h.</p>
|
||||
|
||||
<a name='pleft'></a>
|
||||
<h4>The <tt>%left</tt> directive</h4>
|
||||
|
||||
The %left directive is used (along with the %right and
|
||||
%nonassoc directives) to declare precedences of terminal
|
||||
symbols. Every terminal symbol whose name appears after
|
||||
a %left directive but before the next period (``.'') is
|
||||
The %left directive is used (along with the <a href='#pright'>%right</a> and
|
||||
<a href='#pnonassoc'>%nonassoc</a> directives) to declare precedences of
|
||||
terminal symbols. Every terminal symbol whose name appears after
|
||||
a %left directive but before the next period (".") is
|
||||
given the same left-associative precedence value. Subsequent
|
||||
%left directives have higher precedence. For example:</p>
|
||||
|
||||
@@ -687,10 +751,11 @@ a large amount of stack space if you make heavy use or right-associative
|
||||
operators. For this reason, it is recommended that you use %left
|
||||
rather than %right whenever possible.</p>
|
||||
|
||||
<a name='pname'></a>
|
||||
<h4>The <tt>%name</tt> directive</h4>
|
||||
|
||||
<p>By default, the functions generated by Lemon all begin with the
|
||||
five-character string ``Parse''. You can change this string to something
|
||||
five-character string "Parse". You can change this string to something
|
||||
different using the %name directive. For instance:</p>
|
||||
|
||||
<p><pre>
|
||||
@@ -709,16 +774,19 @@ The %name directive allows you to generator two or more different
|
||||
parsers and link them all into the same executable.
|
||||
</p>
|
||||
|
||||
<a name='pnonassoc'></a>
|
||||
<h4>The <tt>%nonassoc</tt> directive</h4>
|
||||
|
||||
<p>This directive is used to assign non-associative precedence to
|
||||
one or more terminal symbols. See the section on precedence rules
|
||||
or on the %left directive for additional information.</p>
|
||||
one or more terminal symbols. See the section on
|
||||
<a href='#precrules'>precedence rules</a>
|
||||
or on the <a href='#pleft'>%left</a> directive for additional information.</p>
|
||||
|
||||
<a name='parse_accept'></a>
|
||||
<h4>The <tt>%parse_accept</tt> directive</h4>
|
||||
|
||||
<p>The %parse_accept directive specifies a block of C code that is
|
||||
executed whenever the parser accepts its input string. To ``accept''
|
||||
executed whenever the parser accepts its input string. To "accept"
|
||||
an input string means that the parser was able to process all tokens
|
||||
without error.</p>
|
||||
|
||||
@@ -730,7 +798,7 @@ without error.</p>
|
||||
}
|
||||
</pre></p>
|
||||
|
||||
|
||||
<a name='parse_failure'></a>
|
||||
<h4>The <tt>%parse_failure</tt> directive</h4>
|
||||
|
||||
<p>The %parse_failure directive specifies a block of C code that
|
||||
@@ -745,12 +813,15 @@ only invoked when parsing is unable to continue.</p>
|
||||
}
|
||||
</pre></p>
|
||||
|
||||
<a name='pright'></a>
|
||||
<h4>The <tt>%right</tt> directive</h4>
|
||||
|
||||
<p>This directive is used to assign right-associative precedence to
|
||||
one or more terminal symbols. See the section on precedence rules
|
||||
or on the %left directive for additional information.</p>
|
||||
one or more terminal symbols. See the section on
|
||||
<a href='#precrules'>precedence rules</a>
|
||||
or on the <a href='#pleft'>%left</a> directive for additional information.</p>
|
||||
|
||||
<a name='stack_overflow'></a>
|
||||
<h4>The <tt>%stack_overflow</tt> directive</h4>
|
||||
|
||||
<p>The %stack_overflow directive specifies a block of C code that
|
||||
@@ -779,6 +850,7 @@ Not like this:
|
||||
list ::= .
|
||||
</pre>
|
||||
|
||||
<a name='stack_size'></a>
|
||||
<h4>The <tt>%stack_size</tt> directive</h4>
|
||||
|
||||
<p>If stack overflow is a problem and you can't resolve the trouble
|
||||
@@ -791,6 +863,7 @@ with a stack of the requested size. The default value is 100.</p>
|
||||
%stack_size 2000
|
||||
</pre></p>
|
||||
|
||||
<a name='start_symbol'></a>
|
||||
<h4>The <tt>%start_symbol</tt> directive</h4>
|
||||
|
||||
<p>By default, the start-symbol for the grammar that Lemon generates
|
||||
@@ -801,6 +874,7 @@ can choose a different start-symbol using the %start_symbol directive.</p>
|
||||
%start_symbol prog
|
||||
</pre></p>
|
||||
|
||||
<a name='token_destructor'></a>
|
||||
<h4>The <tt>%token_destructor</tt> directive</h4>
|
||||
|
||||
<p>The %destructor directive assigns a destructor to a non-terminal
|
||||
@@ -813,6 +887,7 @@ the %token_type directive) and so they use a common destructor. Other
|
||||
than that, the token destructor works just like the non-terminal
|
||||
destructors.</p>
|
||||
|
||||
<a name='token_prefix'></a>
|
||||
<h4>The <tt>%token_prefix</tt> directive</h4>
|
||||
|
||||
<p>Lemon generates #defines that assign small integer constants
|
||||
@@ -838,6 +913,7 @@ to cause Lemon to produce these symbols instead:
|
||||
#define TOKEN_PLUS 4
|
||||
</pre>
|
||||
|
||||
<a name='token_type'></a><a name='ptype'></a>
|
||||
<h4>The <tt>%token_type</tt> and <tt>%type</tt> directives</h4>
|
||||
|
||||
<p>These directives are used to specify the data types for values
|
||||
@@ -853,7 +929,7 @@ token structure. Like this:</p>
|
||||
</pre></p>
|
||||
|
||||
<p>If the data type of terminals is not specified, the default value
|
||||
is ``int''.</p>
|
||||
is "int".</p>
|
||||
|
||||
<p>Non-terminal symbols can each have their own data types. Typically
|
||||
the data type of a non-terminal is a pointer to the root of a parse-tree
|
||||
@@ -874,6 +950,17 @@ non-terminal whose data type requires 1K of storage, then your 100
|
||||
entry parser stack will require 100K of heap space. If you are willing
|
||||
and able to pay that price, fine. You just need to know.</p>
|
||||
|
||||
<a name='pwildcard'></a>
|
||||
<h4>The <tt>%wildcard</tt> directive</h4>
|
||||
|
||||
<p>The %wildcard directive is followed by a single token name and a
|
||||
period. This directive specifies that the identified token should
|
||||
match any input token.
|
||||
|
||||
<p>When the generated parser has the choice of matching an input against
|
||||
the wildcard token and some other token, the other token is always used.
|
||||
The wildcard token is only matched if there are no other alternatives.
|
||||
|
||||
<h3>Error Processing</h3>
|
||||
|
||||
<p>After extensive experimentation over several years, it has been
|
||||
@@ -885,7 +972,7 @@ first invokes the code specified by the %syntax_error directive, if
|
||||
any. It then enters its error recovery strategy. The error recovery
|
||||
strategy is to begin popping the parsers stack until it enters a
|
||||
state where it is permitted to shift a special non-terminal symbol
|
||||
named ``error''. It then shifts this non-terminal and continues
|
||||
named "error". It then shifts this non-terminal and continues
|
||||
parsing. But the %syntax_error routine will not be called again
|
||||
until at least three new tokens have been successfully shifted.</p>
|
||||
|
||||
@@ -894,7 +981,7 @@ is unable to shift the error symbol, then the %parse_failed routine
|
||||
is invoked and the parser resets itself to its start state, ready
|
||||
to begin parsing a new file. This is what will happen at the very
|
||||
first syntax error, of course, if there are no instances of the
|
||||
``error'' non-terminal in your grammar.</p>
|
||||
"error" non-terminal in your grammar.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3195,7 +3195,7 @@ static int fts3SegmentMerge(
|
||||
** segment. The level of the new segment is equal to the numerically
|
||||
** greatest segment level currently present in the database for this
|
||||
** index. The idx of the new segment is always 0. */
|
||||
if( csr.nSegment==1 ){
|
||||
if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){
|
||||
rc = SQLITE_DONE;
|
||||
goto finished;
|
||||
}
|
||||
@@ -4840,11 +4840,8 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin));
|
||||
if( sqlite3_step(pFindLevel)==SQLITE_ROW ){
|
||||
iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
|
||||
if( nMin<2 ){
|
||||
nSeg = sqlite3_column_int(pFindLevel, 1);
|
||||
}else{
|
||||
nSeg = nMin;
|
||||
}
|
||||
nSeg = sqlite3_column_int(pFindLevel, 1);
|
||||
assert( nSeg>=2 );
|
||||
}else{
|
||||
nSeg = -1;
|
||||
}
|
||||
@@ -4996,7 +4993,7 @@ static int fts3DoIncrmerge(
|
||||
nMin = fts3Getint(&z);
|
||||
}
|
||||
|
||||
if( z[0]!='\0' || nMin<0 || nMin==1 ){
|
||||
if( z[0]!='\0' || nMin<2 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
|
||||
@@ -47,6 +47,10 @@ typedef sqlite3_uint64 u64;
|
||||
|
||||
#endif
|
||||
|
||||
/* Truncate very long tokens to this many bytes. Hard limit is
|
||||
** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
|
||||
** field that occurs at the start of each leaf page (see fts5_index.c). */
|
||||
#define FTS5_MAX_TOKEN_SIZE 32768
|
||||
|
||||
/*
|
||||
** Maximum number of prefix indexes on single FTS5 table. This must be
|
||||
@@ -172,6 +176,7 @@ struct Fts5Config {
|
||||
int pgsz; /* Approximate page size used in %_data */
|
||||
int nAutomerge; /* 'automerge' setting */
|
||||
int nCrisisMerge; /* Maximum allowed segments per level */
|
||||
int nUsermerge; /* 'usermerge' setting */
|
||||
int nHashSize; /* Bytes of memory for in-memory hash */
|
||||
char *zRank; /* Name of rank function */
|
||||
char *zRankArgs; /* Arguments to rank function */
|
||||
@@ -479,6 +484,7 @@ int sqlite3Fts5IndexReads(Fts5Index *p);
|
||||
int sqlite3Fts5IndexReinit(Fts5Index *p);
|
||||
int sqlite3Fts5IndexOptimize(Fts5Index *p);
|
||||
int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
|
||||
int sqlite3Fts5IndexReset(Fts5Index *p);
|
||||
|
||||
int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
|
||||
|
||||
@@ -621,6 +627,7 @@ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
|
||||
int sqlite3Fts5StorageRebuild(Fts5Storage *p);
|
||||
int sqlite3Fts5StorageOptimize(Fts5Storage *p);
|
||||
int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
|
||||
int sqlite3Fts5StorageReset(Fts5Storage *p);
|
||||
|
||||
/*
|
||||
** End of interface to code in fts5_storage.c.
|
||||
@@ -700,6 +707,12 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
|
||||
Fts5ExprNearset *pNear
|
||||
);
|
||||
|
||||
Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
||||
Fts5Parse *pParse,
|
||||
Fts5ExprNode *pLeft,
|
||||
Fts5ExprNode *pRight
|
||||
);
|
||||
|
||||
Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
Fts5Parse *pParse,
|
||||
Fts5ExprPhrase *pPhrase,
|
||||
|
||||
+17
-1
@@ -18,6 +18,7 @@
|
||||
|
||||
#define FTS5_DEFAULT_PAGE_SIZE 4050
|
||||
#define FTS5_DEFAULT_AUTOMERGE 4
|
||||
#define FTS5_DEFAULT_USERMERGE 4
|
||||
#define FTS5_DEFAULT_CRISISMERGE 16
|
||||
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
|
||||
|
||||
@@ -441,7 +442,9 @@ static const char *fts5ConfigGobbleWord(
|
||||
*pbQuoted = 1;
|
||||
}else{
|
||||
zRet = fts5ConfigSkipBareword(zIn);
|
||||
zOut[zRet-zIn] = '\0';
|
||||
if( zRet ){
|
||||
zOut[zRet-zIn] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,6 +860,18 @@ int sqlite3Fts5ConfigSetValue(
|
||||
}
|
||||
}
|
||||
|
||||
else if( 0==sqlite3_stricmp(zKey, "usermerge") ){
|
||||
int nUsermerge = -1;
|
||||
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
|
||||
nUsermerge = sqlite3_value_int(pVal);
|
||||
}
|
||||
if( nUsermerge<2 || nUsermerge>16 ){
|
||||
*pbBadkey = 1;
|
||||
}else{
|
||||
pConfig->nUsermerge = nUsermerge;
|
||||
}
|
||||
}
|
||||
|
||||
else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){
|
||||
int nCrisisMerge = -1;
|
||||
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
|
||||
@@ -903,6 +918,7 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
|
||||
/* Set default values */
|
||||
pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE;
|
||||
pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE;
|
||||
pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
|
||||
pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
|
||||
pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
|
||||
|
||||
|
||||
+134
-37
@@ -258,6 +258,8 @@ int sqlite3Fts5ExprNew(
|
||||
pNew->nPhrase = sParse.nPhrase;
|
||||
sParse.apPhrase = 0;
|
||||
}
|
||||
}else{
|
||||
sqlite3Fts5ParseNodeFree(sParse.pExpr);
|
||||
}
|
||||
|
||||
sqlite3_free(sParse.apPhrase);
|
||||
@@ -1268,6 +1270,8 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
|
||||
if( Fts5NodeIsString(pNode) ){
|
||||
/* Initialize all term iterators in the NEAR object. */
|
||||
rc = fts5ExprNearInitAll(pExpr, pNode);
|
||||
}else if( pNode->xNext==0 ){
|
||||
pNode->bEof = 1;
|
||||
}else{
|
||||
int i;
|
||||
int nEof = 0;
|
||||
@@ -1319,23 +1323,22 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
|
||||
*/
|
||||
int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
|
||||
Fts5ExprNode *pRoot = p->pRoot;
|
||||
int rc = SQLITE_OK;
|
||||
if( pRoot->xNext ){
|
||||
p->pIndex = pIdx;
|
||||
p->bDesc = bDesc;
|
||||
rc = fts5ExprNodeFirst(p, pRoot);
|
||||
int rc; /* Return code */
|
||||
|
||||
/* If not at EOF but the current rowid occurs earlier than iFirst in
|
||||
** the iteration order, move to document iFirst or later. */
|
||||
if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){
|
||||
rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
|
||||
}
|
||||
p->pIndex = pIdx;
|
||||
p->bDesc = bDesc;
|
||||
rc = fts5ExprNodeFirst(p, pRoot);
|
||||
|
||||
/* If the iterator is not at a real match, skip forward until it is. */
|
||||
while( pRoot->bNomatch ){
|
||||
assert( pRoot->bEof==0 && rc==SQLITE_OK );
|
||||
rc = fts5ExprNodeNext(p, pRoot, 0, 0);
|
||||
}
|
||||
/* If not at EOF but the current rowid occurs earlier than iFirst in
|
||||
** the iteration order, move to document iFirst or later. */
|
||||
if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){
|
||||
rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
|
||||
}
|
||||
|
||||
/* If the iterator is not at a real match, skip forward until it is. */
|
||||
while( pRoot->bNomatch ){
|
||||
assert( pRoot->bEof==0 && rc==SQLITE_OK );
|
||||
rc = fts5ExprNodeNext(p, pRoot, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -1444,6 +1447,21 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
||||
sqlite3Fts5ParseNearsetFree(pNear);
|
||||
sqlite3Fts5ParsePhraseFree(pPhrase);
|
||||
}else{
|
||||
if( pRet->nPhrase>0 ){
|
||||
Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1];
|
||||
assert( pLast==pParse->apPhrase[pParse->nPhrase-2] );
|
||||
if( pPhrase->nTerm==0 ){
|
||||
fts5ExprPhraseFree(pPhrase);
|
||||
pRet->nPhrase--;
|
||||
pParse->nPhrase--;
|
||||
pPhrase = pLast;
|
||||
}else if( pLast->nTerm==0 ){
|
||||
fts5ExprPhraseFree(pLast);
|
||||
pParse->apPhrase[pParse->nPhrase-2] = pPhrase;
|
||||
pParse->nPhrase--;
|
||||
pRet->nPhrase--;
|
||||
}
|
||||
}
|
||||
pRet->apPhrase[pRet->nPhrase++] = pPhrase;
|
||||
}
|
||||
return pRet;
|
||||
@@ -1475,9 +1493,9 @@ static int fts5ParseTokenize(
|
||||
|
||||
/* If an error has already occurred, this is a no-op */
|
||||
if( pCtx->rc!=SQLITE_OK ) return pCtx->rc;
|
||||
if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
|
||||
|
||||
assert( pPhrase==0 || pPhrase->nTerm>0 );
|
||||
if( pPhrase && (tflags & FTS5_TOKEN_COLOCATED) ){
|
||||
if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
|
||||
Fts5ExprTerm *pSyn;
|
||||
int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
|
||||
pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
|
||||
@@ -1578,7 +1596,7 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
pParse->rc = rc;
|
||||
fts5ExprPhraseFree(sCtx.pPhrase);
|
||||
sCtx.pPhrase = 0;
|
||||
}else if( sCtx.pPhrase ){
|
||||
}else{
|
||||
|
||||
if( pAppend==0 ){
|
||||
if( (pParse->nPhrase % 8)==0 ){
|
||||
@@ -1595,9 +1613,14 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
pParse->nPhrase++;
|
||||
}
|
||||
|
||||
if( sCtx.pPhrase==0 ){
|
||||
/* This happens when parsing a token or quoted phrase that contains
|
||||
** no token characters at all. (e.g ... MATCH '""'). */
|
||||
sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
|
||||
}else if( sCtx.pPhrase->nTerm ){
|
||||
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
|
||||
}
|
||||
pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
|
||||
assert( sCtx.pPhrase->nTerm>0 );
|
||||
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
|
||||
}
|
||||
|
||||
return sCtx.pPhrase;
|
||||
@@ -1693,23 +1716,25 @@ void sqlite3Fts5ParseSetDistance(
|
||||
Fts5ExprNearset *pNear,
|
||||
Fts5Token *p
|
||||
){
|
||||
int nNear = 0;
|
||||
int i;
|
||||
if( p->n ){
|
||||
for(i=0; i<p->n; i++){
|
||||
char c = (char)p->p[i];
|
||||
if( c<'0' || c>'9' ){
|
||||
sqlite3Fts5ParseError(
|
||||
pParse, "expected integer, got \"%.*s\"", p->n, p->p
|
||||
);
|
||||
return;
|
||||
if( pNear ){
|
||||
int nNear = 0;
|
||||
int i;
|
||||
if( p->n ){
|
||||
for(i=0; i<p->n; i++){
|
||||
char c = (char)p->p[i];
|
||||
if( c<'0' || c>'9' ){
|
||||
sqlite3Fts5ParseError(
|
||||
pParse, "expected integer, got \"%.*s\"", p->n, p->p
|
||||
);
|
||||
return;
|
||||
}
|
||||
nNear = nNear * 10 + (p->p[i] - '0');
|
||||
}
|
||||
nNear = nNear * 10 + (p->p[i] - '0');
|
||||
}else{
|
||||
nNear = FTS5_DEFAULT_NEARDIST;
|
||||
}
|
||||
}else{
|
||||
nNear = FTS5_DEFAULT_NEARDIST;
|
||||
pNear->nNear = nNear;
|
||||
}
|
||||
pNear->nNear = nNear;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1896,10 +1921,14 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
|
||||
int iPhrase;
|
||||
for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
|
||||
pNear->apPhrase[iPhrase]->pNode = pRet;
|
||||
if( pNear->apPhrase[iPhrase]->nTerm==0 ){
|
||||
pRet->xNext = 0;
|
||||
pRet->eType = FTS5_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL
|
||||
&& (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm!=1)
|
||||
&& (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1)
|
||||
){
|
||||
assert( pParse->rc==SQLITE_OK );
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
@@ -1928,6 +1957,70 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
|
||||
return pRet;
|
||||
}
|
||||
|
||||
Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
||||
Fts5Parse *pParse, /* Parse context */
|
||||
Fts5ExprNode *pLeft, /* Left hand child expression */
|
||||
Fts5ExprNode *pRight /* Right hand child expression */
|
||||
){
|
||||
Fts5ExprNode *pRet = 0;
|
||||
Fts5ExprNode *pPrev;
|
||||
|
||||
if( pParse->rc ){
|
||||
sqlite3Fts5ParseNodeFree(pLeft);
|
||||
sqlite3Fts5ParseNodeFree(pRight);
|
||||
}else{
|
||||
|
||||
assert( pLeft->eType==FTS5_STRING
|
||||
|| pLeft->eType==FTS5_TERM
|
||||
|| pLeft->eType==FTS5_EOF
|
||||
|| pLeft->eType==FTS5_AND
|
||||
);
|
||||
assert( pRight->eType==FTS5_STRING
|
||||
|| pRight->eType==FTS5_TERM
|
||||
|| pRight->eType==FTS5_EOF
|
||||
);
|
||||
|
||||
if( pLeft->eType==FTS5_AND ){
|
||||
pPrev = pLeft->apChild[pLeft->nChild-1];
|
||||
}else{
|
||||
pPrev = pLeft;
|
||||
}
|
||||
assert( pPrev->eType==FTS5_STRING
|
||||
|| pPrev->eType==FTS5_TERM
|
||||
|| pPrev->eType==FTS5_EOF
|
||||
);
|
||||
|
||||
if( pRight->eType==FTS5_EOF ){
|
||||
assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
|
||||
sqlite3Fts5ParseNodeFree(pRight);
|
||||
pRet = pLeft;
|
||||
pParse->nPhrase--;
|
||||
}
|
||||
else if( pPrev->eType==FTS5_EOF ){
|
||||
Fts5ExprPhrase **ap;
|
||||
|
||||
if( pPrev==pLeft ){
|
||||
pRet = pRight;
|
||||
}else{
|
||||
pLeft->apChild[pLeft->nChild-1] = pRight;
|
||||
pRet = pLeft;
|
||||
}
|
||||
|
||||
ap = &pParse->apPhrase[pParse->nPhrase-1-pRight->pNear->nPhrase];
|
||||
assert( ap[0]==pPrev->pNear->apPhrase[0] );
|
||||
memmove(ap, &ap[1], sizeof(Fts5ExprPhrase*)*pRight->pNear->nPhrase);
|
||||
pParse->nPhrase--;
|
||||
|
||||
sqlite3Fts5ParseNodeFree(pPrev);
|
||||
}
|
||||
else{
|
||||
pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
|
||||
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
|
||||
int nByte = 0;
|
||||
Fts5ExprTerm *p;
|
||||
@@ -2062,6 +2155,9 @@ static char *fts5ExprPrintTcl(
|
||||
|
||||
static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
|
||||
char *zRet = 0;
|
||||
if( pExpr->eType==0 ){
|
||||
return sqlite3_mprintf("\"\"");
|
||||
}else
|
||||
if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
|
||||
Fts5ExprNearset *pNear = pExpr->pNear;
|
||||
int i;
|
||||
@@ -2122,7 +2218,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
|
||||
zRet = 0;
|
||||
}else{
|
||||
int e = pExpr->apChild[i]->eType;
|
||||
int b = (e!=FTS5_STRING && e!=FTS5_TERM);
|
||||
int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF);
|
||||
zRet = fts5PrintfAppend(zRet, "%s%s%z%s",
|
||||
(i==0 ? "" : zOp),
|
||||
(b?"(":""), z, (b?")":"")
|
||||
@@ -2400,12 +2496,13 @@ static int fts5ExprPopulatePoslistsCb(
|
||||
|
||||
UNUSED_PARAM2(iUnused1, iUnused2);
|
||||
|
||||
if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
|
||||
if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
|
||||
for(i=0; i<pExpr->nPhrase; i++){
|
||||
Fts5ExprTerm *pTerm;
|
||||
if( p->aPopulator[i].bOk==0 ) continue;
|
||||
for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
|
||||
int nTerm = strlen(pTerm->zTerm);
|
||||
int nTerm = (int)strlen(pTerm->zTerm);
|
||||
if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
|
||||
&& memcmp(pTerm->zTerm, pToken, nTerm)==0
|
||||
){
|
||||
|
||||
+243
-71
@@ -304,6 +304,10 @@ struct Fts5Index {
|
||||
sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */
|
||||
sqlite3_stmt *pIdxSelect;
|
||||
int nRead; /* Total number of blocks read */
|
||||
|
||||
sqlite3_stmt *pDataVersion;
|
||||
i64 iStructVersion; /* data_version when pStruct read */
|
||||
Fts5Structure *pStruct; /* Current db structure (or NULL) */
|
||||
};
|
||||
|
||||
struct Fts5DoclistIter {
|
||||
@@ -959,6 +963,50 @@ static void fts5StructureExtendLevel(
|
||||
}
|
||||
}
|
||||
|
||||
static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){
|
||||
Fts5Structure *pRet = 0;
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
int iCookie; /* Configuration cookie */
|
||||
Fts5Data *pData;
|
||||
|
||||
pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
/* TODO: Do we need this if the leaf-index is appended? Probably... */
|
||||
memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
|
||||
p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
|
||||
if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
|
||||
p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
|
||||
}
|
||||
fts5DataRelease(pData);
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
fts5StructureRelease(pRet);
|
||||
pRet = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
|
||||
static i64 fts5IndexDataVersion(Fts5Index *p){
|
||||
i64 iVersion = 0;
|
||||
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( p->pDataVersion==0 ){
|
||||
p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion,
|
||||
sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb)
|
||||
);
|
||||
if( p->rc ) return 0;
|
||||
}
|
||||
|
||||
if( SQLITE_ROW==sqlite3_step(p->pDataVersion) ){
|
||||
iVersion = sqlite3_column_int64(p->pDataVersion, 0);
|
||||
}
|
||||
p->rc = sqlite3_reset(p->pDataVersion);
|
||||
}
|
||||
|
||||
return iVersion;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read, deserialize and return the structure record.
|
||||
**
|
||||
@@ -971,26 +1019,49 @@ static void fts5StructureExtendLevel(
|
||||
** is called, it is a no-op.
|
||||
*/
|
||||
static Fts5Structure *fts5StructureRead(Fts5Index *p){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
Fts5Structure *pRet = 0; /* Object to return */
|
||||
int iCookie; /* Configuration cookie */
|
||||
Fts5Data *pData;
|
||||
|
||||
pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
|
||||
if( p->rc ) return 0;
|
||||
/* TODO: Do we need this if the leaf-index is appended? Probably... */
|
||||
memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
|
||||
p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
|
||||
if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
|
||||
p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
|
||||
if( p->pStruct==0 ){
|
||||
p->iStructVersion = fts5IndexDataVersion(p);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
p->pStruct = fts5StructureReadUncached(p);
|
||||
}
|
||||
}
|
||||
|
||||
fts5DataRelease(pData);
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
fts5StructureRelease(pRet);
|
||||
pRet = 0;
|
||||
#if 0
|
||||
else{
|
||||
Fts5Structure *pTest = fts5StructureReadUncached(p);
|
||||
if( pTest ){
|
||||
int i, j;
|
||||
assert_nc( p->pStruct->nSegment==pTest->nSegment );
|
||||
assert_nc( p->pStruct->nLevel==pTest->nLevel );
|
||||
for(i=0; i<pTest->nLevel; i++){
|
||||
assert_nc( p->pStruct->aLevel[i].nMerge==pTest->aLevel[i].nMerge );
|
||||
assert_nc( p->pStruct->aLevel[i].nSeg==pTest->aLevel[i].nSeg );
|
||||
for(j=0; j<pTest->aLevel[i].nSeg; j++){
|
||||
Fts5StructureSegment *p1 = &pTest->aLevel[i].aSeg[j];
|
||||
Fts5StructureSegment *p2 = &p->pStruct->aLevel[i].aSeg[j];
|
||||
assert_nc( p1->iSegid==p2->iSegid );
|
||||
assert_nc( p1->pgnoFirst==p2->pgnoFirst );
|
||||
assert_nc( p1->pgnoLast==p2->pgnoLast );
|
||||
}
|
||||
}
|
||||
fts5StructureRelease(pTest);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( p->rc!=SQLITE_OK ) return 0;
|
||||
assert( p->iStructVersion!=0 );
|
||||
assert( p->pStruct!=0 );
|
||||
fts5StructureRef(p->pStruct);
|
||||
return p->pStruct;
|
||||
}
|
||||
|
||||
static void fts5StructureInvalidate(Fts5Index *p){
|
||||
if( p->pStruct ){
|
||||
fts5StructureRelease(p->pStruct);
|
||||
p->pStruct = 0;
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2250,6 +2321,18 @@ static void fts5LeafSeek(
|
||||
fts5SegIterLoadNPos(p, pIter);
|
||||
}
|
||||
|
||||
static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){
|
||||
if( p->pIdxSelect==0 ){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
|
||||
"SELECT pgno FROM '%q'.'%q_idx' WHERE "
|
||||
"segid=? AND term<=? ORDER BY term DESC LIMIT 1",
|
||||
pConfig->zDb, pConfig->zName
|
||||
));
|
||||
}
|
||||
return p->pIdxSelect;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the object pIter to point to term pTerm/nTerm within segment
|
||||
** pSeg. If there is no such term in the index, the iterator is set to EOF.
|
||||
@@ -2267,6 +2350,7 @@ static void fts5SegIterSeekInit(
|
||||
int iPg = 1;
|
||||
int bGe = (flags & FTS5INDEX_QUERY_SCAN);
|
||||
int bDlidx = 0; /* True if there is a doclist-index */
|
||||
sqlite3_stmt *pIdxSelect = 0;
|
||||
|
||||
assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 );
|
||||
assert( pTerm && nTerm );
|
||||
@@ -2275,23 +2359,16 @@ static void fts5SegIterSeekInit(
|
||||
|
||||
/* This block sets stack variable iPg to the leaf page number that may
|
||||
** contain term (pTerm/nTerm), if it is present in the segment. */
|
||||
if( p->pIdxSelect==0 ){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
|
||||
"SELECT pgno FROM '%q'.'%q_idx' WHERE "
|
||||
"segid=? AND term<=? ORDER BY term DESC LIMIT 1",
|
||||
pConfig->zDb, pConfig->zName
|
||||
));
|
||||
}
|
||||
pIdxSelect = fts5IdxSelectStmt(p);
|
||||
if( p->rc ) return;
|
||||
sqlite3_bind_int(p->pIdxSelect, 1, pSeg->iSegid);
|
||||
sqlite3_bind_blob(p->pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
|
||||
if( SQLITE_ROW==sqlite3_step(p->pIdxSelect) ){
|
||||
i64 val = sqlite3_column_int(p->pIdxSelect, 0);
|
||||
sqlite3_bind_int(pIdxSelect, 1, pSeg->iSegid);
|
||||
sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
|
||||
if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){
|
||||
i64 val = sqlite3_column_int(pIdxSelect, 0);
|
||||
iPg = (int)(val>>1);
|
||||
bDlidx = (val & 0x0001);
|
||||
}
|
||||
p->rc = sqlite3_reset(p->pIdxSelect);
|
||||
p->rc = sqlite3_reset(pIdxSelect);
|
||||
|
||||
if( iPg<pSeg->pgnoFirst ){
|
||||
iPg = pSeg->pgnoFirst;
|
||||
@@ -3453,18 +3530,46 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
|
||||
if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){
|
||||
p->rc = SQLITE_FULL;
|
||||
}else{
|
||||
while( iSegid==0 ){
|
||||
int iLvl, iSeg;
|
||||
sqlite3_randomness(sizeof(u32), (void*)&iSegid);
|
||||
iSegid = iSegid & ((1 << FTS5_DATA_ID_B)-1);
|
||||
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
if( iSegid==pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ){
|
||||
iSegid = 0;
|
||||
}
|
||||
/* FTS5_MAX_SEGMENT is currently defined as 2000. So the following
|
||||
** array is 63 elements, or 252 bytes, in size. */
|
||||
u32 aUsed[(FTS5_MAX_SEGMENT+31) / 32];
|
||||
int iLvl, iSeg;
|
||||
int i;
|
||||
u32 mask;
|
||||
memset(aUsed, 0, sizeof(aUsed));
|
||||
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
|
||||
if( iId<=FTS5_MAX_SEGMENT ){
|
||||
aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; aUsed[i]==0xFFFFFFFF; i++);
|
||||
mask = aUsed[i];
|
||||
for(iSegid=0; mask & (1 << iSegid); iSegid++);
|
||||
iSegid += 1 + i*32;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
|
||||
}
|
||||
}
|
||||
assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
|
||||
|
||||
{
|
||||
sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
u8 aBlob[2] = {0xff, 0xff};
|
||||
sqlite3_bind_int(pIdxSelect, 1, iSegid);
|
||||
sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC);
|
||||
assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
|
||||
p->rc = sqlite3_reset(pIdxSelect);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3710,6 +3815,9 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
|
||||
Fts5PageWriter *pPage = &pWriter->writer;
|
||||
i64 iRowid;
|
||||
|
||||
static int nCall = 0;
|
||||
nCall++;
|
||||
|
||||
assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) );
|
||||
|
||||
/* Set the szLeaf header field. */
|
||||
@@ -3909,7 +4017,9 @@ static void fts5WriteFinish(
|
||||
fts5WriteFlushLeaf(p, pWriter);
|
||||
}
|
||||
*pnLeaf = pLeaf->pgno-1;
|
||||
fts5WriteFlushBtree(p, pWriter);
|
||||
if( pLeaf->pgno>1 ){
|
||||
fts5WriteFlushBtree(p, pWriter);
|
||||
}
|
||||
}
|
||||
fts5BufferFree(&pLeaf->term);
|
||||
fts5BufferFree(&pLeaf->buf);
|
||||
@@ -4179,13 +4289,17 @@ static void fts5IndexMergeLevel(
|
||||
|
||||
/*
|
||||
** Do up to nPg pages of automerge work on the index.
|
||||
**
|
||||
** Return true if any changes were actually made, or false otherwise.
|
||||
*/
|
||||
static void fts5IndexMerge(
|
||||
static int fts5IndexMerge(
|
||||
Fts5Index *p, /* FTS5 backend object */
|
||||
Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */
|
||||
int nPg /* Pages of work to do */
|
||||
int nPg, /* Pages of work to do */
|
||||
int nMin /* Minimum number of segments to merge */
|
||||
){
|
||||
int nRem = nPg;
|
||||
int bRet = 0;
|
||||
Fts5Structure *pStruct = *ppStruct;
|
||||
while( nRem>0 && p->rc==SQLITE_OK ){
|
||||
int iLvl; /* To iterate through levels */
|
||||
@@ -4216,17 +4330,17 @@ static void fts5IndexMerge(
|
||||
}
|
||||
#endif
|
||||
|
||||
if( nBest<p->pConfig->nAutomerge
|
||||
&& pStruct->aLevel[iBestLvl].nMerge==0
|
||||
){
|
||||
if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
|
||||
break;
|
||||
}
|
||||
bRet = 1;
|
||||
fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
|
||||
if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
|
||||
fts5StructurePromote(p, iBestLvl+1, pStruct);
|
||||
}
|
||||
}
|
||||
*ppStruct = pStruct;
|
||||
return bRet;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4254,7 +4368,7 @@ static void fts5IndexAutomerge(
|
||||
pStruct->nWriteCounter += nLeaf;
|
||||
nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel);
|
||||
|
||||
fts5IndexMerge(p, ppStruct, nRem);
|
||||
fts5IndexMerge(p, ppStruct, nRem, p->pConfig->nAutomerge);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4324,6 +4438,7 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
** for the new level-0 segment. */
|
||||
pStruct = fts5StructureRead(p);
|
||||
iSegid = fts5AllocateSegid(p, pStruct);
|
||||
fts5StructureInvalidate(p);
|
||||
|
||||
if( iSegid ){
|
||||
const int pgsz = p->pConfig->pgsz;
|
||||
@@ -4474,28 +4589,41 @@ static void fts5IndexFlush(Fts5Index *p){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sqlite3Fts5IndexOptimize(Fts5Index *p){
|
||||
Fts5Structure *pStruct;
|
||||
static Fts5Structure *fts5IndexOptimizeStruct(
|
||||
Fts5Index *p,
|
||||
Fts5Structure *pStruct
|
||||
){
|
||||
Fts5Structure *pNew = 0;
|
||||
int nSeg = 0;
|
||||
int nByte = sizeof(Fts5Structure);
|
||||
int nSeg = pStruct->nSegment;
|
||||
int i;
|
||||
|
||||
assert( p->rc==SQLITE_OK );
|
||||
fts5IndexFlush(p);
|
||||
pStruct = fts5StructureRead(p);
|
||||
|
||||
if( pStruct ){
|
||||
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
|
||||
nSeg = pStruct->nSegment;
|
||||
if( nSeg>1 ){
|
||||
int nByte = sizeof(Fts5Structure);
|
||||
nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
|
||||
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
|
||||
/* Figure out if this structure requires optimization. A structure does
|
||||
** not require optimization if either:
|
||||
**
|
||||
** + it consists of fewer than two segments, or
|
||||
** + all segments are on the same level, or
|
||||
** + all segments except one are currently inputs to a merge operation.
|
||||
**
|
||||
** In the first case, return NULL. In the second, increment the ref-count
|
||||
** on *pStruct and return a copy of the pointer to it.
|
||||
*/
|
||||
if( nSeg<2 ) return 0;
|
||||
for(i=0; i<pStruct->nLevel; i++){
|
||||
int nThis = pStruct->aLevel[i].nSeg;
|
||||
if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
|
||||
fts5StructureRef(pStruct);
|
||||
return pStruct;
|
||||
}
|
||||
assert( pStruct->aLevel[i].nMerge<=nThis );
|
||||
}
|
||||
|
||||
nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
|
||||
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
|
||||
|
||||
if( pNew ){
|
||||
Fts5StructureLevel *pLvl;
|
||||
int nByte = nSeg * sizeof(Fts5StructureSegment);
|
||||
nByte = nSeg * sizeof(Fts5StructureSegment);
|
||||
pNew->nLevel = pStruct->nLevel+1;
|
||||
pNew->nRef = 1;
|
||||
pNew->nWriteCounter = pStruct->nWriteCounter;
|
||||
@@ -4520,8 +4648,27 @@ int sqlite3Fts5IndexOptimize(Fts5Index *p){
|
||||
}
|
||||
}
|
||||
|
||||
return pNew;
|
||||
}
|
||||
|
||||
int sqlite3Fts5IndexOptimize(Fts5Index *p){
|
||||
Fts5Structure *pStruct;
|
||||
Fts5Structure *pNew = 0;
|
||||
|
||||
assert( p->rc==SQLITE_OK );
|
||||
fts5IndexFlush(p);
|
||||
pStruct = fts5StructureRead(p);
|
||||
fts5StructureInvalidate(p);
|
||||
|
||||
if( pStruct ){
|
||||
pNew = fts5IndexOptimizeStruct(p, pStruct);
|
||||
}
|
||||
fts5StructureRelease(pStruct);
|
||||
|
||||
assert( pNew==0 || pNew->nSegment>0 );
|
||||
if( pNew ){
|
||||
int iLvl = pNew->nLevel-1;
|
||||
int iLvl;
|
||||
for(iLvl=0; pNew->aLevel[iLvl].nSeg==0; iLvl++){}
|
||||
while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){
|
||||
int nRem = FTS5_OPT_WORK_UNIT;
|
||||
fts5IndexMergeLevel(p, &pNew, iLvl, &nRem);
|
||||
@@ -4531,20 +4678,32 @@ int sqlite3Fts5IndexOptimize(Fts5Index *p){
|
||||
fts5StructureRelease(pNew);
|
||||
}
|
||||
|
||||
fts5StructureRelease(pStruct);
|
||||
return fts5IndexReturn(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called to implement the special "VALUES('merge', $nMerge)"
|
||||
** INSERT command.
|
||||
*/
|
||||
int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
|
||||
Fts5Structure *pStruct;
|
||||
|
||||
pStruct = fts5StructureRead(p);
|
||||
if( pStruct && pStruct->nLevel ){
|
||||
fts5IndexMerge(p, &pStruct, nMerge);
|
||||
fts5StructureWrite(p, pStruct);
|
||||
Fts5Structure *pStruct = fts5StructureRead(p);
|
||||
if( pStruct ){
|
||||
int nMin = p->pConfig->nUsermerge;
|
||||
fts5StructureInvalidate(p);
|
||||
if( nMerge<0 ){
|
||||
Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
|
||||
fts5StructureRelease(pStruct);
|
||||
pStruct = pNew;
|
||||
nMin = 2;
|
||||
nMerge = nMerge*-1;
|
||||
}
|
||||
if( pStruct && pStruct->nLevel ){
|
||||
if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
|
||||
fts5StructureWrite(p, pStruct);
|
||||
}
|
||||
}
|
||||
fts5StructureRelease(pStruct);
|
||||
}
|
||||
fts5StructureRelease(pStruct);
|
||||
|
||||
return fts5IndexReturn(p);
|
||||
}
|
||||
|
||||
@@ -4958,6 +5117,7 @@ int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
|
||||
int sqlite3Fts5IndexRollback(Fts5Index *p){
|
||||
fts5CloseReader(p);
|
||||
fts5IndexDiscardData(p);
|
||||
fts5StructureInvalidate(p);
|
||||
/* assert( p->rc==SQLITE_OK ); */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -4969,6 +5129,7 @@ int sqlite3Fts5IndexRollback(Fts5Index *p){
|
||||
*/
|
||||
int sqlite3Fts5IndexReinit(Fts5Index *p){
|
||||
Fts5Structure s;
|
||||
fts5StructureInvalidate(p);
|
||||
memset(&s, 0, sizeof(Fts5Structure));
|
||||
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
|
||||
fts5StructureWrite(p, &s);
|
||||
@@ -5027,11 +5188,13 @@ int sqlite3Fts5IndexClose(Fts5Index *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p ){
|
||||
assert( p->pReader==0 );
|
||||
fts5StructureInvalidate(p);
|
||||
sqlite3_finalize(p->pWriter);
|
||||
sqlite3_finalize(p->pDeleter);
|
||||
sqlite3_finalize(p->pIdxWriter);
|
||||
sqlite3_finalize(p->pIdxDeleter);
|
||||
sqlite3_finalize(p->pIdxSelect);
|
||||
sqlite3_finalize(p->pDataVersion);
|
||||
sqlite3Fts5HashFree(p->pHash);
|
||||
sqlite3_free(p->zDataTbl);
|
||||
sqlite3_free(p);
|
||||
@@ -6287,3 +6450,12 @@ int sqlite3Fts5IndexInit(sqlite3 *db){
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int sqlite3Fts5IndexReset(Fts5Index *p){
|
||||
assert( p->pStruct==0 || p->iStructVersion!=0 );
|
||||
if( fts5IndexDataVersion(p)!=p->iStructVersion ){
|
||||
fts5StructureInvalidate(p);
|
||||
}
|
||||
return fts5IndexReturn(p);
|
||||
}
|
||||
|
||||
+28
-17
@@ -597,27 +597,38 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int fts5NewTransaction(Fts5Table *pTab){
|
||||
Fts5Cursor *pCsr;
|
||||
for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
|
||||
if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
|
||||
}
|
||||
return sqlite3Fts5StorageReset(pTab->pStorage);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of xOpen method.
|
||||
*/
|
||||
static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
|
||||
Fts5Table *pTab = (Fts5Table*)pVTab;
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5Cursor *pCsr; /* New cursor object */
|
||||
Fts5Cursor *pCsr = 0; /* New cursor object */
|
||||
int nByte; /* Bytes of space to allocate */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int rc; /* Return code */
|
||||
|
||||
nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
|
||||
pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
|
||||
if( pCsr ){
|
||||
Fts5Global *pGlobal = pTab->pGlobal;
|
||||
memset(pCsr, 0, nByte);
|
||||
pCsr->aColumnSize = (int*)&pCsr[1];
|
||||
pCsr->pNext = pGlobal->pCsr;
|
||||
pGlobal->pCsr = pCsr;
|
||||
pCsr->iCsrId = ++pGlobal->iNextId;
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
rc = fts5NewTransaction(pTab);
|
||||
if( rc==SQLITE_OK ){
|
||||
nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
|
||||
pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
|
||||
if( pCsr ){
|
||||
Fts5Global *pGlobal = pTab->pGlobal;
|
||||
memset(pCsr, 0, nByte);
|
||||
pCsr->aColumnSize = (int*)&pCsr[1];
|
||||
pCsr->pNext = pGlobal->pCsr;
|
||||
pGlobal->pCsr = pCsr;
|
||||
pCsr->iCsrId = ++pGlobal->iNextId;
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
*ppCsr = (sqlite3_vtab_cursor*)pCsr;
|
||||
return rc;
|
||||
@@ -1511,13 +1522,13 @@ static int fts5UpdateMethod(
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Case 1: DELETE */
|
||||
/* DELETE */
|
||||
else if( nArg==1 ){
|
||||
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
|
||||
}
|
||||
|
||||
/* Case 2: INSERT */
|
||||
/* INSERT */
|
||||
else if( eType0!=SQLITE_INTEGER ){
|
||||
/* If this is a REPLACE, first remove the current entry (if any) */
|
||||
if( eConflict==SQLITE_REPLACE
|
||||
@@ -1529,7 +1540,7 @@ static int fts5UpdateMethod(
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}
|
||||
|
||||
/* Case 2: UPDATE */
|
||||
/* UPDATE */
|
||||
else{
|
||||
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
|
||||
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
|
||||
@@ -1578,8 +1589,8 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
|
||||
** Implementation of xBegin() method.
|
||||
*/
|
||||
static int fts5BeginMethod(sqlite3_vtab *pVtab){
|
||||
UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
|
||||
fts5NewTransaction((Fts5Table*)pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ static int fts5StorageGetStmt(
|
||||
}
|
||||
|
||||
*ppStmt = p->aStmt[eStmt];
|
||||
sqlite3_reset(*ppStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -368,6 +369,7 @@ static int fts5StorageInsertCallback(
|
||||
Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
|
||||
Fts5Index *pIdx = pCtx->pStorage->pIndex;
|
||||
UNUSED_PARAM2(iUnused1, iUnused2);
|
||||
if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
|
||||
if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
|
||||
pCtx->szCol++;
|
||||
}
|
||||
@@ -639,6 +641,10 @@ int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
|
||||
return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
|
||||
}
|
||||
|
||||
int sqlite3Fts5StorageReset(Fts5Storage *p){
|
||||
return sqlite3Fts5IndexReset(p->pIndex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate a new rowid. This is used for "external content" tables when
|
||||
** a NULL value is inserted into the rowid column. The new rowid is allocated
|
||||
@@ -810,6 +816,7 @@ static int fts5StorageIntegrityCallback(
|
||||
int iCol;
|
||||
|
||||
UNUSED_PARAM2(iUnused1, iUnused2);
|
||||
if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
|
||||
|
||||
if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
|
||||
pCtx->szCol++;
|
||||
@@ -1121,5 +1128,3 @@ int sqlite3Fts5StorageConfigValue(
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+15
-10
@@ -68,18 +68,22 @@ struct Fts5MatchinfoCtx {
|
||||
** If an error occurs, return NULL and leave an error in the database
|
||||
** handle (accessible using sqlite3_errcode()/errmsg()).
|
||||
*/
|
||||
static fts5_api *fts5_api_from_db(sqlite3 *db){
|
||||
fts5_api *pRet = 0;
|
||||
static int fts5_api_from_db(sqlite3 *db, fts5_api **ppApi){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
|
||||
if( SQLITE_OK==sqlite3_prepare(db, "SELECT fts5()", -1, &pStmt, 0)
|
||||
&& SQLITE_ROW==sqlite3_step(pStmt)
|
||||
&& sizeof(pRet)==sqlite3_column_bytes(pStmt, 0)
|
||||
){
|
||||
memcpy(&pRet, sqlite3_column_blob(pStmt, 0), sizeof(pRet));
|
||||
*ppApi = 0;
|
||||
rc = sqlite3_prepare(db, "SELECT fts5()", -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt)
|
||||
&& sizeof(fts5_api*)==sqlite3_column_bytes(pStmt, 0)
|
||||
){
|
||||
memcpy(ppApi, sqlite3_column_blob(pStmt, 0), sizeof(fts5_api*));
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return pRet;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -399,7 +403,8 @@ int sqlite3Fts5TestRegisterMatchinfo(sqlite3 *db){
|
||||
/* Extract the FTS5 API pointer from the database handle. The
|
||||
** fts5_api_from_db() function above is copied verbatim from the
|
||||
** FTS5 documentation. Refer there for details. */
|
||||
pApi = fts5_api_from_db(db);
|
||||
rc = fts5_api_from_db(db, &pApi);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
/* If fts5_api_from_db() returns NULL, then either FTS5 is not registered
|
||||
** with this database handle, or an error (OOM perhaps?) has occurred.
|
||||
|
||||
@@ -104,7 +104,7 @@ expr(A) ::= exprlist(X). {A = X;}
|
||||
|
||||
exprlist(A) ::= cnearset(X). {A = X;}
|
||||
exprlist(A) ::= exprlist(X) cnearset(Y). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_AND, X, Y, 0);
|
||||
A = sqlite3Fts5ParseImplicitAnd(pParse, X, Y);
|
||||
}
|
||||
|
||||
cnearset(A) ::= nearset(X). {
|
||||
|
||||
@@ -159,6 +159,12 @@ proc fts5_aux_test_functions {db} {
|
||||
}
|
||||
}
|
||||
|
||||
proc fts5_segcount {tbl} {
|
||||
set N 0
|
||||
foreach n [fts5_level_segs $tbl] { incr N $n }
|
||||
set N
|
||||
}
|
||||
|
||||
proc fts5_level_segs {tbl} {
|
||||
set sql "SELECT fts5_decode(rowid,block) aS r FROM ${tbl}_data WHERE rowid=10"
|
||||
set ret [list]
|
||||
|
||||
@@ -432,9 +432,16 @@ proc funk {} {
|
||||
}
|
||||
db func funk funk
|
||||
|
||||
# This test case corrupts the structure record within the first invocation
|
||||
# of function funk(). Which used to cause the bm25() function to throw an
|
||||
# exception. But since bm25() can now used the cached structure record,
|
||||
# it never sees the corruption introduced by funk() and so the following
|
||||
# statement no longer fails.
|
||||
#
|
||||
do_catchsql_test 16.2 {
|
||||
SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {0 {{} -1e-06 {}}}
|
||||
# {1 {SQL logic error or missing database}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
@@ -247,5 +247,21 @@ do_catchsql_test 12.1 {
|
||||
INSERT INTO t1(t1, rank) VALUES('rank', NULL);;
|
||||
} {1 {SQL logic error or missing database}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# errors in the 'usermerge' option
|
||||
#
|
||||
do_execsql_test 13.0 {
|
||||
CREATE VIRTUAL TABLE tt USING fts5(ttt);
|
||||
}
|
||||
foreach {tn val} {
|
||||
1 -1
|
||||
2 4.2
|
||||
3 17
|
||||
4 1
|
||||
} {
|
||||
set sql "INSERT INTO tt(tt, rank) VALUES('usermerge', $val)"
|
||||
do_catchsql_test 13.$tn $sql {1 {SQL logic error or missing database}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -179,6 +179,10 @@ for {set i 1} {1} {incr i} {
|
||||
if {$end<=$i} break
|
||||
lset var end [expr $end - $i]
|
||||
set struct [binary format c* $var]
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
db eval {
|
||||
BEGIN;
|
||||
UPDATE t1_data SET block = $struct WHERE id=10;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# 2016 March 21
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
# Specifically, that the fts5 module is deterministic. At one point, when
|
||||
# segment ids were allocated using sqlite3_randomness(), this was not the
|
||||
# case.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5aa
|
||||
return_if_no_fts5
|
||||
|
||||
proc do_determin_test {tn} {
|
||||
uplevel [list
|
||||
do_execsql_test $tn {
|
||||
SELECT (SELECT md5sum(id, block) FROM t1_data)==
|
||||
(SELECT md5sum(id, block) FROM t2_data),
|
||||
(SELECT md5sum(id, block) FROM t1_data)==
|
||||
(SELECT md5sum(id, block) FROM t3_data)
|
||||
} {1 1}
|
||||
]
|
||||
}
|
||||
|
||||
foreach_detail_mode $::testprefix {
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix="1 2", detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(a, b, prefix="1 2", detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t3 USING fts5(a, b, prefix="1 2", detail=%DETAIL%);
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
foreach t {t1 t2 t3} {
|
||||
execsql [string map [list TBL $t] {
|
||||
INSERT INTO TBL VALUES('a b c', 'd e f');
|
||||
INSERT INTO TBL VALUES('c1 c2 c3', 'c1 c2 c3');
|
||||
INSERT INTO TBL VALUES('xyzxyzxyz', 'xyzxyzxyz');
|
||||
}]
|
||||
}
|
||||
} {}
|
||||
|
||||
do_determin_test 1.2
|
||||
|
||||
do_test 1.3 {
|
||||
foreach t {t1 t2 t3} {
|
||||
execsql [string map [list TBL $t] {
|
||||
INSERT INTO TBL(TBL) VALUES('optimize');
|
||||
}]
|
||||
}
|
||||
} {}
|
||||
|
||||
do_determin_test 1.4
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ do_execsql_test 3.2 {
|
||||
ORDER BY rowid DESC;
|
||||
} {16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
do_execsql_test 3.3 {
|
||||
INSERT INTO abc(abc) VALUES('integrity-check');
|
||||
INSERT INTO abc(abc) VALUES('optimize');
|
||||
INSERT INTO abc(abc) VALUES('integrity-check');
|
||||
@@ -187,7 +187,7 @@ do_execsql_test 3.2 {
|
||||
set v [lindex $vocab 0]
|
||||
set i 0
|
||||
foreach v $vocab {
|
||||
do_execsql_test 3.3.[incr i] {
|
||||
do_execsql_test 3.4.[incr i] {
|
||||
SELECT rowid FROM abc WHERE abc MATCH $v
|
||||
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ foreach {tn expr res} {
|
||||
1 {abc} {"abc"}
|
||||
2 {abc ""} {"abc"}
|
||||
3 {""} {}
|
||||
4 {abc OR ""} {"abc"}
|
||||
5 {abc NOT ""} {"abc"}
|
||||
6 {abc AND ""} {"abc"}
|
||||
7 {"" OR abc} {"abc"}
|
||||
8 {"" NOT abc} {"abc"}
|
||||
9 {"" AND abc} {"abc"}
|
||||
4 {abc OR ""} {"abc" OR ""}
|
||||
5 {abc NOT ""} {"abc" NOT ""}
|
||||
6 {abc AND ""} {"abc" AND ""}
|
||||
7 {"" OR abc} {"" OR "abc"}
|
||||
8 {"" NOT abc} {"" NOT "abc"}
|
||||
9 {"" AND abc} {"" AND "abc"}
|
||||
10 {abc + "" + def} {"abc" + "def"}
|
||||
11 {abc "" def} {"abc" AND "def"}
|
||||
12 {r+e OR w} {"r" + "e" OR "w"}
|
||||
|
||||
@@ -86,7 +86,7 @@ set ::res [db eval {SELECT rowid, x1 FROM x1 WHERE x1 MATCH '*reads'}]
|
||||
do_faultsim_test 4 -faults oom-* -body {
|
||||
db eval {SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'}
|
||||
} -test {
|
||||
faultsim_test_result {0 {0 {} 4}}
|
||||
faultsim_test_result {0 {0 {} 3}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -54,7 +54,32 @@ foreach_detail_mode $testprefix {
|
||||
faultsim_test_result {0 {1 3}} {1 SQLITE_NOMEM}
|
||||
}
|
||||
}
|
||||
|
||||
} ;# foreach_detail_mode...
|
||||
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE x2 USING fts5(a);
|
||||
INSERT INTO x2(x2, rank) VALUES('crisismerge', 2);
|
||||
INSERT INTO x2(x2, rank) VALUES('pgsz', 32);
|
||||
INSERT INTO x2 VALUES('a b c d');
|
||||
INSERT INTO x2 VALUES('e f g h');
|
||||
INSERT INTO x2 VALUES('i j k l');
|
||||
INSERT INTO x2 VALUES('m n o p');
|
||||
INSERT INTO x2 VALUES('q r s t');
|
||||
INSERT INTO x2 VALUES('u v w x');
|
||||
INSERT INTO x2 VALUES('y z a b');
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 4 -faults oom-* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { INSERT INTO x2(x2) VALUES('optimize') }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# 2014 June 17
|
||||
#
|
||||
# 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 script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
return_if_no_fts5
|
||||
set testprefix fts5fuzz1
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_catchsql_test 1.1 {
|
||||
CREATE VIRTUAL TABLE f1 USING fts5(a b);
|
||||
} {/1 {parse error in.*}/}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.1 {
|
||||
CREATE VIRTUAL TABLE f1 USING fts5(a, b);
|
||||
INSERT INTO f1 VALUES('a b', 'c d');
|
||||
INSERT INTO f1 VALUES('e f', 'a b');
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.1 {
|
||||
SELECT rowid FROM f1('""');
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.2.2 {
|
||||
SELECT rowid FROM f1('"" AND a');
|
||||
} {}
|
||||
|
||||
|
||||
do_execsql_test 2.2.3 {
|
||||
SELECT rowid FROM f1('"" a');
|
||||
} {1 2}
|
||||
|
||||
do_execsql_test 2.2.4 {
|
||||
SELECT rowid FROM f1('"" OR a');
|
||||
} {1 2}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT a, b FROM f1('NEAR("")');
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
SELECT a, b FROM f1('NEAR("", 5)');
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
SELECT a, b FROM f1('NEAR("" c, 5)');
|
||||
} {{a b} {c d}}
|
||||
|
||||
do_execsql_test 2.6 {
|
||||
SELECT a, b FROM f1('NEAR("" c d, 5)');
|
||||
} {{a b} {c d}}
|
||||
|
||||
do_execsql_test 2.7 {
|
||||
SELECT a, b FROM f1('NEAR(c d, 5)');
|
||||
} {{a b} {c d}}
|
||||
|
||||
do_execsql_test 2.8 {
|
||||
SELECT rowid FROM f1('NEAR("a" "b", 5)');
|
||||
} {1 2}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.2 {
|
||||
CREATE VIRTUAL TABLE f2 USING fts5(o, t, tokenize="ascii separators abc");
|
||||
SELECT * FROM f2('a+4');
|
||||
} {}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_catchsql_test 4.1 {
|
||||
CREATE VIRTUAL TABLE f2 USING fts5(o, t);
|
||||
SELECT * FROM f2('(8 AND 9)`AND 10');
|
||||
} {1 {fts5: syntax error near "`"}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -45,7 +45,7 @@ proc do_merge1_test {testname nRowPerSeg} {
|
||||
WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg)
|
||||
INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii;
|
||||
|
||||
INSERT INTO x8(x8, rank) VALUES('automerge', 2);
|
||||
INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
|
||||
}
|
||||
|
||||
for {set tn 1} {[lindex [fts5_level_segs x8] 0]>0} {incr tn} {
|
||||
@@ -84,9 +84,9 @@ proc do_merge2_test {testname nRow} {
|
||||
execsql { INSERT INTO x8 VALUES( rnddoc(($i%16) + 5) ) }
|
||||
while {[not_merged x8]} {
|
||||
execsql {
|
||||
INSERT INTO x8(x8, rank) VALUES('automerge', 2);
|
||||
INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
|
||||
INSERT INTO x8(x8, rank) VALUES('merge', 1);
|
||||
INSERT INTO x8(x8, rank) VALUES('automerge', 16);
|
||||
INSERT INTO x8(x8, rank) VALUES('usermerge', 16);
|
||||
INSERT INTO x8(x8) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
@@ -104,9 +104,9 @@ do_merge2_test 2.2 10
|
||||
do_merge2_test 2.3 20
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that an auto-merge will complete any merge that has already been
|
||||
# Test that a merge will complete any merge that has already been
|
||||
# started, even if the number of input segments is less than the current
|
||||
# value of the 'automerge' configuration parameter.
|
||||
# value of the 'usermerge' configuration parameter.
|
||||
#
|
||||
db func rnddoc fts5_rnddoc
|
||||
|
||||
@@ -119,7 +119,7 @@ do_execsql_test 3.1 {
|
||||
}
|
||||
do_test 3.2 {
|
||||
execsql {
|
||||
INSERT INTO x8(x8, rank) VALUES('automerge', 4);
|
||||
INSERT INTO x8(x8, rank) VALUES('usermerge', 4);
|
||||
INSERT INTO x8(x8, rank) VALUES('merge', 1);
|
||||
}
|
||||
fts5_level_segs x8
|
||||
@@ -127,14 +127,14 @@ do_test 3.2 {
|
||||
|
||||
do_test 3.3 {
|
||||
execsql {
|
||||
INSERT INTO x8(x8, rank) VALUES('automerge', 2);
|
||||
INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
|
||||
INSERT INTO x8(x8, rank) VALUES('merge', 1);
|
||||
}
|
||||
fts5_level_segs x8
|
||||
} {2 1}
|
||||
|
||||
do_test 3.4 {
|
||||
execsql { INSERT INTO x8(x8, rank) VALUES('automerge', 4) }
|
||||
execsql { INSERT INTO x8(x8, rank) VALUES('usermerge', 4) }
|
||||
while {[not_merged x8]} {
|
||||
execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1) }
|
||||
}
|
||||
@@ -176,7 +176,7 @@ foreach {tn pgsz} {
|
||||
INSERT INTO x8 SELECT mydoc() FROM ii;
|
||||
WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100)
|
||||
INSERT INTO x8 SELECT mydoc() FROM ii;
|
||||
INSERT INTO x8(x8, rank) VALUES('automerge', 2);
|
||||
INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
|
||||
}
|
||||
|
||||
set expect [mycount]
|
||||
@@ -190,5 +190,55 @@ foreach {tn pgsz} {
|
||||
# db eval {SELECT fts5_decode(rowid, block) AS r FROM x8_data} { puts $r }
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that the 'merge' command does not modify the database if there is
|
||||
# no work to do.
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
CREATE VIRTUAL TABLE x9 USING fts5(one, two);
|
||||
INSERT INTO x9(x9, rank) VALUES('pgsz', 32);
|
||||
INSERT INTO x9(x9, rank) VALUES('automerge', 2);
|
||||
INSERT INTO x9(x9, rank) VALUES('usermerge', 2);
|
||||
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
|
||||
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
|
||||
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
|
||||
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
|
||||
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
|
||||
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
|
||||
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
|
||||
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
|
||||
}
|
||||
|
||||
do_test 5.2 {
|
||||
while 1 {
|
||||
set nChange [db total_changes]
|
||||
execsql { INSERT INTO x9(x9, rank) VALUES('merge', 1); }
|
||||
set nChange [expr [db total_changes] - $nChange]
|
||||
#puts $nChange
|
||||
if {$nChange<2} break
|
||||
}
|
||||
} {}
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Test that running 'merge' on an empty database does not cause a
|
||||
# problem.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE g1 USING fts5(a, b);
|
||||
}
|
||||
do_execsql_test 6.1 {
|
||||
INSERT INTO g1(g1, rank) VALUES('merge', 10);
|
||||
}
|
||||
do_execsql_test 6.2 {
|
||||
INSERT INTO g1(g1, rank) VALUES('merge', -10);
|
||||
}
|
||||
do_execsql_test 6.3 {
|
||||
INSERT INTO g1(g1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# 2016 March 17
|
||||
#
|
||||
# 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]
|
||||
source $testdir/lock_common.tcl
|
||||
|
||||
set testprefix fts5multiclient
|
||||
return_if_no_fts5
|
||||
|
||||
foreach_detail_mode $testprefix {
|
||||
|
||||
do_multiclient_test tn {
|
||||
|
||||
do_test 1.$tn.1 {
|
||||
sql1 { CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%) }
|
||||
sql1 { INSERT INTO t1 VALUES('a b c') }
|
||||
sql2 { SELECT rowid FROM t1('b') }
|
||||
} {1}
|
||||
|
||||
do_test 1.$tn.2 {
|
||||
sql2 { INSERT INTO t1 VALUES('a b c') }
|
||||
sql1 { SELECT rowid FROM t1('b') }
|
||||
} {1 2}
|
||||
|
||||
do_test 1.$tn.3 {
|
||||
sql2 { INSERT INTO t1 VALUES('a b c') }
|
||||
sql1 { SELECT rowid FROM t1('b') }
|
||||
} {1 2 3}
|
||||
|
||||
do_test 1.$tn.4 {
|
||||
sql2 { INSERT INTO t1 VALUES('a b c') }
|
||||
sql1 { INSERT INTO t1 VALUES('a b c') }
|
||||
sql3 { INSERT INTO t1(t1) VALUES('integrity-check') }
|
||||
} {}
|
||||
|
||||
};# do_multiclient_test
|
||||
};# foreach_detail_mode
|
||||
finish_test
|
||||
|
||||
@@ -20,6 +20,12 @@ ifcapable !fts5 {
|
||||
return
|
||||
}
|
||||
|
||||
#
|
||||
# 1.* - Warm body tests for index optimization using ('optimize')
|
||||
#
|
||||
# 2.* - Warm body tests for index optimization using ('merge', -1)
|
||||
#
|
||||
|
||||
proc rnddoc {nWord} {
|
||||
set vocab {a b c d e f g h i j k l m n o p q r s t u v w x y z}
|
||||
set nVocab [llength $vocab]
|
||||
@@ -30,14 +36,12 @@ proc rnddoc {nWord} {
|
||||
return $ret
|
||||
}
|
||||
|
||||
|
||||
foreach {tn nStep} {
|
||||
1 2
|
||||
2 10
|
||||
3 50
|
||||
4 500
|
||||
} {
|
||||
if {$tn!=4} continue
|
||||
reset_db
|
||||
db func rnddoc rnddoc
|
||||
do_execsql_test 1.$tn.1 {
|
||||
@@ -60,7 +64,46 @@ if {$tn!=4} continue
|
||||
do_execsql_test 1.$tn.5 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_test 1.$tn.6 { fts5_segcount t1 } 1
|
||||
}
|
||||
|
||||
foreach {tn nStep} {
|
||||
1 2
|
||||
2 10
|
||||
3 50
|
||||
4 500
|
||||
} {
|
||||
reset_db
|
||||
db func rnddoc rnddoc
|
||||
do_execsql_test 1.$tn.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, y);
|
||||
}
|
||||
do_test 2.$tn.2 {
|
||||
for {set i 0} {$i < $nStep} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES( rnddoc(5), rnddoc(5) ) }
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.$tn.3 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_test 2.$tn.4 {
|
||||
execsql { INSERT INTO t1(t1, rank) VALUES('merge', -1) }
|
||||
while 1 {
|
||||
set c [db total_changes]
|
||||
execsql { INSERT INTO t1(t1, rank) VALUES('merge', 1) }
|
||||
set c [expr [db total_changes]-$c]
|
||||
if {$c<2} break
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.$tn.5 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_test 2.$tn.6 { fts5_segcount t1 } 1
|
||||
}
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ do_test 14.2 {
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
db func rnddoc fts5_rnddoc
|
||||
do_execsql_test 4.0 {
|
||||
do_execsql_test 14.3 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(x);
|
||||
INSERT INTO x1(x1, rank) VALUES('pgsz', 32);
|
||||
|
||||
@@ -348,9 +348,9 @@ do_execsql_test 4.0 {
|
||||
INSERT INTO x1 SELECT rnddoc(5) FROM ii;
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
do_execsql_test 14.4 {
|
||||
SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'
|
||||
} {0 {} 4}
|
||||
} {0 {} 3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
@@ -448,4 +448,24 @@ do_execsql_test 20.2 {
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
set doc "a b [string repeat x 100000]"
|
||||
do_execsql_test 21.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(x);
|
||||
INSERT INTO x1(rowid, x) VALUES(11111, $doc);
|
||||
INSERT INTO x1(rowid, x) VALUES(11112, $doc);
|
||||
}
|
||||
do_execsql_test 21.1 {
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 21.2 {
|
||||
SELECT rowid FROM x1($doc);
|
||||
} {11111 11112}
|
||||
do_execsql_test 21.3 {
|
||||
DELETE FROM x1 WHERE rowid=11111;
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
SELECT rowid FROM x1($doc);
|
||||
} {11112}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -17,6 +17,7 @@ proc process_cmdline {} {
|
||||
{detail "full" "Fts5 detail mode to use"}
|
||||
{repeat 1 "Load each file this many times"}
|
||||
{prefix "" "Fts prefix= option"}
|
||||
{trans 1 "True to use a transaction"}
|
||||
database
|
||||
file...
|
||||
} {
|
||||
@@ -214,7 +215,7 @@ foreach c [lrange $cols 1 end] {
|
||||
}
|
||||
append sql ")"
|
||||
|
||||
db eval BEGIN
|
||||
if {$A(trans)} { db eval BEGIN }
|
||||
while {$i < $N} {
|
||||
foreach c $cols s $A(colsize) {
|
||||
set R($c) [lrange $tokens $i [expr $i+$s-1]]
|
||||
@@ -222,7 +223,7 @@ db eval BEGIN
|
||||
}
|
||||
db eval $sql
|
||||
}
|
||||
db eval COMMIT
|
||||
if {$A(trans)} { db eval COMMIT }
|
||||
|
||||
|
||||
|
||||
|
||||
+8
-2
@@ -1734,6 +1734,7 @@ static void scriptCodeSqlFunc(
|
||||
int c, sz;
|
||||
int scriptMask = 0;
|
||||
int res;
|
||||
int seenDigit = 0;
|
||||
# define SCRIPT_LATIN 0x0001
|
||||
# define SCRIPT_CYRILLIC 0x0002
|
||||
# define SCRIPT_GREEK 0x0004
|
||||
@@ -1744,8 +1745,12 @@ static void scriptCodeSqlFunc(
|
||||
c = utf8Read(zIn, nIn, &sz);
|
||||
zIn += sz;
|
||||
nIn -= sz;
|
||||
if( c<0x02af && (c>=0x80 || midClass[c&0x7f]<CCLASS_DIGIT) ){
|
||||
scriptMask |= SCRIPT_LATIN;
|
||||
if( c<0x02af ){
|
||||
if( c>=0x80 || midClass[c&0x7f]<CCLASS_DIGIT ){
|
||||
scriptMask |= SCRIPT_LATIN;
|
||||
}else if( c>='0' && c<='9' ){
|
||||
seenDigit = 1;
|
||||
}
|
||||
}else if( c>=0x0400 && c<=0x04ff ){
|
||||
scriptMask |= SCRIPT_CYRILLIC;
|
||||
}else if( c>=0x0386 && c<=0x03ce ){
|
||||
@@ -1756,6 +1761,7 @@ static void scriptCodeSqlFunc(
|
||||
scriptMask |= SCRIPT_ARABIC;
|
||||
}
|
||||
}
|
||||
if( scriptMask==0 && seenDigit ) scriptMask = SCRIPT_LATIN;
|
||||
switch( scriptMask ){
|
||||
case 0: res = 999; break;
|
||||
case SCRIPT_LATIN: res = 215; break;
|
||||
|
||||
+1
-1
@@ -611,7 +611,7 @@ foreach {tn3 create_vfs destroy_vfs} {
|
||||
9 {
|
||||
CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
|
||||
CREATE TABLE rbu.data_t1(a, b, rbu_control);
|
||||
INSERT INTO rbu.data_t1 VALUES(1, 2, 2);
|
||||
INSERT INTO rbu.data_t1 VALUES(1, 2, 3);
|
||||
} {SQLITE_ERROR - invalid rbu_control value}
|
||||
|
||||
10 {
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# 2016 March 7
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Tests for RBU focused on the REPLACE operation (rbu_control column
|
||||
# contains integer value 2).
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
set ::testprefix rbuC
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This test is actually of an UPDATE directive. Just to establish that
|
||||
# these work with UNIQUE indexes before preceding to REPLACE.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b, c UNIQUE);
|
||||
INSERT INTO t1 VALUES(1, 'a', 'b', 'c');
|
||||
}
|
||||
|
||||
forcedelete rbu.db
|
||||
do_execsql_test 1.1 {
|
||||
ATTACH 'rbu.db' AS rbu;
|
||||
CREATE TABLE rbu.data_t1(i, a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(1, 'a', 'b', 'c', '.xxx');
|
||||
}
|
||||
|
||||
do_test 1.2 {
|
||||
step_rbu test.db rbu.db
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT * FROM t1
|
||||
} {
|
||||
1 a b c
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
foreach {tn schema} {
|
||||
1 {
|
||||
CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b, c UNIQUE);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
}
|
||||
2 {
|
||||
CREATE TABLE t1(i PRIMARY KEY, a, b, c UNIQUE);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
}
|
||||
3 {
|
||||
CREATE TABLE t1(i PRIMARY KEY, a, b, c UNIQUE) WITHOUT ROWID;
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
}
|
||||
} {
|
||||
reset_db
|
||||
forcedelete rbu.db
|
||||
execsql $schema
|
||||
|
||||
do_execsql_test 2.$tn.0 {
|
||||
INSERT INTO t1 VALUES(1, 'a', 'b', 'c');
|
||||
INSERT INTO t1 VALUES(2, 'b', 'c', 'd');
|
||||
INSERT INTO t1 VALUES(3, 'c', 'd', 'e');
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.1 {
|
||||
ATTACH 'rbu.db' AS rbu;
|
||||
CREATE TABLE rbu.data_t1(i, a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(1, 1, 2, 3, 2);
|
||||
INSERT INTO data_t1 VALUES(3, 'c', 'd', 'e', 2);
|
||||
INSERT INTO data_t1 VALUES(4, 'd', 'e', 'f', 2);
|
||||
}
|
||||
|
||||
do_test 2.$tn.2 {
|
||||
step_rbu test.db rbu.db
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_execsql_test 2.$tn.3 {
|
||||
SELECT * FROM t1 ORDER BY i
|
||||
} {
|
||||
1 1 2 3
|
||||
2 b c d
|
||||
3 c d e
|
||||
4 d e f
|
||||
}
|
||||
|
||||
integrity_check 2.$tn.4
|
||||
}
|
||||
|
||||
foreach {tn schema} {
|
||||
1 {
|
||||
CREATE TABLE t1(a, b, c UNIQUE);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
}
|
||||
|
||||
2 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
|
||||
}
|
||||
} {
|
||||
if {$tn==2} { ifcapable !fts5 break }
|
||||
reset_db
|
||||
forcedelete rbu.db
|
||||
execsql $schema
|
||||
|
||||
do_execsql_test 3.$tn.0 {
|
||||
INSERT INTO t1 VALUES('a', 'b', 'c');
|
||||
INSERT INTO t1 VALUES('b', 'c', 'd');
|
||||
INSERT INTO t1 VALUES('c', 'd', 'e');
|
||||
}
|
||||
|
||||
do_execsql_test 3.$tn.1 {
|
||||
ATTACH 'rbu.db' AS rbu;
|
||||
CREATE TABLE rbu.data_t1(rbu_rowid, a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(1, 1, 2, 3, 2);
|
||||
INSERT INTO data_t1 VALUES(3, 'c', 'd', 'e', 2);
|
||||
INSERT INTO data_t1 VALUES(4, 'd', 'e', 'f', 2);
|
||||
}
|
||||
|
||||
do_test 3.$tn.2 {
|
||||
step_rbu test.db rbu.db
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_execsql_test 3.$tn.3 {
|
||||
SELECT rowid, * FROM t1 ORDER BY 1
|
||||
} {
|
||||
1 1 2 3
|
||||
2 b c d
|
||||
3 c d e
|
||||
4 d e f
|
||||
}
|
||||
|
||||
integrity_check 3.$tn.4
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+23
-10
@@ -18,16 +18,7 @@ if {![info exists testdir]} {
|
||||
source $testdir/tester.tcl
|
||||
set testprefix rbudiff
|
||||
|
||||
if {$tcl_platform(platform)=="windows"} {
|
||||
set PROG "sqldiff.exe"
|
||||
} else {
|
||||
set PROG "./sqldiff"
|
||||
}
|
||||
if {![file exe $PROG]} {
|
||||
puts "rbudiff.test cannot run because $PROG is not available"
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
set PROG [test_find_sqldiff]
|
||||
db close
|
||||
|
||||
proc get_rbudiff_sql {db1 db2} {
|
||||
@@ -45,6 +36,7 @@ proc step_rbu {target rbu} {
|
||||
}
|
||||
|
||||
proc apply_rbudiff {sql target} {
|
||||
test_rbucount $sql
|
||||
forcedelete rbu.db
|
||||
sqlite3 rbudb rbu.db
|
||||
rbudb eval $sql
|
||||
@@ -52,6 +44,27 @@ proc apply_rbudiff {sql target} {
|
||||
step_rbu $target rbu.db
|
||||
}
|
||||
|
||||
# The only argument is the output of an [sqldiff -rbu] run. This command
|
||||
# tests that the contents of the rbu_count table is correct. An exception
|
||||
# is thrown if it is not.
|
||||
#
|
||||
proc test_rbucount {sql} {
|
||||
sqlite3 tmpdb ""
|
||||
tmpdb eval $sql
|
||||
tmpdb eval {
|
||||
SELECT name FROM sqlite_master WHERE name LIKE 'data%' AND type='table'
|
||||
} {
|
||||
set a [tmpdb eval "SELECT count(*) FROM $name"]
|
||||
set b [tmpdb eval {SELECT cnt FROM rbu_count WHERE tbl = $name}]
|
||||
if {$a != $b} {
|
||||
tmpdb close
|
||||
error "rbu_count error - tbl = $name"
|
||||
}
|
||||
}
|
||||
tmpdb close
|
||||
return ""
|
||||
}
|
||||
|
||||
proc rbudiff_cksum {db1} {
|
||||
set txt ""
|
||||
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
# 2016 March 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
set ::testprefix rbuprogress
|
||||
|
||||
|
||||
proc create_db_file {filename sql} {
|
||||
forcedelete $filename
|
||||
sqlite3 tmpdb $filename
|
||||
tmpdb eval $sql
|
||||
tmpdb close
|
||||
}
|
||||
|
||||
# Create a simple RBU database. That expects to write to a table:
|
||||
#
|
||||
# CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
#
|
||||
proc create_rbu1 {filename} {
|
||||
create_db_file $filename {
|
||||
CREATE TABLE data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(1, 2, 3, 0);
|
||||
INSERT INTO data_t1 VALUES(2, 'two', 'three', 0);
|
||||
INSERT INTO data_t1 VALUES(3, NULL, 8.2, 0);
|
||||
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data_t1', 3);
|
||||
}
|
||||
return $filename
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
create_rbu1 rbu.db
|
||||
sqlite3rbu rbu test.db rbu.db
|
||||
rbu bp_progress
|
||||
} {0 0}
|
||||
do_test 1.2 { rbu step ; rbu bp_progress } {3333 0}
|
||||
do_test 1.3 { rbu step ; rbu bp_progress } {6666 0}
|
||||
do_test 1.4 { rbu step ; rbu bp_progress } {10000 0}
|
||||
do_test 1.5 { rbu step ; rbu bp_progress } {10000 0}
|
||||
do_test 1.6 { rbu step ; rbu bp_progress } {10000 0}
|
||||
do_test 1.7 { rbu step ; rbu bp_progress } {10000 5000}
|
||||
do_test 1.8 { rbu step ; rbu bp_progress } {10000 10000}
|
||||
do_test 1.9 { rbu step ; rbu bp_progress } {10000 10000}
|
||||
|
||||
do_test 1.10 {
|
||||
rbu close
|
||||
} {SQLITE_DONE}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
proc do_sp_test {tn bReopen target rbu reslist} {
|
||||
uplevel [list do_test $tn [subst -nocommands {
|
||||
if {$bReopen==0} { sqlite3rbu rbu $target $rbu }
|
||||
set res [list]
|
||||
while 1 {
|
||||
if {$bReopen} { sqlite3rbu rbu $target $rbu }
|
||||
set rc [rbu step]
|
||||
if {[set rc] != "SQLITE_OK"} { rbu close ; error "error 1" }
|
||||
lappend res [lindex [rbu bp_progress] 0]
|
||||
if {[lindex [set res] end]==10000} break
|
||||
if {$bReopen} { rbu close }
|
||||
}
|
||||
if {[set res] != [list $reslist]} {
|
||||
rbu close
|
||||
error "1. reslist incorrect (expect=$reslist got=[set res])"
|
||||
}
|
||||
|
||||
# One step to clean up the temporary tables used to update the only
|
||||
# target table in the rbu database. And one more to move the *-oal
|
||||
# file to *-wal. After each of these steps, the progress remains
|
||||
# at "10000 0".
|
||||
#
|
||||
if {[lindex [list $reslist] 0]!=-1} {
|
||||
rbu step
|
||||
set res [rbu bp_progress]
|
||||
if {[set res] != [list 10000 0]} {
|
||||
rbu close
|
||||
error "2. reslist incorrect (expect=10000 0 got=[set res])"
|
||||
}
|
||||
}
|
||||
|
||||
rbu step
|
||||
set res [rbu bp_progress]
|
||||
if {[set res] != [list 10000 0]} {
|
||||
rbu close
|
||||
error "3. reslist incorrect (expect=10000 0 got=[set res])"
|
||||
}
|
||||
|
||||
# Do the checkpoint.
|
||||
while {[rbu step]=="SQLITE_OK"} {
|
||||
foreach {a b} [rbu bp_progress] {}
|
||||
if {[set a]!=10000 || [set b]<=0 || [set b]>10000} {
|
||||
rbu close
|
||||
error "4. reslist incorrect (expect=10000 1..10000 got=[set a] [set b])"
|
||||
}
|
||||
}
|
||||
|
||||
set res [rbu bp_progress]
|
||||
if {[set res] != [list 10000 10000]} {
|
||||
rbu close
|
||||
error "5. reslist is incorrect (expect=10000 10000 got=[set res])"
|
||||
}
|
||||
|
||||
rbu close
|
||||
}] {SQLITE_DONE}]
|
||||
}
|
||||
|
||||
foreach {bReopen} { 0 1 } {
|
||||
reset_db
|
||||
do_test 2.$bReopen.1.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
}
|
||||
create_db_file rbu.db {
|
||||
CREATE TABLE data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(4, 4, 4, 0);
|
||||
INSERT INTO data_t1 VALUES(5, 5, 5, 0);
|
||||
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data_t1', 2);
|
||||
}
|
||||
} {}
|
||||
do_sp_test 2.$bReopen.1.1 $bReopen test.db rbu.db {5000 10000}
|
||||
|
||||
reset_db
|
||||
do_test 2.$bReopen.2.0 {
|
||||
execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
|
||||
create_rbu1 rbu.db
|
||||
} {rbu.db}
|
||||
do_sp_test 2.$bReopen.2.1 $bReopen test.db rbu.db {3333 6666 10000}
|
||||
|
||||
reset_db
|
||||
do_test 2.$bReopen.3.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3, 3);
|
||||
}
|
||||
create_db_file rbu.db {
|
||||
CREATE TABLE data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(4, 4, 4, 0);
|
||||
INSERT INTO data_t1 VALUES(2, NULL, NULL, 1);
|
||||
INSERT INTO data_t1 VALUES(5, NULL, NULL, 1);
|
||||
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data_t1', 3);
|
||||
}
|
||||
} {}
|
||||
do_sp_test 2.$bReopen.3.1 $bReopen test.db rbu.db {1666 3333 6000 8000 10000}
|
||||
|
||||
reset_db
|
||||
do_test 2.$bReopen.4.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3, 3);
|
||||
}
|
||||
create_db_file rbu.db {
|
||||
CREATE TABLE data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(2, 4, 4, '.xx');
|
||||
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data_t1', 1);
|
||||
}
|
||||
} {}
|
||||
do_sp_test 2.$bReopen.4.1 $bReopen test.db rbu.db {3333 6666 10000}
|
||||
|
||||
reset_db
|
||||
do_test 2.$bReopen.5.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3, 3);
|
||||
}
|
||||
create_db_file rbu.db {
|
||||
CREATE TABLE data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(4, NULL, 4, '.xx');
|
||||
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data_t1', 1);
|
||||
}
|
||||
} {}
|
||||
do_sp_test 2.$bReopen.5.1 $bReopen test.db rbu.db {10000}
|
||||
|
||||
reset_db
|
||||
do_test 2.$bReopen.6.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3, 3);
|
||||
}
|
||||
create_db_file rbu.db {
|
||||
CREATE TABLE data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(4, 4, 4, 0);
|
||||
INSERT INTO data_t1 VALUES(2, NULL, NULL, 1);
|
||||
INSERT INTO data_t1 VALUES(5, NULL, NULL, 1);
|
||||
}
|
||||
} {}
|
||||
do_sp_test 2.$bReopen.6.1 $bReopen test.db rbu.db {-1 -1 -1 -1 -1 10000}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests verify that the API works when resuming an update
|
||||
# during the incremental checkpoint stage.
|
||||
#
|
||||
proc do_phase2_test {tn bReopen target rbu nStep} {
|
||||
uplevel [list do_test $tn [subst -nocommands {
|
||||
|
||||
# Build the OAL/WAL file:
|
||||
sqlite3rbu rbu $target $rbu
|
||||
while {[lindex [rbu bp_progress] 0]<10000} {
|
||||
set rc [rbu step]
|
||||
if {"SQLITE_OK" != [set rc]} { rbu close }
|
||||
}
|
||||
|
||||
# Clean up the temp tables and move the *-oal file to *-wal.
|
||||
rbu step
|
||||
rbu step
|
||||
|
||||
for {set i 0} {[set i] < $nStep} {incr i} {
|
||||
if {$bReopen} {
|
||||
rbu close
|
||||
sqlite3rbu rbu $target $rbu
|
||||
}
|
||||
rbu step
|
||||
set res [rbu bp_progress]
|
||||
set expect [expr (1 + [set i]) * 10000 / $nStep]
|
||||
if {[lindex [set res] 1] != [set expect]} {
|
||||
error "Have [set res], expected 10000 [set expect]"
|
||||
}
|
||||
}
|
||||
|
||||
set rc [rbu step]
|
||||
if {[set rc] != "SQLITE_DONE"} {
|
||||
error "Have [set rc], expected SQLITE_DONE"
|
||||
}
|
||||
|
||||
rbu close
|
||||
}] {SQLITE_DONE}]
|
||||
}
|
||||
|
||||
foreach bReopen {0 1} {
|
||||
do_test 3.$bReopen.1.0 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
|
||||
}
|
||||
create_db_file rbu.db {
|
||||
CREATE TABLE data_t1(a, b, rbu_control);
|
||||
CREATE TABLE data_t2(a, b, rbu_control);
|
||||
CREATE TABLE data_t3(a, b, rbu_control);
|
||||
CREATE TABLE data_t4(a, b, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(1, 2, 0);
|
||||
INSERT INTO data_t2 VALUES(1, 2, 0);
|
||||
INSERT INTO data_t3 VALUES(1, 2, 0);
|
||||
INSERT INTO data_t4 VALUES(1, 2, 0);
|
||||
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data_t1', 1);
|
||||
INSERT INTO rbu_count VALUES('data_t2', 1);
|
||||
INSERT INTO rbu_count VALUES('data_t3', 1);
|
||||
INSERT INTO rbu_count VALUES('data_t4', 1);
|
||||
}
|
||||
} {}
|
||||
do_phase2_test 3.$bReopen.1.1 $bReopen test.db rbu.db 5
|
||||
}
|
||||
|
||||
|
||||
foreach {bReopen} { 0 1 } {
|
||||
foreach {tn tbl} {
|
||||
ipk { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
|
||||
wr { CREATE TABLE t1(a INT PRIMARY KEY, b, c) WITHOUT ROWID }
|
||||
pk { CREATE TABLE t1(a INT PRIMARY KEY, b, c) }
|
||||
} {
|
||||
|
||||
foreach {tn2 rbusql r1 r3} {
|
||||
1 {
|
||||
CREATE TABLE data0_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data0_t1 VALUES(15, 15, 15, 0);
|
||||
INSERT INTO data0_t1 VALUES(20, 20, 20, 0);
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data0_t1', 2);
|
||||
}
|
||||
{2500 5000 7500 10000}
|
||||
{1666 3333 5000 6666 8333 10000}
|
||||
|
||||
2 {
|
||||
CREATE TABLE data0_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data0_t1 VALUES(10, 10, 10, 2);
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data0_t1', 1);
|
||||
}
|
||||
{3333 6666 10000}
|
||||
{2000 4000 6000 8000 10000}
|
||||
|
||||
3 {
|
||||
CREATE TABLE data0_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data0_t1 VALUES(7, 7, 7, 2);
|
||||
INSERT INTO data0_t1 VALUES(10, 10, 10, 2);
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data0_t1', 2);
|
||||
}
|
||||
{2500 4000 6000 8000 10000}
|
||||
{1666 2500 3750 5000 6250 7500 8750 10000}
|
||||
|
||||
} {
|
||||
|
||||
reset_db ; execsql $tbl
|
||||
do_test 4.$tn.$bReopen.$tn2.0 {
|
||||
execsql {
|
||||
CREATE INDEX t1c ON t1(c);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(5, 5, 5);
|
||||
INSERT INTO t1 VALUES(10, 10, 10);
|
||||
}
|
||||
create_db_file rbu.db $rbusql
|
||||
} {}
|
||||
|
||||
set R(ipk) $r1
|
||||
set R(wr) $r1
|
||||
set R(pk) $r3
|
||||
do_sp_test 4.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach {bReopen} { 0 1 } {
|
||||
foreach {tn tbl} {
|
||||
nopk {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE INDEX t1c ON t1(c);
|
||||
}
|
||||
vtab {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
|
||||
}
|
||||
} {
|
||||
|
||||
foreach {tn2 rbusql r1 r2} {
|
||||
1 {
|
||||
CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control);
|
||||
INSERT INTO data0_t1 VALUES(15, 15, 15, 4, 0);
|
||||
INSERT INTO data0_t1 VALUES(20, 20, 20, 5, 0);
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data0_t1', 2);
|
||||
}
|
||||
{2500 5000 7500 10000}
|
||||
{5000 10000}
|
||||
|
||||
2 {
|
||||
CREATE TABLE data0_t1(rbu_rowid, a, b, c, rbu_control);
|
||||
INSERT INTO data0_t1 VALUES(0, 7, 7, 7, 2);
|
||||
INSERT INTO data0_t1 VALUES(2, 10, 10, 10, 2);
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data0_t1', 2);
|
||||
}
|
||||
{2500 4000 6000 8000 10000}
|
||||
{5000 10000}
|
||||
|
||||
3 {
|
||||
CREATE TABLE data0_t1(rbu_rowid, a, b, c, rbu_control);
|
||||
INSERT INTO data0_t1 VALUES(1, NULL, NULL, NULL, 1);
|
||||
INSERT INTO data0_t1 VALUES(2, NULL, NULL, 7, '..x');
|
||||
CREATE TABLE rbu_count(tbl, cnt);
|
||||
INSERT INTO rbu_count VALUES('data0_t1', 2);
|
||||
}
|
||||
{2500 4000 6000 8000 10000}
|
||||
{5000 10000}
|
||||
} {
|
||||
|
||||
reset_db ; execsql $tbl
|
||||
do_test 5.$tn.$bReopen.$tn2.0 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(5, 5, 5);
|
||||
INSERT INTO t1 VALUES(10, 10, 10);
|
||||
}
|
||||
create_db_file rbu.db $rbusql
|
||||
} {}
|
||||
|
||||
set R(nopk) $r1
|
||||
set R(vtab) $r2
|
||||
do_sp_test 5.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+309
-87
@@ -147,14 +147,15 @@
|
||||
** RBU_STATE_OALSZ:
|
||||
** Valid if STAGE==1. The size in bytes of the *-oal file.
|
||||
*/
|
||||
#define RBU_STATE_STAGE 1
|
||||
#define RBU_STATE_TBL 2
|
||||
#define RBU_STATE_IDX 3
|
||||
#define RBU_STATE_ROW 4
|
||||
#define RBU_STATE_PROGRESS 5
|
||||
#define RBU_STATE_CKPT 6
|
||||
#define RBU_STATE_COOKIE 7
|
||||
#define RBU_STATE_OALSZ 8
|
||||
#define RBU_STATE_STAGE 1
|
||||
#define RBU_STATE_TBL 2
|
||||
#define RBU_STATE_IDX 3
|
||||
#define RBU_STATE_ROW 4
|
||||
#define RBU_STATE_PROGRESS 5
|
||||
#define RBU_STATE_CKPT 6
|
||||
#define RBU_STATE_COOKIE 7
|
||||
#define RBU_STATE_OALSZ 8
|
||||
#define RBU_STATE_PHASEONESTEP 9
|
||||
|
||||
#define RBU_STAGE_OAL 1
|
||||
#define RBU_STAGE_MOVE 2
|
||||
@@ -200,6 +201,7 @@ struct RbuState {
|
||||
i64 nProgress;
|
||||
u32 iCookie;
|
||||
i64 iOalSz;
|
||||
i64 nPhaseOneStep;
|
||||
};
|
||||
|
||||
struct RbuUpdateStmt {
|
||||
@@ -244,6 +246,7 @@ struct RbuObjIter {
|
||||
int iTnum; /* Root page of current object */
|
||||
int iPkTnum; /* If eType==EXTERNAL, root of PK index */
|
||||
int bUnique; /* Current index is unique */
|
||||
int nIndex; /* Number of aux. indexes on table zTbl */
|
||||
|
||||
/* Statements created by rbuObjIterPrepareAll() */
|
||||
int nCol; /* Number of columns in current object */
|
||||
@@ -280,10 +283,11 @@ struct RbuObjIter {
|
||||
*/
|
||||
#define RBU_INSERT 1 /* Insert on a main table b-tree */
|
||||
#define RBU_DELETE 2 /* Delete a row from a main table b-tree */
|
||||
#define RBU_IDX_DELETE 3 /* Delete a row from an aux. index b-tree */
|
||||
#define RBU_IDX_INSERT 4 /* Insert on an aux. index b-tree */
|
||||
#define RBU_UPDATE 5 /* Update a row in a main table b-tree */
|
||||
#define RBU_REPLACE 3 /* Delete and then insert a row */
|
||||
#define RBU_IDX_DELETE 4 /* Delete a row from an aux. index b-tree */
|
||||
#define RBU_IDX_INSERT 5 /* Insert on an aux. index b-tree */
|
||||
|
||||
#define RBU_UPDATE 6 /* Update a row in a main table b-tree */
|
||||
|
||||
/*
|
||||
** A single step of an incremental checkpoint - frame iWalFrame of the wal
|
||||
@@ -296,6 +300,43 @@ struct RbuFrame {
|
||||
|
||||
/*
|
||||
** RBU handle.
|
||||
**
|
||||
** nPhaseOneStep:
|
||||
** If the RBU database contains an rbu_count table, this value is set to
|
||||
** a running estimate of the number of b-tree operations required to
|
||||
** finish populating the *-oal file. This allows the sqlite3_bp_progress()
|
||||
** API to calculate the permyriadage progress of populating the *-oal file
|
||||
** using the formula:
|
||||
**
|
||||
** permyriadage = (10000 * nProgress) / nPhaseOneStep
|
||||
**
|
||||
** nPhaseOneStep is initialized to the sum of:
|
||||
**
|
||||
** nRow * (nIndex + 1)
|
||||
**
|
||||
** for all source tables in the RBU database, where nRow is the number
|
||||
** of rows in the source table and nIndex the number of indexes on the
|
||||
** corresponding target database table.
|
||||
**
|
||||
** This estimate is accurate if the RBU update consists entirely of
|
||||
** INSERT operations. However, it is inaccurate if:
|
||||
**
|
||||
** * the RBU update contains any UPDATE operations. If the PK specified
|
||||
** for an UPDATE operation does not exist in the target table, then
|
||||
** no b-tree operations are required on index b-trees. Or if the
|
||||
** specified PK does exist, then (nIndex*2) such operations are
|
||||
** required (one delete and one insert on each index b-tree).
|
||||
**
|
||||
** * the RBU update contains any DELETE operations for which the specified
|
||||
** PK does not exist. In this case no operations are required on index
|
||||
** b-trees.
|
||||
**
|
||||
** * the RBU update contains REPLACE operations. These are similar to
|
||||
** UPDATE operations.
|
||||
**
|
||||
** nPhaseOneStep is updated to account for the conditions above during the
|
||||
** first pass of each source table. The updated nPhaseOneStep value is
|
||||
** stored in the rbu_state table if the RBU update is suspended.
|
||||
*/
|
||||
struct sqlite3rbu {
|
||||
int eStage; /* Value of RBU_STATE_STAGE field */
|
||||
@@ -313,6 +354,7 @@ struct sqlite3rbu {
|
||||
const char *zVfsName; /* Name of automatically created rbu vfs */
|
||||
rbu_file *pTargetFd; /* File handle open on target db */
|
||||
i64 iOalSz;
|
||||
i64 nPhaseOneStep;
|
||||
|
||||
/* The following state variables are used as part of the incremental
|
||||
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
|
||||
@@ -1143,6 +1185,7 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
|
||||
);
|
||||
}
|
||||
|
||||
pIter->nIndex = 0;
|
||||
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
|
||||
const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
|
||||
sqlite3_stmt *pXInfo = 0;
|
||||
@@ -1156,6 +1199,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
|
||||
}
|
||||
rbuFinalize(p, pXInfo);
|
||||
bIndex = 1;
|
||||
pIter->nIndex++;
|
||||
}
|
||||
|
||||
if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
|
||||
/* "PRAGMA index_list" includes the main PK b-tree */
|
||||
pIter->nIndex--;
|
||||
}
|
||||
|
||||
rbuFinalize(p, pList);
|
||||
@@ -1269,6 +1318,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
|
||||
rbuFinalize(p, pStmt);
|
||||
rbuObjIterCacheIndexedCols(p, pIter);
|
||||
assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 );
|
||||
assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 );
|
||||
}
|
||||
|
||||
return p->rc;
|
||||
@@ -1822,6 +1872,14 @@ static void rbuTmpInsertFunc(
|
||||
int rc = SQLITE_OK;
|
||||
int i;
|
||||
|
||||
assert( sqlite3_value_int(apVal[0])!=0
|
||||
|| p->objiter.eType==RBU_PK_EXTERNAL
|
||||
|| p->objiter.eType==RBU_PK_NONE
|
||||
);
|
||||
if( sqlite3_value_int(apVal[0])!=0 ){
|
||||
p->nPhaseOneStep += p->objiter.nIndex;
|
||||
}
|
||||
|
||||
for(i=0; rc==SQLITE_OK && i<nVal; i++){
|
||||
rc = sqlite3_bind_value(p->objiter.pTmpInsert, i+1, apVal[i]);
|
||||
}
|
||||
@@ -1909,13 +1967,13 @@ static int rbuObjIterPrepareAll(
|
||||
);
|
||||
}else{
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
|
||||
"UNION ALL "
|
||||
"SELECT %s, rbu_control FROM '%q' "
|
||||
"WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
|
||||
"UNION ALL "
|
||||
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
|
||||
"ORDER BY %s%s",
|
||||
zCollist, pIter->zDataTbl,
|
||||
zCollist, p->zStateDb, pIter->zDataTbl,
|
||||
zCollist, pIter->zDataTbl,
|
||||
zCollist, zLimit
|
||||
);
|
||||
}
|
||||
@@ -1981,17 +2039,17 @@ static int rbuObjIterPrepareAll(
|
||||
rbuMPrintfExec(p, p->dbMain,
|
||||
"CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" "
|
||||
"BEGIN "
|
||||
" SELECT rbu_tmp_insert(2, %s);"
|
||||
" SELECT rbu_tmp_insert(3, %s);"
|
||||
"END;"
|
||||
|
||||
"CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" "
|
||||
"BEGIN "
|
||||
" SELECT rbu_tmp_insert(2, %s);"
|
||||
" SELECT rbu_tmp_insert(3, %s);"
|
||||
"END;"
|
||||
|
||||
"CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" "
|
||||
"BEGIN "
|
||||
" SELECT rbu_tmp_insert(3, %s);"
|
||||
" SELECT rbu_tmp_insert(4, %s);"
|
||||
"END;",
|
||||
zWrite, zTbl, zOldlist,
|
||||
zWrite, zTbl, zOldlist,
|
||||
@@ -2509,14 +2567,12 @@ static int rbuStepType(sqlite3rbu *p, const char **pzMask){
|
||||
switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
|
||||
case SQLITE_INTEGER: {
|
||||
int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
|
||||
if( iVal==0 ){
|
||||
res = RBU_INSERT;
|
||||
}else if( iVal==1 ){
|
||||
res = RBU_DELETE;
|
||||
}else if( iVal==2 ){
|
||||
res = RBU_IDX_DELETE;
|
||||
}else if( iVal==3 ){
|
||||
res = RBU_IDX_INSERT;
|
||||
switch( iVal ){
|
||||
case 0: res = RBU_INSERT; break;
|
||||
case 1: res = RBU_DELETE; break;
|
||||
case 2: res = RBU_REPLACE; break;
|
||||
case 3: res = RBU_IDX_DELETE; break;
|
||||
case 4: res = RBU_IDX_INSERT; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2555,6 +2611,78 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
|
||||
# define assertColumnName(x,y,z)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
|
||||
** RBU_IDX_DELETE. This function performs the work of a single
|
||||
** sqlite3rbu_step() call for the type of operation specified by eType.
|
||||
*/
|
||||
static void rbuStepOneOp(sqlite3rbu *p, int eType){
|
||||
RbuObjIter *pIter = &p->objiter;
|
||||
sqlite3_value *pVal;
|
||||
sqlite3_stmt *pWriter;
|
||||
int i;
|
||||
|
||||
assert( p->rc==SQLITE_OK );
|
||||
assert( eType!=RBU_DELETE || pIter->zIdx==0 );
|
||||
assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
|
||||
|| eType==RBU_INSERT || eType==RBU_IDX_INSERT
|
||||
);
|
||||
|
||||
/* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
|
||||
** statement below does actually delete a row, nPhaseOneStep will be
|
||||
** incremented by the same amount when SQL function rbu_tmp_insert()
|
||||
** is invoked by the trigger. */
|
||||
if( eType==RBU_DELETE ){
|
||||
p->nPhaseOneStep -= p->objiter.nIndex;
|
||||
}
|
||||
|
||||
if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
|
||||
pWriter = pIter->pDelete;
|
||||
}else{
|
||||
pWriter = pIter->pInsert;
|
||||
}
|
||||
|
||||
for(i=0; i<pIter->nCol; i++){
|
||||
/* If this is an INSERT into a table b-tree and the table has an
|
||||
** explicit INTEGER PRIMARY KEY, check that this is not an attempt
|
||||
** to write a NULL into the IPK column. That is not permitted. */
|
||||
if( eType==RBU_INSERT
|
||||
&& pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
|
||||
&& sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
|
||||
){
|
||||
p->rc = SQLITE_MISMATCH;
|
||||
p->zErrmsg = sqlite3_mprintf("datatype mismatch");
|
||||
return;
|
||||
}
|
||||
|
||||
if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
|
||||
continue;
|
||||
}
|
||||
|
||||
pVal = sqlite3_column_value(pIter->pSelect, i);
|
||||
p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
|
||||
if( p->rc ) return;
|
||||
}
|
||||
if( pIter->zIdx==0
|
||||
&& (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
|
||||
){
|
||||
/* For a virtual table, or a table with no primary key, the
|
||||
** SELECT statement is:
|
||||
**
|
||||
** SELECT <cols>, rbu_control, rbu_rowid FROM ....
|
||||
**
|
||||
** Hence column_value(pIter->nCol+1).
|
||||
*/
|
||||
assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
|
||||
pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
|
||||
p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
|
||||
}
|
||||
if( p->rc==SQLITE_OK ){
|
||||
sqlite3_step(pWriter);
|
||||
p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function does the work for an sqlite3rbu_step() call.
|
||||
**
|
||||
@@ -2569,78 +2697,36 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
|
||||
static int rbuStep(sqlite3rbu *p){
|
||||
RbuObjIter *pIter = &p->objiter;
|
||||
const char *zMask = 0;
|
||||
int i;
|
||||
int eType = rbuStepType(p, &zMask);
|
||||
|
||||
if( eType ){
|
||||
assert( eType==RBU_INSERT || eType==RBU_DELETE
|
||||
|| eType==RBU_REPLACE || eType==RBU_IDX_DELETE
|
||||
|| eType==RBU_IDX_INSERT || eType==RBU_UPDATE
|
||||
);
|
||||
assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
|
||||
|
||||
if( pIter->zIdx==0 && eType==RBU_IDX_DELETE ){
|
||||
if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
|
||||
rbuBadControlError(p);
|
||||
}
|
||||
else if(
|
||||
eType==RBU_INSERT
|
||||
|| eType==RBU_DELETE
|
||||
|| eType==RBU_IDX_DELETE
|
||||
|| eType==RBU_IDX_INSERT
|
||||
){
|
||||
sqlite3_value *pVal;
|
||||
sqlite3_stmt *pWriter;
|
||||
|
||||
assert( eType!=RBU_UPDATE );
|
||||
assert( eType!=RBU_DELETE || pIter->zIdx==0 );
|
||||
|
||||
if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
|
||||
pWriter = pIter->pDelete;
|
||||
}else{
|
||||
pWriter = pIter->pInsert;
|
||||
else if( eType==RBU_REPLACE ){
|
||||
if( pIter->zIdx==0 ){
|
||||
p->nPhaseOneStep += p->objiter.nIndex;
|
||||
rbuStepOneOp(p, RBU_DELETE);
|
||||
}
|
||||
|
||||
for(i=0; i<pIter->nCol; i++){
|
||||
/* If this is an INSERT into a table b-tree and the table has an
|
||||
** explicit INTEGER PRIMARY KEY, check that this is not an attempt
|
||||
** to write a NULL into the IPK column. That is not permitted. */
|
||||
if( eType==RBU_INSERT
|
||||
&& pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
|
||||
&& sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
|
||||
){
|
||||
p->rc = SQLITE_MISMATCH;
|
||||
p->zErrmsg = sqlite3_mprintf("datatype mismatch");
|
||||
goto step_out;
|
||||
}
|
||||
|
||||
if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
|
||||
continue;
|
||||
}
|
||||
|
||||
pVal = sqlite3_column_value(pIter->pSelect, i);
|
||||
p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
|
||||
if( p->rc ) goto step_out;
|
||||
}
|
||||
if( pIter->zIdx==0
|
||||
&& (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
|
||||
){
|
||||
/* For a virtual table, or a table with no primary key, the
|
||||
** SELECT statement is:
|
||||
**
|
||||
** SELECT <cols>, rbu_control, rbu_rowid FROM ....
|
||||
**
|
||||
** Hence column_value(pIter->nCol+1).
|
||||
*/
|
||||
assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
|
||||
pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
|
||||
p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
|
||||
}
|
||||
if( p->rc==SQLITE_OK ){
|
||||
sqlite3_step(pWriter);
|
||||
p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
|
||||
}
|
||||
}else{
|
||||
if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
|
||||
}
|
||||
else if( eType!=RBU_UPDATE ){
|
||||
rbuStepOneOp(p, eType);
|
||||
}
|
||||
else{
|
||||
sqlite3_value *pVal;
|
||||
sqlite3_stmt *pUpdate = 0;
|
||||
assert( eType==RBU_UPDATE );
|
||||
p->nPhaseOneStep -= p->objiter.nIndex;
|
||||
rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
|
||||
if( pUpdate ){
|
||||
int i;
|
||||
for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
|
||||
char c = zMask[pIter->aiSrcOrder[i]];
|
||||
pVal = sqlite3_column_value(pIter->pSelect, i);
|
||||
@@ -2663,8 +2749,6 @@ static int rbuStep(sqlite3rbu *p){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
step_out:
|
||||
return p->rc;
|
||||
}
|
||||
|
||||
@@ -2717,6 +2801,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
|
||||
"(%d, %d), "
|
||||
"(%d, %lld), "
|
||||
"(%d, %lld), "
|
||||
"(%d, %lld), "
|
||||
"(%d, %lld) ",
|
||||
p->zStateDb,
|
||||
RBU_STATE_STAGE, eStage,
|
||||
@@ -2726,7 +2811,8 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
|
||||
RBU_STATE_PROGRESS, p->nProgress,
|
||||
RBU_STATE_CKPT, p->iWalCksum,
|
||||
RBU_STATE_COOKIE, (i64)p->pTargetFd->iCookie,
|
||||
RBU_STATE_OALSZ, p->iOalSz
|
||||
RBU_STATE_OALSZ, p->iOalSz,
|
||||
RBU_STATE_PHASEONESTEP, p->nPhaseOneStep
|
||||
)
|
||||
);
|
||||
assert( pInsert==0 || rc==SQLITE_OK );
|
||||
@@ -2913,6 +2999,10 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
|
||||
pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
|
||||
break;
|
||||
|
||||
case RBU_STATE_PHASEONESTEP:
|
||||
pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = SQLITE_CORRUPT;
|
||||
break;
|
||||
@@ -3020,6 +3110,100 @@ static void rbuDeleteVfs(sqlite3rbu *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This user-defined SQL function is invoked with a single argument - the
|
||||
** name of a table expected to appear in the target database. It returns
|
||||
** the number of auxilliary indexes on the table.
|
||||
*/
|
||||
static void rbuIndexCntFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char *zErrmsg = 0;
|
||||
int rc;
|
||||
|
||||
assert( nVal==1 );
|
||||
|
||||
rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg,
|
||||
sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
|
||||
"WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
|
||||
);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_result_error(pCtx, zErrmsg, -1);
|
||||
}else{
|
||||
int nIndex = 0;
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
nIndex = sqlite3_column_int(pStmt, 0);
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_result_int(pCtx, nIndex);
|
||||
}else{
|
||||
sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(zErrmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** If the RBU database contains the rbu_count table, use it to initialize
|
||||
** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
|
||||
** is assumed to contain the same columns as:
|
||||
**
|
||||
** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
|
||||
**
|
||||
** There should be one row in the table for each data_xxx table in the
|
||||
** database. The 'tbl' column should contain the name of a data_xxx table,
|
||||
** and the cnt column the number of rows it contains.
|
||||
**
|
||||
** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
|
||||
** for all rows in the rbu_count table, where nIndex is the number of
|
||||
** indexes on the corresponding target database table.
|
||||
*/
|
||||
static void rbuInitPhaseOneSteps(sqlite3rbu *p){
|
||||
if( p->rc==SQLITE_OK ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int bExists = 0; /* True if rbu_count exists */
|
||||
|
||||
p->nPhaseOneStep = -1;
|
||||
|
||||
p->rc = sqlite3_create_function(p->dbRbu,
|
||||
"rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
|
||||
);
|
||||
|
||||
/* Check for the rbu_count table. If it does not exist, or if an error
|
||||
** occurs, nPhaseOneStep will be left set to -1. */
|
||||
if( p->rc==SQLITE_OK ){
|
||||
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
|
||||
"SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
|
||||
);
|
||||
}
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
bExists = 1;
|
||||
}
|
||||
p->rc = sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
if( p->rc==SQLITE_OK && bExists ){
|
||||
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
|
||||
"SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
|
||||
"FROM rbu_count"
|
||||
);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
|
||||
}
|
||||
p->rc = sqlite3_finalize(pStmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Open and return a new RBU handle.
|
||||
*/
|
||||
@@ -3065,9 +3249,11 @@ sqlite3rbu *sqlite3rbu_open(
|
||||
|
||||
if( pState->eStage==0 ){
|
||||
rbuDeleteOalFile(p);
|
||||
rbuInitPhaseOneSteps(p);
|
||||
p->eStage = RBU_STAGE_OAL;
|
||||
}else{
|
||||
p->eStage = pState->eStage;
|
||||
p->nPhaseOneStep = pState->nPhaseOneStep;
|
||||
}
|
||||
p->nProgress = pState->nProgress;
|
||||
p->iOalSz = pState->iOalSz;
|
||||
@@ -3231,6 +3417,42 @@ sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){
|
||||
return pRbu->nProgress;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return permyriadage progress indications for the two main stages of
|
||||
** an RBU update.
|
||||
*/
|
||||
void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
|
||||
const int MAX_PROGRESS = 10000;
|
||||
switch( p->eStage ){
|
||||
case RBU_STAGE_OAL:
|
||||
if( p->nPhaseOneStep>0 ){
|
||||
*pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
|
||||
}else{
|
||||
*pnOne = -1;
|
||||
}
|
||||
*pnTwo = 0;
|
||||
break;
|
||||
|
||||
case RBU_STAGE_MOVE:
|
||||
*pnOne = MAX_PROGRESS;
|
||||
*pnTwo = 0;
|
||||
break;
|
||||
|
||||
case RBU_STAGE_CKPT:
|
||||
*pnOne = MAX_PROGRESS;
|
||||
*pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
|
||||
break;
|
||||
|
||||
case RBU_STAGE_DONE:
|
||||
*pnOne = MAX_PROGRESS;
|
||||
*pnTwo = MAX_PROGRESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
int sqlite3rbu_savestate(sqlite3rbu *p){
|
||||
int rc = p->rc;
|
||||
|
||||
|
||||
@@ -400,6 +400,48 @@ int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
|
||||
*/
|
||||
sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
|
||||
|
||||
/*
|
||||
** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
|
||||
** progress indications for the two stages of an RBU update. This API may
|
||||
** be useful for driving GUI progress indicators and similar.
|
||||
**
|
||||
** An RBU update is divided into two stages:
|
||||
**
|
||||
** * Stage 1, in which changes are accumulated in an oal/wal file, and
|
||||
** * Stage 2, in which the contents of the wal file are copied into the
|
||||
** main database.
|
||||
**
|
||||
** The update is visible to non-RBU clients during stage 2. During stage 1
|
||||
** non-RBU reader clients may see the original database.
|
||||
**
|
||||
** If this API is called during stage 2 of the update, output variable
|
||||
** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
|
||||
** to a value between 0 and 10000 to indicate the permyriadage progress of
|
||||
** stage 2. A value of 5000 indicates that stage 2 is half finished,
|
||||
** 9000 indicates that it is 90% finished, and so on.
|
||||
**
|
||||
** If this API is called during stage 1 of the update, output variable
|
||||
** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
|
||||
** value to which (*pnOne) is set depends on whether or not the RBU
|
||||
** database contains an "rbu_count" table. The rbu_count table, if it
|
||||
** exists, must contain the same columns as the following:
|
||||
**
|
||||
** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
|
||||
**
|
||||
** There must be one row in the table for each source (data_xxx) table within
|
||||
** the RBU database. The 'tbl' column should contain the name of the source
|
||||
** table. The 'cnt' column should contain the number of rows within the
|
||||
** source table.
|
||||
**
|
||||
** If the rbu_count table is present and populated correctly and this
|
||||
** API is called during stage 1, the *pnOne output variable is set to the
|
||||
** permyriadage progress of the same stage. If the rbu_count table does
|
||||
** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count
|
||||
** table exists but is not correctly populated, the value of the *pnOne
|
||||
** output variable during stage 1 is undefined.
|
||||
*/
|
||||
void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
|
||||
|
||||
/*
|
||||
** Create an RBU VFS named zName that accesses the underlying file-system
|
||||
** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
|
||||
|
||||
@@ -66,6 +66,7 @@ static int test_sqlite3rbu_cmd(
|
||||
{"create_rbu_delta", 2, ""}, /* 2 */
|
||||
{"savestate", 2, ""}, /* 3 */
|
||||
{"dbMain_eval", 3, "SQL"}, /* 4 */
|
||||
{"bp_progress", 2, ""}, /* 5 */
|
||||
{0,0,0}
|
||||
};
|
||||
int iCmd;
|
||||
@@ -136,6 +137,18 @@ static int test_sqlite3rbu_cmd(
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: /* bp_progress */ {
|
||||
int one, two;
|
||||
Tcl_Obj *pObj;
|
||||
sqlite3rbu_bp_progress(pRbu, &one, &two);
|
||||
|
||||
pObj = Tcl_NewObj();
|
||||
Tcl_ListObjAppendElement(interp, pObj, Tcl_NewIntObj(one));
|
||||
Tcl_ListObjAppendElement(interp, pObj, Tcl_NewIntObj(two));
|
||||
Tcl_SetObjResult(interp, pObj);
|
||||
break;
|
||||
}
|
||||
|
||||
default: /* seems unlikely */
|
||||
assert( !"cannot happen" );
|
||||
break;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
C Make\sthe\sSQLITE_DEFAULT_SYNCHRONOUS\sand\sSQLITE_DEFAULT_WAL_SYNCHRONOUS\nvalues\szero-based\sto\sagree\swith\sPRAGMA\ssynchronous.
|
||||
D 2016-03-08T15:30:01.003
|
||||
C Version\s3.12.1
|
||||
D 2016-04-08T15:09:49.426
|
||||
F Makefile.in f53429fb2f313c099283659d0df6f20f932c861f
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc df0bf9ff7f8b3f4dd9fb4cc43f92fe58f6ec5c66
|
||||
F Makefile.msc b00bcf0ec7001857aea81ee39fae45d20f5f4e59
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION c6b1f51809551d60ad001e6d87cf3ab2c7f54b6f
|
||||
F VERSION 427ed37b414e0f9981a0b734fd11cdaefcf4b188
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 4b8bd7896fffb6b22a57747f1f98cba1da9108ae
|
||||
F autoconf/Makefile.msc b8ada5177e6f39c126a88295af5ad0255e08d280
|
||||
F autoconf/Makefile.am 42f7eb1fb2b06ddd6c6adab3e4388cc0a237ba40
|
||||
F autoconf/Makefile.msc 831e7d9c4e5fb3c1e2686465af2193904bcaf892
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 72a5e42beb090b32bca580285dc0ab3c4670adb8
|
||||
F autoconf/configure.ac d807b567f73a2b0986ccdd206b782cecb4d08fff
|
||||
F autoconf/tea/Makefile.in b438a7020446c8a8156e8d97c8914a04833da6fd
|
||||
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
|
||||
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
|
||||
@@ -30,10 +30,10 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure c01a159fdf7ea0171ad01ce2937283f2c7972bde x
|
||||
F configure d4a18d52bb74b2fdcabb372cafa492434baec670 x
|
||||
F configure.ac 89e4e02a83d8a1528011f8395621b8c3186b4089
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html c30255bea0fd87a81f082d17a72c9dffbc3f6dd9
|
||||
F doc/lemon.html e2118945e5f07ed146b45c9cd2b2dd6eabb8ebf2
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
|
||||
@@ -88,7 +88,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c a93f5edc0aff44ef8b06d7cb55b52026541ca145
|
||||
F ext/fts3/fts3_unicode2.c c3d01968d497bd7001e7dc774ba75b372738c057
|
||||
F ext/fts3/fts3_write.c f56345c64387ca30bf91b91511082fa83d9b5178
|
||||
F ext/fts3/fts3_write.c c3863f23b6b4623c8b9d5cf31c12ce4469f78ca9
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3view.c 5d78b668f4e9598af9147f8999632599fb0d9dd5
|
||||
@@ -98,26 +98,26 @@ F ext/fts3/unicode/mkunicode.tcl 2debed3f582d77b3fdd0b8830880250021571fd8
|
||||
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h ff9c2782e8ed890b0de2f697a8d63971939e70c7
|
||||
F ext/fts5/fts5Int.h fa7c17e5c3ec9c8690387ff962f9dc6aee75e114
|
||||
F ext/fts5/fts5Int.h 3677076aecbf645a7f2a019115c6a4ec3272dd78
|
||||
F ext/fts5/fts5_aux.c daa57fb45216491814520bbb587e97bf81ced458
|
||||
F ext/fts5/fts5_buffer.c 4c1502d4c956cd092c89ce4480867f9d8bf325cd
|
||||
F ext/fts5/fts5_config.c 35c5173cae4eb17e82164a7f5aeef56a48903079
|
||||
F ext/fts5/fts5_expr.c 8e8e4635f655133eb39018072fc0f0942a2c4337
|
||||
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c 5ca4bafe29aa3d27683c90e836192e4aefd20a3f
|
||||
F ext/fts5/fts5_hash.c f3a7217c86eb8f272871be5f6aa1b6798960a337
|
||||
F ext/fts5/fts5_index.c 26a4a6112864feb599a6f6144d06a78bb179736a
|
||||
F ext/fts5/fts5_main.c db24ac714c6c4a1b3c24a1f8c25889f2952148c1
|
||||
F ext/fts5/fts5_storage.c f8343db90d8c95a4d4b52f6676e354b4649ffd6e
|
||||
F ext/fts5/fts5_index.c fdd82bb421a5d1e64d004acb43f4dd9970c8d2b3
|
||||
F ext/fts5/fts5_main.c b4a0fc5bf17f2f1f056ee76cdd7d2af08b360f55
|
||||
F ext/fts5/fts5_storage.c 3309c6a8e34b974513016fd1ef47c83f5898f94c
|
||||
F ext/fts5/fts5_tcl.c f8731e0508299bd43f1a2eff7dbeaac870768966
|
||||
F ext/fts5/fts5_test_mi.c b8d04816428202b2898d4ca38deb1739ac0110ae
|
||||
F ext/fts5/fts5_test_mi.c 783b86697ebf773c18fc109992426c0173a055bc
|
||||
F ext/fts5/fts5_test_tok.c db08af63673c3a7d39f053b36fd6e065017706be
|
||||
F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
|
||||
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
|
||||
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
|
||||
F ext/fts5/fts5_vocab.c dba72ca393d71c2588548b51380387f6b44c77a8
|
||||
F ext/fts5/fts5parse.y 86fe6ba094a47e02fe8be2571539e6833d197764
|
||||
F ext/fts5/fts5parse.y fcc5e92e570d38cab38488b2109cbf67468923b2
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl b9b1fed811c0390511cef8b254826ea15d380f4d
|
||||
F ext/fts5/test/fts5aa.test 7e814df4a0e6c22a6fe2d84f210fdc0b5068a084
|
||||
F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841
|
||||
F ext/fts5/test/fts5aa.test bd2d88182b9f7f30d300044048ad14683306b745
|
||||
F ext/fts5/test/fts5ab.test 30325a89453280160106be411bba3acf138e6d1b
|
||||
F ext/fts5/test/fts5ac.test 55cad4275a1f5acabfe14d8442a8046b47e49e5f
|
||||
F ext/fts5/test/fts5ad.test 36995f0586f30f5602074e012b9224c71ec5171c
|
||||
@@ -136,37 +136,40 @@ F ext/fts5/test/fts5auxdata.test 141a7cbffcceb1bd2799b4b29c183ff8780d586e
|
||||
F ext/fts5/test/fts5bigpl.test 04ee0d7eebbebf17c31f5a0b5c5f9494eac3a0cb
|
||||
F ext/fts5/test/fts5bigtok.test 017a9397b14e7598883a6328ead4a6539b42d59a
|
||||
F ext/fts5/test/fts5columnsize.test a8cfef21ffa1c264b9f670a7d94eeaccb5341c07
|
||||
F ext/fts5/test/fts5config.test 8b2bc6dcc0eb06fa2b7dd65b2ce2db09e829e873
|
||||
F ext/fts5/test/fts5config.test 7788b9c058074d640dfcdd81d97b6a9480000368
|
||||
F ext/fts5/test/fts5conflict.test 26f4e46c4d31e16221794832a990dc4e30e18de5
|
||||
F ext/fts5/test/fts5content.test 9a952c95518a14182dc3b59e3c8fa71cda82a4e1
|
||||
F ext/fts5/test/fts5corrupt.test c2ad090192708150d50d961278df10ae7a4b8b62
|
||||
F ext/fts5/test/fts5corrupt2.test 26c0a39dd9ff73207e6229f83b50b21d37c7658c
|
||||
F ext/fts5/test/fts5corrupt3.test b9558d5b0ca44a8b6247fbb5d4a47592a8976892
|
||||
F ext/fts5/test/fts5corrupt3.test f77f65e386231daf62902466b40ff998b2c8ce4f
|
||||
F ext/fts5/test/fts5detail.test ef5c690535a797413acaf5ad9b8ab5d49972df69
|
||||
F ext/fts5/test/fts5dlidx.test 13871a14641017ae42f6f1055a8067bafd44cb3d
|
||||
F ext/fts5/test/fts5determin.test 10648edb75ef1e196b10978fd21a9be0c31e09c3
|
||||
F ext/fts5/test/fts5dlidx.test 007e9390c94638760797dbec2990c97c3fa08dfe
|
||||
F ext/fts5/test/fts5doclist.test 8edb5b57e5f144030ed74ec00ef6fa4294fed79b
|
||||
F ext/fts5/test/fts5ea.test b01e3a18cdfabbff8104a96a5242a06a68a998a0
|
||||
F ext/fts5/test/fts5eb.test 021aa80b7ac09b964249aa32ced9ee908703e4aa
|
||||
F ext/fts5/test/fts5eb.test c516ae0c934be6fd29ec95ea8b5f11f461311535
|
||||
F ext/fts5/test/fts5fault1.test e09040d3e17b8c0837101e8c79c8a874c4376fb7
|
||||
F ext/fts5/test/fts5fault2.test d8c6c7f916ccbdfc10b2c69530e9dd3bc8313232
|
||||
F ext/fts5/test/fts5fault3.test d6e9577d4312e331a913c72931bf131704efc8f3
|
||||
F ext/fts5/test/fts5fault4.test 532b6dacb963016cbf7003196bd87fb366540277
|
||||
F ext/fts5/test/fts5fault4.test dcbe3043c5611edd350191ea03a8daa190f0de5a
|
||||
F ext/fts5/test/fts5fault5.test 10c13a783de3f42a21e3e53e123b62ed0c3a1618
|
||||
F ext/fts5/test/fts5fault6.test 9682664d679643ac6736e90c225526cc84073cda
|
||||
F ext/fts5/test/fts5fault7.test cb14ea3c1f42394f06f2284abc58eecee6ff8080
|
||||
F ext/fts5/test/fts5fault8.test 430837fe6dd0511fd3aea52bd602ac02441bcb58
|
||||
F ext/fts5/test/fts5fault8.test 6785af34bd1760de74e2824ea9c161965af78f85
|
||||
F ext/fts5/test/fts5fault9.test e10e395428a9ea0596ebe752ff7123d16ab78e08
|
||||
F ext/fts5/test/fts5faultA.test fa5d59c0ff62b7125cd14eee38ded1c46e15a7ea
|
||||
F ext/fts5/test/fts5faultB.test 92ae906284062bf081b6c854afa54dcb1aa9ef88
|
||||
F ext/fts5/test/fts5full.test 6f6143af0c6700501d9fd597189dfab1555bb741
|
||||
F ext/fts5/test/fts5fuzz1.test bece4695fc169b61ab236ada7931c6e4942cbef9
|
||||
F ext/fts5/test/fts5hash.test 06f9309ccb4d5050a131594e9e47d0b21456837d
|
||||
F ext/fts5/test/fts5integrity.test f5e4f8d284385875068ad0f3e894ce43e9de835d
|
||||
F ext/fts5/test/fts5matchinfo.test f7dde99697bcb310ea8faa8eb2714d9f4dfc0e1b
|
||||
F ext/fts5/test/fts5merge.test 8f3cdba2ec9c5e7e568246e81b700ad37f764367
|
||||
F ext/fts5/test/fts5merge.test 9f65f090d214ff865c56bef4f864aaa1182af6e3
|
||||
F ext/fts5/test/fts5merge2.test a6da3c16d694235938d1939f503cfa53f0943d75
|
||||
F ext/fts5/test/fts5multiclient.test 5bd54a6bc8ff818be233a50a8dec93da99098f2a
|
||||
F ext/fts5/test/fts5near.test b214cddb1c1f1bddf45c75af768f20145f7e71cc
|
||||
F ext/fts5/test/fts5onepass.test 7ed9608e258132cb8d55e7c479b08676ad68810c
|
||||
F ext/fts5/test/fts5optimize.test 42741e7c085ee0a1276140a752d4407d97c2c9f5
|
||||
F ext/fts5/test/fts5optimize.test 9d3ac53bb9cae58cb070d795db86bcb2f9fec105
|
||||
F ext/fts5/test/fts5phrase.test f6d1d464da5beb25dc56277aa4f1d6102f0d9a2f
|
||||
F ext/fts5/test/fts5plan.test 6a55ecbac9890765b0e16f8c421c7e0888cfe436
|
||||
F ext/fts5/test/fts5porter.test 7cdc07bef301d70eebbfa75dcaf45c3680e1d0e1
|
||||
@@ -177,7 +180,7 @@ F ext/fts5/test/fts5rank.test 7e9e64eac7245637f6f2033aec4b292aaf611aab
|
||||
F ext/fts5/test/fts5rebuild.test 03935f617ace91ed23a6099c7c74d905227ff29b
|
||||
F ext/fts5/test/fts5restart.test c17728fdea26e7d0f617d22ad5b4b2862b994c17
|
||||
F ext/fts5/test/fts5rowid.test 16908a99d6efc9ba21081b4f2b86b3fc699839a6
|
||||
F ext/fts5/test/fts5simple.test ac5006cc3d0d08b3538e1e76c7300de9f24fbed1
|
||||
F ext/fts5/test/fts5simple.test cd23d4072ea095d652c9b6db12284cc642e49c98
|
||||
F ext/fts5/test/fts5simple2.test 98377ae1ff7749a42c21fe1a139c1ed312522c46
|
||||
F ext/fts5/test/fts5simple3.test 8e71733b3d1b0e695011d02c68ebc5ca40b6124e
|
||||
F ext/fts5/test/fts5synonym.test 6475d189c2e20d60795808f83e36bf9318708d48
|
||||
@@ -193,7 +196,7 @@ F ext/fts5/test/fts5update.test 57c7012a7919889048947addae10e0613df45529
|
||||
F ext/fts5/test/fts5version.test 978f59541d8cef7e8591f8be2115ec5ccb863e2e
|
||||
F ext/fts5/test/fts5vocab.test 480d780aa6b699816c5066225fbd86f3a0239477
|
||||
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
|
||||
F ext/fts5/tool/fts5txt2db.tcl 1343745b89ca2a1e975c23f836d0cee410052975
|
||||
F ext/fts5/tool/fts5txt2db.tcl 526a9979c963f1c54fd50976a05a502e533a4c59
|
||||
F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
|
||||
F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
|
||||
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
||||
@@ -214,13 +217,13 @@ F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/series.c e11e534ada797d5b816d7e7a93c022306563ca35
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 194b5fc3a9a63cb6c5680d8f713800012bddca7c
|
||||
F ext/misc/spellfix.c 598bbc45516227701558becdd38f4e6fe8e97cc2
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rbu/rbu.c ba3983dceffa0938532e79142f391737513de023
|
||||
F ext/rbu/rbu1.test 57601977588603e82700a43c279bd55282ffa482
|
||||
F ext/rbu/rbu1.test 42bd835e019eff789ec241017965277baeb658b1
|
||||
F ext/rbu/rbu10.test 046b0980041d30700464a800bbf6733ed2df515d
|
||||
F ext/rbu/rbu11.test 9bc68c2d3dbeb1720153626e3bd0466dcc017702
|
||||
F ext/rbu/rbu12.test bde22ed0004dd5d1888c72a84ae407e574aeae16
|
||||
@@ -234,16 +237,18 @@ F ext/rbu/rbu8.test 3bbf2c35d71a843c463efe93946f14ad10c3ede0
|
||||
F ext/rbu/rbu9.test 0806d1772c9f4981774ff028de6656e4183082af
|
||||
F ext/rbu/rbuA.test c1a7b3e2d926b8f8448bb3b4ae787e314ee4b2b3
|
||||
F ext/rbu/rbuB.test c25bc325b8072a766e56bb76c001866b405925c2
|
||||
F ext/rbu/rbuC.test efe47db508a0269b683cb2a1913a425ffd39a831
|
||||
F ext/rbu/rbu_common.tcl 0398545fed614f807d5f0ba55a85a51f08ba8f1a
|
||||
F ext/rbu/rbucrash.test 8d2ed5d4b05fef6c00c2a6b5f7ead71fa172a695
|
||||
F ext/rbu/rbudiff.test 6cc806dc36389292f2a8f5842d0103721df4a07d
|
||||
F ext/rbu/rbudiff.test 2df0a8a7d998ecf81764c21eeda3cde5611c5091
|
||||
F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
|
||||
F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
|
||||
F ext/rbu/rbufts.test 828cd689da825f0a7b7c53ffc1f6f7fdb6fa5bda
|
||||
F ext/rbu/rbuprogress.test 2023a7df2c523e3df1cb532eff811cda385a789a
|
||||
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
|
||||
F ext/rbu/sqlite3rbu.c 371e8bf06cfb3f691adac47eb15ab1073ed92dcf
|
||||
F ext/rbu/sqlite3rbu.h 0bdeb3be211aaba7d85445fa36f4701a25a3dbde
|
||||
F ext/rbu/test_rbu.c 4a4cdcef4ef9379fc2a21f008805c80b27bcf573
|
||||
F ext/rbu/sqlite3rbu.c 007fc4db8c0b95c7ef10162b5864921ef5cc8106
|
||||
F ext/rbu/sqlite3rbu.h d7cc99350c10134f358fe1a8997d9225b3f712b2
|
||||
F ext/rbu/test_rbu.c 3505641a78b723589b8780d5f9b2faeeb73e037d
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 0b870ccb7b58b734a2a8e1e2755a7c0ded070920
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
@@ -292,17 +297,17 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c f60f0aa55d25d853ffde53d0b0370a7bb7ee41ce
|
||||
F src/bitvec.c 3ee4c8b2c94ed3a7377256e18199e6ff5cf33f63
|
||||
F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
|
||||
F src/btree.c 2712f087351f5c4ff0e71631b1e67b461611b99d
|
||||
F src/btree.c 577fb5674e2f0aa0a38246afc19e1885a0b8c9b0
|
||||
F src/btree.h a5008b9afe56e8e54ade6c436a910f112defcca9
|
||||
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
|
||||
F src/build.c 43b93fe757bfffe00f97462596418b052eefdccd
|
||||
F src/build.c 84fb5a66c8f38f96b5b2c600b42a649e8cf4dbde
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 60e135af364d777a9ab41c97e5e89cd224da6198
|
||||
F src/date.c 0b73e681c11fca867fec554750c07fe0d4e417c1
|
||||
F src/dbstat.c c845548d4346e606e2f2b7d2e714ace2b8a7dd1b
|
||||
F src/delete.c 48802aa3ee6339f576d074336d3ae1b5f40e240f
|
||||
F src/expr.c c4dad2cd6cec00387b75fef4551aff655430dcd2
|
||||
F src/expr.c 289ffac5240b60fee0a824d3d5ab2d7bd2630c94
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 5cb42d9a59e2a590776fd3fc8ff6f61d40df3c6e
|
||||
F src/func.c 552d300265aed09eea21f68ac742a440550c0062
|
||||
@@ -312,15 +317,15 @@ F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 723d5d708cdb61bdd47c00b9f07c75be45aefc09
|
||||
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
|
||||
F src/loadext.c 9e2a41adcaff16ebc1ebff1f336cbf33de55396f
|
||||
F src/main.c 29ea8ebb23ceb5159da167e18d5c807fbb1545c4
|
||||
F src/loadext.c e70f8f9e97624a232870ea5486e682c813ac3002
|
||||
F src/main.c 63791c66321f07b5828bb9161b477d5e0b511d7e
|
||||
F src/malloc.c 1443d1ad95d67c21d77af7ae3f44678252f0efec
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
|
||||
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
F src/memjournal.c 011da5236a7250385cc74c253f14bbee04c0d61e
|
||||
F src/memjournal.c 2815ef7684671d93a1ec6a31e1e63c45de4b4d31
|
||||
F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495
|
||||
F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
@@ -328,37 +333,37 @@ F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
||||
F src/mutex_unix.c 27bb6cc49485ee46711a6580ab7b3f1402211d23
|
||||
F src/mutex_w32.c 5e6fe1c298fb5a8a15aaed4161d5759311431c17
|
||||
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
|
||||
F src/os.c f89e3ca1c2e3d5015b847aec60371c474acbac82
|
||||
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
|
||||
F src/os.c ca10edb445ad2c5fdc7285b49d72bcdf261fa23e
|
||||
F src/os.h 91ff889115ecd01f436d3611f7f5ea4dc12d92f1
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c f5bac8e74aaefc4ea520e43b4540793c3b8a9e8f
|
||||
F src/os_win.c f0d7aa603eb6262143d7169a222aea07c4fca91d
|
||||
F src/os_unix.c b1ccb273771f41dbdbe0ba7c1ad63c38ad5972ec
|
||||
F src/os_win.c ff870d89f4cb088a04cbf5ea0cbd9ff1b089ff4a
|
||||
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
|
||||
F src/pager.c 17aa37b3b53a62a1bd98fe6f3c758bb41429ef08
|
||||
F src/pager.c 38718a019ca762ba4f6795425d5a54db70d1790d
|
||||
F src/pager.h e1d38a2f14849e219df0f91f8323504d134c8a56
|
||||
F src/parse.y 5ea8c81c5c41b27887f41b4a7e1c58470d7d3821
|
||||
F src/pcache.c 647bb53a86b7bbcf55ad88089b3ea5a9170b90df
|
||||
F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545
|
||||
F src/pcache1.c 72f644dc9e1468c72922eff5904048427b817051
|
||||
F src/pragma.c c7061870c235702a513ce4152fe978faf3f282eb
|
||||
F src/pcache1.c c40cdb93586e21b5dd826b5e671240bd91c26b05
|
||||
F src/pragma.c faf42922bb7ab2f6672cb550356c1967abae3c84
|
||||
F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
|
||||
F src/prepare.c 22df6171aec1d86904ed2ad30c2348a5748aa04e
|
||||
F src/printf.c 63e6fb12bbe702dd664dc3703776c090383a5a26
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c b8f7174e5f8c33c44ded3a25a973d0bb89228c20
|
||||
F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
|
||||
F src/select.c 137b31daa84d57d67847bf621bb54f3353e2077b
|
||||
F src/select.c d9b8628acb98f1a38921888d823a6b70c7a7774b
|
||||
F src/shell.c 5e0ab1e708dc294330ccd8230536e1801f60822e
|
||||
F src/sqlite.h.in 0235586b3fb639e85998d495c90f007657fd82af
|
||||
F src/sqlite.h.in e877f141b15ef68ef28f84714e69d7234f9a071e
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
|
||||
F src/sqliteInt.h b017fbf491606a0fd1a5d43af40dbe965a928ead
|
||||
F src/sqliteLimit.h 7b28cf72cbd52f178bfc97ea266445e351f2cd24
|
||||
F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2
|
||||
F src/sqliteInt.h c4dbe726f4ed1d14469a3cb256cff0e6ed24e0c5
|
||||
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
||||
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
|
||||
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
||||
F src/tclsqlite.c 54dca4eaf3a9cb0a4b845ef54ffa99225c30a52e
|
||||
F src/test1.c f14a6f9e2cff6cba4d83e2b0c52857f61886cead
|
||||
F src/tclsqlite.c 4bf3bea9b03aeac176ac114700f35f76a1de4c8a
|
||||
F src/test1.c 7187b7e924bfc97780e6fd2a40dad94a32bddca0
|
||||
F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b
|
||||
F src/test3.c a8887dabbbee3059af338f20d290084a63ed1b0f
|
||||
F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
|
||||
@@ -373,7 +378,7 @@ F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803
|
||||
F src/test_bestindex.c 29af3cc3b963ffe5760c85d142b9b3e5302c1e3d
|
||||
F src/test_blob.c b2551a9b5573232db5f66f292307c37067937239
|
||||
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
|
||||
F src/test_config.c 0dee90328e3dedf8ba002ee94b6a7e7ea7726fe4
|
||||
F src/test_config.c 0fb2571777ef43a8442be4f9c62a25f530872328
|
||||
F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c f10f840ca4f8c72e4837908bd8347ac4bcab074b
|
||||
@@ -385,7 +390,7 @@ F src/test_intarray.h 9dc57417fb65bc7835cc18548852cc08cc062202
|
||||
F src/test_journal.c 5360fbe1d1e4416ca36290562fd5a2e3f70f32aa
|
||||
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
|
||||
F src/test_malloc.c 96df9381a1ff1f6d3805ff7231b9baf1386aaabf
|
||||
F src/test_multiplex.c 6a088d8d9d4aad4bec45dd8878af11b15900702d
|
||||
F src/test_multiplex.c 6a9de820fcaaf506c59aa14bc8693822333cea48
|
||||
F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3
|
||||
F src/test_mutex.c dbdfaff8580071f2212a0deae3325a93a737819c
|
||||
F src/test_onefile.c 38f7cbe79d5bafe95bde683cc3a53b8ca16daf10
|
||||
@@ -412,23 +417,23 @@ F src/treeview.c e4b41a37530a191579d3c53142cc44ee2eb99373
|
||||
F src/trigger.c e14840ee0c3e549e758ec9bf3e4146e166002280
|
||||
F src/update.c 56b3db7edff0110360a12b76af97c39ebe3ea8b8
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c 12800a93f0664f41575f96799eb881a786d565e6
|
||||
F src/util.c 8873d696c9ccc4206058c402e09e101f1b81561a
|
||||
F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52
|
||||
F src/vdbe.c 87ae3a5657fefed7875f3eb30e7ababd48013d71
|
||||
F src/vdbe.h c743791f723049db94f009e3e30958952bc2d512
|
||||
F src/vdbeInt.h 49a74fe5ece206d2d8666ba9afaf1abeda5f123b
|
||||
F src/vdbe.c cd990451b504507b455cc649d46dad51f2835a67
|
||||
F src/vdbe.h 6f44193e7be52fd5f7c308175a936555b1e6b101
|
||||
F src/vdbeInt.h f88d3115e9bde33b01d81f0dd26d8dd51f995991
|
||||
F src/vdbeapi.c 95b1f8e527240a18a9aea41a655b013bf07a7009
|
||||
F src/vdbeaux.c 2c15cf88de4df97428318c8cfac0dea873dae451
|
||||
F src/vdbeaux.c c8dd3e4e932bede6363b380519d05c0557ad27ce
|
||||
F src/vdbeblob.c 3b570b730109e8f653d9d2081649f6e7015113db
|
||||
F src/vdbemem.c 9b0cb32cc267ef026515f15a3594d5ff91fe4dfc
|
||||
F src/vdbemem.c fe76c1f866de362d9b8332e59d74aa44f6560d69
|
||||
F src/vdbesort.c 307460bfa4de4d1c3901fcd42089159131e34062
|
||||
F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484
|
||||
F src/vtab.c fd69fd398e23e57ea4ea377d8a44b6998fc569c7
|
||||
F src/vtab.c 23b6cdfa996152d43b390504ed4a942c8caf3a00
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 10deb6b43887662691e5f53d10b3c171c401169b
|
||||
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
||||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
F src/where.c dff52f7f0842430f80a7017c7859124685b08453
|
||||
F src/where.c 99cc6270fc3915201e2a90bbac3768f007a89c44
|
||||
F src/whereInt.h 93297d56edd137b7ea004490690fb6e2ce028a34
|
||||
F src/wherecode.c 863aedf086131743763c1960637fde904eadc442
|
||||
F src/whereexpr.c fb87944b1254234e5bba671aaf6dee476241506a
|
||||
@@ -458,7 +463,7 @@ F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
|
||||
F test/analyzeD.test 42af58de25a6436502e43006e9e59e2d71bcb0cf
|
||||
F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d
|
||||
F test/analyzeF.test 5d1fe1024ba2dfea3c18bede8c1ccef8aba1ab34
|
||||
F test/analyzer1.test 498e2ff4b62740c2751c3a2f8b744fe26689fae9
|
||||
F test/analyzer1.test 459fa02c445ddbf0101a3bad47b34290a35f2e49
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
@@ -479,21 +484,21 @@ F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
|
||||
F test/autoindex3.test a3be0d1a53a7d2edff208a5e442312957047e972
|
||||
F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf
|
||||
F test/autoindex5.test 96f084a5e6024ea07cace5888df3223f3ea86990
|
||||
F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
|
||||
F test/autovacuum.test 92c24eedbdb68e49f3fb71f26f9ce6d8988cac15
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
F test/backcompat.test 19a1f337c68419b020a7481dd272a472c4ad8ef4
|
||||
F test/backcompat.test 3e64cedda754c778ef6bbe417b6e7a295e662a4d
|
||||
F test/backup.test b79299a536a4c6d919094786595b95be56d02014
|
||||
F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf
|
||||
F test/backup4.test 2a2e4a64388090b152de753fd9e123f28f6a3bd4
|
||||
F test/backup4.test 8f6fd48e0dfde77b9a3bb26dc471ede3e101df32
|
||||
F test/backup5.test ee5da6d7fe5082f5b9b0bbfa31d016f52412a2e4
|
||||
F test/backup_ioerr.test 4c3c7147cee85b024ecf6e150e090c32fdbb5135
|
||||
F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
|
||||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f
|
||||
F test/bc_common.tcl 3eda41ef9cda7d5f6c205462c96228b301da4191
|
||||
F test/bestindex1.test e228fe1e3794dbe20271481164e000d695abcd24
|
||||
F test/bestindex2.test 10f2c6791f1cd0de414012528cd10a114648fd8f
|
||||
F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c
|
||||
F test/bestindex1.test d5ba89a7941a941476d8d69be39b146aaed3614c
|
||||
F test/bestindex2.test 4a06b8922ab2fd09434870da8d1cdf525aaf7060
|
||||
F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c
|
||||
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
|
||||
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
|
||||
@@ -518,15 +523,15 @@ F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
|
||||
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
|
||||
F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738
|
||||
F test/capi3.test bf6f0308bbbba1e770dac13aa08e5c2ac61c7324
|
||||
F test/capi3.test f0c66919e43d42e1572a69be039e4527a931b00f
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test 06f6261f9e9b4ef6f76afcd9900f3665408af1c8
|
||||
F test/capi3c.test 0b9edb0c2156a964b9271cd5ea7ae56736cc2fcb
|
||||
F test/capi3d.test 485048dc5cd07bc68011e4917ad035ad6047ab82
|
||||
F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/cffault.test aadc1f61f8811cb600e3e069acbf8796f472a096
|
||||
F test/check.test 85a84bfc4be0e83f668747211c7cd45a6721d485
|
||||
F test/close.test 340bd24cc58b16c6bc01967402755027c37eb815
|
||||
F test/close.test 83947daf3b700631f90f4850ddaab455be4af73d
|
||||
F test/closure01.test b1703ba40639cfc9b295cf478d70739415eec6a4
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test 08c18e7512a5a32c97938854263fa15362eeb846
|
||||
@@ -546,24 +551,24 @@ F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
|
||||
F test/conflict3.test dec0634c0f31dec9a4b01c63063e939f0cd21b6b
|
||||
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
|
||||
F test/corrupt.test 141c39ea650c1365e85a49e402fa05cb9617fb97
|
||||
F test/corrupt2.test cb787825d761b0f869764d6990531382840de872
|
||||
F test/corrupt3.test 4b548d0bbe2933bc81d3f54099a05fc4d28aff18
|
||||
F test/corrupt4.test b99652079d542b21f4965f6248703b983e40fe80
|
||||
F test/corrupt2.test e4964cee73dda57a90958e0087a6b388b1d9cb58
|
||||
F test/corrupt3.test e676f478fe602915d721472811f6f410b75ddc7e
|
||||
F test/corrupt4.test 8d1d86b850fcc43e417450454f2044e52d55778a
|
||||
F test/corrupt5.test 8ead52af76006f3286e9396cb41898018ccea107
|
||||
F test/corrupt6.test 269548d19427ac554c830763b1c5ea54a0252f80
|
||||
F test/corrupt7.test e4fa6d6584276679cc1d20c4e58beb9559a4eb85
|
||||
F test/corrupt6.test fc6a891716139665dae0073b6945e3670bf92568
|
||||
F test/corrupt7.test b036f94bda4b0b23a2919bf717046ce9ecca4543
|
||||
F test/corrupt8.test 2399dfe40d2c0c63af86706e30f3e6302a8d0516
|
||||
F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85
|
||||
F test/corruptA.test 53e56dafd180addcdadb402244b8cb9771d2ba26
|
||||
F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec
|
||||
F test/corruptC.test 0c46574f8d4f27ecc799b1b5c4cbf9b1817bce9a
|
||||
F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
|
||||
F test/corruptE.test be8e5088c369fc7979c662cd644efdaafc0f7f6d
|
||||
F test/corruptE.test 82ccf4f8f543fdbedd4aa42c709cb077f7374c62
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
|
||||
F test/corruptH.test 99ad81a4bda7cc078c589ef7542ecbc64e453c80
|
||||
F test/corruptI.test 347babbf970e7947e3f91dccf7a1bec28a1bab04
|
||||
F test/corruptJ.test 9e29e7a81ee3b6ac50f77ea7a9e2f3fa03f32d91
|
||||
F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
|
||||
F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
|
||||
F test/corruptI.test 075fe1d75aa1d84e2949be56b6264376c41502e4
|
||||
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
|
||||
F test/cost.test 1eedbfd868f806f3fa08ff072b04cf270dcf61c8
|
||||
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
|
||||
F test/coveridxscan.test b629e896b14df2f000a99b8d170d80589c46562c
|
||||
@@ -574,7 +579,7 @@ F test/crash4.test fe2821baf37168dc59dd733dcf7dba2a401487bc
|
||||
F test/crash5.test 05dd3aa9dbb751a22d5cdaf22a9c49b6667aa219
|
||||
F test/crash6.test 4c56f1e40d0291e1110790a99807aa875b1647ba
|
||||
F test/crash7.test 1a194c4900a255258cf94b7fcbfd29536db572df
|
||||
F test/crash8.test 61442a9964ab6b124fc5254e4258b45747842e6f
|
||||
F test/crash8.test a63907617d8e74fb54b4bff23eca8a4435625245
|
||||
F test/crashM.test d95f59046fa749b0d0822edf18a717788c8f318d
|
||||
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
|
||||
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
|
||||
@@ -614,20 +619,20 @@ F test/e_select.test 52692ff3849541e828ad4661fe3773a9b8711763
|
||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10
|
||||
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
|
||||
F test/e_uri.test eed3eb41b22d051a1164110dacdc778899126e14
|
||||
F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9
|
||||
F test/e_uri.test 25385396082b67fd02ae0038b95a3b3575fe0519
|
||||
F test/e_vacuum.test 4d5b391384bb7d56bb9337d956f08035332421fc
|
||||
F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625
|
||||
F test/e_walauto.test 280714ddf14e1a47dcbc59d515cd0b026dfd5567
|
||||
F test/e_walauto.test 248af31e73c98df23476a22bdb815524c9dc3ba8
|
||||
F test/e_walckpt.test 28c371a6bb5e5fe7f31679c1df1763a19d19e8a0
|
||||
F test/e_walhook.test 4c0613a0c76e7a9d5c4c211e1b4cbcc1143914df
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
|
||||
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
|
||||
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
|
||||
F test/eqp.test 85873fa5816c48915c82c4e74cb5c35a5b48160f
|
||||
F test/eqp.test 3fe051af50921284189d1970eb653f9fcf5117d2
|
||||
F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401
|
||||
F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
|
||||
F test/exclusive.test f48243eaf40e0957215501a12f510a8644d13a02
|
||||
F test/exclusive.test 9a57bd66e39144b888ca75c309914fcdefb4e3f9
|
||||
F test/exclusive2.test 32798111aae78a5deec980eee383213f189df308
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
|
||||
@@ -636,7 +641,7 @@ F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
|
||||
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
|
||||
F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
|
||||
F test/filectrl.test 7c13f96457435238da99aff7343ad6a3a4885787
|
||||
F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146
|
||||
F test/filefmt.test e4edbdc637ca9576ccf4337a3cce627d9df7a56c
|
||||
F test/fkey1.test 13e3d48236a2b9f5c5ebd232eef9b3ab682a8a2c
|
||||
F test/fkey2.test f3d27ecba480a348c328965d154214719bb158a9
|
||||
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
@@ -744,17 +749,17 @@ F test/fts4aa.test 10aac8e9d62c7357590acfabe3fad01e9a9ce1cb
|
||||
F test/fts4check.test c3056eab9524232e4c9bdcd119912947e07bcc1c
|
||||
F test/fts4content.test 05716af19a899cd70d5cd916c580043c03f30db4
|
||||
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
|
||||
F test/fts4growth.test 60d6bb3f78e25b34f533797dd9f2f9402310a13a
|
||||
F test/fts4growth.test e5390da74619cacc389711bac9349640b32c4f9a
|
||||
F test/fts4growth2.test 13ad4e76451af6e6906c95cdc725d01b00044269
|
||||
F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d
|
||||
F test/fts4langid.test 9794addcc8faaee85ac60eceecdb52feb0c70f68
|
||||
F test/fts4merge.test 146563df4a90ccb7f111a6e11ab29bbfe9e6ce2c
|
||||
F test/fts4langid.test 65a7332c9bc257919e259a304aa8a38c41655b9d
|
||||
F test/fts4merge.test d2b39f6b1bd4a9738a13540e2d044cba11c43d47
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
|
||||
F test/fts4merge3.test 8d9ccb4a3d41c4c617a149d6c4b13ad02de797d0
|
||||
F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b
|
||||
F test/fts4noti.test 5553d7bb2e20bf4a06b23e849352efc022ce6309
|
||||
F test/fts4onepass.test 7319d61a2ed1325fc54afd0c060a0513b462303a
|
||||
F test/fts4opt.test f15c84305c4b78c665fc476d8569e27ab9a0d418
|
||||
F test/fts4opt.test fd6a11684b965e1999564ae763797b7fb9e34c96
|
||||
F test/fts4unicode.test 27378af76394542cf490cf001d8d1505fe55f6a9
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
|
||||
@@ -768,7 +773,7 @@ F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
F test/fuzz3.test b47377143f0c80f91ed29d722861077ff34415d5
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
|
||||
F test/fuzzcheck.c 93bb9d309888634615e21ef98d1c30d51483e942
|
||||
F test/fuzzcheck.c f01d432d001ba29e7916df8411be7d4e7cddc574
|
||||
F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
|
||||
F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
@@ -787,12 +792,12 @@ F test/in.test 61a24ae38d4b64ec69f06ccdf022992f68a98176
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
|
||||
F test/in5.test 1de657472fa9ac2924be25c2c959ac5ca1aae554
|
||||
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
|
||||
F test/in5.test acc710c12af118df5f8645eaba9479f5619eed81
|
||||
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
|
||||
F test/incrblob2.test a5ce5ed1d0b01e2ed347245a21170372528af0a5
|
||||
F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4
|
||||
F test/incrblob4.test f26502a5697893e5acea268c910f16478c2f0fab
|
||||
F test/incrblob_err.test af1f12ba60d220c9752073ff2bda2ad59e88960d
|
||||
F test/incrblob_err.test 69f9247fed50278d48ea710d1a8f9cdb09e4c0b8
|
||||
F test/incrblobfault.test 280474078f6da9e732cd2a215d3d854969014b6e
|
||||
F test/incrcorrupt.test 6c567fbf870aa9e91866fe52ce6f200cd548939a
|
||||
F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32
|
||||
@@ -818,8 +823,8 @@ F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
|
||||
F test/instr.test 737bbf80685232033f3abedc6ae92f75860b5dd2
|
||||
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc
|
||||
F test/intpkey.test 7506090fc08e028712a8bf47e5f54111947e3844
|
||||
F test/io.test 3a7abcef18727cc0f2399e04b0e8903eccae50f8
|
||||
F test/intpkey.test 70aab09756b9bd3bcb6b0358f971d7bbace46522
|
||||
F test/io.test f95bca1783b01ea7761671560d023360d2dfa4cc
|
||||
F test/ioerr.test 2a24bd6ed5a8b062e64bfe1f6cf94fb25e92210d
|
||||
F test/ioerr2.test 2593563599e2cc6b6b4fcf5878b177bdd5d8df26
|
||||
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
@@ -887,7 +892,7 @@ F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test d2b2d6ca37890b26703a2258df8fd66f9869da02
|
||||
F test/memsubsys1.test 6d268d0ae90f8d61a2356a1838665654d83de518
|
||||
F test/memsubsys2.test 3e4a8d0c05fd3e5fa92017c64666730a520c7e08
|
||||
F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
|
||||
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
|
||||
@@ -902,19 +907,19 @@ F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2
|
||||
F test/misc8.test 21ac9d35a5e110279ae9e1588b8914f54de1c60b
|
||||
F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912
|
||||
F test/mmap1.test 44a5ff1c1bcc7dcf2de50227d1f997e75a8ef1ae
|
||||
F test/mmap1.test d2cfc1635171c434dcff0ece2f1c8e0a658807ce
|
||||
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
|
||||
F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e
|
||||
F test/mmap3.test b3c297e78e6a8520aafcc1a8f140535594c9086e
|
||||
F test/mmap4.test 2e2b4e32555b58da15176e6fe750f17c9dcf7f93
|
||||
F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3
|
||||
F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60
|
||||
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
|
||||
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
|
||||
F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4
|
||||
F test/mutex1.test e0a44072d98189003deae4b091106f085d94bea8
|
||||
F test/mutex1.test ea2cc74d97f077b9e74c84cbd024f14d79a8126f
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a
|
||||
F test/nolock.test 0540dd96f39b8876e3ffdd8814fad0ea425efeee
|
||||
F test/nan.test dacc57f80859c06a433d30839336fe227d2038b3
|
||||
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
|
||||
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
|
||||
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
|
||||
@@ -935,23 +940,23 @@ F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
|
||||
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
|
||||
F test/oserror.test b32dc34f2363ef18532e3a0a7358e3e7e321974f
|
||||
F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f
|
||||
F test/pager1.test f49df1a8b0e38b9ee3a7dd2ab4d427507b7314ce
|
||||
F test/pager1.test 841868017e9dd3cb459b8d78862091a7d9cff21d
|
||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
F test/pager4.test a122e9e6925d5b23b31e3dfef8c6a44bbf19590e
|
||||
F test/pagerfault.test ae9ee0db5a30aecda9db8290ce3dd12e5f7bbaa1
|
||||
F test/pagerfault2.test caf4c7facb914fd3b03a17b31ae2b180c8d6ca1f
|
||||
F test/pagerfault3.test 1003fcda009bf48a8e22a516e193b6ef0dd1bbd8
|
||||
F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6
|
||||
F test/pageropt.test 84e4cc5cbca285357f7906e99b21be4f2bf5abc0
|
||||
F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305
|
||||
F test/parser1.test 222b5cbf3e2e659fec1bf7d723488c8b9c94f1d0
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test 64abe58d53cde4adcfb881e37aa5ea1b2a980e58
|
||||
F test/pragma.test 507ac7ef2ea5682241ea0ef041799ca70bb5e0bf
|
||||
F test/permutations.test af8067e4b6d684518956f8e2a744f42bde99014d
|
||||
F test/pragma.test afbf028be1c35b68f57db8eb015c4a3c59d8f28e
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c
|
||||
F test/pragma3.test 3f1984a04657331f838df5c519b443c2088df922
|
||||
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
|
||||
F test/printf2.test 0b61566dd1c0f0b802f59dffa228c5dc5aa6b054
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
@@ -969,7 +974,7 @@ F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
|
||||
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/regexp2.test aa7ffcc21350007a78361b82bcf3b74d12227144
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.tcl a246ecb14ed594bf44bf77bd21df873971d779bf
|
||||
F test/releasetest.tcl f2519836bebefcc7db36b4946e8028d4885baa59
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
|
||||
F test/rollback2.test 8435d6ff0f13f51d2a4181c232e706005fa90fc5
|
||||
@@ -997,7 +1002,7 @@ F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test be62204d2bd9a5a8a149e9974cfddce893d8f686
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test 453631158540e5f685b81cac5b7e8bd8c6b4c5fc
|
||||
F test/select4.test d926792a5e4d88fef0ddcddeb45d27ce75f7296c
|
||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
||||
F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0
|
||||
F test/select7.test 95e370c42d47c3c52377d05e9ffc01ccff7c1f61
|
||||
@@ -1023,11 +1028,11 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
|
||||
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test a45b424ec23a4b946848ff9e1af5186c677162ab
|
||||
F test/shell2.test 12b8bf901b0e3a8ac58cf5c0c63a0a388d4d1862
|
||||
F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
|
||||
F test/shell4.test f43e250139dc5dc5f0f2ec1752c50284a1ede102
|
||||
F test/shell5.test c04e9f9f948305706b88377c464c7f08ce7479f9
|
||||
F test/shell1.test dff5b20ad989770aface6d714491121172dfe8b0
|
||||
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test da513d522ef6f01cee8475dcf8332bff8982b3dd
|
||||
F test/shell4.test 69995ee1cc278eb149aa8746ce1f935f4eaf98b9
|
||||
F test/shell5.test 50a732c1c2158b1cd62cf53975ce1ea7ce6b9dc9
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
|
||||
@@ -1037,8 +1042,8 @@ F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a
|
||||
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
|
||||
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
|
||||
F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b
|
||||
F test/snapshot.test c03eb5ba1602df33c1edc1d12393d6ca7a282a46
|
||||
F test/snapshot_fault.test 25973aeb1b86a280800e0bcf1eb5ce70e9ef57ab
|
||||
F test/snapshot.test 9ed24c792fb05382814258daf68b2256f23de57f
|
||||
F test/snapshot_fault.test 062ff0438a074978d45e9f9a92e7ad459b74ee73
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
|
||||
F test/sort.test c2adc635c2564241fefec0b3a68391ef6868fd3b
|
||||
@@ -1058,11 +1063,11 @@ F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 1478cb3fb64ad30f291ddca87ca9dbd72ff552aa
|
||||
F test/spellfix.test f9c1f431e2c096c8775fec032952320c0e4700db
|
||||
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
|
||||
F test/spellfix3.test f7bf7b3482971473d32b6b00f6944c5c066cff97
|
||||
F test/sqldiff1.test 8f6bc7c6a5b3585d350d779c6078869ba402f8f5
|
||||
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
|
||||
F test/sqldiff1.test 28cd737cf1b0078b1ec1bbf425e674c47785835e
|
||||
F test/sqllimits1.test a74ee2a3740b9f9c2437c246d8fb77354862a142
|
||||
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
|
||||
F test/stat.test acc91e80517fff447ae8adcfd953cfdaa5efc0af
|
||||
F test/stat.test b65bad7120c52583b8f0054d99eff80718119a77
|
||||
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
|
||||
F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f
|
||||
F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
|
||||
@@ -1070,7 +1075,7 @@ F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
|
||||
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
|
||||
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test 2f607e1821aa3af3c5c53b58835c05e511c95899
|
||||
F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c
|
||||
@@ -1079,11 +1084,11 @@ F test/tabfunc01.test f977868fa8bb7beb4b2072883190411653473906
|
||||
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054
|
||||
F test/tclsqlite.test c6d9f546f79d15d0134c1e06583fb3ee0c3afad3
|
||||
F test/tempdb.test bd92eba8f20e16a9136e434e20b280794de3cdb6
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl 750365ff97047ded5f2d6e28df82a998f7c66ae0
|
||||
F test/tester.tcl f2b99e912d4da1e5755969b8614febd883885c8b
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1235,7 +1240,7 @@ F test/tkt3929.test cdf67acf5aa936ec4ffead81db87f8a71fe40e59
|
||||
F test/tkt3935.test e15261fedb9e30a4305a311da614a5d8e693c767
|
||||
F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
|
||||
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
|
||||
F test/tkt4018.test 18dbc6617f7a4b90e938d1bd6d26ad18daafaf08
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4
|
||||
F test/trace.test 6f676313e3ebd2a50585036d2f212a3319dd5836
|
||||
@@ -1280,7 +1285,7 @@ F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
|
||||
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test f6c3a39e0c819891265e1d0754e99960d81ef6c9
|
||||
F test/view.test 765802c7a66d37fabd5ac8e2f2dbe572b43eb9ab
|
||||
F test/vtab1.test 7c4b81abd88361ada9cbe414c459efca26be6bda
|
||||
F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
@@ -1301,18 +1306,18 @@ F test/vtabI.test 751b07636700dbdea328e4265b6077ccd6811a3f
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
|
||||
F test/wal.test 0148c8b3421a25fdb4d9c160e84a681d0646371b
|
||||
F test/wal2.test 25ae059e900dbb584e0775627e45415ba5940df1
|
||||
F test/wal3.test 5dd734147f1f8f958c5261a1f2775d346d7013ce
|
||||
F test/wal.test 613efec03e517e1775d86b993a54877d2e29a477
|
||||
F test/wal2.test 56b0bc95b8693a0be294f8d210c49025dd094bd7
|
||||
F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal5.test 88b5d9a6a3d1532497ee9f4296f010d66f07e33c
|
||||
F test/wal5.test 9c11da7aeccd83a46d79a556ad11a18d3cb15aa9
|
||||
F test/wal6.test a9d6aa635b9d63607dabdc11406f5f96ca986635
|
||||
F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8
|
||||
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
|
||||
F test/wal8.test 75c42e1bc4545c277fed212f8fc9b7723cd02216
|
||||
F test/wal8.test d9df3fba4caad5854ed69ed673c68482514203c8
|
||||
F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750
|
||||
F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
|
||||
F test/walbak.test b9f68e39646375c2b877be906babcc15d38b4877
|
||||
F test/walbak.test 018d4e5a3d45c6298d11b99f09a8ef6876527946
|
||||
F test/walbig.test f437473a16cfb314867c6b5d1dbcd519e73e3434
|
||||
F test/walblock.test be48f3a75eff0b4456209f26b3ce186c2015497d
|
||||
F test/walcksum.test bb234a1bb42248b3515d992b719708015c384278
|
||||
@@ -1326,12 +1331,12 @@ F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
|
||||
F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03
|
||||
F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6
|
||||
F test/walprotocol.test 059cb75484a1ecf6357a2c1b3324b8156749221e
|
||||
F test/walro.test 34422d1d95aaff0388f0791ec20edb34e2a3ed57
|
||||
F test/walro.test 4ab7ac01b77c2f894235c699d59e3e3c7f15a160
|
||||
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test f0c325563acde44f2c4ea6ba348e9e29f7121757
|
||||
F test/where2.test af78c55589cbc82d793449493adba0dc3d659f23
|
||||
F test/where2.test 478d2170637b9211f593120648858593bf2445a1
|
||||
F test/where3.test 1ad55ba900bd7747f98b6082e65bd3e442c5004e
|
||||
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
@@ -1373,7 +1378,7 @@ F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
|
||||
F tool/GetTclKit.bat 629d87562e0487c386db630033931d12d62e6372
|
||||
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
|
||||
F tool/addopcodes.tcl 2b089684eb8b7d0db64cf9d8e6d2fe1b6d279e8d
|
||||
F tool/build-all-msvc.bat 55be1cf8545dabd69df2ba6b3de6868da0c26f52 x
|
||||
F tool/build-all-msvc.bat 3e4e4043b53f1aede4308e0d2567bbd773614630 x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/cg_anno.tcl 692ce4b8693d59e3a3de77ca97f4139ecfa641b0 x
|
||||
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
|
||||
@@ -1384,8 +1389,8 @@ F tool/fuzzershell.c 94019b185caceffc9f7c7b678a6489e42bc2aefa
|
||||
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/lemon.c 251f5c3f21b553240cbdd42dd187a51bb2372cd3
|
||||
F tool/lempar.c d5114c7d13aa3af1e27ff3d02e4dea6eadec7ddf
|
||||
F tool/lemon.c cfbfe061a4b2766512f6b484882eee2c86a14506
|
||||
F tool/lempar.c 404ea3dc27dbeed343f0e61b1d36e97b9f5f0fb6
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
|
||||
F tool/mkautoconfamal.sh e855df211ecbcc7131dee817110ff386cfb112f7
|
||||
@@ -1421,7 +1426,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
|
||||
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
||||
F tool/sqldiff.c 5a26205111e6fa856d9b1535b1637744dcdb930b
|
||||
F tool/sqldiff.c ca315aca4e2d24233e8f2000edea5880c53d1875
|
||||
F tool/srcck1.c 4f65e1a6748e42f24c0ea629dddc934d821c729a
|
||||
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
|
||||
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
|
||||
@@ -1454,7 +1459,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 5791407b523abd24e832fc2361b3e9f01ee2f36a
|
||||
R bba2e4d185d472ce58e719fcfcf03f67
|
||||
P 84d2a09eab28b65ab7015e89c2057851c7894842
|
||||
R 53ca277f27cb21538c9d98930a79d380
|
||||
T +bgcolor * #d0c0ff
|
||||
T +sym-release *
|
||||
T +sym-version-3.12.1 *
|
||||
U drh
|
||||
Z 6f7df0629a8472a1465e8e2960a9953c
|
||||
Z d74ba186b3dc4e9d8ac039d3fb832fcf
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
592d2104361500e5002783ba329a2609389c57b9
|
||||
fe7d3b75fe1bde41511b323925af8ae1b910bc4d
|
||||
+12
-7
@@ -2360,12 +2360,12 @@ int sqlite3BtreeOpen(
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
|
||||
while( pSib->pPrev ){ pSib = pSib->pPrev; }
|
||||
if( p->pBt<pSib->pBt ){
|
||||
if( (uptr)p->pBt<(uptr)pSib->pBt ){
|
||||
p->pNext = pSib;
|
||||
p->pPrev = 0;
|
||||
pSib->pPrev = p;
|
||||
}else{
|
||||
while( pSib->pNext && pSib->pNext->pBt<p->pBt ){
|
||||
while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){
|
||||
pSib = pSib->pNext;
|
||||
}
|
||||
p->pNext = pSib->pNext;
|
||||
@@ -4472,8 +4472,13 @@ static int accessPayload(
|
||||
#endif
|
||||
assert( offset+amt <= pCur->info.nPayload );
|
||||
|
||||
if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){
|
||||
/* Trying to read or write past the end of the data is an error */
|
||||
assert( aPayload > pPage->aData );
|
||||
if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
|
||||
/* Trying to read or write past the end of the data is an error. The
|
||||
** conditional above is really:
|
||||
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
|
||||
** but is recast into its current form to avoid integer overflow problems
|
||||
*/
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
@@ -7572,9 +7577,9 @@ static int balance_nonroot(
|
||||
** any cell). But it is important to pass the correct size to
|
||||
** insertCell(), so reparse the cell now.
|
||||
**
|
||||
** Note that this can never happen in an SQLite data file, as all
|
||||
** cells are at least 4 bytes. It only happens in b-trees used
|
||||
** to evaluate "IN (SELECT ...)" and similar clauses.
|
||||
** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
|
||||
** and WITHOUT ROWID tables with exactly one column which is the
|
||||
** primary key.
|
||||
*/
|
||||
if( b.szCell[j]==4 ){
|
||||
assert(leafCorrection==4);
|
||||
|
||||
+54
-42
@@ -1056,9 +1056,6 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
memcpy(z, pName->z, pName->n);
|
||||
z[pName->n] = 0;
|
||||
sqlite3Dequote(z);
|
||||
zType = z + sqlite3Strlen30(z) + 1;
|
||||
memcpy(zType, pType->z, pType->n);
|
||||
zType[pType->n] = 0;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
|
||||
@@ -1086,7 +1083,11 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
pCol->affinity = SQLITE_AFF_BLOB;
|
||||
pCol->szEst = 1;
|
||||
}else{
|
||||
zType = z + sqlite3Strlen30(z) + 1;
|
||||
memcpy(zType, pType->z, pType->n);
|
||||
zType[pType->n] = 0;
|
||||
pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
|
||||
pCol->colFlags |= COLFLAG_HASTYPE;
|
||||
}
|
||||
p->nCol++;
|
||||
pParse->constraintName.n = 0;
|
||||
@@ -1135,7 +1136,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
|
||||
char aff = SQLITE_AFF_NUMERIC;
|
||||
const char *zChar = 0;
|
||||
|
||||
if( zIn==0 ) return aff;
|
||||
assert( zIn!=0 );
|
||||
while( zIn[0] ){
|
||||
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
|
||||
zIn++;
|
||||
@@ -1282,7 +1283,7 @@ void sqlite3AddPrimaryKey(
|
||||
int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
|
||||
){
|
||||
Table *pTab = pParse->pNewTable;
|
||||
const char *zName = 0;
|
||||
Column *pCol = 0;
|
||||
int iCol = -1, i;
|
||||
int nTerm;
|
||||
if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
|
||||
@@ -1294,8 +1295,8 @@ void sqlite3AddPrimaryKey(
|
||||
pTab->tabFlags |= TF_HasPrimaryKey;
|
||||
if( pList==0 ){
|
||||
iCol = pTab->nCol - 1;
|
||||
pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
|
||||
zName = pTab->aCol[iCol].zName;
|
||||
pCol = &pTab->aCol[iCol];
|
||||
pCol->colFlags |= COLFLAG_PRIMKEY;
|
||||
nTerm = 1;
|
||||
}else{
|
||||
nTerm = pList->nExpr;
|
||||
@@ -1307,8 +1308,8 @@ void sqlite3AddPrimaryKey(
|
||||
const char *zCName = pCExpr->u.zToken;
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
|
||||
pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
|
||||
zName = pTab->aCol[iCol].zName;
|
||||
pCol = &pTab->aCol[iCol];
|
||||
pCol->colFlags |= COLFLAG_PRIMKEY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1316,8 +1317,8 @@ void sqlite3AddPrimaryKey(
|
||||
}
|
||||
}
|
||||
if( nTerm==1
|
||||
&& zName
|
||||
&& sqlite3StrICmp(sqlite3StrNext(zName), "INTEGER")==0
|
||||
&& pCol
|
||||
&& sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
|
||||
&& sortOrder!=SQLITE_SO_DESC
|
||||
){
|
||||
pTab->iPKey = iCol;
|
||||
@@ -2175,44 +2176,55 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
** statement that defines the view.
|
||||
*/
|
||||
assert( pTable->pSelect );
|
||||
if( pTable->pCheck ){
|
||||
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
|
||||
if( pSel ){
|
||||
n = pParse->nTab;
|
||||
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
||||
pTable->nCol = -1;
|
||||
db->lookaside.bDisable++;
|
||||
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
|
||||
&pTable->nCol, &pTable->aCol);
|
||||
db->lookaside.bDisable--;
|
||||
}else{
|
||||
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
|
||||
if( pSel ){
|
||||
n = pParse->nTab;
|
||||
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
||||
pTable->nCol = -1;
|
||||
db->lookaside.bDisable++;
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
xAuth = db->xAuth;
|
||||
db->xAuth = 0;
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
db->xAuth = xAuth;
|
||||
xAuth = db->xAuth;
|
||||
db->xAuth = 0;
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
db->xAuth = xAuth;
|
||||
#else
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
#endif
|
||||
db->lookaside.bDisable--;
|
||||
pParse->nTab = n;
|
||||
if( pSelTab ){
|
||||
assert( pTable->aCol==0 );
|
||||
pTable->nCol = pSelTab->nCol;
|
||||
pTable->aCol = pSelTab->aCol;
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
sqlite3DeleteTable(db, pSelTab);
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
||||
}else{
|
||||
pTable->nCol = 0;
|
||||
nErr++;
|
||||
pParse->nTab = n;
|
||||
if( pTable->pCheck ){
|
||||
/* CREATE VIEW name(arglist) AS ...
|
||||
** The names of the columns in the table are taken from
|
||||
** arglist which is stored in pTable->pCheck. The pCheck field
|
||||
** normally holds CHECK constraints on an ordinary table, but for
|
||||
** a VIEW it holds the list of column names.
|
||||
*/
|
||||
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
|
||||
&pTable->nCol, &pTable->aCol);
|
||||
if( db->mallocFailed==0
|
||||
&& pParse->nErr==0
|
||||
&& pTable->nCol==pSel->pEList->nExpr
|
||||
){
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
|
||||
}
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
} else {
|
||||
}else if( pSelTab ){
|
||||
/* CREATE VIEW name AS... without an argument list. Construct
|
||||
** the column names from the SELECT statement that defines the view.
|
||||
*/
|
||||
assert( pTable->aCol==0 );
|
||||
pTable->nCol = pSelTab->nCol;
|
||||
pTable->aCol = pSelTab->aCol;
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
||||
}else{
|
||||
pTable->nCol = 0;
|
||||
nErr++;
|
||||
}
|
||||
if( pSelTab ) sqlite3DeleteTable(db, pSelTab);
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
db->lookaside.bDisable--;
|
||||
} else {
|
||||
nErr++;
|
||||
}
|
||||
pTable->pSchema->schemaFlags |= DB_UnresetViews;
|
||||
#endif /* SQLITE_OMIT_VIEW */
|
||||
|
||||
+68
-53
@@ -1283,7 +1283,8 @@ u32 sqlite3ExprListFlags(const ExprList *pList){
|
||||
if( pList ){
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pExpr = pList->a[i].pExpr;
|
||||
if( ALWAYS(pExpr) ) m |= pExpr->flags;
|
||||
assert( pExpr!=0 );
|
||||
m |= pExpr->flags;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
@@ -1568,23 +1569,22 @@ int sqlite3IsRowid(const char *z){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if we are able to the IN operator optimization on a
|
||||
** query of the form
|
||||
**
|
||||
** x IN (SELECT ...)
|
||||
**
|
||||
** Where the SELECT... clause is as specified by the parameter to this
|
||||
** routine.
|
||||
**
|
||||
** The Select object passed in has already been preprocessed and no
|
||||
** errors have been found.
|
||||
** pX is the RHS of an IN operator. If pX is a SELECT statement
|
||||
** that can be simplified to a direct table access, then return
|
||||
** a pointer to the SELECT statement. If pX is not a SELECT statement,
|
||||
** or if the SELECT statement needs to be manifested into a transient
|
||||
** table, then return NULL.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
static int isCandidateForInOpt(Select *p){
|
||||
static Select *isCandidateForInOpt(Expr *pX){
|
||||
Select *p;
|
||||
SrcList *pSrc;
|
||||
ExprList *pEList;
|
||||
Expr *pRes;
|
||||
Table *pTab;
|
||||
if( p==0 ) return 0; /* right-hand side of IN is SELECT */
|
||||
if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
|
||||
if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
|
||||
p = pX->x.pSelect;
|
||||
if( p->pPrior ) return 0; /* Not a compound SELECT */
|
||||
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
|
||||
testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
|
||||
@@ -1600,13 +1600,15 @@ static int isCandidateForInOpt(Select *p){
|
||||
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
|
||||
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
|
||||
pTab = pSrc->a[0].pTab;
|
||||
if( NEVER(pTab==0) ) return 0;
|
||||
assert( pTab!=0 );
|
||||
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
|
||||
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
|
||||
pEList = p->pEList;
|
||||
if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
|
||||
if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */
|
||||
return 1;
|
||||
pRes = pEList->a[0].pExpr;
|
||||
if( pRes->op!=TK_COLUMN ) return 0; /* Result is a column */
|
||||
assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
|
||||
return p;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
@@ -1738,15 +1740,13 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||
** satisfy the query. This is preferable to generating a new
|
||||
** ephemeral table.
|
||||
*/
|
||||
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||
if( pParse->nErr==0 && isCandidateForInOpt(p) ){
|
||||
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
i16 iCol; /* Index of column <column> */
|
||||
i16 iDb; /* Database idx for pTab */
|
||||
|
||||
assert( p ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
@@ -3549,6 +3549,13 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||
break;
|
||||
}
|
||||
case TK_IS:
|
||||
case TK_ISNOT:
|
||||
testcase( op==TK_IS );
|
||||
testcase( op==TK_ISNOT );
|
||||
op = (op==TK_IS) ? TK_EQ : TK_NE;
|
||||
jumpIfNull = SQLITE_NULLEQ;
|
||||
/* Fall thru */
|
||||
case TK_LT:
|
||||
case TK_LE:
|
||||
case TK_GT:
|
||||
@@ -3564,23 +3571,12 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
||||
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
|
||||
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
|
||||
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
|
||||
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
}
|
||||
case TK_IS:
|
||||
case TK_ISNOT: {
|
||||
testcase( op==TK_IS );
|
||||
testcase( op==TK_ISNOT );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
op = (op==TK_IS) ? TK_EQ : TK_NE;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==TK_EQ);
|
||||
VdbeCoverageIf(v, op==TK_NE);
|
||||
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
|
||||
VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
|
||||
assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
|
||||
VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
@@ -3705,6 +3701,13 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||
break;
|
||||
}
|
||||
case TK_IS:
|
||||
case TK_ISNOT:
|
||||
testcase( pExpr->op==TK_IS );
|
||||
testcase( pExpr->op==TK_ISNOT );
|
||||
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
|
||||
jumpIfNull = SQLITE_NULLEQ;
|
||||
/* Fall thru */
|
||||
case TK_LT:
|
||||
case TK_LE:
|
||||
case TK_GT:
|
||||
@@ -3720,23 +3723,12 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
||||
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
|
||||
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
|
||||
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
|
||||
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
}
|
||||
case TK_IS:
|
||||
case TK_ISNOT: {
|
||||
testcase( pExpr->op==TK_IS );
|
||||
testcase( pExpr->op==TK_ISNOT );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==TK_EQ);
|
||||
VdbeCoverageIf(v, op==TK_NE);
|
||||
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
|
||||
VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
|
||||
assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
|
||||
VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
@@ -4259,3 +4251,26 @@ void sqlite3ClearTempRegCache(Parse *pParse){
|
||||
pParse->nTempReg = 0;
|
||||
pParse->nRangeReg = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Validate that no temporary register falls within the range of
|
||||
** iFirst..iLast, inclusive. This routine is only call from within assert()
|
||||
** statements.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
|
||||
int i;
|
||||
if( pParse->nRangeReg>0
|
||||
&& pParse->iRangeReg+pParse->nRangeReg<iLast
|
||||
&& pParse->iRangeReg>=iFirst
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<pParse->nTempReg; i++){
|
||||
if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
+3
-1
@@ -414,7 +414,9 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
/* Version 3.10.0 and later */
|
||||
sqlite3_status64,
|
||||
sqlite3_strlike,
|
||||
sqlite3_db_cacheflush
|
||||
sqlite3_db_cacheflush,
|
||||
/* Version 3.12.0 and later */
|
||||
sqlite3_system_errno
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+4
-2
@@ -2240,6 +2240,9 @@ int sqlite3_extended_errcode(sqlite3 *db){
|
||||
}
|
||||
return db->errCode;
|
||||
}
|
||||
int sqlite3_system_errno(sqlite3 *db){
|
||||
return db ? db->iSysErrno : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a string that describes the kind of error specified in the
|
||||
@@ -3340,8 +3343,7 @@ int sqlite3_table_column_metadata(
|
||||
** explicitly declared column. Copy meta information from *pCol.
|
||||
*/
|
||||
if( pCol ){
|
||||
zDataType = sqlite3StrNext(pCol->zName);
|
||||
if( zDataType[0]==0 ) zDataType = 0;
|
||||
zDataType = sqlite3ColumnType(pCol,0);
|
||||
zCollSeq = pCol->zColl;
|
||||
notnull = pCol->notNull!=0;
|
||||
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
|
||||
|
||||
+78
-84
@@ -69,7 +69,6 @@ struct MemJournal {
|
||||
int flags; /* xOpen flags */
|
||||
sqlite3_vfs *pVfs; /* The "real" underlying VFS */
|
||||
const char *zJournal; /* Name of the journal file */
|
||||
sqlite3_file *pReal; /* The "real" underlying file descriptor */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -83,40 +82,43 @@ static int memjrnlRead(
|
||||
sqlite_int64 iOfst /* Begin reading at this offset */
|
||||
){
|
||||
MemJournal *p = (MemJournal *)pJfd;
|
||||
if( p->pReal ){
|
||||
return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
|
||||
}else if( (iAmt+iOfst)>p->endpoint.iOffset ){
|
||||
u8 *zOut = zBuf;
|
||||
int nRead = iAmt;
|
||||
int iChunkOffset;
|
||||
FileChunk *pChunk;
|
||||
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
if( (iAmt+iOfst)>p->endpoint.iOffset ){
|
||||
return SQLITE_IOERR_SHORT_READ;
|
||||
}else{
|
||||
u8 *zOut = zBuf;
|
||||
int nRead = iAmt;
|
||||
int iChunkOffset;
|
||||
FileChunk *pChunk;
|
||||
|
||||
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
|
||||
sqlite3_int64 iOff = 0;
|
||||
for(pChunk=p->pFirst;
|
||||
ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
|
||||
pChunk=pChunk->pNext
|
||||
){
|
||||
iOff += p->nChunkSize;
|
||||
}
|
||||
}else{
|
||||
pChunk = p->readpoint.pChunk;
|
||||
}
|
||||
|
||||
iChunkOffset = (int)(iOfst%p->nChunkSize);
|
||||
do {
|
||||
int iSpace = p->nChunkSize - iChunkOffset;
|
||||
int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
|
||||
memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
|
||||
zOut += nCopy;
|
||||
nRead -= iSpace;
|
||||
iChunkOffset = 0;
|
||||
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
|
||||
p->readpoint.iOffset = iOfst+iAmt;
|
||||
p->readpoint.pChunk = pChunk;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert( (iAmt+iOfst)<=p->endpoint.iOffset );
|
||||
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
|
||||
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
|
||||
sqlite3_int64 iOff = 0;
|
||||
for(pChunk=p->pFirst;
|
||||
ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
|
||||
pChunk=pChunk->pNext
|
||||
){
|
||||
iOff += p->nChunkSize;
|
||||
}
|
||||
}else{
|
||||
pChunk = p->readpoint.pChunk;
|
||||
assert( pChunk!=0 );
|
||||
}
|
||||
|
||||
iChunkOffset = (int)(iOfst%p->nChunkSize);
|
||||
do {
|
||||
int iSpace = p->nChunkSize - iChunkOffset;
|
||||
int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
|
||||
memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
|
||||
zOut += nCopy;
|
||||
nRead -= iSpace;
|
||||
iChunkOffset = 0;
|
||||
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
|
||||
p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
|
||||
p->readpoint.pChunk = pChunk;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -138,36 +140,36 @@ static void memjrnlFreeChunks(MemJournal *p){
|
||||
** Flush the contents of memory to a real file on disk.
|
||||
*/
|
||||
static int memjrnlCreateFile(MemJournal *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( !p->pReal ){
|
||||
sqlite3_file *pReal = (sqlite3_file *)&p[1];
|
||||
rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int nChunk = p->nChunkSize;
|
||||
i64 iOff = 0;
|
||||
FileChunk *pIter;
|
||||
p->pReal = pReal;
|
||||
for(pIter=p->pFirst; pIter && rc==SQLITE_OK; pIter=pIter->pNext){
|
||||
int nWrite = nChunk;
|
||||
if( pIter==p->endpoint.pChunk ){
|
||||
nWrite = p->endpoint.iOffset % p->nChunkSize;
|
||||
if( nWrite==0 ) nWrite = p->nChunkSize;
|
||||
}
|
||||
rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nWrite, iOff);
|
||||
iOff += nWrite;
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
/* If an error occurred while writing to the file, close it before
|
||||
** returning. This way, SQLite uses the in-memory journal data to
|
||||
** roll back changes made to the internal page-cache before this
|
||||
** function was called. */
|
||||
sqlite3OsClose(pReal);
|
||||
p->pReal = 0;
|
||||
}else{
|
||||
/* No error has occurred. Free the in-memory buffers. */
|
||||
memjrnlFreeChunks(p);
|
||||
int rc;
|
||||
sqlite3_file *pReal = (sqlite3_file*)p;
|
||||
MemJournal copy = *p;
|
||||
|
||||
memset(p, 0, sizeof(MemJournal));
|
||||
rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int nChunk = copy.nChunkSize;
|
||||
i64 iOff = 0;
|
||||
FileChunk *pIter;
|
||||
for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
|
||||
if( iOff + nChunk > copy.endpoint.iOffset ){
|
||||
nChunk = copy.endpoint.iOffset - iOff;
|
||||
}
|
||||
rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
|
||||
if( rc ) break;
|
||||
iOff += nChunk;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
/* No error has occurred. Free the in-memory buffers. */
|
||||
memjrnlFreeChunks(©);
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
/* If an error occurred while creating or writing to the file, restore
|
||||
** the original before returning. This way, SQLite uses the in-memory
|
||||
** journal data to roll back changes made to the internal page-cache
|
||||
** before this function was called. */
|
||||
sqlite3OsClose(pReal);
|
||||
*p = copy;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -186,16 +188,12 @@ static int memjrnlWrite(
|
||||
int nWrite = iAmt;
|
||||
u8 *zWrite = (u8 *)zBuf;
|
||||
|
||||
/* If the file has already been created on disk. */
|
||||
if( p->pReal ){
|
||||
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
|
||||
}
|
||||
|
||||
/* If the file should be created now. */
|
||||
else if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
|
||||
/* If the file should be created now, create it and write the new data
|
||||
** into the file on disk. */
|
||||
if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
|
||||
int rc = memjrnlCreateFile(p);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = memjrnlWrite(pJfd, zBuf, iAmt, iOfst);
|
||||
rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -208,10 +206,15 @@ static int memjrnlWrite(
|
||||
** atomic-write optimization. In this case the first 28 bytes of the
|
||||
** journal file may be written as part of committing the transaction. */
|
||||
assert( iOfst==p->endpoint.iOffset || iOfst==0 );
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
if( iOfst==0 && p->pFirst ){
|
||||
assert( p->nChunkSize>iAmt );
|
||||
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
|
||||
}else{
|
||||
}else
|
||||
#else
|
||||
assert( iOfst>0 || p->pFirst==0 );
|
||||
#endif
|
||||
{
|
||||
while( nWrite>0 ){
|
||||
FileChunk *pChunk = p->endpoint.pChunk;
|
||||
int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
|
||||
@@ -255,9 +258,7 @@ static int memjrnlWrite(
|
||||
*/
|
||||
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
|
||||
MemJournal *p = (MemJournal *)pJfd;
|
||||
if( p->pReal ){
|
||||
return sqlite3OsTruncate(p->pReal, size);
|
||||
}else if( size==0 ){
|
||||
if( ALWAYS(size==0) ){
|
||||
memjrnlFreeChunks(p);
|
||||
p->nSize = 0;
|
||||
p->endpoint.pChunk = 0;
|
||||
@@ -274,7 +275,6 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
|
||||
static int memjrnlClose(sqlite3_file *pJfd){
|
||||
MemJournal *p = (MemJournal *)pJfd;
|
||||
memjrnlFreeChunks(p);
|
||||
if( p->pReal ) sqlite3OsClose(p->pReal);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -285,10 +285,7 @@ static int memjrnlClose(sqlite3_file *pJfd){
|
||||
** syncing an in-memory journal is a no-op.
|
||||
*/
|
||||
static int memjrnlSync(sqlite3_file *pJfd, int flags){
|
||||
MemJournal *p = (MemJournal *)pJfd;
|
||||
if( p->pReal ){
|
||||
return sqlite3OsSync(p->pReal, flags);
|
||||
}
|
||||
UNUSED_PARAMETER2(pJfd, flags);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -297,9 +294,6 @@ static int memjrnlSync(sqlite3_file *pJfd, int flags){
|
||||
*/
|
||||
static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
|
||||
MemJournal *p = (MemJournal *)pJfd;
|
||||
if( p->pReal ){
|
||||
return sqlite3OsFileSize(p->pReal, pSize);
|
||||
}
|
||||
*pSize = (sqlite_int64) p->endpoint.iOffset;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -354,7 +348,7 @@ int sqlite3JournalOpen(
|
||||
** it using the sqlite3OsOpen() function of the underlying VFS. In this
|
||||
** case none of the code in this module is executed as a result of calls
|
||||
** made on the journal file-handle. */
|
||||
memset(p, 0, sizeof(MemJournal) + (pVfs ? pVfs->szOsFile : 0));
|
||||
memset(p, 0, sizeof(MemJournal));
|
||||
if( nSpill==0 ){
|
||||
return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
|
||||
}
|
||||
@@ -403,7 +397,7 @@ int sqlite3JournalCreate(sqlite3_file *p){
|
||||
** or false otherwise.
|
||||
*/
|
||||
int sqlite3JournalIsInMemory(sqlite3_file *p){
|
||||
return p->pMethods==&MemJournalMethods && ((MemJournal*)p)->pReal==0;
|
||||
return p->pMethods==&MemJournalMethods;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -411,5 +405,5 @@ int sqlite3JournalIsInMemory(sqlite3_file *p){
|
||||
** pVfs to create the underlying on-disk files.
|
||||
*/
|
||||
int sqlite3JournalSize(sqlite3_vfs *pVfs){
|
||||
return pVfs->szOsFile + sizeof(MemJournal);
|
||||
return MAX(pVfs->szOsFile, (int)sizeof(MemJournal));
|
||||
}
|
||||
|
||||
@@ -262,6 +262,9 @@ int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
return pVfs->xSleep(pVfs, nMicro);
|
||||
}
|
||||
int sqlite3OsGetLastError(sqlite3_vfs *pVfs){
|
||||
return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0;
|
||||
}
|
||||
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
|
||||
int rc;
|
||||
/* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
|
||||
|
||||
@@ -197,6 +197,7 @@ void sqlite3OsDlClose(sqlite3_vfs *, void *);
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
|
||||
int sqlite3OsSleep(sqlite3_vfs *, int);
|
||||
int sqlite3OsGetLastError(sqlite3_vfs*);
|
||||
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
|
||||
|
||||
/*
|
||||
|
||||
+11
-14
@@ -1357,12 +1357,16 @@ static int fileHasMoved(unixFile *pFile){
|
||||
static void verifyDbFile(unixFile *pFile){
|
||||
struct stat buf;
|
||||
int rc;
|
||||
|
||||
/* These verifications occurs for the main database only */
|
||||
if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return;
|
||||
|
||||
rc = osFstat(pFile->h, &buf);
|
||||
if( rc!=0 ){
|
||||
sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
|
||||
return;
|
||||
}
|
||||
if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
|
||||
if( buf.st_nlink==0 ){
|
||||
sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
|
||||
return;
|
||||
}
|
||||
@@ -5803,9 +5807,6 @@ static int unixOpen(
|
||||
p->openFlags = openFlags;
|
||||
}
|
||||
#endif
|
||||
|
||||
noLock = eType!=SQLITE_OPEN_MAIN_DB;
|
||||
|
||||
|
||||
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
|
||||
if( fstatfs(fd, &fsInfo) == -1 ){
|
||||
@@ -5824,6 +5825,7 @@ static int unixOpen(
|
||||
/* Set up appropriate ctrlFlags */
|
||||
if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
|
||||
if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
|
||||
noLock = eType!=SQLITE_OPEN_MAIN_DB;
|
||||
if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
|
||||
if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
|
||||
if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
|
||||
@@ -6262,23 +6264,18 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
|
||||
# define unixCurrentTime 0
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
/*
|
||||
** We added the xGetLastError() method with the intention of providing
|
||||
** better low-level error messages when operating-system problems come up
|
||||
** during SQLite operation. But so far, none of that has been implemented
|
||||
** in the core. So this routine is never called. For now, it is merely
|
||||
** a place-holder.
|
||||
** The xGetLastError() method is designed to return a better
|
||||
** low-level error message when operating-system problems come up
|
||||
** during SQLite operation. Only the integer return code is currently
|
||||
** used.
|
||||
*/
|
||||
static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
UNUSED_PARAMETER(NotUsed2);
|
||||
UNUSED_PARAMETER(NotUsed3);
|
||||
return 0;
|
||||
return errno;
|
||||
}
|
||||
#else
|
||||
# define unixGetLastError 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+19
-5
@@ -344,11 +344,23 @@ struct winFile {
|
||||
# define SQLITE_WIN32_HEAP_CREATE (TRUE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is cache size used in the calculation of the initial size of the
|
||||
* Win32-specific heap. It cannot be negative.
|
||||
*/
|
||||
#ifndef SQLITE_WIN32_CACHE_SIZE
|
||||
# if SQLITE_DEFAULT_CACHE_SIZE>=0
|
||||
# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE)
|
||||
# else
|
||||
# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The initial size of the Win32-specific heap. This value may be zero.
|
||||
*/
|
||||
#ifndef SQLITE_WIN32_HEAP_INIT_SIZE
|
||||
# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
|
||||
# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \
|
||||
(SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
|
||||
#endif
|
||||
|
||||
@@ -3257,7 +3269,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_LAST_ERRNO: {
|
||||
case SQLITE_FCNTL_LAST_ERRNO: {
|
||||
*(int*)pArg = (int)pFile->lastErrno;
|
||||
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
|
||||
return SQLITE_OK;
|
||||
@@ -5424,8 +5436,8 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
EntropyGatherer e;
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
memset(zBuf, 0, nBuf);
|
||||
#if defined(_MSC_VER) && _MSC_VER>=1400
|
||||
rand_s((int*)zBuf); /* rand_s() is not available with MinGW */
|
||||
#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE
|
||||
rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */
|
||||
#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */
|
||||
e.a = (unsigned char*)zBuf;
|
||||
e.na = nBuf;
|
||||
@@ -5584,8 +5596,10 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
|
||||
** sqlite3_errmsg(), possibly making IO errors easier to debug.
|
||||
*/
|
||||
static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
DWORD e = osGetLastError();
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf);
|
||||
if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf);
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-17
@@ -428,19 +428,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
||||
*/
|
||||
#define MAX_SECTOR_SIZE 0x10000
|
||||
|
||||
/*
|
||||
** If the option SQLITE_EXTRA_DURABLE option is set at compile-time, then
|
||||
** SQLite will do extra fsync() operations when synchronous==FULL to help
|
||||
** ensure that transactions are durable across a power failure. Most
|
||||
** applications are happy as long as transactions are consistent across
|
||||
** a power failure, and are perfectly willing to lose the last transaction
|
||||
** in exchange for the extra performance of avoiding directory syncs.
|
||||
** And so the default SQLITE_EXTRA_DURABLE setting is off.
|
||||
*/
|
||||
#ifndef SQLITE_EXTRA_DURABLE
|
||||
# define SQLITE_EXTRA_DURABLE 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** An instance of the following structure is allocated for each active
|
||||
@@ -4823,11 +4810,7 @@ act_like_temp_file:
|
||||
assert( pPager->ckptSyncFlags==0 );
|
||||
}else{
|
||||
pPager->fullSync = 1;
|
||||
#if SQLITE_EXTRA_DURABLE
|
||||
pPager->extraSync = 1;
|
||||
#else
|
||||
pPager->extraSync = 0;
|
||||
#endif
|
||||
pPager->syncFlags = SQLITE_SYNC_NORMAL;
|
||||
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
|
||||
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
|
||||
@@ -7184,6 +7167,7 @@ int sqlite3PagerWalCallback(Pager *pPager){
|
||||
*/
|
||||
int sqlite3PagerWalSupported(Pager *pPager){
|
||||
const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
|
||||
if( pPager->noLock ) return 0;
|
||||
return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -348,7 +348,6 @@ static void *pcache1Alloc(int nByte){
|
||||
** Free an allocated buffer obtained from pcache1Alloc().
|
||||
*/
|
||||
static void pcache1Free(void *p){
|
||||
int nFreed = 0;
|
||||
if( p==0 ) return;
|
||||
if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){
|
||||
PgFreeslot *pSlot;
|
||||
@@ -365,10 +364,13 @@ static void pcache1Free(void *p){
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
|
||||
nFreed = sqlite3MallocSize(p);
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
{
|
||||
int nFreed = 0;
|
||||
nFreed = sqlite3MallocSize(p);
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
}
|
||||
#endif
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
+28
-18
@@ -1066,7 +1066,6 @@ void sqlite3Pragma(
|
||||
setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
|
||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
const char *zName;
|
||||
if( IsHiddenColumn(pCol) ){
|
||||
nHidden++;
|
||||
continue;
|
||||
@@ -1079,11 +1078,10 @@ void sqlite3Pragma(
|
||||
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
|
||||
}
|
||||
assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
|
||||
zName = pCol->zName;
|
||||
sqlite3VdbeMultiLoad(v, 1, "issisi",
|
||||
i-nHidden,
|
||||
zName,
|
||||
sqlite3StrNext(zName),
|
||||
pCol->zName,
|
||||
sqlite3ColumnType(pCol,""),
|
||||
pCol->notNull ? 1 : 0,
|
||||
pCol->pDflt ? pCol->pDflt->u.zToken : 0,
|
||||
k);
|
||||
@@ -1439,7 +1437,10 @@ void sqlite3Pragma(
|
||||
for(i=0; i<db->nDb; i++){
|
||||
HashElem *x;
|
||||
Hash *pTbls;
|
||||
int *aRoot;
|
||||
int cnt = 0;
|
||||
int mxIdx = 0;
|
||||
int nIdx;
|
||||
|
||||
if( OMIT_TEMPDB && i==1 ) continue;
|
||||
if( iDb>=0 && i!=iDb ) continue;
|
||||
@@ -1452,31 +1453,35 @@ void sqlite3Pragma(
|
||||
|
||||
/* Do an integrity check of the B-Tree
|
||||
**
|
||||
** Begin by filling registers 2, 3, ... with the root pages numbers
|
||||
** Begin by finding the root pages numbers
|
||||
** for all tables and indices in the database.
|
||||
*/
|
||||
assert( sqlite3SchemaMutexHeld(db, i, 0) );
|
||||
pTbls = &db->aDb[i].pSchema->tblHash;
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
|
||||
VdbeComment((v, "%s", pTab->zName));
|
||||
cnt++;
|
||||
}
|
||||
if( HasRowid(pTab) ) cnt++;
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
|
||||
if( nIdx>mxIdx ) mxIdx = nIdx;
|
||||
}
|
||||
aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
|
||||
if( aRoot==0 ) break;
|
||||
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
cnt++;
|
||||
aRoot[cnt++] = pIdx->tnum;
|
||||
}
|
||||
}
|
||||
aRoot[cnt] = 0;
|
||||
|
||||
/* Make sure sufficient number of registers have been allocated */
|
||||
pParse->nMem = MAX( pParse->nMem, cnt+8 );
|
||||
pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
|
||||
|
||||
/* Do the b-tree integrity checks */
|
||||
sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
|
||||
sqlite3VdbeChangeP5(v, (u8)i);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||
@@ -1510,7 +1515,8 @@ void sqlite3Pragma(
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
|
||||
}
|
||||
pParse->nMem = MAX(pParse->nMem, 8+j);
|
||||
assert( pParse->nMem>=8+j );
|
||||
assert( sqlite3NoTempsInRange(pParse,1,7+j) );
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
|
||||
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
|
||||
/* Verify that all NOT NULL columns really are NOT NULL */
|
||||
@@ -1702,7 +1708,9 @@ void sqlite3Pragma(
|
||||
** PRAGMA [schema.]user_version
|
||||
** PRAGMA [schema.]user_version = <integer>
|
||||
**
|
||||
** PRAGMA [schema.]freelist_count = <integer>
|
||||
** PRAGMA [schema.]freelist_count
|
||||
**
|
||||
** PRAGMA [schema.]data_version
|
||||
**
|
||||
** PRAGMA [schema.]application_id
|
||||
** PRAGMA [schema.]application_id = <integer>
|
||||
@@ -1758,6 +1766,7 @@ void sqlite3Pragma(
|
||||
aOp[1].p3 = iCookie;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
|
||||
sqlite3VdbeReusable(v);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1779,6 +1788,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeLoadString(v, 1, zOpt);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}
|
||||
sqlite3VdbeReusable(v);
|
||||
}
|
||||
break;
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
|
||||
+33
-9
@@ -1430,7 +1430,7 @@ static const char *columnTypeImpl(
|
||||
zOrigCol = "rowid";
|
||||
}else{
|
||||
zOrigCol = pTab->aCol[iCol].zName;
|
||||
zType = sqlite3StrNext(zOrigCol);
|
||||
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
|
||||
estWidth = pTab->aCol[iCol].szEst;
|
||||
}
|
||||
zOrigTab = pTab->zName;
|
||||
@@ -1442,7 +1442,7 @@ static const char *columnTypeImpl(
|
||||
if( iCol<0 ){
|
||||
zType = "INTEGER";
|
||||
}else{
|
||||
zType = sqlite3StrNext(pTab->aCol[iCol].zName);
|
||||
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
|
||||
estWidth = pTab->aCol[iCol].szEst;
|
||||
}
|
||||
#endif
|
||||
@@ -1704,7 +1704,7 @@ int sqlite3ColumnsFromExprList(
|
||||
** This routine requires that all identifiers in the SELECT
|
||||
** statement be resolved.
|
||||
*/
|
||||
static void selectAddColumnTypeAndCollation(
|
||||
void sqlite3SelectAddColumnTypeAndCollation(
|
||||
Parse *pParse, /* Parsing contexts */
|
||||
Table *pTab, /* Add column type information to this table */
|
||||
Select *pSelect /* SELECT used to determine types and collations */
|
||||
@@ -1726,10 +1726,20 @@ static void selectAddColumnTypeAndCollation(
|
||||
sNC.pSrcList = pSelect->pSrc;
|
||||
a = pSelect->pEList->a;
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
const char *zType;
|
||||
int n, m;
|
||||
p = a[i].pExpr;
|
||||
columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
|
||||
zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
|
||||
szAll += pCol->szEst;
|
||||
pCol->affinity = sqlite3ExprAffinity(p);
|
||||
if( zType && (m = sqlite3Strlen30(zType))>0 ){
|
||||
n = sqlite3Strlen30(pCol->zName);
|
||||
pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
|
||||
if( pCol->zName ){
|
||||
memcpy(&pCol->zName[n+1], zType, m+1);
|
||||
pCol->colFlags |= COLFLAG_HASTYPE;
|
||||
}
|
||||
}
|
||||
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
|
||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
if( pColl && pCol->zColl==0 ){
|
||||
@@ -1766,7 +1776,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
||||
pTab->zName = 0;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
||||
selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
||||
pTab->iPKey = -1;
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DeleteTable(db, pTab);
|
||||
@@ -4550,7 +4560,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
||||
Select *pSel = pFrom->pSelect;
|
||||
if( pSel ){
|
||||
while( pSel->pPrior ) pSel = pSel->pPrior;
|
||||
selectAddColumnTypeAndCollation(pParse, pTab, pSel);
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4970,10 +4980,24 @@ int sqlite3Select(
|
||||
}
|
||||
|
||||
/* Generate code to implement the subquery
|
||||
**
|
||||
** The subquery is implemented as a co-routine if all of these are true:
|
||||
** (1) The subquery is guaranteed to be the outer loop (so that it
|
||||
** does not need to be computed more than once)
|
||||
** (2) The ALL keyword after SELECT is omitted. (Applications are
|
||||
** allowed to say "SELECT ALL" instead of just "SELECT" to disable
|
||||
** the use of co-routines.)
|
||||
** (3) Co-routines are not disabled using sqlite3_test_control()
|
||||
** with SQLITE_TESTCTRL_OPTIMIZATIONS.
|
||||
**
|
||||
** TODO: Are there other reasons beside (1) to use a co-routine
|
||||
** implementation?
|
||||
*/
|
||||
if( pTabList->nSrc==1
|
||||
&& (p->selFlags & SF_All)==0
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
if( i==0
|
||||
&& (pTabList->nSrc==1
|
||||
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
|
||||
&& (p->selFlags & SF_All)==0 /* (2) */
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
|
||||
){
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
|
||||
@@ -7915,6 +7915,18 @@ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
|
||||
*/
|
||||
int sqlite3_db_cacheflush(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Low-level system error code
|
||||
**
|
||||
** ^Attempt to return the underlying operating system error code or error
|
||||
** number that caused the most reason I/O error or failure to open a file.
|
||||
** The return value is OS-dependent. For example, on unix systems, after
|
||||
** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
|
||||
** called to get back the underlying "errno" that caused the problem, such
|
||||
** as ENOSPC, EAUTH, EISDIR, and so forth.
|
||||
*/
|
||||
int sqlite3_system_errno(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Snapshot
|
||||
** KEYWORDS: {snapshot}
|
||||
|
||||
@@ -279,6 +279,8 @@ struct sqlite3_api_routines {
|
||||
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
int (*strlike)(const char*,const char*,unsigned int);
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
/* Version 3.12.0 and later */
|
||||
int (*system_errno)(sqlite3*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -522,6 +524,8 @@ struct sqlite3_api_routines {
|
||||
#define sqlite3_status64 sqlite3_api->status64
|
||||
#define sqlite3_strlike sqlite3_api->strlike
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
/* Version 3.12.0 and later */
|
||||
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+50
-18
@@ -181,21 +181,6 @@
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(X))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to
|
||||
** something between S (inclusive) and E (exclusive).
|
||||
**
|
||||
** In other words, S is a buffer and E is a pointer to the first byte after
|
||||
** the end of buffer S. This macro returns true if P points to something
|
||||
** contained within the buffer S.
|
||||
*/
|
||||
#if defined(HAVE_STDINT_H)
|
||||
# define SQLITE_WITHIN(P,S,E) \
|
||||
((uintptr_t)(P)>=(uintptr_t)(S) && (uintptr_t)(P)<(uintptr_t)(E))
|
||||
#else
|
||||
# define SQLITE_WITHIN(P,S,E) ((P)>=(S) && (P)<(E))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A macro to hint to the compiler that a function should not be
|
||||
** inlined.
|
||||
@@ -451,6 +436,13 @@
|
||||
# undef SQLITE_NEED_ERR_NAME
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_EXPLAIN
|
||||
# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if the input is an integer that is too large
|
||||
** to fit in 32-bits. This macro is used inside of various testcase()
|
||||
@@ -576,8 +568,12 @@
|
||||
/*
|
||||
** Macros to compute minimum and maximum of two numbers.
|
||||
*/
|
||||
#define MIN(A,B) ((A)<(B)?(A):(B))
|
||||
#define MAX(A,B) ((A)>(B)?(A):(B))
|
||||
#ifndef MIN
|
||||
# define MIN(A,B) ((A)<(B)?(A):(B))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
# define MAX(A,B) ((A)>(B)?(A):(B))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Swap two objects of type TYPE.
|
||||
@@ -706,6 +702,27 @@ typedef INT16_TYPE LogEst;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The uptr type is an unsigned integer large enough to hold a pointer
|
||||
*/
|
||||
#if defined(HAVE_STDINT_H)
|
||||
typedef uintptr_t uptr;
|
||||
#elif SQLITE_PTRSIZE==4
|
||||
typedef u32 uptr;
|
||||
#else
|
||||
typedef u64 uptr;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to
|
||||
** something between S (inclusive) and E (exclusive).
|
||||
**
|
||||
** In other words, S is a buffer and E is a pointer to the first byte after
|
||||
** the end of buffer S. This macro returns true if P points to something
|
||||
** contained within the buffer S.
|
||||
*/
|
||||
#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
|
||||
|
||||
|
||||
/*
|
||||
** Macros to determine whether the machine is big or little endian,
|
||||
** and whether or not that determination is run-time or compile-time.
|
||||
@@ -1005,6 +1022,14 @@ typedef struct With With;
|
||||
#include "os.h"
|
||||
#include "mutex.h"
|
||||
|
||||
/* The SQLITE_EXTRA_DURABLE compile-time option used to set the default
|
||||
** synchronous setting to EXTRA. It is no longer supported.
|
||||
*/
|
||||
#ifdef SQLITE_EXTRA_DURABLE
|
||||
# warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE
|
||||
# define SQLITE_DEFAULT_SYNCHRONOUS 3
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Default synchronous levels.
|
||||
**
|
||||
@@ -1205,6 +1230,7 @@ struct sqlite3 {
|
||||
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
|
||||
int errCode; /* Most recent error code (SQLITE_*) */
|
||||
int errMask; /* & result codes with this before returning */
|
||||
int iSysErrno; /* Errno value from last system error */
|
||||
u16 dbOptFlags; /* Flags to enable/disable optimizations */
|
||||
u8 enc; /* Text encoding */
|
||||
u8 autoCommit; /* The auto-commit flag. */
|
||||
@@ -1578,6 +1604,7 @@ struct Column {
|
||||
*/
|
||||
#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
|
||||
#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
|
||||
#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */
|
||||
|
||||
/*
|
||||
** A "Collating Sequence" is defined by an instance of the following
|
||||
@@ -3281,7 +3308,7 @@ int sqlite3IsIdChar(u8);
|
||||
*/
|
||||
int sqlite3StrICmp(const char*,const char*);
|
||||
int sqlite3Strlen30(const char*);
|
||||
const char *sqlite3StrNext(const char*);
|
||||
char *sqlite3ColumnType(Column*,char*);
|
||||
#define sqlite3StrNICmp sqlite3_strnicmp
|
||||
|
||||
int sqlite3MallocInit(void);
|
||||
@@ -3404,6 +3431,9 @@ void sqlite3ReleaseTempReg(Parse*,int);
|
||||
int sqlite3GetTempRange(Parse*,int);
|
||||
void sqlite3ReleaseTempRange(Parse*,int,int);
|
||||
void sqlite3ClearTempRegCache(Parse*);
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3NoTempsInRange(Parse*,int,int);
|
||||
#endif
|
||||
Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
|
||||
Expr *sqlite3Expr(sqlite3*,int,const char*);
|
||||
void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
|
||||
@@ -3427,6 +3457,7 @@ void sqlite3CollapseDatabaseArray(sqlite3*);
|
||||
void sqlite3CommitInternalChanges(sqlite3*);
|
||||
void sqlite3DeleteColumnNames(sqlite3*,Table*);
|
||||
int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
|
||||
void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,Select*);
|
||||
void sqlite3OpenMasterTable(Parse *, int);
|
||||
Index *sqlite3PrimaryKeyIndex(Table*);
|
||||
@@ -3748,6 +3779,7 @@ int sqlite3Atoi64(const char*, i64*, int, u8);
|
||||
int sqlite3DecOrHexToI64(const char*, i64*);
|
||||
void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
|
||||
void sqlite3Error(sqlite3*,int);
|
||||
void sqlite3SystemError(sqlite3*,int);
|
||||
void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
|
||||
u8 sqlite3HexToInt(int h);
|
||||
int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
|
||||
|
||||
+2
-2
@@ -101,8 +101,8 @@
|
||||
** The suggested maximum number of in-memory pages to use for
|
||||
** the main database table and for temporary tables.
|
||||
**
|
||||
** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
|
||||
** is 2000*1024 bytes.
|
||||
** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000,
|
||||
** which means the cache size is limited to 2048000 bytes of memory.
|
||||
** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
|
||||
** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
|
||||
*/
|
||||
|
||||
+7
-7
@@ -2574,7 +2574,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** Change the encryption key on the currently open database.
|
||||
*/
|
||||
case DB_REKEY: {
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
int nKey;
|
||||
void *pKey;
|
||||
#endif
|
||||
@@ -2582,7 +2582,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "KEY");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
|
||||
rc = sqlite3_rekey(pDb->db, pKey, nKey);
|
||||
if( rc ){
|
||||
@@ -2955,7 +2955,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
const char *zVfs = 0;
|
||||
int flags;
|
||||
Tcl_DString translatedFilename;
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
void *pKey = 0;
|
||||
int nKey = 0;
|
||||
#endif
|
||||
@@ -2984,7 +2984,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
return TCL_OK;
|
||||
}
|
||||
if( strcmp(zArg,"-has-codec")==0 ){
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
Tcl_AppendResult(interp,"1",(char*)0);
|
||||
#else
|
||||
Tcl_AppendResult(interp,"0",(char*)0);
|
||||
@@ -2995,7 +2995,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
for(i=3; i+1<objc; i+=2){
|
||||
zArg = Tcl_GetString(objv[i]);
|
||||
if( strcmp(zArg,"-key")==0 ){
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
|
||||
#endif
|
||||
}else if( strcmp(zArg, "-vfs")==0 ){
|
||||
@@ -3053,7 +3053,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
|
||||
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
" ?-key CODECKEY?"
|
||||
#endif
|
||||
);
|
||||
@@ -3079,7 +3079,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}else{
|
||||
zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc));
|
||||
}
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
if( p->db ){
|
||||
sqlite3_key(p->db, pKey, nKey);
|
||||
}
|
||||
|
||||
+27
-1
@@ -651,7 +651,7 @@ static int test_key(
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
sqlite3 *db;
|
||||
const char *zKey;
|
||||
int nKey;
|
||||
@@ -1931,6 +1931,8 @@ static int test_load_extension(
|
||||
#ifdef SQLITE_OMIT_LOAD_EXTENSION
|
||||
rc = SQLITE_ERROR;
|
||||
zErr = sqlite3_mprintf("this build omits sqlite3_load_extension()");
|
||||
(void)zProc;
|
||||
(void)zFile;
|
||||
#else
|
||||
rc = sqlite3_load_extension(db, zFile, zProc, &zErr);
|
||||
#endif
|
||||
@@ -4847,6 +4849,29 @@ static int test_db_cacheflush(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_system_errno DB
|
||||
**
|
||||
** Return the low-level system errno value.
|
||||
*/
|
||||
static int test_system_errno(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
int iErrno;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
iErrno = sqlite3_system_errno(db);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(iErrno));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_db_filename DB DBNAME
|
||||
**
|
||||
@@ -7084,6 +7109,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_release_memory", test_release_memory, 0},
|
||||
{ "sqlite3_db_release_memory", test_db_release_memory, 0},
|
||||
{ "sqlite3_db_cacheflush", test_db_cacheflush, 0},
|
||||
{ "sqlite3_system_errno", test_system_errno, 0},
|
||||
{ "sqlite3_db_filename", test_db_filename, 0},
|
||||
{ "sqlite3_db_readonly", test_db_readonly, 0},
|
||||
{ "sqlite3_soft_heap_limit", test_soft_heap_limit, 0},
|
||||
|
||||
+18
-1
@@ -79,6 +79,13 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "debug", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEFAULT_CKPTFULLFSYNC
|
||||
Tcl_SetVar2(interp, "sqlite_options", "default_ckptfullfsync",
|
||||
SQLITE_DEFAULT_CKPTFULLFSYNC ? "1" : "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "default_ckptfullfsync", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
Tcl_SetVar2(interp, "sqlite_options", "direct_read", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@@ -97,6 +104,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "lfs", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
|
||||
Tcl_SetVar2(interp, "sqlite_options", "pagecache_overflow_stats","0",TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "pagecache_overflow_stats","1",TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mmap", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@@ -576,7 +589,11 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
Tcl_SetVar2(interp, "sqlite_options", "threadsafe",
|
||||
STRINGVALUE(SQLITE_THREADSAFE), TCL_GLOBAL_ONLY);
|
||||
SQLITE_THREADSAFE ? "1" : "0", TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar2(interp, "sqlite_options", "threadsafe1",
|
||||
SQLITE_THREADSAFE==1 ? "1" : "0", TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar2(interp, "sqlite_options", "threadsafe2",
|
||||
SQLITE_THREADSAFE==2 ? "1" : "0", TCL_GLOBAL_ONLY);
|
||||
assert( sqlite3_threadsafe()==SQLITE_THREADSAFE );
|
||||
|
||||
#ifdef SQLITE_OMIT_TEMPDB
|
||||
|
||||
@@ -717,7 +717,11 @@ static int multiplexCurrentTime(sqlite3_vfs *a, double *b){
|
||||
return gMultiplex.pOrigVfs->xCurrentTime(gMultiplex.pOrigVfs, b);
|
||||
}
|
||||
static int multiplexGetLastError(sqlite3_vfs *a, int b, char *c){
|
||||
return gMultiplex.pOrigVfs->xGetLastError(gMultiplex.pOrigVfs, b, c);
|
||||
if( gMultiplex.pOrigVfs->xGetLastError ){
|
||||
return gMultiplex.pOrigVfs->xGetLastError(gMultiplex.pOrigVfs, b, c);
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static int multiplexCurrentTimeInt64(sqlite3_vfs *a, sqlite3_int64 *b){
|
||||
return gMultiplex.pOrigVfs->xCurrentTimeInt64(gMultiplex.pOrigVfs, b);
|
||||
|
||||
+43
-9
@@ -110,20 +110,48 @@ int sqlite3Strlen30(const char *z){
|
||||
}
|
||||
|
||||
/*
|
||||
** The string z[] is followed immediately by another string. Return
|
||||
** a poiner to that other string.
|
||||
** Return the declared type of a column. Or return zDflt if the column
|
||||
** has no declared type.
|
||||
**
|
||||
** The column type is an extra string stored after the zero-terminator on
|
||||
** the column name if and only if the COLFLAG_HASTYPE flag is set.
|
||||
*/
|
||||
const char *sqlite3StrNext(const char *z){
|
||||
return z + strlen(z) + 1;
|
||||
char *sqlite3ColumnType(Column *pCol, char *zDflt){
|
||||
if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt;
|
||||
return pCol->zName + strlen(pCol->zName) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper function for sqlite3Error() - called rarely. Broken out into
|
||||
** a separate routine to avoid unnecessary register saves on entry to
|
||||
** sqlite3Error().
|
||||
*/
|
||||
static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){
|
||||
if( db->pErr ) sqlite3ValueSetNull(db->pErr);
|
||||
sqlite3SystemError(db, err_code);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the current error code to err_code and clear any prior error message.
|
||||
** Also set iSysErrno (by calling sqlite3System) if the err_code indicates
|
||||
** that would be appropriate.
|
||||
*/
|
||||
void sqlite3Error(sqlite3 *db, int err_code){
|
||||
assert( db!=0 );
|
||||
db->errCode = err_code;
|
||||
if( db->pErr ) sqlite3ValueSetNull(db->pErr);
|
||||
if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
|
||||
}
|
||||
|
||||
/*
|
||||
** Load the sqlite3.iSysErrno field if that is an appropriate thing
|
||||
** to do based on the SQLite error code in rc.
|
||||
*/
|
||||
void sqlite3SystemError(sqlite3 *db, int rc){
|
||||
if( rc==SQLITE_IOERR_NOMEM ) return;
|
||||
rc &= 0xff;
|
||||
if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
|
||||
db->iSysErrno = sqlite3OsGetLastError(db->pVfs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,6 +178,7 @@ void sqlite3Error(sqlite3 *db, int err_code){
|
||||
void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
|
||||
assert( db!=0 );
|
||||
db->errCode = err_code;
|
||||
sqlite3SystemError(db, err_code);
|
||||
if( zFormat==0 ){
|
||||
sqlite3Error(db, err_code);
|
||||
}else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){
|
||||
@@ -1424,9 +1453,14 @@ u64 sqlite3LogEstToInt(LogEst x){
|
||||
x /= 10;
|
||||
if( n>=5 ) n -= 2;
|
||||
else if( n>=1 ) n -= 1;
|
||||
if( x>=3 ){
|
||||
return x>60 ? (u64)LARGEST_INT64 : (n+8)<<(x-3);
|
||||
}
|
||||
return (n+8)>>(3-x);
|
||||
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
|
||||
defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
|
||||
if( x>60 ) return (u64)LARGEST_INT64;
|
||||
#else
|
||||
/* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input
|
||||
** possible to this routine is 310, resulting in a maximum x of 31 */
|
||||
assert( x<=60 );
|
||||
#endif
|
||||
return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x);
|
||||
}
|
||||
#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
|
||||
|
||||
+52
-53
@@ -192,11 +192,11 @@ static VdbeCursor *allocateCursor(
|
||||
** be freed lazily via the sqlite3_release_memory() API. This
|
||||
** minimizes the number of malloc calls made by the system.
|
||||
**
|
||||
** Memory cells for cursors are allocated at the top of the address
|
||||
** space. Memory cell (p->nMem) corresponds to cursor 0. Space for
|
||||
** cursor 1 is managed by memory cell (p->nMem-1), etc.
|
||||
** The memory cell for cursor 0 is aMem[0]. The rest are allocated from
|
||||
** the top of the register space. Cursor 1 is at Mem[p->nMem-1].
|
||||
** Cursor 2 is at Mem[p->nMem-2]. And so forth.
|
||||
*/
|
||||
Mem *pMem = &p->aMem[p->nMem-iCur];
|
||||
Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem;
|
||||
|
||||
int nByte;
|
||||
VdbeCursor *pCx = 0;
|
||||
@@ -204,7 +204,7 @@ static VdbeCursor *allocateCursor(
|
||||
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
|
||||
(eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
|
||||
|
||||
assert( iCur<p->nCursor );
|
||||
assert( iCur>=0 && iCur<p->nCursor );
|
||||
if( p->apCsr[iCur] ){
|
||||
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
|
||||
p->apCsr[iCur] = 0;
|
||||
@@ -529,7 +529,7 @@ static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){
|
||||
static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
|
||||
Mem *pOut;
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
|
||||
pOut = &p->aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
if( VdbeMemDynamic(pOut) ){
|
||||
@@ -667,33 +667,33 @@ int sqlite3VdbeExec(
|
||||
assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
|
||||
if( (pOp->opflags & OPFLG_IN1)!=0 ){
|
||||
assert( pOp->p1>0 );
|
||||
assert( pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p1]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
|
||||
REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_IN2)!=0 ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p2]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
|
||||
REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_IN3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p3]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
|
||||
REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_OUT2)!=0 ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
|
||||
memAboutToChange(p, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_OUT3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
memAboutToChange(p, &aMem[pOp->p3]);
|
||||
}
|
||||
#endif
|
||||
@@ -792,7 +792,7 @@ check_for_interrupt:
|
||||
** and then jump to address P2.
|
||||
*/
|
||||
case OP_Gosub: { /* jump */
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( VdbeMemDynamic(pIn1)==0 );
|
||||
memAboutToChange(p, pIn1);
|
||||
@@ -832,7 +832,7 @@ case OP_Return: { /* in1 */
|
||||
** See also: EndCoroutine
|
||||
*/
|
||||
case OP_InitCoroutine: { /* jump */
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
assert( pOp->p2>=0 && pOp->p2<p->nOp );
|
||||
assert( pOp->p3>=0 && pOp->p3<p->nOp );
|
||||
pOut = &aMem[pOp->p1];
|
||||
@@ -1101,7 +1101,7 @@ case OP_String: { /* out2 */
|
||||
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
if( pOp->p5 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
assert( pIn3->flags & MEM_Int );
|
||||
if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
|
||||
@@ -1127,7 +1127,7 @@ case OP_Null: { /* out2 */
|
||||
u16 nullFlag;
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
cnt = pOp->p3-pOp->p2;
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
|
||||
while( cnt>0 ){
|
||||
pOut++;
|
||||
@@ -1148,7 +1148,7 @@ case OP_Null: { /* out2 */
|
||||
** previously copied using OP_SCopy, the copies will continue to be valid.
|
||||
*/
|
||||
case OP_SoftNull: {
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
pOut = &aMem[pOp->p1];
|
||||
pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
|
||||
break;
|
||||
@@ -1215,8 +1215,8 @@ case OP_Move: {
|
||||
pIn1 = &aMem[p1];
|
||||
pOut = &aMem[p2];
|
||||
do{
|
||||
assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
|
||||
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
|
||||
assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] );
|
||||
assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
memAboutToChange(p, pOut);
|
||||
sqlite3VdbeMemMove(pOut, pIn1);
|
||||
@@ -1316,7 +1316,7 @@ case OP_ResultRow: {
|
||||
int i;
|
||||
assert( p->nResColumn==pOp->p2 );
|
||||
assert( pOp->p1>0 );
|
||||
assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 );
|
||||
assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
|
||||
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
/* Run the progress counter just before returning.
|
||||
@@ -1628,8 +1628,8 @@ case OP_Function0: {
|
||||
|
||||
assert( pOp->p4type==P4_FUNCDEF );
|
||||
n = pOp->p5;
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
|
||||
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
|
||||
pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
|
||||
if( pCtx==0 ) goto no_mem;
|
||||
@@ -2129,11 +2129,11 @@ case OP_Compare: {
|
||||
if( aPermute ){
|
||||
int k, mx = 0;
|
||||
for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
|
||||
assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 );
|
||||
assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 );
|
||||
assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
|
||||
assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
|
||||
}else{
|
||||
assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 );
|
||||
assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 );
|
||||
assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 );
|
||||
assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 );
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
for(i=0; i<n; i++){
|
||||
@@ -2395,7 +2395,7 @@ case OP_Column: {
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
|
||||
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
@@ -2524,7 +2524,6 @@ case OP_Column: {
|
||||
}while( i<=p2 && zHdr<zEndHdr );
|
||||
pC->nHdrParsed = i;
|
||||
pC->iHdrOffset = (u32)(zHdr - zData);
|
||||
if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
|
||||
|
||||
/* The record is corrupt if any of the following are true:
|
||||
** (1) the bytes of the header extend past the declared header size
|
||||
@@ -2534,9 +2533,12 @@ case OP_Column: {
|
||||
if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize))
|
||||
|| (offset64 > pC->payloadSize)
|
||||
){
|
||||
if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
|
||||
|
||||
}else{
|
||||
t = 0;
|
||||
}
|
||||
@@ -2638,7 +2640,7 @@ case OP_Affinity: {
|
||||
assert( zAffinity[pOp->p2]==0 );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
while( (cAff = *(zAffinity++))!=0 ){
|
||||
assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] );
|
||||
assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
applyAffinity(pIn1, cAff, encoding);
|
||||
pIn1++;
|
||||
@@ -2700,7 +2702,7 @@ case OP_MakeRecord: {
|
||||
nZero = 0; /* Number of zero bytes at the end of the record */
|
||||
nField = pOp->p1;
|
||||
zAffinity = pOp->p4.z;
|
||||
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 );
|
||||
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 );
|
||||
pData0 = &aMem[nField];
|
||||
nField = pOp->p2;
|
||||
pLast = &pData0[nField-1];
|
||||
@@ -2790,7 +2792,7 @@ case OP_MakeRecord: {
|
||||
assert( i==nHdr );
|
||||
assert( j==nByte );
|
||||
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pOut->n = (int)nByte;
|
||||
pOut->flags = MEM_Blob;
|
||||
if( nZero ){
|
||||
@@ -3376,7 +3378,7 @@ case OP_OpenWrite:
|
||||
}
|
||||
if( pOp->p5 & OPFLAG_P2ISREG ){
|
||||
assert( p2>0 );
|
||||
assert( p2<=(p->nMem-p->nCursor) );
|
||||
assert( p2<=(p->nMem+1 - p->nCursor) );
|
||||
pIn2 = &aMem[p2];
|
||||
assert( memIsValid(pIn2) );
|
||||
assert( (pIn2->flags & MEM_Int)!=0 );
|
||||
@@ -4171,7 +4173,7 @@ case OP_NewRowid: { /* out2 */
|
||||
pMem = &pFrame->aMem[pOp->p3];
|
||||
}else{
|
||||
/* Assert that P3 is a valid memory cell. */
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pMem = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pMem);
|
||||
}
|
||||
@@ -4947,7 +4949,7 @@ case OP_IdxDelete: {
|
||||
UnpackedRecord r;
|
||||
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 );
|
||||
assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 );
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
@@ -5422,7 +5424,7 @@ case OP_DropTrigger: {
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
/* Opcode: IntegrityCk P1 P2 P3 * P5
|
||||
/* Opcode: IntegrityCk P1 P2 P3 P4 P5
|
||||
**
|
||||
** Do an analysis of the currently open database. Store in
|
||||
** register P1 the text of an error message describing any problems.
|
||||
@@ -5433,9 +5435,8 @@ case OP_DropTrigger: {
|
||||
** In other words, the analysis stops as soon as reg(P1) errors are
|
||||
** seen. Reg(P1) is updated with the number of errors remaining.
|
||||
**
|
||||
** The root page numbers of all tables in the database are integer
|
||||
** stored in reg(P1), reg(P1+1), reg(P1+2), .... There are P2 tables
|
||||
** total.
|
||||
** The root page numbers of all tables in the database are integers
|
||||
** stored in P4_INTARRAY argument.
|
||||
**
|
||||
** If P5 is not zero, the check is done on the auxiliary database
|
||||
** file, not the main database file.
|
||||
@@ -5445,30 +5446,24 @@ case OP_DropTrigger: {
|
||||
case OP_IntegrityCk: {
|
||||
int nRoot; /* Number of tables to check. (Number of root pages.) */
|
||||
int *aRoot; /* Array of rootpage numbers for tables to be checked */
|
||||
int j; /* Loop counter */
|
||||
int nErr; /* Number of errors reported */
|
||||
char *z; /* Text of the error report */
|
||||
Mem *pnErr; /* Register keeping track of errors remaining */
|
||||
|
||||
assert( p->bIsReader );
|
||||
nRoot = pOp->p2;
|
||||
aRoot = pOp->p4.ai;
|
||||
assert( nRoot>0 );
|
||||
aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(nRoot+1) );
|
||||
if( aRoot==0 ) goto no_mem;
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( aRoot[nRoot]==0 );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pnErr = &aMem[pOp->p3];
|
||||
assert( (pnErr->flags & MEM_Int)!=0 );
|
||||
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
for(j=0; j<nRoot; j++){
|
||||
aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
|
||||
}
|
||||
aRoot[j] = 0;
|
||||
assert( pOp->p5<db->nDb );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p5) );
|
||||
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
|
||||
(int)pnErr->u.i, &nErr);
|
||||
sqlite3DbFree(db, aRoot);
|
||||
pnErr->u.i -= nErr;
|
||||
sqlite3VdbeMemSetNull(pIn1);
|
||||
if( nErr==0 ){
|
||||
@@ -5650,6 +5645,8 @@ case OP_Program: { /* jump */
|
||||
** variable nMem (and later, VdbeFrame.nChildMem) to this value.
|
||||
*/
|
||||
nMem = pProgram->nMem + pProgram->nCsr;
|
||||
assert( nMem>0 );
|
||||
if( pProgram->nCsr==0 ) nMem++;
|
||||
nByte = ROUND8(sizeof(VdbeFrame))
|
||||
+ nMem * sizeof(Mem)
|
||||
+ pProgram->nCsr * sizeof(VdbeCursor *)
|
||||
@@ -5686,7 +5683,8 @@ case OP_Program: { /* jump */
|
||||
}
|
||||
}else{
|
||||
pFrame = pRt->u.pFrame;
|
||||
assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
|
||||
assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem
|
||||
|| (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
|
||||
assert( pProgram->nCsr==pFrame->nChildCsr );
|
||||
assert( (int)(pOp - aOp)==pFrame->pc );
|
||||
}
|
||||
@@ -5701,10 +5699,10 @@ case OP_Program: { /* jump */
|
||||
p->pAuxData = 0;
|
||||
p->nChange = 0;
|
||||
p->pFrame = pFrame;
|
||||
p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
|
||||
p->aMem = aMem = VdbeFrameMem(pFrame);
|
||||
p->nMem = pFrame->nChildMem;
|
||||
p->nCursor = (u16)pFrame->nChildCsr;
|
||||
p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
|
||||
p->apCsr = (VdbeCursor **)&aMem[p->nMem];
|
||||
p->aOp = aOp = pProgram->aOp;
|
||||
p->nOp = pProgram->nOp;
|
||||
p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
|
||||
@@ -5950,8 +5948,8 @@ case OP_AggStep0: {
|
||||
|
||||
assert( pOp->p4type==P4_FUNCDEF );
|
||||
n = pOp->p5;
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
|
||||
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
|
||||
pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
|
||||
if( pCtx==0 ) goto no_mem;
|
||||
@@ -6030,7 +6028,7 @@ case OP_AggStep: {
|
||||
*/
|
||||
case OP_AggFinal: {
|
||||
Mem *pMem;
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
pMem = &aMem[pOp->p1];
|
||||
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
|
||||
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
|
||||
@@ -6472,7 +6470,7 @@ case OP_VColumn: {
|
||||
|
||||
VdbeCursor *pCur = p->apCsr[pOp->p1];
|
||||
assert( pCur->eCurType==CURTYPE_VTAB );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
if( pCur->nullRow ){
|
||||
@@ -6830,6 +6828,7 @@ abort_due_to_error:
|
||||
sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
|
||||
}
|
||||
p->rc = rc;
|
||||
sqlite3SystemError(db, rc);
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
|
||||
(int)(pOp - aOp), p->zSql, p->zErrMsg);
|
||||
|
||||
@@ -202,6 +202,7 @@ void sqlite3VdbeUsesBtree(Vdbe*, int);
|
||||
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||
void sqlite3VdbeRunOnlyOnce(Vdbe*);
|
||||
void sqlite3VdbeReusable(Vdbe*);
|
||||
void sqlite3VdbeDelete(Vdbe*);
|
||||
void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
|
||||
|
||||
+2
-2
@@ -381,16 +381,16 @@ struct Vdbe {
|
||||
#endif
|
||||
u16 nResColumn; /* Number of columns in one row of the result set */
|
||||
u8 errorAction; /* Recovery action to do in case of an error */
|
||||
bft expired:1; /* True if the VM needs to be recompiled */
|
||||
bft doingRerun:1; /* True if rerunning after an auto-reprepare */
|
||||
u8 minWriteFileFormat; /* Minimum file format for writable database files */
|
||||
bft explain:2; /* True if EXPLAIN present on SQL command */
|
||||
bft changeCntOn:1; /* True to update the change-counter */
|
||||
bft expired:1; /* True if the VM needs to be recompiled */
|
||||
bft runOnlyOnce:1; /* Automatically expire on reset */
|
||||
bft usesStmtJournal:1; /* True if uses a statement journal */
|
||||
bft readOnly:1; /* True for statements that do not write */
|
||||
bft bIsReader:1; /* True for statements that read */
|
||||
bft isPrepareV2:1; /* True if prepared with prepare_v2() */
|
||||
bft doingRerun:1; /* True if rerunning after an auto-reprepare */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
|
||||
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
|
||||
|
||||
+16
-13
@@ -391,6 +391,13 @@ void sqlite3VdbeRunOnlyOnce(Vdbe *p){
|
||||
p->runOnlyOnce = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark the VDBE as one that can only be run multiple times.
|
||||
*/
|
||||
void sqlite3VdbeReusable(Vdbe *p){
|
||||
p->runOnlyOnce = 0;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
|
||||
|
||||
/*
|
||||
@@ -1794,7 +1801,7 @@ void sqlite3VdbeRewind(Vdbe *p){
|
||||
p->magic = VDBE_MAGIC_RUN;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(i=1; i<p->nMem; i++){
|
||||
for(i=0; i<p->nMem; i++){
|
||||
assert( p->aMem[i].db==p->db );
|
||||
}
|
||||
#endif
|
||||
@@ -1859,16 +1866,13 @@ void sqlite3VdbeMakeReady(
|
||||
nOnce = pParse->nOnce;
|
||||
if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
|
||||
|
||||
/* For each cursor required, also allocate a memory cell. Memory
|
||||
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
|
||||
** the vdbe program. Instead they are used to allocate memory for
|
||||
** VdbeCursor/BtCursor structures. The blob of memory associated with
|
||||
** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
|
||||
** stores the blob of memory associated with cursor 1, etc.
|
||||
**
|
||||
/* Each cursor uses a memory cell. The first cursor (cursor 0) can
|
||||
** use aMem[0] which is not otherwise used by the VDBE program. Allocate
|
||||
** space at the end of aMem[] for cursors 1 and greater.
|
||||
** See also: allocateCursor().
|
||||
*/
|
||||
nMem += nCursor;
|
||||
if( nCursor==0 && nMem>0 ) nMem++; /* Space for aMem[0] even if not used */
|
||||
|
||||
/* Figure out how much reusable memory is available at the end of the
|
||||
** opcode array. This extra memory will be reallocated for other elements
|
||||
@@ -1930,9 +1934,8 @@ void sqlite3VdbeMakeReady(
|
||||
pParse->nzVar = 0;
|
||||
pParse->azVar = 0;
|
||||
if( p->aMem ){
|
||||
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||
for(n=1; n<=nMem; n++){
|
||||
p->nMem = nMem;
|
||||
for(n=0; n<nMem; n++){
|
||||
p->aMem[n].flags = MEM_Undefined;
|
||||
p->aMem[n].db = db;
|
||||
}
|
||||
@@ -2042,7 +2045,7 @@ static void closeAllCursors(Vdbe *p){
|
||||
assert( p->nFrame==0 );
|
||||
closeCursorsInFrame(p);
|
||||
if( p->aMem ){
|
||||
releaseMemArray(&p->aMem[1], p->nMem);
|
||||
releaseMemArray(p->aMem, p->nMem);
|
||||
}
|
||||
while( p->pDelFrame ){
|
||||
VdbeFrame *pDel = p->pDelFrame;
|
||||
@@ -2067,7 +2070,7 @@ static void Cleanup(Vdbe *p){
|
||||
int i;
|
||||
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
|
||||
if( p->aMem ){
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
|
||||
for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -761,7 +761,7 @@ int sqlite3VdbeMemTooBig(Mem *p){
|
||||
void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
||||
int i;
|
||||
Mem *pX;
|
||||
for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
|
||||
for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
|
||||
if( pX->pScopyFrom==pMem ){
|
||||
pX->flags |= MEM_Undefined;
|
||||
pX->pScopyFrom = 0;
|
||||
|
||||
+7
-13
@@ -564,22 +564,16 @@ static int vtabCallConstructor(
|
||||
pTab->pVTable = pVTable;
|
||||
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
char *zType = (char*)sqlite3StrNext(pTab->aCol[iCol].zName);
|
||||
char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
|
||||
int nType;
|
||||
int i = 0;
|
||||
if( !zType[0] ){
|
||||
pTab->tabFlags |= oooHidden;
|
||||
continue;
|
||||
}
|
||||
nType = sqlite3Strlen30(zType);
|
||||
if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
|
||||
for(i=0; i<nType; i++){
|
||||
if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
|
||||
&& (zType[i+7]=='\0' || zType[i+7]==' ')
|
||||
){
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
for(i=0; i<nType; i++){
|
||||
if( 0==sqlite3StrNICmp("hidden", &zType[i], 6)
|
||||
&& (i==0 || zType[i-1]==' ')
|
||||
&& (zType[i+6]=='\0' || zType[i+6]==' ')
|
||||
){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i<nType ){
|
||||
|
||||
+35
-16
@@ -289,6 +289,7 @@ static WhereTerm *whereScanInit(
|
||||
j = iColumn;
|
||||
iColumn = pIdx->aiColumn[j];
|
||||
if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
|
||||
if( iColumn==pIdx->pTable->iPKey ) iColumn = XN_ROWID;
|
||||
}
|
||||
if( pIdx && iColumn>=0 ){
|
||||
pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
||||
@@ -1979,6 +1980,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
WhereLoop **ppPrev, *p;
|
||||
WhereInfo *pWInfo = pBuilder->pWInfo;
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
int rc;
|
||||
|
||||
/* If pBuilder->pOrSet is defined, then only keep track of the costs
|
||||
** and prereqs.
|
||||
@@ -2061,14 +2063,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
whereLoopDelete(db, pToDel);
|
||||
}
|
||||
}
|
||||
whereLoopXfer(db, p, pTemplate);
|
||||
rc = whereLoopXfer(db, p, pTemplate);
|
||||
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
|
||||
Index *pIndex = p->u.btree.pIndex;
|
||||
if( pIndex && pIndex->tnum==0 ){
|
||||
p->u.btree.pIndex = 0;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2199,8 +2201,6 @@ static int whereLoopAddBtreeIndex(
|
||||
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
|
||||
if( pNew->wsFlags & WHERE_BTM_LIMIT ){
|
||||
opMask = WO_LT|WO_LE;
|
||||
}else if( /*pProbe->tnum<=0 ||*/ (pSrc->fg.jointype & JT_LEFT)!=0 ){
|
||||
opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE;
|
||||
}else{
|
||||
opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
|
||||
}
|
||||
@@ -2238,6 +2238,18 @@ static int whereLoopAddBtreeIndex(
|
||||
** to mix with a lower range bound from some other source */
|
||||
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
|
||||
|
||||
/* Do not allow IS constraints from the WHERE clause to be used by the
|
||||
** right table of a LEFT JOIN. Only constraints in the ON clause are
|
||||
** allowed */
|
||||
if( (pSrc->fg.jointype & JT_LEFT)!=0
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
&& (eOp & (WO_IS|WO_ISNULL))!=0
|
||||
){
|
||||
testcase( eOp & WO_IS );
|
||||
testcase( eOp & WO_ISNULL );
|
||||
continue;
|
||||
}
|
||||
|
||||
pNew->wsFlags = saved_wsFlags;
|
||||
pNew->u.btree.nEq = saved_nEq;
|
||||
pNew->nLTerm = saved_nLTerm;
|
||||
@@ -2810,10 +2822,9 @@ static int whereLoopAddVirtualOne(
|
||||
|
||||
/* Initialize the output fields of the sqlite3_index_info structure */
|
||||
memset(pUsage, 0, sizeof(pUsage[0])*nConstraint);
|
||||
if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
|
||||
assert( pIdxInfo->needToFreeIdxStr==0 );
|
||||
pIdxInfo->idxStr = 0;
|
||||
pIdxInfo->idxNum = 0;
|
||||
pIdxInfo->needToFreeIdxStr = 0;
|
||||
pIdxInfo->orderByConsumed = 0;
|
||||
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
|
||||
pIdxInfo->estimatedRows = 25;
|
||||
@@ -2887,13 +2898,16 @@ static int whereLoopAddVirtualOne(
|
||||
}else{
|
||||
pNew->wsFlags &= ~WHERE_ONEROW;
|
||||
}
|
||||
whereLoopInsert(pBuilder, pNew);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
if( pNew->u.vtab.needFree ){
|
||||
sqlite3_free(pNew->u.vtab.idxStr);
|
||||
pNew->u.vtab.needFree = 0;
|
||||
}
|
||||
WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
|
||||
*pbIn, (sqlite3_uint64)mPrereq,
|
||||
(sqlite3_uint64)(pNew->prereq & ~mPrereq)));
|
||||
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -2958,15 +2972,15 @@ static int whereLoopAddVirtual(
|
||||
}
|
||||
|
||||
/* First call xBestIndex() with all constraints usable. */
|
||||
WHERETRACE(0x40, (" VirtualOne: all usable\n"));
|
||||
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, &bIn);
|
||||
mBest = pNew->prereq & ~mPrereq;
|
||||
|
||||
/* If the call to xBestIndex() with all terms enabled produced a plan
|
||||
** that does not require any source tables, there is no point in making
|
||||
** any further calls - if the xBestIndex() method is sane they will all
|
||||
** return the same plan anyway.
|
||||
*/
|
||||
if( mBest ){
|
||||
** that does not require any source tables (IOW: a plan with mBest==0),
|
||||
** then there is no point in making any further calls to xBestIndex()
|
||||
** since they will all return the same result (if the xBestIndex()
|
||||
** implementation is sane). */
|
||||
if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){
|
||||
int seenZero = 0; /* True if a plan with no prereqs seen */
|
||||
int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */
|
||||
Bitmask mPrev = 0;
|
||||
@@ -2974,7 +2988,8 @@ static int whereLoopAddVirtual(
|
||||
|
||||
/* If the plan produced by the earlier call uses an IN(...) term, call
|
||||
** xBestIndex again, this time with IN(...) terms disabled. */
|
||||
if( rc==SQLITE_OK && bIn ){
|
||||
if( bIn ){
|
||||
WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
|
||||
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, WO_IN, p, &bIn);
|
||||
assert( bIn==0 );
|
||||
mBestNoIn = pNew->prereq & ~mPrereq;
|
||||
@@ -2999,6 +3014,8 @@ static int whereLoopAddVirtual(
|
||||
mPrev = mNext;
|
||||
if( mNext==ALLBITS ) break;
|
||||
if( mNext==mBest || mNext==mBestNoIn ) continue;
|
||||
WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
|
||||
(sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
|
||||
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mNext|mPrereq, 0, p, &bIn);
|
||||
if( pNew->prereq==mPrereq ){
|
||||
seenZero = 1;
|
||||
@@ -3010,6 +3027,7 @@ static int whereLoopAddVirtual(
|
||||
** that requires no source tables at all (i.e. one guaranteed to be
|
||||
** usable), make a call here with all source tables disabled */
|
||||
if( rc==SQLITE_OK && seenZero==0 ){
|
||||
WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
|
||||
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mPrereq, 0, p, &bIn);
|
||||
if( bIn==0 ) seenZeroNoIN = 1;
|
||||
}
|
||||
@@ -3018,6 +3036,7 @@ static int whereLoopAddVirtual(
|
||||
** that requires no source tables at all and does not use an IN(...)
|
||||
** operator, make a final call to obtain one here. */
|
||||
if( rc==SQLITE_OK && seenZeroNoIN==0 ){
|
||||
WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
|
||||
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mPrereq, WO_IN, p, &bIn);
|
||||
}
|
||||
}
|
||||
@@ -3921,7 +3940,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
int j;
|
||||
Table *pTab;
|
||||
Index *pIdx;
|
||||
|
||||
|
||||
pWInfo = pBuilder->pWInfo;
|
||||
if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0;
|
||||
assert( pWInfo->pTabList->nSrc>=1 );
|
||||
|
||||
+6
-3
@@ -25,9 +25,12 @@ if {$tcl_platform(platform)=="windows"} {
|
||||
set PROG "./sqlite3_analyzer"
|
||||
}
|
||||
if {![file exe $PROG]} {
|
||||
puts "analyzer1 cannot run because $PROG is not available"
|
||||
finish_test
|
||||
return
|
||||
set PROG [file normalize [file join $::cmdlinearg(TESTFIXTURE_HOME) $PROG]]
|
||||
if {![file exe $PROG]} {
|
||||
puts "analyzer1 cannot run because $PROG is not available"
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
}
|
||||
db close
|
||||
forcedelete test.db test.db-journal test.db-wal
|
||||
|
||||
+14
-3
@@ -269,7 +269,7 @@ do_test autovacuum-2.4.3 {
|
||||
} {3 4 5 6 7 8 9 10}
|
||||
|
||||
# Right now there are 5 free pages in the database. Consume and then free
|
||||
# a 520 pages. Then create 520 tables. This ensures that at least some of the
|
||||
# all 520 pages. Then create 520 tables. This ensures that at least some of the
|
||||
# desired root-pages reside on the second free-list trunk page, and that the
|
||||
# trunk itself is required at some point.
|
||||
do_test autovacuum-2.4.4 {
|
||||
@@ -280,9 +280,20 @@ do_test autovacuum-2.4.4 {
|
||||
} {}
|
||||
set root_page_list [list]
|
||||
set pending_byte_page [expr ($::sqlite_pending_byte / 1024) + 1]
|
||||
|
||||
# unusable_pages
|
||||
# These are either the pending_byte page or the pointer map pages
|
||||
#
|
||||
unset -nocomplain unusable_page
|
||||
if {[sqlite3 -has-codec]} {
|
||||
array set unusable_page {205 1 408 1}
|
||||
} else {
|
||||
array set unusable_page {207 1 412 1}
|
||||
}
|
||||
set unusable_page($pending_byte_page) 1
|
||||
|
||||
for {set i 3} {$i<=532} {incr i} {
|
||||
# 207 and 412 are pointer-map pages.
|
||||
if { $i!=207 && $i!=412 && $i != $pending_byte_page} {
|
||||
if {![info exists unusable_page($i)]} {
|
||||
lappend root_page_list $i
|
||||
}
|
||||
}
|
||||
|
||||
+10
-3
@@ -63,7 +63,7 @@ proc do_backcompat_test {rv bin1 bin2 script} {
|
||||
set v [split [db version] .]
|
||||
if {[llength $v]==3} {lappend v 0}
|
||||
set ::sqlite_libversion [format \
|
||||
"%d%.2d%.2d%2d" [lindex $v 0] [lindex $v 1] [lindex $v 2] [lindex $v 3]
|
||||
"%d%.2d%.2d%.2d" [lindex $v 0] [lindex $v 1] [lindex $v 2] [lindex $v 3]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,8 @@ proc do_allbackcompat_test {script} {
|
||||
set nErr [set_test_counter errors]
|
||||
foreach dir {0 1} {
|
||||
|
||||
set bintag [string map {testfixture {}} $bin]
|
||||
set bintag $bin
|
||||
regsub {.*testfixture\.} $bintag {} bintag
|
||||
set bintag [string map {\.exe {}} $bintag]
|
||||
if {$bintag == ""} {set bintag self}
|
||||
set ::bcname ".$bintag.$dir."
|
||||
@@ -420,6 +421,12 @@ ifcapable fts3 {
|
||||
if {[code1 { set ::sqlite_libversion }] >=3071200
|
||||
&& [code2 { set ::sqlite_libversion }] >=3071200
|
||||
} {
|
||||
if {[code1 { set ::sqlite_libversion }]<3120000} {
|
||||
set res {0 {0 1} 1 0}
|
||||
} else {
|
||||
set res {1 0}
|
||||
}
|
||||
|
||||
do_test backcompat-3.9 {
|
||||
sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); }
|
||||
sql2 { INSERT INTO t2(t2) VALUES('merge=100,4'); }
|
||||
@@ -428,7 +435,7 @@ ifcapable fts3 {
|
||||
sql2 {
|
||||
SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level;
|
||||
}
|
||||
} {0 {0 1} 1 0}
|
||||
} $res
|
||||
|
||||
do_test backcompat-3.10 {
|
||||
sql1 { INSERT INTO t2(t2) VALUES('integrity-check') }
|
||||
|
||||
@@ -23,6 +23,11 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix backup4
|
||||
|
||||
# The codec logic does not work for zero-length database files. A database
|
||||
# file must contain at least one page in order to be recognized as an
|
||||
# encrypted database.
|
||||
do_not_use_codec
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# At one point this test was failing because [db] was using an out of
|
||||
# date schema in test case 1.2.
|
||||
|
||||
+3
-2
@@ -7,7 +7,7 @@ proc bc_find_binaries {zCaption} {
|
||||
# against.
|
||||
#
|
||||
set binaries [list]
|
||||
set self [file tail [info nameofexec]]
|
||||
set self [info nameofexec]
|
||||
set pattern "$self?*"
|
||||
if {$::tcl_platform(platform)=="windows"} {
|
||||
set pattern [string map {\.exe {}} $pattern]
|
||||
@@ -52,7 +52,8 @@ proc do_bc_test {bin script} {
|
||||
code1 { sqlite3 db test.db }
|
||||
code2 { sqlite3 db test.db }
|
||||
|
||||
set bintag [string map {testfixture {}} $bin]
|
||||
set bintag $bin
|
||||
regsub {.*testfixture\.} $bintag {} bintag
|
||||
set bintag [string map {\.exe {}} $bintag]
|
||||
if {$bintag == ""} {set bintag self}
|
||||
set saved_prefix $::testprefix
|
||||
|
||||
@@ -15,6 +15,11 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix bestindex1
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
register_tcl_module db
|
||||
|
||||
proc vtab_command {method args} {
|
||||
@@ -161,5 +166,3 @@ foreach {tn mode} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix bestindex2
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Virtual table callback for table named $tbl, with the columns specified
|
||||
@@ -135,4 +139,3 @@ do_eqp_test 1.7.2 {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+16
-14
@@ -172,14 +172,15 @@ do_test capi3-3.3 {
|
||||
catch {
|
||||
set db2 [sqlite3_open /bogus/path/test.db {}]
|
||||
}
|
||||
sqlite3_extended_errcode $db2
|
||||
} {SQLITE_CANTOPEN}
|
||||
set ::capi3_errno [sqlite3_system_errno $db2]
|
||||
list [sqlite3_extended_errcode $db2] [expr {$::capi3_errno!=0}]
|
||||
} {SQLITE_CANTOPEN 1}
|
||||
do_test capi3-3.4 {
|
||||
sqlite3_errmsg $db2
|
||||
} {unable to open database file}
|
||||
do_test capi3-3.5 {
|
||||
sqlite3_close $db2
|
||||
} {SQLITE_OK}
|
||||
list [sqlite3_system_errno $db2] [sqlite3_close $db2]
|
||||
} [list $::capi3_errno SQLITE_OK]
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test capi3-3.6.1-misuse {
|
||||
sqlite3_close $db2
|
||||
@@ -925,19 +926,20 @@ do_test capi3-11.9.3 {
|
||||
do_test capi3-11.10 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
ifcapable !autoreset {
|
||||
# If SQLITE_OMIT_AUTORESET is defined, then the statement must be
|
||||
# reset() before it can be passed to step() again.
|
||||
do_test capi3-11.11a { sqlite3_step $STMT } {SQLITE_MISUSE}
|
||||
do_test capi3-11.11b { sqlite3_reset $STMT } {SQLITE_ABORT}
|
||||
}
|
||||
do_test capi3-11.11 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_DONE}
|
||||
do_test capi3-11.12 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
ifcapable !autoreset {
|
||||
do_test capi3-11.12armor {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_MISUSE}
|
||||
} else {
|
||||
do_test capi3-11.12 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
}
|
||||
do_test capi3-11.13 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
+11
-10
@@ -865,19 +865,20 @@ do_test capi3c-11.9.3 {
|
||||
do_test capi3c-11.10 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
ifcapable !autoreset {
|
||||
# If SQLITE_OMIT_AUTORESET is defined, then the statement must be
|
||||
# reset() before it can be passed to step() again.
|
||||
do_test capi3-11.11a { sqlite3_step $STMT } {SQLITE_MISUSE}
|
||||
do_test capi3-11.11b { sqlite3_reset $STMT } {SQLITE_ABORT}
|
||||
}
|
||||
do_test capi3c-11.11 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_DONE}
|
||||
do_test capi3c-11.12 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
ifcapable !autoreset {
|
||||
do_test capi3c-11.12armor {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_MISUSE}
|
||||
} else {
|
||||
do_test capi3c-11.12 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
}
|
||||
do_test capi3c-11.13 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
@@ -17,6 +17,10 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix close
|
||||
|
||||
# This module bypasses the "-key" logic in tester.tcl, so it cannot run
|
||||
# with the codec enabled.
|
||||
do_not_use_codec
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES('one');
|
||||
|
||||
+23
-21
@@ -346,27 +346,29 @@ ifcapable autovacuum {
|
||||
} {1 {database disk image is malformed}}
|
||||
}
|
||||
|
||||
corruption_test -sqlprep {
|
||||
PRAGMA auto_vacuum = 1;
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, randomblob(2500));
|
||||
DELETE FROM t1 WHERE a = 1;
|
||||
} -corrupt {
|
||||
set nAppend [expr 1024*207 - [file size corrupt.db]]
|
||||
set fd [open corrupt.db r+]
|
||||
seek $fd 0 end
|
||||
puts -nonewline $fd [string repeat x $nAppend]
|
||||
close $fd
|
||||
hexio_write corrupt.db 28 00000000
|
||||
} -test {
|
||||
do_test corrupt2-6.4 {
|
||||
catchsql "
|
||||
$::presql
|
||||
BEGIN EXCLUSIVE;
|
||||
COMMIT;
|
||||
"
|
||||
} {1 {database disk image is malformed}}
|
||||
if {![nonzero_reserved_bytes]} {
|
||||
corruption_test -sqlprep {
|
||||
PRAGMA auto_vacuum = 1;
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, randomblob(2500));
|
||||
DELETE FROM t1 WHERE a = 1;
|
||||
} -corrupt {
|
||||
set nAppend [expr 1024*207 - [file size corrupt.db]]
|
||||
set fd [open corrupt.db r+]
|
||||
seek $fd 0 end
|
||||
puts -nonewline $fd [string repeat x $nAppend]
|
||||
close $fd
|
||||
hexio_write corrupt.db 28 00000000
|
||||
} -test {
|
||||
do_test corrupt2-6.4 {
|
||||
catchsql "
|
||||
$::presql
|
||||
BEGIN EXCLUSIVE;
|
||||
COMMIT;
|
||||
"
|
||||
} {1 {database disk image is malformed}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -18,10 +18,9 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
|
||||
+3
-4
@@ -18,10 +18,9 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
|
||||
+3
-4
@@ -19,10 +19,9 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
|
||||
+3
-4
@@ -19,10 +19,9 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
|
||||
+3
-4
@@ -18,10 +18,9 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
|
||||
+3
-4
@@ -14,10 +14,9 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptG
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
|
||||
+4
-4
@@ -14,10 +14,10 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptH
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
database_may_be_corrupt
|
||||
|
||||
# The corruption migrations tested by the code in this file are not detected
|
||||
|
||||
+4
-4
@@ -19,10 +19,10 @@ if {[permutation]=="mmap"} {
|
||||
return
|
||||
}
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
database_may_be_corrupt
|
||||
|
||||
# Initialize the database.
|
||||
|
||||
+4
-4
@@ -22,10 +22,10 @@ if {[permutation]=="mmap"} {
|
||||
return
|
||||
}
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
database_may_be_corrupt
|
||||
|
||||
# Initialize the database.
|
||||
|
||||
@@ -25,6 +25,7 @@ ifcapable !crashtest {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
do_not_use_codec
|
||||
|
||||
do_test crash8-1.1 {
|
||||
execsql {
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix e_uri
|
||||
|
||||
do_not_use_codec
|
||||
db close
|
||||
|
||||
proc parse_uri {uri} {
|
||||
|
||||
+30
-28
@@ -159,35 +159,37 @@ do_test e_vacuum-1.3.1.2 {
|
||||
execsql { PRAGMA page_size ; PRAGMA auto_vacuum }
|
||||
} {1024 1}
|
||||
|
||||
# EVIDENCE-OF: R-08570-19916 However, when not in write-ahead log mode,
|
||||
# the page_size and/or auto_vacuum properties of an existing database
|
||||
# may be changed by using the page_size and/or pragma auto_vacuum
|
||||
# pragmas and then immediately VACUUMing the database.
|
||||
#
|
||||
do_test e_vacuum-1.3.2.1 {
|
||||
execsql { PRAGMA journal_mode = delete }
|
||||
execsql { PRAGMA page_size = 2048 }
|
||||
execsql { PRAGMA auto_vacuum = NONE }
|
||||
execsql VACUUM
|
||||
execsql { PRAGMA page_size ; PRAGMA auto_vacuum }
|
||||
} {2048 0}
|
||||
|
||||
# EVIDENCE-OF: R-48521-51450 When in write-ahead log mode, only the
|
||||
# auto_vacuum support property can be changed using VACUUM.
|
||||
#
|
||||
ifcapable wal {
|
||||
do_test e_vacuum-1.3.3.1 {
|
||||
execsql { PRAGMA journal_mode = wal }
|
||||
execsql { PRAGMA page_size ; PRAGMA auto_vacuum }
|
||||
} {2048 0}
|
||||
do_test e_vacuum-1.3.3.2 {
|
||||
execsql { PRAGMA page_size = 1024 }
|
||||
execsql { PRAGMA auto_vacuum = FULL }
|
||||
execsql VACUUM
|
||||
execsql { PRAGMA page_size ; PRAGMA auto_vacuum }
|
||||
} {2048 1}
|
||||
if {![nonzero_reserved_bytes]} {
|
||||
# EVIDENCE-OF: R-08570-19916 However, when not in write-ahead log mode,
|
||||
# the page_size and/or auto_vacuum properties of an existing database
|
||||
# may be changed by using the page_size and/or pragma auto_vacuum
|
||||
# pragmas and then immediately VACUUMing the database.
|
||||
#
|
||||
do_test e_vacuum-1.3.2.1 {
|
||||
execsql { PRAGMA journal_mode = delete }
|
||||
execsql { PRAGMA page_size = 2048 }
|
||||
execsql { PRAGMA auto_vacuum = NONE }
|
||||
execsql VACUUM
|
||||
execsql { PRAGMA page_size ; PRAGMA auto_vacuum }
|
||||
} {2048 0}
|
||||
|
||||
# EVIDENCE-OF: R-48521-51450 When in write-ahead log mode, only the
|
||||
# auto_vacuum support property can be changed using VACUUM.
|
||||
#
|
||||
ifcapable wal {
|
||||
do_test e_vacuum-1.3.3.1 {
|
||||
execsql { PRAGMA journal_mode = wal }
|
||||
execsql { PRAGMA page_size ; PRAGMA auto_vacuum }
|
||||
} {2048 0}
|
||||
do_test e_vacuum-1.3.3.2 {
|
||||
execsql { PRAGMA page_size = 1024 }
|
||||
execsql { PRAGMA auto_vacuum = FULL }
|
||||
execsql VACUUM
|
||||
execsql { PRAGMA page_size ; PRAGMA auto_vacuum }
|
||||
} {2048 1}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-38001-03952 VACUUM only works on the main database. It
|
||||
# is not possible to VACUUM an attached database file.
|
||||
forcedelete test.db2
|
||||
|
||||
@@ -24,6 +24,11 @@ if {$tcl_platform(os) == "OpenBSD"} {
|
||||
return
|
||||
}
|
||||
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
|
||||
|
||||
proc read_nbackfill {} {
|
||||
seek $::shmfd 96
|
||||
binary scan [read $::shmfd 4] n nBackfill
|
||||
|
||||
+34
-32
@@ -516,45 +516,47 @@ det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" {
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - eqp-6.* - test that the example C code on
|
||||
# documentation page eqp.html works. The C code is duplicated in test1.c
|
||||
# and wrapped in Tcl command [print_explain_query_plan]
|
||||
#
|
||||
set boilerplate {
|
||||
proc explain_query_plan {db sql} {
|
||||
set stmt [sqlite3_prepare_v2 db $sql -1 DUMMY]
|
||||
print_explain_query_plan $stmt
|
||||
sqlite3_finalize $stmt
|
||||
if {![nonzero_reserved_bytes]} {
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - eqp-6.* - test that the example C code on
|
||||
# documentation page eqp.html works. The C code is duplicated in test1.c
|
||||
# and wrapped in Tcl command [print_explain_query_plan]
|
||||
#
|
||||
set boilerplate {
|
||||
proc explain_query_plan {db sql} {
|
||||
set stmt [sqlite3_prepare_v2 db $sql -1 DUMMY]
|
||||
print_explain_query_plan $stmt
|
||||
sqlite3_finalize $stmt
|
||||
}
|
||||
sqlite3 db test.db
|
||||
explain_query_plan db {%SQL%}
|
||||
db close
|
||||
exit
|
||||
}
|
||||
sqlite3 db test.db
|
||||
explain_query_plan db {%SQL%}
|
||||
db close
|
||||
exit
|
||||
}
|
||||
|
||||
# Do a "Print Explain Query Plan" test.
|
||||
proc do_peqp_test {tn sql res} {
|
||||
set fd [open script.tcl w]
|
||||
puts $fd [string map [list %SQL% $sql] $::boilerplate]
|
||||
close $fd
|
||||
|
||||
uplevel do_test $tn [list {
|
||||
set fd [open "|[info nameofexec] script.tcl"]
|
||||
set data [read $fd]
|
||||
|
||||
# Do a "Print Explain Query Plan" test.
|
||||
proc do_peqp_test {tn sql res} {
|
||||
set fd [open script.tcl w]
|
||||
puts $fd [string map [list %SQL% $sql] $::boilerplate]
|
||||
close $fd
|
||||
set data
|
||||
}] [list $res]
|
||||
}
|
||||
|
||||
do_peqp_test 6.1 {
|
||||
SELECT a, b FROM t1 EXCEPT SELECT d, 99 FROM t2 ORDER BY 1
|
||||
} [string trimleft {
|
||||
|
||||
uplevel do_test $tn [list {
|
||||
set fd [open "|[info nameofexec] script.tcl"]
|
||||
set data [read $fd]
|
||||
close $fd
|
||||
set data
|
||||
}] [list $res]
|
||||
}
|
||||
|
||||
do_peqp_test 6.1 {
|
||||
SELECT a, b FROM t1 EXCEPT SELECT d, 99 FROM t2 ORDER BY 1
|
||||
} [string trimleft {
|
||||
1 0 0 SCAN TABLE t1 USING COVERING INDEX i2
|
||||
2 0 0 SCAN TABLE t2
|
||||
2 0 0 USE TEMP B-TREE FOR ORDER BY
|
||||
0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)
|
||||
}]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - eqp-7.* - test that queries that use the OP_Count
|
||||
|
||||
+3
-3
@@ -423,7 +423,7 @@ do_test exclusive-5.1 {
|
||||
# (2016-03-04) The statement-journal is now opened lazily
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} [expr 2 - ($TEMP_STORE>=2)]
|
||||
} {2}
|
||||
do_test exclusive-5.2 {
|
||||
execsql {
|
||||
COMMIT;
|
||||
@@ -450,7 +450,7 @@ do_test exclusive-5.4 {
|
||||
# 2016-03-04: The statement-journal open is deferred
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} [expr 2 - ($TEMP_STORE>=2)]
|
||||
} {2}
|
||||
do_test exclusive-5.5 {
|
||||
execsql {
|
||||
COMMIT;
|
||||
@@ -459,7 +459,7 @@ do_test exclusive-5.5 {
|
||||
# 2016-03-04: The statement-journal open is deferred
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} [expr 2 - ($TEMP_STORE>=2)]
|
||||
} {2}
|
||||
do_test exclusive-5.6 {
|
||||
execsql {
|
||||
PRAGMA locking_mode = normal;
|
||||
|
||||
+10
-6
@@ -144,9 +144,11 @@ do_execsql_test filefmt-2.1.1 {
|
||||
CREATE TABLE t2(a);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
} {}
|
||||
do_test filefmt-2.1.2 {
|
||||
hexio_read test.db 28 4
|
||||
} {00000009}
|
||||
if {![nonzero_reserved_bytes]} {
|
||||
do_test filefmt-2.1.2 {
|
||||
hexio_read test.db 28 4
|
||||
} {00000009}
|
||||
}
|
||||
|
||||
do_test filefmt-2.1.3 {
|
||||
sql36231 { INSERT INTO t1 VALUES(a_string(3000)) }
|
||||
@@ -170,9 +172,11 @@ do_execsql_test filefmt-2.2.1 {
|
||||
CREATE TABLE t2(a);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
} {}
|
||||
do_test filefmt-2.2.2 {
|
||||
hexio_read test.db 28 4
|
||||
} {00000009}
|
||||
if {![nonzero_reserved_bytes]} {
|
||||
do_test filefmt-2.2.2 {
|
||||
hexio_read test.db 28 4
|
||||
} {00000009}
|
||||
}
|
||||
|
||||
do_test filefmt-2.2.3 {
|
||||
sql36231 { INSERT INTO t1 VALUES(a_string(3000)) }
|
||||
|
||||
+22
-18
@@ -59,11 +59,11 @@ do_test 1.4 {
|
||||
INSERT INTO x1(x1) VALUES('merge=4,4');
|
||||
SELECT level, end_block, length(root) FROM x1_segdir;
|
||||
}
|
||||
} {0 {0 110} 110 0 {0 132} 132 0 {0 129} 129 1 {128 658} 2}
|
||||
} {1 {224 921} 2}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
SELECT length(block) FROM x1_segments;
|
||||
} {658 {}}
|
||||
} {921 {}}
|
||||
|
||||
do_test 1.6 {
|
||||
foreach L {
|
||||
@@ -71,27 +71,33 @@ do_test 1.6 {
|
||||
{That perched above Dead Man's Creek, beside the mountain road.}
|
||||
{He turned the cycle down the hill and mounted for the fray,}
|
||||
{But 'ere he'd gone a dozen yards it bolted clean away.}
|
||||
|
||||
{It left the track, and through the trees, just like a silver steak,}
|
||||
{It whistled down the awful slope towards the Dead Man's Creek.}
|
||||
{It shaved a stump by half an inch, it dodged a big white-box:}
|
||||
{The very wallaroos in fright went scrambling up the rocks,}
|
||||
|
||||
{The wombats hiding in their caves dug deeper underground,}
|
||||
{As Mulga Bill, as white as chalk, sat tight to every bound.}
|
||||
{It struck a stone and gave a spring that cleared a fallen tree,}
|
||||
{It raced beside a precipice as close as close could be;}
|
||||
|
||||
{And then as Mulga Bill let out one last despairing shriek}
|
||||
{It made a leap of twenty feet into the Dead Man's Creek.}
|
||||
{It shaved a stump by half an inch, it dodged a big white-box:}
|
||||
{The very wallaroos in fright went scrambling up the rocks,}
|
||||
{The wombats hiding in their caves dug deeper underground,}
|
||||
} {
|
||||
execsql { INSERT INTO x1 VALUES($L) }
|
||||
}
|
||||
execsql {
|
||||
SELECT level, end_block, length(root) FROM x1_segdir;
|
||||
}
|
||||
} {1 {128 658} 2 1 {130 1377} 6 0 {0 117} 117}
|
||||
} {1 {224 921} 2 1 {226 1230} 7 0 {0 98} 98}
|
||||
|
||||
do_execsql_test 1.7 {
|
||||
SELECT sum(length(block)) FROM x1_segments WHERE blockid IN (129, 130);
|
||||
} {1377}
|
||||
SELECT sum(length(block)) FROM x1_segments WHERE blockid IN (224,225,226)
|
||||
} {1230}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -131,24 +137,24 @@ do_execsql_test 2.5 {
|
||||
SELECT end_block FROM x2_segdir WHERE level=3;
|
||||
INSERT INTO x2(x2) VALUES('merge=4,4');
|
||||
SELECT end_block FROM x2_segdir WHERE level=3;
|
||||
} {{3828 -3430} {3828 -10191} {3828 -14109}}
|
||||
} {{5588 -3950} {5588 -11766} {5588 -15541}}
|
||||
|
||||
do_execsql_test 2.6 {
|
||||
SELECT sum(length(block)) FROM x2_segdir, x2_segments WHERE
|
||||
blockid BETWEEN start_block AND leaves_end_block
|
||||
AND level=3
|
||||
} {14109}
|
||||
} {15541}
|
||||
|
||||
do_execsql_test 2.7 {
|
||||
INSERT INTO x2(x2) VALUES('merge=1000,4');
|
||||
SELECT end_block FROM x2_segdir WHERE level=3;
|
||||
} {{3828 86120}}
|
||||
} {{5588 127563}}
|
||||
|
||||
do_execsql_test 2.8 {
|
||||
SELECT sum(length(block)) FROM x2_segdir, x2_segments WHERE
|
||||
blockid BETWEEN start_block AND leaves_end_block
|
||||
AND level=3
|
||||
} {86120}
|
||||
} {127563}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Test that delete markers are removed from FTS segments when possible.
|
||||
@@ -391,7 +397,7 @@ do_execsql_test 7.2 {
|
||||
} {
|
||||
0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006}
|
||||
0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006}
|
||||
1 0 {16014 -51226}
|
||||
1 0 {23694 -69477}
|
||||
}
|
||||
|
||||
do_execsql_test 7.3 {
|
||||
@@ -400,7 +406,7 @@ do_execsql_test 7.3 {
|
||||
} {
|
||||
0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006}
|
||||
0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006}
|
||||
1 0 16014
|
||||
1 0 23694
|
||||
}
|
||||
|
||||
do_execsql_test 7.4 {
|
||||
@@ -409,28 +415,26 @@ do_execsql_test 7.4 {
|
||||
} {
|
||||
0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006}
|
||||
0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006}
|
||||
1 0 16014
|
||||
1 0 23694
|
||||
}
|
||||
|
||||
do_execsql_test 7.5 {
|
||||
INSERT INTO x6(x6) VALUES('merge=2500,4');
|
||||
SELECT level, idx, end_block FROM x6_segdir;
|
||||
SELECT level, idx, start_block, leaves_end_block, end_block FROM x6_segdir;
|
||||
} {
|
||||
0 0 {598 118006} 0 1 {718 118006} 1 0 16014
|
||||
1 0 719 1171 23694
|
||||
}
|
||||
|
||||
do_execsql_test 7.6 {
|
||||
INSERT INTO x6(x6) VALUES('merge=2500,2');
|
||||
SELECT level, idx, start_block, leaves_end_block, end_block FROM x6_segdir;
|
||||
} {
|
||||
2 0 23695 24147 {41262 633507}
|
||||
1 0 719 1171 23694
|
||||
}
|
||||
|
||||
do_execsql_test 7.7 {
|
||||
SELECT sum(length(block)) FROM x6_segments
|
||||
WHERE blockid BETWEEN 23695 AND 24147
|
||||
} {633507}
|
||||
|
||||
} {635247}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -481,6 +481,6 @@ foreach lid [list 4 [expr 1<<30]] {
|
||||
do_execsql_test 5.4.$lid.5 {
|
||||
SELECT count(*) FROM t6_segdir;
|
||||
SELECT count(*) FROM t6_segments;
|
||||
} {4 4}
|
||||
} {1 2}
|
||||
}
|
||||
finish_test
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user