Index: ext/session/session2.test ================================================================== --- ext/session/session2.test +++ ext/session/session2.test @@ -32,13 +32,14 @@ execsql $sql db execsql $sql db2 } proc xConflict args { return "OMIT" } -proc do_then_apply_sql {sql} { - sqlite3session S db main - db eval {SELECT name FROM sqlite_master WHERE type = 'table'} { +proc do_then_apply_sql {sql {dbname main}} { + + sqlite3session S db $dbname + db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" { S attach $name } db eval $sql sqlite3changeset_apply db2 [S changeset] xConflict @@ -169,12 +170,98 @@ BEGIN; DELETE FROM t1 WHERE 1; ROLLBACK; } } { -if {$tn==9} breakpoint do_then_apply_sql $sql - do_test $tn { compare_db db db2 } {} + do_test 1.$tn { compare_db db db2 } {} +} + +# The following block of tests is similar to the last, except that the +# session object is recording changes made to an attached database. The +# main database contains a table of the same name as the table being +# modified within the attached db. +# +test_reset +forcedelete test.db3 +sqlite3 db3 test.db3 +do_test 2.0 { + execsql { + ATTACH 'test.db3' AS 'aux'; + CREATE TABLE t1(a, b PRIMARY KEY); + CREATE TABLE t2(x, y, z); + CREATE TABLE t3(a); + + CREATE TABLE aux.t1(a PRIMARY KEY, b); + CREATE TABLE aux.t2(a, b INTEGER PRIMARY KEY); + CREATE TABLE aux.t3(a, b, c, PRIMARY KEY(a, b)); + } + execsql { + CREATE TABLE t1(a PRIMARY KEY, b); + CREATE TABLE t2(a, b INTEGER PRIMARY KEY); + CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)); + } db2 +} {} + +foreach {tn sql} { + 1 { INSERT INTO aux.t1 VALUES(1, 2) } + + 2 { + INSERT INTO aux.t2 VALUES(1, NULL); + INSERT INTO aux.t2 VALUES(2, NULL); + INSERT INTO aux.t2 VALUES(3, NULL); + DELETE FROM aux.t2 WHERE a = 2; + INSERT INTO aux.t2 VALUES(4, NULL); + UPDATE aux.t2 SET b=0 WHERE b=1; + } + + 3 { INSERT INTO aux.t3 SELECT *, NULL FROM aux.t2 } + + 4 { + INSERT INTO aux.t3 SELECT a||a, b||b, NULL FROM aux.t3; + DELETE FROM aux.t3 WHERE rowid%2; + } + + 5 { UPDATE aux.t3 SET c = a||b } + + 6 { UPDATE aux.t1 SET a = 32 } + + 7 { + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + DELETE FROM aux.t1 WHERE (rowid%3)==0; + } + + 8 { + BEGIN; + INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; + ROLLBACK; + } + 9 { + BEGIN; + UPDATE aux.t1 SET b = 'xxx'; + ROLLBACK; + } + 10 { + BEGIN; + DELETE FROM aux.t1 WHERE 1; + ROLLBACK; + } +} { + do_then_apply_sql $sql aux + do_test 2.$tn { compare_db db3 db2 } {} } + +catch {db3 close} + finish_test Index: ext/session/sqlite3session.c ================================================================== --- ext/session/sqlite3session.c +++ ext/session/sqlite3session.c @@ -1189,10 +1189,11 @@ } } static int sessionSelectStmt( sqlite3 *db, /* Database handle */ + const char *zDb, /* Database name */ const char *zTab, /* Table name */ int nCol, const char **azCol, u8 *abPK, sqlite3_stmt **ppStmt @@ -1201,10 +1202,12 @@ int i; const char *zSep = ""; SessionBuffer buf = {0, 0, 0}; sessionAppendStr(&buf, "SELECT * FROM ", &rc); + sessionAppendIdent(&buf, zDb, &rc); + sessionAppendStr(&buf, ".", &rc); sessionAppendIdent(&buf, zTab, &rc); sessionAppendStr(&buf, " WHERE ", &rc); for(i=0; irc; for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ if( pTab->nEntry ){ + const char *zName = pTab->zName; int nCol = pTab->nCol; /* Local copy of member variable */ u8 *abPK = pTab->abPK; /* Local copy of member variable */ int i; /* Used to iterate through hash buckets */ sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */ int nRewind = buf.nBuf; /* Initial size of write buffer */ @@ -1321,15 +1325,16 @@ int nNoop; /* Size of buffer after writing tbl header */ /* Write a table header */ sessionAppendByte(&buf, 'T', &rc); sessionAppendVarint(&buf, nCol, &rc); - sessionAppendBlob(&buf, (u8 *)pTab->zName, strlen(pTab->zName)+1, &rc); + sessionAppendBlob(&buf, (u8 *)zName, strlen(zName)+1, &rc); /* Build and compile a statement to execute: */ if( rc==SQLITE_OK ){ - rc = sessionSelectStmt(db, pTab->zName, nCol, pTab->azCol, abPK, &pSel); + rc = sessionSelectStmt( + db, pSession->zDb, zName, nCol, pTab->azCol, abPK, &pSel); } if( rc==SQLITE_OK && nCol!=sqlite3_column_count(pSel) ){ rc = SQLITE_SCHEMA; } @@ -1940,11 +1945,12 @@ static int sessionSelectRow( sqlite3 *db, /* Database handle */ const char *zTab, /* Table name */ SessionApplyCtx *p /* Session changeset-apply context */ ){ - return sessionSelectStmt(db, zTab, p->nCol, p->azCol, p->abPK, &p->pSelect); + return sessionSelectStmt( + db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect); } /* ** Formulate and prepare an INSERT statement to add a record to table zTab. ** For example: