Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef215fbf3b | |||
| 96e337df6b | |||
| a3e6495970 | |||
| b6a74caf93 | |||
| c08716a317 | |||
| 4dfdb86c8d | |||
| 91faeec8d0 | |||
| 8c1fbe81d0 | |||
| 24c22753fc | |||
| 47eb561c40 | |||
| 9f567eb9f5 | |||
| 26c48d2aab | |||
| 12a4c41917 | |||
| 08b9208660 | |||
| ed0af52cb1 | |||
| 80aff0847e | |||
| 14d093f847 | |||
| 8afc09dea3 | |||
| 07066d90f6 | |||
| 47d38e2444 | |||
| 35a37c2a47 | |||
| c664355c0f | |||
| a6c13b22b2 | |||
| d43c0cbed2 | |||
| 7033ce4fdc | |||
| 799443b14f | |||
| 26b9540fc2 | |||
| 88819d5870 | |||
| b19493434f | |||
| 2c40b8f3da | |||
| f82ce382f9 | |||
| cec5f1d127 | |||
| 53218e2e2c | |||
| 41af5b34bb | |||
| 1991888238 | |||
| e592c18c1c | |||
| 013e7bb749 | |||
| 91d028f0a1 | |||
| 48bf2d72b9 | |||
| 8deae5ade3 | |||
| 1024822ba8 | |||
| 6528bcdc80 | |||
| 9044361a9a | |||
| e7f3edcd49 | |||
| f31230af12 | |||
| cddfc3922c | |||
| 8caebb26c5 | |||
| d3e38b7c0e | |||
| 25a78fdfa2 | |||
| 8adc8f1ecb | |||
| 0c52f5a2b0 | |||
| d9059bdb5b | |||
| 38f0ccc070 | |||
| b140347395 | |||
| a92eae9751 | |||
| 2add24c0d4 | |||
| 9d44327a83 | |||
| ed109c06e1 | |||
| 17d2d592fb | |||
| 134599e557 | |||
| ca439a4967 | |||
| 69306bf43a | |||
| 3b3ddbae36 | |||
| 584e8b7630 | |||
| bb39ac7773 | |||
| abc3815860 | |||
| 55550b7602 | |||
| a7982eacd5 | |||
| 2f04583f04 | |||
| 82b0f106ce | |||
| bbd620e22c | |||
| 09cf569292 | |||
| 4e6861d23d | |||
| a192807c13 | |||
| e9261dbd53 | |||
| 51da8daf82 | |||
| a7c74006a0 | |||
| aec7dc6563 | |||
| d9674b385c | |||
| 387af48ed4 | |||
| 4c0086d7f0 | |||
| 07ca7d610b | |||
| 7e1d9512af | |||
| b1c993f681 | |||
| 9a23d26cba | |||
| 369e758fdc | |||
| 01b2344b3c | |||
| b866a65d4d | |||
| 6265c47a1a | |||
| 525326ef72 | |||
| ac45b7402d | |||
| e7cf8fdd17 | |||
| 576d5a8634 | |||
| 243210b79b | |||
| 42d7a77b61 | |||
| d8b3c19991 | |||
| 9951522f0b | |||
| 19543b9b7b | |||
| e7877b2d6b | |||
| c37b7680a4 | |||
| fc5bba7dc1 | |||
| bc2cf3b295 | |||
| 751a44ed24 | |||
| 6e4b140e94 | |||
| 9d575e46f3 | |||
| f067ae8eba | |||
| be952c11dc | |||
| a7f82d9f47 | |||
| 5b107654e9 | |||
| 27da907f8e | |||
| bbc9e1908a | |||
| 56215eaff4 | |||
| a1085f0640 | |||
| 6af305de1e | |||
| 413b94af89 | |||
| b16425d05a | |||
| 7db1ed50b8 | |||
| 9c673a29bd | |||
| b13d5c25d6 | |||
| d1d89140c0 | |||
| a78d2c0528 | |||
| a4e42d24df | |||
| 27ee29f68c | |||
| 5f0d37b57e | |||
| c601f1016c | |||
| 0a34cf551c | |||
| 4b849b0b09 | |||
| ec1650a239 | |||
| 15cedda902 | |||
| e3863b5176 | |||
| fa4b0d4453 | |||
| 3f1d0f56e4 | |||
| f488bc1147 | |||
| b8fec21983 | |||
| ec43d8040a | |||
| da36933eb4 | |||
| 8ddf635811 | |||
| 7465787b97 | |||
| 8b023cf592 | |||
| 1e113844fc | |||
| f2972b6083 | |||
| 9ed322d6c3 | |||
| 69887c99d4 |
@@ -11268,7 +11268,7 @@ if test "${enable_amalgamation+set}" = set; then :
|
||||
enableval=$enable_amalgamation;
|
||||
fi
|
||||
|
||||
if test "${enable_amalgamation}" == "no" ; then
|
||||
if test "${enable_amalgamation}" = "no" ; then
|
||||
USE_AMALGAMATION=0
|
||||
fi
|
||||
|
||||
|
||||
+1
-1
@@ -569,7 +569,7 @@ AC_SUBST(TARGET_DEBUG)
|
||||
# See whether we should use the amalgamation to build
|
||||
AC_ARG_ENABLE(amalgamation, AC_HELP_STRING([--disable-amalgamation],
|
||||
[Disable the amalgamation and instead build all files separately]))
|
||||
if test "${enable_amalgamation}" == "no" ; then
|
||||
if test "${enable_amalgamation}" = "no" ; then
|
||||
USE_AMALGAMATION=0
|
||||
fi
|
||||
AC_SUBST(USE_AMALGAMATION)
|
||||
|
||||
+26
-9
@@ -104,9 +104,13 @@ Write all output files into <i>directory</i>. Normally, output files
|
||||
are written into the directory that contains the input grammar file.
|
||||
<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
|
||||
"<tt><a href='#pifdef'>%ifdef</a></tt>",
|
||||
"<tt><a href='#pifdef'>%ifndef</a></tt>", and
|
||||
"<tt><a href="#pifdef">%if</a></tt> lines
|
||||
in the grammar file.
|
||||
<li><b>-E</b>
|
||||
Run the "%if" preprocessor step only and print the revised 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.
|
||||
@@ -555,9 +559,11 @@ other than that, the order of directives in Lemon is arbitrary.</p>
|
||||
<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'>%else</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'>%if</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>
|
||||
@@ -737,10 +743,11 @@ arguments are tokens which fall back to the token identified by the first
|
||||
argument.</p>
|
||||
|
||||
<a name='pifdef'></a>
|
||||
<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives</h4>
|
||||
<h4>The <tt>%if</tt> directive and its friends</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,
|
||||
<p>The <tt>%if</tt>, <tt>%ifdef</tt>, <tt>%ifndef</tt>, <tt>%else</tt>,
|
||||
and <tt>%endif</tt> directives
|
||||
are similar to #if, #ifdef, #ifndef, #else, 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>
|
||||
@@ -749,12 +756,22 @@ is allowed between the "%" and the directive name.</p>
|
||||
"<tt>%endif</tt>" 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>
|
||||
included except when the "-DMACRO" command-line option is used.<p>
|
||||
|
||||
<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>The text in between "<tt>%if</tt> <i>CONDITIONAL</i>" and its
|
||||
corresponding <tt>%endif</tt> is included only if <i>CONDITIONAL</i>
|
||||
is true. The CONDITION is one or more macro names, optionally connected
|
||||
using the "||" and "&&" binary operators, the "!" unary operator,
|
||||
and grouped using balanced parentheses. Each term is true if the
|
||||
corresponding macro exists, and false if it does not exist.</p>
|
||||
|
||||
<p>An optional "<tt>%else</tt>" directive can occur anywhere in between a
|
||||
<tt>%ifdef</tt>, <tt>%ifndef</tt>, or <tt>%if</tt> directive and
|
||||
its corresponding <tt>%endif</tt>.</p>
|
||||
|
||||
<p>Note that the argument to <tt>%ifdef</tt> and <tt>%ifndef</tt> is
|
||||
intended to be a single preprocessor symbol name, not a general expression.
|
||||
Use the "<tt>%if</tt>" directive for general expressions.</p>
|
||||
|
||||
<a name='pinclude'></a>
|
||||
<h4>The <tt>%include</tt> directive</h4>
|
||||
|
||||
+8
-3
@@ -2068,7 +2068,7 @@ static void fts3PutDeltaVarint(
|
||||
sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */
|
||||
sqlite3_int64 iVal /* Write this value to the list */
|
||||
){
|
||||
assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
|
||||
assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
|
||||
*pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
|
||||
*piPrev = iVal;
|
||||
}
|
||||
@@ -3479,7 +3479,7 @@ static int fts3ColumnMethod(
|
||||
break;
|
||||
}else{
|
||||
iCol = p->nColumn;
|
||||
/* fall-through */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -3722,9 +3722,13 @@ static void fts3SnippetFunc(
|
||||
|
||||
switch( nVal ){
|
||||
case 6: nToken = sqlite3_value_int(apVal[5]);
|
||||
/* no break */ deliberate_fall_through
|
||||
case 5: iCol = sqlite3_value_int(apVal[4]);
|
||||
/* no break */ deliberate_fall_through
|
||||
case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
|
||||
/* no break */ deliberate_fall_through
|
||||
case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
|
||||
/* no break */ deliberate_fall_through
|
||||
case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
|
||||
}
|
||||
if( !zEllipsis || !zEnd || !zStart ){
|
||||
@@ -5831,7 +5835,8 @@ static int fts3EvalGatherStats(
|
||||
fts3EvalRestart(pCsr, pRoot, &rc);
|
||||
do {
|
||||
fts3EvalNextRow(pCsr, pRoot, &rc);
|
||||
assert( pRoot->bEof==0 );
|
||||
assert_fts3_nc( pRoot->bEof==0 );
|
||||
if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB;
|
||||
}while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,8 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
|
||||
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
||||
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
||||
|
||||
#define deliberate_fall_through
|
||||
|
||||
#endif /* SQLITE_AMALGAMATION */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
|
||||
@@ -188,7 +188,8 @@ static int fts3tokConnectMethod(
|
||||
|
||||
assert( (rc==SQLITE_OK)==(pMod!=0) );
|
||||
if( rc==SQLITE_OK ){
|
||||
const char * const *azArg = (const char * const *)&azDequote[1];
|
||||
const char * const *azArg = 0;
|
||||
if( nDequote>1 ) azArg = (const char * const *)&azDequote[1];
|
||||
rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
|
||||
}
|
||||
|
||||
|
||||
+20
-10
@@ -2855,6 +2855,19 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
|
||||
if( nReq>pCsr->nBuffer ){
|
||||
char *aNew;
|
||||
pCsr->nBuffer = nReq*2;
|
||||
aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
|
||||
if( !aNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pCsr->aBuffer = aNew;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
int sqlite3Fts3SegReaderStep(
|
||||
Fts3Table *p, /* Virtual table handle */
|
||||
@@ -2989,15 +3002,9 @@ int sqlite3Fts3SegReaderStep(
|
||||
}
|
||||
|
||||
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
|
||||
if( nDoclist+nByte>pCsr->nBuffer ){
|
||||
char *aNew;
|
||||
pCsr->nBuffer = (nDoclist+nByte)*2;
|
||||
aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
|
||||
if( !aNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pCsr->aBuffer = aNew;
|
||||
}
|
||||
|
||||
rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist);
|
||||
if( rc ) return rc;
|
||||
|
||||
if( isFirst ){
|
||||
char *a = &pCsr->aBuffer[nDoclist];
|
||||
@@ -3022,6 +3029,9 @@ int sqlite3Fts3SegReaderStep(
|
||||
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
|
||||
}
|
||||
if( nDoclist>0 ){
|
||||
rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
|
||||
if( rc ) return rc;
|
||||
memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
|
||||
pCsr->aDoclist = pCsr->aBuffer;
|
||||
pCsr->nDoclist = nDoclist;
|
||||
rc = SQLITE_ROW;
|
||||
@@ -4290,7 +4300,7 @@ static int fts3IncrmergeLoad(
|
||||
int i;
|
||||
int nHeight = (int)aRoot[0];
|
||||
NodeWriter *pNode;
|
||||
if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
|
||||
if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){
|
||||
sqlite3_reset(pSelect);
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
@@ -2321,11 +2321,11 @@ static void fts5LeafSeek(
|
||||
}
|
||||
|
||||
search_success:
|
||||
pIter->iLeafOffset = iOff + nNew;
|
||||
if( pIter->iLeafOffset>n || nNew<1 ){
|
||||
if( (i64)iOff+nNew>n || nNew<1 ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}
|
||||
pIter->iLeafOffset = iOff + nNew;
|
||||
pIter->iTermLeafOffset = pIter->iLeafOffset;
|
||||
pIter->iTermLeafPgno = pIter->iLeafPgno;
|
||||
|
||||
|
||||
@@ -10108,6 +10108,221 @@ do_catchsql_test 68.1 {
|
||||
INSERT INTO t1(t1) SELECT x FROM t2;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 69.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 32768 pagesize 4096 filename crash-31c462b8b665d0.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........
|
||||
| 32: 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
|
||||
| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 00 00 00 00 00 00 ...k............
|
||||
| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
|
||||
| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
|
||||
| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
|
||||
| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
|
||||
| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
|
||||
| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
|
||||
| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
|
||||
| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
|
||||
| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
|
||||
| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
|
||||
| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
|
||||
| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
|
||||
| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
|
||||
| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
|
||||
| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
|
||||
| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
|
||||
| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
|
||||
| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
|
||||
| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
|
||||
| 3776: 63 39 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c9, c1, c2)i....
|
||||
| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
|
||||
| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
|
||||
| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
|
||||
| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
|
||||
| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
|
||||
| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
|
||||
| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
|
||||
| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
|
||||
| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
|
||||
| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
|
||||
| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
|
||||
| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
|
||||
| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
|
||||
| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
|
||||
| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
|
||||
| page 3 offset 8192
|
||||
| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
|
||||
| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
|
||||
| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
|
||||
| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
|
||||
| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4.
|
||||
| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
|
||||
| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
|
||||
| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary..
|
||||
| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 3344: 02 02 03 06 00 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp
|
||||
| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
|
||||
| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
|
||||
| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
|
||||
| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
|
||||
| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 3488: 01 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
|
||||
| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 1a 02 03 .........fts4...
|
||||
| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
|
||||
| 3552: 02 03 01 03 67 63 63 01 aa 03 01 02 03 01 02 03 ....gcc.........
|
||||
| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 02 02 03 01 02 ..eopoly........
|
||||
| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........
|
||||
| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
|
||||
| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
|
||||
| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
|
||||
| 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n
|
||||
| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
|
||||
| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 01 ...omit.........
|
||||
| 3744: ff ff ff ff ff ff ff ff f0 00 00 00 00 00 01 02 ................
|
||||
| 3760: 58 81 96 4d 01 06 01 02 02 03 06 01 02 02 03 06 X..M............
|
||||
| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe....
|
||||
| 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab.....
|
||||
| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
|
||||
| 3872: 02 01 06 01 1e 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3936: 00 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
|
||||
| 4048: 12 44 13 11 0f 47 13 0f 0b 0e 11 10 0f 0e 10 0f .D...G..........
|
||||
| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
|
||||
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
|
||||
| page 4 offset 12288
|
||||
| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
|
||||
| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
|
||||
| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
|
||||
| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 00 00 00 00 00 .......h.O......
|
||||
| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
|
||||
| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
|
||||
| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
|
||||
| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
|
||||
| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE=
|
||||
| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM
|
||||
| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
|
||||
| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 d3 19 4f NXBINARY. ..3..O
|
||||
| 3200: 4d 49 54 28 2c 4f 41 44 b2 04 55 85 44 54 e5 34 MIT(,OAD..U.DT.4
|
||||
| 3216: 94 f4 e5 84 e4 f4 34 15 34 51 e1 f0 50 03 30 f1 ......4.4Q..P.0.
|
||||
| 3232: 74 f4 d4 95 42 04 c4 f4 14 42 04 55 85 44 54 e5 t...B....B.U.DT.
|
||||
| 3248: 34 94 f4 e5 85 25 45 24 94 d1 f1 e0 50 03 30 f1 4....%E$....P.0.
|
||||
| 3264: 94 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 03 03 ......T..%..S...
|
||||
| 3280: 03 03 03 05 84 24 94 e4 15 25 91 f1 d0 50 03 30 .....$...%...P.0
|
||||
| 3296: f1 94 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 03 .......T..%..S..
|
||||
| 3312: 03 03 03 03 05 84 e4 f4 34 15 34 51 e1 c0 50 03 ........4.4Q..P.
|
||||
| 3328: 30 f1 74 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 0.t.....T..%..S.
|
||||
| 3344: 03 03 03 03 03 05 85 25 45 24 94 d1 81 b0 50 02 .......%E$....P.
|
||||
| 3360: 50 f1 94 54 e4 14 24 c4 52 05 25 45 24 54 55 84 P..T..$.R.%E$TU.
|
||||
| 3376: 24 94 e4 15 25 91 81 a0 50 02 50 f1 94 54 e4 14 $...%...P.P..T..
|
||||
| 3392: 24 c4 52 05 25 45 24 54 55 84 e4 f4 34 15 34 51 $.R.%E$TU...4.4Q
|
||||
| 3408: 71 90 50 02 50 f1 74 54 e4 14 24 c4 52 05 25 45 q.P.P.tT..$.R.%E
|
||||
| 3424: 24 54 55 85 25 45 24 94 d1 a1 80 50 02 90 f1 94 $TU.%E$....P....
|
||||
| 3440: 54 e4 14 24 c4 52 04 d4 54 d5 35 95 33 55 84 24 T..$.R..T.5.3U.$
|
||||
| 3456: 94 e4 15 25 91 a1 70 50 02 90 f1 94 54 e4 14 24 ...%..pP....T..$
|
||||
| 3472: c4 52 04 d4 54 d5 35 95 33 55 84 e4 f4 34 15 34 .R..T.5.3U...4.4
|
||||
| 3488: 51 91 60 50 02 90 f1 74 54 e4 14 24 c4 52 04 d4 Q.`P...tT..$.R..
|
||||
| 3504: 54 d5 35 95 33 55 85 25 45 24 94 d1 81 50 50 02 T.5.3U.%E$...PP.
|
||||
| 3520: 50 f1 94 54 e4 14 24 c4 52 04 a5 34 f4 e3 15 84 P..T..$.R..4....
|
||||
| 3536: 24 94 e4 15 25 91 81 40 50 02 50 f1 94 54 e4 14 $...%..@P.P..T..
|
||||
| 3552: 24 c4 52 04 a5 34 f4 e3 15 84 e4 f4 34 15 34 51 $.R..4......4.4Q
|
||||
| 3568: 71 30 50 02 4f f1 74 54 e4 14 24 c4 52 04 a5 34 q0P.O.tT..$.R..4
|
||||
| 3584: f4 e3 15 85 25 45 24 94 d1 a1 20 50 02 90 f1 94 ....%E$... P....
|
||||
| 3600: 54 e4 14 24 c4 52 04 74 54 f5 04 f4 c5 95 84 24 T..$.R.tT......$
|
||||
| 3616: 94 e4 15 25 91 a1 10 50 02 90 f1 94 54 e4 14 24 ...%...P....T..$
|
||||
| 3632: c4 52 04 74 54 f5 04 f4 c5 95 84 e4 f4 34 15 34 .R.tT........4.4
|
||||
| 3648: 51 91 00 50 02 90 f1 74 54 e4 14 24 c4 51 f4 74 Q..P...tT..$.Q.t
|
||||
| 3664: 54 f5 04 f4 c5 95 85 25 45 24 94 d1 70 f0 50 02 T......%E$..p.P.
|
||||
| 3680: 30 f1 94 54 e4 14 24 c5 20 46 54 53 35 58 42 49 0..T..$. FTS5XBI
|
||||
| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
|
||||
| 3712: 45 20 46 54 53 35 58 4f 4f 43 41 53 45 16 0d 05 E FTS5XOOCASE...
|
||||
| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
|
||||
| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
|
||||
| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 97 0b LE FTS4XBINARY..
|
||||
| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
|
||||
| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
|
||||
| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
|
||||
| 3824: 09 05 00 3e 5f 19 45 4e 41 42 4c 45 20 44 42 53 ...>_.ENABLE DBS
|
||||
| 3840: 44 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e DAT VTABXBINARY.
|
||||
| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
|
||||
| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 4d e3 45 1d TAT VTABXNOCM.E.
|
||||
| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
|
||||
| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM..
|
||||
| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
|
||||
| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
|
||||
| 3952: 43 41 53 45 10 02 02 50 08 5f 17 44 45 42 55 47 CASE...P._.DEBUG
|
||||
| 3968: 58 52 54 52 49 4d 27 03 05 00 44 0f 19 43 4f 4d XRTRIM'...D..COM
|
||||
| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
|
||||
| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
|
||||
| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
|
||||
| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
|
||||
| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 c9 17 43 9XNOCASE&...C..C
|
||||
| 4064: 4f 4d 50 49 4c 47 02 3d 67 63 63 2d 35 2e 34 2e OMPILG.=gcc-5.4.
|
||||
| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
|
||||
| page 6 offset 20480
|
||||
| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
|
||||
| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
|
||||
| 32: 0f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
|
||||
| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 00 00 00 00 00 00 .X.P.H.@.8......
|
||||
| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
|
||||
| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
|
||||
| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
|
||||
| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
|
||||
| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
|
||||
| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
|
||||
| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
|
||||
| 3920: 06 16 03 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
|
||||
| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
|
||||
| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
|
||||
| 3968: 06 10 03 00 12 02 01 01 06 1f 03 00 12 02 01 01 ................
|
||||
| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
|
||||
| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
|
||||
| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
|
||||
| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
|
||||
| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
|
||||
| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
|
||||
| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
|
||||
| page 7 offset 24576
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| page 8 offset 28672
|
||||
| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 67 72 .........+integr
|
||||
| 4064: 69 74 79 2d 63 68 65 63 6b 09 00 00 00 00 00 00 ity-check.......
|
||||
| end crash-31c462b8b665d0.db
|
||||
}]} {}
|
||||
|
||||
|
||||
do_catchsql_test 69.2 {
|
||||
SELECT * FROM t1 WHERE a MATCH 'fx*'
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
finish_test
|
||||
|
||||
@@ -439,7 +439,7 @@ static int apndOpen(
|
||||
p = (ApndFile*)pFile;
|
||||
memset(p, 0, sizeof(*p));
|
||||
pSubFile = ORIGFILE(pFile);
|
||||
p->base.pMethods = &apnd_io_methods;
|
||||
pFile->pMethods = &apnd_io_methods;
|
||||
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
|
||||
if( rc ) goto apnd_open_done;
|
||||
rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
|
||||
|
||||
+1
-1
@@ -634,7 +634,7 @@ static int cksmOpen(
|
||||
p = (CksmFile*)pFile;
|
||||
memset(p, 0, sizeof(*p));
|
||||
pSubFile = ORIGFILE(pFile);
|
||||
p->base.pMethods = &cksm_io_methods;
|
||||
pFile->pMethods = &cksm_io_methods;
|
||||
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
|
||||
if( rc ) goto cksm_open_done;
|
||||
if( flags & SQLITE_OPEN_WAL ){
|
||||
|
||||
+17
-2
@@ -21,6 +21,12 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Mark a function parameter as unused, to suppress nuisance compiler
|
||||
** warnings. */
|
||||
#ifndef UNUSED_PARAMETER
|
||||
# define UNUSED_PARAMETER(X) (void)(X)
|
||||
#endif
|
||||
|
||||
|
||||
/* A decimal object */
|
||||
typedef struct Decimal Decimal;
|
||||
@@ -235,6 +241,7 @@ static void decimalFunc(
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Decimal *p = decimal_new(context, argv[0], 0, 0);
|
||||
UNUSED_PARAMETER(argc);
|
||||
decimal_result(context, p);
|
||||
decimal_free(p);
|
||||
}
|
||||
@@ -288,6 +295,7 @@ static void decimalCmpFunc(
|
||||
Decimal *pA = 0, *pB = 0;
|
||||
int rc;
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
pA = decimal_new(context, argv[0], 0, 0);
|
||||
if( pA==0 || pA->isNull ) goto cmp_done;
|
||||
pB = decimal_new(context, argv[1], 0, 0);
|
||||
@@ -412,6 +420,7 @@ static int decimalCollFunc(
|
||||
Decimal *pA = decimal_new(0, 0, nKey1, zA);
|
||||
Decimal *pB = decimal_new(0, 0, nKey2, zB);
|
||||
int rc;
|
||||
UNUSED_PARAMETER(notUsed);
|
||||
if( pA==0 || pB==0 ){
|
||||
rc = 0;
|
||||
}else{
|
||||
@@ -436,6 +445,7 @@ static void decimalAddFunc(
|
||||
){
|
||||
Decimal *pA = decimal_new(context, argv[0], 0, 0);
|
||||
Decimal *pB = decimal_new(context, argv[1], 0, 0);
|
||||
UNUSED_PARAMETER(argc);
|
||||
decimal_add(pA, pB);
|
||||
decimal_result(context, pA);
|
||||
decimal_free(pA);
|
||||
@@ -448,6 +458,7 @@ static void decimalSubFunc(
|
||||
){
|
||||
Decimal *pA = decimal_new(context, argv[0], 0, 0);
|
||||
Decimal *pB = decimal_new(context, argv[1], 0, 0);
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( pB==0 ) return;
|
||||
pB->sign = !pB->sign;
|
||||
decimal_add(pA, pB);
|
||||
@@ -468,6 +479,7 @@ static void decimalSumStep(
|
||||
){
|
||||
Decimal *p;
|
||||
Decimal *pArg;
|
||||
UNUSED_PARAMETER(argc);
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p==0 ) return;
|
||||
if( !p->isInit ){
|
||||
@@ -493,6 +505,7 @@ static void decimalSumInverse(
|
||||
){
|
||||
Decimal *p;
|
||||
Decimal *pArg;
|
||||
UNUSED_PARAMETER(argc);
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p==0 ) return;
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
@@ -533,6 +546,7 @@ static void decimalMulFunc(
|
||||
signed char *acc = 0;
|
||||
int i, j, k;
|
||||
int minFrac;
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( pA==0 || pA->oom || pA->isNull
|
||||
|| pB==0 || pB->oom || pB->isNull
|
||||
){
|
||||
@@ -585,7 +599,6 @@ int sqlite3_decimal_init(
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
static const struct {
|
||||
const char *zFuncName;
|
||||
int nArg;
|
||||
@@ -597,9 +610,11 @@ int sqlite3_decimal_init(
|
||||
{ "decimal_sub", 2, decimalSubFunc },
|
||||
{ "decimal_mul", 2, decimalMulFunc },
|
||||
};
|
||||
int i;
|
||||
unsigned int i;
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
|
||||
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
|
||||
+12
-4
@@ -90,6 +90,12 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Mark a function parameter as unused, to suppress nuisance compiler
|
||||
** warnings. */
|
||||
#ifndef UNUSED_PARAMETER
|
||||
# define UNUSED_PARAMETER(X) (void)(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Implementation of the ieee754() function
|
||||
*/
|
||||
@@ -109,7 +115,7 @@ static void ieee754func(
|
||||
&& sqlite3_value_bytes(argv[0])==sizeof(r)
|
||||
){
|
||||
const unsigned char *x = sqlite3_value_blob(argv[0]);
|
||||
int i;
|
||||
unsigned int i;
|
||||
sqlite3_uint64 v = 0;
|
||||
for(i=0; i<sizeof(r); i++){
|
||||
v = (v<<8) | x[i];
|
||||
@@ -201,12 +207,13 @@ static void ieee754func_from_blob(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_BLOB
|
||||
&& sqlite3_value_bytes(argv[0])==sizeof(double)
|
||||
){
|
||||
double r;
|
||||
const unsigned char *x = sqlite3_value_blob(argv[0]);
|
||||
int i;
|
||||
unsigned int i;
|
||||
sqlite3_uint64 v = 0;
|
||||
for(i=0; i<sizeof(r); i++){
|
||||
v = (v<<8) | x[i];
|
||||
@@ -220,13 +227,14 @@ static void ieee754func_to_blob(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_FLOAT
|
||||
|| sqlite3_value_type(argv[0])==SQLITE_INTEGER
|
||||
){
|
||||
double r = sqlite3_value_double(argv[0]);
|
||||
sqlite3_uint64 v;
|
||||
unsigned char a[sizeof(r)];
|
||||
int i;
|
||||
unsigned int i;
|
||||
memcpy(&v, &r, sizeof(r));
|
||||
for(i=1; i<=sizeof(r); i++){
|
||||
a[sizeof(r)-i] = v&0xff;
|
||||
@@ -259,7 +267,7 @@ int sqlite3_ieee_init(
|
||||
{ "ieee754_from_blob", 1, 0, ieee754func_from_blob },
|
||||
|
||||
};
|
||||
int i;
|
||||
unsigned int i;
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
|
||||
+7
-2
@@ -42,6 +42,10 @@ SQLITE_EXTENSION_INIT1
|
||||
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
|
||||
#endif
|
||||
|
||||
#ifndef deliberate_fall_through
|
||||
# define deliberate_fall_through
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Versions of isspace(), isalnum() and isdigit() to which it is safe
|
||||
** to pass signed char values.
|
||||
@@ -460,7 +464,7 @@ static void jsonRenderNode(
|
||||
jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
|
||||
break;
|
||||
}
|
||||
/* Fall through into the next case */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case JSON_REAL:
|
||||
case JSON_INT: {
|
||||
@@ -601,7 +605,7 @@ static void jsonReturn(
|
||||
sqlite3_result_int64(pCtx, i);
|
||||
int_done:
|
||||
break;
|
||||
int_as_real: /* fall through to real */;
|
||||
int_as_real: i=0; /* no break */ deliberate_fall_through
|
||||
}
|
||||
case JSON_REAL: {
|
||||
double r;
|
||||
@@ -2304,6 +2308,7 @@ static int jsonEachColumn(
|
||||
}
|
||||
/* For json_each() path and root are the same so fall through
|
||||
** into the root case */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
default: {
|
||||
const char *zRoot = p->zRoot;
|
||||
|
||||
@@ -286,6 +286,13 @@ static const unsigned char sqlite3CtypeMap[256] = {
|
||||
#define TK_VARIABLE TK_LITERAL
|
||||
#define TK_BLOB TK_LITERAL
|
||||
|
||||
/* Disable nuisence warnings about case fall-through */
|
||||
#if !defined(deliberate_fall_through) && defined(__GCC__) && __GCC__>=7
|
||||
# define deliberate_fall_through __attribute__((fallthrough));
|
||||
#else
|
||||
# define deliberate_fall_through
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the length (in bytes) of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
@@ -436,6 +443,7 @@ static int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
}
|
||||
/* If the next character is a digit, this is a floating point
|
||||
** number that begins with ".". Fall thru into the next case */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case CC_DIGIT: {
|
||||
*tokenType = TK_INTEGER;
|
||||
@@ -528,6 +536,7 @@ static int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
}
|
||||
/* If it is not a BLOB literal, then it must be an ID, since no
|
||||
** SQL keywords start with the letter 'x'. Fall through */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case CC_ID: {
|
||||
i = 1;
|
||||
|
||||
@@ -82,6 +82,7 @@ typedef unsigned int u32;
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* The following macro is used to suppress compiler warnings.
|
||||
*/
|
||||
@@ -419,6 +420,23 @@ struct RtreeMatchArg {
|
||||
# define testcase(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Make sure that the compiler intrinsics we desire are enabled when
|
||||
** compiling with an appropriate version of MSVC unless prevented by
|
||||
** the SQLITE_DISABLE_INTRINSIC define.
|
||||
*/
|
||||
#if !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
# if defined(_MSC_VER) && _MSC_VER>=1400
|
||||
# if !defined(_WIN32_WCE)
|
||||
# include <intrin.h>
|
||||
# pragma intrinsic(_byteswap_ulong)
|
||||
# pragma intrinsic(_byteswap_uint64)
|
||||
# else
|
||||
# include <cmnintrin.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros to determine whether the machine is big or little endian,
|
||||
** and whether or not that determination is run-time or compile-time.
|
||||
|
||||
@@ -2956,8 +2956,13 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
|
||||
}
|
||||
|
||||
p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
|
||||
p->abPK = (u8*)&p->apValue[p->nCol*2];
|
||||
p->zTab = (char*)&p->abPK[p->nCol];
|
||||
if( p->apValue==0 ){
|
||||
p->abPK = 0;
|
||||
p->zTab = 0;
|
||||
}else{
|
||||
p->abPK = (u8*)&p->apValue[p->nCol*2];
|
||||
p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0;
|
||||
}
|
||||
return (p->rc = rc);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
ada43e7c490bf72a50ee84e1db994e149744b2a943260449076b83d1874813b2
|
||||
fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f
|
||||
+24
-16
@@ -1160,7 +1160,7 @@ static int renameEditSql(
|
||||
** successful. Otherwise, return an SQLite error code and leave an error
|
||||
** message in the Parse object.
|
||||
*/
|
||||
static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
||||
static int renameResolveTrigger(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
Trigger *pNew = pParse->pNewTrigger;
|
||||
TriggerStep *pStep;
|
||||
@@ -1191,17 +1191,22 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
||||
if( pParse->nErr ) rc = pParse->rc;
|
||||
}
|
||||
if( rc==SQLITE_OK && pStep->zTarget ){
|
||||
Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb);
|
||||
if( pTarget==0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){
|
||||
SrcList sSrc;
|
||||
memset(&sSrc, 0, sizeof(sSrc));
|
||||
sSrc.nSrc = 1;
|
||||
sSrc.a[0].zName = pStep->zTarget;
|
||||
sSrc.a[0].pTab = pTarget;
|
||||
sNC.pSrcList = &sSrc;
|
||||
if( pStep->pWhere ){
|
||||
SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
|
||||
if( pSrc ){
|
||||
int i;
|
||||
for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
|
||||
struct SrcList_item *p = &pSrc->a[i];
|
||||
p->pTab = sqlite3LocateTableItem(pParse, 0, p);
|
||||
p->iCursor = pParse->nTab++;
|
||||
if( p->pTab==0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
p->pTab->nTabRef++;
|
||||
rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
|
||||
}
|
||||
}
|
||||
sNC.pSrcList = pSrc;
|
||||
if( rc==SQLITE_OK && pStep->pWhere ){
|
||||
rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -1211,7 +1216,7 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
||||
if( pStep->pUpsert ){
|
||||
Upsert *pUpsert = pStep->pUpsert;
|
||||
assert( rc==SQLITE_OK );
|
||||
pUpsert->pUpsertSrc = &sSrc;
|
||||
pUpsert->pUpsertSrc = pSrc;
|
||||
sNC.uNC.pUpsert = pUpsert;
|
||||
sNC.ncFlags = NC_UUpsert;
|
||||
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
|
||||
@@ -1228,6 +1233,9 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
||||
sNC.ncFlags = 0;
|
||||
}
|
||||
sNC.pSrcList = 0;
|
||||
sqlite3SrcListDelete(db, pSrc);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1414,7 +1422,7 @@ static void renameColumnFunc(
|
||||
}else{
|
||||
/* A trigger */
|
||||
TriggerStep *pStep;
|
||||
rc = renameResolveTrigger(&sParse, (bTemp ? 0 : zDb));
|
||||
rc = renameResolveTrigger(&sParse);
|
||||
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
||||
|
||||
for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
@@ -1617,7 +1625,7 @@ static void renameTableFunc(
|
||||
}
|
||||
|
||||
if( isLegacy==0 ){
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
rc = renameResolveTrigger(&sParse);
|
||||
if( rc==SQLITE_OK ){
|
||||
renameWalkTrigger(&sWalker, pTrigger);
|
||||
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
@@ -1704,7 +1712,7 @@ static void renameTableTest(
|
||||
|
||||
else if( sParse.pNewTrigger ){
|
||||
if( isLegacy==0 ){
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
rc = renameResolveTrigger(&sParse);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
|
||||
|
||||
+4
-4
@@ -186,7 +186,7 @@ static void openStatTable(
|
||||
sqlite3 *db = pParse->db;
|
||||
Db *pDb;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int aRoot[ArraySize(aTable)];
|
||||
u32 aRoot[ArraySize(aTable)];
|
||||
u8 aCreateTbl[ArraySize(aTable)];
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
|
||||
@@ -215,7 +215,7 @@ static void openStatTable(
|
||||
sqlite3NestedParse(pParse,
|
||||
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
|
||||
);
|
||||
aRoot[i] = pParse->regRoot;
|
||||
aRoot[i] = (u32)pParse->regRoot;
|
||||
aCreateTbl[i] = OPFLAG_P2ISREG;
|
||||
}
|
||||
}else{
|
||||
@@ -235,7 +235,7 @@ static void openStatTable(
|
||||
#endif
|
||||
}else{
|
||||
/* The sqlite_stat[134] table already exists. Delete all rows. */
|
||||
sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +243,7 @@ static void openStatTable(
|
||||
/* Open the sqlite_stat[134] tables for writing. */
|
||||
for(i=0; i<nToOpen; i++){
|
||||
assert( i<ArraySize(aTable) );
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, (int)aRoot[i], iDb, 3);
|
||||
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
|
||||
VdbeComment((v, aTable[i].zName));
|
||||
}
|
||||
|
||||
@@ -599,6 +599,9 @@ int sqlite3FixTriggerStep(
|
||||
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
|
||||
return 1;
|
||||
}
|
||||
if( pStep->pFrom && sqlite3FixSrcList(pFix, pStep->pFrom) ){
|
||||
return 1;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
if( pStep->pUpsert ){
|
||||
Upsert *pUp = pStep->pUpsert;
|
||||
|
||||
+100
-65
@@ -2139,12 +2139,11 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){
|
||||
** error, return ((unsigned int)-1).
|
||||
*/
|
||||
static Pgno btreePagecount(BtShared *pBt){
|
||||
assert( (pBt->nPage & 0x80000000)==0 || CORRUPT_DB );
|
||||
return pBt->nPage;
|
||||
}
|
||||
u32 sqlite3BtreeLastPage(Btree *p){
|
||||
Pgno sqlite3BtreeLastPage(Btree *p){
|
||||
assert( sqlite3BtreeHoldsMutex(p) );
|
||||
return btreePagecount(p->pBt) & 0x7fffffff;
|
||||
return btreePagecount(p->pBt);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2932,8 +2931,8 @@ int sqlite3BtreeGetRequestedReserve(Btree *p){
|
||||
** No changes are made if mxPage is 0 or negative.
|
||||
** Regardless of the value of mxPage, return the maximum page count.
|
||||
*/
|
||||
int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
|
||||
int n;
|
||||
Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){
|
||||
Pgno n;
|
||||
sqlite3BtreeEnter(p);
|
||||
n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
|
||||
sqlite3BtreeLeave(p);
|
||||
@@ -3886,7 +3885,7 @@ int sqlite3BtreeIncrVacuum(Btree *p){
|
||||
Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
|
||||
Pgno nFin = finalDbSize(pBt, nOrig, nFree);
|
||||
|
||||
if( nOrig<nFin ){
|
||||
if( nOrig<nFin || nFree>=nOrig ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else if( nFree>0 ){
|
||||
rc = saveAllCursors(pBt, 0, 0);
|
||||
@@ -4372,7 +4371,7 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
|
||||
*/
|
||||
static int btreeCursor(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
Pgno iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
||||
BtCursor *pCur /* Space for new cursor */
|
||||
@@ -4415,7 +4414,7 @@ static int btreeCursor(
|
||||
|
||||
/* Now that no other errors can occur, finish filling in the BtCursor
|
||||
** variables and link the cursor into the BtShared list. */
|
||||
pCur->pgnoRoot = (Pgno)iTable;
|
||||
pCur->pgnoRoot = iTable;
|
||||
pCur->iPage = -1;
|
||||
pCur->pKeyInfo = pKeyInfo;
|
||||
pCur->pBtree = p;
|
||||
@@ -4425,7 +4424,7 @@ static int btreeCursor(
|
||||
/* If there are two or more cursors on the same btree, then all such
|
||||
** cursors *must* have the BTCF_Multiple flag set. */
|
||||
for(pX=pBt->pCursor; pX; pX=pX->pNext){
|
||||
if( pX->pgnoRoot==(Pgno)iTable ){
|
||||
if( pX->pgnoRoot==iTable ){
|
||||
pX->curFlags |= BTCF_Multiple;
|
||||
pCur->curFlags |= BTCF_Multiple;
|
||||
}
|
||||
@@ -4437,7 +4436,7 @@ static int btreeCursor(
|
||||
}
|
||||
static int btreeCursorWithLock(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
Pgno iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
||||
BtCursor *pCur /* Space for new cursor */
|
||||
@@ -4450,7 +4449,7 @@ static int btreeCursorWithLock(
|
||||
}
|
||||
int sqlite3BtreeCursor(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
Pgno iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
|
||||
BtCursor *pCur /* Write new cursor here */
|
||||
@@ -4836,7 +4835,7 @@ static int accessPayload(
|
||||
Pgno nextPage;
|
||||
|
||||
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
|
||||
|
||||
|
||||
/* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
|
||||
**
|
||||
** The aOverflow[] array is sized at one entry for each overflow page
|
||||
@@ -4875,6 +4874,7 @@ static int accessPayload(
|
||||
assert( rc==SQLITE_OK && amt>0 );
|
||||
while( nextPage ){
|
||||
/* If required, populate the overflow page-list cache. */
|
||||
if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT;
|
||||
assert( pCur->aOverflow[iIdx]==0
|
||||
|| pCur->aOverflow[iIdx]==nextPage
|
||||
|| CORRUPT_DB );
|
||||
@@ -6290,6 +6290,10 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
u32 nLeaf; /* Initial number of leaf cells on trunk page */
|
||||
|
||||
iTrunk = get4byte(&pPage1->aData[32]);
|
||||
if( iTrunk>btreePagecount(pBt) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto freepage_out;
|
||||
}
|
||||
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto freepage_out;
|
||||
@@ -8772,7 +8776,11 @@ int sqlite3BtreeInsert(
|
||||
assert( pPage->intKey || pX->nKey>=0 );
|
||||
assert( pPage->leaf || !pPage->intKey );
|
||||
if( pPage->nFree<0 ){
|
||||
rc = btreeComputeFreeSpace(pPage);
|
||||
if( pCur->eState>CURSOR_INVALID ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
rc = btreeComputeFreeSpace(pPage);
|
||||
}
|
||||
if( rc ) return rc;
|
||||
}
|
||||
|
||||
@@ -9090,7 +9098,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
|
||||
** BTREE_ZERODATA Used for SQL indices
|
||||
*/
|
||||
static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
|
||||
BtShared *pBt = p->pBt;
|
||||
MemPage *pRoot;
|
||||
Pgno pgnoRoot;
|
||||
@@ -9123,6 +9131,9 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
** created so far, so the new root-page is (meta[3]+1).
|
||||
*/
|
||||
sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
|
||||
if( pgnoRoot>btreePagecount(pBt) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
pgnoRoot++;
|
||||
|
||||
/* The new root-page may not be allocated on a pointer-map page, or the
|
||||
@@ -9132,8 +9143,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
|
||||
pgnoRoot++;
|
||||
}
|
||||
assert( pgnoRoot>=3 || CORRUPT_DB );
|
||||
testcase( pgnoRoot<3 );
|
||||
assert( pgnoRoot>=3 );
|
||||
|
||||
/* Allocate a page. The page that currently resides at pgnoRoot will
|
||||
** be moved to the allocated page (unless the allocated page happens
|
||||
@@ -9230,10 +9240,10 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
zeroPage(pRoot, ptfFlags);
|
||||
sqlite3PagerUnref(pRoot->pDbPage);
|
||||
assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
|
||||
*piTable = (int)pgnoRoot;
|
||||
*piTable = pgnoRoot;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
|
||||
int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){
|
||||
int rc;
|
||||
sqlite3BtreeEnter(p);
|
||||
rc = btreeCreateTable(p, piTable, flags);
|
||||
@@ -9632,7 +9642,7 @@ static void checkAppendMsg(
|
||||
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
|
||||
va_end(ap);
|
||||
if( pCheck->errMsg.accError==SQLITE_NOMEM ){
|
||||
pCheck->mallocFailed = 1;
|
||||
pCheck->bOomFault = 1;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
@@ -9697,7 +9707,7 @@ static void checkPtrmap(
|
||||
|
||||
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1;
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1;
|
||||
checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
|
||||
return;
|
||||
}
|
||||
@@ -9717,7 +9727,7 @@ static void checkPtrmap(
|
||||
static void checkList(
|
||||
IntegrityCk *pCheck, /* Integrity checking context */
|
||||
int isFreeList, /* True for a freelist. False for overflow page list */
|
||||
int iPage, /* Page number for first page in the list */
|
||||
Pgno iPage, /* Page number for first page in the list */
|
||||
u32 N /* Expected number of pages in the list */
|
||||
){
|
||||
int i;
|
||||
@@ -9849,7 +9859,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
|
||||
*/
|
||||
static int checkTreePage(
|
||||
IntegrityCk *pCheck, /* Context for the sanity check */
|
||||
int iPage, /* Page number of the page to check */
|
||||
Pgno iPage, /* Page number of the page to check */
|
||||
i64 *piMinKey, /* Write minimum integer primary key here */
|
||||
i64 maxKey /* Error if integer primary key greater than this */
|
||||
){
|
||||
@@ -9885,9 +9895,9 @@ static int checkTreePage(
|
||||
usableSize = pBt->usableSize;
|
||||
if( iPage==0 ) return 0;
|
||||
if( checkRef(pCheck, iPage) ) return 0;
|
||||
pCheck->zPfx = "Page %d: ";
|
||||
pCheck->zPfx = "Page %u: ";
|
||||
pCheck->v1 = iPage;
|
||||
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
|
||||
if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
|
||||
checkAppendMsg(pCheck,
|
||||
"unable to get the page. error code=%d", rc);
|
||||
goto end_of_check;
|
||||
@@ -9912,7 +9922,7 @@ static int checkTreePage(
|
||||
hdr = pPage->hdrOffset;
|
||||
|
||||
/* Set up for cell analysis */
|
||||
pCheck->zPfx = "On tree page %d cell %d: ";
|
||||
pCheck->zPfx = "On tree page %u cell %d: ";
|
||||
contentOffset = get2byteNotZero(&data[hdr+5]);
|
||||
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
|
||||
|
||||
@@ -9932,7 +9942,7 @@ static int checkTreePage(
|
||||
pgno = get4byte(&data[hdr+8]);
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum ){
|
||||
pCheck->zPfx = "On page %d at right child: ";
|
||||
pCheck->zPfx = "On page %u at right child: ";
|
||||
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
|
||||
}
|
||||
#endif
|
||||
@@ -10073,7 +10083,7 @@ static int checkTreePage(
|
||||
while( btreeHeapPull(heap,&x) ){
|
||||
if( (prev&0xffff)>=(x>>16) ){
|
||||
checkAppendMsg(pCheck,
|
||||
"Multiple uses for byte %u of page %d", x>>16, iPage);
|
||||
"Multiple uses for byte %u of page %u", x>>16, iPage);
|
||||
break;
|
||||
}else{
|
||||
nFrag += (x>>16) - (prev&0xffff) - 1;
|
||||
@@ -10088,7 +10098,7 @@ static int checkTreePage(
|
||||
*/
|
||||
if( heap[0]==0 && nFrag!=data[hdr+7] ){
|
||||
checkAppendMsg(pCheck,
|
||||
"Fragmentation of %d bytes reported as %d on page %d",
|
||||
"Fragmentation of %d bytes reported as %d on page %u",
|
||||
nFrag, data[hdr+7], iPage);
|
||||
}
|
||||
}
|
||||
@@ -10116,11 +10126,20 @@ end_of_check:
|
||||
** allocation errors, an error message held in memory obtained from
|
||||
** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is
|
||||
** returned. If a memory allocation error occurs, NULL is returned.
|
||||
**
|
||||
** If the first entry in aRoot[] is 0, that indicates that the list of
|
||||
** root pages is incomplete. This is a "partial integrity-check". This
|
||||
** happens when performing an integrity check on a single table. The
|
||||
** zero is skipped, of course. But in addition, the freelist checks
|
||||
** and the checks to make sure every page is referenced are also skipped,
|
||||
** since obviously it is not possible to know which pages are covered by
|
||||
** the unverified btrees. Except, if aRoot[1] is 1, then the freelist
|
||||
** checks are still performed.
|
||||
*/
|
||||
char *sqlite3BtreeIntegrityCheck(
|
||||
sqlite3 *db, /* Database connection that is running the check */
|
||||
Btree *p, /* The btree to be checked */
|
||||
int *aRoot, /* An array of root pages numbers for individual trees */
|
||||
Pgno *aRoot, /* An array of root pages numbers for individual trees */
|
||||
int nRoot, /* Number of entries in aRoot[] */
|
||||
int mxErr, /* Stop reporting errors after this many */
|
||||
int *pnErr /* Write number of errors seen to this variable */
|
||||
@@ -10130,7 +10149,17 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
BtShared *pBt = p->pBt;
|
||||
u64 savedDbFlags = pBt->db->flags;
|
||||
char zErr[100];
|
||||
int bPartial = 0; /* True if not checking all btrees */
|
||||
int bCkFreelist = 1; /* True to scan the freelist */
|
||||
VVA_ONLY( int nRef );
|
||||
assert( nRoot>0 );
|
||||
|
||||
/* aRoot[0]==0 means this is a partial check */
|
||||
if( aRoot[0]==0 ){
|
||||
assert( nRoot>1 );
|
||||
bPartial = 1;
|
||||
if( aRoot[1]!=1 ) bCkFreelist = 0;
|
||||
}
|
||||
|
||||
sqlite3BtreeEnter(p);
|
||||
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
|
||||
@@ -10142,7 +10171,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
sCheck.nPage = btreePagecount(sCheck.pBt);
|
||||
sCheck.mxErr = mxErr;
|
||||
sCheck.nErr = 0;
|
||||
sCheck.mallocFailed = 0;
|
||||
sCheck.bOomFault = 0;
|
||||
sCheck.zPfx = 0;
|
||||
sCheck.v1 = 0;
|
||||
sCheck.v2 = 0;
|
||||
@@ -10156,12 +10185,12 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
|
||||
sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
|
||||
if( !sCheck.aPgRef ){
|
||||
sCheck.mallocFailed = 1;
|
||||
sCheck.bOomFault = 1;
|
||||
goto integrity_ck_cleanup;
|
||||
}
|
||||
sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
|
||||
if( sCheck.heap==0 ){
|
||||
sCheck.mallocFailed = 1;
|
||||
sCheck.bOomFault = 1;
|
||||
goto integrity_ck_cleanup;
|
||||
}
|
||||
|
||||
@@ -10170,29 +10199,33 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
|
||||
/* Check the integrity of the freelist
|
||||
*/
|
||||
sCheck.zPfx = "Main freelist: ";
|
||||
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
|
||||
get4byte(&pBt->pPage1->aData[36]));
|
||||
sCheck.zPfx = 0;
|
||||
if( bCkFreelist ){
|
||||
sCheck.zPfx = "Main freelist: ";
|
||||
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
|
||||
get4byte(&pBt->pPage1->aData[36]));
|
||||
sCheck.zPfx = 0;
|
||||
}
|
||||
|
||||
/* Check all the tables.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum ){
|
||||
int mx = 0;
|
||||
int mxInHdr;
|
||||
for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
|
||||
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
|
||||
if( mx!=mxInHdr ){
|
||||
if( !bPartial ){
|
||||
if( pBt->autoVacuum ){
|
||||
Pgno mx = 0;
|
||||
Pgno mxInHdr;
|
||||
for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
|
||||
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
|
||||
if( mx!=mxInHdr ){
|
||||
checkAppendMsg(&sCheck,
|
||||
"max rootpage (%d) disagrees with header (%d)",
|
||||
mx, mxInHdr
|
||||
);
|
||||
}
|
||||
}else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
|
||||
checkAppendMsg(&sCheck,
|
||||
"max rootpage (%d) disagrees with header (%d)",
|
||||
mx, mxInHdr
|
||||
"incremental_vacuum enabled with a max rootpage of zero"
|
||||
);
|
||||
}
|
||||
}else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
|
||||
checkAppendMsg(&sCheck,
|
||||
"incremental_vacuum enabled with a max rootpage of zero"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
testcase( pBt->db->flags & SQLITE_CellSizeCk );
|
||||
@@ -10201,7 +10234,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
i64 notUsed;
|
||||
if( aRoot[i]==0 ) continue;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum && aRoot[i]>1 ){
|
||||
if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
|
||||
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
|
||||
}
|
||||
#endif
|
||||
@@ -10211,24 +10244,26 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
|
||||
/* Make sure every page in the file is referenced
|
||||
*/
|
||||
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
|
||||
if( !bPartial ){
|
||||
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
if( getPageReferenced(&sCheck, i)==0 ){
|
||||
checkAppendMsg(&sCheck, "Page %d is never used", i);
|
||||
}
|
||||
if( getPageReferenced(&sCheck, i)==0 ){
|
||||
checkAppendMsg(&sCheck, "Page %d is never used", i);
|
||||
}
|
||||
#else
|
||||
/* If the database supports auto-vacuum, make sure no tables contain
|
||||
** references to pointer-map pages.
|
||||
*/
|
||||
if( getPageReferenced(&sCheck, i)==0 &&
|
||||
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
|
||||
checkAppendMsg(&sCheck, "Page %d is never used", i);
|
||||
}
|
||||
if( getPageReferenced(&sCheck, i)!=0 &&
|
||||
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
|
||||
checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
|
||||
}
|
||||
/* If the database supports auto-vacuum, make sure no tables contain
|
||||
** references to pointer-map pages.
|
||||
*/
|
||||
if( getPageReferenced(&sCheck, i)==0 &&
|
||||
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
|
||||
checkAppendMsg(&sCheck, "Page %d is never used", i);
|
||||
}
|
||||
if( getPageReferenced(&sCheck, i)!=0 &&
|
||||
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
|
||||
checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up and report errors.
|
||||
@@ -10236,7 +10271,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
integrity_ck_cleanup:
|
||||
sqlite3PageFree(sCheck.heap);
|
||||
sqlite3_free(sCheck.aPgRef);
|
||||
if( sCheck.mallocFailed ){
|
||||
if( sCheck.bOomFault ){
|
||||
sqlite3_str_reset(&sCheck.errMsg);
|
||||
sCheck.nErr++;
|
||||
}
|
||||
|
||||
+5
-5
@@ -71,8 +71,8 @@ int sqlite3BtreeSetSpillSize(Btree*,int);
|
||||
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
||||
int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeMaxPageCount(Btree*,int);
|
||||
u32 sqlite3BtreeLastPage(Btree*);
|
||||
Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno);
|
||||
Pgno sqlite3BtreeLastPage(Btree*);
|
||||
int sqlite3BtreeSecureDelete(Btree*,int);
|
||||
int sqlite3BtreeGetRequestedReserve(Btree*);
|
||||
int sqlite3BtreeGetReserveNoMutex(Btree *p);
|
||||
@@ -84,7 +84,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree*, int);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*,int,int);
|
||||
int sqlite3BtreeBeginStmt(Btree*,int);
|
||||
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
||||
int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags);
|
||||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
int sqlite3BtreeIsInReadTrans(Btree*);
|
||||
int sqlite3BtreeIsInBackup(Btree*);
|
||||
@@ -225,7 +225,7 @@ int sqlite3BtreeNewDb(Btree *p);
|
||||
|
||||
int sqlite3BtreeCursor(
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
Pgno iTable, /* Index of root page */
|
||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
struct KeyInfo*, /* First argument to compare function */
|
||||
BtCursor *pCursor /* Space to write cursor structure */
|
||||
@@ -316,7 +316,7 @@ const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
|
||||
u32 sqlite3BtreePayloadSize(BtCursor*);
|
||||
sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
|
||||
|
||||
char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,int*aRoot,int nRoot,int,int*);
|
||||
char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
i64 sqlite3BtreeRowCountEst(BtCursor*);
|
||||
|
||||
|
||||
+3
-2
@@ -679,9 +679,10 @@ struct IntegrityCk {
|
||||
Pgno nPage; /* Number of pages in the database */
|
||||
int mxErr; /* Stop accumulating errors when this reaches zero */
|
||||
int nErr; /* Number of messages written to zErrMsg so far */
|
||||
int mallocFailed; /* A memory allocation error has occurred */
|
||||
int bOomFault; /* A memory allocation error has occurred */
|
||||
const char *zPfx; /* Error message prefix */
|
||||
int v1, v2; /* Values for up to two %d fields in zPfx */
|
||||
Pgno v1; /* Value for first %u substitution in zPfx */
|
||||
int v2; /* Value for second %d substitution in zPfx */
|
||||
StrAccum errMsg; /* Accumulate the error message text here */
|
||||
u32 *heap; /* Min-heap used for analyzing cell coverage */
|
||||
sqlite3 *db; /* Database connection running the check */
|
||||
|
||||
+40
-23
@@ -31,7 +31,7 @@
|
||||
*/
|
||||
struct TableLock {
|
||||
int iDb; /* The database containing the table to be locked */
|
||||
int iTab; /* The root page of the table to be locked */
|
||||
Pgno iTab; /* The root page of the table to be locked */
|
||||
u8 isWriteLock; /* True for write lock. False for a read lock */
|
||||
const char *zLockName; /* Name of the table */
|
||||
};
|
||||
@@ -49,7 +49,7 @@ struct TableLock {
|
||||
void sqlite3TableLock(
|
||||
Parse *pParse, /* Parsing context */
|
||||
int iDb, /* Index of the database containing the table to lock */
|
||||
int iTab, /* Root page number of the table to be locked */
|
||||
Pgno iTab, /* Root page number of the table to be locked */
|
||||
u8 isWriteLock, /* True for a write lock */
|
||||
const char *zName /* Name of the table to be locked */
|
||||
){
|
||||
@@ -888,7 +888,10 @@ int sqlite3CheckObjectName(
|
||||
const char *zTblName /* Parent table name for triggers and indexes */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( sqlite3WritableSchema(db) || db->init.imposterTable ){
|
||||
if( sqlite3WritableSchema(db)
|
||||
|| db->init.imposterTable
|
||||
|| !sqlite3Config.bExtraSchemaChecks
|
||||
){
|
||||
/* Skip these error checks for writable_schema=ON */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -897,10 +900,8 @@ int sqlite3CheckObjectName(
|
||||
|| sqlite3_stricmp(zName, db->init.azInit[1])
|
||||
|| sqlite3_stricmp(zTblName, db->init.azInit[2])
|
||||
){
|
||||
if( sqlite3Config.bExtraSchemaChecks ){
|
||||
sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}else{
|
||||
if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
|
||||
@@ -2114,7 +2115,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
** a database schema). */
|
||||
if( v && pPk->tnum>0 ){
|
||||
assert( db->init.busy==0 );
|
||||
sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
|
||||
sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto);
|
||||
}
|
||||
|
||||
/* The root page of the PRIMARY KEY is the table root page */
|
||||
@@ -2702,10 +2703,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
assert( pTable->pSelect );
|
||||
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
|
||||
if( pSel ){
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
u8 eParseMode = pParse->eParseMode;
|
||||
pParse->eParseMode = PARSE_MODE_NORMAL;
|
||||
#endif
|
||||
n = pParse->nTab;
|
||||
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
||||
pTable->nCol = -1;
|
||||
@@ -2753,9 +2752,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
sqlite3DeleteTable(db, pSelTab);
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
EnableLookaside;
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
pParse->eParseMode = eParseMode;
|
||||
#endif
|
||||
} else {
|
||||
nErr++;
|
||||
}
|
||||
@@ -2810,7 +2807,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
|
||||
** in order to be certain that we got the right one.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
|
||||
void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
|
||||
HashElem *pElem;
|
||||
Hash *pHash;
|
||||
Db *pDb;
|
||||
@@ -2887,18 +2884,18 @@ static void destroyTable(Parse *pParse, Table *pTab){
|
||||
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
|
||||
** a free-list page.
|
||||
*/
|
||||
int iTab = pTab->tnum;
|
||||
int iDestroyed = 0;
|
||||
Pgno iTab = pTab->tnum;
|
||||
Pgno iDestroyed = 0;
|
||||
|
||||
while( 1 ){
|
||||
Index *pIdx;
|
||||
int iLargest = 0;
|
||||
Pgno iLargest = 0;
|
||||
|
||||
if( iDestroyed==0 || iTab<iDestroyed ){
|
||||
iLargest = iTab;
|
||||
}
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int iIdx = pIdx->tnum;
|
||||
Pgno iIdx = pIdx->tnum;
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
|
||||
iLargest = iIdx;
|
||||
@@ -3321,7 +3318,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
int iSorter; /* Cursor opened by OpenSorter (if in use) */
|
||||
int addr1; /* Address of top of loop */
|
||||
int addr2; /* Address to jump to for next iteration */
|
||||
int tnum; /* Root page of index */
|
||||
Pgno tnum; /* Root page of index */
|
||||
int iPartIdxLabel; /* Jump to this label to skip a row */
|
||||
Vdbe *v; /* Generate code into this virtual machine */
|
||||
KeyInfo *pKey; /* KeyInfo for index */
|
||||
@@ -3342,7 +3339,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
if( memRootPage>=0 ){
|
||||
tnum = memRootPage;
|
||||
tnum = (Pgno)memRootPage;
|
||||
}else{
|
||||
tnum = pIndex->tnum;
|
||||
}
|
||||
@@ -3367,7 +3364,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
|
||||
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb,
|
||||
(char *)pKey, P4_KEYINFO);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
|
||||
|
||||
@@ -3976,7 +3973,7 @@ void sqlite3CreateIndex(
|
||||
** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
|
||||
** that case the convertToWithoutRowidTable() routine will replace
|
||||
** the Noop with a Goto to jump over the VDBE code generated below. */
|
||||
pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
|
||||
pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop);
|
||||
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
|
||||
|
||||
/* Gather the complete text of the CREATE INDEX statement into
|
||||
@@ -4018,7 +4015,7 @@ void sqlite3CreateIndex(
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
||||
}
|
||||
|
||||
sqlite3VdbeJumpHere(v, pIndex->tnum);
|
||||
sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
|
||||
}
|
||||
}
|
||||
if( db->init.busy || pTblName==0 ){
|
||||
@@ -4093,7 +4090,7 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
** table but other parts we are having to guess at, then do not let the
|
||||
** estimated number of rows in the table be less than 1000 (LogEst 99).
|
||||
** Failure to do this can cause the indexes for which we do not have
|
||||
** stat1 data to be ignored by the query planner. tag-20200527-1
|
||||
** stat1 data to be ignored by the query planner.
|
||||
*/
|
||||
x = pIdx->pTable->nRowLogEst;
|
||||
assert( 99==sqlite3LogEst(1000) );
|
||||
@@ -4569,6 +4566,26 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Append the contents of SrcList p2 to SrcList p1 and return the resulting
|
||||
** SrcList. Or, if an error occurs, return NULL. In all cases, p1 and p2
|
||||
** are deleted by this function.
|
||||
*/
|
||||
SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){
|
||||
assert( p1 && p1->nSrc==1 );
|
||||
if( p2 ){
|
||||
SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1);
|
||||
if( pNew==0 ){
|
||||
sqlite3SrcListDelete(pParse->db, p2);
|
||||
}else{
|
||||
p1 = pNew;
|
||||
memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(struct SrcList_item));
|
||||
sqlite3DbFree(pParse->db, p2);
|
||||
}
|
||||
}
|
||||
return p1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the list of function arguments to the SrcList entry for a
|
||||
** table-valued-function.
|
||||
|
||||
+2
-2
@@ -1112,8 +1112,8 @@ static void strftimeFunc(
|
||||
case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
|
||||
case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
|
||||
case 's': {
|
||||
sqlite3_snprintf(30,&z[j],"%lld",
|
||||
(i64)(x.iJD/1000 - 21086676*(i64)10000));
|
||||
i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
|
||||
sqlite3Int64ToText(iS, &z[j]);
|
||||
j += sqlite3Strlen30(&z[j]);
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
struct SrcList_item *pItem = pSrc->a;
|
||||
Table *pTab;
|
||||
assert( pItem && pSrc->nSrc==1 );
|
||||
assert( pItem && pSrc->nSrc>=1 );
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
|
||||
sqlite3DeleteTable(pParse->db, pItem->pTab);
|
||||
pItem->pTab = pTab;
|
||||
|
||||
+14
-14
@@ -52,12 +52,10 @@ char sqlite3ExprAffinity(const Expr *pExpr){
|
||||
op = pExpr->op;
|
||||
if( op==TK_SELECT ){
|
||||
assert( pExpr->flags&EP_xIsSelect );
|
||||
if( ALWAYS(pExpr->x.pSelect)
|
||||
&& pExpr->x.pSelect->pEList
|
||||
&& ALWAYS(pExpr->x.pSelect->pEList->a[0].pExpr)
|
||||
){
|
||||
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||
}
|
||||
assert( pExpr->x.pSelect!=0 );
|
||||
assert( pExpr->x.pSelect->pEList!=0 );
|
||||
assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
|
||||
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||
}
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
@@ -200,7 +198,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
|
||||
&& ALWAYS(!ExprHasProperty(p, EP_xIsSelect))
|
||||
){
|
||||
int i;
|
||||
for(i=0; i<p->x.pList->nExpr; i++){
|
||||
for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
|
||||
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
|
||||
pNext = p->x.pList->a[i].pExpr;
|
||||
break;
|
||||
@@ -2031,7 +2029,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
if( sqlite3ExprIdToTrueFalse(pExpr) ){
|
||||
return WRC_Prune;
|
||||
}
|
||||
/* Fall thru */
|
||||
/* no break */ deliberate_fall_through
|
||||
case TK_COLUMN:
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_AGG_COLUMN:
|
||||
@@ -2045,7 +2043,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
|
||||
return WRC_Continue;
|
||||
}
|
||||
/* Fall through */
|
||||
/* no break */ deliberate_fall_through
|
||||
case TK_IF_NULL_ROW:
|
||||
case TK_REGISTER:
|
||||
case TK_DOT:
|
||||
@@ -2066,7 +2064,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
pWalker->eCode = 0;
|
||||
return WRC_Abort;
|
||||
}
|
||||
/* Fall through */
|
||||
/* no break */ deliberate_fall_through
|
||||
default:
|
||||
testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
|
||||
testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
|
||||
@@ -3838,6 +3836,7 @@ expr_code_doover:
|
||||
return target;
|
||||
}
|
||||
/* Otherwise, fall thru into the TK_COLUMN case */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
int iTab = pExpr->iTable;
|
||||
@@ -4903,7 +4902,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
testcase( op==TK_ISNOT );
|
||||
op = (op==TK_IS) ? TK_EQ : TK_NE;
|
||||
jumpIfNull = SQLITE_NULLEQ;
|
||||
/* Fall thru */
|
||||
/* no break */ deliberate_fall_through
|
||||
case TK_LT:
|
||||
case TK_LE:
|
||||
case TK_GT:
|
||||
@@ -5079,7 +5078,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
testcase( pExpr->op==TK_ISNOT );
|
||||
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
|
||||
jumpIfNull = SQLITE_NULLEQ;
|
||||
/* Fall thru */
|
||||
/* no break */ deliberate_fall_through
|
||||
case TK_LT:
|
||||
case TK_LE:
|
||||
case TK_GT:
|
||||
@@ -5391,13 +5390,13 @@ static int exprImpliesNotNull(
|
||||
case TK_RSHIFT:
|
||||
case TK_CONCAT:
|
||||
seenNot = 1;
|
||||
/* Fall thru */
|
||||
/* no break */ deliberate_fall_through
|
||||
case TK_STAR:
|
||||
case TK_REM:
|
||||
case TK_BITAND:
|
||||
case TK_SLASH: {
|
||||
if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
|
||||
/* Fall thru into the next case */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case TK_SPAN:
|
||||
case TK_COLLATE:
|
||||
@@ -5546,6 +5545,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
){
|
||||
return WRC_Prune;
|
||||
}
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
default:
|
||||
return WRC_Continue;
|
||||
|
||||
@@ -1359,6 +1359,7 @@ static Trigger *fkActionTrigger(
|
||||
pStep->op = TK_DELETE;
|
||||
break;
|
||||
}
|
||||
/* no break */ deliberate_fall_through
|
||||
default:
|
||||
pStep->op = TK_UPDATE;
|
||||
}
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@ int sqlite3PendingByte = 0x40000000;
|
||||
/*
|
||||
** Flags for select tracing and the ".selecttrace" macro of the CLI
|
||||
*/
|
||||
/**/ u32 sqlite3SelectTrace = 0;
|
||||
u32 sqlite3_unsupported_selecttrace = 0;
|
||||
|
||||
#include "opcodes.h"
|
||||
/*
|
||||
|
||||
+5
-5
@@ -180,7 +180,7 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
|
||||
assert( pOp!=0 );
|
||||
if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
|
||||
Index *pIndex;
|
||||
int tnum = pOp->p2;
|
||||
Pgno tnum = pOp->p2;
|
||||
if( tnum==pTab->tnum ){
|
||||
return 1;
|
||||
}
|
||||
@@ -1612,7 +1612,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
case OE_Abort:
|
||||
sqlite3MayAbort(pParse);
|
||||
/* Fall through */
|
||||
/* no break */ deliberate_fall_through
|
||||
case OE_Rollback:
|
||||
case OE_Fail: {
|
||||
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
|
||||
@@ -1840,7 +1840,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
switch( onError ){
|
||||
default: {
|
||||
onError = OE_Abort;
|
||||
/* Fall thru into the next case */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case OE_Rollback:
|
||||
case OE_Abort:
|
||||
@@ -1901,7 +1901,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
case OE_Update: {
|
||||
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
|
||||
/* Fall through */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
#endif
|
||||
case OE_Ignore: {
|
||||
@@ -2122,7 +2122,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
case OE_Update: {
|
||||
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
|
||||
/* Fall through */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
#endif
|
||||
case OE_Ignore: {
|
||||
|
||||
+10
-4
@@ -100,7 +100,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
|
||||
** contains the text of SQLITE_VERSION macro.
|
||||
** contains the text of SQLITE_VERSION macro.
|
||||
*/
|
||||
const char sqlite3_version[] = SQLITE_VERSION;
|
||||
#endif
|
||||
@@ -1202,7 +1202,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( db->mTrace & SQLITE_TRACE_CLOSE ){
|
||||
db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
|
||||
db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
|
||||
}
|
||||
|
||||
/* Force xDisconnect calls on all virtual tables */
|
||||
@@ -2091,7 +2091,7 @@ void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
pOld = db->pTraceArg;
|
||||
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
|
||||
db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
|
||||
db->trace.xLegacy = xTrace;
|
||||
db->pTraceArg = pArg;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return pOld;
|
||||
@@ -2115,7 +2115,7 @@ int sqlite3_trace_v2(
|
||||
if( mTrace==0 ) xTrace = 0;
|
||||
if( xTrace==0 ) mTrace = 0;
|
||||
db->mTrace = mTrace;
|
||||
db->xTrace = xTrace;
|
||||
db->trace.xV2 = xTrace;
|
||||
db->pTraceArg = pArg;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
@@ -4091,6 +4091,12 @@ int sqlite3_test_control(int op, ...){
|
||||
** Set or clear a flag that causes SQLite to verify that type, name,
|
||||
** and tbl_name fields of the sqlite_schema table. This is normally
|
||||
** on, but it is sometimes useful to turn it off for testing.
|
||||
**
|
||||
** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the
|
||||
** verification of rootpage numbers when parsing the schema. This
|
||||
** is useful to make it easier to reach strange internal error states
|
||||
** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled
|
||||
** in production.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
|
||||
sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
|
||||
|
||||
+2
-4
@@ -719,11 +719,9 @@ char *sqlite3DbStrDup(sqlite3 *db, const char *z){
|
||||
char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
|
||||
char *zNew;
|
||||
assert( db!=0 );
|
||||
if( z==0 ){
|
||||
return 0;
|
||||
}
|
||||
assert( z!=0 || n==0 );
|
||||
assert( (n&0x7fffffff)==n );
|
||||
zNew = sqlite3DbMallocRawNN(db, n+1);
|
||||
zNew = z ? sqlite3DbMallocRawNN(db, n+1) : 0;
|
||||
if( zNew ){
|
||||
memcpy(zNew, z, (size_t)n);
|
||||
zNew[n] = 0;
|
||||
|
||||
+3
-3
@@ -379,7 +379,7 @@ void sqlite3MemSetDefault(void){
|
||||
** Set the "type" of an allocation.
|
||||
*/
|
||||
void sqlite3MemdebugSetType(void *p, u8 eType){
|
||||
if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
||||
if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
|
||||
struct MemBlockHdr *pHdr;
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
assert( pHdr->iForeGuard==FOREGUARD );
|
||||
@@ -398,7 +398,7 @@ void sqlite3MemdebugSetType(void *p, u8 eType){
|
||||
*/
|
||||
int sqlite3MemdebugHasType(void *p, u8 eType){
|
||||
int rc = 1;
|
||||
if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
||||
if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
|
||||
struct MemBlockHdr *pHdr;
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
|
||||
@@ -420,7 +420,7 @@ int sqlite3MemdebugHasType(void *p, u8 eType){
|
||||
*/
|
||||
int sqlite3MemdebugNoType(void *p, u8 eType){
|
||||
int rc = 1;
|
||||
if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
||||
if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
|
||||
struct MemBlockHdr *pHdr;
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
|
||||
|
||||
+1
-1
@@ -339,7 +339,7 @@ static int memdbOpen(
|
||||
p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
|
||||
assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
|
||||
*pOutFlags = flags | SQLITE_OPEN_MEMORY;
|
||||
p->base.pMethods = &memdb_io_methods;
|
||||
pFile->pMethods = &memdb_io_methods;
|
||||
p->szMax = sqlite3GlobalConfig.mxMemdbSize;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+2
-2
@@ -366,7 +366,7 @@ int sqlite3JournalOpen(
|
||||
assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
|
||||
}
|
||||
|
||||
p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
|
||||
pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods;
|
||||
p->nSpill = nSpill;
|
||||
p->flags = flags;
|
||||
p->zJournal = zName;
|
||||
@@ -392,7 +392,7 @@ void sqlite3MemJournalOpen(sqlite3_file *pJfd){
|
||||
int sqlite3JournalCreate(sqlite3_file *pJfd){
|
||||
int rc = SQLITE_OK;
|
||||
MemJournal *p = (MemJournal*)pJfd;
|
||||
if( p->pMethod==&MemJournalMethods && (
|
||||
if( pJfd->pMethods==&MemJournalMethods && (
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
p->nSpill>0
|
||||
#else
|
||||
|
||||
+1
-1
@@ -5692,7 +5692,7 @@ static int fillInUnixFile(
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( h>=0 ) robust_close(pNew, h, __LINE__);
|
||||
}else{
|
||||
pNew->pMethod = pLockingStyle;
|
||||
pId->pMethods = pLockingStyle;
|
||||
OpenCounter(+1);
|
||||
verifyDbFile(pNew);
|
||||
}
|
||||
|
||||
+1
-1
@@ -5266,7 +5266,7 @@ static int winOpen(
|
||||
}
|
||||
|
||||
sqlite3_free(zTmpname);
|
||||
pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
|
||||
id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod;
|
||||
pFile->pVfs = pVfs;
|
||||
pFile->h = h;
|
||||
if( isReadonly ){
|
||||
|
||||
+6
-10
@@ -786,11 +786,6 @@ static const unsigned char aJournalMagic[] = {
|
||||
# define USEFETCH(x) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum legal page number is (2^31 - 1).
|
||||
*/
|
||||
#define PAGER_MAX_PGNO 2147483647
|
||||
|
||||
/*
|
||||
** The argument to this macro is a file descriptor (type sqlite3_file*).
|
||||
** Return 0 if it is not open, or non-zero (but not 1) if it is.
|
||||
@@ -2497,12 +2492,13 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
|
||||
** If successful, open the super-journal file for reading.
|
||||
*/
|
||||
pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
|
||||
pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
|
||||
if( !pSuper ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
pJournal = 0;
|
||||
}else{
|
||||
const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
|
||||
rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
|
||||
pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto delsuper_out;
|
||||
|
||||
@@ -3763,7 +3759,7 @@ void *sqlite3PagerTempSpace(Pager *pPager){
|
||||
**
|
||||
** Regardless of mxPage, return the current maximum page count.
|
||||
*/
|
||||
int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
|
||||
Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){
|
||||
if( mxPage>0 ){
|
||||
pPager->mxPgno = mxPage;
|
||||
}
|
||||
@@ -5490,7 +5486,7 @@ static int getPageNormal(
|
||||
if( pPg->pPager && !noContent ){
|
||||
/* In this case the pcache already contains an initialized copy of
|
||||
** the page. Return without further ado. */
|
||||
assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
|
||||
assert( pgno!=PAGER_MJ_PGNO(pPager) );
|
||||
pPager->aStat[PAGER_STAT_HIT]++;
|
||||
return SQLITE_OK;
|
||||
|
||||
@@ -5498,10 +5494,10 @@ static int getPageNormal(
|
||||
/* The pager cache has created a new page. Its content needs to
|
||||
** be initialized. But first some error checks:
|
||||
**
|
||||
** (1) The maximum page number is 2^31
|
||||
** (*) obsolete. Was: maximum page number is 2^31
|
||||
** (2) Never try to fetch the locking page
|
||||
*/
|
||||
if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
|
||||
if( pgno==PAGER_MJ_PGNO(pPager) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto pager_acquire_err;
|
||||
}
|
||||
|
||||
+1
-1
@@ -128,7 +128,7 @@ int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
|
||||
/* Functions used to configure a Pager object. */
|
||||
void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
|
||||
int sqlite3PagerSetPagesize(Pager*, u32*, int);
|
||||
int sqlite3PagerMaxPageCount(Pager*, int);
|
||||
Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
|
||||
void sqlite3PagerSetCachesize(Pager*, int);
|
||||
int sqlite3PagerSetSpillsize(Pager*, int);
|
||||
void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
|
||||
|
||||
+50
-19
@@ -111,6 +111,27 @@ static void disableLookaside(Parse *pParse){
|
||||
DisableLookaside;
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \
|
||||
&& defined(SQLITE_UDL_CAPABLE_PARSER)
|
||||
/*
|
||||
** Issue an error message if an ORDER BY or LIMIT clause occurs on an
|
||||
** UPDATE or DELETE statement.
|
||||
*/
|
||||
static void updateDeleteLimitError(
|
||||
Parse *pParse,
|
||||
ExprList *pOrderBy,
|
||||
Expr *pLimit
|
||||
){
|
||||
if( pOrderBy ){
|
||||
sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\"");
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\"");
|
||||
}
|
||||
sqlite3ExprListDelete(pParse->db, pOrderBy);
|
||||
sqlite3ExprDelete(pParse->db, pLimit);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */
|
||||
|
||||
} // end %include
|
||||
|
||||
// Input is a single SQL command
|
||||
@@ -448,7 +469,7 @@ cmd ::= DROP VIEW ifexists(E) fullname(X). {
|
||||
//////////////////////// The SELECT statement /////////////////////////////////
|
||||
//
|
||||
cmd ::= select(X). {
|
||||
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
|
||||
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
|
||||
sqlite3Select(pParse, X, &dest);
|
||||
sqlite3SelectDelete(pParse->db, X);
|
||||
}
|
||||
@@ -637,7 +658,7 @@ as(X) ::= . {X.n = 0; X.z = 0;}
|
||||
|
||||
// A complete FROM clause.
|
||||
//
|
||||
from(A) ::= . {A = sqlite3DbMallocZero(pParse->db, sizeof(*A));}
|
||||
from(A) ::= . {A = 0;}
|
||||
from(A) ::= FROM seltablist(X). {
|
||||
A = X;
|
||||
sqlite3SrcListShiftJoinType(A);
|
||||
@@ -840,18 +861,20 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
|
||||
|
||||
/////////////////////////// The DELETE statement /////////////////////////////
|
||||
//
|
||||
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
|
||||
cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W)
|
||||
orderby_opt(O) limit_opt(L). {
|
||||
sqlite3SrcListIndexedBy(pParse, X, &I);
|
||||
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
sqlite3ExprListDelete(pParse->db, O); O = 0;
|
||||
sqlite3ExprDelete(pParse->db, L); L = 0;
|
||||
if( O || L ){
|
||||
updateDeleteLimitError(pParse,O,L);
|
||||
O = 0;
|
||||
L = 0;
|
||||
}
|
||||
#endif
|
||||
sqlite3DeleteFrom(pParse,X,W,O,L);
|
||||
}
|
||||
%endif
|
||||
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
%else
|
||||
cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W). {
|
||||
sqlite3SrcListIndexedBy(pParse, X, &I);
|
||||
sqlite3DeleteFrom(pParse,X,W,0,0);
|
||||
@@ -866,23 +889,33 @@ where_opt(A) ::= WHERE expr(X). {A = X;}
|
||||
|
||||
////////////////////////// The UPDATE command ////////////////////////////////
|
||||
//
|
||||
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y)
|
||||
%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
|
||||
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
|
||||
where_opt(W) orderby_opt(O) limit_opt(L). {
|
||||
sqlite3SrcListIndexedBy(pParse, X, &I);
|
||||
X = sqlite3SrcListAppendList(pParse, X, F);
|
||||
sqlite3ExprListCheckLength(pParse,Y,"set list");
|
||||
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
if( O || L ){
|
||||
updateDeleteLimitError(pParse,O,L);
|
||||
O = 0;
|
||||
L = 0;
|
||||
}
|
||||
#endif
|
||||
sqlite3Update(pParse,X,Y,W,R,O,L,0);
|
||||
}
|
||||
%endif
|
||||
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y)
|
||||
where_opt(W). {
|
||||
%else
|
||||
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
|
||||
where_opt(W). {
|
||||
sqlite3SrcListIndexedBy(pParse, X, &I);
|
||||
sqlite3ExprListCheckLength(pParse,Y,"set list");
|
||||
X = sqlite3SrcListAppendList(pParse, X, F);
|
||||
sqlite3Update(pParse,X,Y,W,R,0,0,0);
|
||||
}
|
||||
%endif
|
||||
|
||||
|
||||
|
||||
%type setlist {ExprList*}
|
||||
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
|
||||
|
||||
@@ -1370,16 +1403,14 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
|
||||
|
||||
///////////////////////////// The VACUUM command /////////////////////////////
|
||||
//
|
||||
%ifndef SQLITE_OMIT_VACUUM
|
||||
%ifndef SQLITE_OMIT_ATTACH
|
||||
%if !SQLITE_OMIT_VACUUM && !SQLITE_OMIT_ATTACH
|
||||
%type vinto {Expr*}
|
||||
%destructor vinto {sqlite3ExprDelete(pParse->db, $$);}
|
||||
cmd ::= VACUUM vinto(Y). {sqlite3Vacuum(pParse,0,Y);}
|
||||
cmd ::= VACUUM nm(X) vinto(Y). {sqlite3Vacuum(pParse,&X,Y);}
|
||||
vinto(A) ::= INTO expr(X). {A = X;}
|
||||
vinto(A) ::= . {A = 0;}
|
||||
%endif SQLITE_OMIT_ATTACH
|
||||
%endif SQLITE_OMIT_VACUUM
|
||||
%endif
|
||||
|
||||
///////////////////////////// The PRAGMA command /////////////////////////////
|
||||
//
|
||||
@@ -1486,8 +1517,8 @@ tridxby ::= NOT INDEXED. {
|
||||
%destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);}
|
||||
// UPDATE
|
||||
trigger_cmd(A) ::=
|
||||
UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z) scanpt(E).
|
||||
{A = sqlite3TriggerUpdateStep(pParse, &X, Y, Z, R, B.z, E);}
|
||||
UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) from(F) where_opt(Z) scanpt(E).
|
||||
{A = sqlite3TriggerUpdateStep(pParse, &X, F, Y, Z, R, B.z, E);}
|
||||
|
||||
// INSERT
|
||||
trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO
|
||||
|
||||
+46
-16
@@ -611,13 +611,19 @@ void sqlite3Pragma(
|
||||
*/
|
||||
case PragTyp_PAGE_COUNT: {
|
||||
int iReg;
|
||||
i64 x = 0;
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
iReg = ++pParse->nMem;
|
||||
if( sqlite3Tolower(zLeft[0])=='p' ){
|
||||
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
|
||||
sqlite3AbsInt32(sqlite3Atoi(zRight)));
|
||||
if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){
|
||||
if( x<0 ) x = 0;
|
||||
else if( x>0xfffffffe ) x = 0xfffffffe;
|
||||
}else{
|
||||
x = 0;
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
|
||||
break;
|
||||
@@ -1138,15 +1144,14 @@ void sqlite3Pragma(
|
||||
*/
|
||||
case PragTyp_TABLE_INFO: if( zRight ){
|
||||
Table *pTab;
|
||||
sqlite3CodeVerifyNamedSchema(pParse, zDb);
|
||||
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
|
||||
if( pTab ){
|
||||
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
int i, k;
|
||||
int nHidden = 0;
|
||||
Column *pCol;
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
pParse->nMem = 7;
|
||||
sqlite3CodeVerifySchema(pParse, iTabDb);
|
||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
int isHidden = 0;
|
||||
@@ -1403,7 +1408,6 @@ void sqlite3Pragma(
|
||||
regRow = ++pParse->nMem;
|
||||
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
|
||||
while( k ){
|
||||
int iTabDb;
|
||||
if( zRight ){
|
||||
pTab = sqlite3LocateTable(pParse, 0, zRight, zDb);
|
||||
k = 0;
|
||||
@@ -1412,23 +1416,24 @@ void sqlite3Pragma(
|
||||
k = sqliteHashNext(k);
|
||||
}
|
||||
if( pTab==0 || pTab->pFKey==0 ) continue;
|
||||
iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3CodeVerifySchema(pParse, iTabDb);
|
||||
sqlite3TableLock(pParse, iTabDb, pTab->tnum, 0, pTab->zName);
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
zDb = db->aDb[iDb].zDbSName;
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
|
||||
sqlite3OpenTable(pParse, 0, iTabDb, pTab, OP_OpenRead);
|
||||
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
|
||||
sqlite3VdbeLoadString(v, regResult, pTab->zName);
|
||||
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
||||
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
|
||||
if( pParent==0 ) continue;
|
||||
pIdx = 0;
|
||||
sqlite3TableLock(pParse, iTabDb, pParent->tnum, 0, pParent->zName);
|
||||
sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName);
|
||||
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0);
|
||||
if( x==0 ){
|
||||
if( pIdx==0 ){
|
||||
sqlite3OpenTable(pParse, i, iTabDb, pParent, OP_OpenRead);
|
||||
sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iTabDb);
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb);
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||
}
|
||||
}else{
|
||||
@@ -1521,9 +1526,22 @@ void sqlite3Pragma(
|
||||
** integrity_check designed to detect most database corruption
|
||||
** without the overhead of cross-checking indexes. Quick_check
|
||||
** is linear time wherease integrity_check is O(NlogN).
|
||||
**
|
||||
** The maximum nubmer of errors is 100 by default. A different default
|
||||
** can be specified using a numeric parameter N.
|
||||
**
|
||||
** Or, the parameter N can be the name of a table. In that case, only
|
||||
** the one table named is verified. The freelist is only verified if
|
||||
** the named table is "sqlite_schema" (or one of its aliases).
|
||||
**
|
||||
** All schemas are checked by default. To check just a single
|
||||
** schema, use the form:
|
||||
**
|
||||
** PRAGMA schema.integrity_check;
|
||||
*/
|
||||
case PragTyp_INTEGRITY_CHECK: {
|
||||
int i, j, addr, mxErr;
|
||||
Table *pObjTab = 0; /* Check only this one table, if not NULL */
|
||||
|
||||
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
|
||||
|
||||
@@ -1546,9 +1564,13 @@ void sqlite3Pragma(
|
||||
/* Set the maximum error count */
|
||||
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
||||
if( zRight ){
|
||||
sqlite3GetInt32(zRight, &mxErr);
|
||||
if( mxErr<=0 ){
|
||||
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
||||
if( sqlite3GetInt32(zRight, &mxErr) ){
|
||||
if( mxErr<=0 ){
|
||||
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
||||
}
|
||||
}else{
|
||||
pObjTab = sqlite3LocateTable(pParse, 0, zRight,
|
||||
iDb>=0 ? db->aDb[iDb].zDbSName : 0);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
|
||||
@@ -1577,15 +1599,21 @@ void sqlite3Pragma(
|
||||
Table *pTab = sqliteHashData(x); /* Current table */
|
||||
Index *pIdx; /* An index on pTab */
|
||||
int nIdx; /* Number of indexes on pTab */
|
||||
if( pObjTab && pObjTab!=pTab ) continue;
|
||||
if( HasRowid(pTab) ) cnt++;
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
|
||||
if( nIdx>mxIdx ) mxIdx = nIdx;
|
||||
}
|
||||
if( cnt==0 ) continue;
|
||||
if( pObjTab ) cnt++;
|
||||
aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
|
||||
if( aRoot==0 ) break;
|
||||
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
cnt = 0;
|
||||
if( pObjTab ) aRoot[++cnt] = 0;
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
if( pObjTab && pObjTab!=pTab ) continue;
|
||||
if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
aRoot[++cnt] = pIdx->tnum;
|
||||
@@ -1619,6 +1647,7 @@ void sqlite3Pragma(
|
||||
int r1 = -1;
|
||||
|
||||
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
|
||||
if( pObjTab && pObjTab!=pTab ) continue;
|
||||
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
|
||||
1, 0, &iDataCur, &iIdxCur);
|
||||
@@ -1890,6 +1919,7 @@ void sqlite3Pragma(
|
||||
aOp[1].p1 = iDb;
|
||||
aOp[1].p2 = iCookie;
|
||||
aOp[1].p3 = sqlite3Atoi(zRight);
|
||||
aOp[1].p5 = 1;
|
||||
}else{
|
||||
/* Read the specified cookie value */
|
||||
static const VdbeOpList readCookie[] = {
|
||||
|
||||
+1
-1
@@ -281,7 +281,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
{/* zName: */ "foreign_key_check",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 37, 4,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
|
||||
+17
-4
@@ -115,7 +115,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
|
||||
assert( db->init.busy );
|
||||
db->init.iDb = iDb;
|
||||
db->init.newTnum = sqlite3Atoi(argv[3]);
|
||||
if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0
|
||||
|| (db->init.newTnum>pData->mxPage && pData->mxPage>0)
|
||||
){
|
||||
if( sqlite3Config.bExtraSchemaChecks ){
|
||||
corruptSchema(pData, argv[1], "invalid rootpage");
|
||||
}
|
||||
}
|
||||
db->init.orphanTrigger = 0;
|
||||
db->init.azInit = argv;
|
||||
pStmt = 0;
|
||||
@@ -148,12 +154,17 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
*/
|
||||
Index *pIndex;
|
||||
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
|
||||
if( pIndex==0
|
||||
|| sqlite3GetInt32(argv[3],&pIndex->tnum)==0
|
||||
if( pIndex==0 ){
|
||||
corruptSchema(pData, argv[1], "orphan index");
|
||||
}else
|
||||
if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
|
||||
|| pIndex->tnum<2
|
||||
|| pIndex->tnum>pData->mxPage
|
||||
|| sqlite3IndexHasDuplicateRootPage(pIndex)
|
||||
){
|
||||
corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index");
|
||||
if( sqlite3Config.bExtraSchemaChecks ){
|
||||
corruptSchema(pData, argv[1], "invalid rootpage");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -207,6 +218,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
initData.mInitFlags = mFlags;
|
||||
initData.nInitRow = 0;
|
||||
initData.mxPage = 0;
|
||||
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
|
||||
db->mDbFlags &= mask;
|
||||
if( initData.rc ){
|
||||
@@ -329,6 +341,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
/* Read the schema information out of the schema tables
|
||||
*/
|
||||
assert( db->init.busy );
|
||||
initData.mxPage = sqlite3BtreeLastPage(pDb->pBt);
|
||||
{
|
||||
char *zSql;
|
||||
zSql = sqlite3MPrintf(db,
|
||||
|
||||
+2
-2
@@ -407,11 +407,11 @@ void sqlite3_str_vappendf(
|
||||
case etPOINTER:
|
||||
flag_long = sizeof(char*)==sizeof(i64) ? 2 :
|
||||
sizeof(char*)==sizeof(long int) ? 1 : 0;
|
||||
/* Fall through into the next case */
|
||||
/* no break */ deliberate_fall_through
|
||||
case etORDINAL:
|
||||
case etRADIX:
|
||||
cThousand = 0;
|
||||
/* Fall through into the next case */
|
||||
/* no break */ deliberate_fall_through
|
||||
case etDECIMAL:
|
||||
if( infop->flags & FLAG_SIGNED ){
|
||||
i64 v;
|
||||
|
||||
+14
-11
@@ -16,6 +16,11 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Magic table number to mean the EXCLUDED table in an UPSERT statement.
|
||||
*/
|
||||
#define EXCLUDED_TABLE_NUMBER 2
|
||||
|
||||
/*
|
||||
** Walk the expression tree pExpr and increase the aggregate function
|
||||
** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node.
|
||||
@@ -386,7 +391,7 @@ static int lookupName(
|
||||
Upsert *pUpsert = pNC->uNC.pUpsert;
|
||||
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
|
||||
pTab = pUpsert->pUpsertSrc->a[0].pTab;
|
||||
pExpr->iTable = 2;
|
||||
pExpr->iTable = EXCLUDED_TABLE_NUMBER;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UPSERT */
|
||||
@@ -411,14 +416,15 @@ static int lookupName(
|
||||
if( iCol<pTab->nCol ){
|
||||
cnt++;
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
if( pExpr->iTable==2 ){
|
||||
if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){
|
||||
testcase( iCol==(-1) );
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pExpr->iColumn = iCol;
|
||||
pExpr->y.pTab = pTab;
|
||||
eNewExprOp = TK_COLUMN;
|
||||
}else{
|
||||
pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
|
||||
pExpr->iTable = pNC->uNC.pUpsert->regData +
|
||||
sqlite3TableColumnToStorage(pTab, iCol);
|
||||
eNewExprOp = TK_REGISTER;
|
||||
ExprSetProperty(pExpr, EP_Alias);
|
||||
}
|
||||
@@ -750,26 +756,23 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
#endif
|
||||
switch( pExpr->op ){
|
||||
|
||||
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
|
||||
/* The special operator TK_ROW means use the rowid for the first
|
||||
** column in the FROM clause. This is used by the LIMIT and ORDER BY
|
||||
** clause processing on UPDATE and DELETE statements.
|
||||
** clause processing on UPDATE and DELETE statements, and by
|
||||
** UPDATE ... FROM statement processing.
|
||||
*/
|
||||
case TK_ROW: {
|
||||
SrcList *pSrcList = pNC->pSrcList;
|
||||
struct SrcList_item *pItem;
|
||||
assert( pSrcList && pSrcList->nSrc==1 );
|
||||
assert( pSrcList && pSrcList->nSrc>=1 );
|
||||
pItem = pSrcList->a;
|
||||
assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 );
|
||||
pExpr->op = TK_COLUMN;
|
||||
pExpr->y.pTab = pItem->pTab;
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pExpr->iColumn = -1;
|
||||
pExpr->iColumn--;
|
||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||
break;
|
||||
}
|
||||
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
||||
&& !defined(SQLITE_OMIT_SUBQUERY) */
|
||||
|
||||
/* A column name: ID
|
||||
** Or table name and column name: ID.ID
|
||||
@@ -1081,7 +1084,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Continue;
|
||||
}
|
||||
}
|
||||
/* Fall thru */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case TK_BETWEEN:
|
||||
case TK_EQ:
|
||||
|
||||
+92
-45
@@ -103,6 +103,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
||||
void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
|
||||
pDest->eDest = (u8)eDest;
|
||||
pDest->iSDParm = iParm;
|
||||
pDest->iSDParm2 = 0;
|
||||
pDest->zAffSdst = 0;
|
||||
pDest->iSdst = 0;
|
||||
pDest->nSdst = 0;
|
||||
@@ -175,21 +176,6 @@ void sqlite3SelectDelete(sqlite3 *db, Select *p){
|
||||
if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete all the substructure for p, but keep p allocated. Redefine
|
||||
** p to be a single SELECT where every column of the result set has a
|
||||
** value of NULL.
|
||||
*/
|
||||
void sqlite3SelectReset(Parse *pParse, Select *p){
|
||||
if( ALWAYS(p) ){
|
||||
clearSelect(pParse->db, p, 0);
|
||||
memset(&p->iLimit, 0, sizeof(Select) - offsetof(Select,iLimit));
|
||||
p->pEList = sqlite3ExprListAppend(pParse, 0,
|
||||
sqlite3ExprAlloc(pParse->db,TK_NULL,0,0));
|
||||
p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(SrcList));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the right-most SELECT statement in a compound.
|
||||
*/
|
||||
@@ -278,8 +264,10 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
|
||||
*/
|
||||
static int columnIndex(Table *pTab, const char *zCol){
|
||||
int i;
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
|
||||
u8 h = sqlite3StrIHash(zCol);
|
||||
Column *pCol;
|
||||
for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){
|
||||
if( pCol->hName==h && sqlite3StrICmp(pCol->zName, zCol)==0 ) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -990,7 +978,8 @@ static void selectInnerLoop(
|
||||
testcase( eDest==SRT_Coroutine );
|
||||
testcase( eDest==SRT_Output );
|
||||
assert( eDest==SRT_Set || eDest==SRT_Mem
|
||||
|| eDest==SRT_Coroutine || eDest==SRT_Output );
|
||||
|| eDest==SRT_Coroutine || eDest==SRT_Output
|
||||
|| eDest==SRT_Upfrom );
|
||||
}
|
||||
sRowLoadInfo.regResult = regResult;
|
||||
sRowLoadInfo.ecelFlags = ecelFlags;
|
||||
@@ -1139,6 +1128,30 @@ static void selectInnerLoop(
|
||||
break;
|
||||
}
|
||||
|
||||
case SRT_Upfrom: {
|
||||
if( pSort ){
|
||||
pushOntoSorter(
|
||||
pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
|
||||
}else{
|
||||
int i2 = pDest->iSDParm2;
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
|
||||
/* If the UPDATE FROM join is an aggregate that matches no rows, it
|
||||
** might still be trying to return one row, because that is what
|
||||
** aggregates do. Don't record that empty row in the output table. */
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v);
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord,
|
||||
regResult+(i2<0), nResultCol-(i2<0), r1);
|
||||
if( i2<0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
/* If we are creating a set for an "expr IN (SELECT ...)" construct,
|
||||
** then there should be a single item on the stack. Write this
|
||||
@@ -1163,6 +1176,7 @@ static void selectInnerLoop(
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* If any row exist in the result set, record that fact and abort.
|
||||
*/
|
||||
case SRT_Exists: {
|
||||
@@ -1570,6 +1584,17 @@ static void generateSortTail(
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case SRT_Upfrom: {
|
||||
int i2 = pDest->iSDParm2;
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1);
|
||||
if( i2<0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regRow);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert( eDest==SRT_Output || eDest==SRT_Coroutine );
|
||||
testcase( eDest==SRT_Output );
|
||||
@@ -3156,7 +3181,7 @@ static int multiSelectOrderBy(
|
||||
sqlite3 *db; /* Database connection */
|
||||
ExprList *pOrderBy; /* The ORDER BY clause */
|
||||
int nOrderBy; /* Number of terms in the ORDER BY clause */
|
||||
int *aPermute; /* Mapping from ORDER BY terms to result set columns */
|
||||
u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */
|
||||
|
||||
assert( p->pOrderBy!=0 );
|
||||
assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
|
||||
@@ -3205,7 +3230,7 @@ static int multiSelectOrderBy(
|
||||
** to the right and the left are evaluated, they use the correct
|
||||
** collation.
|
||||
*/
|
||||
aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
|
||||
aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
|
||||
if( aPermute ){
|
||||
struct ExprList_item *pItem;
|
||||
aPermute[0] = nOrderBy;
|
||||
@@ -4161,7 +4186,7 @@ static int flattenSubquery(
|
||||
sqlite3SelectDelete(db, pSub1);
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x100 ){
|
||||
SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
@@ -4984,8 +5009,8 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
||||
Table *pTab;
|
||||
assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
|
||||
if( pFrom->fg.isRecursive ) continue;
|
||||
assert( pFrom->pTab==0 );
|
||||
if( pFrom->pTab ) continue;
|
||||
assert( pFrom->fg.isRecursive==0 );
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
if( withExpand(pWalker, pFrom) ) return WRC_Abort;
|
||||
if( pFrom->pTab ) {} else
|
||||
@@ -5451,15 +5476,19 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
||||
Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
|
||||
if( pAggInfo->nAccumulator
|
||||
&& (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
|
||||
&& regAcc
|
||||
){
|
||||
/* If regAcc==0, there there exists some min() or max() function
|
||||
** without a FILTER clause that will ensure the magnet registers
|
||||
** are populated. */
|
||||
if( regHit==0 ) regHit = ++pParse->nMem;
|
||||
/* If this is the first row of the group (regAcc==0), clear the
|
||||
/* If this is the first row of the group (regAcc contains 0), clear the
|
||||
** "magnet" register regHit so that the accumulator registers
|
||||
** are populated if the FILTER clause jumps over the the
|
||||
** invocation of min() or max() altogether. Or, if this is not
|
||||
** the first row (regAcc==1), set the magnet register so that the
|
||||
** accumulators are not populated unless the min()/max() is invoked and
|
||||
** indicates that they should be. */
|
||||
** the first row (regAcc contains 1), set the magnet register so that
|
||||
** the accumulators are not populated unless the min()/max() is invoked
|
||||
** and indicates that they should be. */
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit);
|
||||
}
|
||||
addrNext = sqlite3VdbeMakeLabel(pParse);
|
||||
@@ -5595,7 +5624,7 @@ static void havingToWhere(Parse *pParse, Select *p){
|
||||
sWalker.u.pSelect = p;
|
||||
sqlite3WalkExpr(&sWalker, p->pHaving);
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){
|
||||
if( sWalker.eCode && (sqlite3_unsupported_selecttrace & 0x100)!=0 ){
|
||||
SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
@@ -5717,7 +5746,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
p->selFlags &= ~SF_Aggregate;
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x400 ){
|
||||
SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
@@ -5770,7 +5799,7 @@ int sqlite3Select(
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x100 ){
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
@@ -5797,12 +5826,30 @@ int sqlite3Select(
|
||||
}
|
||||
assert( p->pEList!=0 );
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x104 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x104 ){
|
||||
SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the SF_UpdateFrom flag is set, then this function is being called
|
||||
** as part of populating the temp table for an UPDATE...FROM statement.
|
||||
** In this case, it is an error if the target object (pSrc->a[0]) name
|
||||
** or alias is duplicated within FROM clause (pSrc->a[1..n]). */
|
||||
if( p->selFlags & SF_UpdateFrom ){
|
||||
struct SrcList_item *p0 = &p->pSrc->a[0];
|
||||
for(i=1; i<p->pSrc->nSrc; i++){
|
||||
struct SrcList_item *p1 = &p->pSrc->a[i];
|
||||
if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"target object/alias may not appear in FROM clause: %s",
|
||||
p0->zAlias ? p0->zAlias : p0->pTab->zName
|
||||
);
|
||||
goto select_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pDest->eDest==SRT_Output ){
|
||||
generateColumnNames(pParse, p);
|
||||
}
|
||||
@@ -5814,7 +5861,7 @@ int sqlite3Select(
|
||||
goto select_end;
|
||||
}
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
|
||||
if( p->pWin && (sqlite3_unsupported_selecttrace & 0x108)!=0 ){
|
||||
SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
@@ -5921,7 +5968,7 @@ int sqlite3Select(
|
||||
rc = multiSelect(pParse, p, pDest);
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
|
||||
if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
||||
if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
@@ -5940,7 +5987,7 @@ int sqlite3Select(
|
||||
&& propagateConstants(pParse, p)
|
||||
){
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x100 ){
|
||||
SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
@@ -6028,7 +6075,7 @@ int sqlite3Select(
|
||||
(pItem->fg.jointype & JT_OUTER)!=0)
|
||||
){
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x100 ){
|
||||
SELECTTRACE(0x100,pParse,p,
|
||||
("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
@@ -6128,7 +6175,7 @@ int sqlite3Select(
|
||||
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x400 ){
|
||||
SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
@@ -6164,7 +6211,7 @@ int sqlite3Select(
|
||||
assert( sDistinct.isTnct );
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x400 ){
|
||||
SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
@@ -6412,7 +6459,7 @@ int sqlite3Select(
|
||||
pAggInfo->mxReg = pParse->nMem;
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
if( sqlite3_unsupported_selecttrace & 0x400 ){
|
||||
int ii;
|
||||
SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
@@ -6676,7 +6723,7 @@ int sqlite3Select(
|
||||
Index *pIdx; /* Iterator variable */
|
||||
KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
|
||||
Index *pBest = 0; /* Best index found so far */
|
||||
int iRoot = pTab->tnum; /* Root page of scanned b-tree */
|
||||
Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */
|
||||
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
@@ -6708,7 +6755,7 @@ int sqlite3Select(
|
||||
}
|
||||
|
||||
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1);
|
||||
if( pKeyInfo ){
|
||||
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
|
||||
}
|
||||
@@ -6717,6 +6764,7 @@ int sqlite3Select(
|
||||
explainSimpleCount(pParse, pTab, pBest);
|
||||
}else{
|
||||
int regAcc = 0; /* "populate accumulators" flag */
|
||||
int addrSkip;
|
||||
|
||||
/* If there are accumulator registers but no min() or max() functions
|
||||
** without FILTER clauses, allocate register regAcc. Register regAcc
|
||||
@@ -6765,10 +6813,9 @@ int sqlite3Select(
|
||||
}
|
||||
updateAccumulator(pParse, regAcc, pAggInfo);
|
||||
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
|
||||
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
||||
sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
|
||||
VdbeComment((v, "%s() by index",
|
||||
(minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
|
||||
addrSkip = sqlite3WhereOrderByLimitOptLabel(pWInfo);
|
||||
if( addrSkip!=sqlite3WhereContinueLabel(pWInfo) ){
|
||||
sqlite3VdbeGoto(v, addrSkip);
|
||||
}
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
finalizeAggFunctions(pParse, pAggInfo);
|
||||
@@ -6831,7 +6878,7 @@ select_end:
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(0x1,pParse,p,("end processing\n"));
|
||||
if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
||||
if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
+50
-20
@@ -623,6 +623,21 @@ static int strlenChar(const char *z){
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if zFile does not exist or if it is not an ordinary file.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
# define notNormalFile(X) 0
|
||||
#else
|
||||
static int notNormalFile(const char *zFile){
|
||||
struct stat x;
|
||||
int rc;
|
||||
memset(&x, 0, sizeof(x));
|
||||
rc = stat(zFile, &x);
|
||||
return rc || !S_ISREG(x.st_mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine reads a line of text from FILE in, stores
|
||||
** the text in memory obtained from malloc() and returns a pointer
|
||||
@@ -2866,7 +2881,7 @@ static void explain_data_delete(ShellState *p){
|
||||
** Disable and restore .wheretrace and .selecttrace settings.
|
||||
*/
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
extern int sqlite3SelectTrace;
|
||||
extern unsigned int sqlite3_unsupported_selecttrace;
|
||||
static int savedSelectTrace;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
|
||||
@@ -2875,8 +2890,8 @@ static int savedWhereTrace;
|
||||
#endif
|
||||
static void disable_debug_trace_modes(void){
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
savedSelectTrace = sqlite3SelectTrace;
|
||||
sqlite3SelectTrace = 0;
|
||||
savedSelectTrace = sqlite3_unsupported_selecttrace;
|
||||
sqlite3_unsupported_selecttrace = 0;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
|
||||
savedWhereTrace = sqlite3WhereTrace;
|
||||
@@ -2885,7 +2900,7 @@ static void disable_debug_trace_modes(void){
|
||||
}
|
||||
static void restore_debug_trace_modes(void){
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
sqlite3SelectTrace = savedSelectTrace;
|
||||
sqlite3_unsupported_selecttrace = savedSelectTrace;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
|
||||
sqlite3WhereTrace = savedWhereTrace;
|
||||
@@ -3036,25 +3051,38 @@ static void exec_prepared_stmt_columnar(
|
||||
ShellState *p, /* Pointer to ShellState */
|
||||
sqlite3_stmt *pStmt /* Statment to run */
|
||||
){
|
||||
int nRow = 0;
|
||||
sqlite3_int64 nRow = 0;
|
||||
int nColumn = 0;
|
||||
char **azData = 0;
|
||||
char *zMsg = 0;
|
||||
sqlite3_int64 nAlloc = 0;
|
||||
const char *z;
|
||||
int rc;
|
||||
int i, j, nTotal, w, n;
|
||||
sqlite3_int64 i, nData;
|
||||
int j, nTotal, w, n;
|
||||
const char *colSep = 0;
|
||||
const char *rowSep = 0;
|
||||
|
||||
rc = sqlite3_get_table(p->db, sqlite3_sql(pStmt),
|
||||
&azData, &nRow, &nColumn, &zMsg);
|
||||
if( rc ){
|
||||
utf8_printf(p->out, "ERROR: %s\n", zMsg);
|
||||
sqlite3_free(zMsg);
|
||||
sqlite3_free_table(azData);
|
||||
return;
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc!=SQLITE_ROW ) return;
|
||||
nColumn = sqlite3_column_count(pStmt);
|
||||
nAlloc = nColumn*4;
|
||||
azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
|
||||
if( azData==0 ) shell_out_of_memory();
|
||||
for(i=0; i<nColumn; i++){
|
||||
azData[i] = strdup(sqlite3_column_name(pStmt,i));
|
||||
}
|
||||
if( nRow==0 || nColumn==0 ) goto columnar_end;
|
||||
do{
|
||||
if( (nRow+2)*nColumn >= nAlloc ){
|
||||
nAlloc *= 2;
|
||||
azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
|
||||
if( azData==0 ) shell_out_of_memory();
|
||||
}
|
||||
nRow++;
|
||||
for(i=0; i<nColumn; i++){
|
||||
z = (const char*)sqlite3_column_text(pStmt,i);
|
||||
azData[nRow*nColumn + i] = z ? strdup(z) : 0;
|
||||
}
|
||||
}while( (rc = sqlite3_step(pStmt))==SQLITE_ROW );
|
||||
if( nColumn>p->nWidth ){
|
||||
p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
|
||||
if( p->colWidth==0 ) shell_out_of_memory();
|
||||
@@ -3164,7 +3192,9 @@ columnar_end:
|
||||
if( seenInterrupt ){
|
||||
utf8_printf(p->out, "Interrupt\n");
|
||||
}
|
||||
sqlite3_free_table(azData);
|
||||
nData = (nRow+1)*nColumn;
|
||||
for(i=0; i<nData; i++) free(azData[i]);
|
||||
sqlite3_free(azData);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -8136,7 +8166,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
while( (nSkip--)>0 ){
|
||||
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
|
||||
sCtx.nLine++;
|
||||
}
|
||||
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
|
||||
if( zSql==0 ){
|
||||
@@ -8933,8 +8962,9 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
p->in = fopen(azArg[1], "rb");
|
||||
if( p->in==0 ){
|
||||
if( notNormalFile(azArg[1])
|
||||
|| (p->in = fopen(azArg[1], "rb"))==0
|
||||
){
|
||||
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
|
||||
rc = 1;
|
||||
}else{
|
||||
@@ -9140,7 +9170,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
|
||||
sqlite3SelectTrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
|
||||
sqlite3_unsupported_selecttrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
|
||||
}else
|
||||
#endif
|
||||
|
||||
|
||||
+44
-21
@@ -128,6 +128,15 @@
|
||||
# define _BSD_SOURCE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro to disable warnings about missing "break" at the end of a "case".
|
||||
*/
|
||||
#if GCC_VERSION>=7000000
|
||||
# define deliberate_fall_through __attribute__((fallthrough));
|
||||
#else
|
||||
# define deliberate_fall_through
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For MinGW, check to see if we can include the header file containing its
|
||||
** version information, among other things. Normally, this internal MinGW
|
||||
@@ -902,6 +911,7 @@ typedef INT16_TYPE LogEst;
|
||||
** compilers.
|
||||
*/
|
||||
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
||||
#define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32))
|
||||
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
||||
|
||||
/*
|
||||
@@ -982,7 +992,7 @@ typedef INT16_TYPE LogEst;
|
||||
#if defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
# define SELECTTRACE_ENABLED 1
|
||||
# define SELECTTRACE(K,P,S,X) \
|
||||
if(sqlite3SelectTrace&(K)) \
|
||||
if(sqlite3_unsupported_selecttrace&(K)) \
|
||||
sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
|
||||
sqlite3DebugPrintf X
|
||||
#else
|
||||
@@ -1045,7 +1055,7 @@ struct BusyHandler {
|
||||
** pointer will work here as long as it is distinct from SQLITE_STATIC
|
||||
** and SQLITE_TRANSIENT.
|
||||
*/
|
||||
#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize)
|
||||
#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault)
|
||||
|
||||
/*
|
||||
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
|
||||
@@ -1185,9 +1195,9 @@ typedef int VList;
|
||||
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
|
||||
** pointer types (i.e. FuncDef) defined above.
|
||||
*/
|
||||
#include "pager.h"
|
||||
#include "btree.h"
|
||||
#include "vdbe.h"
|
||||
#include "pager.h"
|
||||
#include "pcache.h"
|
||||
#include "os.h"
|
||||
#include "mutex.h"
|
||||
@@ -1481,7 +1491,7 @@ struct sqlite3 {
|
||||
int aLimit[SQLITE_N_LIMIT]; /* Limits */
|
||||
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
|
||||
struct sqlite3InitInfo { /* Information used during initialization */
|
||||
int newTnum; /* Rootpage of table being initialized */
|
||||
Pgno newTnum; /* Rootpage of table being initialized */
|
||||
u8 iDb; /* Which db file is being initialized */
|
||||
u8 busy; /* TRUE if currently initializing */
|
||||
unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
|
||||
@@ -1496,7 +1506,10 @@ struct sqlite3 {
|
||||
int nVDestroy; /* Number of active OP_VDestroy operations */
|
||||
int nExtension; /* Number of loaded extensions */
|
||||
void **aExtension; /* Array of shared library handles */
|
||||
int (*xTrace)(u32,void*,void*,void*); /* Trace function */
|
||||
union {
|
||||
void (*xLegacy)(void*,const char*); /* Legacy trace function */
|
||||
int (*xV2)(u32,void*,void*,void*); /* V2 Trace function */
|
||||
} trace;
|
||||
void *pTraceArg; /* Argument to the trace function */
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
void (*xProfile)(void*,const char*,u64); /* Profiling function */
|
||||
@@ -2120,7 +2133,7 @@ struct Table {
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
ExprList *pCheck; /* All CHECK constraints */
|
||||
/* ... also used as column name list in a VIEW */
|
||||
int tnum; /* Root BTree page for this table */
|
||||
Pgno tnum; /* Root BTree page for this table */
|
||||
u32 nTabRef; /* Number of pointers to this Table */
|
||||
u32 tabFlags; /* Mask of TF_* values */
|
||||
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
|
||||
@@ -2413,7 +2426,7 @@ struct Index {
|
||||
const char **azColl; /* Array of collation sequence names for index */
|
||||
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
|
||||
ExprList *aColExpr; /* Column expressions */
|
||||
int tnum; /* DB Page containing root of this index */
|
||||
Pgno tnum; /* DB Page containing root of this index */
|
||||
LogEst szIdxRow; /* Estimated average row size in bytes */
|
||||
u16 nKeyCol; /* Number of columns forming the key */
|
||||
u16 nColumn; /* Number of columns stored in the index */
|
||||
@@ -2539,11 +2552,6 @@ struct AggInfo {
|
||||
AggInfo *pNext; /* Next in list of them all */
|
||||
};
|
||||
|
||||
/*
|
||||
** Value for AggInfo.iAggMagic when the structure is valid
|
||||
*/
|
||||
#define AggInfoMagic 0x2059e99e
|
||||
|
||||
/*
|
||||
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
|
||||
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
|
||||
@@ -3125,6 +3133,7 @@ struct Select {
|
||||
#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */
|
||||
#define SF_View 0x0200000 /* SELECT statement is a view */
|
||||
#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
|
||||
#define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
@@ -3189,6 +3198,14 @@ struct Select {
|
||||
** SRT_DistQueue Store results in priority queue pDest->iSDParm only if
|
||||
** the same record has never been stored before. The
|
||||
** index at pDest->iSDParm+1 hold all prior stores.
|
||||
**
|
||||
** SRT_Upfrom Store results in the temporary table already opened by
|
||||
** pDest->iSDParm. If (pDest->iSDParm<0), then the temp
|
||||
** table is an intkey table - in this case the first
|
||||
** column returned by the SELECT is used as the integer
|
||||
** key. If (pDest->iSDParm>0), then the table is an index
|
||||
** table. (pDest->iSDParm) is the number of key columns in
|
||||
** each index record in this case.
|
||||
*/
|
||||
#define SRT_Union 1 /* Store result as keys in an index */
|
||||
#define SRT_Except 2 /* Remove result from a UNION index */
|
||||
@@ -3208,14 +3225,16 @@ struct Select {
|
||||
#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
|
||||
#define SRT_Coroutine 13 /* Generate a single row of result */
|
||||
#define SRT_Table 14 /* Store result as data with an automatic rowid */
|
||||
#define SRT_Upfrom 15 /* Store result as data with rowid */
|
||||
|
||||
/*
|
||||
** An instance of this object describes where to put of the results of
|
||||
** a SELECT statement.
|
||||
*/
|
||||
struct SelectDest {
|
||||
u8 eDest; /* How to dispose of the results. On of SRT_* above. */
|
||||
u8 eDest; /* How to dispose of the results. One of SRT_* above. */
|
||||
int iSDParm; /* A parameter used by the eDest disposal method */
|
||||
int iSDParm2; /* A second parameter for the eDest disposal method */
|
||||
int iSdst; /* Base register where results are written */
|
||||
int nSdst; /* Number of registers allocated */
|
||||
char *zAffSdst; /* Affinity used when eDest==SRT_Set */
|
||||
@@ -3371,9 +3390,7 @@ struct Parse {
|
||||
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
|
||||
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
|
||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
||||
#if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE))
|
||||
u8 eParseMode; /* PARSE_MODE_XXX constant */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
int nVtabLock; /* Number of virtual tables to lock */
|
||||
#endif
|
||||
@@ -3561,6 +3578,7 @@ struct TriggerStep {
|
||||
Trigger *pTrig; /* The trigger that this step is a part of */
|
||||
Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */
|
||||
char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
|
||||
SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */
|
||||
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
|
||||
ExprList *pExprList; /* SET clause for UPDATE */
|
||||
IdList *pIdList; /* Column names for INSERT */
|
||||
@@ -3616,6 +3634,7 @@ typedef struct {
|
||||
int rc; /* Result code stored here */
|
||||
u32 mInitFlags; /* Flags controlling error messages */
|
||||
u32 nInitRow; /* Number of rows processed */
|
||||
Pgno mxPage; /* Maximum page number. 0 for no limit. */
|
||||
} InitData;
|
||||
|
||||
/*
|
||||
@@ -4229,6 +4248,7 @@ void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
||||
IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
|
||||
int sqlite3IdListIndex(IdList*,const char*);
|
||||
SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
|
||||
SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
|
||||
SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
|
||||
SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
|
||||
Token*, Select*, Expr*, IdList*);
|
||||
@@ -4247,7 +4267,6 @@ int sqlite3Select(Parse*, Select*, SelectDest*);
|
||||
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
|
||||
Expr*,ExprList*,u32,Expr*);
|
||||
void sqlite3SelectDelete(sqlite3*, Select*);
|
||||
void sqlite3SelectReset(Parse*, Select*);
|
||||
Table *sqlite3SrcListLookup(Parse*, SrcList*);
|
||||
int sqlite3IsReadOnly(Parse*, Table*, int);
|
||||
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
||||
@@ -4399,13 +4418,14 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
||||
TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*,
|
||||
Select*,u8,Upsert*,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,ExprList*, Expr*, u8,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*,
|
||||
Expr*, u8, const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*,
|
||||
const char*,const char*);
|
||||
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
|
||||
u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
|
||||
SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*);
|
||||
# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
|
||||
# define sqlite3IsToplevel(p) ((p)->pToplevel==0)
|
||||
#else
|
||||
@@ -4419,6 +4439,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
||||
# define sqlite3ParseToplevel(p) p
|
||||
# define sqlite3IsToplevel(p) 1
|
||||
# define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
|
||||
# define sqlite3TriggerStepSrc(A,B) 0
|
||||
#endif
|
||||
|
||||
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
||||
@@ -4447,8 +4468,10 @@ int sqlite3FixExpr(DbFixer*, Expr*);
|
||||
int sqlite3FixExprList(DbFixer*, ExprList*);
|
||||
int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
|
||||
int sqlite3RealSameAsInt(double,sqlite3_int64);
|
||||
void sqlite3Int64ToText(i64,char*);
|
||||
int sqlite3AtoF(const char *z, double*, int, u8);
|
||||
int sqlite3GetInt32(const char *, int*);
|
||||
int sqlite3GetUInt32(const char*, u32*);
|
||||
int sqlite3Atoi(const char*);
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
int sqlite3Utf16ByteLen(const void *pData, int nChar);
|
||||
@@ -4568,7 +4591,7 @@ extern const unsigned char sqlite3UpperToLower[];
|
||||
extern const unsigned char sqlite3CtypeMap[];
|
||||
extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
|
||||
extern FuncDefHash sqlite3BuiltinFunctions;
|
||||
extern u32 sqlite3SelectTrace;
|
||||
extern u32 sqlite3_unsupported_selecttrace;
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
extern int sqlite3PendingByte;
|
||||
#endif
|
||||
@@ -4576,7 +4599,7 @@ extern int sqlite3PendingByte;
|
||||
#ifdef VDBE_PROFILE
|
||||
extern sqlite3_uint64 sqlite3NProfileCnt;
|
||||
#endif
|
||||
void sqlite3RootPageMoved(sqlite3*, int, int, int);
|
||||
void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno);
|
||||
void sqlite3Reindex(Parse*, Token*, Token*);
|
||||
void sqlite3AlterFunctions(void);
|
||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
@@ -4690,7 +4713,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
void sqlite3TableLock(Parse *, int, int, u8, const char *);
|
||||
void sqlite3TableLock(Parse *, int, Pgno, u8, const char *);
|
||||
#else
|
||||
#define sqlite3TableLock(v,w,x,y,z)
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -352,7 +352,7 @@ int sqlite3_db_status(
|
||||
*/
|
||||
case SQLITE_DBSTATUS_CACHE_SPILL:
|
||||
op = SQLITE_DBSTATUS_CACHE_WRITE+1;
|
||||
/* Fall through into the next case */
|
||||
/* no break */ deliberate_fall_through
|
||||
case SQLITE_DBSTATUS_CACHE_HIT:
|
||||
case SQLITE_DBSTATUS_CACHE_MISS:
|
||||
case SQLITE_DBSTATUS_CACHE_WRITE:{
|
||||
|
||||
+64
-3
@@ -6437,6 +6437,30 @@ static int SQLITE_TCLAPI prng_seed(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: extra_schema_checks BOOLEAN
|
||||
**
|
||||
** Enable or disable schema checks when parsing the sqlite_schema file.
|
||||
** This is always enabled in production, but it is sometimes useful to
|
||||
** disable the checks in order to make some internal error states reachable
|
||||
** for testing.
|
||||
*/
|
||||
static int SQLITE_TCLAPI extra_schema_checks(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
int i = 0;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetBooleanFromObj(interp,objv[1],&i) ) return TCL_ERROR;
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, i);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: database_may_be_corrupt
|
||||
**
|
||||
@@ -7778,6 +7802,41 @@ static int SQLITE_TCLAPI test_mmap_warm(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: test_write_db DB OFFSET DATA
|
||||
**
|
||||
** Obtain the sqlite3_file* object for the database file for the "main" db
|
||||
** of handle DB. Then invoke its xWrite method to write data DATA to offset
|
||||
** OFFSET.
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_write_db(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db = 0;
|
||||
Tcl_WideInt iOff = 0;
|
||||
const unsigned char *aData = 0;
|
||||
int nData = 0;
|
||||
sqlite3_file *pFile = 0;
|
||||
int rc;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB OFFSET DATA");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
if( Tcl_GetWideIntFromObj(interp, objv[2], &iOff) ) return TCL_ERROR;
|
||||
aData = Tcl_GetByteArrayFromObj(objv[3], &nData);
|
||||
|
||||
sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFile);
|
||||
rc = pFile->pMethods->xWrite(pFile, aData, nData, iOff);
|
||||
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: decode_hexdb TEXT
|
||||
**
|
||||
@@ -8003,6 +8062,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "restore_prng_state", restore_prng_state, 0 },
|
||||
{ "reset_prng_state", reset_prng_state, 0 },
|
||||
{ "prng_seed", prng_seed, 0 },
|
||||
{ "extra_schema_checks", extra_schema_checks, 0},
|
||||
{ "database_never_corrupt", database_never_corrupt, 0},
|
||||
{ "database_may_be_corrupt", database_may_be_corrupt, 0},
|
||||
{ "optimization_control", optimization_control,0},
|
||||
@@ -8141,6 +8201,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_mmap_warm", test_mmap_warm, 0 },
|
||||
{ "sqlite3_config_sorterref", test_config_sorterref, 0 },
|
||||
{ "decode_hexdb", test_decode_hexdb, 0 },
|
||||
{ "test_write_db", test_write_db, 0 },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
|
||||
@@ -8166,7 +8227,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
extern u32 sqlite3SelectTrace;
|
||||
extern u32 sqlite3_unsupported_selecttrace;
|
||||
#endif
|
||||
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
@@ -8254,8 +8315,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
Tcl_LinkVar(interp, "sqlite_fullsync_count",
|
||||
(char*)&sqlite3_fullsync_count, TCL_LINK_INT);
|
||||
#if defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
Tcl_LinkVar(interp, "sqlite3SelectTrace",
|
||||
(char*)&sqlite3SelectTrace, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite3_unsupported_selecttrace",
|
||||
(char*)&sqlite3_unsupported_selecttrace, TCL_LINK_INT);
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST)
|
||||
Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
|
||||
|
||||
+3
-36
@@ -112,32 +112,6 @@ static void *faultsimRealloc(void *pOld, int n){
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following method calls are passed directly through to the underlying
|
||||
** malloc system:
|
||||
**
|
||||
** xFree
|
||||
** xSize
|
||||
** xRoundup
|
||||
** xInit
|
||||
** xShutdown
|
||||
*/
|
||||
static void faultsimFree(void *p){
|
||||
memfault.m.xFree(p);
|
||||
}
|
||||
static int faultsimSize(void *p){
|
||||
return memfault.m.xSize(p);
|
||||
}
|
||||
static int faultsimRoundup(int n){
|
||||
return memfault.m.xRoundup(n);
|
||||
}
|
||||
static int faultsimInit(void *p){
|
||||
return memfault.m.xInit(memfault.m.pAppData);
|
||||
}
|
||||
static void faultsimShutdown(void *p){
|
||||
memfault.m.xShutdown(memfault.m.pAppData);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine configures the malloc failure simulation. After
|
||||
** calling this routine, the next nDelay mallocs will succeed, followed
|
||||
@@ -204,16 +178,6 @@ static void faultsimEndBenign(void){
|
||||
** the argument is non-zero, the
|
||||
*/
|
||||
static int faultsimInstall(int install){
|
||||
static struct sqlite3_mem_methods m = {
|
||||
faultsimMalloc, /* xMalloc */
|
||||
faultsimFree, /* xFree */
|
||||
faultsimRealloc, /* xRealloc */
|
||||
faultsimSize, /* xSize */
|
||||
faultsimRoundup, /* xRoundup */
|
||||
faultsimInit, /* xInit */
|
||||
faultsimShutdown, /* xShutdown */
|
||||
0 /* pAppData */
|
||||
};
|
||||
int rc;
|
||||
|
||||
install = (install ? 1 : 0);
|
||||
@@ -227,6 +191,9 @@ static int faultsimInstall(int install){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
|
||||
assert(memfault.m.xMalloc);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_mem_methods m = memfault.m;
|
||||
m.xMalloc = faultsimMalloc;
|
||||
m.xRealloc = faultsimRealloc;
|
||||
rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
|
||||
}
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
|
||||
|
||||
@@ -591,9 +591,9 @@ static int multiplexOpen(
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pSubOpen->pMethods->iVersion==1 ){
|
||||
pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
|
||||
pConn->pMethods = &gMultiplex.sIoMethodsV1;
|
||||
}else{
|
||||
pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV2;
|
||||
pConn->pMethods = &gMultiplex.sIoMethodsV2;
|
||||
}
|
||||
}else{
|
||||
multiplexFreeComponents(pGroup);
|
||||
|
||||
@@ -422,6 +422,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
}
|
||||
/* If the next character is a digit, this is a floating point
|
||||
** number that begins with ".". Fall thru into the next case */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case CC_DIGIT: {
|
||||
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
|
||||
@@ -526,6 +527,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
#endif
|
||||
/* If it is not a BLOB literal, then it must be an ID, since no
|
||||
** SQL keywords start with the letter 'x'. Fall through */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case CC_ID: {
|
||||
i = 1;
|
||||
|
||||
+24
-15
@@ -26,6 +26,7 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
|
||||
sqlite3SelectDelete(db, pTmp->pSelect);
|
||||
sqlite3IdListDelete(db, pTmp->pIdList);
|
||||
sqlite3UpsertDelete(db, pTmp->pUpsert);
|
||||
sqlite3SrcListDelete(db, pTmp->pFrom);
|
||||
sqlite3DbFree(db, pTmp->zSpan);
|
||||
|
||||
sqlite3DbFree(db, pTmp);
|
||||
@@ -486,6 +487,7 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
TriggerStep *sqlite3TriggerUpdateStep(
|
||||
Parse *pParse, /* Parser */
|
||||
Token *pTableName, /* Name of the table to be updated */
|
||||
SrcList *pFrom,
|
||||
ExprList *pEList, /* The SET clause: list of column and new values */
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
|
||||
@@ -500,16 +502,20 @@ TriggerStep *sqlite3TriggerUpdateStep(
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
pTriggerStep->pFrom = pFrom;
|
||||
pEList = 0;
|
||||
pWhere = 0;
|
||||
pFrom = 0;
|
||||
}else{
|
||||
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
|
||||
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE);
|
||||
}
|
||||
pTriggerStep->orconf = orconf;
|
||||
}
|
||||
sqlite3ExprListDelete(db, pEList);
|
||||
sqlite3ExprDelete(db, pWhere);
|
||||
sqlite3SrcListDelete(db, pFrom);
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
@@ -736,25 +742,28 @@ Trigger *sqlite3TriggersExist(
|
||||
** trigger is in TEMP in which case it can refer to any other database it
|
||||
** wants.
|
||||
*/
|
||||
static SrcList *targetSrcList(
|
||||
SrcList *sqlite3TriggerStepSrc(
|
||||
Parse *pParse, /* The parsing context */
|
||||
TriggerStep *pStep /* The trigger containing the target token */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb; /* Index of the database to use */
|
||||
SrcList *pSrc; /* SrcList to be returned */
|
||||
|
||||
SrcList *pSrc; /* SrcList to be returned */
|
||||
char *zName = sqlite3DbStrDup(db, pStep->zTarget);
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
assert( pSrc==0 || pSrc->nSrc==1 );
|
||||
assert( zName || pSrc==0 );
|
||||
if( pSrc ){
|
||||
assert( pSrc->nSrc>0 );
|
||||
pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
|
||||
iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
|
||||
if( iDb==0 || iDb>=2 ){
|
||||
const char *zDb;
|
||||
assert( iDb<db->nDb );
|
||||
zDb = db->aDb[iDb].zDbSName;
|
||||
pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb);
|
||||
Schema *pSchema = pStep->pTrig->pSchema;
|
||||
pSrc->a[0].zName = zName;
|
||||
if( pSchema!=db->aDb[1].pSchema ){
|
||||
pSrc->a[0].pSchema = pSchema;
|
||||
}
|
||||
if( pStep->pFrom ){
|
||||
SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
|
||||
pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup);
|
||||
}
|
||||
}else{
|
||||
sqlite3DbFree(db, zName);
|
||||
}
|
||||
return pSrc;
|
||||
}
|
||||
@@ -803,7 +812,7 @@ static int codeTriggerProgram(
|
||||
switch( pStep->op ){
|
||||
case TK_UPDATE: {
|
||||
sqlite3Update(pParse,
|
||||
targetSrcList(pParse, pStep),
|
||||
sqlite3TriggerStepSrc(pParse, pStep),
|
||||
sqlite3ExprListDup(db, pStep->pExprList, 0),
|
||||
sqlite3ExprDup(db, pStep->pWhere, 0),
|
||||
pParse->eOrconf, 0, 0, 0
|
||||
@@ -812,7 +821,7 @@ static int codeTriggerProgram(
|
||||
}
|
||||
case TK_INSERT: {
|
||||
sqlite3Insert(pParse,
|
||||
targetSrcList(pParse, pStep),
|
||||
sqlite3TriggerStepSrc(pParse, pStep),
|
||||
sqlite3SelectDup(db, pStep->pSelect, 0),
|
||||
sqlite3IdListDup(db, pStep->pIdList),
|
||||
pParse->eOrconf,
|
||||
@@ -822,7 +831,7 @@ static int codeTriggerProgram(
|
||||
}
|
||||
case TK_DELETE: {
|
||||
sqlite3DeleteFrom(pParse,
|
||||
targetSrcList(pParse, pStep),
|
||||
sqlite3TriggerStepSrc(pParse, pStep),
|
||||
sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0
|
||||
);
|
||||
break;
|
||||
|
||||
+414
-183
@@ -130,12 +130,149 @@ static int indexWhereClauseMightChange(
|
||||
aXRef, chngRowid);
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate and return a pointer to an expression of type TK_ROW with
|
||||
** Expr.iColumn set to value (iCol+1). The resolver will modify the
|
||||
** expression to be a TK_COLUMN reading column iCol of the first
|
||||
** table in the source-list (pSrc->a[0]).
|
||||
*/
|
||||
static Expr *exprRowColumn(Parse *pParse, int iCol){
|
||||
Expr *pRet = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
||||
if( pRet ) pRet->iColumn = iCol+1;
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Assuming both the pLimit and pOrderBy parameters are NULL, this function
|
||||
** generates VM code to run the query:
|
||||
**
|
||||
** SELECT <other-columns>, pChanges FROM pTabList WHERE pWhere
|
||||
**
|
||||
** and write the results to the ephemeral table already opened as cursor
|
||||
** iEph. None of pChanges, pTabList or pWhere are modified or consumed by
|
||||
** this function, they must be deleted by the caller.
|
||||
**
|
||||
** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view:
|
||||
**
|
||||
** SELECT <other-columns>, pChanges FROM pTabList
|
||||
** WHERE pWhere
|
||||
** GROUP BY <other-columns>
|
||||
** ORDER BY pOrderBy LIMIT pLimit
|
||||
**
|
||||
** If pTab is a view, the GROUP BY clause is omitted.
|
||||
**
|
||||
** Exactly how results are written to table iEph, and exactly what
|
||||
** the <other-columns> in the query above are is determined by the type
|
||||
** of table pTabList->a[0].pTab.
|
||||
**
|
||||
** If the table is a WITHOUT ROWID table, then argument pPk must be its
|
||||
** PRIMARY KEY. In this case <other-columns> are the primary key columns
|
||||
** of the table, in order. The results of the query are written to ephemeral
|
||||
** table iEph as index keys, using OP_IdxInsert.
|
||||
**
|
||||
** If the table is actually a view, then <other-columns> are all columns of
|
||||
** the view. The results are written to the ephemeral table iEph as records
|
||||
** with automatically assigned integer keys.
|
||||
**
|
||||
** If the table is a virtual or ordinary intkey table, then <other-columns>
|
||||
** is its rowid. For a virtual table, the results are written to iEph as
|
||||
** records with automatically assigned integer keys For intkey tables, the
|
||||
** rowid value in <other-columns> is used as the integer key, and the
|
||||
** remaining fields make up the table record.
|
||||
*/
|
||||
static void updateFromSelect(
|
||||
Parse *pParse, /* Parse context */
|
||||
int iEph, /* Cursor for open eph. table */
|
||||
Index *pPk, /* PK if table 0 is WITHOUT ROWID */
|
||||
ExprList *pChanges, /* List of expressions to return */
|
||||
SrcList *pTabList, /* List of tables to select from */
|
||||
Expr *pWhere, /* WHERE clause for query */
|
||||
ExprList *pOrderBy, /* ORDER BY clause */
|
||||
Expr *pLimit /* LIMIT clause */
|
||||
){
|
||||
int i;
|
||||
SelectDest dest;
|
||||
Select *pSelect = 0;
|
||||
ExprList *pList = 0;
|
||||
ExprList *pGrp = 0;
|
||||
Expr *pLimit2 = 0;
|
||||
ExprList *pOrderBy2 = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
Table *pTab = pTabList->a[0].pTab;
|
||||
SrcList *pSrc;
|
||||
Expr *pWhere2;
|
||||
int eDest;
|
||||
|
||||
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
if( pOrderBy && pLimit==0 ) {
|
||||
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on UPDATE");
|
||||
return;
|
||||
}
|
||||
pOrderBy2 = sqlite3ExprListDup(db, pOrderBy, 0);
|
||||
pLimit2 = sqlite3ExprDup(db, pLimit, 0);
|
||||
#else
|
||||
UNUSED_PARAMETER(pOrderBy);
|
||||
UNUSED_PARAMETER(pLimit);
|
||||
#endif
|
||||
|
||||
pSrc = sqlite3SrcListDup(db, pTabList, 0);
|
||||
pWhere2 = sqlite3ExprDup(db, pWhere, 0);
|
||||
|
||||
assert( pTabList->nSrc>1 );
|
||||
if( pSrc ){
|
||||
pSrc->a[0].iCursor = -1;
|
||||
pSrc->a[0].pTab->nTabRef--;
|
||||
pSrc->a[0].pTab = 0;
|
||||
}
|
||||
if( pPk ){
|
||||
for(i=0; i<pPk->nKeyCol; i++){
|
||||
Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]);
|
||||
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
if( pLimit ){
|
||||
pGrp = sqlite3ExprListAppend(pParse, pGrp, sqlite3ExprDup(db, pNew, 0));
|
||||
}
|
||||
#endif
|
||||
pList = sqlite3ExprListAppend(pParse, pList, pNew);
|
||||
}
|
||||
eDest = SRT_Upfrom;
|
||||
}else if( pTab->pSelect ){
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
|
||||
}
|
||||
eDest = SRT_Table;
|
||||
}else{
|
||||
eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom;
|
||||
pList = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0));
|
||||
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
if( pLimit ){
|
||||
pGrp = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if( ALWAYS(pChanges) ){
|
||||
for(i=0; i<pChanges->nExpr; i++){
|
||||
pList = sqlite3ExprListAppend(pParse, pList,
|
||||
sqlite3ExprDup(db, pChanges->a[i].pExpr, 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pParse, pList,
|
||||
pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UpdateFrom|SF_IncludeHidden, pLimit2
|
||||
);
|
||||
sqlite3SelectDestInit(&dest, eDest, iEph);
|
||||
dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1);
|
||||
sqlite3Select(pParse, pSelect, &dest);
|
||||
sqlite3SelectDelete(db, pSelect);
|
||||
}
|
||||
|
||||
/*
|
||||
** Process an UPDATE statement.
|
||||
**
|
||||
** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
|
||||
** \_______/ \________/ \______/ \________________/
|
||||
* onError pTabList pChanges pWhere
|
||||
** UPDATE OR IGNORE tbl SET a=b, c=d FROM tbl2... WHERE e<5 AND f NOT NULL;
|
||||
** \_______/ \_/ \______/ \_____/ \________________/
|
||||
** onError | pChanges | pWhere
|
||||
** \_______________________/
|
||||
** pTabList
|
||||
*/
|
||||
void sqlite3Update(
|
||||
Parse *pParse, /* The parser context */
|
||||
@@ -150,7 +287,7 @@ void sqlite3Update(
|
||||
int i, j, k; /* Loop counters */
|
||||
Table *pTab; /* The table to be updated */
|
||||
int addrTop = 0; /* VDBE instruction address of the start of the loop */
|
||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||
WhereInfo *pWInfo = 0; /* Information about the WHERE clause */
|
||||
Vdbe *v; /* The virtual database engine */
|
||||
Index *pIdx; /* For looping over indices */
|
||||
Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */
|
||||
@@ -169,6 +306,7 @@ void sqlite3Update(
|
||||
u8 chngRowid; /* Rowid changed in a normal table */
|
||||
u8 chngKey; /* Either chngPk or chngRowid */
|
||||
Expr *pRowidExpr = 0; /* Expression defining the new record number */
|
||||
int iRowidExpr = -1; /* Index of "rowid=" (or IPK) assignment in pChanges */
|
||||
AuthContext sContext; /* The authorization context */
|
||||
NameContext sNC; /* The name-context to resolve expressions in */
|
||||
int iDb; /* Database containing the table being updated */
|
||||
@@ -192,6 +330,7 @@ void sqlite3Update(
|
||||
i16 nPk = 0; /* Number of components of the PRIMARY KEY */
|
||||
int bReplace = 0; /* True if REPLACE conflict resolution might happen */
|
||||
int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */
|
||||
int nChangeFrom = 0; /* If there is a FROM, pChanges->nExpr, else 0 */
|
||||
|
||||
/* Register Allocations */
|
||||
int regRowCount = 0; /* A count of rows changed */
|
||||
@@ -207,7 +346,6 @@ void sqlite3Update(
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
assert( pTabList->nSrc==1 );
|
||||
|
||||
/* Locate the table which we want to update.
|
||||
*/
|
||||
@@ -232,8 +370,15 @@ void sqlite3Update(
|
||||
# define isView 0
|
||||
#endif
|
||||
|
||||
/* If there was a FROM clause, set nChangeFrom to the number of expressions
|
||||
** in the change-list. Otherwise, set it to 0. There cannot be a FROM
|
||||
** clause if this function is being called to generate code for part of
|
||||
** an UPSERT statement. */
|
||||
nChangeFrom = (pTabList->nSrc>1) ? pChanges->nExpr : 0;
|
||||
assert( nChangeFrom==0 || pUpsert==0 );
|
||||
|
||||
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
if( !isView ){
|
||||
if( !isView && nChangeFrom==0 ){
|
||||
pWhere = sqlite3LimitWhere(
|
||||
pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE"
|
||||
);
|
||||
@@ -302,7 +447,9 @@ void sqlite3Update(
|
||||
*/
|
||||
chngRowid = chngPk = 0;
|
||||
for(i=0; i<pChanges->nExpr; i++){
|
||||
if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
|
||||
/* If this is an UPDATE with a FROM clause, do not resolve expressions
|
||||
** here. The call to sqlite3Select() below will do that. */
|
||||
if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
@@ -310,6 +457,7 @@ void sqlite3Update(
|
||||
if( j==pTab->iPKey ){
|
||||
chngRowid = 1;
|
||||
pRowidExpr = pChanges->a[i].pExpr;
|
||||
iRowidExpr = i;
|
||||
}else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
|
||||
chngPk = 1;
|
||||
}
|
||||
@@ -332,6 +480,7 @@ void sqlite3Update(
|
||||
j = -1;
|
||||
chngRowid = 1;
|
||||
pRowidExpr = pChanges->a[i].pExpr;
|
||||
iRowidExpr = i;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName);
|
||||
pParse->checkSchema = 1;
|
||||
@@ -461,7 +610,7 @@ void sqlite3Update(
|
||||
** an ephemeral table.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( isView ){
|
||||
if( nChangeFrom==0 && isView ){
|
||||
sqlite3MaterializeView(pParse, pTab,
|
||||
pWhere, pOrderBy, pLimit, iDataCur
|
||||
);
|
||||
@@ -473,7 +622,7 @@ void sqlite3Update(
|
||||
/* Resolve the column names in all the expressions in the
|
||||
** WHERE clause.
|
||||
*/
|
||||
if( sqlite3ResolveExprNames(&sNC, pWhere) ){
|
||||
if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pWhere) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
||||
@@ -500,105 +649,128 @@ void sqlite3Update(
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
|
||||
}
|
||||
|
||||
if( HasRowid(pTab) ){
|
||||
if( nChangeFrom==0 && HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
|
||||
}else{
|
||||
assert( pPk!=0 );
|
||||
nPk = pPk->nKeyCol;
|
||||
assert( pPk!=0 || HasRowid(pTab) );
|
||||
nPk = pPk ? pPk->nKeyCol : 0;
|
||||
iPk = pParse->nMem+1;
|
||||
pParse->nMem += nPk;
|
||||
pParse->nMem += nChangeFrom;
|
||||
regKey = ++pParse->nMem;
|
||||
if( pUpsert==0 ){
|
||||
int nEphCol = nPk + nChangeFrom + (isView ? pTab->nCol : 0);
|
||||
iEph = pParse->nTab++;
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
|
||||
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
||||
if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
|
||||
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol);
|
||||
if( pPk ){
|
||||
KeyInfo *pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pPk);
|
||||
if( pKeyInfo ){
|
||||
pKeyInfo->nAllField = nEphCol;
|
||||
sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
|
||||
}
|
||||
}
|
||||
if( nChangeFrom ){
|
||||
updateFromSelect(
|
||||
pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit
|
||||
);
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
if( isView ) iDataCur = iEph;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pUpsert ){
|
||||
/* If this is an UPSERT, then all cursors have already been opened by
|
||||
** the outer INSERT and the data cursor should be pointing at the row
|
||||
** that is to be updated. So bypass the code that searches for the
|
||||
** row(s) to be updated.
|
||||
*/
|
||||
pWInfo = 0;
|
||||
eOnePass = ONEPASS_SINGLE;
|
||||
sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
|
||||
bFinishSeek = 0;
|
||||
if( nChangeFrom ){
|
||||
sqlite3MultiWrite(pParse);
|
||||
eOnePass = ONEPASS_OFF;
|
||||
nKey = nPk;
|
||||
regKey = iPk;
|
||||
}else{
|
||||
/* Begin the database scan.
|
||||
**
|
||||
** Do not consider a single-pass strategy for a multi-row update if
|
||||
** there are any triggers or foreign keys to process, or rows may
|
||||
** be deleted as a result of REPLACE conflict handling. Any of these
|
||||
** things might disturb a cursor being used to scan through the table
|
||||
** or index, causing a single-pass approach to malfunction. */
|
||||
flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
|
||||
if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
|
||||
flags |= WHERE_ONEPASS_MULTIROW;
|
||||
}
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
|
||||
/* A one-pass strategy that might update more than one row may not
|
||||
** be used if any column of the index used for the scan is being
|
||||
** updated. Otherwise, if there is an index on "b", statements like
|
||||
** the following could create an infinite loop:
|
||||
**
|
||||
** UPDATE t1 SET b=b+1 WHERE b>?
|
||||
**
|
||||
** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
|
||||
** strategy that uses an index for which one or more columns are being
|
||||
** updated. */
|
||||
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
||||
bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
|
||||
if( eOnePass!=ONEPASS_SINGLE ){
|
||||
sqlite3MultiWrite(pParse);
|
||||
if( eOnePass==ONEPASS_MULTI ){
|
||||
int iCur = aiCurOnePass[1];
|
||||
if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
|
||||
eOnePass = ONEPASS_OFF;
|
||||
if( pUpsert ){
|
||||
/* If this is an UPSERT, then all cursors have already been opened by
|
||||
** the outer INSERT and the data cursor should be pointing at the row
|
||||
** that is to be updated. So bypass the code that searches for the
|
||||
** row(s) to be updated.
|
||||
*/
|
||||
pWInfo = 0;
|
||||
eOnePass = ONEPASS_SINGLE;
|
||||
sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
|
||||
bFinishSeek = 0;
|
||||
}else{
|
||||
/* Begin the database scan.
|
||||
**
|
||||
** Do not consider a single-pass strategy for a multi-row update if
|
||||
** there are any triggers or foreign keys to process, or rows may
|
||||
** be deleted as a result of REPLACE conflict handling. Any of these
|
||||
** things might disturb a cursor being used to scan through the table
|
||||
** or index, causing a single-pass approach to malfunction. */
|
||||
flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
|
||||
if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
|
||||
flags |= WHERE_ONEPASS_MULTIROW;
|
||||
}
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags,iIdxCur);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
|
||||
/* A one-pass strategy that might update more than one row may not
|
||||
** be used if any column of the index used for the scan is being
|
||||
** updated. Otherwise, if there is an index on "b", statements like
|
||||
** the following could create an infinite loop:
|
||||
**
|
||||
** UPDATE t1 SET b=b+1 WHERE b>?
|
||||
**
|
||||
** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
|
||||
** strategy that uses an index for which one or more columns are being
|
||||
** updated. */
|
||||
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
||||
bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
|
||||
if( eOnePass!=ONEPASS_SINGLE ){
|
||||
sqlite3MultiWrite(pParse);
|
||||
if( eOnePass==ONEPASS_MULTI ){
|
||||
int iCur = aiCurOnePass[1];
|
||||
if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
|
||||
eOnePass = ONEPASS_OFF;
|
||||
}
|
||||
assert( iCur!=iDataCur || !HasRowid(pTab) );
|
||||
}
|
||||
assert( iCur!=iDataCur || !HasRowid(pTab) );
|
||||
}
|
||||
}
|
||||
|
||||
if( HasRowid(pTab) ){
|
||||
/* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
|
||||
** mode, write the rowid into the FIFO. In either of the one-pass modes,
|
||||
** leave it in register regOldRowid. */
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
|
||||
if( eOnePass==ONEPASS_OFF ){
|
||||
/* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
|
||||
aRegIdx[nAllIdx] = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
|
||||
}
|
||||
}else{
|
||||
/* Read the PK of the current row into an array of registers. In
|
||||
** ONEPASS_OFF mode, serialize the array into a record and store it in
|
||||
** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
|
||||
** the OP_OpenEphemeral instruction to a Noop (the ephemeral table
|
||||
** is not required) and leave the PK fields in the array of registers. */
|
||||
for(i=0; i<nPk; i++){
|
||||
assert( pPk->aiColumn[i]>=0 );
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
|
||||
pPk->aiColumn[i], iPk+i);
|
||||
}
|
||||
if( eOnePass ){
|
||||
if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
|
||||
nKey = nPk;
|
||||
regKey = iPk;
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
|
||||
sqlite3IndexAffinityStr(db, pPk), nPk);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( HasRowid(pTab) ){
|
||||
/* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
|
||||
** mode, write the rowid into the FIFO. In either of the one-pass modes,
|
||||
** leave it in register regOldRowid. */
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
|
||||
if( eOnePass==ONEPASS_OFF ){
|
||||
/* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
|
||||
aRegIdx[nAllIdx] = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
|
||||
}
|
||||
}else{
|
||||
/* Read the PK of the current row into an array of registers. In
|
||||
** ONEPASS_OFF mode, serialize the array into a record and store it in
|
||||
** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
|
||||
** the OP_OpenEphemeral instruction to a Noop (the ephemeral table
|
||||
** is not required) and leave the PK fields in the array of registers. */
|
||||
for(i=0; i<nPk; i++){
|
||||
assert( pPk->aiColumn[i]>=0 );
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
|
||||
pPk->aiColumn[i], iPk+i);
|
||||
}
|
||||
if( eOnePass ){
|
||||
if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
|
||||
nKey = nPk;
|
||||
regKey = iPk;
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
|
||||
sqlite3IndexAffinityStr(db, pPk), nPk);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
|
||||
}
|
||||
}
|
||||
|
||||
if( pUpsert==0 ){
|
||||
if( eOnePass!=ONEPASS_MULTI ){
|
||||
if( nChangeFrom==0 && eOnePass!=ONEPASS_MULTI ){
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
}
|
||||
|
||||
@@ -634,12 +806,31 @@ void sqlite3Update(
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
|
||||
VdbeCoverageIf(v, pPk==0);
|
||||
VdbeCoverageIf(v, pPk!=0);
|
||||
}else if( pPk ){
|
||||
}else if( pPk || nChangeFrom ){
|
||||
labelContinue = sqlite3VdbeMakeLabel(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
|
||||
addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
|
||||
VdbeCoverage(v);
|
||||
addrTop = sqlite3VdbeCurrentAddr(v);
|
||||
if( nChangeFrom ){
|
||||
if( !isView ){
|
||||
if( pPk ){
|
||||
for(i=0; i<nPk; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iEph, i, iPk+i);
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(
|
||||
v, OP_NotFound, iDataCur, labelContinue, iPk, nPk
|
||||
); VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid);
|
||||
sqlite3VdbeAddOp3(
|
||||
v, OP_NotExists, iDataCur, labelContinue, regOldRowid
|
||||
); VdbeCoverage(v);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey,0);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
}else{
|
||||
labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak,
|
||||
regOldRowid);
|
||||
@@ -655,7 +846,12 @@ void sqlite3Update(
|
||||
** already populated. */
|
||||
assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid );
|
||||
if( chngRowid ){
|
||||
sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
|
||||
assert( iRowidExpr>=0 );
|
||||
if( nChangeFrom==0 ){
|
||||
sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
@@ -708,7 +904,13 @@ void sqlite3Update(
|
||||
}else{
|
||||
j = aXRef[i];
|
||||
if( j>=0 ){
|
||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
|
||||
if( nChangeFrom ){
|
||||
int nOff = (isView ? pTab->nCol : nPk);
|
||||
assert( eOnePass==ONEPASS_OFF );
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iEph, nOff+j, k);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
|
||||
}
|
||||
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){
|
||||
/* This branch loads the value of a column that will not be changed
|
||||
** into a register. This is done if there are no BEFORE triggers, or
|
||||
@@ -740,43 +942,45 @@ void sqlite3Update(
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
||||
TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue);
|
||||
|
||||
/* The row-trigger may have deleted the row being updated. In this
|
||||
** case, jump to the next row. No updates or AFTER triggers are
|
||||
** required. This behavior - what happens when the row being updated
|
||||
** is deleted or renamed by a BEFORE trigger - is left undefined in the
|
||||
** documentation.
|
||||
*/
|
||||
if( pPk ){
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* After-BEFORE-trigger-reload-loop:
|
||||
** If it did not delete it, the BEFORE trigger may still have modified
|
||||
** some of the columns of the row being updated. Load the values for
|
||||
** all columns not modified by the update statement into their registers
|
||||
** in case this has happened. Only unmodified columns are reloaded.
|
||||
** The values computed for modified columns use the values before the
|
||||
** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
|
||||
** for an example.
|
||||
*/
|
||||
for(i=0, k=regNew; i<pTab->nCol; i++, k++){
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
|
||||
}else if( aXRef[i]<0 && i!=pTab->iPKey ){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
|
||||
if( !isView ){
|
||||
/* The row-trigger may have deleted the row being updated. In this
|
||||
** case, jump to the next row. No updates or AFTER triggers are
|
||||
** required. This behavior - what happens when the row being updated
|
||||
** is deleted or renamed by a BEFORE trigger - is left undefined in the
|
||||
** documentation.
|
||||
*/
|
||||
if( pPk ){
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* After-BEFORE-trigger-reload-loop:
|
||||
** If it did not delete it, the BEFORE trigger may still have modified
|
||||
** some of the columns of the row being updated. Load the values for
|
||||
** all columns not modified by the update statement into their registers
|
||||
** in case this has happened. Only unmodified columns are reloaded.
|
||||
** The values computed for modified columns use the values before the
|
||||
** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
|
||||
** for an example.
|
||||
*/
|
||||
for(i=0, k=regNew; i<pTab->nCol; i++, k++){
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
|
||||
}else if( aXRef[i]<0 && i!=pTab->iPKey ){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
if( pTab->tabFlags & TF_HasGenerated ){
|
||||
testcase( pTab->tabFlags & TF_HasVirtual );
|
||||
testcase( pTab->tabFlags & TF_HasStored );
|
||||
sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
|
||||
}
|
||||
if( pTab->tabFlags & TF_HasGenerated ){
|
||||
testcase( pTab->tabFlags & TF_HasVirtual );
|
||||
testcase( pTab->tabFlags & TF_HasStored );
|
||||
sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if( !isView ){
|
||||
@@ -879,7 +1083,7 @@ void sqlite3Update(
|
||||
}else if( eOnePass==ONEPASS_MULTI ){
|
||||
sqlite3VdbeResolveLabel(v, labelContinue);
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
}else if( pPk ){
|
||||
}else if( pPk || nChangeFrom ){
|
||||
sqlite3VdbeResolveLabel(v, labelContinue);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
|
||||
}else{
|
||||
@@ -964,7 +1168,7 @@ static void updateVirtualTable(
|
||||
int i; /* Loop counter */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
|
||||
WhereInfo *pWInfo;
|
||||
WhereInfo *pWInfo = 0;
|
||||
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
|
||||
int regArg; /* First register in VUpdate arg array */
|
||||
int regRec; /* Register in which to assemble record */
|
||||
@@ -982,69 +1186,96 @@ static void updateVirtualTable(
|
||||
addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
|
||||
regArg = pParse->nMem + 1;
|
||||
pParse->nMem += nArg;
|
||||
regRec = ++pParse->nMem;
|
||||
regRowid = ++pParse->nMem;
|
||||
|
||||
/* Start scanning the virtual table */
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
|
||||
if( pWInfo==0 ) return;
|
||||
|
||||
/* Populate the argument registers. */
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
|
||||
if( aXRef[i]>=0 ){
|
||||
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable sqlite3_vtab_nochange() */
|
||||
}
|
||||
}
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
|
||||
if( pSrc->nSrc>1 ){
|
||||
Expr *pRow;
|
||||
ExprList *pList;
|
||||
if( pRowid ){
|
||||
sqlite3ExprCode(pParse, pRowid, regArg+1);
|
||||
pRow = sqlite3ExprDup(db, pRowid, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
|
||||
pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
||||
}
|
||||
pList = sqlite3ExprListAppend(pParse, 0, pRow);
|
||||
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( aXRef[i]>=0 ){
|
||||
pList = sqlite3ExprListAppend(pParse, pList,
|
||||
sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0)
|
||||
);
|
||||
}else{
|
||||
pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
|
||||
}
|
||||
}
|
||||
|
||||
updateFromSelect(pParse, ephemTab, 0, pList, pSrc, pWhere, 0, 0);
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
eOnePass = ONEPASS_OFF;
|
||||
}else{
|
||||
Index *pPk; /* PRIMARY KEY index */
|
||||
i16 iPk; /* PRIMARY KEY column */
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
assert( pPk!=0 );
|
||||
assert( pPk->nKeyCol==1 );
|
||||
iPk = pPk->aiColumn[0];
|
||||
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
|
||||
}
|
||||
regRec = ++pParse->nMem;
|
||||
regRowid = ++pParse->nMem;
|
||||
|
||||
eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
|
||||
/* Start scanning the virtual table */
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc,pWhere,0,0,WHERE_ONEPASS_DESIRED,0);
|
||||
if( pWInfo==0 ) return;
|
||||
|
||||
/* There is no ONEPASS_MULTI on virtual tables */
|
||||
assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
|
||||
/* Populate the argument registers. */
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
|
||||
if( aXRef[i]>=0 ){
|
||||
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* For sqlite3_vtab_nochange() */
|
||||
}
|
||||
}
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
|
||||
if( pRowid ){
|
||||
sqlite3ExprCode(pParse, pRowid, regArg+1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
|
||||
}
|
||||
}else{
|
||||
Index *pPk; /* PRIMARY KEY index */
|
||||
i16 iPk; /* PRIMARY KEY column */
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
assert( pPk!=0 );
|
||||
assert( pPk->nKeyCol==1 );
|
||||
iPk = pPk->aiColumn[0];
|
||||
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
|
||||
}
|
||||
|
||||
if( eOnePass ){
|
||||
/* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
|
||||
** above. */
|
||||
sqlite3VdbeChangeToNoop(v, addr);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
||||
}else{
|
||||
/* Create a record from the argument register contents and insert it into
|
||||
** the ephemeral table. */
|
||||
sqlite3MultiWrite(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Signal an assert() within OP_MakeRecord that it is allowed to
|
||||
** accept no-change records with serial_type 10 */
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
|
||||
eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
|
||||
|
||||
/* There is no ONEPASS_MULTI on virtual tables */
|
||||
assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
|
||||
|
||||
if( eOnePass ){
|
||||
/* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
|
||||
** above. */
|
||||
sqlite3VdbeChangeToNoop(v, addr);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
||||
}else{
|
||||
/* Create a record from the argument register contents and insert it into
|
||||
** the ephemeral table. */
|
||||
sqlite3MultiWrite(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
|
||||
#if defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_NULL_TRIM)
|
||||
/* Signal an assert() within OP_MakeRecord that it is allowed to
|
||||
** accept no-change records with serial_type 10 */
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
|
||||
#endif
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( eOnePass==ONEPASS_OFF ){
|
||||
/* End the virtual table scan */
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
if( pSrc->nSrc==1 ){
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
}
|
||||
|
||||
/* Begin scannning through the ephemeral table. */
|
||||
addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
|
||||
|
||||
+44
-3
@@ -595,6 +595,30 @@ do_atof_calc:
|
||||
#pragma warning(default : 4756)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Render an signed 64-bit integer as text. Store the result in zOut[].
|
||||
**
|
||||
** The caller must ensure that zOut[] is at least 21 bytes in size.
|
||||
*/
|
||||
void sqlite3Int64ToText(i64 v, char *zOut){
|
||||
int i;
|
||||
u64 x;
|
||||
char zTemp[22];
|
||||
if( v<0 ){
|
||||
x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
|
||||
}else{
|
||||
x = v;
|
||||
}
|
||||
i = sizeof(zTemp)-2;
|
||||
zTemp[sizeof(zTemp)-1] = 0;
|
||||
do{
|
||||
zTemp[i--] = (x%10) + '0';
|
||||
x = x/10;
|
||||
}while( x );
|
||||
if( v<0 ) zTemp[i--] = '-';
|
||||
memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the 19-character string zNum against the text representation
|
||||
** value 2^63: 9223372036854775808. Return negative, zero, or positive
|
||||
@@ -835,10 +859,28 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
|
||||
*/
|
||||
int sqlite3Atoi(const char *z){
|
||||
int x = 0;
|
||||
if( z ) sqlite3GetInt32(z, &x);
|
||||
sqlite3GetInt32(z, &x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to convert z into an unsigned 32-bit integer. Return true on
|
||||
** success and false if there is an error.
|
||||
**
|
||||
** Only decimal notation is accepted.
|
||||
*/
|
||||
int sqlite3GetUInt32(const char *z, u32 *pI){
|
||||
u64 v = 0;
|
||||
int i;
|
||||
for(i=0; sqlite3Isdigit(z[i]); i++){
|
||||
v = v*10 + z[i] - '0';
|
||||
if( v>4294967296LL ){ *pI = 0; return 0; }
|
||||
}
|
||||
if( i==0 || z[i]!=0 ){ *pI = 0; return 0; }
|
||||
*pI = (u32)v;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** The variable-length integer encoding is as follows:
|
||||
**
|
||||
@@ -1141,8 +1183,7 @@ u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
|
||||
u64 v64;
|
||||
u8 n;
|
||||
|
||||
p -= 2;
|
||||
n = sqlite3GetVarint(p, &v64);
|
||||
n = sqlite3GetVarint(p-2, &v64);
|
||||
assert( n>3 && n<=9 );
|
||||
if( (v64 & SQLITE_MAX_U32)!=v64 ){
|
||||
*v = 0xffffffff;
|
||||
|
||||
+53
-33
@@ -671,9 +671,9 @@ int sqlite3VdbeExec(
|
||||
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
|
||||
u8 encoding = ENC(db); /* The database encoding */
|
||||
int iCompare = 0; /* Result of last comparison */
|
||||
unsigned nVmStep = 0; /* Number of virtual machine steps */
|
||||
u64 nVmStep = 0; /* Number of virtual machine steps */
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
|
||||
u64 nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
|
||||
#endif
|
||||
Mem *aMem = p->aMem; /* Copy of p->aMem */
|
||||
Mem *pIn1 = 0; /* 1st input operand */
|
||||
@@ -693,7 +693,7 @@ int sqlite3VdbeExec(
|
||||
assert( 0 < db->nProgressOps );
|
||||
nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
|
||||
}else{
|
||||
nProgressLimit = 0xffffffff;
|
||||
nProgressLimit = LARGEST_UINT64;
|
||||
}
|
||||
#endif
|
||||
if( p->rc==SQLITE_NOMEM ){
|
||||
@@ -905,7 +905,7 @@ check_for_interrupt:
|
||||
assert( db->nProgressOps!=0 );
|
||||
nProgressLimit += db->nProgressOps;
|
||||
if( db->xProgress(db->pProgressArg) ){
|
||||
nProgressLimit = 0xffffffff;
|
||||
nProgressLimit = LARGEST_UINT64;
|
||||
rc = SQLITE_INTERRUPT;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
@@ -1033,6 +1033,7 @@ case OP_HaltIfNull: { /* in3 */
|
||||
#endif
|
||||
if( (pIn3->flags & MEM_Null)==0 ) break;
|
||||
/* Fall through into OP_Halt */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
|
||||
/* Opcode: Halt P1 P2 * P4 P5
|
||||
@@ -1203,6 +1204,7 @@ case OP_String8: { /* same as TK_STRING, out2 */
|
||||
pOp->opcode = OP_String;
|
||||
assert( rc==SQLITE_OK );
|
||||
/* Fall through to the next case, OP_String */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
|
||||
/* Opcode: String P1 P2 P3 P4 P5
|
||||
@@ -1514,7 +1516,7 @@ case OP_ResultRow: {
|
||||
if( db->mallocFailed ) goto no_mem;
|
||||
|
||||
if( db->mTrace & SQLITE_TRACE_ROW ){
|
||||
db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
|
||||
db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -2250,10 +2252,10 @@ case OP_Compare: {
|
||||
int p1;
|
||||
int p2;
|
||||
const KeyInfo *pKeyInfo;
|
||||
int idx;
|
||||
u32 idx;
|
||||
CollSeq *pColl; /* Collating sequence to use on this term */
|
||||
int bRev; /* True for DESCENDING sort order */
|
||||
int *aPermute; /* The permutation */
|
||||
u32 *aPermute; /* The permutation */
|
||||
|
||||
if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
|
||||
aPermute = 0;
|
||||
@@ -2273,7 +2275,7 @@ case OP_Compare: {
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( aPermute ){
|
||||
int k, mx = 0;
|
||||
for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
|
||||
for(k=0; k<n; k++) if( aPermute[k]>(u32)mx ) mx = aPermute[k];
|
||||
assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
|
||||
assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
|
||||
}else{
|
||||
@@ -2282,7 +2284,7 @@ case OP_Compare: {
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
for(i=0; i<n; i++){
|
||||
idx = aPermute ? aPermute[i] : i;
|
||||
idx = aPermute ? aPermute[i] : (u32)i;
|
||||
assert( memIsValid(&aMem[p1+idx]) );
|
||||
assert( memIsValid(&aMem[p2+idx]) );
|
||||
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
|
||||
@@ -2593,7 +2595,7 @@ case OP_Offset: { /* out3 */
|
||||
** skipped for length() and all content loading can be skipped for typeof().
|
||||
*/
|
||||
case OP_Column: {
|
||||
int p2; /* column number to retrieve */
|
||||
u32 p2; /* column number to retrieve */
|
||||
VdbeCursor *pC; /* The VDBE cursor */
|
||||
BtCursor *pCrsr; /* The BTree cursor */
|
||||
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
|
||||
@@ -2611,7 +2613,7 @@ case OP_Column: {
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
p2 = pOp->p2;
|
||||
p2 = (u32)pOp->p2;
|
||||
|
||||
/* If the cursor cache is stale (meaning it is not currently point at
|
||||
** the correct row) then bring it up-to-date by doing the necessary
|
||||
@@ -2623,7 +2625,7 @@ case OP_Column: {
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
assert( pC!=0 );
|
||||
assert( p2<pC->nField );
|
||||
assert( p2<(u32)pC->nField );
|
||||
aOffset = pC->aOffset;
|
||||
assert( pC->eCurType!=CURTYPE_VTAB );
|
||||
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
|
||||
@@ -2738,7 +2740,7 @@ case OP_Column: {
|
||||
offset64 += sqlite3VdbeSerialTypeLen(t);
|
||||
}
|
||||
aOffset[++i] = (u32)(offset64 & 0xffffffff);
|
||||
}while( i<=p2 && zHdr<zEndHdr );
|
||||
}while( (u32)i<=p2 && zHdr<zEndHdr );
|
||||
|
||||
/* The record is corrupt if any of the following are true:
|
||||
** (1) the bytes of the header extend past the declared header size
|
||||
@@ -2922,6 +2924,17 @@ case OP_Affinity: {
|
||||
** macros defined in sqliteInt.h.
|
||||
**
|
||||
** If P4 is NULL then all index fields have the affinity BLOB.
|
||||
**
|
||||
** The meaning of P5 depends on whether or not the SQLITE_ENABLE_NULL_TRIM
|
||||
** compile-time option is enabled:
|
||||
**
|
||||
** * If SQLITE_ENABLE_NULL_TRIM is enabled, then the P5 is the index
|
||||
** of the right-most table that can be null-trimmed.
|
||||
**
|
||||
** * If SQLITE_ENABLE_NULL_TRIM is omitted, then P5 has the value
|
||||
** OPFLAG_NOCHNG_MAGIC if the OP_MakeRecord opcode is allowed to
|
||||
** accept no-change records with serial_type 10. This value is
|
||||
** only used inside an assert() and does not affect the end result.
|
||||
*/
|
||||
case OP_MakeRecord: {
|
||||
Mem *pRec; /* The new record */
|
||||
@@ -3040,7 +3053,9 @@ case OP_MakeRecord: {
|
||||
** Give such values a special internal-use-only serial-type of 10
|
||||
** so that they can be passed through to xUpdate and have
|
||||
** a true sqlite3_value_nochange(). */
|
||||
#ifndef SQLITE_ENABLE_NULL_TRIM
|
||||
assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
|
||||
#endif
|
||||
pRec->uTemp = 10;
|
||||
}else{
|
||||
pRec->uTemp = 0;
|
||||
@@ -3616,7 +3631,7 @@ case OP_ReadCookie: { /* out2 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SetCookie P1 P2 P3 * *
|
||||
/* Opcode: SetCookie P1 P2 P3 * P5
|
||||
**
|
||||
** Write the integer value P3 into cookie number P2 of database P1.
|
||||
** P2==1 is the schema version. P2==2 is the database format.
|
||||
@@ -3625,6 +3640,11 @@ case OP_ReadCookie: { /* out2 */
|
||||
** database file used to store temporary tables.
|
||||
**
|
||||
** A transaction must be started before executing this opcode.
|
||||
**
|
||||
** If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal
|
||||
** schema version is set to P3-P5. The "PRAGMA schema_version=N" statement
|
||||
** has P5 set to 1, so that the internal schema version will be different
|
||||
** from the database schema version, resulting in a schema reset.
|
||||
*/
|
||||
case OP_SetCookie: {
|
||||
Db *pDb;
|
||||
@@ -3641,7 +3661,7 @@ case OP_SetCookie: {
|
||||
rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
|
||||
if( pOp->p2==BTREE_SCHEMA_VERSION ){
|
||||
/* When the schema cookie changes, record the new cookie internally */
|
||||
pDb->pSchema->schema_cookie = pOp->p3;
|
||||
pDb->pSchema->schema_cookie = pOp->p3 - pOp->p5;
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
}else if( pOp->p2==BTREE_FILE_FORMAT ){
|
||||
/* Record changes in the file format */
|
||||
@@ -3744,7 +3764,7 @@ case OP_SetCookie: {
|
||||
case OP_ReopenIdx: {
|
||||
int nField;
|
||||
KeyInfo *pKeyInfo;
|
||||
int p2;
|
||||
u32 p2;
|
||||
int iDb;
|
||||
int wrFlag;
|
||||
Btree *pX;
|
||||
@@ -3775,7 +3795,7 @@ case OP_OpenWrite:
|
||||
|
||||
nField = 0;
|
||||
pKeyInfo = 0;
|
||||
p2 = pOp->p2;
|
||||
p2 = (u32)pOp->p2;
|
||||
iDb = pOp->p3;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( DbMaskTest(p->btreeMask, iDb) );
|
||||
@@ -3794,7 +3814,7 @@ case OP_OpenWrite:
|
||||
}
|
||||
if( pOp->p5 & OPFLAG_P2ISREG ){
|
||||
assert( p2>0 );
|
||||
assert( p2<=(p->nMem+1 - p->nCursor) );
|
||||
assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
|
||||
assert( pOp->opcode==OP_OpenWrite );
|
||||
pIn2 = &aMem[p2];
|
||||
assert( memIsValid(pIn2) );
|
||||
@@ -3947,7 +3967,7 @@ case OP_OpenEphemeral: {
|
||||
*/
|
||||
if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
|
||||
assert( pOp->p4type==P4_KEYINFO );
|
||||
rc = sqlite3BtreeCreateTable(pCx->pBtx, (int*)&pCx->pgnoRoot,
|
||||
rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
|
||||
BTREE_BLOBKEY | pOp->p5);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
|
||||
@@ -4367,7 +4387,7 @@ seek_not_found:
|
||||
** Synopsis: seekHit=P2
|
||||
**
|
||||
** Set the seekHit flag on cursor P1 to the value in P2.
|
||||
* The seekHit flag is used by the IfNoHope opcode.
|
||||
** The seekHit flag is used by the IfNoHope opcode.
|
||||
**
|
||||
** P1 must be a valid b-tree cursor. P2 must be a boolean value,
|
||||
** either 0 or 1.
|
||||
@@ -4489,6 +4509,7 @@ case OP_IfNoHope: { /* jump, in3 */
|
||||
assert( pC!=0 );
|
||||
if( pC->seekHit ) break;
|
||||
/* Fall through into OP_NotFound */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case OP_NoConflict: /* jump, in3 */
|
||||
case OP_NotFound: /* jump, in3 */
|
||||
@@ -4643,6 +4664,7 @@ case OP_SeekRowid: { /* jump, in3 */
|
||||
goto notExistsWithKey;
|
||||
}
|
||||
/* Fall through into OP_NotExists */
|
||||
/* no break */ deliberate_fall_through
|
||||
case OP_NotExists: /* jump, in3 */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
|
||||
@@ -5211,10 +5233,6 @@ case OP_RowData: {
|
||||
*/
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
#if 0 /* Not required due to the previous to assert() statements */
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
#endif
|
||||
|
||||
n = sqlite3BtreePayloadSize(pCrsr);
|
||||
if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
@@ -5418,6 +5436,7 @@ case OP_Sort: { /* jump */
|
||||
#endif
|
||||
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
|
||||
/* Fall through into OP_Rewind */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
/* Opcode: Rewind P1 P2 * * *
|
||||
**
|
||||
@@ -5984,7 +6003,7 @@ case OP_Clear: {
|
||||
assert( p->readOnly==0 );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p2) );
|
||||
rc = sqlite3BtreeClearTable(
|
||||
db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
|
||||
db->aDb[pOp->p2].pBt, (u32)pOp->p1, (pOp->p3 ? &nChange : 0)
|
||||
);
|
||||
if( pOp->p3 ){
|
||||
p->nChange += nChange;
|
||||
@@ -6033,7 +6052,7 @@ case OP_ResetSorter: {
|
||||
** The root page number of the new b-tree is stored in register P2.
|
||||
*/
|
||||
case OP_CreateBtree: { /* out2 */
|
||||
int pgno;
|
||||
Pgno pgno;
|
||||
Db *pDb;
|
||||
|
||||
sqlite3VdbeIncrWriteCounter(p, 0);
|
||||
@@ -6108,6 +6127,7 @@ case OP_ParseSchema: {
|
||||
initData.iDb = iDb;
|
||||
initData.pzErrMsg = &p->zErrMsg;
|
||||
initData.mInitFlags = 0;
|
||||
initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt);
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
|
||||
db->aDb[iDb].zDbSName, zSchema, pOp->p4.z);
|
||||
@@ -6221,7 +6241,7 @@ case OP_DropTrigger: {
|
||||
*/
|
||||
case OP_IntegrityCk: {
|
||||
int nRoot; /* Number of tables to check. (Number of root pages.) */
|
||||
int *aRoot; /* Array of rootpage numbers for tables to be checked */
|
||||
Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */
|
||||
int nErr; /* Number of errors reported */
|
||||
char *z; /* Text of the error report */
|
||||
Mem *pnErr; /* Register keeping track of errors remaining */
|
||||
@@ -6230,7 +6250,7 @@ case OP_IntegrityCk: {
|
||||
nRoot = pOp->p2;
|
||||
aRoot = pOp->p4.ai;
|
||||
assert( nRoot>0 );
|
||||
assert( aRoot[0]==nRoot );
|
||||
assert( aRoot[0]==(Pgno)nRoot );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pnErr = &aMem[pOp->p3];
|
||||
assert( (pnErr->flags & MEM_Int)!=0 );
|
||||
@@ -6770,6 +6790,7 @@ case OP_AggStep: {
|
||||
|
||||
pOp->opcode = OP_AggStep1;
|
||||
/* Fall through into OP_AggStep */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case OP_AggStep1: {
|
||||
int i;
|
||||
@@ -7759,18 +7780,17 @@ case OP_Init: { /* jump */
|
||||
){
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
if( db->mTrace & SQLITE_TRACE_LEGACY ){
|
||||
void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
|
||||
char *z = sqlite3VdbeExpandSql(p, zTrace);
|
||||
x(db->pTraceArg, z);
|
||||
db->trace.xLegacy(db->pTraceArg, z);
|
||||
sqlite3_free(z);
|
||||
}else
|
||||
#endif
|
||||
if( db->nVdbeExec>1 ){
|
||||
char *z = sqlite3MPrintf(db, "-- %s", zTrace);
|
||||
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
|
||||
(void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
|
||||
sqlite3DbFree(db, z);
|
||||
}else{
|
||||
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
|
||||
(void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
|
||||
}
|
||||
}
|
||||
#ifdef SQLITE_USE_FCNTL_TRACE
|
||||
@@ -7983,7 +8003,7 @@ vdbe_return:
|
||||
while( nVmStep>=nProgressLimit && db->xProgress!=0 ){
|
||||
nProgressLimit += db->nProgressOps;
|
||||
if( db->xProgress(db->pProgressArg) ){
|
||||
nProgressLimit = 0xffffffff;
|
||||
nProgressLimit = LARGEST_UINT64;
|
||||
rc = SQLITE_INTERRUPT;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ struct VdbeOp {
|
||||
Mem *pMem; /* Used when p4type is P4_MEM */
|
||||
VTable *pVtab; /* Used when p4type is P4_VTAB */
|
||||
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
|
||||
int *ai; /* Used when p4type is P4_INTARRAY */
|
||||
u32 *ai; /* Used when p4type is P4_INTARRAY */
|
||||
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
|
||||
Table *pTab; /* Used when p4type is P4_TABLE */
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
|
||||
+2
-2
@@ -89,7 +89,7 @@ struct VdbeCursor {
|
||||
Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
|
||||
Btree *pBtx; /* Separate file holding temporary table */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
int *aAltMap; /* Mapping from table to index column numbers */
|
||||
u32 *aAltMap; /* Mapping from table to index column numbers */
|
||||
|
||||
/* Cached OP_Column parse information is only valid if cacheStatus matches
|
||||
** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
|
||||
@@ -485,7 +485,7 @@ void sqlite3VdbeError(Vdbe*, const char *, ...);
|
||||
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor**, u32*);
|
||||
int sqlite3VdbeCursorRestore(VdbeCursor*);
|
||||
u32 sqlite3VdbeSerialTypeLen(u32);
|
||||
u8 sqlite3VdbeOneByteSerialTypeLen(u8);
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
|
||||
}
|
||||
#endif
|
||||
if( db->mTrace & SQLITE_TRACE_PROFILE ){
|
||||
db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
|
||||
db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
|
||||
}
|
||||
p->startTime = 0;
|
||||
}
|
||||
|
||||
+8
-7
@@ -808,7 +808,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
switch( pOp->opcode ){
|
||||
case OP_Transaction: {
|
||||
if( pOp->p2!=0 ) p->readOnly = 0;
|
||||
/* fall thru */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case OP_AutoCommit:
|
||||
case OP_Savepoint: {
|
||||
@@ -855,6 +855,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
n = pOp[-1].p1;
|
||||
if( n>nMaxArgs ) nMaxArgs = n;
|
||||
/* Fall through into the default case */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
@@ -1712,12 +1713,12 @@ char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
|
||||
}
|
||||
#endif
|
||||
case P4_INTARRAY: {
|
||||
int i;
|
||||
int *ai = pOp->p4.ai;
|
||||
int n = ai[0]; /* The first element of an INTARRAY is always the
|
||||
u32 i;
|
||||
u32 *ai = pOp->p4.ai;
|
||||
u32 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++){
|
||||
sqlite3_str_appendf(&x, "%c%d", (i==1 ? '[' : ','), ai[i]);
|
||||
sqlite3_str_appendf(&x, "%c%u", (i==1 ? '[' : ','), ai[i]);
|
||||
}
|
||||
sqlite3_str_append(&x, "]", 1);
|
||||
break;
|
||||
@@ -3561,11 +3562,11 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
||||
** If the cursor is already pointing to the correct row and that row has
|
||||
** not been deleted out from under the cursor, then this routine is a no-op.
|
||||
*/
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
|
||||
VdbeCursor *p = *pp;
|
||||
assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
|
||||
if( p->deferredMoveto ){
|
||||
int iMap;
|
||||
u32 iMap;
|
||||
if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
|
||||
*pp = p->pAltCursor;
|
||||
*piCol = iMap - 1;
|
||||
|
||||
+16
-7
@@ -104,16 +104,25 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
|
||||
static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
|
||||
StrAccum acc;
|
||||
assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
|
||||
sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
|
||||
assert( sz>22 );
|
||||
if( p->flags & MEM_Int ){
|
||||
sqlite3_str_appendf(&acc, "%lld", p->u.i);
|
||||
}else if( p->flags & MEM_IntReal ){
|
||||
sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i);
|
||||
#if GCC_VERSION>=7000000
|
||||
/* Work-around for GCC bug
|
||||
** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */
|
||||
i64 x;
|
||||
assert( (p->flags&MEM_Int)*2==sizeof(x) );
|
||||
memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
|
||||
sqlite3Int64ToText(x, zBuf);
|
||||
#else
|
||||
sqlite3Int64ToText(p->u.i, zBuf);
|
||||
#endif
|
||||
}else{
|
||||
sqlite3_str_appendf(&acc, "%!.15g", p->u.r);
|
||||
sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
|
||||
sqlite3_str_appendf(&acc, "%!.15g",
|
||||
(p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
|
||||
assert( acc.zText==zBuf && acc.mxAlloc<=0 );
|
||||
zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
|
||||
}
|
||||
assert( acc.zText==zBuf && acc.mxAlloc<=0 );
|
||||
zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ static int bytecodevtabColumn(
|
||||
Schema *pSchema;
|
||||
HashElem *k;
|
||||
int iDb = pOp->p3;
|
||||
int iRoot = pOp->p2;
|
||||
Pgno iRoot = (Pgno)pOp->p2;
|
||||
sqlite3 *db = pVTab->db;
|
||||
pSchema = db->aDb[iDb].pSchema;
|
||||
pCur->zSchema = db->aDb[iDb].zDbSName;
|
||||
|
||||
@@ -508,7 +508,7 @@ typedef u16 ht_slot;
|
||||
** This functionality is used by the checkpoint code (see walCheckpoint()).
|
||||
*/
|
||||
struct WalIterator {
|
||||
int iPrior; /* Last result returned from the iterator */
|
||||
u32 iPrior; /* Last result returned from the iterator */
|
||||
int nSegment; /* Number of entries in aSegment[] */
|
||||
struct WalSegment {
|
||||
int iNext; /* Next slot in aIndex[] not yet returned */
|
||||
@@ -590,7 +590,9 @@ static SQLITE_NOINLINE int walIndexPageRealloc(
|
||||
);
|
||||
assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
|
||||
testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
|
||||
if( (rc&0xff)==SQLITE_READONLY ){
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM;
|
||||
}else if( (rc&0xff)==SQLITE_READONLY ){
|
||||
pWal->readOnly |= WAL_SHM_RDONLY;
|
||||
if( rc==SQLITE_READONLY ){
|
||||
rc = SQLITE_OK;
|
||||
@@ -965,6 +967,7 @@ static int walFramePage(u32 iFrame){
|
||||
&& (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
|
||||
&& (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
|
||||
);
|
||||
assert( iHash>=0 );
|
||||
return iHash;
|
||||
}
|
||||
|
||||
@@ -1161,12 +1164,6 @@ static int walIndexRecover(Wal *pWal){
|
||||
assert( pWal->writeLock );
|
||||
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
|
||||
rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
if( rc!=SQLITE_OK ){
|
||||
walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
|
||||
}
|
||||
}
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
@@ -1182,15 +1179,16 @@ static int walIndexRecover(Wal *pWal){
|
||||
|
||||
if( nSize>WAL_HDRSIZE ){
|
||||
u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
|
||||
u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */
|
||||
u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
|
||||
int szFrame; /* Number of bytes in buffer aFrame[] */
|
||||
u8 *aData; /* Pointer to data part of aFrame buffer */
|
||||
int iFrame; /* Index of last frame read */
|
||||
i64 iOffset; /* Next offset to read from log file */
|
||||
int szPage; /* Page size according to the log */
|
||||
u32 magic; /* Magic value read from WAL header */
|
||||
u32 version; /* Magic value read from WAL header */
|
||||
int isValid; /* True if this frame is valid */
|
||||
u32 iPg; /* Current 32KB wal-index page */
|
||||
u32 iLastFrame; /* Last frame in wal, based on nSize alone */
|
||||
|
||||
/* Read in the WAL header. */
|
||||
rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
|
||||
@@ -1237,38 +1235,82 @@ static int walIndexRecover(Wal *pWal){
|
||||
|
||||
/* Malloc a buffer to read frames into. */
|
||||
szFrame = szPage + WAL_FRAME_HDRSIZE;
|
||||
aFrame = (u8 *)sqlite3_malloc64(szFrame);
|
||||
aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
|
||||
if( !aFrame ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto recovery_error;
|
||||
}
|
||||
aData = &aFrame[WAL_FRAME_HDRSIZE];
|
||||
aPrivate = (u32*)&aData[szPage];
|
||||
|
||||
/* Read all frames from the log file. */
|
||||
iFrame = 0;
|
||||
for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
|
||||
u32 pgno; /* Database page number for frame */
|
||||
u32 nTruncate; /* dbsize field from frame header */
|
||||
iLastFrame = (nSize - WAL_HDRSIZE) / szFrame;
|
||||
for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){
|
||||
u32 *aShare;
|
||||
u32 iFrame; /* Index of last frame read */
|
||||
u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE);
|
||||
u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE);
|
||||
u32 nHdr, nHdr32;
|
||||
rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
|
||||
if( rc ) break;
|
||||
pWal->apWiData[iPg] = aPrivate;
|
||||
|
||||
for(iFrame=iFirst; iFrame<=iLast; iFrame++){
|
||||
i64 iOffset = walFrameOffset(iFrame, szPage);
|
||||
u32 pgno; /* Database page number for frame */
|
||||
u32 nTruncate; /* dbsize field from frame header */
|
||||
|
||||
/* Read and decode the next log frame. */
|
||||
iFrame++;
|
||||
rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
|
||||
if( !isValid ) break;
|
||||
rc = walIndexAppend(pWal, iFrame, pgno);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
/* Read and decode the next log frame. */
|
||||
rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
|
||||
if( !isValid ) break;
|
||||
rc = walIndexAppend(pWal, iFrame, pgno);
|
||||
if( NEVER(rc!=SQLITE_OK) ) break;
|
||||
|
||||
/* If nTruncate is non-zero, this is a commit record. */
|
||||
if( nTruncate ){
|
||||
pWal->hdr.mxFrame = iFrame;
|
||||
pWal->hdr.nPage = nTruncate;
|
||||
pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
|
||||
aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
|
||||
/* If nTruncate is non-zero, this is a commit record. */
|
||||
if( nTruncate ){
|
||||
pWal->hdr.mxFrame = iFrame;
|
||||
pWal->hdr.nPage = nTruncate;
|
||||
pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
|
||||
aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
|
||||
}
|
||||
}
|
||||
pWal->apWiData[iPg] = aShare;
|
||||
nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
|
||||
nHdr32 = nHdr / sizeof(u32);
|
||||
#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
|
||||
/* Memcpy() should work fine here, on all reasonable implementations.
|
||||
** Technically, memcpy() might change the destination to some
|
||||
** intermediate value before setting to the final value, and that might
|
||||
** cause a concurrent reader to malfunction. Memcpy() is allowed to
|
||||
** do that, according to the spec, but no memcpy() implementation that
|
||||
** we know of actually does that, which is why we say that memcpy()
|
||||
** is safe for this. Memcpy() is certainly a lot faster.
|
||||
*/
|
||||
memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr);
|
||||
#else
|
||||
/* In the event that some platform is found for which memcpy()
|
||||
** changes the destination to some intermediate value before
|
||||
** setting the final value, this alternative copy routine is
|
||||
** provided.
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
for(i=nHdr32; i<WALINDEX_PGSZ/sizeof(u32); i++){
|
||||
if( aShare[i]!=aPrivate[i] ){
|
||||
/* Atomic memory operations are not required here because if
|
||||
** the value needs to be changed, that means it is not being
|
||||
** accessed concurrently. */
|
||||
aShare[i] = aPrivate[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( iFrame<=iLast ) break;
|
||||
}
|
||||
|
||||
sqlite3_free(aFrame);
|
||||
@@ -1283,15 +1325,26 @@ finished:
|
||||
walIndexWriteHdr(pWal);
|
||||
|
||||
/* Reset the checkpoint-header. This is safe because this thread is
|
||||
** currently holding locks that exclude all other readers, writers and
|
||||
** checkpointers.
|
||||
** currently holding locks that exclude all other writers and
|
||||
** checkpointers. Then set the values of read-mark slots 1 through N.
|
||||
*/
|
||||
pInfo = walCkptInfo(pWal);
|
||||
pInfo->nBackfill = 0;
|
||||
pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
|
||||
pInfo->aReadMark[0] = 0;
|
||||
for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
|
||||
if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( i==1 && pWal->hdr.mxFrame ){
|
||||
pInfo->aReadMark[i] = pWal->hdr.mxFrame;
|
||||
}else{
|
||||
pInfo->aReadMark[i] = READMARK_NOT_USED;
|
||||
}
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
}else if( rc!=SQLITE_BUSY ){
|
||||
goto recovery_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* If more than one frame was recovered from the log file, report an
|
||||
** event via sqlite3_log(). This is to help with identifying performance
|
||||
@@ -1309,7 +1362,6 @@ finished:
|
||||
recovery_error:
|
||||
WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
|
||||
walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1957,10 +2009,18 @@ static int walCheckpoint(
|
||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0);
|
||||
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
|
||||
if( rc==SQLITE_OK && nSize<nReq ){
|
||||
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
|
||||
if( (nSize+65536+(i64)pWal->hdr.mxFrame*szPage)<nReq ){
|
||||
/* If the size of the final database is larger than the current
|
||||
** database plus the amount of data in the wal file, plus the
|
||||
** maximum size of the pending-byte page (65536 bytes), then
|
||||
** must be corruption somewhere. */
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Iterate through the contents of the WAL, copying data to the db file */
|
||||
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
|
||||
|
||||
+19
-7
@@ -59,8 +59,12 @@ int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the WHERE clause returns rows in ORDER BY order.
|
||||
** Return FALSE if the output needs to be sorted.
|
||||
** Return the number of ORDER BY terms that are satisfied by the
|
||||
** WHERE clause. A return of 0 means that the output must be
|
||||
** completely sorted. A return equal to the number of ORDER BY
|
||||
** terms means that no sorting is needed at all. A return that
|
||||
** is positive but less than the number of ORDER BY terms means that
|
||||
** block sorting is required.
|
||||
*/
|
||||
int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
|
||||
return pWInfo->nOBSat;
|
||||
@@ -3606,7 +3610,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
int rc = SQLITE_OK;
|
||||
WhereLoop *pNew;
|
||||
u8 priorJointype = 0;
|
||||
|
||||
/* Loop over the tables in the join, from left to right */
|
||||
pNew = pBuilder->pNew;
|
||||
@@ -3617,12 +3620,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
pNew->iTab = iTab;
|
||||
pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
|
||||
pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
|
||||
if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
|
||||
if( (pItem->fg.jointype & (JT_LEFT|JT_CROSS))!=0 ){
|
||||
/* This condition is true when pItem is the FROM clause term on the
|
||||
** right-hand-side of a LEFT or CROSS JOIN. */
|
||||
mPrereq = mPrior;
|
||||
}else{
|
||||
mPrereq = 0;
|
||||
}
|
||||
priorJointype = pItem->fg.jointype;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
struct SrcList_item *p;
|
||||
@@ -3740,7 +3744,9 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
orderDistinctMask = 0;
|
||||
ready = 0;
|
||||
eqOpMask = WO_EQ | WO_IS | WO_ISNULL;
|
||||
if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN;
|
||||
if( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MAX|WHERE_ORDERBY_MIN) ){
|
||||
eqOpMask |= WO_IN;
|
||||
}
|
||||
for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
|
||||
if( iLoop>0 ) ready |= pLoop->maskSelf;
|
||||
if( iLoop<nLoop ){
|
||||
@@ -3776,7 +3782,8 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
/* IN terms are only valid for sorting in the ORDER BY LIMIT
|
||||
** optimization, and then only if they are actually used
|
||||
** by the query plan */
|
||||
assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
|
||||
assert( wctrlFlags &
|
||||
(WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) );
|
||||
for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
|
||||
if( j>=pLoop->nLTerm ) continue;
|
||||
}
|
||||
@@ -4424,6 +4431,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if( nLoop
|
||||
&& pWInfo->nOBSat==1
|
||||
&& (pWInfo->wctrlFlags & (WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX))!=0
|
||||
){
|
||||
pWInfo->bOrderedInnerLoop = 1;
|
||||
}
|
||||
}
|
||||
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
|
||||
|
||||
+1
-1
@@ -1052,7 +1052,7 @@ static void codeDeferredSeek(
|
||||
){
|
||||
int i;
|
||||
Table *pTab = pIdx->pTable;
|
||||
int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
|
||||
u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1));
|
||||
if( ai ){
|
||||
ai[0] = pTab->nCol;
|
||||
for(i=0; i<pIdx->nColumn-1; i++){
|
||||
|
||||
+3
-2
@@ -783,7 +783,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Fall through. */
|
||||
/* no break */ deliberate_fall_through
|
||||
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_COLUMN: {
|
||||
@@ -803,6 +803,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
|
||||
}
|
||||
if( p->pSub ){
|
||||
int f = pExpr->flags & EP_Collate;
|
||||
assert( ExprHasProperty(pExpr, EP_Static)==0 );
|
||||
ExprSetProperty(pExpr, EP_Static);
|
||||
sqlite3ExprDelete(pParse->db, pExpr);
|
||||
@@ -813,6 +814,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol);
|
||||
pExpr->iTable = p->pWin->iEphCsr;
|
||||
pExpr->y.pTab = p->pTab;
|
||||
pExpr->flags = f;
|
||||
}
|
||||
if( pParse->db->mallocFailed ) return WRC_Abort;
|
||||
break;
|
||||
@@ -1082,7 +1084,6 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
assert( pParse->db->mallocFailed );
|
||||
sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
|
||||
}
|
||||
sqlite3SelectReset(pParse, p);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -658,5 +658,23 @@ do_catchsql_test 21.3 {
|
||||
ALTER TABLE a RENAME TO e;
|
||||
} {1 {error in view c: 1st ORDER BY term does not match any column in the result set}}
|
||||
|
||||
# After forum thread https://sqlite.org/forum/forumpost/ddbe1c7efa
|
||||
# Ensure that PRAGMA schema_version=N causes a full schema reload.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 22.0 {
|
||||
CREATE TABLE t1(a INT, b TEXT NOT NULL);
|
||||
INSERT INTO t1 VALUES(1,2),('a','b');
|
||||
BEGIN;
|
||||
PRAGMA writable_schema=ON;
|
||||
UPDATE sqlite_schema SET sql='CREATE TABLE t1(a INT, b TEXT)' WHERE name LIKE 't1';
|
||||
PRAGMA schema_version=1234;
|
||||
COMMIT;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
do_execsql_test 22.1 {
|
||||
ALTER TABLE t1 ADD COLUMN c INT DEFAULT 78;
|
||||
SELECT * FROM t1;
|
||||
} {1 2 78 a b 78}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -586,5 +586,19 @@ do_execsql_test 24.4 {
|
||||
DELETE FROM v2;
|
||||
END}}
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 25.1 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE TABLE t2(a, b, c);
|
||||
CREATE TRIGGER ttt AFTER INSERT ON t1 BEGIN
|
||||
UPDATE t1 SET a=t2.a FROM t2 WHERE t1.a=t2.a;
|
||||
END;
|
||||
}
|
||||
#do_execsql_test 25.2 {
|
||||
# ALTER TABLE t2 RENAME COLUMN a TO aaa;
|
||||
#}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -50,5 +50,86 @@ do_multiclient_test tn {
|
||||
} {}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
do_multiclient_test tn {
|
||||
# Make the db a WAL mode db. And add a table and a row to it. Then open
|
||||
# a second connection within process 1. Process 1 now has connections
|
||||
# [db] and [db1.2], process 2 has connection [db2] only.
|
||||
#
|
||||
# Configure all connections to use a 1000 ms timeout.
|
||||
#
|
||||
do_test 2.$tn.0 {
|
||||
code1 {
|
||||
sqlite3 db1.2 test.db
|
||||
}
|
||||
sql1 {
|
||||
PRAGMA auto_vacuum = off;
|
||||
PRAGMA journal_mode = wal;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
code2 {
|
||||
db2 timeout 1000
|
||||
}
|
||||
code1 {
|
||||
db1.2 timeout 1000
|
||||
db timeout 1000
|
||||
db1.2 eval {SELECT * FROM t1}
|
||||
}
|
||||
} {1 2}
|
||||
|
||||
# Take a read lock with [db] in process 1.
|
||||
#
|
||||
do_test 2.$tn.1 {
|
||||
sql1 {
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 2}
|
||||
|
||||
# Insert a row using [db2] in process 2. Then try a passive checkpoint.
|
||||
# It fails to checkpoint the final frame (due to the readlock taken by
|
||||
# [db]), and returns in less than 250ms.
|
||||
do_test 2.$tn.2 {
|
||||
sql2 { INSERT INTO t1 VALUES(3, 4) }
|
||||
set us [lindex [time {
|
||||
set res [code2 { db2 eval { PRAGMA wal_checkpoint } }]
|
||||
}] 0]
|
||||
list [expr $us < 250000] $res
|
||||
} {1 {0 4 3}}
|
||||
|
||||
# Now try a FULL checkpoint with [db2]. It returns SQLITE_BUSY. And takes
|
||||
# over 950ms to do so.
|
||||
do_test 2.$tn.3 {
|
||||
set us [lindex [time {
|
||||
set res [code2 { db2 eval { PRAGMA wal_checkpoint = FULL } }]
|
||||
}] 0]
|
||||
list [expr $us > 950000] $res
|
||||
} {1 {1 4 3}}
|
||||
|
||||
# Passive checkpoint with [db1.2] (process 1). No SQLITE_BUSY, returns
|
||||
# in under 250ms.
|
||||
do_test 2.$tn.4 {
|
||||
set us [lindex [time {
|
||||
set res [code1 { db1.2 eval { PRAGMA wal_checkpoint } }]
|
||||
}] 0]
|
||||
list [expr $us < 250000] $res
|
||||
} {1 {0 4 3}}
|
||||
|
||||
# Full checkpoint with [db1.2] (process 1). SQLITE_BUSY returned in
|
||||
# a bit over 950ms.
|
||||
do_test 2.$tn.5 {
|
||||
set us [lindex [time {
|
||||
set res [code1 { db1.2 eval { PRAGMA wal_checkpoint = FULL } }]
|
||||
}] 0]
|
||||
list [expr $us > 950000] $res
|
||||
} {1 {1 4 3}}
|
||||
|
||||
code1 {
|
||||
db1.2 close
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ do_test corrupt3-1.9 {
|
||||
catchsql {
|
||||
SELECT substr(x,1,10) FROM t1
|
||||
}
|
||||
} [list 0 0123456789]
|
||||
} [list 1 {database disk image is malformed}]
|
||||
do_test corrupt3-1.10 {
|
||||
catchsql {
|
||||
PRAGMA integrity_check
|
||||
|
||||
+72
-1
@@ -1174,6 +1174,7 @@ do_test 14.0 {
|
||||
| end clusterfuzz-testcase-minimized-sqlite3_dbfuzz2_fuzzer-4806406219825152
|
||||
}]} {}
|
||||
|
||||
extra_schema_checks 0
|
||||
do_catchsql_test 14.1 {
|
||||
PRAGMA integrity_check;
|
||||
} {1 {database disk image is malformed}}
|
||||
@@ -1181,6 +1182,7 @@ do_catchsql_test 14.1 {
|
||||
do_catchsql_test 14.2 {
|
||||
ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s;
|
||||
} {1 {database disk image is malformed}}
|
||||
extra_schema_checks 1
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
@@ -1263,8 +1265,77 @@ do_test 15.0 {
|
||||
| end crash-3afa1ca9e9c1bd.db
|
||||
}]} {}
|
||||
|
||||
extra_schema_checks 0
|
||||
do_execsql_test 15.1 {
|
||||
PRAGMA cell_size_check = 0;
|
||||
UPDATE c1 SET c= NOT EXISTS(SELECT 1 FROM c1 ORDER BY (SELECT 1 FROM c1 ORDER BY a)) +10 WHERE d BETWEEN 4 AND 7;
|
||||
} {}
|
||||
finish_test
|
||||
extra_schema_checks 1
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 16.0 {
|
||||
CREATE TABLE t1(w, x, y, z, UNIQUE(w, x), UNIQUE(y, z));
|
||||
INSERT INTO t1 VALUES(1, 1, 1, 1);
|
||||
|
||||
CREATE TABLE t1idx(x, y, i INTEGER, PRIMARY KEY(x)) WITHOUT ROWID;
|
||||
INSERT INTO t1idx VALUES(10, NULL, 5);
|
||||
|
||||
PRAGMA writable_schema = 1;
|
||||
UPDATE sqlite_master SET rootpage = (
|
||||
SELECT rootpage FROM sqlite_master WHERE name='t1idx'
|
||||
) WHERE type = 'index';
|
||||
}
|
||||
|
||||
extra_schema_checks 0
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
extra_schema_checks 1
|
||||
|
||||
do_catchsql_test 16.1 {
|
||||
PRAGMA writable_schema = ON;
|
||||
INSERT INTO t1(rowid, w, x, y, z) VALUES(5, 10, 11, 10, NULL);
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that corruption is reported from within a checkpoint if the
|
||||
# expected final size of the database (according to the last commit
|
||||
# frame in the wal file) is greater than the combined initial sizes
|
||||
# of the database and wal file.
|
||||
#
|
||||
if {[wal_is_capable]} {
|
||||
reset_db
|
||||
do_execsql_test 17.0 {
|
||||
CREATE TABLE t1(o INTEGER PRIMARY KEY, t UNIQUE);
|
||||
INSERT INTO t1(t) VALUES(randomblob(123));
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
|
||||
|
||||
PRAGMA journal_mode = wal;
|
||||
INSERT INTO t1 VALUES(-1, 'b');
|
||||
} {wal}
|
||||
|
||||
do_test 17.1 {
|
||||
set fd [open test.db r+]
|
||||
chan truncate $fd 2048
|
||||
file size test.db
|
||||
} {2048}
|
||||
|
||||
do_catchsql_test 17.2 {
|
||||
PRAGMA wal_checkpoint
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_test 17.3 {
|
||||
close $fd
|
||||
} {}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -361,6 +361,7 @@ do_test dbfuzz001-310 {
|
||||
}]
|
||||
} {}
|
||||
|
||||
extra_schema_checks 0
|
||||
do_catchsql_test dbfuzz001-320 {
|
||||
PRAGMA integrity_check;
|
||||
} {1 {database disk image is malformed}}
|
||||
@@ -368,5 +369,6 @@ do_catchsql_test dbfuzz001-320 {
|
||||
do_catchsql_test dbfuzz001-330 {
|
||||
DELETE FROM t3 WHERE x IN (SELECT x FROM t4);
|
||||
} {1 {database disk image is malformed}}
|
||||
extra_schema_checks 1
|
||||
|
||||
finish_test
|
||||
|
||||
+45
-1
@@ -15,7 +15,7 @@ source $testdir/tester.tcl
|
||||
set testprefix decimal
|
||||
|
||||
if {[catch {load_static_extension db decimal} error]} {
|
||||
puts "Skipping zipfile tests, hit load error: $error"
|
||||
puts "Skipping decimal tests, hit load error: $error"
|
||||
finish_test; return
|
||||
}
|
||||
|
||||
@@ -138,5 +138,49 @@ do_execsql_test 5103 {
|
||||
SELECT decimal_mul('1234.0000','2');
|
||||
} {2468}
|
||||
|
||||
if {[catch {load_static_extension db ieee754} error]} {
|
||||
puts "Skipping ieee754 tests, hit load error: $error"
|
||||
finish_test; return
|
||||
}
|
||||
|
||||
do_execsql_test 6000 {
|
||||
CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT);
|
||||
WITH RECURSIVE c(x,v) AS (
|
||||
VALUES(0,'1')
|
||||
UNION ALL
|
||||
SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971
|
||||
) INSERT INTO pow2(x,v) SELECT x, v FROM c;
|
||||
WITH RECURSIVE c(x,v) AS (
|
||||
VALUES(-1,'0.5')
|
||||
UNION ALL
|
||||
SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075
|
||||
) INSERT INTO pow2(x,v) SELECT x, v FROM c;
|
||||
} {}
|
||||
do_execsql_test 6010 {
|
||||
WITH c(n) AS (SELECT ieee754_from_blob(x'0000000000000001'))
|
||||
SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
|
||||
FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
|
||||
} {0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625}
|
||||
do_execsql_test 6020 {
|
||||
WITH c(n) AS (SELECT ieee754_from_blob(x'7fefffffffffffff'))
|
||||
SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
|
||||
FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
|
||||
} {179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368}
|
||||
|
||||
do_execsql_test 6100 {
|
||||
SELECT ieee754(ieee754_from_blob(x'0000000000000001'));
|
||||
} {ieee754(1,-1074)}
|
||||
do_execsql_test 6110 {
|
||||
SELECT ieee754(ieee754_from_blob(x'7fefffffffffffff'));
|
||||
} {ieee754(9007199254740991,971)}
|
||||
do_execsql_test 6120 {
|
||||
SELECT printf('%.8e',ieee754_from_blob(x'0000000000000001'));
|
||||
} {4.94065646e-324}
|
||||
do_execsql_test 6130 {
|
||||
SELECT printf('%.8e',ieee754_from_blob(x'ffefffffffffffff'));
|
||||
} {-1.79769313e+308}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -127,8 +127,8 @@ foreach {tn tbl droptrigger before after} {
|
||||
} $after
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-50239-29811 Once removed, the trigger definition is no
|
||||
# longer present in the sqlite_master (or sqlite_temp_master) table and
|
||||
# EVIDENCE-OF: R-04950-25529 Once removed, the trigger definition is no
|
||||
# longer present in the sqlite_schema (or sqlite_temp_schema) table and
|
||||
# is not fired by any subsequent INSERT, UPDATE or DELETE statements.
|
||||
#
|
||||
# Test cases e_droptrigger-1.* test the first part of this statement
|
||||
|
||||
+2
-2
@@ -2528,8 +2528,8 @@ test_efkey_6 3 "ALTER TABLE tbl ADD COLUMN c DEFAULT 0 REFERENCES xx" 1
|
||||
#
|
||||
# Test that these adjustments are visible in the sqlite_master table.
|
||||
#
|
||||
# EVIDENCE-OF: R-63827-54774 The text of the child CREATE TABLE
|
||||
# statement or statements stored in the sqlite_master table are modified
|
||||
# EVIDENCE-OF: R-43040-62530 The text of the child CREATE TABLE
|
||||
# statement or statements stored in the sqlite_schema table are modified
|
||||
# to reflect the new parent table name.
|
||||
#
|
||||
do_test e_fkey-56.1 {
|
||||
|
||||
@@ -204,4 +204,22 @@ do_execsql_test 6.3 {
|
||||
SELECT (SELECT COUNT(a) FROM t2) FROM t1;
|
||||
} {2}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(321, 100000);
|
||||
INSERT INTO t1 VALUES(111, 110000);
|
||||
INSERT INTO t1 VALUES(444, 120000);
|
||||
INSERT INTO t1 VALUES(222, 130000);
|
||||
}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
SELECT max(a), max(a) FILTER (WHERE b<12345), b FROM t1;
|
||||
} {
|
||||
444 {} 120000
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+62
-3
@@ -15,10 +15,10 @@
|
||||
# EVIDENCE-OF: R-15402-03103 PRAGMA schema.foreign_key_check; PRAGMA
|
||||
# schema.foreign_key_check(table-name);
|
||||
#
|
||||
# EVIDENCE-OF: R-23918-17301 The foreign_key_check pragma checks the
|
||||
# EVIDENCE-OF: R-41653-15278 The foreign_key_check pragma checks the
|
||||
# database, or the table called "table-name", for foreign key
|
||||
# constraints that are violated and returns one row of output for each
|
||||
# violation.
|
||||
# constraints that are violated. The foreign_key_check pragma returns
|
||||
# one row output for each foreign key violation.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -430,4 +430,63 @@ do_catchsql_test 11.1 {
|
||||
PRAGMA foreign_key_check;
|
||||
} {1 {foreign key mismatch - "c11" referencing "tt"}}
|
||||
|
||||
# 2020-07-03 Bug in foreign_key_check discovered while working on the
|
||||
# forum reports that pragma_foreign_key_check does not accept an argument:
|
||||
# If two separate schemas seem to reference one another, that causes
|
||||
# problems for foreign_key_check.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 12.0 {
|
||||
ATTACH ':memory:' as aux;
|
||||
CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b TEXT REFERENCES t2);
|
||||
CREATE TABLE main.t2(x TEXT PRIMARY KEY, y INT);
|
||||
INSERT INTO main.t2 VALUES('abc',11),('def',22),('xyz',99);
|
||||
INSERT INTO aux.t1 VALUES(5,'abc'),(7,'xyz'),(9,'oops');
|
||||
PRAGMA foreign_key_check=t1;
|
||||
} {t1 5 t2 0 t1 7 t2 0 t1 9 t2 0}
|
||||
do_execsql_test 12.1 {
|
||||
CREATE TABLE aux.t2(x TEXT PRIMARY KEY, y INT);
|
||||
INSERT INTO aux.t2 VALUES('abc',11),('def',22),('xyz',99);
|
||||
PRAGMA foreign_key_check=t1;
|
||||
} {t1 9 t2 0}
|
||||
|
||||
# 2020-07-03: the pragma_foreign_key_check virtual table should
|
||||
# accept arguments for the table name and/or schema name.
|
||||
#
|
||||
ifcapable vtab {
|
||||
do_execsql_test 13.0 {
|
||||
SELECT *, 'x' FROM pragma_foreign_key_check('t1');
|
||||
} {t1 9 t2 0 x}
|
||||
do_catchsql_test 13.1 {
|
||||
SELECT *, 'x' FROM pragma_foreign_key_check('t1','main');
|
||||
} {1 {no such table: main.t1}}
|
||||
do_execsql_test 13.2 {
|
||||
SELECT *, 'x' FROM pragma_foreign_key_check('t1','aux');
|
||||
} {t1 9 t2 0 x}
|
||||
}
|
||||
|
||||
ifcapable vtab {
|
||||
reset_db
|
||||
do_execsql_test 13.10 {
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT REFERENCES t2);
|
||||
CREATE TABLE t2(x TEXT PRIMARY KEY, y INT);
|
||||
CREATE TABLE t3(w TEXT, z INT REFERENCES t1);
|
||||
INSERT INTO t2 VALUES('abc',11),('def',22),('xyz',99);
|
||||
INSERT INTO t1 VALUES(5,'abc'),(7,'xyz'),(9,'oops');
|
||||
INSERT INTO t3 VALUES(11,7),(22,19);
|
||||
} {}
|
||||
do_execsql_test 13.11 {
|
||||
SELECT x.*, '|'
|
||||
FROM sqlite_schema, pragma_foreign_key_check(name) AS x
|
||||
WHERE type='table'
|
||||
ORDER BY x."table";
|
||||
} {t1 9 t2 0 | t3 2 t1 0 |}
|
||||
do_execsql_test 13.12 {
|
||||
SELECT *, '|'
|
||||
FROM pragma_foreign_key_check AS x
|
||||
ORDER BY x."table";
|
||||
} {t1 9 t2 0 | t3 2 t1 0 |}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -27,6 +27,7 @@ ifcapable !fts3 {
|
||||
|
||||
sqlite3_fts3_may_be_corrupt 1
|
||||
database_may_be_corrupt
|
||||
extra_schema_checks 0
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
BEGIN;
|
||||
@@ -6150,4 +6151,151 @@ do_execsql_test 43.2 {
|
||||
|
||||
set sqlite_fts3_enable_parentheses $saved
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 44.1 {
|
||||
CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
|
||||
INSERT INTO t0_content VALUES(0,NULL,NULL,NULL,NULL);
|
||||
INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'00013103010200010332333405010201ba00000461616161050101020200000462626262050101030200');
|
||||
}
|
||||
|
||||
do_execsql_test 44.2 {
|
||||
SELECT matchinfo(t0, t0) IS NULL FROM t0 WHERE t0 MATCH '1*'
|
||||
} {0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_test 45.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 24576 pagesize 4096 filename crash-65c98512cc9e49.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
|
||||
| 96: 00 00 00 00 0d 0e fc 00 06 0d bc 00 0f ca 0f 6c ...............l
|
||||
| 112: 0f 04 0e 13 0e c9 0d bc 00 00 00 00 00 00 00 00 ................
|
||||
| 3504: 00 00 00 00 00 00 00 00 00 00 00 00 55 06 07 17 ............U...
|
||||
| 3520: 1b 1b 01 81 01 74 61 62 6c 65 78 31 5f 73 74 61 .....tablex1_sta
|
||||
| 3536: 74 78 31 5f 73 74 61 74 06 43 52 45 41 54 45 20 tx1_stat.CREATE
|
||||
| 3552: 54 41 42 4c 45 20 27 78 31 5f 73 74 61 74 27 28 TABLE 'x1_stat'(
|
||||
| 3568: 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 id INTEGER PRIMA
|
||||
| 3584: 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 4c RY KEY, value BL
|
||||
| 3600: 41 82 29 81 33 04 07 17 1f 1f 01 82 35 74 61 62 A.).3.......5tab
|
||||
| 3616: 6c 65 78 31 5f 73 65 67 64 69 72 78 31 5f 73 65 lex1_segdirx1_se
|
||||
| 3632: 67 64 69 72 04 43 52 45 41 54 45 20 54 41 42 4c gdir.CREATE TABL
|
||||
| 3648: 45 20 27 78 31 5f 73 65 67 64 69 72 27 28 6c 65 E 'x1_segdir'(le
|
||||
| 3664: 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 64 78 20 vel INTEGER,idx
|
||||
| 3680: 49 4e 54 45 47 45 52 2c 73 74 61 72 74 5f 62 6c INTEGER,start_bl
|
||||
| 3696: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c 65 61 76 ock INTEGER,leav
|
||||
| 3712: 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 es_end_block INT
|
||||
| 3728: 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 6b 20 49 EGER,end_block I
|
||||
| 3744: 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 4c 4f 42 NTEGER,root BLOB
|
||||
| 3760: 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 6c 65 76 ,PRIMARY KEY(lev
|
||||
| 3776: 65 6c 2c 20 69 64 78 29 29 31 05 06 17 45 1f 01 el, idx))1...E..
|
||||
| 3792: 00 69 6e 64 65 78 73 71 6c 69 74 65 5f 61 75 74 .indexsqlite_aut
|
||||
| 3808: 6f 69 6e 64 65 78 5f 78 31 5f 73 65 67 64 69 72 oindex_x1_segdir
|
||||
| 3824: 5f 31 78 31 5f 73 65 67 64 69 72 05 00 00 00 08 _1x1_segdir.....
|
||||
| 3840: 60 00 00 00 66 03 07 17 23 23 01 81 13 74 61 62 `...f...##...tab
|
||||
| 3856: 6c 65 78 31 5f 73 65 67 6d 65 6e 74 73 78 31 5f lex1_segmentsx1_
|
||||
| 3872: 73 65 67 6d 65 6e 74 73 03 43 52 45 41 54 45 20 segments.CREATE
|
||||
| 3888: 54 41 42 4c 45 20 27 78 31 5f 73 65 67 6d 65 6e TABLE 'x1_segmen
|
||||
| 3904: 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 4e 54 45 ts'(blockid INTE
|
||||
| 3920: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
|
||||
| 3936: 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c 02 07 17 block BLOB)....
|
||||
| 3952: 21 21 01 81 03 74 61 62 6c 65 78 31 5f 63 6f 6e !!...tablex1_con
|
||||
| 3968: 74 65 6e 74 78 31 5f 63 6f 6e 74 65 6e 74 02 43 tentx1_content.C
|
||||
| 3984: 52 45 41 54 45 20 54 41 42 4c 45 20 27 78 31 5f REATE TABLE 'x1_
|
||||
| 4000: 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 64 20 49 content'(docid I
|
||||
| 4016: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K
|
||||
| 4032: 45 59 2c 20 27 63 30 78 27 29 34 01 06 17 11 11 EY, 'c0x')4.....
|
||||
| 4048: 08 57 74 61 62 6c 65 78 31 78 31 43 52 45 41 54 .Wtablex1x1CREAT
|
||||
| 4064: 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 E VIRTUAL TABLE
|
||||
| 4080: 78 31 20 55 53 49 4e 47 20 66 74 73 33 28 78 29 x1 USING fts3(x)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 00 00 00 11 0f 77 f0 0f f8 0f f0 0f e8 0f e0 ......w.........
|
||||
| 16: 0f d8 0f d0 0f c8 0f c0 00 00 00 00 00 00 00 00 ................
|
||||
| 3952: 00 00 00 00 00 00 00 00 06 11 03 00 13 77 78 79 .............wxy
|
||||
| 3968: 06 10 03 00 13 74 75 76 06 0f 03 00 13 71 33 73 .....tuv.....q3s
|
||||
| 3984: 06 0e 03 00 13 6e 6f 70 06 0d 03 00 13 6b 6c 6d .....nop.....klm
|
||||
| 4000: 06 0c 03 04 c3 68 69 6a 06 0b 03 00 13 65 66 67 .....hij.....efg
|
||||
| 4016: 06 0a 03 00 13 62 63 64 06 09 03 00 13 79 7a 61 .....bcd.....yza
|
||||
| 4032: 06 08 03 00 13 76 77 78 06 07 03 00 13 73 74 75 .....vwx.....stu
|
||||
| 4048: 06 06 03 00 13 70 71 72 06 05 03 00 13 6d 6e 6f .....pqr.....mno
|
||||
| 4064: 06 03 03 00 13 6a 6b 6c 06 03 03 00 13 67 68 69 .....jkl.....ghi
|
||||
| 4080: 06 02 02 00 03 64 65 66 06 01 03 00 13 61 52 63 .....def.....aRc
|
||||
| page 3 offset 8192
|
||||
| 0: 0d 00 00 00 03 0f a7 00 0f b5 0f a7 0f fa 01 00 ................
|
||||
| 4000: 00 00 00 00 00 00 00 0c 02 03 00 1e 00 03 6b 6c ..............kl
|
||||
| 4016: 6d 03 0d 02 00 43 01 04 00 81 0a 00 03 61 62 63 m....C.......abc
|
||||
| 4032: 03 0b 32 00 00 03 62 63 64 03 0a 02 00 00 03 64 ..2...bcd......d
|
||||
| 4048: 69 26 03 02 02 00 00 03 65 66 67 03 0b 02 00 00 i&......efg.....
|
||||
| 4064: 03 67 68 69 03 03 02 00 00 03 68 69 6a 03 0c 02 .ghi......hij...
|
||||
| 4080: 00 00 03 6a 6a 2c 03 04 02 00 03 81 00 03 00 00 ...jj,..........
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 0f 3a 00 05 0f 25 00 0f 9e 0f 88 0f 43 0f 25 ..:...%......C.%
|
||||
| 16: 0f 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .r..............
|
||||
| 3856: 00 00 00 00 00 00 00 00 00 56 01 08 08 13 1e 03 .........V......
|
||||
| 3872: 30 20 39 00 03 13 05 07 08 08 18 08 13 1e 30 20 0 9...........0
|
||||
| 3888: 39 00 03 77 78 79 03 11 02 00 0f 6c 00 09 01 08 9..wxy.....l....
|
||||
| 3904: 08 15 54 27 04 07 09 01 08 08 15 42 02 30 20 33 ..T'.......B.0 3
|
||||
| 3920: 36 00 03 6e 6f 70 03 0e 02 00 00 03 71 72 73 03 6..nop......qrs.
|
||||
| 3936: 0f 02 00 00 03 74 75 76 03 10 02 00 0f cf b1 06 .....tuv........
|
||||
| 3952: 01 08 14 06 07 01 08 09 01 1b 14 02 02 31 32 38 .............128
|
||||
| 3968: 20 2d 37 32 10 01 01 6b 14 03 07 09 09 08 08 15 -72...k........
|
||||
| 3984: 1e 30 20 33 36 00 03 79 7a 61 03 09 02 00 2f 02 .0 36..yza..../.
|
||||
| 4000: 07 09 08 08 08 15 54 30 20 33 36 00 03 6d 6e 6f ......T0 36..mno
|
||||
| 4016: 03 05 02 00 00 03 70 71 72 03 06 02 00 00 03 73 ......pqr......s
|
||||
| 4032: 74 75 03 07 02 00 00 03 76 77 78 03 08 02 00 00 tu......vwx.....
|
||||
| 4048: 00 00 4a 08 08 08 15 54 30 20 33 36 00 03 61 62 ..J....T0 36..ab
|
||||
| 4064: 63 03 01 02 00 00 03 64 65 66 03 02 02 00 00 03 c......def......
|
||||
| 4080: 67 68 69 03 03 67 00 00 03 6a 6b 6c 03 04 02 00 ghi..g...jkl....
|
||||
| page 5 offset 16384
|
||||
| 0: 0a 0f e7 00 05 0f da 00 0f e1 0f fa 0f f4 0f ed ................
|
||||
| 16: 0f da 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4048: 00 00 00 00 00 00 00 1a 01 03 06 04 01 08 01 02 ................
|
||||
| 4064: 06 05 04 08 08 01 05 00 00 00 06 01 03 06 04 09 ................
|
||||
| 4080: 02 01 02 04 05 04 09 09 01 03 05 04 09 08 01 02 ................
|
||||
| page 6 offset 20480
|
||||
| 0: 0d 00 10 00 01 0f f9 00 0f f9 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 05 01 03 00 10 01 03 ................
|
||||
| end crash-65c98512cc9e49.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 45.2 {
|
||||
INSERT INTO x1(x1) VALUES( 'merge=1' )
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
set saved $sqlite_fts3_enable_parentheses
|
||||
set sqlite_fts3_enable_parentheses 1
|
||||
do_execsql_test 46.1 {
|
||||
CREATE VIRTUAL TABLE t0 USING fts3(a INTEGER PRIMARY KEY,b,c,d);
|
||||
INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'0001310301c9000103323334050d8000f200000461616161050101020200000462626262050101030200');
|
||||
} {}
|
||||
|
||||
do_catchsql_test 46.2 {
|
||||
SELECT * FROM t0
|
||||
WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
set sqlite_fts3_enable_parentheses $saved
|
||||
extra_schema_checks 1
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 47.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts3(a,b,c);
|
||||
}
|
||||
do_execsql_test 47.2 {
|
||||
INSERT INTO t1_segdir VALUES(0,0,0,0,0,X'000130120106000106000106001f030001030001030000083230313630363039090107000107000107000001340901050001050001050000013509010400010400010400010730303030303030091c0400010400010400000662696e6172793c0301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000008636f6d70696c657209010200010200010200000664627374617409070300010300010300010465627567090402000102000102000006656e61626c653f07020001020001020001020001020001020001020001020001020001020001020001020001010001020001020001020001020001020001020001020001020001087874656e73696f6e091f0400010400010400000466747334090a0300010300010300030135090d03000103000103000003676363090103000103000103000106656f706f6c790910030001030001030000056a736f6e310913030001030001030000046c6f6164091f030001030001030000036d6178091c02000102000102000105656d6f7279091c03000103000103000304737973350916030001030001030000066e6f636173653c02010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020000046f6d6974091f020001020001020000057274726565091903000103000103000302696d3c01010202000301020200030102020003010202000301020200030102020003010202000301a202000301020200030102020003010202000301020200000a746872656164736166650922020001020001020000047674616209070400010400010400000178b401010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200');
|
||||
INSERT INTO t1_segdir VALUES(0,1,0,0,0,X'0001300425061b000008323031363036303903250700000134032505000001350325040001073030303030303003251a000008636f6d70696c657203250200000664627374617403250a00010465627567032508000006656e61626c650925090504040404040001087874656e73696f6e03251d0000046674733403250d0003013503250f000003676363032503000106656f706f6c790325110000056a736f6e310325130000046c6f616403251c0000036d6178032518000105656d6f7279032519000304737973350325150000046f6d697403251b000005727472656503251700000a7468726561647361666503251e0000047674616333250b00');
|
||||
}
|
||||
|
||||
do_catchsql_test 47.3 {
|
||||
SELECT matchinfo(t1) FROM t1 WHERE t1 MATCH '"json1 enable"';
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
# 2020 February 24
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing UPDATE statements with FROM clauses
|
||||
# against FTS4 tables.
|
||||
#
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts4upfrom
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
foreach {tn create_table} {
|
||||
0 { CREATE VIRTUAL TABLE ft USING fts5(a, b, c) }
|
||||
1 { CREATE VIRTUAL TABLE ft USING fts3(a, b, c) }
|
||||
2 { CREATE TABLE ft(a, b, c) }
|
||||
3 {
|
||||
CREATE TABLE real(a, b, c);
|
||||
CREATE INDEX i1 ON real(a);
|
||||
CREATE VIEW ft AS SELECT rowid, a, b, c FROM real;
|
||||
CREATE TRIGGER tr1 INSTEAD OF INSERT ON ft BEGIN
|
||||
INSERT INTO real(rowid, a, b, c) VALUES(new.rowid, new.a, new.b, new.c);
|
||||
END;
|
||||
CREATE TRIGGER tr2 INSTEAD OF UPDATE ON ft BEGIN
|
||||
UPDATE real SET rowid=new.rowid, a=new.a, b=new.b, c=new.c
|
||||
WHERE rowid=old.rowid;
|
||||
END;
|
||||
}
|
||||
} {
|
||||
if {$tn==0} { ifcapable !fts5 { continue } }
|
||||
catchsql { DROP VIEW IF EXISTS changes }
|
||||
catchsql { DROP TABLE IF EXISTS ft }
|
||||
catchsql { DROP VIEW IF EXISTS ft }
|
||||
execsql $create_table
|
||||
|
||||
do_execsql_test 1.$tn.0 {
|
||||
INSERT INTO ft(a, b, c) VALUES('a', NULL, 'apple');
|
||||
INSERT INTO ft(a, b, c) VALUES('b', NULL, 'banana');
|
||||
INSERT INTO ft(a, b, c) VALUES('c', NULL, 'cherry');
|
||||
INSERT INTO ft(a, b, c) VALUES('d', NULL, 'damson plum');
|
||||
}
|
||||
|
||||
do_execsql_test 1.$tn.1 {
|
||||
SELECT a, b, c FROM ft ORDER BY rowid;
|
||||
} {
|
||||
a {} apple
|
||||
b {} banana
|
||||
c {} cherry
|
||||
d {} {damson plum}
|
||||
}
|
||||
|
||||
do_execsql_test 1.$tn.2 {
|
||||
UPDATE ft SET b=o.c FROM ft AS o WHERE (ft.a == char(unicode(o.a)+1))
|
||||
}
|
||||
|
||||
do_execsql_test 1.$tn.3 {
|
||||
SELECT a, b, c FROM ft ORDER BY rowid;
|
||||
} {
|
||||
a {} apple
|
||||
b apple banana
|
||||
c banana cherry
|
||||
d cherry {damson plum}
|
||||
}
|
||||
|
||||
do_catchsql_test 1.$tn.4 {
|
||||
UPDATE ft SET c=v FROM changes WHERE a=k;
|
||||
} {1 {no such table: changes}}
|
||||
|
||||
do_execsql_test 1.$tn.5 {
|
||||
create view changes(k, v) AS
|
||||
VALUES( 'd', 'dewberry' ) UNION ALL
|
||||
VALUES( 'c', 'clementine' ) UNION ALL
|
||||
VALUES( 'b', 'blueberry' ) UNION ALL
|
||||
VALUES( 'a', 'apricot' )
|
||||
;
|
||||
}
|
||||
|
||||
do_execsql_test 1.$tn.6 {
|
||||
UPDATE ft SET c=v FROM changes WHERE a=k;
|
||||
}
|
||||
|
||||
do_execsql_test 1.$tn.7 {
|
||||
SELECT rowid, a, b, c FROM ft ORDER BY rowid;
|
||||
} {
|
||||
1 a {} apricot
|
||||
2 b apple blueberry
|
||||
3 c banana clementine
|
||||
4 d cherry dewberry
|
||||
}
|
||||
|
||||
do_execsql_test 1.$tn.8 "
|
||||
WITH x1(o, n) AS (
|
||||
VALUES(1, 11) UNION ALL
|
||||
VALUES(2, 12) UNION ALL
|
||||
VALUES(3, 13) UNION ALL
|
||||
VALUES(4, 14)
|
||||
)
|
||||
SELECT ft.rowid, a, b, c, o, n FROM ft, x1 WHERE ft.rowid = o;
|
||||
" {
|
||||
1 a {} apricot 1 11
|
||||
2 b apple blueberry 2 12
|
||||
3 c banana clementine 3 13
|
||||
4 d cherry dewberry 4 14
|
||||
}
|
||||
|
||||
set ROWID rowid
|
||||
if {$tn==1} { set ROWID docid }
|
||||
do_execsql_test 1.$tn.9 "
|
||||
WITH x1(o, n) AS (
|
||||
VALUES(1, 11) UNION ALL
|
||||
VALUES(2, 12) UNION ALL
|
||||
VALUES(3, 13) UNION ALL
|
||||
VALUES(4, 14)
|
||||
)
|
||||
UPDATE ft SET $ROWID = n FROM x1 WHERE ft.rowid = o;
|
||||
SELECT rowid, a, b, c FROM ft ORDER BY rowid;
|
||||
" {
|
||||
11 a {} apricot
|
||||
12 b apple blueberry
|
||||
13 c banana clementine
|
||||
14 d cherry dewberry
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
Binary file not shown.
@@ -560,4 +560,30 @@ do_catchsql_test gencol1-19.10 {
|
||||
INSERT INTO t0(c1) VALUES(0.16334143182538696), (0);
|
||||
} {1 {UNIQUE constraint failed: t0.c0}}
|
||||
|
||||
# 2020-06-29 forum bug report.
|
||||
# https://sqlite.org/forum/forumpost/73b9a8ccfb
|
||||
#
|
||||
do_execsql_test gencol1-20.1 {
|
||||
CREATE TEMPORARY TABLE tab (
|
||||
prim DATE PRIMARY KEY,
|
||||
a INTEGER,
|
||||
comp INTEGER AS (a),
|
||||
b INTEGER,
|
||||
x INTEGER
|
||||
);
|
||||
-- Add some data
|
||||
INSERT INTO tab (prim, a, b) VALUES ('2001-01-01', 0, 0);
|
||||
-- Check that each column is 0 like I expect
|
||||
SELECT * FROM tab;
|
||||
} {2001-01-01 0 0 0 {}}
|
||||
do_execsql_test gencol1-20.2 {
|
||||
-- Do an UPSERT on the b column
|
||||
INSERT INTO tab (prim, b)
|
||||
VALUES ('2001-01-01',5)
|
||||
ON CONFLICT(prim) DO UPDATE SET b=excluded.b;
|
||||
-- Now b is NULL rather than 5
|
||||
SELECT * FROM tab;
|
||||
} {2001-01-01 0 0 5 {}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-3
@@ -142,9 +142,8 @@ do_test hook-4.1.1a {
|
||||
set ::update_hook {}
|
||||
db update_hook [list lappend ::update_hook]
|
||||
#
|
||||
# EVIDENCE-OF: R-52223-27275 The update hook is not invoked when
|
||||
# internal system tables are modified (i.e. sqlite_master and
|
||||
# sqlite_sequence).
|
||||
# EVIDENCE-OF: R-24531-54682 The update hook is not invoked when
|
||||
# internal system tables are modified (i.e. sqlite_sequence).
|
||||
#
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
|
||||
+2
-1
@@ -455,12 +455,13 @@ if {$tcl_platform(platform)!="windows"} {
|
||||
catchsql {
|
||||
SELECT count(*) FROM t3;
|
||||
}
|
||||
} {1 {database disk image is malformed}}
|
||||
} {1 {malformed database schema (t3) - invalid rootpage}}
|
||||
}
|
||||
}
|
||||
|
||||
# Ticket #2470
|
||||
#
|
||||
reset_db
|
||||
do_test misc7-18.1 {
|
||||
execsql {
|
||||
CREATE TABLE table_1 (col_10);
|
||||
|
||||
@@ -1930,6 +1930,7 @@ do_test pager1-18.4 {
|
||||
catchsql { SELECT length(x||'') FROM t2 } db2
|
||||
} {1 {database disk image is malformed}}
|
||||
db2 close
|
||||
extra_schema_checks 0
|
||||
do_test pager1-18.5 {
|
||||
sqlite3 db ""
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
@@ -1944,6 +1945,7 @@ do_test pager1-18.5 {
|
||||
catchsql { SELECT * FROM x1 }
|
||||
} {1 {database disk image is malformed}}
|
||||
db close
|
||||
extra_schema_checks 1
|
||||
|
||||
do_test pager1-18.6 {
|
||||
faultsim_delete_and_reopen
|
||||
|
||||
+18
-2
@@ -136,9 +136,24 @@ if {[info exists ::env(QUICKTEST_INCLUDE)]} {
|
||||
set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)]
|
||||
}
|
||||
if {[info exists ::env(QUICKTEST_OMIT)]} {
|
||||
foreach x [split $::env(QUICKTEST_OMIT) ,] {
|
||||
regsub -all \\y$x\\y $allquicktests {} allquicktests
|
||||
# If environment variable QUICKTEST_OMIT is set, it is a comma-separated
|
||||
# list of regular expressions to match against test file names in
|
||||
# the "allquicktests" set. Any matches are excluded. Only the filename
|
||||
# is matched, not any directory component of the path.
|
||||
set all [list]
|
||||
foreach a $allquicktests {
|
||||
set bIn 1
|
||||
foreach x [split $::env(QUICKTEST_OMIT) ,] {
|
||||
if {[regexp $x [file tail $a]]} {
|
||||
set bIn 0
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$bIn} {
|
||||
lappend all $a
|
||||
}
|
||||
}
|
||||
set allquicktests $all
|
||||
}
|
||||
|
||||
# If the TEST_FAILURE environment variable is set, it means that we what to
|
||||
@@ -974,6 +989,7 @@ test_suite "journaltest" -description {
|
||||
pager1.test syscall.test tkt3457.test *malloc* mmap* multiplex* nolock*
|
||||
pager2.test *fault* rowal* snapshot* superlock* symlink.test
|
||||
delete_db.test shmlock.test chunksize.test
|
||||
busy2.test
|
||||
}]
|
||||
|
||||
if {[info commands register_demovfs] != ""} {
|
||||
|
||||
@@ -18,6 +18,8 @@ sqlite3 sqlite ""
|
||||
|
||||
proc execsql {sql} {
|
||||
|
||||
set sql [string map {{WITHOUT ROWID} {}} $sql]
|
||||
|
||||
set lSql [list]
|
||||
set frag ""
|
||||
while {[string length $sql]>0} {
|
||||
|
||||
+16
-6
@@ -387,11 +387,15 @@ ifcapable attach {
|
||||
PRAGMA integrity_check=4
|
||||
}
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}}
|
||||
do_test pragma-3.6 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=xyz
|
||||
}
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
do_catchsql_test pragma-3.6 {
|
||||
PRAGMA integrity_check=xyz
|
||||
} {1 {no such table: xyz}}
|
||||
do_catchsql_test pragma-3.6b {
|
||||
PRAGMA integrity_check=t2
|
||||
} {0 {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}}
|
||||
do_catchsql_test pragma-3.6c {
|
||||
PRAGMA integrity_check=sqlite_schema
|
||||
} {0 ok}
|
||||
do_test pragma-3.7 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=0
|
||||
@@ -423,7 +427,7 @@ ifcapable attach {
|
||||
do_test pragma-3.8.2 {
|
||||
execsql {PRAGMA QUICK_CHECK}
|
||||
} {ok}
|
||||
do_test pragma-3.9 {
|
||||
do_test pragma-3.9a {
|
||||
execsql {
|
||||
ATTACH 'testerr.db' AS t2;
|
||||
PRAGMA integrity_check
|
||||
@@ -432,6 +436,12 @@ ifcapable attach {
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
do_execsql_test pragma-3.9b {
|
||||
PRAGMA t2.integrity_check=t2;
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
do_execsql_test pragma-3.9c {
|
||||
PRAGMA t2.integrity_check=sqlite_schema;
|
||||
} {ok}
|
||||
do_test pragma-3.10 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=1
|
||||
|
||||
+9
-2
@@ -120,8 +120,15 @@ do_test 4.1.4 {
|
||||
sqlite3 db2 test.db2
|
||||
execsql { DROP TABLE t1 } db3
|
||||
execsql { DROP TABLE t2 } db2
|
||||
} {}
|
||||
do_execsql_test 4.1.5 { PRAGMA table_info(t1) }
|
||||
} {}
|
||||
if {[permutation]=="prepare"} {
|
||||
do_catchsql_test 4.1.5a {
|
||||
PRAGMA table_info(t1)
|
||||
} {1 {database schema has changed}}
|
||||
}
|
||||
do_execsql_test 4.1.5 {
|
||||
PRAGMA table_info(t1)
|
||||
}
|
||||
do_execsql_test 4.1.6 { PRAGMA table_info(t2) }
|
||||
|
||||
db2 close
|
||||
|
||||
@@ -698,7 +698,9 @@ static const char zHelp[] =
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#ifndef OMIT_ZLIB
|
||||
#include "zlib.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
|
||||
@@ -715,6 +717,9 @@ static void sqlarUncompressFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
#ifdef OMIT_ZLIB
|
||||
sqlite3_result_value(context, argv[0]);
|
||||
#else
|
||||
uLong nData;
|
||||
uLongf sz;
|
||||
|
||||
@@ -733,6 +738,7 @@ static void sqlarUncompressFunc(
|
||||
}
|
||||
sqlite3_free(pOut);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1166,4 +1166,57 @@ do_test shell1-7.1.7 {
|
||||
|
||||
}
|
||||
|
||||
# Test case for the ieee754 and decimal extensions in the shell.
|
||||
# See the "floatingpoint.html" file in the documentation for more
|
||||
# information.
|
||||
#
|
||||
do_test shell1-8.1 {
|
||||
catchcmd ":memory:" {
|
||||
-- The pow2 table will hold all the necessary powers of two.
|
||||
CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT);
|
||||
WITH RECURSIVE c(x,v) AS (
|
||||
VALUES(0,'1')
|
||||
UNION ALL
|
||||
SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971
|
||||
) INSERT INTO pow2(x,v) SELECT x, v FROM c;
|
||||
WITH RECURSIVE c(x,v) AS (
|
||||
VALUES(-1,'0.5')
|
||||
UNION ALL
|
||||
SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075
|
||||
) INSERT INTO pow2(x,v) SELECT x, v FROM c;
|
||||
|
||||
-- This query finds the decimal representation of each value in the "c" table.
|
||||
WITH c(n) AS (VALUES(47.49))
|
||||
----XXXXX----------- Replace with whatever you want
|
||||
SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
|
||||
FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
|
||||
}
|
||||
} {0 47.49000000000000198951966012828052043914794921875}
|
||||
do_test shell1-8.2 {
|
||||
catchcmd :memory: {
|
||||
.mode box
|
||||
SELECT ieee754(47.49) AS x;
|
||||
}
|
||||
} {0 {┌───────────────────────────────┐
|
||||
│ x │
|
||||
├───────────────────────────────┤
|
||||
│ ieee754(6683623321994527,-47) │
|
||||
└───────────────────────────────┘}}
|
||||
do_test shell1-8.3 {
|
||||
catchcmd ":memory: --box" {
|
||||
select ieee754(6683623321994527,-47) as x;
|
||||
}
|
||||
} {0 {┌───────┐
|
||||
│ x │
|
||||
├───────┤
|
||||
│ 47.49 │
|
||||
└───────┘}}
|
||||
do_test shell1-8.4 {
|
||||
catchcmd ":memory: --table" {SELECT ieee754_mantissa(47.49) AS M, ieee754_exponent(47.49) AS E;}
|
||||
} {0 {+------------------+-----+
|
||||
| M | E |
|
||||
+------------------+-----+
|
||||
| 6683623321994527 | -47 |
|
||||
+------------------+-----+}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -8,6 +8,7 @@ static const char zHelp[] =
|
||||
"Options:\n"
|
||||
" --autovacuum Enable AUTOVACUUM mode\n"
|
||||
" --cachesize N Set the cache size to N\n"
|
||||
" --checkpoint Run PRAGMA wal_checkpoint after each test case\n"
|
||||
" --exclusive Enable locking_mode=EXCLUSIVE\n"
|
||||
" --explain Like --sqlonly but with added EXPLAIN keywords\n"
|
||||
" --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
|
||||
@@ -91,6 +92,7 @@ static struct Global {
|
||||
int eTemp; /* 0: no TEMP. 9: always TEMP. */
|
||||
int szTest; /* Scale factor for test iterations */
|
||||
int nRepeat; /* Repeat selects this many times */
|
||||
int doCheckpoint; /* Run PRAGMA wal_checkpoint after each trans */
|
||||
const char *zWR; /* Might be WITHOUT ROWID */
|
||||
const char *zNN; /* Might be NOT NULL */
|
||||
const char *zPK; /* Might be UNIQUE or PRIMARY KEY */
|
||||
@@ -390,9 +392,13 @@ void speedtest1_begin_test(int iTestNum, const char *zTestName, ...){
|
||||
g.y = 0x44f9eac8;
|
||||
}
|
||||
|
||||
/* Forward reference */
|
||||
void speedtest1_exec(const char*,...);
|
||||
|
||||
/* Complete a test case */
|
||||
void speedtest1_end_test(void){
|
||||
sqlite3_int64 iElapseTime = speedtest1_timestamp() - g.iStart;
|
||||
if( g.doCheckpoint ) speedtest1_exec("PRAGMA wal_checkpoint;");
|
||||
if( !g.bSqlOnly ){
|
||||
g.iTotal += iElapseTime;
|
||||
printf("%4d.%03ds\n", (int)(iElapseTime/1000), (int)(iElapseTime%1000));
|
||||
@@ -2185,6 +2191,8 @@ int main(int argc, char **argv){
|
||||
cacheSize = integerValue(argv[i]);
|
||||
}else if( strcmp(z,"exclusive")==0 ){
|
||||
doExclusive = 1;
|
||||
}else if( strcmp(z,"checkpoint")==0 ){
|
||||
g.doCheckpoint = 1;
|
||||
}else if( strcmp(z,"explain")==0 ){
|
||||
g.bSqlOnly = 1;
|
||||
g.bExplain = 1;
|
||||
|
||||
@@ -129,6 +129,7 @@ if {[info command sqlite_orig]==""} {
|
||||
set ::dbhandle [lindex $args 0]
|
||||
uplevel #0 $::G(perm:dbconfig)
|
||||
}
|
||||
[lindex $args 0] cache size 3
|
||||
set res
|
||||
} else {
|
||||
# This command is not opening a new database connection. Pass the
|
||||
@@ -2478,6 +2479,7 @@ set sqlite_fts3_enable_parentheses 0
|
||||
# this setting by invoking "database_can_be_corrupt"
|
||||
#
|
||||
database_never_corrupt
|
||||
extra_schema_checks 1
|
||||
|
||||
source $testdir/thread_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
# 2020 July 14
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix triggerupfrom
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE map(k, v);
|
||||
INSERT INTO map VALUES(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four');
|
||||
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
|
||||
CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN
|
||||
UPDATE t1 SET c = v FROM map WHERE k=new.a AND a=new.a;
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
INSERT INTO t1(a) VALUES(1);
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT a, c FROM t1 ORDER BY a;
|
||||
} {1 one}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO t1(a) VALUES(2), (3), (4), (5);
|
||||
SELECT a, c FROM t1 ORDER BY a;
|
||||
} {1 one 2 two 3 three 4 four 5 {}}
|
||||
|
||||
forcedelete test.db2
|
||||
do_execsql_test 2.0 {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.t3(x, y);
|
||||
INSERT INTO aux.t3 VALUES('x', 'y');
|
||||
}
|
||||
|
||||
do_catchsql_test 2.1 {
|
||||
CREATE TRIGGER tr2 AFTER INSERT ON t1 BEGIN
|
||||
UPDATE t1 SET b = y FROM aux.t3 WHERE k=new.a;
|
||||
END;
|
||||
} {1 {trigger tr2 cannot reference objects in database aux}}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
CREATE TEMP TRIGGER tr2 AFTER INSERT ON t1 BEGIN
|
||||
UPDATE t1 SET b = y FROM aux.t3 WHERE a=new.a;
|
||||
END;
|
||||
INSERT INTO t1(a) VALUES(10), (20);
|
||||
SELECT * FROM t1;
|
||||
} {
|
||||
1 {} one
|
||||
2 {} two
|
||||
3 {} three
|
||||
4 {} four
|
||||
5 {} {}
|
||||
10 y {}
|
||||
20 y {}
|
||||
}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
CREATE TABLE link(f, t);
|
||||
INSERT INTO link VALUES(5, 2), (20, 10), (2, 1);
|
||||
CREATE TRIGGER tr3 BEFORE DELETE ON t1 BEGIN
|
||||
UPDATE t1 SET b=coalesce(old.b,old.c) FROM main.link WHERE a=t AND old.a=f;
|
||||
END;
|
||||
DELETE FROM t1 WHERE a=2;
|
||||
SELECT * FROM t1;
|
||||
} {
|
||||
1 two one
|
||||
3 {} three
|
||||
4 {} four
|
||||
5 {} {}
|
||||
10 y {}
|
||||
20 y {}
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db ""
|
||||
do_catchsql_test 2.4 {
|
||||
ATTACH 'test.db' AS yyy;
|
||||
SELECT * FROM t1;
|
||||
} {1 {malformed database schema (tr3) - trigger tr3 cannot reference objects in database main}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE mmm(x, y);
|
||||
INSERT INTO mmm VALUES(1, 'one');
|
||||
INSERT INTO mmm VALUES(2, 'two');
|
||||
INSERT INTO mmm VALUES(3, 'three');
|
||||
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.t1(a, b);
|
||||
CREATE TABLE aux.mmm(x, y);
|
||||
INSERT INTO aux.mmm VALUES(1, 'ONE');
|
||||
INSERT INTO aux.mmm VALUES(2, 'TWO');
|
||||
INSERT INTO aux.mmm VALUES(3, 'THREE');
|
||||
|
||||
CREATE TRIGGER aux.ttt AFTER INSERT ON t1 BEGIN
|
||||
UPDATE t1 SET b=y FROM mmm WHERE x=new.a AND a=new.a;
|
||||
END;
|
||||
|
||||
INSERT INTO t1(a) VALUES (2);
|
||||
SELECT * FROM t1;
|
||||
} {2 TWO}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that INSTEAD OF UPDATE triggers on views work with UPDATE...FROM
|
||||
# statements. Including, if the library is built with ENABLE_HIDDEN_COLUMNS,
|
||||
# that they work correctly on views with hidden columns.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1(k, a, b);
|
||||
INSERT INTO t1 VALUES('a', 1, 'one');
|
||||
INSERT INTO t1 VALUES('b', 2, 'two');
|
||||
INSERT INTO t1 VALUES('c', 3, 'three');
|
||||
INSERT INTO t1 VALUES('d', 4, 'four');
|
||||
|
||||
CREATE TABLE log(x);
|
||||
CREATE VIEW v1 AS SELECT k, a, b AS __hidden__b FROM t1;
|
||||
CREATE TRIGGER tr1 INSTEAD OF UPDATE ON v1 BEGIN
|
||||
INSERT INTO log VALUES(
|
||||
'('||old.a||','||old.__hidden__b||')->('||new.a||','||new.__hidden__b||')'
|
||||
);
|
||||
END;
|
||||
}
|
||||
|
||||
ifcapable hiddencolumns {
|
||||
do_execsql_test 4.1-hc-enabled {
|
||||
SELECT * FROM v1
|
||||
} {a 1 b 2 c 3 d 4}
|
||||
} else {
|
||||
do_execsql_test 4.1-hc-disabled {
|
||||
SELECT * FROM v1
|
||||
} {a 1 one b 2 two c 3 three d 4 four}
|
||||
}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
UPDATE v1 SET a='xyz' WHERE k IN ('a', 'c');
|
||||
SELECT * FROM log;
|
||||
DELETE FROM log;
|
||||
} {
|
||||
(1,one)->(xyz,one)
|
||||
(3,three)->(xyz,three)
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
CREATE TABLE map(k, v);
|
||||
INSERT INTO map VALUES('b', 'twelve');
|
||||
INSERT INTO map VALUES('d', 'fourteen');
|
||||
UPDATE v1 SET a=map.v FROM map WHERE v1.k=map.k;
|
||||
SELECT * FROM log;
|
||||
DELETE FROM log;
|
||||
} {
|
||||
(2,two)->(twelve,two)
|
||||
(4,four)->(fourteen,four)
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
# 2020 April 22
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname $argv0] pg_common.tcl]
|
||||
|
||||
#=========================================================================
|
||||
|
||||
start_test upfrom1 "2020 April 22"
|
||||
|
||||
foreach {tn wo} {
|
||||
1 "WITHOUT ROWID"
|
||||
2 ""
|
||||
} {
|
||||
eval [string map [list %TN% $tn %WITHOUT_ROWID% $wo] {
|
||||
execsql_test 1.%TN%.0 {
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) %WITHOUT_ROWID%;
|
||||
INSERT INTO t2 VALUES(1, 2, 3);
|
||||
INSERT INTO t2 VALUES(4, 5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8, 9);
|
||||
|
||||
DROP TABLE IF EXISTS chng;
|
||||
CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER);
|
||||
INSERT INTO chng VALUES(1, 100, 1000);
|
||||
INSERT INTO chng VALUES(7, 700, 7000);
|
||||
}
|
||||
|
||||
execsql_test 1.%TN%.1 {
|
||||
SELECT * FROM t2;
|
||||
}
|
||||
|
||||
execsql_test 1.%TN%.2 {
|
||||
UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
}
|
||||
|
||||
execsql_test 1.%TN%.3 {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2 VALUES(1, 2, 3);
|
||||
INSERT INTO t2 VALUES(4, 5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8, 9);
|
||||
}
|
||||
|
||||
execsql_test 1.%TN%.4 {
|
||||
UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a)
|
||||
WHERE a IN (SELECT a FROM chng);
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
}
|
||||
|
||||
execsql_test 1.%TN%.5 {
|
||||
DROP TABLE IF EXISTS t3;
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) %WITHOUT_ROWID%;
|
||||
INSERT INTO t3 VALUES(1, 1, 'one');
|
||||
INSERT INTO t3 VALUES(2, 2, 'two');
|
||||
INSERT INTO t3 VALUES(3, 3, 'three');
|
||||
|
||||
DROP TABLE IF EXISTS t4;
|
||||
CREATE TABLE t4(x TEXT);
|
||||
INSERT INTO t4 VALUES('five');
|
||||
|
||||
SELECT * FROM t3 ORDER BY a;
|
||||
}
|
||||
|
||||
execsql_test 1.%TN%.6 {
|
||||
UPDATE t3 SET c=x FROM t4;
|
||||
SELECT * FROM t3 ORDER BY a;
|
||||
}
|
||||
}]}
|
||||
|
||||
execsql_test 2.1 {
|
||||
DROP TABLE IF EXISTS t5;
|
||||
DROP TABLE IF EXISTS m1;
|
||||
DROP TABLE IF EXISTS m2;
|
||||
CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT);
|
||||
CREATE TABLE m1(x INTEGER PRIMARY KEY, y TEXT);
|
||||
CREATE TABLE m2(u INTEGER PRIMARY KEY, v TEXT);
|
||||
|
||||
INSERT INTO t5 VALUES(1, 'one', 'ONE');
|
||||
INSERT INTO t5 VALUES(2, 'two', 'TWO');
|
||||
INSERT INTO t5 VALUES(3, 'three', 'THREE');
|
||||
INSERT INTO t5 VALUES(4, 'four', 'FOUR');
|
||||
|
||||
INSERT INTO m1 VALUES(1, 'i');
|
||||
INSERT INTO m1 VALUES(2, 'ii');
|
||||
INSERT INTO m1 VALUES(3, 'iii');
|
||||
|
||||
INSERT INTO m2 VALUES(1, 'I');
|
||||
INSERT INTO m2 VALUES(3, 'II');
|
||||
INSERT INTO m2 VALUES(4, 'III');
|
||||
}
|
||||
|
||||
execsql_test 2.2 {
|
||||
UPDATE t5 SET b=y, c=v FROM m1 LEFT JOIN m2 ON (x=u) WHERE x=a;
|
||||
SELECT * FROM t5 ORDER BY a;
|
||||
}
|
||||
|
||||
errorsql_test 2.3.1 {
|
||||
UPDATE t5 SET b=1 FROM t5;
|
||||
}
|
||||
errorsql_test 2.3.2 {
|
||||
UPDATE t5 AS apples SET b=1 FROM t5 AS apples;
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
# 2020 April 22
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
####################################################
|
||||
# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
|
||||
####################################################
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix upfrom1
|
||||
|
||||
do_execsql_test 1.1.0 {
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) WITHOUT ROWID;
|
||||
INSERT INTO t2 VALUES(1, 2, 3);
|
||||
INSERT INTO t2 VALUES(4, 5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8, 9);
|
||||
|
||||
DROP TABLE IF EXISTS chng;
|
||||
CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER);
|
||||
INSERT INTO chng VALUES(1, 100, 1000);
|
||||
INSERT INTO chng VALUES(7, 700, 7000);
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.1.1 {
|
||||
SELECT * FROM t2;
|
||||
} {1 2 3 4 5 6 7 8 9}
|
||||
|
||||
do_execsql_test 1.1.2 {
|
||||
UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
} {1 100 1000 4 5 6 7 700 7000}
|
||||
|
||||
do_execsql_test 1.1.3 {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2 VALUES(1, 2, 3);
|
||||
INSERT INTO t2 VALUES(4, 5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8, 9);
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.1.4 {
|
||||
UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a)
|
||||
WHERE a IN (SELECT a FROM chng);
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
} {1 100 1000 4 5 6 7 700 7000}
|
||||
|
||||
do_execsql_test 1.1.5 {
|
||||
DROP TABLE IF EXISTS t3;
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) WITHOUT ROWID;
|
||||
INSERT INTO t3 VALUES(1, 1, 'one');
|
||||
INSERT INTO t3 VALUES(2, 2, 'two');
|
||||
INSERT INTO t3 VALUES(3, 3, 'three');
|
||||
|
||||
DROP TABLE IF EXISTS t4;
|
||||
CREATE TABLE t4(x TEXT);
|
||||
INSERT INTO t4 VALUES('five');
|
||||
|
||||
SELECT * FROM t3 ORDER BY a;
|
||||
} {1 1 one 2 2 two 3 3 three}
|
||||
|
||||
do_execsql_test 1.1.6 {
|
||||
UPDATE t3 SET c=x FROM t4;
|
||||
SELECT * FROM t3 ORDER BY a;
|
||||
} {1 1 five 2 2 five 3 3 five}
|
||||
|
||||
do_execsql_test 1.2.0 {
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) ;
|
||||
INSERT INTO t2 VALUES(1, 2, 3);
|
||||
INSERT INTO t2 VALUES(4, 5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8, 9);
|
||||
|
||||
DROP TABLE IF EXISTS chng;
|
||||
CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER);
|
||||
INSERT INTO chng VALUES(1, 100, 1000);
|
||||
INSERT INTO chng VALUES(7, 700, 7000);
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2.1 {
|
||||
SELECT * FROM t2;
|
||||
} {1 2 3 4 5 6 7 8 9}
|
||||
|
||||
do_execsql_test 1.2.2 {
|
||||
UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
} {1 100 1000 4 5 6 7 700 7000}
|
||||
|
||||
do_execsql_test 1.2.3 {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2 VALUES(1, 2, 3);
|
||||
INSERT INTO t2 VALUES(4, 5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8, 9);
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2.4 {
|
||||
UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a)
|
||||
WHERE a IN (SELECT a FROM chng);
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
} {1 100 1000 4 5 6 7 700 7000}
|
||||
|
||||
do_execsql_test 1.2.5 {
|
||||
DROP TABLE IF EXISTS t3;
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) ;
|
||||
INSERT INTO t3 VALUES(1, 1, 'one');
|
||||
INSERT INTO t3 VALUES(2, 2, 'two');
|
||||
INSERT INTO t3 VALUES(3, 3, 'three');
|
||||
|
||||
DROP TABLE IF EXISTS t4;
|
||||
CREATE TABLE t4(x TEXT);
|
||||
INSERT INTO t4 VALUES('five');
|
||||
|
||||
SELECT * FROM t3 ORDER BY a;
|
||||
} {1 1 one 2 2 two 3 3 three}
|
||||
|
||||
do_execsql_test 1.2.6 {
|
||||
UPDATE t3 SET c=x FROM t4;
|
||||
SELECT * FROM t3 ORDER BY a;
|
||||
} {1 1 five 2 2 five 3 3 five}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
DROP TABLE IF EXISTS t5;
|
||||
DROP TABLE IF EXISTS m1;
|
||||
DROP TABLE IF EXISTS m2;
|
||||
CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT);
|
||||
CREATE TABLE m1(x INTEGER PRIMARY KEY, y TEXT);
|
||||
CREATE TABLE m2(u INTEGER PRIMARY KEY, v TEXT);
|
||||
|
||||
INSERT INTO t5 VALUES(1, 'one', 'ONE');
|
||||
INSERT INTO t5 VALUES(2, 'two', 'TWO');
|
||||
INSERT INTO t5 VALUES(3, 'three', 'THREE');
|
||||
INSERT INTO t5 VALUES(4, 'four', 'FOUR');
|
||||
|
||||
INSERT INTO m1 VALUES(1, 'i');
|
||||
INSERT INTO m1 VALUES(2, 'ii');
|
||||
INSERT INTO m1 VALUES(3, 'iii');
|
||||
|
||||
INSERT INTO m2 VALUES(1, 'I');
|
||||
INSERT INTO m2 VALUES(3, 'II');
|
||||
INSERT INTO m2 VALUES(4, 'III');
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
UPDATE t5 SET b=y, c=v FROM m1 LEFT JOIN m2 ON (x=u) WHERE x=a;
|
||||
SELECT * FROM t5 ORDER BY a;
|
||||
} {1 i I 2 ii {} 3 iii II 4 four FOUR}
|
||||
|
||||
# PG says ERROR: table name "t5" specified more than once
|
||||
do_test 2.3.1 { catch { execsql {
|
||||
UPDATE t5 SET b=1 FROM t5;
|
||||
} } } 1
|
||||
|
||||
# PG says ERROR: table name "apples" specified more than once
|
||||
do_test 2.3.2 { catch { execsql {
|
||||
UPDATE t5 AS apples SET b=1 FROM t5 AS apples;
|
||||
} } } 1
|
||||
|
||||
# Problem found by OSSFuzz on 2020-07-20
|
||||
# https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24282
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 3.1 {
|
||||
CREATE TABLE t0(a);
|
||||
CREATE TABLE t1(b);
|
||||
UPDATE t1 SET b=sum(a) FROM t0;
|
||||
SELECT * FROM t0, t1;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,371 @@
|
||||
# 2020 April 29
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix upfrom2
|
||||
|
||||
# Test cases:
|
||||
#
|
||||
# 1.*: Test that triggers are fired correctly for UPDATE FROM statements,
|
||||
# and only once for each row. Except for INSTEAD OF triggers on
|
||||
# views - these are fired once for each row returned by the join,
|
||||
# including duplicates.
|
||||
#
|
||||
# 2.*: Test adding ORDER BY and LIMIT clauses with UPDATE FROM statements.
|
||||
#
|
||||
# 5.*: Test that specifying the target table name or alias in the FROM
|
||||
# clause of an UPDATE statement is an error.
|
||||
#
|
||||
|
||||
foreach {tn wo} {
|
||||
1 ""
|
||||
2 "WITHOUT ROWID"
|
||||
} {
|
||||
reset_db
|
||||
|
||||
eval [string map [list %WO% $wo %TN% $tn] {
|
||||
do_execsql_test 1.%TN%.0 {
|
||||
CREATE TABLE log(t TEXT);
|
||||
CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE) %WO%;
|
||||
CREATE INDEX t1y ON t1(y);
|
||||
|
||||
INSERT INTO t1 VALUES(1, 'i', 'one');
|
||||
INSERT INTO t1 VALUES(2, 'ii', 'two');
|
||||
INSERT INTO t1 VALUES(3, 'iii', 'three');
|
||||
INSERT INTO t1 VALUES(4, 'iv', 'four');
|
||||
|
||||
CREATE TRIGGER tr1 BEFORE UPDATE ON t1 BEGIN
|
||||
INSERT INTO log VALUES(old.z || '->' || new.z);
|
||||
END;
|
||||
CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
|
||||
INSERT INTO log VALUES(old.y || '->' || new.y);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.1 {
|
||||
WITH data(k, v) AS (
|
||||
VALUES(3, 'thirty'), (1, 'ten')
|
||||
)
|
||||
UPDATE t1 SET z=v FROM data WHERE x=k;
|
||||
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM log;
|
||||
} {
|
||||
1 i ten 2 ii two 3 iii thirty 4 iv four
|
||||
one->ten i->i
|
||||
three->thirty iii->iii
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.2 {
|
||||
CREATE TABLE t2(a, b);
|
||||
CREATE TABLE t3(k, v);
|
||||
|
||||
INSERT INTO t3 VALUES(5, 'v');
|
||||
INSERT INTO t3 VALUES(12, 'xii');
|
||||
|
||||
INSERT INTO t2 VALUES(2, 12);
|
||||
INSERT INTO t2 VALUES(3, 5);
|
||||
|
||||
DELETE FROM log;
|
||||
UPDATE t1 SET y=v FROM t2, t3 WHERE t1.x=t2.a AND t3.k=t2.b;
|
||||
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM log;
|
||||
} {
|
||||
1 i ten 2 xii two 3 v thirty 4 iv four
|
||||
two->two ii->xii
|
||||
thirty->thirty iii->v
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.3 {
|
||||
DELETE FROM log;
|
||||
WITH data(k, v) AS (
|
||||
VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve')
|
||||
)
|
||||
UPDATE t1 SET z=v FROM data WHERE x=k;
|
||||
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM log;
|
||||
} {
|
||||
1 i eight 2 xii twelve 3 v thirty 4 iv four
|
||||
ten->eight i->i
|
||||
two->twelve xii->xii
|
||||
}
|
||||
|
||||
do_test 1.%TN%.4 { db changes } {2}
|
||||
|
||||
do_execsql_test 1.%TN%.5 {
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
CREATE TRIGGER v1tr INSTEAD OF UPDATE ON v1 BEGIN
|
||||
UPDATE t1 SET y=new.y, z=new.z WHERE x=new.x;
|
||||
END;
|
||||
|
||||
DELETE FROM log;
|
||||
WITH data(k, v) AS (
|
||||
VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen')
|
||||
)
|
||||
UPDATE v1 SET z=v FROM data WHERE x=k;
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.6 {
|
||||
SELECT * FROM v1;
|
||||
SELECT * FROM log;
|
||||
} {
|
||||
1 i eight 2 xii twelve 3 v fourteen 4 iv sixteen
|
||||
thirty->thirteen v->v
|
||||
thirteen->fourteen v->v
|
||||
four->fifteen iv->iv
|
||||
fifteen->sixteen iv->iv
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------
|
||||
|
||||
do_execsql_test 1.%TN%.7 {
|
||||
CREATE TABLE o1(w, x, y, z UNIQUE, PRIMARY KEY(w, x)) %WO%;
|
||||
CREATE INDEX o1y ON t1(y);
|
||||
|
||||
INSERT INTO o1 VALUES(0, 0, 'i', 'one');
|
||||
INSERT INTO o1 VALUES(0, 1, 'ii', 'two');
|
||||
INSERT INTO o1 VALUES(1, 0, 'iii', 'three');
|
||||
INSERT INTO o1 VALUES(1, 1, 'iv', 'four');
|
||||
|
||||
CREATE TRIGGER tro1 BEFORE UPDATE ON o1 BEGIN
|
||||
INSERT INTO log VALUES(old.z || '->' || new.z);
|
||||
END;
|
||||
CREATE TRIGGER tro2 AFTER UPDATE ON o1 BEGIN
|
||||
INSERT INTO log VALUES(old.y || '->' || new.y);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.8 {
|
||||
DELETE FROM log;
|
||||
WITH data(k, v) AS (
|
||||
VALUES(3, 'thirty'), (1, 'ten')
|
||||
)
|
||||
UPDATE o1 SET z=v FROM data WHERE (1+x+w*2)=k;
|
||||
|
||||
SELECT * FROM o1;
|
||||
SELECT * FROM log;
|
||||
} {
|
||||
0 0 i ten 0 1 ii two 1 0 iii thirty 1 1 iv four
|
||||
one->ten i->i
|
||||
three->thirty iii->iii
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.9 {
|
||||
DELETE FROM log;
|
||||
UPDATE o1 SET y=v FROM t2, t3 WHERE (1+o1.w*2+o1.x)=t2.a AND t3.k=t2.b;
|
||||
|
||||
SELECT * FROM o1;
|
||||
SELECT * FROM log;
|
||||
} {
|
||||
0 0 i ten 0 1 xii two 1 0 v thirty 1 1 iv four
|
||||
two->two ii->xii
|
||||
thirty->thirty iii->v
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.10 {
|
||||
DELETE FROM log;
|
||||
WITH data(k, v) AS (
|
||||
VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve')
|
||||
)
|
||||
UPDATE o1 SET z=v FROM data WHERE (1+w*2+x)=k;
|
||||
|
||||
SELECT * FROM o1;
|
||||
SELECT * FROM log;
|
||||
} {
|
||||
0 0 i eight 0 1 xii twelve 1 0 v thirty 1 1 iv four
|
||||
ten->eight i->i
|
||||
two->twelve xii->xii
|
||||
}
|
||||
|
||||
do_test 1.%TN%.11 { db changes } {2}
|
||||
|
||||
do_execsql_test 1.%TN%.12 {
|
||||
CREATE VIEW w1 AS SELECT * FROM o1;
|
||||
CREATE TRIGGER w1tr INSTEAD OF UPDATE ON w1 BEGIN
|
||||
UPDATE o1 SET y=new.y, z=new.z WHERE w=new.w AND x=new.x;
|
||||
END;
|
||||
|
||||
DELETE FROM log;
|
||||
WITH data(k, v) AS (
|
||||
VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen')
|
||||
)
|
||||
UPDATE w1 SET z=v FROM data WHERE (1+w*2+x)=k;
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.13 {
|
||||
SELECT * FROM w1;
|
||||
SELECT * FROM log;
|
||||
} {
|
||||
0 0 i eight 0 1 xii twelve 1 0 v fourteen 1 1 iv sixteen
|
||||
thirty->thirteen v->v
|
||||
thirteen->fourteen v->v
|
||||
four->fifteen iv->iv
|
||||
fifteen->sixteen iv->iv
|
||||
}
|
||||
|
||||
}]
|
||||
}
|
||||
|
||||
ifcapable update_delete_limit {
|
||||
foreach {tn wo} {
|
||||
1 ""
|
||||
2 "WITHOUT ROWID"
|
||||
} {
|
||||
reset_db
|
||||
|
||||
eval [string map [list %WO% $wo %TN% $tn] {
|
||||
do_execsql_test 2.%TN%.1 {
|
||||
CREATE TABLE x1(a INTEGER PRIMARY KEY, b) %WO%;
|
||||
INSERT INTO x1 VALUES
|
||||
(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'),
|
||||
(5, 'five'), (6, 'six'), (7, 'seven'), (8, 'eight');
|
||||
}
|
||||
|
||||
do_execsql_test 2.%TN%.2 {
|
||||
CREATE TABLE data1(x, y);
|
||||
INSERT INTO data1 VALUES
|
||||
(1, 'eleven'), (1, 'twenty-one'), (2, 'twelve'), (2, 'twenty-two'),
|
||||
(3, 'thirteen'), (3, 'twenty-three'), (4, 'fourteen'), (4, 'twenty-four');
|
||||
}
|
||||
|
||||
do_execsql_test 2.%TN%.3 {
|
||||
UPDATE x1 SET b=y FROM data1 WHERE a=x ORDER BY a LIMIT 3;
|
||||
SELECT * FROM x1;
|
||||
} {
|
||||
1 eleven 2 twelve 3 thirteen 4 four 5 five 6 six 7 seven 8 eight
|
||||
}
|
||||
|
||||
do_execsql_test 2.%TN%.4 {
|
||||
UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b LIMIT 3;
|
||||
SELECT * FROM x1;
|
||||
} {
|
||||
1 eleveneleven 2 twelve 3 thirteenthirteen 4 fourfourteen
|
||||
5 five 6 six 7 seven 8 eight
|
||||
}
|
||||
|
||||
do_catchsql_test 2.%TN%.5 {
|
||||
UPDATE x1 SET b=b||b ORDER BY b;
|
||||
} {1 {ORDER BY without LIMIT on UPDATE}}
|
||||
do_catchsql_test 2.%TN%.6 {
|
||||
UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b;
|
||||
} {1 {ORDER BY without LIMIT on UPDATE}}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
do_execsql_test 2.%TN%.6 {
|
||||
DROP TABLE x1;
|
||||
CREATE TABLE x1(u, v, b, PRIMARY KEY(u, v)) %WO%;
|
||||
INSERT INTO x1 VALUES
|
||||
(0, 1, 'one'), (1, 0, 'two'), (1, 1, 'three'), (2, 0, 'four'),
|
||||
(2, 1, 'five'), (3, 0, 'six'), (3, 1, 'seven'), (4, 0, 'eight');
|
||||
}
|
||||
|
||||
do_execsql_test 2.%TN%.7 {
|
||||
UPDATE x1 SET b=y FROM data1 WHERE (u*2+v)=x ORDER BY u, v LIMIT 3;
|
||||
SELECT * FROM x1;
|
||||
} {
|
||||
0 1 eleven 1 0 twelve 1 1 thirteen 2 0 four
|
||||
2 1 five 3 0 six 3 1 seven 4 0 eight
|
||||
}
|
||||
|
||||
do_execsql_test 2.%TN%.8 {
|
||||
UPDATE x1 SET b=b||y FROM data1 WHERE (u*2+v)=x ORDER BY b LIMIT 3;
|
||||
SELECT * FROM x1;
|
||||
} {
|
||||
0 1 eleveneleven 1 0 twelve 1 1 thirteenthirteen 2 0 fourfourteen
|
||||
2 1 five 3 0 six 3 1 seven 4 0 eight
|
||||
}
|
||||
|
||||
|
||||
}]
|
||||
}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE data(x, y, z);
|
||||
CREATE VIEW t1 AS SELECT * FROM data;
|
||||
CREATE TRIGGER t1_insert INSTEAD OF INSERT ON t1 BEGIN
|
||||
INSERT INTO data VALUES(new.x, new.y, new.z);
|
||||
END;
|
||||
CREATE TRIGGER t1_update INSTEAD OF UPDATE ON t1 BEGIN
|
||||
INSERT INTO log VALUES(old.z || '->' || new.z);
|
||||
END;
|
||||
|
||||
CREATE TABLE log(t TEXT);
|
||||
|
||||
INSERT INTO t1 VALUES(1, 'i', 'one');
|
||||
INSERT INTO t1 VALUES(2, 'ii', 'two');
|
||||
INSERT INTO t1 VALUES(3, 'iii', 'three');
|
||||
INSERT INTO t1 VALUES(4, 'iv', 'four');
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
WITH input(k, v) AS (
|
||||
VALUES(3, 'thirty'), (1, 'ten')
|
||||
)
|
||||
UPDATE t1 SET z=v FROM input WHERE x=k;
|
||||
}
|
||||
|
||||
foreach {tn sql} {
|
||||
2 {
|
||||
CREATE TABLE x1(a INT PRIMARY KEY, b, c) WITHOUT ROWID;
|
||||
}
|
||||
1 {
|
||||
CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c);
|
||||
}
|
||||
3 {
|
||||
CREATE TABLE x1(a INT PRIMARY KEY, b, c);
|
||||
}
|
||||
} {
|
||||
|
||||
reset_db
|
||||
execsql $sql
|
||||
|
||||
do_execsql_test 4.$tn.0 {
|
||||
INSERT INTO x1 VALUES(1, 1, 1);
|
||||
INSERT INTO x1 VALUES(2, 2, 2);
|
||||
INSERT INTO x1 VALUES(3, 3, 3);
|
||||
INSERT INTO x1 VALUES(4, 4, 4);
|
||||
INSERT INTO x1 VALUES(5, 5, 5);
|
||||
CREATE TABLE map(o, t);
|
||||
INSERT INTO map VALUES(3, 30), (4, 40), (1, 10);
|
||||
}
|
||||
|
||||
do_execsql_test 4.$tn.1 {
|
||||
UPDATE x1 SET a=t FROM map WHERE a=o;
|
||||
SELECT * FROM x1 ORDER BY a;
|
||||
} {2 2 2 5 5 5 10 1 1 30 3 3 40 4 4}
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE x1(a, b, c);
|
||||
CREATE TABLE x2(a, b, c);
|
||||
}
|
||||
|
||||
foreach {tn update nm} {
|
||||
1 "UPDATE x1 SET a=5 FROM x1" x1
|
||||
2 "UPDATE x1 AS grapes SET a=5 FROM x1 AS grapes" grapes
|
||||
3 "UPDATE x1 SET a=5 FROM x2, x1" x1
|
||||
4 "UPDATE x1 AS grapes SET a=5 FROM x2, x1 AS grapes" grapes
|
||||
} {
|
||||
do_catchsql_test 5.$tn $update \
|
||||
"1 {target object/alias may not appear in FROM clause: $nm}"
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
# 2020 July 14
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix upfrom3
|
||||
|
||||
# Test plan:
|
||||
#
|
||||
# 1.*: Test UPDATE ... FROM statements that modify IPK fields. And that
|
||||
# modify "INTEGER PRIMARY KEY" fields on WITHOUT ROWID tables.
|
||||
#
|
||||
# 2.*: Test UPDATE ... FROM statements that modify PK fields of WITHOUT
|
||||
# ROWID tables.
|
||||
#
|
||||
# 3.*: Test that UPDATE ... FROM statements are not confused if there
|
||||
# are multiple tables of the same name in attached databases.
|
||||
#
|
||||
# 4.*: Tests for UPDATE ... FROM statements and foreign keys.
|
||||
#
|
||||
|
||||
foreach {tn wo} {
|
||||
1 ""
|
||||
2 "WITHOUT ROWID"
|
||||
} {
|
||||
reset_db
|
||||
eval [string map [list %WO% $wo %TN% $tn] {
|
||||
|
||||
do_execsql_test 1.%TN%.0 {
|
||||
CREATE TABLE log(t TEXT);
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y, z UNIQUE) %WO%;
|
||||
CREATE INDEX t1y ON t1(y);
|
||||
|
||||
INSERT INTO t1 VALUES(1, 'i', 'one');
|
||||
INSERT INTO t1 VALUES(2, 'ii', 'two');
|
||||
INSERT INTO t1 VALUES(3, 'iii', 'three');
|
||||
INSERT INTO t1 VALUES(4, 'iv', 'four');
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.1 {
|
||||
CREATE TABLE x1(o, n);
|
||||
INSERT INTO x1 VALUES(1, 11);
|
||||
INSERT INTO x1 VALUES(2, 12);
|
||||
INSERT INTO x1 VALUES(3, 13);
|
||||
INSERT INTO x1 VALUES(4, 14);
|
||||
UPDATE t1 SET x=n FROM x1 WHERE x=o;
|
||||
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||
} {
|
||||
11 i one
|
||||
12 ii two
|
||||
13 iii three
|
||||
14 iv four
|
||||
}
|
||||
|
||||
do_test 1.%TN%.2 { db changes } 4
|
||||
|
||||
do_execsql_test 1.%TN%.3 {
|
||||
INSERT INTO x1 VALUES(11, 21);
|
||||
INSERT INTO x1 VALUES(12, 22);
|
||||
INSERT INTO x1 VALUES(13, 23);
|
||||
INSERT INTO x1 VALUES(14, 24);
|
||||
|
||||
INSERT INTO x1 VALUES(21, 31);
|
||||
INSERT INTO x1 VALUES(22, 32);
|
||||
INSERT INTO x1 VALUES(23, 33);
|
||||
INSERT INTO x1 VALUES(24, 34);
|
||||
UPDATE t1 SET x=n FROM x1 WHERE x=o;
|
||||
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||
} {
|
||||
21 i one
|
||||
22 ii two
|
||||
23 iii three
|
||||
24 iv four
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.4 {
|
||||
UPDATE t1 SET x=n FROM x1 WHERE x=o;
|
||||
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||
} {
|
||||
31 i one
|
||||
32 ii two
|
||||
33 iii three
|
||||
34 iv four
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.5 {
|
||||
INSERT INTO x1 VALUES(31, 32);
|
||||
INSERT INTO x1 VALUES(33, 34);
|
||||
UPDATE OR REPLACE t1 SET x=n FROM x1 WHERE x=o;
|
||||
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||
} {
|
||||
32 i one
|
||||
34 iii three
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.6 {
|
||||
INSERT INTO t1 VALUES(33, 'ii', 'two');
|
||||
INSERT INTO t1 VALUES(35, 'iv', 'four');
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.7 {
|
||||
CREATE TABLE x2(o, n, zz);
|
||||
INSERT INTO x2 VALUES(32, 41, 'four');
|
||||
INSERT INTO x2 VALUES(33, 42, 'three');
|
||||
UPDATE OR IGNORE t1 SET x=n, z=zz FROM x2 WHERE x=o;
|
||||
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||
} {
|
||||
32 i one
|
||||
33 ii two
|
||||
34 iii three
|
||||
35 iv four
|
||||
}
|
||||
|
||||
do_execsql_test 1.%TN%.8 {
|
||||
UPDATE OR REPLACE t1 SET x=n, z=zz FROM x2 WHERE x=o;
|
||||
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||
} {
|
||||
41 i four
|
||||
42 ii three
|
||||
}
|
||||
|
||||
}]
|
||||
}
|
||||
|
||||
do_execsql_test 2.1.1 {
|
||||
CREATE TABLE u1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
|
||||
INSERT INTO u1 VALUES(0, 0, 0);
|
||||
INSERT INTO u1 VALUES(1, 0, 1);
|
||||
INSERT INTO u1 VALUES(2, 1, 0);
|
||||
INSERT INTO u1 VALUES(3, 1, 1);
|
||||
}
|
||||
|
||||
do_execsql_test 2.1.2 {
|
||||
CREATE TABLE map(f, t);
|
||||
INSERT INTO map VALUES(0, 10);
|
||||
INSERT INTO map VALUES(1, 11);
|
||||
UPDATE u1 SET c=t FROM map WHERE c=f;
|
||||
SELECT * FROM u1 ORDER BY a;
|
||||
} {
|
||||
0 0 10
|
||||
1 0 11
|
||||
2 1 10
|
||||
3 1 11
|
||||
}
|
||||
|
||||
do_execsql_test 2.1.3 {
|
||||
UPDATE u1 SET b=t FROM map WHERE b=f;
|
||||
SELECT * FROM u1 ORDER BY a;
|
||||
} {
|
||||
0 10 10
|
||||
1 10 11
|
||||
2 11 10
|
||||
3 11 11
|
||||
}
|
||||
|
||||
do_execsql_test 2.1.4 {
|
||||
CREATE TABLE map2(o1, o2, n1, n2);
|
||||
INSERT INTO map2 VALUES
|
||||
(10, 10, 50, 50), (10, 11, 50, 60),
|
||||
(11, 10, 60, 50), (11, 11, 60, 60);
|
||||
UPDATE u1 SET b=n1, c=n2 FROM map2 WHERE b=o1 AND c=o2;
|
||||
SELECT * FROM u1 ORDER BY a;
|
||||
} {
|
||||
0 50 50
|
||||
1 50 60
|
||||
2 60 50
|
||||
3 60 60
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
foreach {tn wo} {
|
||||
1 ""
|
||||
2 "WITHOUT ROWID"
|
||||
} {
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
eval [string map [list %WO% $wo %TN% $tn] {
|
||||
do_execsql_test 3.$tn.1 {
|
||||
CREATE TABLE g1(a, b, c, PRIMARY KEY(a, b)) %WO%;
|
||||
INSERT INTO g1 VALUES(1, 1, 1);
|
||||
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.g1(a, b, c, PRIMARY KEY(a, b)) %WO%;
|
||||
INSERT INTO aux.g1 VALUES(10, 1, 10);
|
||||
INSERT INTO aux.g1 VALUES(20, 2, 20);
|
||||
INSERT INTO aux.g1 VALUES(30, 3, 30);
|
||||
}
|
||||
|
||||
do_execsql_test 3.$tn.2 {
|
||||
UPDATE aux.g1 SET c=101 FROM main.g1;
|
||||
}
|
||||
do_execsql_test 3.$tn.3 {
|
||||
SELECT * FROM aux.g1;
|
||||
} {10 1 101 20 2 101 30 3 101}
|
||||
|
||||
do_execsql_test 3.$tn.4 {
|
||||
UPDATE g1 SET c=101 FROM g1 AS g2;
|
||||
}
|
||||
do_execsql_test 3.$tn.5 {
|
||||
SELECT * FROM g1;
|
||||
} {1 1 101}
|
||||
}]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
foreach {tn wo} {
|
||||
1 ""
|
||||
2 "WITHOUT ROWID"
|
||||
} {
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
eval [string map [list %WO% $wo %TN% $tn] {
|
||||
|
||||
do_execsql_test 4.$tn.1 {
|
||||
CREATE TABLE p1(a INTEGER PRIMARY KEY, b) %WO%;
|
||||
CREATE TABLE c1(x PRIMARY KEY, y REFERENCES p1 ON UPDATE CASCADE) %WO%;
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
INSERT INTO p1 VALUES(1, 'one');
|
||||
INSERT INTO p1 VALUES(11, 'eleven');
|
||||
INSERT INTO p1 VALUES(111, 'eleventyone');
|
||||
|
||||
INSERT INTO c1 VALUES('a', 1);
|
||||
INSERT INTO c1 VALUES('b', 11);
|
||||
INSERT INTO c1 VALUES('c', 111);
|
||||
}
|
||||
|
||||
do_execsql_test 4.$tn.2 {
|
||||
CREATE TABLE map(f, t);
|
||||
INSERT INTO map VALUES('a', 111);
|
||||
INSERT INTO map VALUES('c', 112);
|
||||
}
|
||||
|
||||
do_catchsql_test 4.$tn.3 {
|
||||
UPDATE c1 SET y=t FROM map WHERE x=f;
|
||||
} {1 {FOREIGN KEY constraint failed}}
|
||||
|
||||
do_execsql_test 4.$tn.4 {
|
||||
INSERT INTO map VALUES('eleven', 12);
|
||||
INSERT INTO map VALUES('eleventyone', 112);
|
||||
UPDATE p1 SET a=t FROM map WHERE b=f;
|
||||
}
|
||||
|
||||
do_execsql_test 4.$tn.5 {
|
||||
SELECT * FROM c1
|
||||
} {a 1 b 12 c 112}
|
||||
|
||||
}]
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user