Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a81eb93bba | |||
| 702948edbe | |||
| ca90eced28 | |||
| d351e7643f |
@@ -428,7 +428,6 @@ TESTSRC += \
|
||||
$(TOP)/ext/fts5/fts5_test_mi.c \
|
||||
$(TOP)/ext/fts5/fts5_test_tok.c \
|
||||
$(TOP)/ext/misc/ieee754.c \
|
||||
$(TOP)/ext/misc/mmapwarm.c \
|
||||
$(TOP)/ext/misc/nextchar.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
|
||||
@@ -1411,7 +1411,6 @@ TESTEXT = \
|
||||
$(TOP)\ext\fts5\fts5_test_mi.c \
|
||||
$(TOP)\ext\fts5\fts5_test_tok.c \
|
||||
$(TOP)\ext\misc\ieee754.c \
|
||||
$(TOP)\ext\misc\mmapwarm.c \
|
||||
$(TOP)\ext\misc\nextchar.c \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
|
||||
@@ -10304,7 +10304,7 @@ USE_AMALGAMATION=1
|
||||
# if not, then we fall back to plain tclsh.
|
||||
# TODO: try other versions before falling back?
|
||||
#
|
||||
for ac_prog in tclsh8.7 tclsh8.6 tclsh8.5 tclsh
|
||||
for ac_prog in tclsh8.6 tclsh8.5 tclsh
|
||||
do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ USE_AMALGAMATION=1
|
||||
# if not, then we fall back to plain tclsh.
|
||||
# TODO: try other versions before falling back?
|
||||
#
|
||||
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.7 tclsh8.6 tclsh8.5 tclsh], none)
|
||||
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh8.5 tclsh], none)
|
||||
if test "$TCLSH_CMD" = "none"; then
|
||||
# If we can't find a local tclsh, then building the amalgamation will fail.
|
||||
# We act as though --disable-amalgamation has been used.
|
||||
|
||||
+176
-203
@@ -2,12 +2,12 @@
|
||||
<head>
|
||||
<title>The Lemon Parser Generator</title>
|
||||
</head>
|
||||
<body bgcolor='white'>
|
||||
<h1 align='center'>The Lemon Parser Generator</h1>
|
||||
<body bgcolor=white>
|
||||
<h1 align=center>The Lemon Parser Generator</h1>
|
||||
|
||||
<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
|
||||
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
|
||||
parsing engine that is faster than yacc and
|
||||
@@ -16,7 +16,7 @@ bison and which is both reentrant and threadsafe.
|
||||
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 it suitable for use
|
||||
to eliminate resource leaks, making is suitable for use
|
||||
in long-running programs such as graphical user interfaces
|
||||
or embedded controllers.</p>
|
||||
|
||||
@@ -58,8 +58,8 @@ Lemon comes with a default parser template which works fine for most
|
||||
applications. But the user is free to substitute a different parser
|
||||
template if desired.</p>
|
||||
|
||||
<p>Depending on command-line options, Lemon will generate up to
|
||||
three output files.
|
||||
<p>Depending on command-line options, Lemon will generate between
|
||||
one and three files of outputs.
|
||||
<ul>
|
||||
<li>C code to implement the parser.
|
||||
<li>A header file defining an integer ID for each terminal symbol.
|
||||
@@ -90,20 +90,17 @@ the states used by the parser automaton.</p>
|
||||
You can obtain a list of the available command-line options together
|
||||
with a brief explanation of what each does by typing
|
||||
<pre>
|
||||
lemon "-?"
|
||||
lemon -?
|
||||
</pre>
|
||||
As of this writing, the following command-line options are supported:
|
||||
<ul>
|
||||
<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. The parser will be a
|
||||
little larger and slower, but it will detect syntax errors sooner.
|
||||
Do not compress the generated action tables.
|
||||
<li><b>-D<i>name</i></b>
|
||||
Define C preprocessor macro <i>name</i>. This macro is usable by
|
||||
"<tt><a href='#pifdef'>%ifdef</a></tt>" and
|
||||
"<tt><a href='#pifdef'>%ifndef</a></tt>" lines
|
||||
in the grammar file.
|
||||
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.
|
||||
@@ -111,9 +108,9 @@ output with all comments, actions, and other extraneous text removed.
|
||||
Omit "#line" directives in the generated parser C code.
|
||||
<li><b>-m</b>
|
||||
Cause the output C source code to be compatible with the "makeheaders"
|
||||
program.
|
||||
program.
|
||||
<li><b>-p</b>
|
||||
Display all conflicts that are resolved by
|
||||
Display all conflicts that are resolved by
|
||||
<a href='#precrules'>precedence rules</a>.
|
||||
<li><b>-q</b>
|
||||
Suppress generation of the report file.
|
||||
@@ -168,7 +165,7 @@ once for each token:
|
||||
</pre>
|
||||
The first argument to the Parse() routine is the pointer returned by
|
||||
ParseAlloc().
|
||||
The second argument is a small positive integer that tells the parser the
|
||||
The second argument is a small positive integer that tells the parse the
|
||||
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
|
||||
@@ -176,7 +173,7 @@ 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.
|
||||
The third argument is the value of the given token. By default,
|
||||
the type of the third argument is "void*", but the grammar will
|
||||
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
|
||||
@@ -184,7 +181,7 @@ be the name of the identifier or the value of the number.</p>
|
||||
|
||||
<p>The Parse() function may have either three or four arguments,
|
||||
depending on the grammar. If the grammar specification file requests
|
||||
it (via the <tt><a href='#extraarg'>%extra_argument</a></tt> directive),
|
||||
it (via the <a href='#extraarg'><tt>extra_argument</tt> directive</a>),
|
||||
the Parse() function will have a fourth parameter that can be
|
||||
of any type chosen by the programmer. The parser doesn't do anything
|
||||
with this argument except to pass it through to action routines.
|
||||
@@ -194,20 +191,20 @@ to the action routines without having to use global variables.</p>
|
||||
<p>A typical use of a Lemon parser might look something like the
|
||||
following:
|
||||
<pre>
|
||||
1 ParseTree *ParseFile(const char *zFilename){
|
||||
2 Tokenizer *pTokenizer;
|
||||
3 void *pParser;
|
||||
4 Token sToken;
|
||||
5 int hTokenId;
|
||||
6 ParserState sState;
|
||||
7
|
||||
8 pTokenizer = TokenizerCreate(zFilename);
|
||||
9 pParser = ParseAlloc( malloc );
|
||||
10 InitParserState(&sState);
|
||||
11 while( GetNextToken(pTokenizer, &hTokenId, &sToken) ){
|
||||
12 Parse(pParser, hTokenId, sToken, &sState);
|
||||
01 ParseTree *ParseFile(const char *zFilename){
|
||||
02 Tokenizer *pTokenizer;
|
||||
03 void *pParser;
|
||||
04 Token sToken;
|
||||
05 int hTokenId;
|
||||
06 ParserState sState;
|
||||
07
|
||||
08 pTokenizer = TokenizerCreate(zFilename);
|
||||
09 pParser = ParseAlloc( malloc );
|
||||
10 InitParserState(&sState);
|
||||
11 while( GetNextToken(pTokenizer, &hTokenId, &sToken) ){
|
||||
12 Parse(pParser, hTokenId, sToken, &sState);
|
||||
13 }
|
||||
14 Parse(pParser, 0, sToken, &sState);
|
||||
14 Parse(pParser, 0, sToken, &sState);
|
||||
15 ParseFree(pParser, free );
|
||||
16 TokenizerFree(pTokenizer);
|
||||
17 return sState.treeRoot;
|
||||
@@ -220,10 +217,10 @@ simple.)
|
||||
We assume the existence of some kind of tokenizer which is created
|
||||
using TokenizerCreate() on line 8 and deleted by TokenizerFree()
|
||||
on line 16. The GetNextToken() function on line 11 retrieves the
|
||||
next token from the input file and puts its type in the
|
||||
next token from the input file and puts its type in the
|
||||
integer variable hTokenId. The sToken variable is assumed to be
|
||||
some kind of structure that contains details about each token,
|
||||
such as its complete text, what line it occurs on, etc.</p>
|
||||
such as its complete text, what line it occurs on, etc. </p>
|
||||
|
||||
<p>This example also assumes the existence of structure of type
|
||||
ParserState that holds state information about a particular parse.
|
||||
@@ -240,7 +237,7 @@ tree.</p>
|
||||
<pre>
|
||||
ParseFile(){
|
||||
pParser = ParseAlloc( malloc );
|
||||
while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){
|
||||
while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){
|
||||
Parse(pParser, hTokenId, sToken);
|
||||
}
|
||||
Parse(pParser, 0, sToken);
|
||||
@@ -300,25 +297,25 @@ specifies additional information Lemon requires to do its job.
|
||||
Most of the work in using Lemon is in writing an appropriate
|
||||
grammar file.</p>
|
||||
|
||||
<p>The grammar file for Lemon is, for the most part, free format.
|
||||
<p>The grammar file for lemon is, for the most part, free format.
|
||||
It does not have sections or divisions like yacc or bison. Any
|
||||
declaration can occur at any point in the file.
|
||||
Lemon ignores whitespace (except where it is needed to separate
|
||||
tokens), and it honors the same commenting conventions as C and C++.</p>
|
||||
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/or underscore characters
|
||||
that begins with an uppercase letter.
|
||||
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 uppercase.
|
||||
but the usual convention is to make terminals all upper case.
|
||||
A nonterminal, on the other hand, is any string of alphanumeric
|
||||
and underscore characters than begins with a lowercase letter.
|
||||
Again, the usual convention is to make nonterminals use all lowercase
|
||||
letters.</p>
|
||||
and underscore characters than begins with a lower case letter.
|
||||
Again, the usual convention is to make nonterminals use all lower
|
||||
case letters.</p>
|
||||
|
||||
<p>In Lemon, terminal and nonterminal symbols do not need to
|
||||
<p>In Lemon, terminal and nonterminal symbols do not need to
|
||||
be declared or identified in a separate section of the grammar file.
|
||||
Lemon is able to generate a list of all terminals and nonterminals
|
||||
by examining the grammar rules, and it can always distinguish a
|
||||
@@ -342,8 +339,7 @@ The list of terminals and nonterminals on the right-hand side of the
|
||||
rule can be empty.
|
||||
Rules can occur in any order, except that the left-hand side of the
|
||||
first rule is assumed to be the start symbol for the grammar (unless
|
||||
specified otherwise using the <tt><a href='#start_symbol'>%start_symbol</a></tt>
|
||||
directive described below.)
|
||||
specified otherwise using the <tt>%start</tt> directive described below.)
|
||||
A typical sequence of grammar rules might look something like this:
|
||||
<pre>
|
||||
expr ::= expr PLUS expr.
|
||||
@@ -386,7 +382,7 @@ names to each symbol in a grammar rule and then using those symbolic
|
||||
names in the action.
|
||||
In yacc or bison, one would write this:
|
||||
<pre>
|
||||
expr -> expr PLUS expr { $$ = $1 + $3; };
|
||||
expr -> expr PLUS expr { $$ = $1 + $3; };
|
||||
</pre>
|
||||
But in Lemon, the same rule becomes the following:
|
||||
<pre>
|
||||
@@ -426,14 +422,14 @@ of the shift, and a reduce-reduce conflict is resolved by reducing
|
||||
whichever rule comes first in the grammar file.</p>
|
||||
|
||||
<p>Just like in
|
||||
yacc and bison, Lemon allows a measure of control
|
||||
over the resolution of parsing conflicts using precedence rules.
|
||||
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
|
||||
<tt><a href='#pleft'>%left</a></tt>,
|
||||
<tt><a href='#pright'>%right</a></tt> or
|
||||
<tt><a href='#pnonassoc'>%nonassoc</a></tt> directives. Terminal symbols
|
||||
mentioned in earlier directives have a lower precedence than
|
||||
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>
|
||||
|
||||
<p><pre>
|
||||
@@ -509,29 +505,29 @@ as follows:
|
||||
<li> If the precedence of the token to be shifted is greater than
|
||||
the precedence of the rule to reduce, then resolve in favor
|
||||
of the shift. No parsing conflict is reported.
|
||||
<li> If the precedence of the token to be shifted is less than the
|
||||
<li> If the precedence of the token it be shifted is less than the
|
||||
precedence of the rule to reduce, then resolve in favor of the
|
||||
reduce action. No parsing conflict is reported.
|
||||
<li> If the precedences are the same and the shift token is
|
||||
right-associative, then resolve in favor of the shift.
|
||||
No parsing conflict is reported.
|
||||
<li> If the precedences are the same and the shift token is
|
||||
<li> If the precedences are the same the shift token is
|
||||
left-associative, then resolve in favor of the reduce.
|
||||
No parsing conflict is reported.
|
||||
<li> Otherwise, resolve the conflict by doing the shift, and
|
||||
report a parsing conflict.
|
||||
<li> Otherwise, resolve the conflict by doing the shift and
|
||||
report the parsing conflict.
|
||||
</ul>
|
||||
Reduce-reduce conflicts are resolved this way:
|
||||
<ul>
|
||||
<li> If either reduce rule
|
||||
<li> If either reduce rule
|
||||
lacks precedence information, then resolve in favor of the
|
||||
rule that appears first in the grammar, and report a parsing
|
||||
rule that appears first in the grammar and report a parsing
|
||||
conflict.
|
||||
<li> If both rules have precedence and the precedence is different,
|
||||
<li> If both rules have precedence and the precedence is different
|
||||
then resolve the dispute in favor of the rule with the highest
|
||||
precedence, and do not report a conflict.
|
||||
precedence and do not report a conflict.
|
||||
<li> Otherwise, resolve the conflict by reducing by the rule that
|
||||
appears first in the grammar, and report a parsing conflict.
|
||||
appears first in the grammar and report a parsing conflict.
|
||||
</ul>
|
||||
|
||||
<h3>Special Directives</h3>
|
||||
@@ -540,40 +536,40 @@ Reduce-reduce conflicts are resolved this way:
|
||||
directives. We've described all the grammar rules, so now we'll
|
||||
talk about the special directives.</p>
|
||||
|
||||
<p>Directives in Lemon can occur in any order. You can put them before
|
||||
the grammar rules, or after the grammar rules, or in the midst of the
|
||||
<p>Directives in lemon can occur in any order. You can put them before
|
||||
the grammar rules, or after the grammar rules, or in the mist of the
|
||||
grammar rules. It doesn't matter. The relative order of
|
||||
directives used to assign precedence to terminals is important, but
|
||||
other than that, the order of directives in Lemon is arbitrary.</p>
|
||||
|
||||
<p>Lemon supports the following special directives:
|
||||
<ul>
|
||||
<li><tt><a href='#pcode'>%code</a></tt>
|
||||
<li><tt><a href='#default_destructor'>%default_destructor</a></tt>
|
||||
<li><tt><a href='#default_type'>%default_type</a></tt>
|
||||
<li><tt><a href='#destructor'>%destructor</a></tt>
|
||||
<li><tt><a href='#pifdef'>%endif</a></tt>
|
||||
<li><tt><a href='#extraarg'>%extra_argument</a></tt>
|
||||
<li><tt><a href='#pfallback'>%fallback</a></tt>
|
||||
<li><tt><a href='#pifdef'>%ifdef</a></tt>
|
||||
<li><tt><a href='#pifdef'>%ifndef</a></tt>
|
||||
<li><tt><a href='#pinclude'>%include</a></tt>
|
||||
<li><tt><a href='#pleft'>%left</a></tt>
|
||||
<li><tt><a href='#pname'>%name</a></tt>
|
||||
<li><tt><a href='#pnonassoc'>%nonassoc</a></tt>
|
||||
<li><tt><a href='#parse_accept'>%parse_accept</a></tt>
|
||||
<li><tt><a href='#parse_failure'>%parse_failure</a></tt>
|
||||
<li><tt><a href='#pright'>%right</a></tt>
|
||||
<li><tt><a href='#stack_overflow'>%stack_overflow</a></tt>
|
||||
<li><tt><a href='#stack_size'>%stack_size</a></tt>
|
||||
<li><tt><a href='#start_symbol'>%start_symbol</a></tt>
|
||||
<li><tt><a href='#syntax_error'>%syntax_error</a></tt>
|
||||
<li><tt><a href='#token_class'>%token_class</a></tt>
|
||||
<li><tt><a href='#token_destructor'>%token_destructor</a></tt>
|
||||
<li><tt><a href='#token_prefix'>%token_prefix</a></tt>
|
||||
<li><tt><a href='#token_type'>%token_type</a></tt>
|
||||
<li><tt><a href='#ptype'>%type</a></tt>
|
||||
<li><tt><a href='#pwildcard'>%wildcard</a></tt>
|
||||
<li><tt>%code</tt>
|
||||
<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>
|
||||
<li><tt>%nonassoc</tt>
|
||||
<li><tt>%parse_accept</tt>
|
||||
<li><tt>%parse_failure </tt>
|
||||
<li><tt>%right</tt>
|
||||
<li><tt>%stack_overflow</tt>
|
||||
<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>
|
||||
@@ -581,42 +577,43 @@ following sections:</p>
|
||||
<a name='pcode'></a>
|
||||
<h4>The <tt>%code</tt> directive</h4>
|
||||
|
||||
<p>The <tt>%code</tt> directive is used to specify additional 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 <tt><a href='#pinclude'>%include</a></tt> directive except that
|
||||
<tt>%include</tt> 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><tt>%code</tt> is typically used to include some action routines or perhaps
|
||||
a tokenizer or even the "main()" function
|
||||
<p>%code is typically used to include some action routines or perhaps
|
||||
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 <tt>%default_destructor</tt> directive specifies a destructor to
|
||||
<p>The %default_destructor directive specifies a destructor to
|
||||
use for non-terminals that do not have their own destructor
|
||||
specified by a separate <tt>%destructor</tt> directive. See the documentation
|
||||
on the <tt><a name='#destructor'>%destructor</a></tt> directive below for
|
||||
specified by a separate %destructor directive. See the documentation
|
||||
on the <a name='#destructor'>%destructor</a> directive below for
|
||||
additional information.</p>
|
||||
|
||||
<p>In some grammars, many different non-terminal symbols have the
|
||||
same data type and hence the same destructor. This directive is
|
||||
a convenient way to specify the same destructor for all those
|
||||
<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 <tt>%default_type</tt> directive specifies the data type of non-terminal
|
||||
symbols that do not have their own data type defined using a separate
|
||||
<tt><a href='#ptype'>%type</a></tt> directive.</p>
|
||||
<p>The %default_type directive specifies the datatype of non-terminal
|
||||
symbols that do no have their own datatype defined using a separate
|
||||
<a href='#ptype'>%type</a> directive.
|
||||
</p>
|
||||
|
||||
<a name='destructor'></a>
|
||||
<h4>The <tt>%destructor</tt> directive</h4>
|
||||
|
||||
<p>The <tt>%destructor</tt> directive is used to specify a destructor for
|
||||
<p>The %destructor directive is used to specify a destructor for
|
||||
a non-terminal symbol.
|
||||
(See also the <tt><a href='#token_destructor'>%token_destructor</a></tt>
|
||||
(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
|
||||
@@ -638,7 +635,7 @@ or other resources held by that non-terminal.</p>
|
||||
%destructor nt { free($$); }
|
||||
nt(A) ::= ID NUM. { A = malloc( 100 ); }
|
||||
</pre>
|
||||
This example is a bit contrived, but it serves to illustrate how
|
||||
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
|
||||
@@ -654,17 +651,17 @@ 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.
|
||||
More commonly, the value is used to build some
|
||||
larger structure, and we don't want to destroy it, which is why
|
||||
larger structure and we don't want to destroy it, which is why
|
||||
the destructor is not called in this circumstance.</p>
|
||||
|
||||
<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>
|
||||
<a name="extraarg"></a>
|
||||
<h4>The <tt>%extra_argument</tt> directive</h4>
|
||||
|
||||
The <tt>%extra_argument</tt> directive instructs Lemon to add a 4th parameter
|
||||
The %extra_argument directive instructs Lemon to add a 4th parameter
|
||||
to the parameter list of the Parse() function it generates. Lemon
|
||||
doesn't do anything itself with this extra argument, but it does
|
||||
make the argument available to C-code action routines, destructors,
|
||||
@@ -682,64 +679,61 @@ in the most recent call to Parse().</p>
|
||||
<a name='pfallback'></a>
|
||||
<h4>The <tt>%fallback</tt> directive</h4>
|
||||
|
||||
<p>The <tt>%fallback</tt> directive specifies an alternative meaning for one
|
||||
<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>
|
||||
would have generated a syntax error.
|
||||
|
||||
<p>The <tt>%fallback</tt> directive was added to support robust parsing of SQL
|
||||
syntax in <a href='https://www.sqlite.org/'>SQLite</a>.
|
||||
<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
|
||||
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 <tt>%fallback</tt> directive
|
||||
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>
|
||||
this keyword, try treating it as an identifier instead."
|
||||
|
||||
<p>The syntax of <tt>%fallback</tt> is as follows:
|
||||
<p>The syntax of %fallback is as follows:
|
||||
|
||||
<blockquote>
|
||||
<tt>%fallback</tt> <i>ID</i> <i>TOKEN...</i> <b>.</b>
|
||||
</blockquote></p>
|
||||
<tt>%fallback</tt> <i>ID</i> <i>TOKEN...</i> <b>.</b>
|
||||
</blockquote>
|
||||
|
||||
<p>In words, the <tt>%fallback</tt> directive is followed by a list of token
|
||||
names terminated by a period.
|
||||
The first token name is the fallback token — the
|
||||
<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.</p>
|
||||
argument.
|
||||
|
||||
<a name='pifdef'></a>
|
||||
<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives</h4>
|
||||
<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives.</h4>
|
||||
|
||||
<p>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives
|
||||
are similar to #ifdef, #ifndef, and #endif in the C-preprocessor,
|
||||
just not as general.
|
||||
<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>
|
||||
is allowed between the "%" and the directive name.
|
||||
|
||||
<p>Grammar text in between "<tt>%ifdef MACRO</tt>" and the next nested
|
||||
"<tt>%endif</tt>" is
|
||||
<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 "<tt>%ifndef MACRO</tt>" and the next nested "<tt>%endif</tt>" is
|
||||
included except when the "-DMACRO" command-line option is used.</p>
|
||||
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 <tt>%ifdef</tt> and <tt>%ifndef</tt> must
|
||||
be a single preprocessor symbol name, not a general expression.
|
||||
There is no "<tt>%else</tt>" directive.</p>
|
||||
<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 <tt>%include</tt> directive specifies C code that is included at the
|
||||
top of the generated parser. You can include any text you want —
|
||||
<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
|
||||
<tt>%include</tt> directives in your grammar file, their values are concatenated
|
||||
so that all <tt>%include</tt> code ultimately appears near the top of the
|
||||
generated parser, in the same order as it appeared in the grammar.</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 <tt>%include</tt> directive is very handy for getting some extra #include
|
||||
<p>The %include directive is very handy for getting some extra #include
|
||||
preprocessor statements at the beginning of the generated parser.
|
||||
For example:</p>
|
||||
|
||||
@@ -748,19 +742,17 @@ For example:</p>
|
||||
</pre></p>
|
||||
|
||||
<p>This might be needed, for example, if some of the C actions in the
|
||||
grammar call functions that are prototyped in unistd.h.</p>
|
||||
grammar call functions that are prototyed in unistd.h.</p>
|
||||
|
||||
<a name='pleft'></a>
|
||||
<h4>The <tt>%left</tt> directive</h4>
|
||||
|
||||
The <tt>%left</tt> directive is used (along with the
|
||||
<tt><a href='#pright'>%right</a></tt> and
|
||||
<tt><a href='#pnonassoc'>%nonassoc</a></tt> directives) to declare
|
||||
precedences of terminal symbols.
|
||||
Every terminal symbol whose name appears after
|
||||
a <tt>%left</tt> 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
|
||||
<tt>%left</tt> directives have higher precedence. For example:</p>
|
||||
%left directives have higher precedence. For example:</p>
|
||||
|
||||
<p><pre>
|
||||
%left AND.
|
||||
@@ -771,21 +763,20 @@ given the same left-associative precedence value. Subsequent
|
||||
%right EXP NOT.
|
||||
</pre></p>
|
||||
|
||||
<p>Note the period that terminates each <tt>%left</tt>,
|
||||
<tt>%right</tt> or <tt>%nonassoc</tt>
|
||||
<p>Note the period that terminates each %left, %right or %nonassoc
|
||||
directive.</p>
|
||||
|
||||
<p>LALR(1) grammars can get into a situation where they require
|
||||
a large amount of stack space if you make heavy use or right-associative
|
||||
operators. For this reason, it is recommended that you use <tt>%left</tt>
|
||||
rather than <tt>%right</tt> whenever possible.</p>
|
||||
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
|
||||
different using the <tt>%name</tt> directive. For instance:</p>
|
||||
different using the %name directive. For instance:</p>
|
||||
|
||||
<p><pre>
|
||||
%name Abcde
|
||||
@@ -799,22 +790,22 @@ functions named
|
||||
<li> AbcdeTrace(), and
|
||||
<li> Abcde().
|
||||
</ul>
|
||||
The <tt>%name</tt> directive allows you to generate two or more different
|
||||
parsers and link them all into the same executable.</p>
|
||||
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
|
||||
one or more terminal symbols. See the section on
|
||||
<a href='#precrules'>precedence rules</a>
|
||||
or on the <tt><a href='#pleft'>%left</a></tt> directive
|
||||
for additional information.</p>
|
||||
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 <tt>%parse_accept</tt> directive specifies a block of C code that is
|
||||
<p>The %parse_accept directive specifies a block of C code that is
|
||||
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>
|
||||
@@ -830,7 +821,7 @@ without error.</p>
|
||||
<a name='parse_failure'></a>
|
||||
<h4>The <tt>%parse_failure</tt> directive</h4>
|
||||
|
||||
<p>The <tt>%parse_failure</tt> directive specifies a block of C code that
|
||||
<p>The %parse_failure directive specifies a block of C code that
|
||||
is executed whenever the parser fails complete. This code is not
|
||||
executed until the parser has tried and failed to resolve an input
|
||||
error using is usual error recovery strategy. The routine is
|
||||
@@ -846,14 +837,14 @@ only invoked when parsing is unable to continue.</p>
|
||||
<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
|
||||
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 <tt>%stack_overflow</tt> directive specifies a block of C code that
|
||||
<p>The %stack_overflow directive specifies a block of C code that
|
||||
is executed if the parser's internal stack ever overflows. Typically
|
||||
this just prints an error message. After a stack overflow, the parser
|
||||
will be unable to continue and must be reset.</p>
|
||||
@@ -866,7 +857,7 @@ will be unable to continue and must be reset.</p>
|
||||
|
||||
<p>You can help prevent parser stack overflows by avoiding the use
|
||||
of right recursion and right-precedence operators in your grammar.
|
||||
Use left recursion and and left-precedence operators instead to
|
||||
Use left recursion and and left-precedence operators instead, to
|
||||
encourage rules to reduce sooner and keep the stack size down.
|
||||
For example, do rules like this:
|
||||
<pre>
|
||||
@@ -877,7 +868,7 @@ Not like this:
|
||||
<pre>
|
||||
list ::= element list. // right-recursion. Bad!
|
||||
list ::= .
|
||||
</pre></p>
|
||||
</pre>
|
||||
|
||||
<a name='stack_size'></a>
|
||||
<h4>The <tt>%stack_size</tt> directive</h4>
|
||||
@@ -885,7 +876,7 @@ Not like this:
|
||||
<p>If stack overflow is a problem and you can't resolve the trouble
|
||||
by using left-recursion, then you might want to increase the size
|
||||
of the parser's stack using this directive. Put an positive integer
|
||||
after the <tt>%stack_size</tt> directive and Lemon will generate a parse
|
||||
after the %stack_size directive and Lemon will generate a parse
|
||||
with a stack of the requested size. The default value is 100.</p>
|
||||
|
||||
<p><pre>
|
||||
@@ -895,40 +886,25 @@ with a stack of the requested size. The default value is 100.</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
|
||||
<p>By default, the start-symbol for the grammar that Lemon generates
|
||||
is the first non-terminal that appears in the grammar file. But you
|
||||
can choose a different start symbol using the
|
||||
<tt>%start_symbol</tt> directive.</p>
|
||||
can choose a different start-symbol using the %start_symbol directive.</p>
|
||||
|
||||
<p><pre>
|
||||
%start_symbol prog
|
||||
</pre></p>
|
||||
|
||||
<a name='syntax_error'></a>
|
||||
<h4>The <tt>%syntax_error</tt> directive</h4>
|
||||
|
||||
<p>See <a href='#error_processing'>Error Processing</a>.</p>
|
||||
|
||||
<a name='token_class'></a>
|
||||
<h4>The <tt>%token_class</tt> directive</h4>
|
||||
|
||||
<p>Undocumented. Appears to be related to the MULTITERMINAL concept.
|
||||
<a href='http://sqlite.org/src/fdiff?v1=796930d5fc2036c7&v2=624b24c5dc048e09&sbs=0'>Implementation</a>.</p>
|
||||
|
||||
<a name='token_destructor'></a>
|
||||
<h4>The <tt>%token_destructor</tt> directive</h4>
|
||||
|
||||
<p>The <tt>%destructor</tt> directive assigns a destructor to a non-terminal
|
||||
symbol. (See the description of the
|
||||
<tt><a href='%destructor'>%destructor</a></tt> directive above.)
|
||||
The <tt>%token_destructor</tt> directive does the same thing
|
||||
for all terminal symbols.</p>
|
||||
<p>The %destructor directive assigns a destructor to a non-terminal
|
||||
symbol. (See the description of the %destructor directive above.)
|
||||
This directive does the same thing for all terminal symbols.</p>
|
||||
|
||||
<p>Unlike non-terminal symbols which may each have a different data type
|
||||
for their values, terminals all use the same data type (defined by
|
||||
the <tt><a href='#token_type'>%token_type</a></tt> directive)
|
||||
and so they use a common destructor.
|
||||
Other than that, the token destructor works just like the non-terminal
|
||||
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>
|
||||
@@ -937,9 +913,8 @@ destructors.</p>
|
||||
<p>Lemon generates #defines that assign small integer constants
|
||||
to each terminal symbol in the grammar. If desired, Lemon will
|
||||
add a prefix specified by this directive
|
||||
to each of the #defines it generates.</p>
|
||||
|
||||
<p>So if the default output of Lemon looked like this:
|
||||
to each of the #defines it generates.
|
||||
So if the default output of Lemon looked like this:
|
||||
<pre>
|
||||
#define AND 1
|
||||
#define MINUS 2
|
||||
@@ -956,7 +931,7 @@ to cause Lemon to produce these symbols instead:
|
||||
#define TOKEN_MINUS 2
|
||||
#define TOKEN_OR 3
|
||||
#define TOKEN_PLUS 4
|
||||
</pre></p>
|
||||
</pre>
|
||||
|
||||
<a name='token_type'></a><a name='ptype'></a>
|
||||
<h4>The <tt>%token_type</tt> and <tt>%type</tt> directives</h4>
|
||||
@@ -977,7 +952,7 @@ token structure. Like this:</p>
|
||||
is "void*".</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
|
||||
the data type of a non-terminal is a pointer to the root of a parse-tree
|
||||
structure that contains all information about that non-terminal.
|
||||
For example:</p>
|
||||
|
||||
@@ -998,15 +973,14 @@ 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 <tt>%wildcard</tt> directive is followed by a single token name and a
|
||||
period. This directive specifies that the identified token should
|
||||
match any input token.</p>
|
||||
<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 alternatives.</p>
|
||||
The wildcard token is only matched if there are no other alternatives.
|
||||
|
||||
<a name='error_processing'></a>
|
||||
<h3>Error Processing</h3>
|
||||
|
||||
<p>After extensive experimentation over several years, it has been
|
||||
@@ -1014,20 +988,19 @@ discovered that the error recovery strategy used by yacc is about
|
||||
as good as it gets. And so that is what Lemon uses.</p>
|
||||
|
||||
<p>When a Lemon-generated parser encounters a syntax error, it
|
||||
first invokes the code specified by the <tt>%syntax_error</tt> directive, if
|
||||
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
|
||||
parsing. The <tt>%syntax_error</tt> routine will not be called again
|
||||
parsing. But the %syntax_error routine will not be called again
|
||||
until at least three new tokens have been successfully shifted.</p>
|
||||
|
||||
<p>If the parser pops its stack until the stack is empty, and it still
|
||||
is unable to shift the error symbol, then the
|
||||
<tt><a href='#parse_failure'>%parse_failure</a></tt> routine
|
||||
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
|
||||
first syntax error, of course, if there are no instances of the
|
||||
"error" non-terminal in your grammar.</p>
|
||||
|
||||
</body>
|
||||
|
||||
+7
-7
@@ -102,15 +102,15 @@ static int icuLikeCompare(
|
||||
const uint8_t *zString, /* The UTF-8 string to compare against */
|
||||
const UChar32 uEsc /* The escape character */
|
||||
){
|
||||
static const uint32_t MATCH_ONE = (uint32_t)'_';
|
||||
static const uint32_t MATCH_ALL = (uint32_t)'%';
|
||||
static const int MATCH_ONE = (UChar32)'_';
|
||||
static const int MATCH_ALL = (UChar32)'%';
|
||||
|
||||
int prevEscape = 0; /* True if the previous character was uEsc */
|
||||
|
||||
while( 1 ){
|
||||
|
||||
/* Read (and consume) the next character from the input pattern. */
|
||||
uint32_t uPattern;
|
||||
UChar32 uPattern;
|
||||
SQLITE_ICU_READ_UTF8(zPattern, uPattern);
|
||||
if( uPattern==0 ) break;
|
||||
|
||||
@@ -152,16 +152,16 @@ static int icuLikeCompare(
|
||||
if( *zString==0 ) return 0;
|
||||
SQLITE_ICU_SKIP_UTF8(zString);
|
||||
|
||||
}else if( !prevEscape && uPattern==(uint32_t)uEsc){
|
||||
}else if( !prevEscape && uPattern==uEsc){
|
||||
/* Case 3. */
|
||||
prevEscape = 1;
|
||||
|
||||
}else{
|
||||
/* Case 4. */
|
||||
uint32_t uString;
|
||||
UChar32 uString;
|
||||
SQLITE_ICU_READ_UTF8(zString, uString);
|
||||
uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
|
||||
uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
|
||||
uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT);
|
||||
uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT);
|
||||
if( uString!=uPattern ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
** 2017-09-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.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
|
||||
/*
|
||||
** This function is used to touch each page of a mapping of a memory
|
||||
** mapped SQLite database. Assuming that the system has sufficient free
|
||||
** memory and supports sufficiently large mappings, this causes the OS
|
||||
** to cache the entire database in main memory, making subsequent
|
||||
** database accesses faster.
|
||||
**
|
||||
** If the second parameter to this function is not NULL, it is the name of
|
||||
** the specific database to operate on (i.e. "main" or the name of an
|
||||
** attached database).
|
||||
**
|
||||
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
||||
** It is not considered an error if the file is not memory-mapped, or if
|
||||
** the mapping does not span the entire file. If an error does occur, a
|
||||
** transaction may be left open on the database file.
|
||||
**
|
||||
** It is illegal to call this function when the database handle has an
|
||||
** open transaction. SQLITE_MISUSE is returned in this case.
|
||||
*/
|
||||
int sqlite3_mmap_warm(sqlite3 *db, const char *zDb){
|
||||
int rc = SQLITE_OK;
|
||||
char *zSql = 0;
|
||||
int pgsz = 0;
|
||||
int nTotal = 0;
|
||||
|
||||
if( 0==sqlite3_get_autocommit(db) ) return SQLITE_MISUSE;
|
||||
|
||||
/* Open a read-only transaction on the file in question */
|
||||
zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_master",
|
||||
(zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
|
||||
);
|
||||
if( zSql==0 ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_exec(db, zSql, 0, 0, 0);
|
||||
sqlite3_free(zSql);
|
||||
|
||||
/* Find the SQLite page size of the file */
|
||||
if( rc==SQLITE_OK ){
|
||||
zSql = sqlite3_mprintf("PRAGMA %s%q%spage_size",
|
||||
(zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
|
||||
);
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
sqlite3_stmt *pPgsz = 0;
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pPgsz, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( sqlite3_step(pPgsz)==SQLITE_ROW ){
|
||||
pgsz = sqlite3_column_int(pPgsz, 0);
|
||||
}
|
||||
rc = sqlite3_finalize(pPgsz);
|
||||
}
|
||||
if( rc==SQLITE_OK && pgsz==0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch each mmap'd page of the file */
|
||||
if( rc==SQLITE_OK ){
|
||||
int rc2;
|
||||
sqlite3_file *pFd = 0;
|
||||
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFd);
|
||||
if( rc==SQLITE_OK && pFd->pMethods->iVersion>=3 ){
|
||||
sqlite3_int64 iPg = 1;
|
||||
sqlite3_io_methods const *p = pFd->pMethods;
|
||||
while( 1 ){
|
||||
unsigned char *pMap;
|
||||
rc = p->xFetch(pFd, pgsz*iPg, pgsz, (void**)&pMap);
|
||||
if( rc!=SQLITE_OK || pMap==0 ) break;
|
||||
|
||||
nTotal += pMap[0];
|
||||
nTotal += pMap[pgsz-1];
|
||||
|
||||
rc = p->xUnfetch(pFd, pgsz*iPg, (void*)pMap);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
iPg++;
|
||||
}
|
||||
sqlite3_log(SQLITE_OK,
|
||||
"sqlite3_mmap_warm_cache: Warmed up %d pages of %s", iPg==1?0:iPg,
|
||||
sqlite3_db_filename(db, zDb)
|
||||
);
|
||||
}
|
||||
|
||||
rc2 = sqlite3_exec(db, "END", 0, 0, 0);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
+1
-1
@@ -2853,7 +2853,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
|
||||
int rc; /* Return code */
|
||||
RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */
|
||||
int iCell; /* Index of iDelete cell in pLeaf */
|
||||
RtreeNode *pRoot = 0; /* Root node of rtree structure */
|
||||
RtreeNode *pRoot; /* Root node of rtree structure */
|
||||
|
||||
|
||||
/* Obtain a reference to the root node to initialize Rtree.iDepth */
|
||||
|
||||
@@ -334,7 +334,6 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/fuzzer.c \
|
||||
$(TOP)/ext/misc/ieee754.c \
|
||||
$(TOP)/ext/misc/mmapwarm.c \
|
||||
$(TOP)/ext/misc/nextchar.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
C More\sdetails\sin\sthe\sheader\scomment\sof\spushDownWhereTerms().\s\sNo\schanges\sto\ncode.
|
||||
D 2017-09-30T11:47:06.786
|
||||
F Makefile.in 4bc36d913c2e3e2d326d588d72f618ac9788b2fd4b7efda61102611a6495c3ff
|
||||
C Merge\slatest\strunk\schanges\swith\sthis\sbranch.
|
||||
D 2017-09-18T08:51:04.787
|
||||
F Makefile.in c644bbe8ebe4aae82ad6783eae6b6beea4c727b99ff97568b847ced5e2ac7afb
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 6033b51b6aea702ea059f6ab2d47b1d3cef648695f787247dd4fb395fe60673f
|
||||
F Makefile.msc 6a7a74bf60ad395098c0bd175ab054cd65ef85d7f034198d52bcc4d9e5fb4c6b
|
||||
F README.md f5c87359573c4d255425e588a56554b50fdcc2afba4e017a2e02a43701456afd
|
||||
F VERSION f81232df28e2d3ff049feefad5fbd5489cc33697f6bd2ecf61af7f0dde3b83d0
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -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 e9dbb65b61c36bb9622225de254b768d4816749ff4cb4d71307bb067095aceec x
|
||||
F configure.ac 369ebae6c04d9d2de5064e21d300f2f42f2fbf13235cabff9d1a54f2b2c4d05d
|
||||
F configure e691ad9b505f1f47bc5d99be9e1d49b1be9037e9cb3821c9b14c63c3d413d055 x
|
||||
F configure.ac bb85c1c53e952c8c7078a2f147eba613e0128b8b6e7780d64758d8fb29bcc695
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 278113807f49d12d04179a93fab92b5b917a08771152ca7949d34e928efa3941
|
||||
F doc/lemon.html 1f8b8d4c9f5cfe40e679fee279cc9eb2da8e6eb74ad406028538d7864cc4b6cb
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
|
||||
@@ -209,7 +209,7 @@ F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
|
||||
F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
|
||||
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
||||
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c 635775226d07c743c770888a9dd5175afc6e67d3e28a4032b7fedc3bcaa92e65
|
||||
F ext/icu/icu.c 84900472a088a3a172c6c079f58a1d3a1952c332
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/lsm1/Makefile 2951812df1c1cbc9e023af7e070876f479b3d75ce3898b3b9d00f83fecf13608
|
||||
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
|
||||
@@ -270,7 +270,6 @@ F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
|
||||
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
|
||||
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
|
||||
F ext/misc/regexp.c a68d25c659bd2d893cd1215667bbf75ecb9dc7d4
|
||||
@@ -326,7 +325,7 @@ F ext/rbu/sqlite3rbu.c a1a303de8b90f987ef63bf9cef57f5d7dd7983a9e8aed3775a759d87a
|
||||
F ext/rbu/sqlite3rbu.h b42bcd4d8357268c6c39ab2a60b29c091e89328fa8cc49c8fac5ab8d007e79b2
|
||||
F ext/rbu/test_rbu.c 7073979b9cc80912bb03599ac8d85ab5d3bf03cfacd3463f2dcdd7822997533a
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c f2fd34db37ea053798f8e66b44a473449b21301d2b92505ee576823789e909fb
|
||||
F ext/rtree/rtree.c cf84d52958a7ec6a506f1711e119db847ed6bb5dedde78a58e97503287afcda1
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 4fdd60ae034e43f2fefc26492032d02e742e8b14d468b7c51d95a1e2fa47cf00
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@@ -382,7 +381,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk d0145f02deb67d65c4822225847cba112c237cdb62f4905eeb4b648e82bfc222
|
||||
F main.mk da75a0527a56da0b7f568a976b3cb69756613080f16e4d208b6c6a0495bfb132
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -401,7 +400,7 @@ F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 221bc1b836f0c386676999a7c62c8dc60455e255fab37df97eca2aa619b92f2a
|
||||
F src/btree.c 1c2b2f1714c411d7a9bc52c90d9dd7eab261261d5691ac0f67e1ced92419799c
|
||||
F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09
|
||||
F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc
|
||||
F src/build.c e71e96a67daf3d1dd23188423e66cd6af38017e2ec73fead5d2b57da2d3c7e16
|
||||
@@ -411,10 +410,10 @@ F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
||||
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
||||
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
||||
F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
|
||||
F src/expr.c 4d2d0aafd945424f638ee03e11330f03288ccf616e025498f3c8602d01609a0a
|
||||
F src/expr.c 38a225057f5b7d6a2bc403d7a5d3a67f59ee57b73fe7c546221e3c53202a3731
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333
|
||||
F src/func.c b4d259af627e3cd9510cf08db37f0bcc88b1887c735169c74490c3739d5cf5c6
|
||||
F src/func.c 8c46246dcb5779e77bf2ef192fa1355460aeec1d3d0b2537608d319bcd7d8778
|
||||
F src/global.c ac3094f1dc59fbeb919aef7cc0cc827a8459d1fb1adb7972ef75bd9e0c10b75b
|
||||
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
@@ -423,7 +422,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c d2d1bf12d2b5382450620d7cede84c7ffe57e6a89fa9a908f1aba68df2731cd9
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
|
||||
F src/main.c 1c2307a9f7e3183232a2d049881026fe43bf25659857cc11a9a44898accd3200
|
||||
F src/main.c cd03aeca7a9d5f221010d0212b3abdd558e37a317947f8e78dd9162a5d904223
|
||||
F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -442,34 +441,34 @@ F src/os.c 93e0979b9b55df29c0c4923f73b48e9d3fe728f01dd8ed4f6a9d2f1d79779bc8
|
||||
F src/os.h 8e976e59eb4ca1c0fca6d35ee803e38951cb0343
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c 3984fc069df59e26f000e30609611cecdb4e93293e6ee52313a473a7e874af1b
|
||||
F src/os_win.c 6892c3ff23b7886577e47f13d827ca220c0831bae3ce00eea8c258352692f8c6
|
||||
F src/os_unix.c dffae52f34dbdc5f270616254b490c61d8e104a7a8fb5ceaa865db25f139ba3c
|
||||
F src/os_win.c 225432ab6512f63ab2f37eb76872f818b01f0483ba0bea04a7a1168be3070ea5
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 2aa56a99bb13128d9102e84c7a9f835e546cbb58f0861d481bc3db32973b1628
|
||||
F src/pager.c 2a523bf8ec77678b35fe56b43ac24045d2f97ad44d58c6a0894c131feda3eeff
|
||||
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
|
||||
F src/parse.y 52ef3cecd0934e9da4a45b585883a03243ad615d338ad94f44501a05891dcdfa
|
||||
F src/pcache.c 4bada070456980c3c1f16d58ec2e64e389ad77b935e3d77e0c96e7bbd397289c
|
||||
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||
F src/pragma.c d04725ac25387d9638919e197fb009f378e13af7bf899516979e54b3164e3602
|
||||
F src/pragma.c 88d99aa4752894aaf4102eefd09b5e497f4277661aff69f8fff61f8611f19d14
|
||||
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/prepare.c 9a141a1b02dca53beaa9771699d390aafcac01f5d1f1c0ae6e23ded8dcdb709a
|
||||
F src/printf.c 40aee47ae9be4bd3dbdc8968bd07fddc027be8edec8daddf24d3391d36698a1c
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/random.c f27af4099afaea7284ade5c206224dcfdb2334cfd119d018b470d46356b3f27d
|
||||
F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 19ebf10e33de8e1f327cbc844aff12af74bdf0513b3eb1b712b7bcdca4c9bdb5
|
||||
F src/select.c 420d3f5d9e24f0d81c28a0d4e5f7d7abf07beae6c25ce8981e51638e9e9ee2ae
|
||||
F src/shell.c c1206a23d9239f8f51751d3be9b8c3b02fa4103546bea1add7f864d84a8276ab
|
||||
F src/shell.c.in bb9720a8c5c98d3984b16ab7540e7142bcae959666ecf248bfc523a1d44220ee
|
||||
F src/sqlite.h.in ab4f8a29d1580dfaeb6891fa1b83cff8229ba0daa56994707ceaca71495d9ab7
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h a1fd3aa82f967da436164e0728a7d6841651fd0c6e27b9044e0eb9f6c8462e47
|
||||
F src/sqliteInt.h 99e4beebd466495434ca6ed94bd7966a7f8c5879cd1f01768c588a5a2acd84c2
|
||||
F src/sqliteInt.h cfcfc4238dd5d148bc1802d1588a35e16d7e57abb956779b1c3ffb69b90723ed
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 487951d81f9704800fd9f0ffdaa2f935a83ccb6be3575c2c4ef83e4789b4c828
|
||||
F src/test1.c 8ef15f7a357f85dfc41c6c748ce9c947b4f676e01bb5ae6a45bee4923dff8b51
|
||||
F src/test1.c 8513b17ca4a7a9ba28748535d178b6e472ec7394ae0eea53907f2d3bcdbab2df
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
@@ -524,26 +523,26 @@ F src/treeview.c 2ee4a5dada213d5ab08a742af5c876cee6f1aaae65f10a61923f3fb63846afe
|
||||
F src/trigger.c 48e0f7ed6749ce4d50a695e09e20ce9cf84ecabf2691852c965a51e0b620eccc
|
||||
F src/update.c 5404be9e840717323a69209190cdbc9d0d34adaedaaf1d1a1069babf2c4171c0
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c 5168013cfd937a695d23cce8c67cb07a3dda242d4cb812530ba1148b88e0f159
|
||||
F src/util.c ece10cb34b4a62cbb3aab8d711b67e93a2765e0b81d0f72458cb801a3ac60703
|
||||
F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
|
||||
F src/vdbe.c 176c0897af0aedecd3abc9afaf7fa80eaa7cf5eaf62583de256a9961df474373
|
||||
F src/vdbe.c 0a0ef7f0759ee4c3ed5ff0c6e9641216d4b31ebb0fea9a7b5a9c4a86ce875ff3
|
||||
F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
|
||||
F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9
|
||||
F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1
|
||||
F src/vdbeaux.c 831a77aaa7aa43005f1c9bf3e9eb6506f4865e1cf99943ccdcd3be5d2dd8a3c7
|
||||
F src/vdbeaux.c 3be977a032e54fe46cb1b1f3ba62158438b0cc93e091f6feca7742d20dad3203
|
||||
F src/vdbeblob.c 635a79b60340a6a14a622ea8dcb081f0a66b1ac3836870c587f232eec08c0286
|
||||
F src/vdbemem.c 5c1533bf756918b4e46b2ed2bb82c29c7c651e1e37bbd0a0d8731a68787598ff
|
||||
F src/vdbemem.c 2f9d672af5260f0145787e1dc2c6985414987cc0dc575133a0dc17dda767d868
|
||||
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
|
||||
F src/vdbetrace.c 48e11ebe040c6b41d146abed2602e3d00d621d7ebe4eb29b0a0f1617fd3c2f6c
|
||||
F src/vtab.c f1d5c23132fb0247af3e86146404112283ddedb6c518de0d4edc91cfb36970ef
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 839db09792fead5052bb35e533fa485e134913d547d05b5f42e537b73e63f07a
|
||||
F src/wal.c 2a205ec9c9be4e4b2933d32481c4654b4c6b644d8a6c755a5f8c7a10ade64616
|
||||
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||
F src/walker.c 3ccfa8637f95355bff61144e01a615b8ef26f79c312880848da73f03367da1e6
|
||||
F src/where.c 049522adcf5426f1a8c3ed07be15e1ffa3266afd34e8e7bee64b63e2fbfad0b5
|
||||
F src/where.c 21eea981920a13fd3c0ac3d6c128d0a34b22cbec064e4f0603375fe1ffe26ca6
|
||||
F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
|
||||
F src/wherecode.c e8c2ece5843ea56e6c90277d421f2d628f3f7b7c976642369cc519f008e1d2b1
|
||||
F src/whereexpr.c afcac9cccfc0fdaccbdda94034a398947b6dc47dbf821c1b496261722832a6a4
|
||||
F src/whereexpr.c 4953ca4e769c047d0a00a1ba9085849626b1f3a6e89f6befcf5c38fa0722acdd
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||
@@ -732,7 +731,7 @@ F test/e_createtable.test d4c6059d44dcd4b636de9aae322766062b471844
|
||||
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
|
||||
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
|
||||
F test/e_dropview.test 21ce09c361227ddbc9819a5608ee2700c276bdd5
|
||||
F test/e_expr.test ca8896601ade1e27c6559614c7f32c63d44636fdfa720436a160f09b8bf66c89
|
||||
F test/e_expr.test 146deba180273d19e3bf9f6b45f4e50094c64c7ec4756ea72f79dda25818eb17
|
||||
F test/e_fkey.test dcdc6ad26b1d4f07636208de4c1c22aae7c0597a685a6c10fe6da91f3191dd96
|
||||
F test/e_fts3.test 8cf40550bb088a6aa187c818c00fabe26ef82900a4cd5c66b427ccafe28bedaa
|
||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||
@@ -911,7 +910,7 @@ F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/having.test e4098a4b8962f9596035c3b87a8928a10648acc509f1bb8d6f96413bbf79a1b3
|
||||
F test/having.test b3d6b17cc9601b6b373b2d0f08c075ccf30e2d307249c3c8a236e3c36907b1a5
|
||||
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
|
||||
@@ -946,7 +945,7 @@ F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
|
||||
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
|
||||
F test/indexedby.test 9c4cd331224e57f79fbf411ae245e6272d415985
|
||||
F test/indexexpr1.test 84100e880154a4b645db9f4fc7642756d9a2b6011b68f73c8efda4d244816de9
|
||||
F test/indexexpr2.test 13247bac49143196556eb3f65e97ef301bd3e993f4511558b5db322ddc370ea6
|
||||
F test/indexexpr2.test fdccd5c13a57af59a8e392660953dbcaacc4699c433516372cfba52994aa503a
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
|
||||
@@ -987,7 +986,7 @@ F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
|
||||
F test/kvtest.c fcb38ffe3db028a3138b4818fc098359c80dc51a0d1278a91c99c554cc1abb92
|
||||
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test 11cfd7d4ef8625389df9efc46735ff0b0b41d5e62047ef0f3bc24c380d28a7a6
|
||||
F test/like.test 67d7431c9b664254febce9e90fd2f47c7c75c8b38444e2a50ef9ec2776b84ca8
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/like3.test 3608a2042b6f922f900fbfd5d3ce4e7eca57f7c4
|
||||
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
|
||||
@@ -1101,7 +1100,7 @@ F test/permutations.test d911c9ba49088d22054a05dc73743f677872a92ac89288bcdeafa0e
|
||||
F test/pragma.test c31b5e98998c160a4c85b1e04f590655c67f2daa7f73854640cd120610e3ac15
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
F test/pragma4.test 3046501bee2f652dc2a4f9c87781e2741361d6864439c8381aba6c3b774b335c
|
||||
F test/pragma4.test 6e85b6eab8e61ffc9c7db59d842276674e8e3264
|
||||
F test/pragma5.test fd517f42ee847e126afbbbd9fd0fb9e5a4a61a962496a350adb8a22583fbdc37
|
||||
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
|
||||
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
|
||||
@@ -1158,7 +1157,7 @@ F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e
|
||||
F test/schema6.test 5b21bbdd405bc93b3e6af5e6ece64d230e35f65cc4035e5c2b89fc8a090d7270
|
||||
F test/securedel.test 5f997cb6bd38727b81e0985f53ec386c99db6441b2b9e6357240649d29017239
|
||||
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test 460a5824df01575b18f7fa4bd8e40d09de20c542e90c1543e164bc7d3b0a0bb7
|
||||
F test/select1.test be62204d2bd9a5a8a149e9974cfddce893d8f686
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test 5389d9895968d1196c457d59b3ee6515d771d328
|
||||
@@ -1205,7 +1204,7 @@ F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
|
||||
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
|
||||
F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b
|
||||
F test/snapshot.test 85735bd997a4f6d710140c28fd860519a299649f
|
||||
F test/snapshot2.test 925e42427e923262db63c9d7155183f889e3e99feaedec4075f659e51608344f
|
||||
F test/snapshot2.test 867652ed4a13282dce218723535fad1c7b44c3c4
|
||||
F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
|
||||
@@ -1593,7 +1592,7 @@ F tool/mkopcodeh.tcl 4ee2a30ccbd900dc4d5cdb61bdab87cd2166cd2affcc78c9cc0b8d22a65
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd
|
||||
F tool/mkshellc.tcl 950c36f45941c12140e346a907fb66198bc2770ff7a17c749201e78d34bb3b0b
|
||||
F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
|
||||
F tool/mksourceid.c 30966d568654a4fd962fb324753e49429b7379e1f72d2be489ade963121f5943
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
||||
F tool/mksqlite3c.tcl b258d679829a9305f5cf107b7d97b9bf23adb3773df42947fed5ef7b180dfbd9
|
||||
@@ -1655,7 +1654,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 6aed4ea34c4163c682ad5bb2956fdf4f3a3ad048fefd3edab0fef6761c3783cc
|
||||
R f601c290e8e6d8b405b953711d4d99d6
|
||||
U drh
|
||||
Z 5fa1972988b6fbd3340440a07005926a
|
||||
P 8b1fc4b9f3e743bffcfbbb8e26991240441778e10512fb502b8eaec460184296 42f07775556758754e92e29a759d200d0d81d16eee83ab982b840db11292f834
|
||||
R 4a30c0e0d01ae979fbda091d7fb31409
|
||||
U dan
|
||||
Z 11c76cfa54aab138b4cbd06a81c15433
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
928486231ff7cc0df17a5aa23a080a1b8720e168db5227a7dbd34861283ba689
|
||||
2e57335081287a2db9fd20d86a8e98218309a37569e1ca1df8deb5fb198d73ff
|
||||
@@ -1399,9 +1399,6 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
int sz2 = 0;
|
||||
int sz = get2byte(&data[iFree+2]);
|
||||
int top = get2byte(&data[hdr+5]);
|
||||
if( top>=iFree ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
}
|
||||
if( iFree2 ){
|
||||
assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
|
||||
sz2 = get2byte(&data[iFree2+2]);
|
||||
|
||||
+10
-40
@@ -124,11 +124,6 @@ Expr *sqlite3ExprSkipCollate(Expr *pExpr){
|
||||
** Return the collation sequence for the expression pExpr. If
|
||||
** there is no defined collating sequence, return NULL.
|
||||
**
|
||||
** See also: sqlite3ExprNNCollSeq()
|
||||
**
|
||||
** The sqlite3ExprNNCollSeq() works the same exact that it returns the
|
||||
** default collation if pExpr has no defined collation.
|
||||
**
|
||||
** The collating sequence might be determined by a COLLATE operator
|
||||
** or by the presence of a column with a defined collating sequence.
|
||||
** COLLATE operators take first precedence. Left operands take
|
||||
@@ -193,32 +188,6 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
return pColl;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the collation sequence for the expression pExpr. If
|
||||
** there is no defined collating sequence, return a pointer to the
|
||||
** defautl collation sequence.
|
||||
**
|
||||
** See also: sqlite3ExprCollSeq()
|
||||
**
|
||||
** The sqlite3ExprCollSeq() routine works the same except that it
|
||||
** returns NULL if there is no defined collation.
|
||||
*/
|
||||
CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){
|
||||
CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
if( p==0 ) p = pParse->db->pDfltColl;
|
||||
assert( p!=0 );
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the two expressions have equivalent collating sequences.
|
||||
*/
|
||||
int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
|
||||
CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
|
||||
CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
|
||||
return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** pExpr is an operand of a comparison operator. aff2 is the
|
||||
** type affinity of the other operand. This routine returns the
|
||||
@@ -1712,11 +1681,12 @@ void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
||||
u32 sqlite3ExprListFlags(const ExprList *pList){
|
||||
int i;
|
||||
u32 m = 0;
|
||||
assert( pList!=0 );
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pExpr = pList->a[i].pExpr;
|
||||
assert( pExpr!=0 );
|
||||
m |= pExpr->flags;
|
||||
if( pList ){
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pExpr = pList->a[i].pExpr;
|
||||
assert( pExpr!=0 );
|
||||
m |= pExpr->flags;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
@@ -1873,8 +1843,8 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
|
||||
for(i=0; i<pGroupBy->nExpr; i++){
|
||||
Expr *p = pGroupBy->a[i].pExpr;
|
||||
if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){
|
||||
CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p);
|
||||
if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p);
|
||||
if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){
|
||||
return WRC_Prune;
|
||||
}
|
||||
}
|
||||
@@ -3106,7 +3076,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
||||
const char *z = pExpr->u.zToken;
|
||||
assert( z!=0 );
|
||||
c = sqlite3DecOrHexToI64(z, &value);
|
||||
if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){
|
||||
if( c==1 || (c==2 && !negFlag) || (negFlag && value==SMALLEST_INT64)){
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
|
||||
#else
|
||||
@@ -3120,7 +3090,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
||||
}
|
||||
#endif
|
||||
}else{
|
||||
if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; }
|
||||
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
|
||||
sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -481,8 +481,9 @@ static void randomFunc(
|
||||
sqlite3_value **NotUsed2
|
||||
){
|
||||
sqlite_int64 r;
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
sqlite3FastRandomness(&db->sPrng, sizeof(r), &r);
|
||||
if( r<0 ){
|
||||
/* We need to prevent a random number of 0x8000000000000000
|
||||
** (or -9223372036854775808) since when you do abs() of that
|
||||
@@ -508,6 +509,7 @@ static void randomBlob(
|
||||
){
|
||||
int n;
|
||||
unsigned char *p;
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
n = sqlite3_value_int(argv[0]);
|
||||
@@ -516,7 +518,7 @@ static void randomBlob(
|
||||
}
|
||||
p = contextMalloc(context, n);
|
||||
if( p ){
|
||||
sqlite3_randomness(n, p);
|
||||
sqlite3FastRandomness(&db->sPrng, n, p);
|
||||
sqlite3_result_blob(context, (char*)p, n, sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -2865,6 +2865,7 @@ static int openDatabase(
|
||||
db->nDb = 2;
|
||||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
db->aDb = db->aDbStatic;
|
||||
sqlite3FastPrngInit(&db->sPrng);
|
||||
|
||||
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
|
||||
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
|
||||
@@ -3942,7 +3943,7 @@ sqlite3_int64 sqlite3_uri_int64(
|
||||
){
|
||||
const char *z = sqlite3_uri_parameter(zFilename, zParam);
|
||||
sqlite3_int64 v;
|
||||
if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
|
||||
if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
|
||||
bDflt = v;
|
||||
}
|
||||
return bDflt;
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
#include "sqliteInt.h"
|
||||
#if SQLITE_OS_UNIX /* This file is used on unix only */
|
||||
|
||||
/* #define SQLITE_SHARED_MAPPING 1 */
|
||||
|
||||
/*
|
||||
** There are various methods for file locking used for concurrency
|
||||
** control:
|
||||
@@ -1115,6 +1117,10 @@ struct unixInodeInfo {
|
||||
sem_t *pSem; /* Named POSIX semaphore */
|
||||
char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
|
||||
#endif
|
||||
#ifdef SQLITE_SHARED_MAPPING
|
||||
sqlite3_int64 nSharedMapping; /* Size of mapped region in bytes */
|
||||
void *pSharedMapping; /* Memory mapped region */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1249,6 +1255,13 @@ static void releaseInodeInfo(unixFile *pFile){
|
||||
pInode->nRef--;
|
||||
if( pInode->nRef==0 ){
|
||||
assert( pInode->pShmNode==0 );
|
||||
#ifdef SQLITE_SHARED_MAPPING
|
||||
if( pInode->pSharedMapping ){
|
||||
osMunmap(pInode->pSharedMapping, pInode->nSharedMapping);
|
||||
pInode->pSharedMapping = 0;
|
||||
pInode->nSharedMapping = 0;
|
||||
}
|
||||
#endif
|
||||
closePendingFds(pFile);
|
||||
if( pInode->pPrev ){
|
||||
assert( pInode->pPrev->pNext==pInode );
|
||||
@@ -2055,6 +2068,14 @@ static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){
|
||||
** Close the file.
|
||||
*/
|
||||
static int nolockClose(sqlite3_file *id) {
|
||||
#ifdef SQLITE_SHARED_MAPPING
|
||||
unixFile *pFd = (unixFile*)id;
|
||||
if( pFd->pInode ){
|
||||
unixEnterMutex();
|
||||
releaseInodeInfo(pFd);
|
||||
unixLeaveMutex();
|
||||
}
|
||||
#endif
|
||||
return closeUnixFile(id);
|
||||
}
|
||||
|
||||
@@ -3874,6 +3895,9 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
*(i64*)pArg = pFile->mmapSizeMax;
|
||||
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
|
||||
pFile->mmapSizeMax = newLimit;
|
||||
#ifdef SQLITE_SHARED_MAPPING
|
||||
if( pFile->pInode==0 )
|
||||
#endif
|
||||
if( pFile->mmapSize>0 ){
|
||||
unixUnmapfile(pFile);
|
||||
rc = unixMapfile(pFile, -1);
|
||||
@@ -4774,6 +4798,9 @@ static int unixShmUnmap(
|
||||
*/
|
||||
static void unixUnmapfile(unixFile *pFd){
|
||||
assert( pFd->nFetchOut==0 );
|
||||
#ifdef SQLITE_SHARED_MAPPING
|
||||
if( pFd->pInode ) return;
|
||||
#endif
|
||||
if( pFd->pMapRegion ){
|
||||
osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
|
||||
pFd->pMapRegion = 0;
|
||||
@@ -4905,6 +4932,28 @@ static int unixMapfile(unixFile *pFd, i64 nMap){
|
||||
nMap = pFd->mmapSizeMax;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_SHARED_MAPPING
|
||||
if( pFd->pInode ){
|
||||
unixInodeInfo *pInode = pFd->pInode;
|
||||
if( pFd->pMapRegion ) return SQLITE_OK;
|
||||
unixEnterMutex();
|
||||
if( pInode->pSharedMapping==0 ){
|
||||
u8 *pNew = osMmap(0, nMap, PROT_READ, MAP_SHARED, pFd->h, 0);
|
||||
if( pNew==MAP_FAILED ){
|
||||
unixLogError(SQLITE_OK, "mmap", pFd->zPath);
|
||||
pFd->mmapSizeMax = 0;
|
||||
}else{
|
||||
pInode->pSharedMapping = pNew;
|
||||
pInode->nSharedMapping = nMap;
|
||||
}
|
||||
}
|
||||
pFd->pMapRegion = pInode->pSharedMapping;
|
||||
pFd->mmapSizeActual = pFd->mmapSize = pInode->nSharedMapping;
|
||||
unixLeaveMutex();
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) );
|
||||
if( nMap!=pFd->mmapSize ){
|
||||
unixRemapfile(pFd, nMap);
|
||||
@@ -5342,6 +5391,9 @@ static int fillInUnixFile(
|
||||
if( pLockingStyle == &posixIoMethods
|
||||
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
|
||||
|| pLockingStyle == &nfsIoMethods
|
||||
#endif
|
||||
#ifdef SQLITE_SHARED_MAPPING
|
||||
|| pLockingStyle == &nolockIoMethods
|
||||
#endif
|
||||
){
|
||||
unixEnterMutex();
|
||||
|
||||
+28
-51
@@ -4879,14 +4879,6 @@ static int winIsDir(const void *zConverted){
|
||||
return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
/* forward reference */
|
||||
static int winAccess(
|
||||
sqlite3_vfs *pVfs, /* Not used on win32 */
|
||||
const char *zFilename, /* Name of file to check */
|
||||
int flags, /* Type of test to make on this file */
|
||||
int *pResOut /* OUT: Result */
|
||||
);
|
||||
|
||||
/*
|
||||
** Open a file.
|
||||
*/
|
||||
@@ -5063,52 +5055,37 @@ static int winOpen(
|
||||
extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
|
||||
extendedParameters.lpSecurityAttributes = NULL;
|
||||
extendedParameters.hTemplateFile = NULL;
|
||||
do{
|
||||
h = osCreateFile2((LPCWSTR)zConverted,
|
||||
dwDesiredAccess,
|
||||
dwShareMode,
|
||||
dwCreationDisposition,
|
||||
&extendedParameters);
|
||||
if( h!=INVALID_HANDLE_VALUE ) break;
|
||||
if( isReadWrite ){
|
||||
int isRO = 0;
|
||||
int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
|
||||
if( rc2==SQLITE_OK && isRO ) break;
|
||||
}
|
||||
}while( winRetryIoerr(&cnt, &lastErrno) );
|
||||
while( (h = osCreateFile2((LPCWSTR)zConverted,
|
||||
dwDesiredAccess,
|
||||
dwShareMode,
|
||||
dwCreationDisposition,
|
||||
&extendedParameters))==INVALID_HANDLE_VALUE &&
|
||||
winRetryIoerr(&cnt, &lastErrno) ){
|
||||
/* Noop */
|
||||
}
|
||||
#else
|
||||
do{
|
||||
h = osCreateFileW((LPCWSTR)zConverted,
|
||||
dwDesiredAccess,
|
||||
dwShareMode, NULL,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
NULL);
|
||||
if( h!=INVALID_HANDLE_VALUE ) break;
|
||||
if( isReadWrite ){
|
||||
int isRO = 0;
|
||||
int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
|
||||
if( rc2==SQLITE_OK && isRO ) break;
|
||||
}
|
||||
}while( winRetryIoerr(&cnt, &lastErrno) );
|
||||
while( (h = osCreateFileW((LPCWSTR)zConverted,
|
||||
dwDesiredAccess,
|
||||
dwShareMode, NULL,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
NULL))==INVALID_HANDLE_VALUE &&
|
||||
winRetryIoerr(&cnt, &lastErrno) ){
|
||||
/* Noop */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef SQLITE_WIN32_HAS_ANSI
|
||||
else{
|
||||
do{
|
||||
h = osCreateFileA((LPCSTR)zConverted,
|
||||
dwDesiredAccess,
|
||||
dwShareMode, NULL,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
NULL);
|
||||
if( h!=INVALID_HANDLE_VALUE ) break;
|
||||
if( isReadWrite ){
|
||||
int isRO = 0;
|
||||
int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
|
||||
if( rc2==SQLITE_OK && isRO ) break;
|
||||
}
|
||||
}while( winRetryIoerr(&cnt, &lastErrno) );
|
||||
while( (h = osCreateFileA((LPCSTR)zConverted,
|
||||
dwDesiredAccess,
|
||||
dwShareMode, NULL,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
NULL))==INVALID_HANDLE_VALUE &&
|
||||
winRetryIoerr(&cnt, &lastErrno) ){
|
||||
/* Noop */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
winLogIoerr(cnt, __LINE__);
|
||||
@@ -5117,6 +5094,8 @@ static int winOpen(
|
||||
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
|
||||
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
pFile->lastErrno = lastErrno;
|
||||
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
|
||||
sqlite3_free(zConverted);
|
||||
sqlite3_free(zTmpname);
|
||||
if( isReadWrite && !isExclusive ){
|
||||
@@ -5125,8 +5104,6 @@ static int winOpen(
|
||||
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
|
||||
pOutFlags);
|
||||
}else{
|
||||
pFile->lastErrno = lastErrno;
|
||||
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
|
||||
return SQLITE_CANTOPEN_BKPT;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-8
@@ -2807,7 +2807,6 @@ static int pager_playback(Pager *pPager, int isHot){
|
||||
char *zMaster = 0; /* Name of master journal file if any */
|
||||
int needPagerReset; /* True to reset page prior to first page rollback */
|
||||
int nPlayback = 0; /* Total number of pages restored from journal */
|
||||
u32 savedPageSize = pPager->pageSize;
|
||||
|
||||
/* Figure out how many records are in the journal. Abort early if
|
||||
** the journal is empty.
|
||||
@@ -2845,12 +2844,13 @@ static int pager_playback(Pager *pPager, int isHot){
|
||||
** pager_playback_one_page() call returns SQLITE_DONE or an IO error
|
||||
** occurs.
|
||||
*/
|
||||
while( 1 ){
|
||||
do{
|
||||
/* Read the next journal header from the journal file. If there are
|
||||
** not enough bytes left in the journal file for a complete header, or
|
||||
** it is corrupted, then a process must have failed while writing it.
|
||||
** This indicates nothing more needs to be rolled back.
|
||||
*/
|
||||
u32 savedPageSize = pPager->pageSize;
|
||||
rc = readJournalHdr(pPager, isHot, szJ, &nRec, &mxPg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_DONE ){
|
||||
@@ -2932,14 +2932,10 @@ static int pager_playback(Pager *pPager, int isHot){
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
assert( 0 );
|
||||
rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1);
|
||||
}while( rc==SQLITE_OK );
|
||||
|
||||
end_playback:
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1);
|
||||
}
|
||||
/* Following a rollback, the database file should be back in its original
|
||||
** state prior to the start of the transaction, so invoke the
|
||||
** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
|
||||
|
||||
+3
-3
@@ -1515,12 +1515,12 @@ void sqlite3Pragma(
|
||||
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
|
||||
if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
aRoot[++cnt] = pIdx->tnum;
|
||||
aRoot[cnt++] = pIdx->tnum;
|
||||
}
|
||||
}
|
||||
aRoot[0] = cnt;
|
||||
aRoot[cnt] = 0;
|
||||
|
||||
/* Make sure sufficient number of registers have been allocated */
|
||||
pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
|
||||
|
||||
@@ -106,6 +106,28 @@ void sqlite3_randomness(int N, void *pBuf){
|
||||
sqlite3_mutex_leave(mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a fast PRNG. A Fast PRNG is called "fast" because it does
|
||||
** not need a mutex to operate, though it does use a mutex to initialize.
|
||||
** The quality of the randomness is not as good as the global PRNG.
|
||||
*/
|
||||
void sqlite3FastPrngInit(FastPrng *pPrng){
|
||||
sqlite3_randomness(sizeof(*pPrng), pPrng);
|
||||
pPrng->x |= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate N bytes of pseudo-randomness using a FastPrng
|
||||
*/
|
||||
void sqlite3FastRandomness(FastPrng *pPrng, int N, void *P){
|
||||
unsigned char *pOut = (unsigned char*)P;
|
||||
while( N-->0 ){
|
||||
pPrng->x = ((pPrng->x)>>1) ^ ((1+~((pPrng->x)&1)) & 0xd0000001);
|
||||
pPrng->y = (pPrng->y)*1103515245 + 12345;
|
||||
*(pOut++) = (pPrng->x ^ pPrng->y) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_UNTESTABLE
|
||||
/*
|
||||
** For testing purposes, we sometimes want to preserve the state of
|
||||
|
||||
+153
-175
@@ -118,8 +118,7 @@ Select *sqlite3SelectNew(
|
||||
pNew = &standin;
|
||||
}
|
||||
if( pEList==0 ){
|
||||
pEList = sqlite3ExprListAppend(pParse, 0,
|
||||
sqlite3Expr(pParse->db,TK_ASTERISK,0));
|
||||
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0));
|
||||
}
|
||||
pNew->pEList = pEList;
|
||||
pNew->op = TK_SELECT;
|
||||
@@ -143,8 +142,7 @@ Select *sqlite3SelectNew(
|
||||
pNew->pLimit = pLimit;
|
||||
pNew->pOffset = pOffset;
|
||||
pNew->pWith = 0;
|
||||
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0
|
||||
|| pParse->db->mallocFailed!=0 );
|
||||
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || pParse->db->mallocFailed!=0 );
|
||||
if( pParse->db->mallocFailed ) {
|
||||
clearSelect(pParse->db, pNew, pNew!=&standin);
|
||||
pNew = 0;
|
||||
@@ -761,8 +759,7 @@ static void selectInnerLoop(
|
||||
assert( eDest==SRT_Set || eDest==SRT_Mem
|
||||
|| eDest==SRT_Coroutine || eDest==SRT_Output );
|
||||
}
|
||||
nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult,
|
||||
0,ecelFlags);
|
||||
nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult,0,ecelFlags);
|
||||
}
|
||||
|
||||
/* If the DISTINCT keyword was present on the SELECT statement
|
||||
@@ -1112,7 +1109,10 @@ static KeyInfo *keyInfoFromExprList(
|
||||
if( pInfo ){
|
||||
assert( sqlite3KeyInfoIsWriteable(pInfo) );
|
||||
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
|
||||
pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
|
||||
CollSeq *pColl;
|
||||
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
pInfo->aColl[i-iStart] = pColl;
|
||||
pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
|
||||
}
|
||||
}
|
||||
@@ -1573,9 +1573,9 @@ static void generateColumnTypes(
|
||||
** other words, the zSpan of the result expression.
|
||||
**
|
||||
** short=ON, full=OFF: (This is the default setting). If the result
|
||||
** refers directly to a table column, then the
|
||||
** result column name is just the table column
|
||||
** name: COLUMN. Otherwise use zSpan.
|
||||
** refers directly to a table column, then the result
|
||||
** column name is just the table column name: COLUMN.
|
||||
** Otherwise use zSpan.
|
||||
**
|
||||
** full=ON, short=ANY: If the result refers directly to a table column,
|
||||
** then the result column name with the table name
|
||||
@@ -1617,7 +1617,7 @@ static void generateColumnNames(
|
||||
|
||||
assert( p!=0 );
|
||||
assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */
|
||||
assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering idx not yet coded */
|
||||
assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering indexes not yet coded */
|
||||
if( pEList->a[i].zName ){
|
||||
/* An AS clause always takes first priority */
|
||||
char *zName = pEList->a[i].zName;
|
||||
@@ -1744,7 +1744,7 @@ int sqlite3ColumnsFromExprList(
|
||||
if( zName[j]==':' ) nName = j;
|
||||
}
|
||||
zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
|
||||
if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
|
||||
if( cnt>3 ) sqlite3FastRandomness(&db->sPrng, sizeof(cnt), &cnt);
|
||||
}
|
||||
pCol->zName = zName;
|
||||
sqlite3ColumnPropertiesFromName(0, pCol);
|
||||
@@ -2281,9 +2281,15 @@ static int multiSelect(
|
||||
db = pParse->db;
|
||||
pPrior = p->pPrior;
|
||||
dest = *pDest;
|
||||
if( pPrior->pOrderBy || pPrior->pLimit ){
|
||||
sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
|
||||
pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op));
|
||||
if( pPrior->pOrderBy ){
|
||||
sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
|
||||
selectOpName(p->op));
|
||||
rc = 1;
|
||||
goto multi_select_end;
|
||||
}
|
||||
if( pPrior->pLimit ){
|
||||
sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
|
||||
selectOpName(p->op));
|
||||
rc = 1;
|
||||
goto multi_select_end;
|
||||
}
|
||||
@@ -3181,9 +3187,7 @@ static Expr *substExpr(
|
||||
Expr *pExpr /* Expr in which substitution occurs */
|
||||
){
|
||||
if( pExpr==0 ) return 0;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin)
|
||||
&& pExpr->iRightJoinTable==pSubst->iTable
|
||||
){
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){
|
||||
pExpr->iRightJoinTable = pSubst->iNewTable;
|
||||
}
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
|
||||
@@ -3296,74 +3300,68 @@ static void substSelect(
|
||||
** exist on the table t1, a complete scan of the data might be
|
||||
** avoided.
|
||||
**
|
||||
** Flattening is subject to the following constraints:
|
||||
** Flattening is only attempted if all of the following are true:
|
||||
**
|
||||
** (**) We no longer attempt to flatten aggregate subqueries. Was:
|
||||
** The subquery and the outer query cannot both be aggregates.
|
||||
** (1) The subquery and the outer query do not both use aggregates.
|
||||
**
|
||||
** (**) We no longer attempt to flatten aggregate subqueries. Was:
|
||||
** (2) If the subquery is an aggregate then
|
||||
** (2a) the outer query must not be a join and
|
||||
** (2b) the outer query must not use subqueries
|
||||
** other than the one FROM-clause subquery that is a candidate
|
||||
** for flattening. (This is due to ticket [2f7170d73bf9abf80]
|
||||
** from 2015-02-09.)
|
||||
** (2) The subquery is not an aggregate or (2a) the outer query is not a join
|
||||
** and (2b) the outer query does not use subqueries other than the one
|
||||
** FROM-clause subquery that is a candidate for flattening. (2b is
|
||||
** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
|
||||
**
|
||||
** (3) If the subquery is the right operand of a LEFT JOIN then
|
||||
** (3a) the subquery may not be a join and
|
||||
** (3b) the FROM clause of the subquery may not contain a virtual
|
||||
** table and
|
||||
** (3c) the outer query may not be an aggregate.
|
||||
** (3) The subquery is not the right operand of a LEFT JOIN
|
||||
** or (a) the subquery is not itself a join and (b) the FROM clause
|
||||
** of the subquery does not contain a virtual table and (c) the
|
||||
** outer query is not an aggregate.
|
||||
**
|
||||
** (4) The subquery can not be DISTINCT.
|
||||
** (4) The subquery is not DISTINCT.
|
||||
**
|
||||
** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT
|
||||
** sub-queries that were excluded from this optimization. Restriction
|
||||
** (4) has since been expanded to exclude all DISTINCT subqueries.
|
||||
**
|
||||
** (**) We no longer attempt to flatten aggregate subqueries. Was:
|
||||
** If the subquery is aggregate, the outer query may not be DISTINCT.
|
||||
** (6) The subquery does not use aggregates or the outer query is not
|
||||
** DISTINCT.
|
||||
**
|
||||
** (7) The subquery must have a FROM clause. TODO: For subqueries without
|
||||
** (7) The subquery has a FROM clause. TODO: For subqueries without
|
||||
** A FROM clause, consider adding a FROM clause with the special
|
||||
** table sqlite_once that consists of a single row containing a
|
||||
** single NULL.
|
||||
**
|
||||
** (8) If the subquery uses LIMIT then the outer query may not be a join.
|
||||
** (8) The subquery does not use LIMIT or the outer query is not a join.
|
||||
**
|
||||
** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
|
||||
** (9) The subquery does not use LIMIT or the outer query does not use
|
||||
** aggregates.
|
||||
**
|
||||
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
|
||||
** accidently carried the comment forward until 2014-09-15. Original
|
||||
** constraint: "If the subquery is aggregate then the outer query
|
||||
** may not use LIMIT."
|
||||
** text: "The subquery does not use aggregates or the outer query
|
||||
** does not use LIMIT."
|
||||
**
|
||||
** (11) The subquery and the outer query may not both have ORDER BY clauses.
|
||||
** (11) The subquery and the outer query do not both have ORDER BY clauses.
|
||||
**
|
||||
** (**) Not implemented. Subsumed into restriction (3). Was previously
|
||||
** a separate restriction deriving from ticket #350.
|
||||
**
|
||||
** (13) The subquery and outer query may not both use LIMIT.
|
||||
** (13) The subquery and outer query do not both use LIMIT.
|
||||
**
|
||||
** (14) The subquery may not use OFFSET.
|
||||
** (14) The subquery does not use OFFSET.
|
||||
**
|
||||
** (15) If the outer query is part of a compound select, then the
|
||||
** subquery may not use LIMIT.
|
||||
** (15) The outer query is not part of a compound select or the
|
||||
** subquery does not have a LIMIT clause.
|
||||
** (See ticket #2339 and ticket [02a8e81d44]).
|
||||
**
|
||||
** (16) If the outer query is aggregate, then the subquery may not
|
||||
** use ORDER BY. (Ticket #2942) This used to not matter
|
||||
** (16) The outer query is not an aggregate or the subquery does
|
||||
** not contain ORDER BY. (Ticket #2942) This used to not matter
|
||||
** until we introduced the group_concat() function.
|
||||
**
|
||||
** (17) If the subquery is a compound select, then
|
||||
** (17a) all compound operators must be a UNION ALL, and
|
||||
** (17b) no terms within the subquery compound may be aggregate
|
||||
** or DISTINT, and
|
||||
** (17c) every term within the subquery compound must have a FROM clause
|
||||
** (17d) the outer query may not be
|
||||
** (17d1) aggregate, or
|
||||
** (17d2) DISTINCT, or
|
||||
** (17d3) a join.
|
||||
** (17) The sub-query is not a compound select, or it is a UNION ALL
|
||||
** compound clause made up entirely of non-aggregate queries, and
|
||||
** the parent query:
|
||||
**
|
||||
** * is not itself part of a compound select,
|
||||
** * is not an aggregate or DISTINCT query, and
|
||||
** * is not a join
|
||||
**
|
||||
** The parent and sub-query may contain WHERE clauses. Subject to
|
||||
** rules (11), (13) and (14), they may also contain ORDER BY,
|
||||
@@ -3379,10 +3377,10 @@ static void substSelect(
|
||||
** syntax error and return a detailed message.
|
||||
**
|
||||
** (18) If the sub-query is a compound select, then all terms of the
|
||||
** ORDER BY clause of the parent must be simple references to
|
||||
** ORDER by clause of the parent must be simple references to
|
||||
** columns of the sub-query.
|
||||
**
|
||||
** (19) If the subquery uses LIMIT then the outer query may not
|
||||
** (19) The subquery does not use LIMIT or the outer query does not
|
||||
** have a WHERE clause.
|
||||
**
|
||||
** (20) If the sub-query is a compound select, then it must not use
|
||||
@@ -3391,18 +3389,17 @@ static void substSelect(
|
||||
** appear as unmodified result columns in the outer query. But we
|
||||
** have other optimizations in mind to deal with that case.
|
||||
**
|
||||
** (21) If the subquery uses LIMIT then the outer query may not be
|
||||
** (21) The subquery does not use LIMIT or the outer query is not
|
||||
** DISTINCT. (See ticket [752e1646fc]).
|
||||
**
|
||||
** (22) The subquery may not be a recursive CTE.
|
||||
** (22) The subquery is not a recursive CTE.
|
||||
**
|
||||
** (23) If the outer query is a recursive CTE, then the sub-query may not be
|
||||
** a compound query. This restriction is because transforming the
|
||||
** (23) The parent is not a recursive CTE, or the sub-query is not a
|
||||
** compound query. This restriction is because transforming the
|
||||
** parent to a compound query confuses the code that handles
|
||||
** recursive queries in multiSelect().
|
||||
**
|
||||
** (**) We no longer attempt to flatten aggregate subqueries. Was:
|
||||
** The subquery may not be an aggregate that uses the built-in min() or
|
||||
** (24) The subquery is not an aggregate that uses the built-in min() or
|
||||
** or max() functions. (Without this restriction, a query like:
|
||||
** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
|
||||
** return the value X for which Y was maximal.)
|
||||
@@ -3410,7 +3407,7 @@ static void substSelect(
|
||||
**
|
||||
** In this routine, the "p" parameter is a pointer to the outer query.
|
||||
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
|
||||
** uses aggregates.
|
||||
** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
|
||||
**
|
||||
** If flattening is not attempted, this routine is a no-op and returns 0.
|
||||
** If flattening is attempted this routine returns 1.
|
||||
@@ -3422,7 +3419,8 @@ static int flattenSubquery(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Select *p, /* The parent or outer SELECT statement */
|
||||
int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
|
||||
int isAgg /* True if outer SELECT uses aggregate functions */
|
||||
int isAgg, /* True if outer SELECT uses aggregate functions */
|
||||
int subqueryIsAgg /* True if the subquery uses aggregate functions */
|
||||
){
|
||||
const char *zSavedAuthContext = pParse->zAuthContext;
|
||||
Select *pParent; /* Current UNION ALL term of the other query */
|
||||
@@ -3441,7 +3439,7 @@ static int flattenSubquery(
|
||||
/* Check to see if flattening is permitted. Return 0 if not.
|
||||
*/
|
||||
assert( p!=0 );
|
||||
assert( p->pPrior==0 );
|
||||
assert( p->pPrior==0 ); /* Unable to flatten compound queries */
|
||||
if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
|
||||
pSrc = p->pSrc;
|
||||
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
|
||||
@@ -3449,6 +3447,16 @@ static int flattenSubquery(
|
||||
iParent = pSubitem->iCursor;
|
||||
pSub = pSubitem->pSelect;
|
||||
assert( pSub!=0 );
|
||||
if( subqueryIsAgg ){
|
||||
if( isAgg ) return 0; /* Restriction (1) */
|
||||
if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */
|
||||
if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
|
||||
|| (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
|
||||
|| (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
|
||||
){
|
||||
return 0; /* Restriction (2b) */
|
||||
}
|
||||
}
|
||||
|
||||
pSubSrc = pSub->pSrc;
|
||||
assert( pSubSrc );
|
||||
@@ -3463,10 +3471,13 @@ static int flattenSubquery(
|
||||
return 0; /* Restriction (15) */
|
||||
}
|
||||
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
|
||||
if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (4) */
|
||||
if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */
|
||||
if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){
|
||||
return 0; /* Restrictions (8)(9) */
|
||||
}
|
||||
if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){
|
||||
return 0; /* Restriction (6) */
|
||||
}
|
||||
if( p->pOrderBy && pSub->pOrderBy ){
|
||||
return 0; /* Restriction (11) */
|
||||
}
|
||||
@@ -3475,8 +3486,10 @@ static int flattenSubquery(
|
||||
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
|
||||
return 0; /* Restriction (21) */
|
||||
}
|
||||
if( pSub->selFlags & (SF_Recursive) ){
|
||||
return 0; /* Restrictions (22) */
|
||||
testcase( pSub->selFlags & SF_Recursive );
|
||||
testcase( pSub->selFlags & SF_MinMaxAgg );
|
||||
if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
|
||||
return 0; /* Restrictions (22) and (24) */
|
||||
}
|
||||
if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
|
||||
return 0; /* Restriction (23) */
|
||||
@@ -3484,8 +3497,7 @@ static int flattenSubquery(
|
||||
|
||||
/*
|
||||
** If the subquery is the right operand of a LEFT JOIN, then the
|
||||
** subquery may not be a join itself (3a). Example of why this is not
|
||||
** allowed:
|
||||
** subquery may not be a join itself. Example of why this is not allowed:
|
||||
**
|
||||
** t1 LEFT OUTER JOIN (t2 JOIN t3)
|
||||
**
|
||||
@@ -3496,56 +3508,54 @@ static int flattenSubquery(
|
||||
** which is not at all the same thing.
|
||||
**
|
||||
** If the subquery is the right operand of a LEFT JOIN, then the outer
|
||||
** query cannot be an aggregate. (3c) This is an artifact of the way
|
||||
** aggregates are processed - there is no mechanism to determine if
|
||||
** the LEFT JOIN table should be all-NULL.
|
||||
** query cannot be an aggregate. This is an artifact of the way aggregates
|
||||
** are processed - there is no mechanism to determine if the LEFT JOIN
|
||||
** table should be all-NULL.
|
||||
**
|
||||
** See also tickets #306, #350, and #3300.
|
||||
*/
|
||||
if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
|
||||
isLeftJoin = 1;
|
||||
if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
|
||||
/* (3a) (3c) (3b) */
|
||||
return 0;
|
||||
return 0; /* Restriction (3) */
|
||||
}
|
||||
}
|
||||
#ifdef SQLITE_EXTRA_IFNULLROW
|
||||
else if( iFrom>0 && !isAgg ){
|
||||
/* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for
|
||||
** every reference to any result column from subquery in a join, even
|
||||
** though they are not necessary. This will stress-test the OP_IfNullRow
|
||||
** opcode. */
|
||||
** every reference to any result column from subquery in a join, even though
|
||||
** they are not necessary. This will stress-test the OP_IfNullRow opcode. */
|
||||
isLeftJoin = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Restriction (17): If the sub-query is a compound SELECT, then it must
|
||||
/* Restriction 17: If the sub-query is a compound SELECT, then it must
|
||||
** use only the UNION ALL operator. And none of the simple select queries
|
||||
** that make up the compound SELECT are allowed to be aggregate or distinct
|
||||
** queries.
|
||||
*/
|
||||
if( pSub->pPrior ){
|
||||
if( pSub->pOrderBy ){
|
||||
return 0; /* Restriction (20) */
|
||||
return 0; /* Restriction 20 */
|
||||
}
|
||||
if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
|
||||
return 0; /* (17d1), (17d2), or (17d3) */
|
||||
return 0;
|
||||
}
|
||||
for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
|
||||
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
|
||||
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
|
||||
assert( pSub->pSrc!=0 );
|
||||
assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
|
||||
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */
|
||||
|| (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */
|
||||
|| pSub1->pSrc->nSrc<1 /* (17c) */
|
||||
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
|
||||
|| (pSub1->pPrior && pSub1->op!=TK_ALL)
|
||||
|| pSub1->pSrc->nSrc<1
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
testcase( pSub1->pSrc->nSrc>1 );
|
||||
}
|
||||
|
||||
/* Restriction (18). */
|
||||
/* Restriction 18. */
|
||||
if( p->pOrderBy ){
|
||||
int ii;
|
||||
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
|
||||
@@ -3766,7 +3776,18 @@ static int flattenSubquery(
|
||||
if( isLeftJoin>0 ){
|
||||
setJoinExpr(pWhere, iNewParent);
|
||||
}
|
||||
pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
|
||||
if( subqueryIsAgg ){
|
||||
assert( pParent->pHaving==0 );
|
||||
pParent->pHaving = pParent->pWhere;
|
||||
pParent->pWhere = pWhere;
|
||||
pParent->pHaving = sqlite3ExprAnd(db,
|
||||
sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving
|
||||
);
|
||||
assert( pParent->pGroupBy==0 );
|
||||
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
|
||||
}else{
|
||||
pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
|
||||
}
|
||||
if( db->mallocFailed==0 ){
|
||||
SubstContext x;
|
||||
x.pParse = pParse;
|
||||
@@ -3829,13 +3850,9 @@ static int flattenSubquery(
|
||||
**
|
||||
** Do not attempt this optimization if:
|
||||
**
|
||||
** (1) (** This restriction was removed on 2017-09-29. We used to
|
||||
** disallow this optimization for aggregate subqueries, but now
|
||||
** it is allowed by putting the extra terms on the HAVING clause.
|
||||
** The added HAVING clause is pointless if the subquery lacks
|
||||
** a GROUP BY clause. But such a HAVING clause is also harmless
|
||||
** so there does not appear to be any reason to add extra logic
|
||||
** to suppress it. **)
|
||||
** (1) The inner query is an aggregate. (In that case, we'd really want
|
||||
** to copy the outer WHERE-clause terms onto the HAVING clause of the
|
||||
** inner query. But they probably won't help there so do not bother.)
|
||||
**
|
||||
** (2) The inner query is the recursive part of a common table expression.
|
||||
**
|
||||
@@ -3860,22 +3877,16 @@ static int pushDownWhereTerms(
|
||||
){
|
||||
Expr *pNew;
|
||||
int nChng = 0;
|
||||
Select *pX; /* For looping over compound SELECTs in pSubq */
|
||||
if( pWhere==0 ) return 0;
|
||||
if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Only the first term of a compound can have a WITH clause. But make
|
||||
** sure no other terms are marked SF_Recursive in case something changes
|
||||
** in the future.
|
||||
*/
|
||||
{
|
||||
Select *pX;
|
||||
for(pX=pSubq; pX; pX=pX->pPrior){
|
||||
assert( (pX->selFlags & (SF_Recursive))==0 );
|
||||
for(pX=pSubq; pX; pX=pX->pPrior){
|
||||
if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
|
||||
testcase( pX->selFlags & SF_Aggregate );
|
||||
testcase( pX->selFlags & SF_Recursive );
|
||||
testcase( pX!=pSubq );
|
||||
return 0; /* restrictions (1) and (2) */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( pSubq->pLimit!=0 ){
|
||||
return 0; /* restriction (3) */
|
||||
}
|
||||
@@ -3883,7 +3894,7 @@ static int pushDownWhereTerms(
|
||||
nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor);
|
||||
pWhere = pWhere->pLeft;
|
||||
}
|
||||
if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction (5) */
|
||||
if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
|
||||
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
||||
nChng++;
|
||||
while( pSubq ){
|
||||
@@ -3895,11 +3906,7 @@ static int pushDownWhereTerms(
|
||||
x.isLeftJoin = 0;
|
||||
x.pEList = pSubq->pEList;
|
||||
pNew = substExpr(&x, pNew);
|
||||
if( pSubq->selFlags & SF_Aggregate ){
|
||||
pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew);
|
||||
}else{
|
||||
pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
|
||||
}
|
||||
pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
|
||||
pSubq = pSubq->pPrior;
|
||||
}
|
||||
}
|
||||
@@ -4227,8 +4234,7 @@ static int withExpand(
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
assert( pTab->nTabRef==1 ||
|
||||
((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
|
||||
assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
|
||||
|
||||
pCte->zCteErr = "circular reference: %s";
|
||||
pSavedWith = pParse->pWith;
|
||||
@@ -4372,11 +4378,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( pTab==0 ) return WRC_Abort;
|
||||
pTab->nTabRef = 1;
|
||||
if( pFrom->zAlias ){
|
||||
pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias);
|
||||
}else{
|
||||
pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab);
|
||||
}
|
||||
pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
|
||||
while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
||||
sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
|
||||
pTab->iPKey = -1;
|
||||
@@ -5036,24 +5038,24 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
Expr *pExpr;
|
||||
Expr *pCount;
|
||||
sqlite3 *db;
|
||||
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
|
||||
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate query */
|
||||
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
|
||||
pExpr = p->pEList->a[0].pExpr;
|
||||
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
|
||||
if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */
|
||||
if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Must be count() */
|
||||
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
|
||||
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
|
||||
if( p->pSrc->nSrc!=1 ) return 0; /* One table in the FROM clause */
|
||||
pSub = p->pSrc->a[0].pSelect;
|
||||
if( pSub==0 ) return 0; /* The FROM is a subquery */
|
||||
if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */
|
||||
if( pSub->pPrior==0 ) return 0; /* Must be a compound subquery */
|
||||
do{
|
||||
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
|
||||
if( pSub->pWhere ) return 0; /* No WHERE clause */
|
||||
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
|
||||
pSub = pSub->pPrior; /* Repeat over compound */
|
||||
pSub = pSub->pPrior; /* Repeat over compound terms */
|
||||
}while( pSub );
|
||||
|
||||
/* If we reach this point then it is OK to perform the transformation */
|
||||
/* If we reach this point, that means it is OK to perform the transformation */
|
||||
|
||||
db = pParse->db;
|
||||
pCount = pExpr;
|
||||
@@ -5193,6 +5195,7 @@ int sqlite3Select(
|
||||
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
Select *pSub = pItem->pSelect;
|
||||
int isAggSub;
|
||||
Table *pTab = pItem->pTab;
|
||||
if( pSub==0 ) continue;
|
||||
|
||||
@@ -5204,36 +5207,13 @@ int sqlite3Select(
|
||||
goto select_end;
|
||||
}
|
||||
|
||||
/* Do not try to flatten an aggregate subquery.
|
||||
**
|
||||
** Flattening an aggregate subquery is only possible if the outer query
|
||||
** is not a join. But if the outer query is not a join, then the subquery
|
||||
** will be implemented as a co-routine and there is no advantage to
|
||||
** flattening in that case.
|
||||
*/
|
||||
if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
|
||||
assert( pSub->pGroupBy==0 );
|
||||
|
||||
/* If the subquery contains an ORDER BY clause and if
|
||||
** it will be implemented as a co-routine, then do not flatten. This
|
||||
** restriction allows SQL constructs like this:
|
||||
**
|
||||
** SELECT expensive_function(x)
|
||||
** FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
|
||||
**
|
||||
** The expensive_function() is only computed on the 10 rows that
|
||||
** are output, rather than every row of the table.
|
||||
*/
|
||||
if( pSub->pOrderBy!=0
|
||||
&& i==0
|
||||
&& (pTabList->nSrc==1
|
||||
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
|
||||
if( flattenSubquery(pParse, p, i, isAgg) ){
|
||||
isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
|
||||
if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
|
||||
/* This subquery can be absorbed into its parent. */
|
||||
if( isAggSub ){
|
||||
isAgg = 1;
|
||||
p->selFlags |= SF_Aggregate;
|
||||
}
|
||||
i = -1;
|
||||
}
|
||||
pTabList = p->pSrc;
|
||||
@@ -5267,14 +5247,10 @@ int sqlite3Select(
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
SelectDest dest;
|
||||
Select *pSub;
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
const char *zSavedAuthContext;
|
||||
#endif
|
||||
|
||||
/* Issue SQLITE_READ authorizations with a fake column name for any
|
||||
** tables that are referenced but from which no values are extracted.
|
||||
** Examples of where these kinds of null SQLITE_READ authorizations
|
||||
** would occur:
|
||||
/* Issue SQLITE_READ authorizations with a fake column name for any tables that
|
||||
** are referenced but from which no values are extracted. Examples of where these
|
||||
** kinds of null SQLITE_READ authorizations would occur:
|
||||
**
|
||||
** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
|
||||
** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2.""
|
||||
@@ -5282,10 +5258,10 @@ int sqlite3Select(
|
||||
** The fake column name is an empty string. It is possible for a table to
|
||||
** have a column named by the empty string, in which case there is no way to
|
||||
** distinguish between an unreferenced table and an actual reference to the
|
||||
** "" column. The original design was for the fake column name to be a NULL,
|
||||
** "" column. The original design was for the fake column name to be a NULL,
|
||||
** which would be unambiguous. But legacy authorization callbacks might
|
||||
** assume the column name is non-NULL and segfault. The use of an empty
|
||||
** string for the fake column name seems safer.
|
||||
** assume the column name is non-NULL and segfault. The use of an empty string
|
||||
** for the fake column name seems safer.
|
||||
*/
|
||||
if( pItem->colUsed==0 ){
|
||||
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
|
||||
@@ -5337,14 +5313,16 @@ int sqlite3Select(
|
||||
#endif
|
||||
}
|
||||
|
||||
zSavedAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = pItem->zName;
|
||||
|
||||
/* Generate code to implement the subquery
|
||||
**
|
||||
** The subquery is implemented as a co-routine if the subquery is
|
||||
** guaranteed to be the outer loop (so that it does not need to be
|
||||
** computed more than once)
|
||||
** 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?
|
||||
@@ -5352,12 +5330,13 @@ int sqlite3Select(
|
||||
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.
|
||||
*/
|
||||
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
|
||||
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
|
||||
VdbeComment((v, "%s", pItem->pTab->zName));
|
||||
@@ -5415,7 +5394,6 @@ int sqlite3Select(
|
||||
}
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
||||
pParse->zAuthContext = zSavedAuthContext;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+21
-10
@@ -1065,6 +1065,7 @@ typedef struct NameContext NameContext;
|
||||
typedef struct Parse Parse;
|
||||
typedef struct PreUpdate PreUpdate;
|
||||
typedef struct PrintfArguments PrintfArguments;
|
||||
typedef struct FastPrng FastPrng;
|
||||
typedef struct RowSet RowSet;
|
||||
typedef struct Savepoint Savepoint;
|
||||
typedef struct Select Select;
|
||||
@@ -1137,6 +1138,14 @@ typedef int VList;
|
||||
# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
|
||||
#endif
|
||||
|
||||
/*
|
||||
** State of a simple PRNG used for the per-connection and per-pager
|
||||
** pseudo-random number generators.
|
||||
*/
|
||||
struct FastPrng {
|
||||
unsigned int x, y;
|
||||
};
|
||||
|
||||
/*
|
||||
** Each database file to be accessed by the system is an instance
|
||||
** of the following structure. There are normally two of these structures
|
||||
@@ -1343,6 +1352,7 @@ struct sqlite3 {
|
||||
u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
|
||||
int nextPagesize; /* Pagesize after VACUUM if >0 */
|
||||
u32 magic; /* Magic number for detect library misuse */
|
||||
FastPrng sPrng; /* State of the per-connection PRNG */
|
||||
int nChange; /* Value returned by sqlite3_changes() */
|
||||
int nTotalChange; /* Value returned by sqlite3_total_changes() */
|
||||
int aLimit[SQLITE_N_LIMIT]; /* Limits */
|
||||
@@ -1506,15 +1516,16 @@ struct sqlite3 {
|
||||
#define SQLITE_ColumnCache 0x0002 /* Column cache */
|
||||
#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
|
||||
#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
|
||||
#define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */
|
||||
#define SQLITE_CoverIdxScan 0x0020 /* Covering index scans */
|
||||
#define SQLITE_OrderByIdxJoin 0x0040 /* ORDER BY of joins via index */
|
||||
#define SQLITE_Transitive 0x0080 /* Transitive constraints */
|
||||
#define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */
|
||||
#define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */
|
||||
#define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */
|
||||
/* not used 0x0010 // Was: SQLITE_IdxRealAsInt */
|
||||
#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
|
||||
#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
|
||||
#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
|
||||
#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
|
||||
#define SQLITE_Transitive 0x0200 /* Transitive constraints */
|
||||
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
|
||||
#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
|
||||
/* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */
|
||||
#define SQLITE_CountOfView 0x1000 /* The count-of-view optimization */
|
||||
#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */
|
||||
#define SQLITE_AllOpts 0xffff /* All optimizations */
|
||||
|
||||
/*
|
||||
@@ -3811,6 +3822,8 @@ Vdbe *sqlite3GetVdbe(Parse*);
|
||||
void sqlite3PrngSaveState(void);
|
||||
void sqlite3PrngRestoreState(void);
|
||||
#endif
|
||||
void sqlite3FastPrngInit(FastPrng*);
|
||||
void sqlite3FastRandomness(FastPrng*, int N, void *P);
|
||||
void sqlite3RollbackAll(sqlite3*,int);
|
||||
void sqlite3CodeVerifySchema(Parse*, int);
|
||||
void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
|
||||
@@ -4003,8 +4016,6 @@ int sqlite3ReadSchema(Parse *pParse);
|
||||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);
|
||||
int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
|
||||
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
|
||||
Expr *sqlite3ExprSkipCollate(Expr*);
|
||||
|
||||
+3
-32
@@ -6901,6 +6901,7 @@ static int SQLITE_TCLAPI optimization_control(
|
||||
{ "cover-idx-scan", SQLITE_CoverIdxScan },
|
||||
{ "order-by-idx-join", SQLITE_OrderByIdxJoin },
|
||||
{ "transitive", SQLITE_Transitive },
|
||||
{ "subquery-coroutine", SQLITE_SubqCoroutine },
|
||||
{ "omit-noop-join", SQLITE_OmitNoopJoin },
|
||||
{ "stat3", SQLITE_Stat34 },
|
||||
{ "stat4", SQLITE_Stat34 },
|
||||
@@ -7414,35 +7415,6 @@ static int SQLITE_TCLAPI test_dbconfig_maindbname_icecube(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_mmap_warm DB DBNAME
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_mmap_warm(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
|
||||
extern int sqlite3_mmap_warm(sqlite3 *db, const char *);
|
||||
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB ?DBNAME?");
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
int rc;
|
||||
sqlite3 *db;
|
||||
const char *zDb = 0;
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
if( objc==3 ){
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
}
|
||||
rc = sqlite3_mmap_warm(db, zDb);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
@@ -7712,9 +7684,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
|
||||
{ "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
|
||||
#endif
|
||||
{ "sqlite3_delete_database", test_delete_database, 0 },
|
||||
{ "atomic_batch_write", test_atomic_batch_write, 0 },
|
||||
{ "sqlite3_mmap_warm", test_mmap_warm, 0 },
|
||||
{ "sqlite3_delete_database", test_delete_database, 0 },
|
||||
{ "atomic_batch_write", test_atomic_batch_write, 0 },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
|
||||
|
||||
+18
-20
@@ -557,12 +557,16 @@ static int compare2pow63(const char *zNum, int incr){
|
||||
** Convert zNum to a 64-bit signed integer. zNum must be decimal. This
|
||||
** routine does *not* accept hexadecimal notation.
|
||||
**
|
||||
** Returns:
|
||||
** If the zNum value is representable as a 64-bit twos-complement
|
||||
** integer, then write that value into *pNum and return 0.
|
||||
**
|
||||
** 0 Successful transformation. Fits in a 64-bit signed integer.
|
||||
** 1 Excess text after the integer value
|
||||
** 2 Integer too large for a 64-bit signed integer or is malformed
|
||||
** 3 Special case of 9223372036854775808
|
||||
** If zNum is exactly 9223372036854775808, return 2. This special
|
||||
** case is broken out because while 9223372036854775808 cannot be a
|
||||
** signed 64-bit integer, its negative -9223372036854775808 can be.
|
||||
**
|
||||
** If zNum is too big for a 64-bit integer and is not
|
||||
** 9223372036854775808 or if zNum contains any non-numeric text,
|
||||
** then return 1.
|
||||
**
|
||||
** length is the number of bytes in the string (bytes, not characters).
|
||||
** The string is not necessarily zero-terminated. The encoding is
|
||||
@@ -575,7 +579,6 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
int i;
|
||||
int c = 0;
|
||||
int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
|
||||
int rc; /* Baseline return code */
|
||||
const char *zStart;
|
||||
const char *zEnd = zNum + length;
|
||||
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
||||
@@ -615,35 +618,31 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
testcase( i==20 );
|
||||
if( &zNum[i]<zEnd /* Extra bytes at the end */
|
||||
|| (i==0 && zStart==zNum) /* No digits */
|
||||
|| i>19*incr /* Too many digits */
|
||||
|| nonNum /* UTF16 with high-order bytes non-zero */
|
||||
){
|
||||
rc = 1;
|
||||
}else{
|
||||
rc = 0;
|
||||
}
|
||||
if( i>19*incr ){ /* Too many digits */
|
||||
/* zNum is empty or contains non-numeric text or is longer
|
||||
** than 19 digits (thus guaranteeing that it is too large) */
|
||||
return 2;
|
||||
return 1;
|
||||
}else if( i<19*incr ){
|
||||
/* Less than 19 digits, so we know that it fits in 64 bits */
|
||||
assert( u<=LARGEST_INT64 );
|
||||
return rc;
|
||||
return 0;
|
||||
}else{
|
||||
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
|
||||
c = compare2pow63(zNum, incr);
|
||||
if( c<0 ){
|
||||
/* zNum is less than 9223372036854775808 so it fits */
|
||||
assert( u<=LARGEST_INT64 );
|
||||
return rc;
|
||||
return 0;
|
||||
}else if( c>0 ){
|
||||
/* zNum is greater than 9223372036854775808 so it overflows */
|
||||
return 2;
|
||||
return 1;
|
||||
}else{
|
||||
/* zNum is exactly 9223372036854775808. Fits if negative. The
|
||||
** special case 2 overflow if positive */
|
||||
assert( u-1==LARGEST_INT64 );
|
||||
return neg ? rc : 3;
|
||||
return neg ? 0 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,9 +655,8 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
** Returns:
|
||||
**
|
||||
** 0 Successful transformation. Fits in a 64-bit signed integer.
|
||||
** 1 Excess text after the integer value
|
||||
** 2 Integer too large for a 64-bit signed integer or is malformed
|
||||
** 3 Special case of 9223372036854775808
|
||||
** 1 Integer too large for a 64-bit signed integer or is malformed
|
||||
** 2 Special case of 9223372036854775808
|
||||
*/
|
||||
int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
|
||||
#ifndef SQLITE_OMIT_HEX_INTEGER
|
||||
@@ -672,7 +670,7 @@ int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
|
||||
u = u*16 + sqlite3HexToInt(z[k]);
|
||||
}
|
||||
memcpy(pOut, &u, 8);
|
||||
return (z[k]==0 && k-i<=16) ? 0 : 2;
|
||||
return (z[k]==0 && k-i<=16) ? 0 : 1;
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_HEX_INTEGER */
|
||||
{
|
||||
|
||||
+3
-3
@@ -354,7 +354,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
|
||||
if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
|
||||
return 0;
|
||||
}
|
||||
if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){
|
||||
if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
|
||||
return MEM_Int;
|
||||
}
|
||||
return MEM_Real;
|
||||
@@ -5673,7 +5673,7 @@ case OP_IntegrityCk: {
|
||||
nRoot = pOp->p2;
|
||||
aRoot = pOp->p4.ai;
|
||||
assert( nRoot>0 );
|
||||
assert( aRoot[0]==nRoot );
|
||||
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 );
|
||||
@@ -5681,7 +5681,7 @@ case OP_IntegrityCk: {
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pOp->p5<db->nDb );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p5) );
|
||||
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
|
||||
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
|
||||
(int)pnErr->u.i+1, &nErr);
|
||||
sqlite3VdbeMemSetNull(pIn1);
|
||||
if( nErr==0 ){
|
||||
|
||||
+1
-1
@@ -1396,7 +1396,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
int *ai = pOp->p4.ai;
|
||||
int n = ai[0]; /* The first element of an INTARRAY is always the
|
||||
** count of the number of elements to follow */
|
||||
for(i=1; i<=n; i++){
|
||||
for(i=1; i<n; i++){
|
||||
sqlite3XPrintf(&x, ",%d", ai[i]);
|
||||
}
|
||||
zTemp[0] = '[';
|
||||
|
||||
+30
-33
@@ -155,7 +155,7 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
assert( pMem->szMalloc==0
|
||||
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
|
||||
if( n<32 ) n = 32;
|
||||
if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
|
||||
if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
|
||||
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
|
||||
bPreserve = 0;
|
||||
}else{
|
||||
@@ -171,8 +171,7 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
|
||||
}
|
||||
|
||||
if( bPreserve && pMem->z ){
|
||||
assert( pMem->z!=pMem->zMalloc );
|
||||
if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){
|
||||
memcpy(pMem->zMalloc, pMem->z, pMem->n);
|
||||
}
|
||||
if( (pMem->flags&MEM_Dyn)!=0 ){
|
||||
@@ -210,20 +209,6 @@ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** It is already known that pMem contains an unterminated string.
|
||||
** Add the zero terminator.
|
||||
*/
|
||||
static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
|
||||
if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
pMem->z[pMem->n] = 0;
|
||||
pMem->z[pMem->n+1] = 0;
|
||||
pMem->flags |= MEM_Term;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change pMem so that its MEM_Str or MEM_Blob value is stored in
|
||||
** MEM.zMalloc, where it can be safely written.
|
||||
@@ -236,8 +221,12 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
||||
if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
|
||||
if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
|
||||
if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
|
||||
int rc = vdbeMemAddTerminator(pMem);
|
||||
if( rc ) return rc;
|
||||
if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
pMem->z[pMem->n] = 0;
|
||||
pMem->z[pMem->n+1] = 0;
|
||||
pMem->flags |= MEM_Term;
|
||||
}
|
||||
}
|
||||
pMem->flags &= ~MEM_Ephem;
|
||||
@@ -276,6 +265,20 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** It is already known that pMem contains an unterminated string.
|
||||
** Add the zero terminator.
|
||||
*/
|
||||
static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
|
||||
if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
pMem->z[pMem->n] = 0;
|
||||
pMem->z[pMem->n+1] = 0;
|
||||
pMem->flags |= MEM_Term;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure the given Mem is \u0000 terminated.
|
||||
*/
|
||||
@@ -594,21 +597,14 @@ int sqlite3VdbeMemRealify(Mem *pMem){
|
||||
*/
|
||||
int sqlite3VdbeMemNumerify(Mem *pMem){
|
||||
if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
|
||||
int rc;
|
||||
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc);
|
||||
if( rc==0 ){
|
||||
if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
|
||||
MemSetTypeFlag(pMem, MEM_Int);
|
||||
}else{
|
||||
i64 i = pMem->u.i;
|
||||
sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
|
||||
if( rc==1 && pMem->u.r==(double)i ){
|
||||
pMem->u.i = i;
|
||||
MemSetTypeFlag(pMem, MEM_Int);
|
||||
}else{
|
||||
MemSetTypeFlag(pMem, MEM_Real);
|
||||
}
|
||||
pMem->u.r = sqlite3VdbeRealValue(pMem);
|
||||
MemSetTypeFlag(pMem, MEM_Real);
|
||||
sqlite3VdbeIntegerAffinity(pMem);
|
||||
}
|
||||
}
|
||||
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
|
||||
@@ -1013,11 +1009,12 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
|
||||
){
|
||||
int rc;
|
||||
pMem->flags = MEM_Null;
|
||||
if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){
|
||||
if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
|
||||
rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z);
|
||||
if( rc==SQLITE_OK ){
|
||||
pMem->z[amt] = 0; /* Overrun area used when reading malformed records */
|
||||
pMem->flags = MEM_Blob;
|
||||
pMem->z[amt] = 0;
|
||||
pMem->z[amt+1] = 0;
|
||||
pMem->flags = MEM_Blob|MEM_Term;
|
||||
pMem->n = (int)amt;
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
|
||||
@@ -448,6 +448,7 @@ struct Wal {
|
||||
u32 iReCksum; /* On commit, recalculate checksums from here */
|
||||
const char *zWalName; /* Name of WAL file */
|
||||
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
|
||||
FastPrng sPrng; /* Random number generator */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 lockError; /* True if a locking error has occurred */
|
||||
#endif
|
||||
@@ -1323,6 +1324,7 @@ int sqlite3WalOpen(
|
||||
pRet->syncHeader = 1;
|
||||
pRet->padToSectorBoundary = 1;
|
||||
pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
|
||||
sqlite3FastPrngInit(&pRet->sPrng);
|
||||
|
||||
/* Open file handle on the write-ahead log file. */
|
||||
flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
|
||||
@@ -1870,7 +1872,7 @@ static int walCheckpoint(
|
||||
rc = SQLITE_BUSY;
|
||||
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
|
||||
u32 salt1;
|
||||
sqlite3_randomness(4, &salt1);
|
||||
sqlite3FastRandomness(&pWal->sPrng, 4, &salt1);
|
||||
assert( pInfo->nBackfill==pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -2878,7 +2880,7 @@ static int walRestartLog(Wal *pWal){
|
||||
assert( pInfo->nBackfill==pWal->hdr.mxFrame );
|
||||
if( pInfo->nBackfill>0 ){
|
||||
u32 salt1;
|
||||
sqlite3_randomness(4, &salt1);
|
||||
sqlite3FastRandomness(&pWal->sPrng, 4, &salt1);
|
||||
rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
if( rc==SQLITE_OK ){
|
||||
/* If all readers are using WAL_READ_LOCK(0) (in other words if no
|
||||
@@ -3094,7 +3096,7 @@ int sqlite3WalFrames(
|
||||
sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
|
||||
sqlite3Put4byte(&aWalHdr[8], szPage);
|
||||
sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
|
||||
if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
|
||||
if( pWal->nCkpt==0 ) sqlite3FastRandomness(&pWal->sPrng, 8, pWal->hdr.aSalt);
|
||||
memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
|
||||
walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
|
||||
sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
|
||||
|
||||
+17
-12
@@ -403,8 +403,8 @@ static int findIndexCol(
|
||||
&& p->iColumn==pIdx->aiColumn[iCol]
|
||||
&& p->iTable==iBase
|
||||
){
|
||||
CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
|
||||
if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
|
||||
if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -2669,7 +2669,7 @@ static int indexMightHelpWithOrderBy(
|
||||
}else if( (aColExpr = pIndex->aColExpr)!=0 ){
|
||||
for(jj=0; jj<pIndex->nKeyCol; jj++){
|
||||
if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
|
||||
if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
|
||||
if( sqlite3ExprCompare(0, pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -3579,10 +3579,14 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
if( j>=pLoop->nLTerm ) continue;
|
||||
}
|
||||
if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
|
||||
if( sqlite3ExprCollSeqMatch(pWInfo->pParse,
|
||||
pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){
|
||||
continue;
|
||||
}
|
||||
const char *z1, *z2;
|
||||
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
z1 = pColl->zName;
|
||||
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr);
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
z2 = pColl->zName;
|
||||
if( sqlite3StrICmp(z1, z2)!=0 ) continue;
|
||||
testcase( pTerm->pExpr->op==TK_IS );
|
||||
}
|
||||
obSat |= MASKBIT(i);
|
||||
@@ -3654,7 +3658,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
if( pIndex ){
|
||||
iColumn = pIndex->aiColumn[j];
|
||||
revIdx = pIndex->aSortOrder[j];
|
||||
if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID;
|
||||
if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
|
||||
}else{
|
||||
iColumn = XN_ROWID;
|
||||
revIdx = 0;
|
||||
@@ -3681,18 +3685,19 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
testcase( wctrlFlags & WHERE_GROUPBY );
|
||||
testcase( wctrlFlags & WHERE_DISTINCTBY );
|
||||
if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
|
||||
if( iColumn>=XN_ROWID ){
|
||||
if( iColumn>=(-1) ){
|
||||
if( pOBExpr->op!=TK_COLUMN ) continue;
|
||||
if( pOBExpr->iTable!=iCur ) continue;
|
||||
if( pOBExpr->iColumn!=iColumn ) continue;
|
||||
}else{
|
||||
Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
|
||||
if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
|
||||
if( sqlite3ExprCompare(0,
|
||||
pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( iColumn!=XN_ROWID ){
|
||||
pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
|
||||
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
|
||||
}
|
||||
pLoop->u.btree.nIdxCol = j+1;
|
||||
|
||||
+6
-1
@@ -842,6 +842,7 @@ static void exprAnalyzeOrTerm(
|
||||
static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
||||
char aff1, aff2;
|
||||
CollSeq *pColl;
|
||||
const char *zColl1, *zColl2;
|
||||
if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
|
||||
if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
|
||||
@@ -854,7 +855,11 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
|
||||
if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
|
||||
return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
|
||||
pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
|
||||
zColl1 = pColl ? pColl->zName : 0;
|
||||
pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
|
||||
zColl2 = pColl ? pColl->zName : 0;
|
||||
return sqlite3_stricmp(zColl1, zColl2)==0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1663,50 +1663,6 @@ do_expr_test e_expr-32.2.3 {
|
||||
do_expr_test e_expr-32.2.4 {
|
||||
CAST(9223372036854775807 AS NUMERIC)
|
||||
} integer 9223372036854775807
|
||||
do_expr_test e_expr-32.2.5 {
|
||||
CAST('9223372036854775807 ' AS NUMERIC)
|
||||
} integer 9223372036854775807
|
||||
do_expr_test e_expr-32.2.6 {
|
||||
CAST(' 9223372036854775807 ' AS NUMERIC)
|
||||
} integer 9223372036854775807
|
||||
do_expr_test e_expr-32.2.7 {
|
||||
CAST(' ' AS NUMERIC)
|
||||
} integer 0
|
||||
do_execsql_test e_expr-32.2.8 {
|
||||
WITH t1(x) AS (VALUES
|
||||
('9000000000000000001'),
|
||||
('9000000000000000001x'),
|
||||
('9000000000000000001 '),
|
||||
(' 9000000000000000001 '),
|
||||
(' 9000000000000000001'),
|
||||
(' 9000000000000000001.'),
|
||||
('9223372036854775807'),
|
||||
('9223372036854775807 '),
|
||||
(' 9223372036854775807 '),
|
||||
('9223372036854775808'),
|
||||
(' 9223372036854775808 '),
|
||||
('9223372036854775807.0'),
|
||||
('9223372036854775807e+0'),
|
||||
('-5.0'),
|
||||
('-5e+0'))
|
||||
SELECT typeof(CAST(x AS NUMERIC)), CAST(x AS NUMERIC)||'' FROM t1;
|
||||
} [list \
|
||||
integer 9000000000000000001 \
|
||||
integer 9000000000000000001 \
|
||||
integer 9000000000000000001 \
|
||||
integer 9000000000000000001 \
|
||||
integer 9000000000000000001 \
|
||||
integer 9000000000000000001 \
|
||||
integer 9223372036854775807 \
|
||||
integer 9223372036854775807 \
|
||||
integer 9223372036854775807 \
|
||||
real 9.22337203685478e+18 \
|
||||
real 9.22337203685478e+18 \
|
||||
integer 9223372036854775807 \
|
||||
integer 9223372036854775807 \
|
||||
integer -5 \
|
||||
integer -5 \
|
||||
]
|
||||
|
||||
# EVIDENCE-OF: R-64550-29191 Note that the result from casting any
|
||||
# non-BLOB value into a BLOB and the result from casting any BLOB value
|
||||
|
||||
+13
-18
@@ -65,6 +65,19 @@ foreach {tn sql1 sql2} {
|
||||
3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary"
|
||||
|
||||
4 {
|
||||
SELECT x,y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1
|
||||
GROUP BY a
|
||||
) WHERE x BETWEEN 8888 AND 9999
|
||||
} {
|
||||
SELECT x,y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1
|
||||
WHERE x BETWEEN 8888 AND 9999
|
||||
GROUP BY a
|
||||
)
|
||||
}
|
||||
|
||||
5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 0"
|
||||
"SELECT a, sum(b) FROM t1 WHERE 0 GROUP BY a COLLATE binary"
|
||||
|
||||
@@ -85,24 +98,6 @@ foreach {tn sql1 sql2} {
|
||||
do_compare_vdbe_test 2.$tn $sql1 $sql2 1
|
||||
}
|
||||
|
||||
# The (4) test in the above set used to generate identical bytecode, but
|
||||
# that is no longer the case. The byte code is equivalent, though.
|
||||
#
|
||||
do_execsql_test 2.4a {
|
||||
SELECT x,y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1
|
||||
GROUP BY a
|
||||
) WHERE x BETWEEN 2 AND 9999
|
||||
} {2 12}
|
||||
do_execsql_test 2.4b {
|
||||
SELECT x,y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1
|
||||
WHERE x BETWEEN 2 AND 9999
|
||||
GROUP BY a
|
||||
)
|
||||
} {2 12}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# 1: Test that the optimization is only applied if the GROUP BY term
|
||||
# uses BINARY collation.
|
||||
|
||||
@@ -136,26 +136,4 @@ do_execsql_test 3.4.2 {
|
||||
.ABC 1 .ABC 3 .abc 2 .abc 4
|
||||
}
|
||||
|
||||
do_execsql_test 3.4.3 {
|
||||
DROP INDEX i4;
|
||||
UPDATE t4 SET a = printf('%s%d',a,b);
|
||||
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
|
||||
} {.ABC1 1 .abc2 2 .ABC3 3 .abc4 4}
|
||||
do_execsql_test 3.4.4 {
|
||||
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary;
|
||||
} {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4}
|
||||
|
||||
do_execsql_test 3.4.5 {
|
||||
CREATE INDEX i4 ON t4( Substr(a,-2) COLLATE nocase );
|
||||
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
|
||||
} {.ABC1 1 .abc2 2 .ABC3 3 .abc4 4}
|
||||
do_execsql_test 3.4.5eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
|
||||
} {/SCAN TABLE t4 USING INDEX i4/}
|
||||
do_execsql_test 3.4.6 {
|
||||
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary;
|
||||
} {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+3
-2
@@ -1048,7 +1048,6 @@ ifcapable !icu {
|
||||
} {1}
|
||||
}
|
||||
|
||||
ifcapable !icu {
|
||||
# As of 2017-07-27 (3.21.0) the LIKE optimization works with ESCAPE as
|
||||
# long as the ESCAPE is a single-byte literal.
|
||||
#
|
||||
@@ -1093,6 +1092,8 @@ do_execsql_test like-15.121 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/';
|
||||
} {/SEARCH/}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -80,24 +80,5 @@ foreach {tn sql} {
|
||||
do_pragma_ncol_test 1.$tn.1 $sql 0
|
||||
}
|
||||
|
||||
# EXPLAIN on a PRAGMA integrity_check.
|
||||
# Verify that that P4_INTARRAY argument to OP_IntegrityCk is rendered
|
||||
# correctly.
|
||||
#
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
do_test pragma4-2.100 {
|
||||
db eval {
|
||||
PRAGMA page_size=512;
|
||||
CREATE TABLE t1(x);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10000)
|
||||
INSERT INTO t1(x) SELECT zeroblob(300) FROM c;
|
||||
CREATE TABLE t2(y);
|
||||
DROP TABLE t1;
|
||||
}
|
||||
string map {\[ x \] x \173 {} \175 {}} \
|
||||
[db eval {EXPLAIN PRAGMA integrity_check}]
|
||||
} {/ IntegrityCk 2 2 1 x[0-9]+,1x /}
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-2
@@ -545,9 +545,9 @@ do_test select1-6.9.7 {
|
||||
set x [execsql2 {
|
||||
SELECT * FROM test1 a, (select 5, 6) LIMIT 1
|
||||
}]
|
||||
regsub -all {subquery_[0-9a-fA-F_]+} $x {subquery} x
|
||||
regsub -all {sq_[0-9a-fA-F_]+} $x {subquery} x
|
||||
set x
|
||||
} {a.f1 11 a.f2 22 subquery.5 5 subquery.6 6}
|
||||
} {a.f1 11 a.f2 22 sqlite_subquery.5 5 sqlite_subquery.6 6}
|
||||
do_test select1-6.9.8 {
|
||||
set x [execsql2 {
|
||||
SELECT * FROM test1 a, (select 5 AS x, 6 AS y) AS b LIMIT 1
|
||||
|
||||
@@ -197,45 +197,4 @@ do_test 4.7 {
|
||||
list [catch { sqlite3_snapshot_recover db aux } msg] $msg
|
||||
} {1 SQLITE_ERROR}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
sqlite3 db2 test.db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t2(x);
|
||||
PRAGMA journal_mode = wal;
|
||||
INSERT INTO t2 VALUES('abc');
|
||||
INSERT INTO t2 VALUES('def');
|
||||
INSERT INTO t2 VALUES('ghi');
|
||||
} {wal}
|
||||
|
||||
do_test 5.1 {
|
||||
execsql {
|
||||
SELECT * FROM t2;
|
||||
BEGIN;
|
||||
} db2
|
||||
set snap [sqlite3_snapshot_get_blob db2 main]
|
||||
db2 eval END
|
||||
} {}
|
||||
|
||||
do_test 5.2 {
|
||||
execsql BEGIN db2
|
||||
sqlite3_snapshot_open_blob db2 main $snap
|
||||
db2 eval { SELECT * FROM t2 ; END }
|
||||
} {abc def ghi}
|
||||
|
||||
do_test 5.3 {
|
||||
execsql { PRAGMA wal_checkpoint = RESTART }
|
||||
execsql BEGIN db2
|
||||
sqlite3_snapshot_open_blob db2 main $snap
|
||||
db2 eval { SELECT * FROM t2 ; END }
|
||||
} {abc def ghi}
|
||||
|
||||
do_test 5.4 {
|
||||
execsql { INSERT INTO t2 VALUES('jkl') }
|
||||
execsql BEGIN db2
|
||||
list [catch { sqlite3_snapshot_open_blob db2 main $snap } msg] $msg
|
||||
} {1 SQLITE_BUSY_SNAPSHOT}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+6
-7
@@ -777,10 +777,9 @@ int main(int argc, char **argv){
|
||||
FILE *in;
|
||||
int allValid = 1;
|
||||
int rc;
|
||||
SHA3Context ctx;
|
||||
char zDate[50];
|
||||
char zHash[100];
|
||||
char zLine[20000];
|
||||
char zLine[1000];
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
@@ -806,11 +805,7 @@ int main(int argc, char **argv){
|
||||
fprintf(stderr, "cannot open \"%s\" for reading\n", zManifest);
|
||||
exit(1);
|
||||
}
|
||||
SHA3Init(&ctx, 256);
|
||||
while( fgets(zLine, sizeof(zLine), in) ){
|
||||
if( strncmp(zLine,"# Remove this line", 18)!=0 ){
|
||||
SHA3Update(&ctx, (unsigned char*)zLine, (unsigned)strlen(zLine));
|
||||
}
|
||||
if( strncmp(zLine, "D 20", 4)==0 ){
|
||||
memcpy(zDate, &zLine[2], 10);
|
||||
zDate[10] = ' ';
|
||||
@@ -831,6 +826,8 @@ int main(int argc, char **argv){
|
||||
allValid = 0;
|
||||
if( bVerbose ){
|
||||
printf("hash failed: %s\n", zFilename);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}else if( strcmp(zHash, zMHash)!=0 ){
|
||||
allValid = 0;
|
||||
@@ -838,12 +835,14 @@ int main(int argc, char **argv){
|
||||
printf("wrong hash: %s\n", zFilename);
|
||||
printf("... expected: %s\n", zMHash);
|
||||
printf("... got: %s\n", zHash);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(in);
|
||||
DigestToBase16(SHA3Final(&ctx), zHash, 256/8);
|
||||
sha3sum_file(zManifest, 256, zHash);
|
||||
if( !allValid ){
|
||||
printf("%s %.60salt1\n", zDate, zHash);
|
||||
}else{
|
||||
|
||||
Reference in New Issue
Block a user