Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | If a NULL pointer is passed to sqlite3session_attach() in place of a table name, attach all database tables to the session object. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | sessions |
Files: | files | file ages | folders |
SHA1: |
e9037e4e4ccaa5c633759c4d041b60b6 |
User & Date: | dan 2011-03-22 15:21:04.000 |
Context
2011-03-22
| ||
16:54 | Fix a crash that can follow an OOM when "all tables" are registered with a session module. (check-in: 183c236e99 user: dan tags: sessions) | |
15:21 | If a NULL pointer is passed to sqlite3session_attach() in place of a table name, attach all database tables to the session object. (check-in: e9037e4e4c user: dan tags: sessions) | |
12:08 | Add OOM tests and related fixes for the session module. (check-in: 06048a68b3 user: dan tags: sessions) | |
Changes
Changes to ext/session/session2.test.
︙ | ︙ | |||
253 254 255 256 257 258 259 260 261 262 | 8 { INSERT INTO t2 VALUES(1, 2, 3) } { {INSERT t2 {} {i 1 i 2 i 3}} } 9 { DELETE FROM t2 WHERE 1 } { {DELETE t2 {i 1 i 2 i 3} {}} } } { do_iterator_test 4.$tn {t1 t2 t3} $sql $changeset } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | 8 { INSERT INTO t2 VALUES(1, 2, 3) } { {INSERT t2 {} {i 1 i 2 i 3}} } 9 { DELETE FROM t2 WHERE 1 } { {DELETE t2 {i 1 i 2 i 3} {}} } } { do_iterator_test 4.$tn {t1 t2 t3} $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 |
Changes to ext/session/session_common.tcl.
︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | catch { S delete } if {$rc} {error $msg} } proc do_iterator_test {tn tbl_list sql res} { sqlite3session S db main foreach t $tbl_list {S attach $t} execsql $sql set r [list] foreach v $res { lappend r $v } set x [list] sqlite3session_foreach c [S changeset] { lappend x $c } | > > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | catch { S delete } if {$rc} {error $msg} } 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] foreach v $res { lappend r $v } set x [list] sqlite3session_foreach c [S changeset] { lappend x $c } |
︙ | ︙ |
Changes to ext/session/sqlite3session.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /* ** Session handle structure. */ 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 rc; /* Non-zero if an error has occurred */ sqlite3_session *pNext; /* Next session object on same db. */ SessionTable *pTable; /* List of attached tables */ }; /* ** Structure for changeset iterators. | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /* ** Session handle structure. */ 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 */ }; /* ** Structure for changeset iterators. |
︙ | ︙ | |||
771 772 773 774 775 776 777 | /* If this session is attached to a different database ("main", "temp" ** etc.), or if it is not currently enabled, there is nothing to do. Skip ** to the next session object attached to this database. */ if( pSession->bEnable==0 ) continue; if( pSession->rc ) continue; if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue; | | > > > > > > > > > | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | /* If this session is attached to a different database ("main", "temp" ** etc.), or if it is not currently enabled, there is nothing to do. Skip ** to the next session object attached to this database. */ if( pSession->bEnable==0 ) continue; if( pSession->rc ) continue; if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue; 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 ){ sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab); } break; } |
︙ | ︙ | |||
872 873 874 875 876 877 878 | ** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) ** or not. */ int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ const char *zName /* Table name */ ){ | < < > > | > > > | | | | | | | | | | | | | | | | | | > | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 | ** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) ** or not. */ int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ const char *zName /* Table name */ ){ int rc = SQLITE_OK; sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); 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; } } } sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); return rc; } |
︙ | ︙ |
Changes to ext/session/sqlite3session.h.
︙ | ︙ | |||
89 90 91 92 93 94 95 | ** the session is disabled, or 1 if it is enabled. */ int sqlite3session_enable(sqlite3_session *pSession, int bEnable); /* ** CAPI3REF: Attach A Table To A Session Object ** | > | | | > > > > > | | < | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | ** the session is disabled, or 1 if it is enabled. */ int sqlite3session_enable(sqlite3_session *pSession, int bEnable); /* ** CAPI3REF: Attach A Table To A Session Object ** ** 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 ** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY ** KEY may consist of a single column, or may be a composite key. ** ** It is not an error if the named table does not exist in the database. Nor ** is it an error if the named table does not have a PRIMARY KEY. However, ** no changes will be recorded in either of these scenarios. ** ** 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 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 */ const char *zTab /* Table name */ ); /* |
︙ | ︙ |
Changes to ext/session/test_session.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 | if( rc!=TCL_OK ) return rc; if( objc!=2+aSub[iSub].nArg ){ Tcl_WrongNumArgs(interp, 2, objv, aSub[iSub].zMsg); return TCL_ERROR; } switch( iSub ){ | | > > | > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | if( rc!=TCL_OK ) return rc; if( objc!=2+aSub[iSub].nArg ){ Tcl_WrongNumArgs(interp, 2, objv, aSub[iSub].zMsg); return TCL_ERROR; } switch( iSub ){ 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 */ int nChange; void *pChange; rc = sqlite3session_changeset(pSession, &nChange, &pChange); if( rc==SQLITE_OK ){ |
︙ | ︙ |