int sqlite3changeset_apply( sqlite3 *db, /* Apply change to "main" db of this handle */ int nChangeset, /* Size of changeset in bytes */ void *pChangeset, /* Changeset blob */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx /* First argument passed to xConflict */ ); int sqlite3changeset_apply_v2( sqlite3 *db, /* Apply change to "main" db of this handle */ int nChangeset, /* Size of changeset in bytes */ void *pChangeset, /* Changeset blob */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ int flags /* SESSION_CHANGESETAPPLY_* flags */ );
将变更集或补丁集应用到数据库。这些函数尝试使用通过第二个和第三个参数传递的变更集中找到的更改来更新附加到句柄 db 的“主”数据库。
传递给这些函数的第四个参数 (xFilter) 是“过滤器回调”。如果它不为 NULL,则对于受变更集中至少一个更改影响的每个表,都会使用表名作为第二个参数调用过滤器回调,并将作为第六个参数传递的上下文指针的副本作为第一个参数。如果“过滤器回调”返回零,则不会尝试对表应用任何更改。否则,如果返回值非零或 xFilter 参数为 NULL,则会尝试所有与表相关的更改。
对于每个未被过滤器回调排除的表,此函数都会测试目标数据库是否包含兼容的表。如果以下所有条件都为真,则表被视为兼容
如果没有兼容的表,这不是错误,但不会应用与该表关联的任何更改。通过 sqlite3_log() 机制发出警告消息,错误代码为 SQLITE_SCHEMA。对于变更集中的每个表,最多发出一个这样的警告。
对于每个存在兼容表的更改,都会尝试根据 UPDATE、INSERT 或 DELETE 更改修改表内容。如果无法干净地应用更改,则可能会调用作为 sqlite3changeset_apply() 的第五个参数传递的冲突处理程序函数。下面详细介绍了每次更改类型调用冲突处理程序的确切时间。
与 xFilter 参数不同,xConflict 不能传递 NULL。将除有效函数指针之外的任何内容作为 xConflict 参数传递的结果未定义。
每次调用冲突处理程序函数时,它都必须返回 SQLITE_CHANGESET_OMIT、SQLITE_CHANGESET_ABORT 或 SQLITE_CHANGESET_REPLACE 之一。只有当传递给冲突处理程序的第二个参数为 SQLITE_CHANGESET_DATA 或 SQLITE_CHANGESET_CONFLICT 时,才能返回 SQLITE_CHANGESET_REPLACE。如果冲突处理程序返回非法值,则会回滚已进行的任何更改,并且对 sqlite3changeset_apply() 的调用将返回 SQLITE_MISUSE。sqlite3changeset_apply() 根据每次调用冲突处理程序函数返回的值采取不同的操作。有关详细信息,请参阅三个 可用返回值 的文档。
如果找到具有匹配 Primary Key 值的行,但一个或多个非 Primary Key 字段包含的值与存储在变更集中的原始行值不同,则会使用 SQLITE_CHANGESET_DATA 作为第二个参数调用冲突处理程序函数。如果数据库表具有比变更集中记录的更多的列,则仅将这些非 Primary Key 字段的值与当前数据库内容进行比较 - 任何尾随的数据库表列都将被忽略。
如果在数据库中找不到具有匹配 Primary Key 值的行,则会使用 SQLITE_CHANGESET_NOTFOUND 作为第二个参数调用冲突处理程序函数。
如果尝试执行 DELETE 操作,但 SQLite 返回 SQLITE_CONSTRAINT(这只能在违反外键约束时发生),则会使用 SQLITE_CHANGESET_CONSTRAINT 作为第二个参数调用冲突处理程序函数。这包括尝试执行 DELETE 操作的情况,因为之前对冲突处理程序函数的调用返回了 SQLITE_CHANGESET_REPLACE。
如果插入行尝试失败,因为数据库已包含具有相同 Primary Key 值的行,则会使用 SQLITE_CHANGESET_CONFLICT 设置为第二个参数调用冲突处理程序函数。
如果插入行尝试失败,因为某些其他约束违规(例如 NOT NULL 或 UNIQUE),则会使用 SQLITE_CHANGESET_CONSTRAINT 设置为第二个参数调用冲突处理程序函数。这包括重新尝试 INSERT 操作的情况,因为之前对冲突处理程序函数的调用返回了 SQLITE_CHANGESET_REPLACE。
如果找到具有匹配 Primary Key 值的行,但一个或多个已修改的非 Primary Key 字段包含的值与存储在变更集中的原始行值不同,则会使用 SQLITE_CHANGESET_DATA 作为第二个参数调用冲突处理程序函数。由于 UPDATE 更改仅包含要修改的非 Primary Key 字段的值,因此只需要这些字段与原始值匹配以避免 SQLITE_CHANGESET_DATA 冲突处理程序回调。
如果在数据库中找不到具有匹配 Primary Key 值的行,则会使用 SQLITE_CHANGESET_NOTFOUND 作为第二个参数调用冲突处理程序函数。
如果尝试执行 UPDATE 操作,但 SQLite 返回 SQLITE_CONSTRAINT,则会使用 SQLITE_CHANGESET_CONSTRAINT 作为第二个参数调用冲突处理程序函数。这包括在之前对冲突处理程序函数的调用返回 SQLITE_CHANGESET_REPLACE 后尝试执行 UPDATE 操作的情况。
可以安全地执行 SQL 语句,包括那些写入与之相关的回调相关的表的 SQL 语句,这些语句可以在 xConflict 回调中执行。这可以用于进一步自定义应用程序的冲突解决策略。
这些函数所做的所有更改都包含在一个保存点事务中。如果发生任何其他错误(除了尝试写入目标数据库时的约束失败),则保存点事务将回滚,将目标数据库恢复到其原始状态,并返回 SQLite 错误代码。
如果输出参数 (ppRebase) 和 (pnRebase) 不为 NULL 且输入是变更集(而不是补丁集),则 sqlite3changeset_apply_v2() 可能会将 (*ppRebase) 设置为指向“rebase”,该“rebase”可以在返回之前与 sqlite3_rebaser API 缓冲区一起使用。在这种情况下,(*pnRebase) 将设置为缓冲区的大小(以字节为单位)。调用者有责任最终使用 sqlite3_free() 释放任何此类缓冲区。只有在应用补丁集时遇到一个或多个冲突时,才会分配和填充缓冲区。有关更多详细信息,请参阅 sqlite3_rebaser API 周围的注释。
可以通过将 支持的标志 的组合作为第九个参数传递来修改 sqlite3changeset_apply_v2() 及其流等效项的行为。
请注意,sqlite3changeset_apply_v2() API 仍处于实验阶段,因此可能会发生更改。