Load enhancements from trunk into the returning branch.

FossilOrigin-Name: b84c7f60c2e1e7debf9f50622087f87d60c6870061d61e14e59cc1ba0775ee92
This commit is contained in:
drh 2021-02-03 00:05:57 +00:00
commit 47600083f1
8 changed files with 264 additions and 153 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -1 +1 @@
2e9bd94b9ad37c7e4123b7324f2fe42d3609a65af449eb8a0064057647709a73
b84c7f60c2e1e7debf9f50622087f87d60c6870061d61e14e59cc1ba0775ee92

View File

@ -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 );

View File

@ -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)) ){

View File

@ -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.