SQLite

Check-in [364f3b820a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Note in the documentation that when iterating through a changeset, all changes to a single table are grouped together. Also add the sqlite3session_isempty() function.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 364f3b820a26f9b15cf74a0222ed5e302becc54f
User & Date: dan 2011-07-16 18:05:07.557
Context
2011-07-16
18:35
Fix error in a comment in sqlite3session.h. No changes to code. (check-in: 70c84e5020 user: dan tags: sessions)
18:05
Note in the documentation that when iterating through a changeset, all changes to a single table are grouped together. Also add the sqlite3session_isempty() function. (check-in: 364f3b820a user: dan tags: sessions)
2011-07-15
19:11
Add a few casts required by 64-bit VS2010 to the sessions code. (check-in: 5ac4a06111 user: dan tags: sessions)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/session/session1.test.
460
461
462
463
464
465
466



























467
468
469
  INSERT INTO aux.t1 VALUES('three', 3);
  INSERT INTO aux.t1 VALUES('four', 4);
} {
  {INSERT t1 0 X. {} {t two i 2}} 
  {INSERT t1 0 X. {} {t one i 1}}
}





























catch { db2 close }
finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  INSERT INTO aux.t1 VALUES('three', 3);
  INSERT INTO aux.t1 VALUES('four', 4);
} {
  {INSERT t1 0 X. {} {t two i 2}} 
  {INSERT t1 0 X. {} {t one i 1}}
}

#-------------------------------------------------------------------------
# Test the sqlite3session_isempty() function.
#
do_test 8.1 {
  execsql {
    CREATE TABLE t5(x PRIMARY KEY, y);
    CREATE TABLE t6(x PRIMARY KEY, y);
    INSERT INTO t5 VALUES('a', 'b');
    INSERT INTO t6 VALUES('a', 'b');
  }
  sqlite3session S db main
  S attach *

  S isempty
} {0}
do_test 8.2 {
  execsql { DELETE FROM t5 }
  S isempty
} {1}
do_test 8.3 {
  S delete
  sqlite3session S db main
  S attach t5
  execsql { DELETE FROM t5 }
  S isempty
} {0}
do_test 8.4 { S delete } {}

catch { db2 close }
finish_test
Changes to ext/session/sqlite3session.c.
1766
1767
1768
1769
1770
1771
1772

















1773
1774
1775
1776
1777
1778
1779
  int ret;
  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
  if( bIndirect>=0 ){
    pSession->bIndirect = bIndirect;
  }
  ret = pSession->bIndirect;
  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));

















  return ret;
}

/*
** Create an iterator used to iterate through the contents of a changeset.
*/
int sqlite3changeset_start(







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
  int ret;
  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
  if( bIndirect>=0 ){
    pSession->bIndirect = bIndirect;
  }
  ret = pSession->bIndirect;
  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
  return ret;
}

/*
** Return true if there have been no changes to monitored tables recorded
** by the session object passed as the only argument.
*/
int sqlite3session_isempty(sqlite3_session *pSession){
  int ret = 0;
  SessionTable *pTab;

  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
  for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){
    ret = (pTab->nEntry>0);
  }
  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));

  return ret;
}

/*
** Create an iterator used to iterate through the contents of a changeset.
*/
int sqlite3changeset_start(
Changes to ext/session/sqlite3session.h.
250
251
252
253
254
255
256

















257
258
259
260
261
262
263
*/
int sqlite3session_changeset(
  sqlite3_session *pSession,      /* Session object */
  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
  void **ppChangeset              /* OUT: Buffer containing changeset */
);


















/*
** CAPI3REF: Create An Iterator To Traverse A Changeset 
**
** Create an iterator used to iterate through the contents of a changeset.
** If successful, *pp is set to point to the iterator handle and SQLITE_OK
** is returned. Otherwise, if an error occurs, *pp is set to zero and an
** SQLite error code is returned.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







250
251
252
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
*/
int sqlite3session_changeset(
  sqlite3_session *pSession,      /* Session object */
  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
  void **ppChangeset              /* OUT: Buffer containing changeset */
);

/*
** CAPI3REF: Test if a changeset has recorded any changes.
**
** Return non-zero if no changes to attached tables have been recorded by 
** the session object passed as the first argument. Otherwise, if one or 
** more changes have been recorded, return zero.
**
** Even if this function returns zero, it is possible that calling
** [sqlite3session_changeset()] on the session handle may still return a
** changeset that contains no changes. This can happen when a row in 
** an attached table is modified and then later on the original values 
** are restored. However, if this function returns non-zero, then it is
** guaranteed that a call to sqlite3session_changeset() will return a 
** changeset containing zero changes.
*/
int sqlite3session_isempty(sqlite3_session *pSession);

/*
** CAPI3REF: Create An Iterator To Traverse A Changeset 
**
** Create an iterator used to iterate through the contents of a changeset.
** If successful, *pp is set to point to the iterator handle and SQLITE_OK
** is returned. Otherwise, if an error occurs, *pp is set to zero and an
** SQLite error code is returned.
272
273
274
275
276
277
278









279
280
281
282
283
284
285
**   <li> [sqlite3changeset_old()]
** </ul>
**
** It is the responsibility of the caller to eventually destroy the iterator
** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
** changeset (pChangeset) must remain valid until after the iterator is
** destroyed.









*/
int sqlite3changeset_start(
  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
  int nChangeset,                 /* Size of changeset blob in bytes */
  void *pChangeset                /* Pointer to blob containing changeset */
);








>
>
>
>
>
>
>
>
>







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
**   <li> [sqlite3changeset_old()]
** </ul>
**
** It is the responsibility of the caller to eventually destroy the iterator
** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
** changeset (pChangeset) must remain valid until after the iterator is
** destroyed.
**
** Assuming the changeset blob was created by one of the
** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
** [sqlite3changest_invert()], all changes within the changeset that apply
** to a single table are grouped together. This means that when an application
** iterates through a changeset using an iterator created by this function,
** all changes that relate to a single table are visted consecutively. There 
** is no chance that the iterator will visit a change the applies to table X, 
** then one for table Y, and then later on visit another change for table X.
*/
int sqlite3changeset_start(
  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
  int nChangeset,                 /* Size of changeset blob in bytes */
  void *pChangeset                /* Pointer to blob containing changeset */
);

Changes to ext/session/test_session.c.
34
35
36
37
38
39
40

41
42
43
44
45
46
47
    int iSub;
  } aSub[] = {
    { "attach",    1, "TABLE", }, /* 0 */
    { "changeset", 0, "",      }, /* 1 */
    { "delete",    0, "",      }, /* 2 */
    { "enable",    1, "BOOL",  }, /* 3 */
    { "indirect",  1, "BOOL",  }, /* 4 */

    { 0 }
  };
  int iSub;
  int rc;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");







>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    int iSub;
  } aSub[] = {
    { "attach",    1, "TABLE", }, /* 0 */
    { "changeset", 0, "",      }, /* 1 */
    { "delete",    0, "",      }, /* 2 */
    { "enable",    1, "BOOL",  }, /* 3 */
    { "indirect",  1, "BOOL",  }, /* 4 */
    { "isempty",   0, "",      }, /* 5 */
    { 0 }
  };
  int iSub;
  int rc;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
95
96
97
98
99
100
101







102
103
104
105
106
107
108
    case 4: {      /* indirect */
      int val;
      if( Tcl_GetIntFromObj(interp, objv[2], &val) ) return TCL_ERROR;
      val = sqlite3session_indirect(pSession, val);
      Tcl_SetObjResult(interp, Tcl_NewBooleanObj(val));
      break;
    }







  }

  return TCL_OK;
}

static void test_session_del(void *clientData){
  sqlite3_session *pSession = (sqlite3_session *)clientData;







>
>
>
>
>
>
>







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
    case 4: {      /* indirect */
      int val;
      if( Tcl_GetIntFromObj(interp, objv[2], &val) ) return TCL_ERROR;
      val = sqlite3session_indirect(pSession, val);
      Tcl_SetObjResult(interp, Tcl_NewBooleanObj(val));
      break;
    }

    case 5: {      /* isempty */
      int val;
      val = sqlite3session_isempty(pSession);
      Tcl_SetObjResult(interp, Tcl_NewBooleanObj(val));
      break;
    }
  }

  return TCL_OK;
}

static void test_session_del(void *clientData){
  sqlite3_session *pSession = (sqlite3_session *)clientData;