aboutsummaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/session/session2.test24
-rw-r--r--ext/session/session_common.tcl2
-rw-r--r--ext/session/sqlite3session.c56
-rw-r--r--ext/session/sqlite3session.h17
-rw-r--r--ext/session/test_session.c7
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 */