diff options
Diffstat (limited to 'ext/session')
-rw-r--r-- | ext/session/session2.test | 24 | ||||
-rw-r--r-- | ext/session/session_common.tcl | 2 | ||||
-rw-r--r-- | ext/session/sqlite3session.c | 56 | ||||
-rw-r--r-- | ext/session/sqlite3session.h | 17 | ||||
-rw-r--r-- | ext/session/test_session.c | 7 |
5 files changed, 77 insertions, 29 deletions
diff --git a/ext/session/session2.test b/ext/session/session2.test index 984559bb1..d0d8fa561 100644 --- a/ext/session/session2.test +++ b/ext/session/session2.test @@ -258,5 +258,29 @@ foreach {tn sql changeset} { } +#------------------------------------------------------------------------- +# Test that if NULL is passed to sqlite3session_attach(), all database +# tables are attached to the session object. +# +test_reset +do_execsql_test 5.0 { + CREATE TABLE t1(a PRIMARY KEY); + CREATE TABLE t2(x, y PRIMARY KEY); +} + +foreach {tn sql changeset} { + 1 { INSERT INTO t1 VALUES(35) } { {INSERT t1 {} {i 35}} } + 2 { INSERT INTO t2 VALUES(36, 37) } { {INSERT t2 {} {i 36 i 37}} } + 3 { + DELETE FROM t1 WHERE 1; + UPDATE t2 SET x = 34; + } { + {UPDATE t2 {i 36 i 37} {i 34 {} {}}} + {DELETE t1 {i 35} {}} + } +} { + do_iterator_test 5.$tn * $sql $changeset +} + finish_test diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl index 41c80dee8..d5c74fba5 100644 --- a/ext/session/session_common.tcl +++ b/ext/session/session_common.tcl @@ -77,7 +77,9 @@ proc do_then_apply_sql {sql {dbname main}} { proc do_iterator_test {tn tbl_list sql res} { sqlite3session S db main + if {[llength $tbl_list]==0} { S attach * } foreach t $tbl_list {S attach $t} + execsql $sql set r [list] diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 7c7890aed..2b0e3ac6b 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -19,6 +19,7 @@ struct sqlite3_session { sqlite3 *db; /* Database handle session is attached to */ char *zDb; /* Name of database session is attached to */ int bEnable; /* True if currently recording */ + int bAutoAttach; /* True to auto-attach tables */ int rc; /* Non-zero if an error has occurred */ sqlite3_session *pNext; /* Next session object on same db. */ SessionTable *pTable; /* List of attached tables */ @@ -775,7 +776,16 @@ static void xPreUpdate( if( pSession->rc ) continue; if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue; - for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){ + for(pTab=pSession->pTable; pTab || pSession->bAutoAttach; pTab=pTab->pNext){ + if( !pTab ){ + /* This branch is taken if table zName has not yet been attached to + ** this session and the auto-attach flag is set. */ + pSession->rc = sqlite3session_attach(pSession,zName); + if( pSession->rc ) continue; + pTab = pSession->pTable; + assert( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ); + } + if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ){ sessionPreupdateOneChange(op, pSession, pTab); if( op==SQLITE_UPDATE ){ @@ -876,31 +886,35 @@ int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ const char *zName /* Table name */ ){ - SessionTable *pTab; /* New table object (if required) */ - int nName; /* Number of bytes in string zName */ int rc = SQLITE_OK; - sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); - /* First search for an existing entry. If one is found, this call is - ** a no-op. Return early. */ - nName = strlen(zName); - for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){ - if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break; - } + if( !zName ){ + pSession->bAutoAttach = 1; + }else{ + SessionTable *pTab; /* New table object (if required) */ + int nName; /* Number of bytes in string zName */ + + /* First search for an existing entry. If one is found, this call is + ** a no-op. Return early. */ + nName = strlen(zName); + for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){ + if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break; + } - if( !pTab ){ - /* Allocate new SessionTable object. */ - pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1); if( !pTab ){ - rc = SQLITE_NOMEM; - }else{ - /* Populate the new SessionTable object and link it into the list. */ - memset(pTab, 0, sizeof(SessionTable)); - pTab->zName = (char *)&pTab[1]; - memcpy(pTab->zName, zName, nName+1); - pTab->pNext = pSession->pTable; - pSession->pTable = pTab; + /* Allocate new SessionTable object. */ + pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1); + if( !pTab ){ + rc = SQLITE_NOMEM; + }else{ + /* Populate the new SessionTable object and link it into the list. */ + memset(pTab, 0, sizeof(SessionTable)); + pTab->zName = (char *)&pTab[1]; + memcpy(pTab->zName, zName, nName+1); + pTab->pNext = pSession->pTable; + pSession->pTable = pTab; + } } } diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h index 8e1767efa..d9d0ae1f5 100644 --- a/ext/session/sqlite3session.h +++ b/ext/session/sqlite3session.h @@ -93,9 +93,15 @@ int sqlite3session_enable(sqlite3_session *pSession, int bEnable); /* ** CAPI3REF: Attach A Table To A Session Object ** -** Attach a table to a session. All subsequent changes made to the table -** while the session object is enabled will be recorded. See documentation -** for [sqlite3session_changeset()] for further details. +** If argument zTab is not NULL, then it is the name of a table to attach +** to the session object passed as the first argument. All subsequent changes +** made to the table while the session object is enabled will be recorded. See +** documentation for [sqlite3session_changeset()] for further details. +** +** Or, if argument zTab is NULL, then changes are recorded for all tables +** in the database. If additional tables are added to the database (by +** executing "CREATE TABLE" statements) after this call is made, changes for +** the new tables are also recorded. ** ** Changes can only be recorded for tables that have a PRIMARY KEY explicitly ** defined as part of their CREATE TABLE statement. It does not matter if the @@ -109,9 +115,8 @@ int sqlite3session_enable(sqlite3_session *pSession, int bEnable); ** Changes are not recorded for individual rows that have NULL values stored ** in one or more of their PRIMARY KEY columns. ** -** SQLITE_OK is returned if the table is successfully attached to the session -** object. Or, if an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) -** is returned. +** SQLITE_OK is returned if the call completes without error. Or, if an error +** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. */ int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ diff --git a/ext/session/test_session.c b/ext/session/test_session.c index e3c7f4a21..ecc07187d 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -54,11 +54,14 @@ static int test_session_cmd( } switch( iSub ){ - case 0: /* attach */ - rc = sqlite3session_attach(pSession, Tcl_GetString(objv[2])); + case 0: { /* attach */ + char *zArg = Tcl_GetString(objv[2]); + if( zArg[0]=='*' && zArg[1]=='\0' ) zArg = 0; + rc = sqlite3session_attach(pSession, zArg); if( rc!=SQLITE_OK ){ return test_session_error(interp, rc); } + } break; case 1: { /* changeset */ |