1
0
mirror of https://github.com/sqlite/sqlite.git synced 2026-10-26 21:59:27 +03:00

Merge bug fixes from trunk.

FossilOrigin-Name: 1e973f65e8340a34eef9b9c4e064f69fc9c3995bd15e5c25777ab803160b73b4
This commit is contained in:
drh
2018-10-25 16:58:27 +00:00
15 changed files with 454 additions and 93 deletions

View File

@@ -95,6 +95,23 @@ proc changeset_from_sql {sql {dbname main}} {
return $changeset
}
proc patchset_from_sql {sql {dbname main}} {
set rc [catch {
sqlite3session S db $dbname
db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
S attach $name
}
db eval $sql
S patchset
} patchset]
catch { S delete }
if {$rc} {
error $patchset
}
return $patchset
}
proc do_then_apply_sql {sql {dbname main}} {
proc xConflict args { return "OMIT" }
set rc [catch {

View File

@@ -0,0 +1,159 @@
# 2018 October 18
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}
set testprefix sessioninvert
proc iter_invert {C} {
set x [list]
sqlite3session_foreach -invert c $C { lappend x $c }
set x
}
proc do_invert_test {tn sql {iter {}}} {
forcecopy test.db test.db2
sqlite3 db2 test.db2
set C [changeset_from_sql $sql]
forcecopy test.db test.db3
sqlite3 db3 test.db3
uplevel [list do_test $tn.1 [list compare_db db db3] {}]
set I [sqlite3changeset_invert $C]
sqlite3changeset_apply db $I {}
uplevel [list do_test $tn.2 [list compare_db db db2] {}]
sqlite3changeset_apply_v2 -invert db3 $C {}
uplevel [list do_test $tn.3 [list compare_db db db3] {}]
if {$iter!=""} {
uplevel [list do_test $tn.4 [list iter_invert $C] [list {*}$iter]]
}
catch { db2 close }
catch { db3 close }
}
do_execsql_test 1.0 {
CREATE TABLE t1(a PRIMARY KEY, b, c);
CREATE TABLE t2(d, e, f, PRIMARY KEY(e, f));
INSERT INTO t1 VALUES(1, 'one', 'i');
INSERT INTO t1 VALUES(2, 'two', 'ii');
INSERT INTO t1 VALUES(3, 'three', 'iii');
INSERT INTO t1 VALUES(4, 'four', 'iv');
INSERT INTO t1 VALUES(5, 'five', 'v');
INSERT INTO t1 VALUES(6, 'six', 'vi');
INSERT INTO t2 SELECT * FROM t1;
}
do_invert_test 1.1 {
INSERT INTO t1 VALUES(7, 'seven', 'vii');
} {
{DELETE t1 0 X.. {i 7 t seven t vii} {}}
}
do_invert_test 1.2 {
DELETE FROM t1 WHERE a<4;
} {
{INSERT t1 0 X.. {} {i 1 t one t i}}
{INSERT t1 0 X.. {} {i 2 t two t ii}}
{INSERT t1 0 X.. {} {i 3 t three t iii}}
}
do_invert_test 1.3 {
UPDATE t1 SET c=5;
} {
{UPDATE t1 0 X.. {i 1 {} {} i 5} {{} {} {} {} t i}}
{UPDATE t1 0 X.. {i 2 {} {} i 5} {{} {} {} {} t ii}}
{UPDATE t1 0 X.. {i 3 {} {} i 5} {{} {} {} {} t iii}}
{UPDATE t1 0 X.. {i 4 {} {} i 5} {{} {} {} {} t iv}}
{UPDATE t1 0 X.. {i 5 {} {} i 5} {{} {} {} {} t v}}
{UPDATE t1 0 X.. {i 6 {} {} i 5} {{} {} {} {} t vi}}
}
do_invert_test 1.4 {
UPDATE t1 SET b = a+1 WHERE a%2;
DELETE FROM t2;
INSERT INTO t1 VALUES(10, 'ten', NULL);
}
do_invert_test 1.5 {
UPDATE t2 SET d = d-1;
} {
{UPDATE t2 0 .XX {i 2 t three t iii} {i 3 {} {} {} {}}}
{UPDATE t2 0 .XX {i 1 t two t ii} {i 2 {} {} {} {}}}
{UPDATE t2 0 .XX {i 5 t six t vi} {i 6 {} {} {} {}}}
{UPDATE t2 0 .XX {i 3 t four t iv} {i 4 {} {} {} {}}}
{UPDATE t2 0 .XX {i 0 t one t i} {i 1 {} {} {} {}}}
{UPDATE t2 0 .XX {i 4 t five t v} {i 5 {} {} {} {}}}
}
do_execsql_test 2.0 {
ANALYZE;
PRAGMA writable_schema = 1;
DROP TABLE IF EXISTS sqlite_stat4;
SELECT * FROM sqlite_stat1;
} {
t2 sqlite_autoindex_t2_1 {6 1 1}
t1 sqlite_autoindex_t1_1 {6 1}
}
do_invert_test 2.1 {
INSERT INTO sqlite_stat1 VALUES('t3', 'idx2', '1 2 3');
} {
{DELETE sqlite_stat1 0 XX. {t t3 t idx2 t {1 2 3}} {}}
}
do_invert_test 2.2 {
DELETE FROM sqlite_stat1;
} {
{INSERT sqlite_stat1 0 XX. {} {t t1 t sqlite_autoindex_t1_1 t {6 1}}}
{INSERT sqlite_stat1 0 XX. {} {t t2 t sqlite_autoindex_t2_1 t {6 1 1}}}
}
do_invert_test 2.3 {
UPDATE sqlite_stat1 SET stat = 'hello world';
}
do_test 3.0 {
forcecopy test.db test.db2
sqlite3 db2 test.db2
set P [patchset_from_sql {
INSERT INTO t2 VALUES(1, 2, 3);
DELETE FROM t2 WHERE d = 3;
}]
list [catch { sqlite3changeset_apply_v2 -invert db2 $P {} } msg] $msg
} {1 SQLITE_CORRUPT}
do_test 3.1 {
list [catch { sqlite3session_foreach -invert db2 $P {} } msg] $msg
} {1 SQLITE_CORRUPT}
do_test 3.2 {
sqlite3changeset_apply_v2 db2 $P {}
compare_db db db2
} {}
finish_test

View File

@@ -87,6 +87,7 @@ struct sqlite3_changeset_iter {
SessionInput in; /* Input buffer or stream */
SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */
int bPatchset; /* True if this is a patchset */
int bInvert; /* True to invert changeset */
int rc; /* Iterator error code */
sqlite3_stmt *pConflict; /* Points to conflicting row, if any */
char *zTab; /* Current table */
@@ -1793,12 +1794,12 @@ int sqlite3session_attach(
static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
u8 *aNew;
int nNew = p->nAlloc ? p->nAlloc : 128;
i64 nNew = p->nAlloc ? p->nAlloc : 128;
do {
nNew = nNew*2;
}while( nNew<(p->nBuf+nByte) );
}while( (nNew-p->nBuf)<nByte );
aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew);
if( 0==aNew ){
*pRc = SQLITE_NOMEM;
}else{
@@ -2540,7 +2541,8 @@ static int sessionChangesetStart(
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn,
int nChangeset, /* Size of buffer pChangeset in bytes */
void *pChangeset /* Pointer to buffer containing changeset */
void *pChangeset, /* Pointer to buffer containing changeset */
int bInvert /* True to invert changeset */
){
sqlite3_changeset_iter *pRet; /* Iterator to return */
int nByte; /* Number of bytes to allocate for iterator */
@@ -2560,6 +2562,7 @@ static int sessionChangesetStart(
pRet->in.xInput = xInput;
pRet->in.pIn = pIn;
pRet->in.bEof = (xInput ? 0 : 1);
pRet->bInvert = bInvert;
/* Populate the output variable and return success. */
*pp = pRet;
@@ -2574,7 +2577,16 @@ int sqlite3changeset_start(
int nChangeset, /* Size of buffer pChangeset in bytes */
void *pChangeset /* Pointer to buffer containing changeset */
){
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0);
}
int sqlite3changeset_start_v2(
sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
int nChangeset, /* Size of buffer pChangeset in bytes */
void *pChangeset, /* Pointer to buffer containing changeset */
int flags
){
int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert);
}
/*
@@ -2585,7 +2597,16 @@ int sqlite3changeset_start_strm(
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
){
return sessionChangesetStart(pp, xInput, pIn, 0, 0);
return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0);
}
int sqlite3changeset_start_v2_strm(
sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn,
int flags
){
int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert);
}
/*
@@ -2964,10 +2985,10 @@ static int sessionChangesetNext(
op = p->in.aData[p->in.iNext++];
}
if( p->zTab==0 ){
if( p->zTab==0 || (p->bPatchset && p->bInvert) ){
/* The first record in the changeset is not a table header. Must be a
** corrupt changeset. */
assert( p->in.iNext==1 );
assert( p->in.iNext==1 || p->zTab );
return (p->rc = SQLITE_CORRUPT_BKPT);
}
@@ -2992,33 +3013,39 @@ static int sessionChangesetNext(
*paRec = &p->in.aData[p->in.iNext];
p->in.iNext += *pnRec;
}else{
sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue);
sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]);
/* If this is an UPDATE or DELETE, read the old.* record. */
if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
u8 *abPK = p->bPatchset ? p->abPK : 0;
p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld);
if( p->rc!=SQLITE_OK ) return p->rc;
}
/* If this is an INSERT or UPDATE, read the new.* record. */
if( p->op!=SQLITE_DELETE ){
p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew);
if( p->rc!=SQLITE_OK ) return p->rc;
}
if( p->bPatchset && p->op==SQLITE_UPDATE ){
if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){
/* If this is an UPDATE that is part of a patchset, then all PK and
** modified fields are present in the new.* record. The old.* record
** is currently completely empty. This block shifts the PK fields from
** new.* to old.*, to accommodate the code that reads these arrays. */
for(i=0; i<p->nCol; i++){
assert( p->apValue[i]==0 );
assert( p->bPatchset==0 || p->apValue[i]==0 );
if( p->abPK[i] ){
assert( p->apValue[i]==0 );
p->apValue[i] = p->apValue[i+p->nCol];
if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT);
p->apValue[i+p->nCol] = 0;
}
}
}else if( p->bInvert ){
if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE;
else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT;
}
}
@@ -4182,7 +4209,7 @@ static int sessionRetryConstraints(
SessionBuffer cons = pApply->constraints;
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0);
if( rc==SQLITE_OK ){
int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
int rc2;
@@ -4436,7 +4463,8 @@ int sqlite3changeset_apply_v2(
int flags
){
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse);
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
@@ -4493,7 +4521,8 @@ int sqlite3changeset_apply_v2_strm(
int flags
){
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse);
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags

View File

@@ -473,12 +473,38 @@ int sqlite3session_isempty(sqlite3_session *pSession);
** consecutively. There is no chance that the iterator will visit a change
** the applies to table X, then one for table Y, and then later on visit
** another change for table X.
**
** The behavior of sqlite3changeset_start_v2() and its streaming equivalent
** may be modified by passing a combination of
** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter.
**
** Note that the sqlite3changeset_start_v2() API is still <b>experimental</b>
** and therefore subject to change.
*/
int sqlite3changeset_start(
sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
int nChangeset, /* Size of changeset blob in bytes */
void *pChangeset /* Pointer to blob containing changeset */
);
int sqlite3changeset_start_v2(
sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
int nChangeset, /* Size of changeset blob in bytes */
void *pChangeset, /* Pointer to blob containing changeset */
int flags /* SESSION_CHANGESETSTART_* flags */
);
/*
** CAPI3REF: Flags for sqlite3changeset_start_v2
**
** The following flags may passed via the 4th parameter to
** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]:
**
** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
** Invert the changeset while iterating through it. This is equivalent to
** inverting a changeset using sqlite3changeset_invert() before applying it.
** It is an error to specify this flag with a patchset.
*/
#define SQLITE_CHANGESETSTART_INVERT 0x0002
/*
@@ -1133,7 +1159,7 @@ int sqlite3changeset_apply_v2(
),
void *pCtx, /* First argument passed to xConflict */
void **ppRebase, int *pnRebase, /* OUT: Rebase data */
int flags /* Combination of SESSION_APPLY_* flags */
int flags /* SESSION_CHANGESETAPPLY_* flags */
);
/*
@@ -1151,8 +1177,14 @@ int sqlite3changeset_apply_v2(
** causes the sessions module to omit this savepoint. In this case, if the
** caller has an open transaction or savepoint when apply_v2() is called,
** it may revert the partially applied changeset by rolling it back.
**
** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -1546,6 +1578,12 @@ int sqlite3changeset_start_strm(
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
);
int sqlite3changeset_start_v2_strm(
sqlite3_changeset_iter **pp,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn,
int flags
);
int sqlite3session_changeset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),

View File

@@ -737,20 +737,32 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
/* Check for the -nosavepoint flag */
if( bV2 && objc>1 ){
const char *z1 = Tcl_GetString(objv[1]);
int n = strlen(z1);
if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
flags = SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
objc--;
objv++;
if( bV2 ){
if( objc>1 ){
const char *z1 = Tcl_GetString(objv[1]);
int n = strlen(z1);
if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
flags |= SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
objc--;
objv++;
}
}
if( objc>1 ){
const char *z1 = Tcl_GetString(objv[1]);
int n = strlen(z1);
if( n>1 && n<=7 && 0==sqlite3_strnicmp("-invert", z1, n) ){
flags |= SQLITE_CHANGESETAPPLY_INVERT;
objc--;
objv++;
}
}
}
if( objc!=4 && objc!=5 ){
const char *zMsg;
if( bV2 ){
zMsg = "?-nosavepoint? DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
zMsg = "?-nosavepoint? ?-inverse? "
"DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
}else{
zMsg = "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
}
@@ -969,31 +981,56 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach(
Tcl_Obj *pCS;
Tcl_Obj *pScript;
int isCheckNext = 0;
int isInvert = 0;
TestStreamInput sStr;
memset(&sStr, 0, sizeof(sStr));
if( objc>1 ){
while( objc>1 ){
char *zOpt = Tcl_GetString(objv[1]);
isCheckNext = (strcmp(zOpt, "-next")==0);
int nOpt = strlen(zOpt);
if( zOpt[0]!='-' ) break;
if( nOpt<=7 && 0==sqlite3_strnicmp(zOpt, "-invert", nOpt) ){
isInvert = 1;
}else
if( nOpt<=5 && 0==sqlite3_strnicmp(zOpt, "-next", nOpt) ){
isCheckNext = 1;
}else{
break;
}
objv++;
objc--;
}
if( objc!=4+isCheckNext ){
Tcl_WrongNumArgs(interp, 1, objv, "?-next? VARNAME CHANGESET SCRIPT");
if( objc!=4 ){
Tcl_WrongNumArgs(
interp, 1, objv, "?-next? ?-invert? VARNAME CHANGESET SCRIPT");
return TCL_ERROR;
}
pVarname = objv[1+isCheckNext];
pCS = objv[2+isCheckNext];
pScript = objv[3+isCheckNext];
pVarname = objv[1];
pCS = objv[2];
pScript = objv[3];
pChangeset = (void *)Tcl_GetByteArrayFromObj(pCS, &nChangeset);
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
if( sStr.nStream==0 ){
rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
if( isInvert ){
int f = SQLITE_CHANGESETSTART_INVERT;
if( sStr.nStream==0 ){
rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, f);
}else{
void *pCtx = (void*)&sStr;
sStr.aData = (unsigned char*)pChangeset;
sStr.nData = nChangeset;
rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, f);
}
}else{
sStr.aData = (unsigned char*)pChangeset;
sStr.nData = nChangeset;
rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
if( sStr.nStream==0 ){
rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
}else{
sStr.aData = (unsigned char*)pChangeset;
sStr.nData = nChangeset;
rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
}
}
if( rc!=SQLITE_OK ){
return test_session_error(interp, rc, 0);

View File

@@ -1,5 +1,5 @@
C Fix\sthe\sSQLITE_ENABLE_APPLE_SPI\scompile-time\soption.
D 2018-10-12T22:02:27.294
C Merge\sbug\sfixes\sfrom\strunk.
D 2018-10-25T16:58:27.726
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 001aa40c74053940551df31971fc3ae9873cf1df2015d118815d0ea7cc39baf0
@@ -407,18 +407,19 @@ F ext/session/sessionE.test 0a616c4ad8fd2c05f23217ebb6212ef80b7fef30f5f086a6633a
F ext/session/sessionF.test c2f178d4dfd723a5fd94a730ea2ccb44c669e3ce
F ext/session/sessionG.test 3edde849c4071078d92bd682c836186f6e4e5a3fb6bcf3fc1de1a7caa5e4427d
F ext/session/sessionH.test 332b60e4c2e0a680105e11936201cabe378216f307e2747803cea56fa7d9ebae
F ext/session/session_common.tcl ee925e0d233677e45e395fb1f559b84068ce7baa8aa1034441739d3e87ee249c
F ext/session/session_common.tcl 29ec9910aca1e996ca1c8531b8cecabf96eb576aa53de65a8ff03d848b9a2a8b
F ext/session/session_speed_test.c edc1f96fd5e0e4b16eb03e2a73041013d59e8723
F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28f0c1cc142c3ec
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
F ext/session/sessionfault2.test 555a8504de03d59b369ef20209585da5aeb2671dedabc4584e9ffe6269689185
F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b2953cf48683fb2724169
F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8
F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e
F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
F ext/session/sqlite3session.c ba76c7f01d4c71ab4d134cfda0ba43faae04bff01b8e81d1279a6101c706e3b5
F ext/session/sqlite3session.h c01820d5b6e73e86d88008f4d1c1c7dfb83422963018292b864028a0400ceccf
F ext/session/test_session.c dba36c6c0153b22501112d3e8882b5c946cf617c955153b6712bd2f8ba1428c0
F ext/session/sqlite3session.c 7b9ae0d7f3f89551c893ad5beafe831df1c097623f6abc983dad7b6dbca726cb
F ext/session/sqlite3session.h 11f229ec3f123da40c31500b01a2f6807185293d9173a5e0aa5be42ad70ab85d
F ext/session/test_session.c 4699405b2afcf6833c11358cdb9da50f8f5d2b7123f44b3e2cef1cfb88c9fa39
F ext/sqlrr/README.txt 4239030e73023e72a2e727808cd433577d5bf730
F ext/sqlrr/sqlrr.c 8d1e6571cd6a6beabdb5bcdfe3a0e723b914db41
F ext/sqlrr/sqlrr.h 09e4f8929ad9bc2638732c0cc0db5eef8c417824
@@ -453,7 +454,7 @@ F src/btreeInt.h 5903b9a6710110a483a0501a708fd09975357e7cdc98300208a2071ad7d1750
F src/build.c 0b3d422770877d74ee6d54f4c122d82c48f7d04ee3bfb91702e402de7f5c45ac
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387
F src/ctime.c 56e2f32d2e5491c152352bd53cffc9979ee1e1b70df39ec97a90920ae420a950
F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
@@ -506,7 +507,7 @@ F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
F src/select.c 33aacf1c17c64a00788c779b23d0875dd0d90eb4c08f867ebc31139ef3a67c95
F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f
F src/shell.c.in 248af8c0d785c98268353e58c96715313f3b091bf220d35366affc9a9c0d4e1d
F src/sqlite.h.in 5bed5f546e0fb389a572a65983108bd5dc975705660a4c7fe5819a84ccb32f1f
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
@@ -596,7 +597,7 @@ F src/where.c a54a3d639bcd751d1474deff58e239b2e475a96e1b8f9178aa7864df8782a4e3
F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f
F src/wherecode.c 3df0a541373d5f999684d761e4bd700d57adb46c7d39da4e77b767b5adcd5893
F src/whereexpr.c 1b5a5a7876997f65232bbf19c5c1eeb47eb328b8fa5b28c865543052904cde00
F src/window.c a28d8d42c51c7e31136a42f3e245282049d4a9466b36d7bd765772991472df41
F src/window.c 6550e2850ebced51100ef83d49b00a1cf03f81a482dafedafb0320df647ed8fc
F test/8_3_names.test 05034aadccd2253ffe6cbefb06662b8aa4600f77
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -774,7 +775,7 @@ F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
F test/dbpage.test dbf50a4d361f9e45a979432c727506065113124478a7d2db12074fa655e65d6c
F test/dbstatus.test c15fa97f743dac7ce996814c84b56317e138895ee15ce27f15b608aa6924c90a
F test/dbstatus.test cd83aa623b8aab477269bc94cf8aa90c1e195a144561dd04a1620770aaa8524e
F test/dbstatus2.test ce94261a9e45cfd2d08195a82553c03b45c01e5ebad8a17888aeef818d9da69c
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
F test/delete.test 31832b0c45ecb51a54348c68db173be462985901e6ed7f403d6d7a8f70ab4ef0
@@ -1180,7 +1181,7 @@ F test/permutations.test 8749e292c8f7e98072049543da8c0fe60e1625f0a9f490686230609
F test/pg_common.tcl 301ac19c1a52fd55166d26db929b3b89165c634d52b5f8ad76ea8cb06960db30
F test/pragma.test 3ce8294c0f86ef7586e44fdc7be887f0cfeaec01093ad3e24d5736b96fb55984
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9
F test/pragma4.test da107b2fd465e67aa9f419a4e313b26b76336fabf71059c51d0b3211a6ae3c51
F test/pragma5.test 824ce6ced5d6b7ec71abe37fc6005ff836fe39d638273dc5192b39864b9ee983
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
@@ -1260,7 +1261,7 @@ F test/server1.test c2b00864514a68a0e6fd518659dc95d0050307a357a08969872bef027d78
F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be
F test/sessionfuzz-data1.db 1f8d5def831f19b1c74571037f0d53a588ea49a6c4ca2a028fc0c27ef896dbcb
F test/sessionfuzz.c b0fcdcf757451957e17396a3af5171f1fdf9b2babc81da9fa35675df46c4729a
F test/shared.test 13376ba3be1c5685ab1ec184189adabd15fa70be
F test/shared.test ccc380a78e84972f5181a4f3ab02484e482f24160e496e653bede72669d2f72d
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
F test/shared3.test ab693f9b6e156b8bfb2a0ad94f29fe69602a5d38
F test/shared4.test c75f476804e76e26bf6fa0e7b421fb0ca7d07558
@@ -1640,7 +1641,7 @@ F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test b7769ee8dbefd987fb266715fee887f05f9ff180016b06fca7fa402df739193b
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
F test/whereL.test 84de61afe4b8e5a3ff7d741c990d85cb44b3ce798cd8412d5603930f3f75014f
F test/whereL.test 0a19fc44cd1122040f56c934f1b14d0ca85bde28f270268a428dd9796ea0634c
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0
@@ -1650,7 +1651,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
F test/window1.test 474bef1a6ac291755e51d1f9458dc11117c1870ac5e08b4d3938649b215f8334
F test/window1.test 02e481ac48c445b43bab7b3cf1e4115165b5127a1aa29e14f5372922c836f1a4
F test/window2.tcl 9bfa842d8a62b0d36dc8c1b5972206393c43847433c6d75940b87fec93ce3143
F test/window2.test 8e6d2a1b9f54dfebee1cde961c8590cd87b4db45c50f44947a211e1b63c2a05e
F test/window3.tcl 577a3b1ff913208e5248c04dab9df17fd760ce159a752789e26d0cb4a5f91823
@@ -1776,7 +1777,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P d1008b07280b51354dfcdebbb5b0c68e276d1ac206df46edbade0838dc27b273
R 2ce7ab783b5cd659a132a79c3ab41518
P 6cb537bdce85e08810ac952b753ecd97b656cc0885cfda443b810b9242bf9c79 5d5b596f152bb2781011a05f75f9e200774d4f69d648ef68de577b4ace973e07
R d07ff796d06a0108315833f69c0f4bba
U drh
Z c9c072a55e9712099f83ecf5c0a6cde3
Z 940710d2d4303a2817cf6ad4a78a8415

View File

@@ -1 +1 @@
6cb537bdce85e08810ac952b753ecd97b656cc0885cfda443b810b9242bf9c79
1e973f65e8340a34eef9b9c4e064f69fc9c3995bd15e5c25777ab803160b73b4

View File

@@ -235,6 +235,9 @@ static const char * const sqlite3azCompileOpt[] = {
#if SQLITE_ENABLE_FTS5
"ENABLE_FTS5",
#endif
#if SQLITE_ENABLE_GEOPOLY
"ENABLE_GEOPOLY",
#endif
#if SQLITE_ENABLE_HIDDEN_COLUMNS
"ENABLE_HIDDEN_COLUMNS",
#endif

View File

@@ -4074,7 +4074,7 @@ static int flattenSubquery(
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
** A structure to keep track of all of the column values that fixed to
** A structure to keep track of all of the column values that are fixed to
** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
*/
typedef struct WhereConst WhereConst;
@@ -4086,13 +4086,28 @@ struct WhereConst {
};
/*
** Add a new entry to the pConst object
** Add a new entry to the pConst object. Except, do not add duplicate
** pColumn entires.
*/
static void constInsert(
WhereConst *pConst,
Expr *pColumn,
Expr *pValue
WhereConst *pConst, /* The WhereConst into which we are inserting */
Expr *pColumn, /* The COLUMN part of the constraint */
Expr *pValue /* The VALUE part of the constraint */
){
int i;
assert( pColumn->op==TK_COLUMN );
/* 2018-10-25 ticket [cf5ed20f]
** Make sure the same pColumn is not inserted more than once */
for(i=0; i<pConst->nConst; i++){
const Expr *pExpr = pConst->apExpr[i*2];
assert( pExpr->op==TK_COLUMN );
if( pExpr->iTable==pColumn->iTable
&& pExpr->iColumn==pColumn->iColumn
){
return; /* Already present. Return without doing anything. */
}
}
pConst->nConst++;
pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,

View File

@@ -746,7 +746,7 @@ static ExprList *exprListAppendList(
*/
int sqlite3WindowRewrite(Parse *pParse, Select *p){
int rc = SQLITE_OK;
if( p->pWin ){
if( p->pWin && p->pPrior==0 ){
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3 *db = pParse->db;
Select *pSub = 0; /* The subquery */

View File

@@ -379,9 +379,9 @@ foreach ::lookaside_buffer_size {0 64 120} {
# The following tests focus on DBSTATUS_CACHE_USED_SHARED
#
ifcapable shared_cache {
if {[permutation]=="memsys3"
if {([permutation]=="memsys3"
|| [permutation]=="memsys5"
|| $::tcl_platform(os)=="Linux"} {
|| $::tcl_platform(os)=="Linux") && ![sqlite3 -has-codec]} {
proc do_cacheused_test {tn db res} {
set cu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED 0]
set pcu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED_SHARED 0]

View File

@@ -15,7 +15,11 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_not_use_codec
if {[sqlite3 -has-codec]} {
finish_test
return
}
do_execsql_test pragma3-100 {
PRAGMA data_version;

View File

@@ -1141,38 +1141,40 @@ do_test shared-$av-16.8 {
# Shared cache on named memory databases attached to readonly connections.
#
do_test shared-$av-16.8.1 {
if {![sqlite3 -has-codec]} {
do_test shared-$av-16.8.1 {
db1 close
db2 close
sqlite3 db test1.db
db eval {
CREATE TABLE yy(a, b);
INSERT INTO yy VALUES(77, 88);
}
db close
sqlite3 db1 test1.db -uri 1 -readonly 1
sqlite3 db2 test2.db -uri 1
db1 eval {
ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
CREATE TABLE shared.xx(a, b);
INSERT INTO xx VALUES(55, 66);
}
db2 eval {
ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
SELECT * FROM xx;
}
} {55 66}
do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88}
do_test shared-$av-16.8.3 {
list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg
} {1 {attempt to write a readonly database}}
db1 close
db2 close
sqlite3 db test1.db
db eval {
CREATE TABLE yy(a, b);
INSERT INTO yy VALUES(77, 88);
}
db close
sqlite3 db1 test1.db -uri 1 -readonly 1
sqlite3 db2 test2.db -uri 1
db1 eval {
ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
CREATE TABLE shared.xx(a, b);
INSERT INTO xx VALUES(55, 66);
}
db2 eval {
ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
SELECT * FROM xx;
}
} {55 66}
do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88}
do_test shared-$av-16.8.3 {
list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg
} {1 {attempt to write a readonly database}}
db1 close
db2 close
}
} ;# end of autovacuum on/off loop

View File

@@ -111,4 +111,15 @@ do_execsql_test 302 {
AND B.id=subq.zz;
} {1}
# 2018-10-25: Ticket [cf5ed20f]
# Incorrect join result with duplicate WHERE clause constraint.
#
do_execsql_test 400 {
CREATE TABLE x(a, b, c);
CREATE TABLE y(a, b);
INSERT INTO x VALUES (1, 0, 1);
INSERT INTO y VALUES (1, 2);
SELECT x.a FROM x JOIN y ON x.c = y.a WHERE x.b = 1 AND x.b = 1;
} {}
finish_test

View File

@@ -549,4 +549,49 @@ do_execsql_test 12.110 {
ORDER BY b LIMIT 2;
} {2 B two 3 C three}
#-------------------------------------------------------------------------
do_execsql_test 13.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a int, b int);
INSERT INTO t1 VALUES(1,11);
INSERT INTO t1 VALUES(2,12);
}
do_execsql_test 13.2.1 {
SELECT a, rank() OVER(ORDER BY b) FROM t1;
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
} {
1 1 2 2 2 1 1 2
}
do_execsql_test 13.2.2 {
SELECT a, rank() OVER(ORDER BY b) FROM t1
UNION ALL
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
} {
1 1 2 2 2 1 1 2
}
do_execsql_test 13.3 {
SELECT a, rank() OVER(ORDER BY b) FROM t1
UNION
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
} {
1 1 1 2 2 1 2 2
}
do_execsql_test 13.4 {
SELECT a, rank() OVER(ORDER BY b) FROM t1
EXCEPT
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
} {
1 1 2 2
}
do_execsql_test 13.5 {
SELECT a, rank() OVER(ORDER BY b) FROM t1
INTERSECT
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
} {
}
finish_test