int sqlite3changeset_apply_strm( sqlite3 *db, /* Apply change to "main" db of this handle */ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ void *pIn, /* First arg for xInput */ 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_strm( sqlite3 *db, /* Apply change to "main" db of this handle */ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ void *pIn, /* First arg for xInput */ 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, int flags ); int sqlite3changeset_concat_strm( int (*xInputA)(void *pIn, void *pData, int *pnData), void *pInA, int (*xInputB)(void *pIn, void *pData, int *pnData), void *pInB, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); int sqlite3changeset_invert_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); int sqlite3changeset_start_strm( sqlite3_changeset_iter **pp, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); int sqlite3changeset_start_v2_strm( sqlite3_changeset_iter **pp, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int flags ); int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); int sqlite3session_patchset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); int sqlite3changegroup_add_strm(sqlite3_changegroup*, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); int sqlite3changegroup_output_strm(sqlite3_changegroup*, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); int sqlite3rebaser_rebase_strm( sqlite3_rebaser *pRebaser, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut );
六个流式 API xxx_strm() 函数的功能与相应的非流式 API 函数类似。
流式函数 | 非流式等效项 |
---|---|
sqlite3changeset_apply_strm | sqlite3changeset_apply |
sqlite3changeset_apply_strm_v2 | sqlite3changeset_apply_v2 |
sqlite3changeset_concat_strm | sqlite3changeset_concat |
sqlite3changeset_invert_strm | sqlite3changeset_invert |
sqlite3changeset_start_strm | sqlite3changeset_start |
sqlite3session_changeset_strm | sqlite3session_changeset |
sqlite3session_patchset_strm | sqlite3session_patchset |
接受 changeset(或 patchset)作为输入的非流式函数要求整个 changeset 存储在内存中的单个缓冲区中。类似地,那些返回 changeset 或 patchset 的函数通过返回指向使用 sqlite3_malloc() 分配的单个大型缓冲区的指针来实现。通常这很方便。但是,如果在低内存环境中运行的应用程序需要处理非常大的 changeset,则所需的大型连续内存分配可能会变得繁重。
为了避免此问题,流式 API 函数的输入不是通过单个大型缓冲区,而是通过回调函数传递,会话模块调用该回调函数以根据需要增量请求输入数据。在所有情况下,一对 API 函数参数(如
int nChangeset, void *pChangeset,
被替换为
int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn,
每次会话模块调用 xInput 回调时,传递的第一个参数都是提供的 pIn 上下文指针的副本。第二个参数 pData 指向大小为 (*pnData) 字节的缓冲区。假设没有发生错误,xInput 方法应将最多 (*pnData) 字节的数据复制到缓冲区中,并在返回 SQLITE_OK 之前将 (*pnData) 设置为实际复制的字节数。如果输入已完全耗尽,则应将 (*pnData) 设置为零以指示这一点。或者,如果发生错误,则应返回 SQLite 错误代码。在所有情况下,如果 xInput 回调返回错误,则所有处理都将被放弃,并且流式 API 函数会将错误代码的副本返回给调用方。
对于 sqlite3changeset_start_strm(),会话模块可以在迭代器生命周期的任何时间点调用 xInput 回调。如果此类 xInput 回调返回错误,则迭代器进入错误状态,从而所有后续对迭代器函数的调用都会立即失败,并返回与 xInput 返回的相同的错误代码。
类似地,返回 changeset(或 patchset)的流式 API 函数通过回调函数而不是通过指向单个大型缓冲区的指针来分块返回它们。在这种情况下,一对参数(如
int *pnChangeset, void **ppChangeset,
被替换为
int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut
xOutput 回调被调用零次或多次以将数据返回给应用程序。传递给每个调用的第一个参数都是应用程序提供的 pOut 指针的副本。第二个参数 pData 指向大小为 nData 字节的缓冲区,其中包含正在返回的输出数据块。如果 xOutput 回调成功处理了提供的数据,则应返回 SQLITE_OK 以指示成功。否则,它应返回其他一些 SQLite 错误代码。在这种情况下,处理将立即被放弃,并且流式 API 函数会将 xOutput 错误代码的副本返回给应用程序。
会话模块永远不会以第三个参数设置为小于或等于零的值来调用 xOutput 回调。除此之外,不保证返回的数据块的大小。