int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ );
获取包含对作为第一个参数传递的会话对象附加的表的更改的变更集。如果成功,则在返回 SQLITE_OK 之前,将 *ppChangeset 设置为指向包含变更集的缓冲区的指针,并将 *pnChangeset 设置为变更集的大小(以字节为单位)。如果发生错误,则将 *ppChangeset 和 *pnChangeset 均设置为零,并返回 SQLite 错误代码。
变更集由零个或多个 INSERT、UPDATE 和/或 DELETE 更改组成,每个更改代表对附加表的单行的更改。INSERT 更改包含新数据库行中每个字段的值。DELETE 包含已删除数据库行中每个字段的原始值。UPDATE 更改包含已更新数据库行中每个字段的原始值以及每个已更新的非主键列的更新值。UPDATE 更改无法表示修改主键列值的更改。如果进行了此类更改,则在变更集中表示为 DELETE 后跟 INSERT。
不会记录在主键列的一个或多个列中存储有 NULL 值的行所做的更改。如果插入或删除了此类行,则返回的变更集中不存在相应的更改。如果更新了在主键列中存储有一个或多个 NULL 值的现有行,使其所有主键列均为非 NULL,则变更集中仅出现 INSERT。类似地,如果更新了具有非 NULL 主键值的现有行,使其主键列中的一个或多个设置为 NULL,则生成的变更集中仅包含 DELETE 更改。
可以使用使用 sqlite3changeset_start() API 创建的迭代器遍历变更集的内容。可以使用 sqlite3changeset_apply() API 将变更集应用于具有兼容模式的数据库。
在由此函数生成的变更集中,与单个表相关的的所有更改都分组在一起。换句话说,在遍历变更集或将变更集应用于数据库时,会在继续处理下一个表之前处理与单个表相关的的所有更改。表的排序顺序与它们附加到 sqlite3_session 对象(或自动附加)的顺序相同。与单个表相关的更改的存储顺序未定义。
在成功调用此函数后,调用者有责任最终使用 sqlite3_free() 释放 *ppChangeset 指向的缓冲区。
将表附加到会话对象后,会话对象会记录插入到表中的所有新行的主键值。它还会记录任何已删除或更新行的原始主键和其他列值。对于每个唯一的主键值,数据仅记录一次 - 在会话的生命周期中,第一次插入、更新或删除具有该主键的行时。
上一段话有一个例外:当插入、更新或删除行时,如果其主键列中的一个或多个包含 NULL 值,则不会记录更改。
因此,会话对象会累积两种类型的记录 - 仅由主键值组成的记录(在用户插入新记录时创建)和由主键值以及其他表列的原始值组成的记录(在用户删除或更新记录时创建)。
调用此函数时,请求的变更集是使用累积的记录和数据库文件的当前内容创建的。具体来说
这意味着,除其他事项外,如果在会话对象处于活动状态时插入一行然后稍后删除,则变更集中既不会出现插入也不会出现删除。或者,如果在会话对象处于活动状态时删除一行然后稍后插入具有相同主键值的另一行,则生成的变更集中将包含 UPDATE 更改而不是 DELETE 和 INSERT。
当会话对象被禁用(请参阅 sqlite3session_enable() API)时,它在插入、更新或删除行时不会累积记录。如果在会话期间多次写入同一行,这似乎会产生一些违反直觉的效果。例如,如果在会话对象启用时插入一行,然后在同一会话对象禁用时删除该行,则变更集中不会出现 INSERT 记录,即使删除发生在会话禁用时也是如此。或者,如果在会话禁用时更新行的某个字段,并在会话启用时更新同一行的另一个字段,则生成的变更集中将包含一个更新两个字段的 UPDATE 更改。