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) байт данных в буфер и установить (*pnData) в фактическое число байтов, скопированных прежде, чем возвратить SQLITE_OK. Если вход полностью исчерпан, (*pnData) должен быть установлен в 0, чтобы указать на это. Или, если ошибка происходит, код ошибки SQLite должен быть возвращен. Во всех случаях, если отзыв xInput возвращает ошибку, оставлена вся обработка, и функция потокового API возвращает копию кода ошибки.
В случае sqlite3changeset_start_strm() отзыв xInput может быть вызван модулем сессий в любом пункте в течение жизни iterator. Если отзыв xInput возвращает ошибку, iterator входит в состояние ошибки, посредством чего все последующие обращения к функциям iterator немедленно терпят неудачу с тем же самым кодом ошибки, как возвращено xInput.
Точно так же функции потокового API, которые возвращают changeset (или patchset) возвращают их в кусках посредством функции обратного вызова вместо указателя на единственный большой буфер. В этом случае пара параметров, таких как:
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 с третьим параметром, установленным в значения 0 или меньше. Кроме этого, никакие гарантии не сделаны относительно размера кусков возвращенных данных.