Are you sure it is not the special case documented in the ATTACH command? (see 
https://sqlite.org/lang_attach.html)

" Transactions involving multiple attached databases are atomic, assuming that 
the main database is not ":memory:" and the journal_mode is not WAL. If the 
main database is ":memory:" or if the journal_mode is WAL, then transactions 
continue to be atomic within each individual database file. But if the host 
computer crashes in the middle of a COMMIT where two or more database files are 
updated, some of those files might get the changes where others might not."

-----Ursprüngliche Nachricht-----
Von: sqlite-users [mailto:sqlite-users-boun...@mailinglists.sqlite.org] Im 
Auftrag von sanhua.zh
Gesendet: Mittwoch, 01. August 2018 09:57
An: sqlite-users <sqlite-users@mailinglists.sqlite.org>; drh <d...@sqlite.org>
Betreff: [EXTERNAL] [sqlite] UNION ALL bug in Multi-threading

I find a bug that exists in `UNION ALL`.


tldr: `UNION ALL` will not merge the data in different schemas in the moment 
that one of schema is committed but the another not. BUT, `UNION` will.


Here are the reproduce steps:


Preparation:
1. Prepare a database named "OLD"
1.1 Create a table for "OLD": `CREATE TABLE old(i INTEGER)`
1.2 Insert values into "OLD" to make it large enough: `INSERT INTO old 
VALUES(?1)` 2. Prepare a database named "NEW"
2.1 Create a table for "NEW": `CREATE TABLE new(i INTEGER)`


Migration:
For thread 1:
1. Attach "OLD" to "NEW" as "oldSchema": `ATTACH OLD AS oldSchema` 2. Migrate 
data from "OLD" to "NEW" in same transaction. Note that they should be executed 
with same handle using ATTACH mentioned in 1.
2.1 `BEGIN IMMEDIATE`
2.1 Select one of the row from "OLD": `SELECT i FROM oldSchema.old`
2.2 Insert the row into "NEW": `INSERT INTO main.new VALUES(?1)`
2.3 Delete the row from "OLD": `DELETE FROM oldSchema.old WHERE i == ?1`
2.4 `COMMIT`


For thread 2-N:
1. Create a view that union two tables: `CREATE TEMP VIEW v AS SELECT i FROM 
oldSchema.old UNION ALL SELECT i FROM main.new` 2. Select one of the value from 
view: `SELECT i FROM temp.v ORDER BY i LIMIT 1 OFFSET ?1`.
Here is the strange result:
As an example, if the values of 0-999 is inserted into "OLD", then value N 
should be selected as expected at offset N.
But in these kind of steps, it will not.


It can be a little bit hard to reproduce due to the multi-threading. BUT if it 
sleeps for a while when committing, it will be much easier to reproduce:
// vdbeCommit method of vdbeaux.c
for(i=0; rc==SQLITE_OK  idb-nDb; i++){
 Btree *pBt = db-aDb[i].pBt;
 sqlite3_sleep(10); // additional sleep here  if( pBt ){
  rc = sqlite3BtreeCommitPhaseOne(pBt, 0);  } }


It seems that the bug happens when one of the schema is committed but the 
another one is not.
On the other handle, if `UNION ALL` is changed to `UNION` while creating view, 
the bug will not happen too.
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


___________________________________________
 Gunter Hick | Software Engineer | Scientific Games International GmbH | 
Klitschgasse 2-4, A-1130 Vienna | FN 157284 a, HG Wien, DVR: 0430013 | (O) +43 
1 80100 - 0

May be privileged. May be confidential. Please delete if not the addressee.
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to