会话模块 C 接口

将变更集应用于数据库

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 */
);

将变更集或补丁集应用于数据库。这些函数尝试使用通过第二个和第三个参数传递的变更集中发现的变更来更新附加到 handle db 的“主”数据库。

传递给这些函数的第四个参数 (xFilter) 是“过滤器回调”。如果它不为 NULL,则对于受变更集中至少一个更改影响的每个表,将调用过滤器回调,并将表名作为第二个参数,并将上下文指针的副本作为第六个参数作为第一个参数传递。如果“过滤器回调”返回零,则不会尝试对表应用任何更改。否则,如果返回值非零或 xFilter 参数为 NULL,则尝试与表相关的所有更改。

对于过滤器回调未排除的每个表,此函数测试目标数据库是否包含兼容表。如果满足以下所有条件,则表被认为是兼容的:

如果没有兼容的表,这不是错误,但不会应用与该表关联的任何更改。通过 sqlite3_log() 机制发出警告消息,错误代码为 SQLITE_SCHEMA。最多为变更集中的每个表发出一个这样的警告。

对于有兼容表的每个更改,都会尝试根据 UPDATE、INSERT 或 DELETE 更改修改表内容。如果不能干净地应用更改,则可以调用作为第五个参数传递给 sqlite3changeset_apply() 的冲突处理函数。下面描述了何时为每种类型的更改调用冲突处理程序的确切时间。

与 xFilter 参数不同,xConflict 不能传递 NULL。将有效函数指针以外的任何内容作为 xConflict 参数传递的结果是未定义的。

每次调用冲突处理程序函数时,它必须返回SQLITE_CHANGESET_OMITSQLITE_CHANGESET_ABORTSQLITE_CHANGESET_REPLACE之一。如果传递给冲突处理程序的第二个参数是 SQLITE_CHANGESET_DATA 或 SQLITE_CHANGESET_CONFLICT,则只能返回 SQLITE_CHANGESET_REPLACE。如果冲突处理程序返回非法值,则已进行的任何更改都将回滚并且对 sqlite3changeset_apply() 的调用返回 SQLITE_MISUSE。sqlite3changeset_apply() 根据每次调用冲突处理程序函数返回的值采取不同的操作。有关详细信息,请参阅有关三个 可用返回值的文档。

DELETE Changes
对于每个 DELETE 更改,该函数检查目标数据库是否包含与存储在变更集中的原始行值具有相同主键值(或多个值)的行。如果是,并且存储在所有非主键列中的值也与存储在变更集中的值相匹配,则该行将从目标数据库中删除。

如果找到具有匹配主键值的行,但一个或多个非主键字段包含与存储在变更集中的原始行值不同的值,则使用SQLITE_CHANGESET_DATA作为第二个参数调用冲突处理函数。如果数据库表的列多于变更集中记录的列,则仅将那些非主键字段的值与当前数据库内容进行比较——忽略任何尾随的数据库表列。

如果在数据库中找不到具有匹配主键值的行,则调用冲突处理函数,并将SQLITE_CHANGESET_NOTFOUND 作为第二个参数传递。

如果尝试执行 DELETE 操作,但 SQLite 返回 SQLITE_CONSTRAINT(只有在违反外键约束时才会发生),将调用冲突处理函数,并将SQLITE_CHANGESET_CONSTRAINT 作为第二个参数传递。这包括尝试 DELETE 操作的情况,因为之前对冲突处理函数的调用返回了SQLITE_CHANGESET_REPLACE

INSERT Changes
对于每个 INSERT 更改,都会尝试将新行插入数据库。如果变更集行包含的字段少于数据库表,则尾随字段将使用它们的默认值填充。

如果因为数据库已经包含具有相同主键值的行而尝试插入行失败,则调用冲突处理函数并将第二个参数设置为 SQLITE_CHANGESET_CONFLICT

如果由于某些其他约束违规(例如 NOT NULL 或 UNIQUE)而导致插入行的尝试失败,则调用冲突处理程序函数并将第二个参数设置为SQLITE_CHANGESET_CONSTRAINT这包括重新尝试 INSERT 操作的情况,因为之前对冲突处理函数的调用返回了 SQLITE_CHANGESET_REPLACE

UPDATE Changes
对于每个 UPDATE 更改,该函数检查目标数据库是否包含与存储在变更集中的原始行值具有相同主键值(或多个值)的行。如果是,并且存储在所有修改后的非主键列中的值也与存储在变更集中的值相匹配,则在目标数据库中更新该行。

如果找到具有匹配主键值的行,但一个或多个修改后的非主键字段包含与存储在变更集中的原始行值不同的值,则使用SQLITE_CHANGESET_DATA作为第二个参数调用冲突处理函数. 由于 UPDATE 更改仅包含要修改的非主键字段的值,因此只有那些字段需要与原始值匹配以避免 SQLITE_CHANGESET_DATA 冲突处理程序回调。

如果在数据库中找不到具有匹配主键值的行,则调用冲突处理函数,并将SQLITE_CHANGESET_NOTFOUND 作为第二个参数传递。

如果尝试执行 UPDATE 操作,但 SQLite 返回 SQLITE_CONSTRAINT,则会调用冲突处理函数,并将 SQLITE_CHANGESET_CONSTRAINT作为第二个参数传递。这包括在先前调用冲突处理程序函数返回SQLITE_CHANGESET_REPLACE之后尝试更新操作的情况

从 xConflict 回调中执行 SQL 语句是安全的,包括那些写入与回调相关的表的语句。这可用于进一步自定义应用程序的冲突解决策略。

这些函数所做的所有更改都包含在保存点事务中。如果发生任何其他错误(尝试写入目标数据库时约束失败除外),则回滚保存点事务,将目标数据库恢复到其原始状态,并返回 SQLite 错误代码。

如果输出参数 (ppRebase) 和 (pnRebase) 是非 NULL 并且输入是一个变更集(不是补丁集),那么 sqlite3changeset_apply_v2() 可以设置 (*ppRebase) 指向一个可以与sqlite3_rebaser APIs 在返回之前缓冲。在这种情况下,(*pnRebase) 被设置为以字节为单位的缓冲区大小。调用者有责任使用 sqlite3_free() 最终释放任何此类缓冲区。只有在应用补丁集时遇到一个或多个冲突时,才会分配和填充缓冲区。有关详细信息,请参阅围绕 sqlite3_rebaser API 的评论。

sqlite3changeset_apply_v2() 及其等效流的行为可以通过将 支持的标志组合作为第 9 个参数传递来修改。

请注意,sqlite3changeset_apply_v2() API 仍处于实验阶段 ,因此可能会发生变化。

另请参阅 对象常量函数的列表。