Load enhancements from trunk into the returning branch.
FossilOrigin-Name: b84c7f60c2e1e7debf9f50622087f87d60c6870061d61e14e59cc1ba0775ee92
This commit is contained in:
commit
47600083f1
@ -35,7 +35,7 @@ proc test_reset {} {
|
||||
|
||||
test_reset
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
CREATE TABLE t1(a INT PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES('i', 'one');
|
||||
}
|
||||
do_iterator_test 1.1 t1 {
|
||||
@ -184,7 +184,7 @@ set set_of_tests {
|
||||
|
||||
test_reset
|
||||
do_common_sql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
CREATE TABLE t1(a int PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
|
||||
CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b));
|
||||
CREATE TABLE t4(a, b, PRIMARY KEY(b, a));
|
||||
@ -206,17 +206,17 @@ sqlite3 db3 test.db3
|
||||
do_test 3.0 {
|
||||
execsql {
|
||||
ATTACH 'test.db3' AS 'aux';
|
||||
CREATE TABLE t1(a, b PRIMARY KEY);
|
||||
CREATE TABLE t1(a int, b PRIMARY KEY);
|
||||
CREATE TABLE t2(x, y, z);
|
||||
CREATE TABLE t3(a);
|
||||
|
||||
CREATE TABLE aux.t1(a PRIMARY KEY, b);
|
||||
CREATE TABLE aux.t1(a int PRIMARY KEY, b);
|
||||
CREATE TABLE aux.t2(a, b INTEGER PRIMARY KEY);
|
||||
CREATE TABLE aux.t3(a, b, c, PRIMARY KEY(a, b));
|
||||
CREATE TABLE aux.t4(a, b, PRIMARY KEY(b, a));
|
||||
}
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
CREATE TABLE t1(a int PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
|
||||
CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b));
|
||||
CREATE TABLE t4(a, b, PRIMARY KEY(b, a));
|
||||
@ -588,4 +588,52 @@ do_execsql_test 10.2 {
|
||||
} {0 0 1 1}
|
||||
S delete
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
test_reset
|
||||
do_common_sql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d, e, f);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<32
|
||||
)
|
||||
INSERT INTO t1 SELECT NULL, 0, 0, 0, 0, 0 FROM s
|
||||
}
|
||||
|
||||
do_then_apply_sql {
|
||||
UPDATE t1 SET f=f+1 WHERE a=1;
|
||||
UPDATE t1 SET e=e+1 WHERE a=2;
|
||||
UPDATE t1 SET e=e+1, f=f+1 WHERE a=3;
|
||||
UPDATE t1 SET d=d+1 WHERE a=4;
|
||||
UPDATE t1 SET d=d+1, f=f+1 WHERE a=5;
|
||||
UPDATE t1 SET d=d+1, e=e+1 WHERE a=6;
|
||||
UPDATE t1 SET d=d+1, e=e+1, f=f+1 WHERE a=7;
|
||||
UPDATE t1 SET c=c+1 WHERE a=8;
|
||||
UPDATE t1 SET c=c+1, f=f+1 WHERE a=9;
|
||||
UPDATE t1 SET c=c+1, e=e+1 WHERE a=10;
|
||||
UPDATE t1 SET c=c+1, e=e+1, f=f+1 WHERE a=11;
|
||||
UPDATE t1 SET c=c+1, d=d+1 WHERE a=12;
|
||||
UPDATE t1 SET c=c+1, d=d+1, f=f+1 WHERE a=13;
|
||||
UPDATE t1 SET c=c+1, d=d+1, e=e+1 WHERE a=14;
|
||||
UPDATE t1 SET c=c+1, d=d+1, e=e+1, f=f+1 WHERE a=15;
|
||||
UPDATE t1 SET d=d+1 WHERE a=16;
|
||||
UPDATE t1 SET d=d+1, f=f+1 WHERE a=17;
|
||||
UPDATE t1 SET d=d+1, e=e+1 WHERE a=18;
|
||||
UPDATE t1 SET d=d+1, e=e+1, f=f+1 WHERE a=19;
|
||||
UPDATE t1 SET d=d+1, d=d+1 WHERE a=20;
|
||||
UPDATE t1 SET d=d+1, d=d+1, f=f+1 WHERE a=21;
|
||||
UPDATE t1 SET d=d+1, d=d+1, e=e+1 WHERE a=22;
|
||||
UPDATE t1 SET d=d+1, d=d+1, e=e+1, f=f+1 WHERE a=23;
|
||||
UPDATE t1 SET d=d+1, c=c+1 WHERE a=24;
|
||||
UPDATE t1 SET d=d+1, c=c+1, f=f+1 WHERE a=25;
|
||||
UPDATE t1 SET d=d+1, c=c+1, e=e+1 WHERE a=26;
|
||||
UPDATE t1 SET d=d+1, c=c+1, e=e+1, f=f+1 WHERE a=27;
|
||||
UPDATE t1 SET d=d+1, c=c+1, d=d+1 WHERE a=28;
|
||||
UPDATE t1 SET d=d+1, c=c+1, d=d+1, f=f+1 WHERE a=29;
|
||||
UPDATE t1 SET d=d+1, c=c+1, d=d+1, e=e+1 WHERE a=30;
|
||||
UPDATE t1 SET d=d+1, c=c+1, d=d+1, e=e+1, f=f+1 WHERE a=31;
|
||||
}
|
||||
|
||||
do_test 11.0 {
|
||||
compare_db db db2
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
@ -3510,16 +3510,25 @@ int sqlite3changeset_invert_strm(
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
typedef struct SessionUpdate SessionUpdate;
|
||||
struct SessionUpdate {
|
||||
sqlite3_stmt *pStmt;
|
||||
u32 *aMask;
|
||||
SessionUpdate *pNext;
|
||||
};
|
||||
|
||||
typedef struct SessionApplyCtx SessionApplyCtx;
|
||||
struct SessionApplyCtx {
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *pDelete; /* DELETE statement */
|
||||
sqlite3_stmt *pUpdate; /* UPDATE statement */
|
||||
sqlite3_stmt *pInsert; /* INSERT statement */
|
||||
sqlite3_stmt *pSelect; /* SELECT statement */
|
||||
int nCol; /* Size of azCol[] and abPK[] arrays */
|
||||
const char **azCol; /* Array of column names */
|
||||
u8 *abPK; /* Boolean array - true if column is in PK */
|
||||
u32 *aUpdateMask; /* Used by sessionUpdateFind */
|
||||
SessionUpdate *pUp;
|
||||
int bStat1; /* True if table is sqlite_stat1 */
|
||||
int bDeferConstraints; /* True to defer constraints */
|
||||
int bInvertConstraints; /* Invert when iterating constraints buffer */
|
||||
@ -3529,6 +3538,167 @@ struct SessionApplyCtx {
|
||||
u8 bRebase; /* True to collect rebase information */
|
||||
};
|
||||
|
||||
/* Number of prepared UPDATE statements to cache. */
|
||||
#define SESSION_UPDATE_CACHE_SZ 12
|
||||
|
||||
/*
|
||||
** Find a prepared UPDATE statement suitable for the UPDATE step currently
|
||||
** being visited by the iterator. The UPDATE is of the form:
|
||||
**
|
||||
** UPDATE tbl SET col = ?, col2 = ? WHERE pk1 IS ? AND pk2 IS ?
|
||||
*/
|
||||
static int sessionUpdateFind(
|
||||
sqlite3_changeset_iter *pIter,
|
||||
SessionApplyCtx *p,
|
||||
int bPatchset,
|
||||
sqlite3_stmt **ppStmt
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SessionUpdate *pUp = 0;
|
||||
int nCol = pIter->nCol;
|
||||
int nU32 = (pIter->nCol+33)/32;
|
||||
int ii;
|
||||
|
||||
if( p->aUpdateMask==0 ){
|
||||
p->aUpdateMask = sqlite3_malloc(nU32*sizeof(u32));
|
||||
if( p->aUpdateMask==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(p->aUpdateMask, 0, nU32*sizeof(u32));
|
||||
rc = SQLITE_CORRUPT;
|
||||
for(ii=0; ii<pIter->nCol; ii++){
|
||||
if( sessionChangesetNew(pIter, ii) ){
|
||||
p->aUpdateMask[ii/32] |= (1<<(ii%32));
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( bPatchset ) p->aUpdateMask[nCol/32] |= (1<<(nCol%32));
|
||||
|
||||
if( p->pUp ){
|
||||
int nUp = 0;
|
||||
SessionUpdate **pp = &p->pUp;
|
||||
while( 1 ){
|
||||
nUp++;
|
||||
if( 0==memcmp(p->aUpdateMask, (*pp)->aMask, nU32*sizeof(u32)) ){
|
||||
pUp = *pp;
|
||||
*pp = pUp->pNext;
|
||||
pUp->pNext = p->pUp;
|
||||
p->pUp = pUp;
|
||||
break;
|
||||
}
|
||||
|
||||
if( (*pp)->pNext ){
|
||||
pp = &(*pp)->pNext;
|
||||
}else{
|
||||
if( nUp>=SESSION_UPDATE_CACHE_SZ ){
|
||||
sqlite3_finalize((*pp)->pStmt);
|
||||
sqlite3_free(*pp);
|
||||
*pp = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pUp==0 ){
|
||||
int nByte = sizeof(SessionUpdate) * nU32*sizeof(u32);
|
||||
int bStat1 = (sqlite3_stricmp(pIter->zTab, "sqlite_stat1")==0);
|
||||
pUp = (SessionUpdate*)sqlite3_malloc(nByte);
|
||||
if( pUp==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
const char *zSep = "";
|
||||
SessionBuffer buf;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
pUp->aMask = (u32*)&pUp[1];
|
||||
memcpy(pUp->aMask, p->aUpdateMask, nU32*sizeof(u32));
|
||||
|
||||
sessionAppendStr(&buf, "UPDATE main.", &rc);
|
||||
sessionAppendIdent(&buf, pIter->zTab, &rc);
|
||||
sessionAppendStr(&buf, " SET ", &rc);
|
||||
|
||||
/* Create the assignments part of the UPDATE */
|
||||
for(ii=0; ii<pIter->nCol; ii++){
|
||||
if( p->abPK[ii]==0 && sessionChangesetNew(pIter, ii) ){
|
||||
sessionAppendStr(&buf, zSep, &rc);
|
||||
sessionAppendIdent(&buf, p->azCol[ii], &rc);
|
||||
sessionAppendStr(&buf, " = ?", &rc);
|
||||
sessionAppendInteger(&buf, ii*2+1, &rc);
|
||||
zSep = ", ";
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the WHERE clause part of the UPDATE */
|
||||
zSep = "";
|
||||
sessionAppendStr(&buf, " WHERE ", &rc);
|
||||
for(ii=0; ii<pIter->nCol; ii++){
|
||||
if( p->abPK[ii] || (bPatchset==0 && sessionChangesetOld(pIter, ii)) ){
|
||||
sessionAppendStr(&buf, zSep, &rc);
|
||||
if( bStat1 && ii==1 ){
|
||||
assert( sqlite3_stricmp(p->azCol[ii], "idx")==0 );
|
||||
sessionAppendStr(&buf,
|
||||
"idx IS CASE "
|
||||
"WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL "
|
||||
"ELSE ?4 END ", &rc
|
||||
);
|
||||
}else{
|
||||
sessionAppendIdent(&buf, p->azCol[ii], &rc);
|
||||
sessionAppendStr(&buf, " IS ?", &rc);
|
||||
sessionAppendInteger(&buf, ii*2+2, &rc);
|
||||
}
|
||||
zSep = " AND ";
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
char *zSql = (char*)buf.aBuf;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, buf.nBuf, &pUp->pStmt, 0);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(pUp);
|
||||
pUp = 0;
|
||||
}else{
|
||||
pUp->pNext = p->pUp;
|
||||
p->pUp = pUp;
|
||||
}
|
||||
sqlite3_free(buf.aBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert( (rc==SQLITE_OK)==(pUp!=0) );
|
||||
if( pUp ){
|
||||
*ppStmt = pUp->pStmt;
|
||||
}else{
|
||||
*ppStmt = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all cached UPDATE statements.
|
||||
*/
|
||||
static void sessionUpdateFree(SessionApplyCtx *p){
|
||||
SessionUpdate *pUp;
|
||||
SessionUpdate *pNext;
|
||||
for(pUp=p->pUp; pUp; pUp=pNext){
|
||||
pNext = pUp->pNext;
|
||||
sqlite3_finalize(pUp->pStmt);
|
||||
sqlite3_free(pUp);
|
||||
}
|
||||
p->pUp = 0;
|
||||
sqlite3_free(p->aUpdateMask);
|
||||
p->aUpdateMask = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Formulate a statement to DELETE a row from database db. Assuming a table
|
||||
** structure like this:
|
||||
@ -3598,103 +3768,6 @@ static int sessionDeleteRow(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Formulate and prepare a statement to UPDATE a row from database db.
|
||||
** Assuming a table structure like this:
|
||||
**
|
||||
** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
|
||||
**
|
||||
** The UPDATE statement looks like this:
|
||||
**
|
||||
** UPDATE x SET
|
||||
** a = CASE WHEN ?2 THEN ?3 ELSE a END,
|
||||
** b = CASE WHEN ?5 THEN ?6 ELSE b END,
|
||||
** c = CASE WHEN ?8 THEN ?9 ELSE c END,
|
||||
** d = CASE WHEN ?11 THEN ?12 ELSE d END
|
||||
** WHERE a = ?1 AND c = ?7 AND (?13 OR
|
||||
** (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
|
||||
** )
|
||||
**
|
||||
** For each column in the table, there are three variables to bind:
|
||||
**
|
||||
** ?(i*3+1) The old.* value of the column, if any.
|
||||
** ?(i*3+2) A boolean flag indicating that the value is being modified.
|
||||
** ?(i*3+3) The new.* value of the column, if any.
|
||||
**
|
||||
** Also, a boolean flag that, if set to true, causes the statement to update
|
||||
** a row even if the non-PK values do not match. This is required if the
|
||||
** conflict-handler is invoked with CHANGESET_DATA and returns
|
||||
** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
|
||||
**
|
||||
** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
|
||||
** pointing to the prepared version of the SQL statement.
|
||||
*/
|
||||
static int sessionUpdateRow(
|
||||
sqlite3 *db, /* Database handle */
|
||||
const char *zTab, /* Table name */
|
||||
SessionApplyCtx *p /* Session changeset-apply context */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
int i;
|
||||
const char *zSep = "";
|
||||
SessionBuffer buf = {0, 0, 0};
|
||||
|
||||
/* Append "UPDATE tbl SET " */
|
||||
sessionAppendStr(&buf, "UPDATE main.", &rc);
|
||||
sessionAppendIdent(&buf, zTab, &rc);
|
||||
sessionAppendStr(&buf, " SET ", &rc);
|
||||
|
||||
/* Append the assignments */
|
||||
for(i=0; i<p->nCol; i++){
|
||||
sessionAppendStr(&buf, zSep, &rc);
|
||||
sessionAppendIdent(&buf, p->azCol[i], &rc);
|
||||
sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
|
||||
sessionAppendInteger(&buf, i*3+2, &rc);
|
||||
sessionAppendStr(&buf, " THEN ?", &rc);
|
||||
sessionAppendInteger(&buf, i*3+3, &rc);
|
||||
sessionAppendStr(&buf, " ELSE ", &rc);
|
||||
sessionAppendIdent(&buf, p->azCol[i], &rc);
|
||||
sessionAppendStr(&buf, " END", &rc);
|
||||
zSep = ", ";
|
||||
}
|
||||
|
||||
/* Append the PK part of the WHERE clause */
|
||||
sessionAppendStr(&buf, " WHERE ", &rc);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( p->abPK[i] ){
|
||||
sessionAppendIdent(&buf, p->azCol[i], &rc);
|
||||
sessionAppendStr(&buf, " = ?", &rc);
|
||||
sessionAppendInteger(&buf, i*3+1, &rc);
|
||||
sessionAppendStr(&buf, " AND ", &rc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Append the non-PK part of the WHERE clause */
|
||||
sessionAppendStr(&buf, " (?", &rc);
|
||||
sessionAppendInteger(&buf, p->nCol*3+1, &rc);
|
||||
sessionAppendStr(&buf, " OR 1", &rc);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( !p->abPK[i] ){
|
||||
sessionAppendStr(&buf, " AND (?", &rc);
|
||||
sessionAppendInteger(&buf, i*3+2, &rc);
|
||||
sessionAppendStr(&buf, "=0 OR ", &rc);
|
||||
sessionAppendIdent(&buf, p->azCol[i], &rc);
|
||||
sessionAppendStr(&buf, " IS ?", &rc);
|
||||
sessionAppendInteger(&buf, i*3+1, &rc);
|
||||
sessionAppendStr(&buf, ")", &rc);
|
||||
}
|
||||
}
|
||||
sessionAppendStr(&buf, ")", &rc);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
|
||||
}
|
||||
sqlite3_free(buf.aBuf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Formulate and prepare an SQL statement to query table zTab by primary
|
||||
** key. Assuming the following table structure:
|
||||
@ -3775,17 +3848,6 @@ static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
|
||||
"?3)"
|
||||
);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sessionPrepare(db, &p->pUpdate,
|
||||
"UPDATE main.sqlite_stat1 SET "
|
||||
"tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
|
||||
"idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
|
||||
"stat = CASE WHEN ?8 THEN ?9 ELSE stat END "
|
||||
"WHERE tbl=?1 AND idx IS "
|
||||
"CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END "
|
||||
"AND (?10 OR ?8=0 OR stat IS ?7)"
|
||||
);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sessionPrepare(db, &p->pDelete,
|
||||
"DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
|
||||
@ -4102,7 +4164,7 @@ static int sessionApplyOneOp(
|
||||
int nCol;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
|
||||
assert( p->pDelete && p->pInsert && p->pSelect );
|
||||
assert( p->azCol && p->abPK );
|
||||
assert( !pbReplace || *pbReplace==0 );
|
||||
|
||||
@ -4142,29 +4204,28 @@ static int sessionApplyOneOp(
|
||||
|
||||
}else if( op==SQLITE_UPDATE ){
|
||||
int i;
|
||||
sqlite3_stmt *pUp = 0;
|
||||
int bPatchset = (pbRetry==0 || pIter->bPatchset);
|
||||
|
||||
rc = sessionUpdateFind(pIter, p, bPatchset, &pUp);
|
||||
|
||||
/* Bind values to the UPDATE statement. */
|
||||
for(i=0; rc==SQLITE_OK && i<nCol; i++){
|
||||
sqlite3_value *pOld = sessionChangesetOld(pIter, i);
|
||||
sqlite3_value *pNew = sessionChangesetNew(pIter, i);
|
||||
|
||||
sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
|
||||
if( pOld ){
|
||||
rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
|
||||
if( p->abPK[i] || (bPatchset==0 && pOld) ){
|
||||
rc = sessionBindValue(pUp, i*2+2, pOld);
|
||||
}
|
||||
if( rc==SQLITE_OK && pNew ){
|
||||
rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
|
||||
rc = sessionBindValue(pUp, i*2+1, pNew);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
/* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
|
||||
** the result will be SQLITE_OK with 0 rows modified. */
|
||||
sqlite3_step(p->pUpdate);
|
||||
rc = sqlite3_reset(p->pUpdate);
|
||||
sqlite3_step(pUp);
|
||||
rc = sqlite3_reset(pUp);
|
||||
|
||||
if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
|
||||
/* A NOTFOUND or DATA error. Search the table to see if it contains
|
||||
@ -4387,14 +4448,13 @@ static int sessionChangesetApply(
|
||||
);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
|
||||
sessionUpdateFree(&sApply);
|
||||
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
|
||||
sqlite3_finalize(sApply.pDelete);
|
||||
sqlite3_finalize(sApply.pUpdate);
|
||||
sqlite3_finalize(sApply.pInsert);
|
||||
sqlite3_finalize(sApply.pSelect);
|
||||
sApply.db = db;
|
||||
sApply.pDelete = 0;
|
||||
sApply.pUpdate = 0;
|
||||
sApply.pInsert = 0;
|
||||
sApply.pSelect = 0;
|
||||
sApply.nCol = 0;
|
||||
@ -4458,11 +4518,10 @@ static int sessionChangesetApply(
|
||||
}
|
||||
sApply.bStat1 = 1;
|
||||
}else{
|
||||
if((rc = sessionSelectRow(db, zTab, &sApply))
|
||||
|| (rc = sessionUpdateRow(db, zTab, &sApply))
|
||||
|| (rc = sessionDeleteRow(db, zTab, &sApply))
|
||||
|| (rc = sessionInsertRow(db, zTab, &sApply))
|
||||
){
|
||||
if( (rc = sessionSelectRow(db, zTab, &sApply))
|
||||
|| (rc = sessionDeleteRow(db, zTab, &sApply))
|
||||
|| (rc = sessionInsertRow(db, zTab, &sApply))
|
||||
){
|
||||
break;
|
||||
}
|
||||
sApply.bStat1 = 0;
|
||||
@ -4521,9 +4580,9 @@ static int sessionChangesetApply(
|
||||
*pnRebase = sApply.rebase.nBuf;
|
||||
sApply.rebase.aBuf = 0;
|
||||
}
|
||||
sessionUpdateFree(&sApply);
|
||||
sqlite3_finalize(sApply.pInsert);
|
||||
sqlite3_finalize(sApply.pDelete);
|
||||
sqlite3_finalize(sApply.pUpdate);
|
||||
sqlite3_finalize(sApply.pSelect);
|
||||
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
|
||||
sqlite3_free((char*)sApply.constraints.aBuf);
|
||||
|
22
manifest
22
manifest
@ -1,5 +1,5 @@
|
||||
C Do\snot\sallow\saggregates\sin\sa\sRETURNING\sclause.\s\sFix\sa\smemory\sleak\sthat\noccurs\swhen\swindow\sfunctions\sare\sused\sin\sa\sRETURNING\sclause.
|
||||
D 2021-02-02T20:46:11.972
|
||||
C Load\senhancements\sfrom\strunk\sinto\sthe\sreturning\sbranch.
|
||||
D 2021-02-03T00:05:57.450
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -428,7 +428,7 @@ F ext/session/changeset.c 7a1e6a14c7e92d36ca177e92e88b5281acd709f3b726298dc34ec0
|
||||
F ext/session/changesetfuzz.c 227076ab0ae4447d742c01ee88a564da6478bbf26b65108bf8fac9cd8b0b24aa
|
||||
F ext/session/changesetfuzz1.test 2e1b90d888fbf0eea5e1bd2f1e527a48cc85f8e0ff75df1ec4e320b21f580b3a
|
||||
F ext/session/session1.test 0b2f88995832ea040ae8e83a1ad4afa99c00b85c779d213da73a95ea4113233e
|
||||
F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
|
||||
F ext/session/session2.test 7f53d755d921e0baf815c4258348e0ed460dfd8a772351bca5ad3ccbb1dc786e
|
||||
F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479
|
||||
F ext/session/session4.test 6778997065b44d99c51ff9cece047ff9244a32856b328735ae27ddef68979c40
|
||||
F ext/session/session5.test 716bc6fafd625ce60dfa62ae128971628c1a1169
|
||||
@ -454,7 +454,7 @@ F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a
|
||||
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
|
||||
F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5
|
||||
F ext/session/sessionwor.test 67b5ab91d4f93ce65ff1f58240ac5ddf73f8670facc1ffa49cef56293d52818d
|
||||
F ext/session/sqlite3session.c d2aaaf05241ac7d23a1b1eaa8b1f165c90f7ff0fe57ff1932a87c6b89b886117
|
||||
F ext/session/sqlite3session.c 1d0553077b55ffcfa69963c354e9bad3bace6ce79bbe7368e650c6ae1e106314
|
||||
F ext/session/sqlite3session.h f53c99731882bf59c7362855cdeba176ce1fe8eeba089e38a8cce0172f8473aa
|
||||
F ext/session/test_session.c 93ca965112d2b4d9d669c9c0be6b1e52942a268796050a145612df1eee175ce0
|
||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
@ -482,7 +482,7 @@ F src/auth.c 8d1df0e2ef8bafbedd4f1fe4baff03eb27507da4bf6e449df3613d383c4018b2
|
||||
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 47d9fe97d5c0d74506154e3597f8a23b81a00080751dc4d11fec91ee22796f4c
|
||||
F src/btree.c 4da25694985ac8f5f714bfa58a6cd453f9161d7da9394a95605aaa4db2752757
|
||||
F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
|
||||
F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
|
||||
F src/build.c 118e1076282415229420d04f9cc25bb148a2c412d82ea3c319136d2122c842e5
|
||||
@ -496,7 +496,7 @@ F src/delete.c 352ea931218c45a3daf17472d4141b9c7fc026d85da3f1ade404ea5bb6d67f77
|
||||
F src/expr.c 47c85263e6d179424e6b09e2c79db5704ab5b8cbc2fae2ee3285faa2566f2e74
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 02e4a3311885cd2b31eb17fd58dc2fc738cd2c823d0d39e4dd5595169c6f8bc3
|
||||
F src/func.c 796a7a4a0ff5eee82a04ee3c8265c5ebf9c6a9f5625621c5f97ed94f6224d7d9
|
||||
F src/func.c 2ea99e9e0531b7f020d5e8e167d25344d618afc718ddc94dd91fa8fef1c85a91
|
||||
F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
|
||||
@ -1030,7 +1030,7 @@ F test/func3.test 2bb0f31ab7baaed690b962a88544d7be6b34fa389364bc36a44e441ed3e3f1
|
||||
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
|
||||
F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a
|
||||
F test/func6.test 90e42b64c4f9fb6f04f44cb8a1da586c8542502e926b19c76504fe74ff2a9b7c
|
||||
F test/func7.test bb05a77daedf0e3f8764f323a49bc3b8d98f280a0bc6a370387117f4596bde05
|
||||
F test/func7.test b9e2a1a30a8562b00841b4a21a5d2d81754fa3ab99275fd71fd5279287b44b1c
|
||||
F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa
|
||||
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
|
||||
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
@ -1046,7 +1046,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
|
||||
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
|
||||
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
|
||||
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
|
||||
F test/fuzzdata8.db 7f6c5443d67ba040f760b4d28da54cc9f68174fa212ae34ccb86c645de761ec4
|
||||
F test/fuzzdata8.db 977cb95f4a5d828056dea804a6de416debe3fa0182c77f47fe19a0554aaf4db0
|
||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
@ -1899,7 +1899,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 bd5dee8425327fde0429043ce325b910f1b7951988d9a448a8eeeb713a46bc81
|
||||
R cd87aa40fae996ae8358e0b84594bda6
|
||||
P 2e9bd94b9ad37c7e4123b7324f2fe42d3609a65af449eb8a0064057647709a73 e4ccfac09b6fe8cc3aec29d10f4e4c83097964f29882343db52ed91f6f0dde1c
|
||||
R 189e18b39cf3d0cb3ef657405a5431b5
|
||||
U drh
|
||||
Z 25e8d0af3fd413c8e6c9d01783338232
|
||||
Z 8f661fe5807957ca703992c48d933956
|
||||
|
@ -1 +1 @@
|
||||
2e9bd94b9ad37c7e4123b7324f2fe42d3609a65af449eb8a0064057647709a73
|
||||
b84c7f60c2e1e7debf9f50622087f87d60c6870061d61e14e59cc1ba0775ee92
|
@ -7975,6 +7975,9 @@ static int balance_nonroot(
|
||||
apOld[i] = 0;
|
||||
rc = sqlite3PagerWrite(pNew->pDbPage);
|
||||
nNew++;
|
||||
if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv)) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
if( rc ) goto balance_cleanup;
|
||||
}else{
|
||||
assert( i>0 );
|
||||
|
@ -1980,7 +1980,7 @@ static void logFunc(
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
x = sqlite3_value_double(argv[0]);
|
||||
if( x<0.0 ) return;
|
||||
if( x<=0.0 ) return;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -1989,14 +1989,15 @@ static void logFunc(
|
||||
switch( sqlite3_value_numeric_type(argv[0]) ){
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
b = x;
|
||||
b = log(x);
|
||||
if( b<=0.0 ) return;
|
||||
x = sqlite3_value_double(argv[1]);
|
||||
if( x<0.0 ) return;
|
||||
if( x<=0.0 ) return;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
ans = log(x)/log(b);
|
||||
ans = log(x)/b;
|
||||
}else{
|
||||
ans = log(x);
|
||||
switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
|
||||
|
@ -202,11 +202,11 @@ do_execsql_test func7-mysql-210 {
|
||||
#} {0.6931472 NULL}
|
||||
# log() means natural logarithm in MySQL
|
||||
do_execsql_test func7-mysql-230 {
|
||||
SELECT log(2,65536), log(10,100), quote(log(1,100));
|
||||
} {16.0 2.0 Inf}
|
||||
SELECT log(2,65536), log(10,100), quote(log(1,100)), quote(log(0,100));
|
||||
} {16.0 2.0 NULL NULL}
|
||||
do_execsql_test func7-mysql-240 {
|
||||
SELECT log2(65536), quote(log2(-100));
|
||||
} {16.0 NULL}
|
||||
SELECT log2(65536), quote(log2(-100)), quote(log2(0));
|
||||
} {16.0 NULL NULL}
|
||||
do_execsql_test func7-mysql-250 {
|
||||
SELECT round(log10(2),7), log10(100), quote(log10(-100));
|
||||
} {0.30103 2.0 NULL}
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user