checkpointing 9th attached database checkpoints all databases
(1) By Richard PArkins (rparkins) on 2021-03-10 14:11:15 [source]
The problem is in the interface to sqlite3Checkpoint()
, where the value
SQLITE_MAX_ATTACHED
for the argument iDb
is used to indicate that all
databases are to be checkpointed.
Presumably the assumption of the writer of this code was that index into the
array aDb
in a struct sqlite3
must be less than SQLITE_MAX_ATTACHED
.
Unfortunately this is incorrect.
As stated in the comment on the definition of struct Db
, aDb[0]
and
aDb[1]
are reserved for the main
and temp
databases respectively,
and SQLITE_MAX_ATTACHED
further databases can be attached,
making the maximum possible index SQLITE_MAX_ATTACHED+1
.
I think that line 103198
assert( iDb>=0 && iDb<SQLITE_MAX_ATTACHED );
is a bit dubious as well. sqlite3SchemaToIndex()
can validly return
SQLITE_MAX_ATTACHED
or SQLITE_MAX_ATTACHED+1
as noted above.
This is a script that demonstrates the problem (assuming that sqlite
is compiled with the default SQLITE_MAX_ATTACHED
of 10):-
gdb sqlite3
start
break sqlite3.c:166381
c
.open main.sqlite
ATTACH 'attach1.sqlite' AS 'attach1';
ATTACH 'attach2.sqlite' AS 'attach2';
ATTACH 'attach3.sqlite' AS 'attach3';
ATTACH 'attach4.sqlite' AS 'attach4';
ATTACH 'attach5.sqlite' AS 'attach5';
ATTACH 'attach6.sqlite' AS 'attach6';
ATTACH 'attach7.sqlite' AS 'attach7';
ATTACH 'attach8.sqlite' AS 'attach8';
ATTACH 'attach9.sqlite' AS 'attach9';
PRAGMA attach8.wal_checkpoint; -- checkpoints one database
display i
display db->aDb[i].zDbSName
c
PRAGMA attach9.wal_checkpoint; -- checkpoints all of them
c
c
c
c
c
c
c
c
c
c
c
.quit
q
This is suggested diff that fixes the problem. It isn't the simplest possible
patch, but it has in my opinion better maintainability because any change to the
set of reserved slots in the aDb array is propagated to all places in the code
that are affected.
16740,16741c16740,16741
< ** aDb[1] is the database file used to hold temporary tables. Additional
< ** databases may be attached.
---
> ** aDb[1] is the database file used to hold temporary tables.
> ** SQLITE_LIMIT_ATTACHED additional databases may be attached.
16742a16743
> #define SQLITE_MAX_DATABASES (SQLITE_MAX_ATTACHED + 2)
103198c103199
< assert( iDb>=0 && iDb<SQLITE_MAX_ATTACHED );
---
> assert( iDb>=0 && iDb<SQLITE_MAX_DATABASES );
116369c116370
< assert( iDb<SQLITE_MAX_ATTACHED+2 );
---
> assert( iDb<SQLITE_MAX_DATABASES);
129425c129426
< int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
---
> int iBt = (pId2->z?iDb:SQLITE_MAX_DATABASES);
166292c166293
< int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
---
> int iDb = SQLITE_MAX_DATABASES; /* sqlite3.aDb[] index of db to checkpoint */
166363c166364
< ** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are
---
> ** If iDb is passed SQLITE_MAX_DATABASES, then all attached databases are
166380c166381
< if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
---
> if( i==iDb || iDb==SQLITE_MAX_DATABASES ){