RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

Small. Fast. Reliable.
Choose any three.

Интерфейс C/C++ модуля сессии SQLite

Эта страница определяет интерфейс языка C к SQLite расширению session. Это не обучающая программа. Эти страницы разработаны, чтобы быть точными. Обучающая программа доступна здесь.

Эта страница содержит всю информацию об интерфейсе языка C в единственном файле HTML. Та же самая информация также доступна маленькими порциями для более легкого просмотра

Этот документ создается скриптом, который сканирует комментарии в файле исходного кода sqlite3session.h.


Объекты:


Константы:


Функции:


Флаги для sqlite3changeset_start_v2

#define SQLITE_CHANGESETSTART_INVERT        0x0002

Следующие флаги могут быть переднаы через 4-й параметр sqlite3changeset_start_v2 и sqlite3changeset_start_v2_strm:

SQLITE_CHANGESETAPPLY_INVERT
Инвертируйте набор, повторяя через него. Это эквивалентно инвертированию changeset, используя sqlite3changeset_invert() прежде, чем применить его. Ошибка определить этот флаг с patchset.


Значения для sqlite3session_config().

#define SQLITE_SESSION_CONFIG_STRMSIZE 1

Обработчик Changegroup

typedef struct sqlite3_changegroup sqlite3_changegroup;

changegroup это объект, используемый, чтобы объединить два или больше changesets или patchsets.

Конструктор: sqlite3changegroup_new()

Деструктор: sqlite3changegroup_delete()

Методы: sqlite3changegroup_add(), sqlite3changegroup_output()


Обработчик Changeset Iterator

typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;

Экземпляр этого объекта действует как курсор для повторения по элементам changeset или patchset.

Конструкторы: sqlite3changeset_start(), sqlite3changeset_start_v2()


Перебазирование changesets

typedef struct sqlite3_rebaser sqlite3_rebaser;

Важно: Этот интерфейс экспериментален и подлежит изменению без уведомления.

Предположим, что есть место, принимающее базу данных в состоянии S0. Модификации сделаны, база данных перешла в состояние S1 и зарегистрирован changeset ("local" changeset). Затем changeset на основе S0 получается от другого места ("remote" changeset) и применяется к базе данных. База данных находится тогда в состоянии (S1+"remote"), где точное состояние зависит от любых решений разрешения конфликтов (OMIT или REPLACE) сделанных, применяя "remote". Перебазирование changeset должно обновить его, чтобы принять те решения разрешения конфликтов во внимание, так, чтобы те же самые конфликты не были решены в другом месте в сети.

Например, если местные и отдаленные changesets содержат INSERT того же самого ключа на "CREATE TABLE t1(a PRIMARY KEY, b)":

local: INSERT INTO t1 VALUES(1, 'v1'); remote: INSERT INTO t1 VALUES(1, 'v2');

и разрешение конфликтов REPLACE, тогда изменение INSERT удалено из местного changeset (это было отвергнуто). Или, если разрешением конфликтов был "OMIT", то местный changeset изменяется, чтобы вместо этого содержать:

UPDATE t1 SET b = 'v2' WHERE a=1;

Изменения в местном changeset перебазируются следующим образом:

Local INSERT
Это может только находиться в противоречии с отдаленным INSERT. Если разрешением конфликтов был OMIT, то добавьте, что UPDATE изменяется на перебазированный changeset. Или, если разрешением конфликтов был REPLACE, ничего не добавьте к перебазированному changeset.

Local DELETE
Это может находиться в противоречии с удаленным обновлением или DELETE. В обоих случаях единственная возможная резолюция это OMIT. Если удаленной операцией был DELETE, то не добавляйте изменение в changeset. Если удаленной операцией был UPDATE, то поля old.* изменения обновляются, чтобы отразить значения new.* в UPDATE.

Local UPDATE
Это может находиться в противоречии с удаленным обновлением или DELETE. Если это находится в противоречии с DELETE, и разрешением конфликтов был OMIT, то обновление изменяется в INSERT. Любые неопределенные значения в записи new.* от изменения обновления заполнены с применением значений old.* от противоречивого DELETE. Или, если разрешением конфликтов был REPLACE, изменение UPDATE просто опущено от changeset.

Если конфликт с удаленным обновлением, и резолюция OMIT, значения old.* перебазирующиеся, используя значения new.* в удаленном изменении. Или, если резолюция REPLACE, то изменение копируется в перебазированный changeset с обновлениями колонок, также обновленных противоречивым удаленным UPDATE. Если это означает, что никакие колонки не были бы обновлены, изменение пропущено.

Местное изменение может быть перебазирующимся против многократных отдаленных изменений одновременно. Если единственный ключ изменяется многократным отдаленным changeset, они объединены следующим образом, прежде чем местный changeset перебазируется:

  • Если были одна или более резолюций REPLACE по ключу, он перебазирующийся согласно REPLACE.

  • Если не было никаких резолюций REPLACE по ключу, то местный changeset перебазирующийся согласно новой резолюции OMIT.

Обратите внимание на то, что разрешения конфликтов от многократного отдаленного changeset объединены на основе поля, а не строки. Это означает, что в случае многократных операций по удаленному обновлению, некоторые области единственного местного изменения могут быть перебазирующимися для REPLACE, в то время как другие перебазирующиеся для OMIT.

Чтобы повторно основывать местный changeset, отдаленный changeset должен сначала быть применен к локальной базе данных, используя sqlite3changeset_apply_v2() и буфер захваченной информации. Тогда:

  1. Объект sqlite3_rebaser создается, вызывая sqlite3rebaser_create().
  2. Новый объект формируется с переосновным буфером, полученным из sqlite3changeset_apply_v2(), вызывая sqlite3rebaser_configure(). Если местный changeset должен быть перебазирующимся против многократного отдаленного changeset, sqlite3rebaser_configure() нужно вызвать многократно в том же самом порядке, в котором были сделаны многократные вызовы sqlite3changeset_apply_v2().
  3. Каждый местный changeset перебазируется вызовом sqlite3rebaser_rebase().
  4. Объект sqlite3_rebaser удален, вызывая sqlite3rebaser_delete().


Обработчик объекта Session

typedef struct sqlite3_session sqlite3_session;

Экземпляр этого объекта это session, который может использоваться, чтобы сделать запись изменений базы данных.

Конструктор: sqlite3session_create()

Деструктор: sqlite3session_delete()


Добавьте Changeset к Changegroup

int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);

Добавьте все изменения в changeset (или patchset) в буфере pData (размеом nData байт) к changegroup.

Если буфер содержит patchset, то все предшествующие обращения к этой функции на том же самом объекте changegroup, должно быть, также определили patchsets. Или, если буфер содержит changeset, должны быть более ранние обращения к этой функции. Иначе SQLITE_ERROR возвращен, и никакие изменения не добавляются к changegroup.

Строки в changeset и changegroup определяются значениями в их колонках PRIMARY KEY. Изменение в changeset, как полагают, относится к той же самой строке, как изменение, уже существующее в changegroup, если у этих двух строк есть тот же самый первичный ключ.

Изменения строк, которые уже не появляются в changegroup, просто копируются в него. Или, если новый changeset и changegroup содержат изменения, которые относятся к единственной строке, заключительное содержание changegroup зависит от типа каждого изменения, следующим образом:

Существующее изменение Новое изменение Изменение на выходе
INSERT INSERT Новое изменение проигнорировано. Этот случай не происходит, если новый changeset был немедленно зарегистрирован после changesets, уже добавленного к changegroup.
INSERT UPDATE Изменение INSERT остается в changegroup. Значения в изменении INSERT изменяются, как будто строка была вставлена существующим изменением и затем обновлена согласно новому изменению.
INSERT DELETE Существующий INSERT удален из changegroup. DELETE не добавляется.
UPDATE INSERT Новое изменение проигнорировано. Этот случай не происходит, если новый changeset был немедленно зарегистрирован после changeset, уже добавленного к changegroup.
UPDATE UPDATE Существующий UPDATE остается в changegroup. Это исправлено так, чтобы сопровождающие значения состояли в том, как будто строка была обновлена однажды существующим изменением, а затем еще и новым изменением.
UPDATE DELETE Существующий UPDATE заменяется новым DELETE в changegroup.
DELETE INSERT Если одно или больше значений столбцов в строке, вставленной новым изменением, отличаются от таких же в строке, удаленной существующим изменением, существующий DELETE заменяется UPDATE в changegroup. Иначе, если вставленная строка это точно то же самое как удаленная, от существующего DELETE просто отказываются.
DELETE UPDATE Новое изменение проигнорировано. Этот случай не происходит, если новый changeset был немедленно зарегистрирован после changeset, уже добавленного к changegroup.
DELETE DELETE Новое изменение проигнорировано. Этот случай не происходит, если новый changeset был немедленно зарегистрирован после changeset, добавленного к changegroup.

Если новый changeset содержит изменения, которые уже присутствуют в changegroup, то количество колонок и положение колонок первичного ключа для таблицы должны быть последовательными. Если дело обстоит не так, эта функция терпит неудачу с SQLITE_SCHEMA. Кроме того, если объект changegroup формировался со схемой базы данных, используя sqlite3changegroup_schema() API, возможно объединить changeset с различными числами колонок для единственной таблицы при условии, что они в других отношениях совместимы.

Во всех случаях, если ошибка происходит, статус заключительного содержания changegroup не определен. Если никакая ошибка не происходит, SQLITE_OK возвращен.

Если вход changeset, кажется, поврежден, SQLITE_CORRUPT возвращен. Или, если переполнение памяти происходит во время обработки, эта функция возвращает SQLITE_NOMEM.


Удалите объект Changegroup

void sqlite3changegroup_delete(sqlite3_changegroup*);

Создайте объект Changegroup

int sqlite3changegroup_new(sqlite3_changegroup **pp);

Объект sqlite3_changegroup используется, чтобы объединить два или больше changeset (или patchset) в единственный changeset (или patchset). Единственный объект changegroup может объединить changeset или patchset, но не обоих. Вывод всегда находится в том же самом формате как вход.

Если успешно, эта функция возвращает SQLITE_OK и наполняет (*pp) с указателем на новый объект sqlite3_changegroup перед возвращением. Вызывающий должен в конечном счете освободить возвращенный объект, используя sqlite3changegroup_delete(). Если ошибка происходит, код ошибки SQLite (то есть, SQLITE_NOMEM) возвращен и *pp = NULL.

Обычный образец использования для объекта sqlite3_changegroup следующий:

  • Это создается, используя sqlite3changegroup_new().

  • Ноль или больше changeset (или patchset) добавляются к объекту, вызывая sqlite3changegroup_add().

  • Результат объединения всего входа changeset вместе получен применением через sqlite3changegroup_output().

  • Объект удален, используя sqlite3changegroup_delete().

Любое количество add() и output() может быть сделано между обращениями к new() и delete() в любом порядке.

А также регулярные функции sqlite3changegroup_add() и sqlite3changegroup_output() являются текущими версиями sqlite3changegroup_add_strm() и sqlite3changegroup_output_strm().


Получите сложный Changeset из Changegroup

int sqlite3changegroup_output(
  sqlite3_changegroup*,
  int *pnData,                    /* OUT: Size of output buffer in bytes */
  void **ppData                   /* OUT: Pointer to output buffer */
);

Получите буфер, содержащий changeset (или patchset), представляющий текущее содержание changegroup. Если входы к changegroup были самостоятельно changeset, вывод это changeset. Или, если входы были patchsets, выводом будет также patchset.

Как с выводом sqlite3session_changeset() и sqlite3session_patchset(), все изменения, связанные с единственной таблицей, группируются в выводе этой функции. Таблицы появляются в том же самом порядке, как у самого первого changeset, добавленного к changegroup. Если вторые или последующие changeset, добавленные к changegroup, содержат изменения для таблиц, которые не появляются в первом changeset, они приложены в конце вывода changeset, снова в порядке, в котором с ними сначала сталкиваются.

Если ошибка происходит, код ошибки SQLite возвращен, и выходные переменные (*pnData) и (*ppData) установлены в 0. Иначе SQLITE_OK возвращен, и выходные переменные установлены в размер и указатель на буфер вывода, соответственно. В этом случае ответственность вызвавшего освободить буфер, используя sqlite3_free().


Добавьте схему к Changegroup

int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*,
                              const char *zDb);

Этот метод может использоваться, чтобы произвольно провести в жизнь правило, что changeset, добавленный к дескриптору changegroup, должен соответствовать схеме базы данных zDb ("main", "temp" или название приложенной базы данных). Если вызывают sqlite3changegroup_add(), чтобы добавить changeset, который несовместим с формируемой схемой, SQLITE_SCHEMA возвращен, и объект changegroup оставляют в неопределенном состоянии.

changeset схему считают совместимой со схемой базы данных таким же образом, что касается sqlite3changeset_apply(). Определенно, для каждой таблицы в changeset там существует таблица базы данных с:

  • Имя, определенное changeset
  • по крайней мере, столько же колонок, сколько зарегистрировано в changeset
  • колонки первичного ключа в том же самом положении, как зарегистрировано в changeset.

У вывода объекта changegroup всегда есть та же самая схема, как у базы данных при использовании этой функции. В случаях, где у changeset, переданных к sqlite3changegroup_add(), есть меньше колонок, чем у соответствующей таблицы в схеме базы данных, они заполнены с использованием значений столбцов по умолчанию из схемы базы данных. Это позволяет объединение changeset, у которых есть различные числа колонок для единственной таблицы в changegroup, при условии, что они в других отношениях совместимы.


Свяжите два объекта Changeset

int sqlite3changeset_concat(
  int nA,                         /* Number of bytes in buffer pA */
  void *pA,                       /* Pointer to buffer containing changeset A */
  int nB,                         /* Number of bytes in buffer pB */
  void *pB,                       /* Pointer to buffer containing changeset B */
  int *pnOut,                     /* OUT: Number of bytes in output changeset */
  void **ppOut                    /* OUT: Buffer containing output changeset */
);

Эта функция используется, чтобы связать два changeset A и B в единственный changeset. Результат это changeset, эквивалентный применению changeset A, сопровождаемого changeset B.

Эта функция объединяет два входных changeset с использованием объекта sqlite3_changegroup. Запрос его приводит к подобным результатам как к следующему кодовому фрагменту:

sqlite3_changegroup *pGrp;
rc = sqlite3_changegroup_new(&pGrp);
if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
if( rc==SQLITE_OK )
{
  rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
}
else
{
  *ppOut = 0;
  *pnOut = 0;
}

Обратитесь к документации на sqlite3_changegroup ниже для деталей.


Получите значения строк конфликтов из Changeset Iterator

int sqlite3changeset_conflict
(
  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
  int iVal,                       /* Column number */
  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
);

Эта функция должна использоваться только с объектами iterator, переданными к отзыву обработчика конфликта sqlite3changeset_apply() с SQLITE_CHANGESET_DATA или SQLITE_CHANGESET_CONFLICT. Если эта функция вызвана на каком-либо другом iterator, SQLITE_MISUSE возвращена и *ppValue установлен в NULL.

iVal должен быть больше или равным 0, но меньше, чем количество колонок в таблице, затронутой текущим изменением. Иначе вернется SQLITE_RANGE и *ppValue = NULL.

Если успешно, эта функция устанавливает указатель *ppValue на защищенный объект sqlite3_value, содержащий iVal-ое значение от "противоречивой строки", связанной с текущим отзывом дескриптора конфликта, и вернет SQLITE_OK.

Если некоторая другая ошибка происходит (например, условие OOM), код ошибки SQLite возвращен, и *ppValue установлен в NULL.


Завершите Changeset Iterator

int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);

Эта функция используется, чтобы завершить iterator, ассигнованный sqlite3changeset_start().

К этой функции нужно обратиться только в итераторах, созданных с использованием функции sqlite3changeset_start(). Если применение вызывает эту функцию с iterator, переданным обработчику конфликта sqlite3changeset_apply(), SQLITE_MISUSE немедленно возвращен, и вызов не имеет никакого эффекта.

Если с ошибкой столкнулись в рамках обращения к sqlite3changeset_xxx() (например, SQLITE_CORRUPT в sqlite3changeset_next() или SQLITE_NOMEM в sqlite3changeset_new()), код ошибки, соответствующий той ошибке, возвращен этой функцией. Иначе SQLITE_OK возвращен. Это должно позволить следующий образец (псевдокод):

sqlite3changeset_start();
while( SQLITE_ROW==sqlite3changeset_next() )
{
  // Do something with change.
}
rc = sqlite3changeset_finalize();
if( rc!=SQLITE_OK )
{
  // An error has occurred
}

Определите количество ограничительных нарушений внешнего ключа

int sqlite3changeset_fk_conflicts
(
  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
  int *pnOut                      /* OUT: Number of FK violations */
);

Эта функция может быть вызвана только с iterator, переданным к отзыву обработчика конфликта SQLITE_CHANGESET_FOREIGN_KEY. В этом случае это устанавливает выходную переменную в общее количество известных нарушений внешнего ключа в целевой базе данных и возвращает SQLITE_OK.

Во всех других случаях эта функция возвращает SQLITE_MISUSE.


Инвертируйте Changeset

int sqlite3changeset_invert
(
  int nIn, const void *pIn,       /* Input changeset */
  int *pnOut, void **ppOut        /* OUT: Inverse of input */
);

Эта функция используется, чтобы "инвертировать" объект changeset. Применение перевернутого changeset к базе данных полностью изменяет эффекты применения неперевернутого changeset. Определенно:

  • Каждое изменение DELETE изменяется на INSERT
  • Каждое изменение INSERT изменяется на DELETE
  • Для каждого изменения UPDATE значения old.* и new.* обменены.

Эта функция не изменяет порядок, в котором изменения появляются в changeset. Это просто полностью изменяет смысл каждого отдельного изменения.

Если успешно, указатель на буфер, содержащий перевернутый changeset, сохранен в *ppOut, размер того буфера сохранен в *pnOut, и SQLITE_OK возвращен. Если ошибка происходит, *pnOut и *ppOut обнулены и возвращен код ошибки SQLite.

Обязанность вызвавшего в конечном счете вызвать sqlite3_free() для указателя *ppOut, чтобы освободить распределение буферов после успешного вызова этой функции.

WARNING/TODO: Эта функция в настоящее время предполагает, что вход это действительный changeset. Если это не так, результаты не определены.


Получите значения new.* из Changeset Iterator

int sqlite3changeset_new
(
  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
  int iVal,                       /* Column number */
  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
);

pIter аргументом, переданным к этой функции, может быть iterator, переданный обработчику конфликта sqlite3changeset_apply(), или итератор, созданный sqlite3changeset_start(). В последнем случае новое обращение к sqlite3changeset_next() должно быть, возвратило SQLITE_ROW. Кроме того, это можно вызвать только если тип изменения, на которое в настоящее время указывает iterator, является SQLITE_UPDATE или SQLITE_INSERT. Иначе эта функция возвращает SQLITE_MISUSE и *ppValue = NULL.

Аргумент iVal должен быть больше или равным 0, но меньше, чем количество колонок в таблице, затронутой текущим изменением. Иначе SQLITE_RANGE возвращен, и *ppValue установлен в NULL.

Если успешно, эта функция устанавливает указатель *ppValue на защищенный объект sqlite3_value, содержащий значение iVal от вектора новых значений строки, сохраненных как часть изменения UPDATE или INSERT и вернет SQLITE_OK. Если изменение UPDATE и не включает новое значение для требуемой колонки, *ppValue установлен в NULL и возвращен SQLITE_OK. Название функции происходит от того, что это подобно колонке "new.*", доступной, чтобы обновить или удалить триггеры.

Если некоторая другая ошибка происходит (например, условие OOM), код ошибки SQLite возвращен, и *ppValue установлен в NULL.


Продвиньте Changeset Iterator

int sqlite3changeset_next(sqlite3_changeset_iter *pIter);

Эта функция может использоваться только с итератором, созданным функцией sqlite3changeset_start(). Если это вызывают на iterator, переданном к отзыву дескриптора конфликта sqlite3changeset_apply(), SQLITE_MISUSE SQLITE_MISUSE возвращен, и вызов не имеет никакого эффекта.

Немедленно после того, как iterator создается sqlite3changeset_start(), это не указывает ни на какое изменение в changeset. Считая changeset не пустым, первое обращение к этой функции продвигает iterator, чтобы указать на первое изменение в changeset. Каждое последующее обращение продвигает iterator, чтобы указать на следующее изменение в changeset (если таковые имеются). Если никакая ошибка не происходит, и iterator указывает на действительное изменение после того, как обращение к sqlite3changeset_next() продвинуло его, SQLITE_ROW возвращен. Иначе, если все изменения в changeset уже отработаны, SQLITE_DONE возвращен.

Если ошибка происходит, код ошибки SQLite возвращен. Возможные коды ошибок включают SQLITE_CORRUPT (если буфер changeset поврежден) или SQLITE_NOMEM.


Получите значения old.* из Changeset Iterator

int sqlite3changeset_old
(
  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
  int iVal,                       /* Column number */
  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
);

Аргументом pIter, переданным к этой функции, может быть iterator, переданный обработчику конфликта sqlite3changeset_apply(), или iterator, созданный sqlite3changeset_start(). В последнем случае новое обращение к sqlite3changeset_next() должно возвратить SQLITE_ROW. Кроме того, это можно вызвать только, если тип изменения, на которое в настоящее время указывает iterator, является SQLITE_DELETE или SQLITE_UPDATE. Иначе эта функция возвращает SQLITE_MISUSE и ставит *ppValue = NULL.

iVal должен быть больше или равным 0, но меньше, чем количество колонок в таблице, затронутой текущим изменением. Иначе возвращен SQLITE_RANGE и *ppValue = NULL.

Если успешно, эта функция устанавливает указатель *ppValue на защищенный объект sqlite3_value, содержащий значение iVal от вектора первоначальных значений строки, сохраненных как часть изменения UPDATE или DELETE и вернет SQLITE_OK. Название функции происходит от того, что это подобно столбцам "old.*", доступным, чтобы обновить или удалить триггеры

Если некоторая другая ошибка происходит (например, условие OOM), код ошибки SQLite возвращен, и *ppValue установлен в NULL.


Получите текущую операцию из Changeset Iterator

int sqlite3changeset_op
(
  sqlite3_changeset_iter *pIter,  /* Iterator object */
  const char **pzTab,             /* OUT: Pointer to table name */
  int *pnCol,                     /* OUT: Number of columns in table */
  int *pOp,                       /* OUT: SQLITE_INSERT, DELETE or UPDATE */
  int *pbIndirect                 /* OUT: True for an 'indirect' change */
);

Аргументом pIter, переданным к этой функции, может быть iterator, переданный обработчику конфликта sqlite3changeset_apply(), или итератор, созданный sqlite3changeset_start(). В последнем случае новое обращение к sqlite3changeset_next() должно вернуть SQLITE_ROW. Если дело обстоит не так, эта функция возвращает SQLITE_MISUSE.

Аргументы pOp, pnCol и pzTab не могут быть NULL. По возвращению три вывода установлены через эти указатели:

*pOp установлен в один из SQLITE_INSERT, SQLITE_DELETE или SQLITE_UPDATE, в зависимости от типа изменения, на которое в настоящее время указывает iterator.

*pnCol установлен в количество колонок в таблице, затронутых изменением

*pzTab указывает на nul-законченную utf-8 последовательность, содержащую название таблицы, затронутой текущим изменением. Буфер остается действительным до вызова sqlite3changeset_next() на iterator или до возврата функции-обработчика конфликта.

Если pbIndirect не NULL, *pbIndirect = true (1), если изменение косвенное, или в false (0) иначе. См. документацию для sqlite3session_indirect() для описания прямых и косвенных изменений.

Если никакая ошибка не происходит, SQLITE_OK возвращен. Если ошибка происходит, код ошибки SQLite возвращен. Значениям выходных переменных нельзя доверять в этом случае.


Получите определение первичного ключа таблицы

int sqlite3changeset_pk
(
  sqlite3_changeset_iter *pIter,  /* Iterator object */
  unsigned char **pabPK,          /* OUT: Array of boolean - true for PK cols */
  int *pnCol                      /* OUT: Number of entries in output array */
);

Для каждой измененной таблицы changeset включает следующее:

  • Количество колонок в таблице
  • Какая из тех колонок составляет таблицы PRIMARY KEY

Эта функция используется, чтобы найти, какие колонки включают PRIMARY KEY таблицы, измененной тем изменением, на которое в настоящее время указывает iterator pIter. Если успешно, *pabPK укажет на множество записей nCol, где nCol это количество колонок в таблице. Элементы *pabPK установлены в 0x01, если соответствующая колонка это часть первичного ключа таблицы, иначе в 0x00.

Если pnCol не NULL, *pnCol установлен в количество колонок в таблице.

Если эта функция вызвана, когда iterator не указывает на действительный доступ, SQLITE_MISUSE возвращен, и выходные переменные обнулены. Иначе SQLITE_OK возвращен, и выходные переменные наполнены, как описано выше.


Модернизируйте схему Changeset/Patchset

int sqlite3changeset_upgrade(sqlite3 *db, const char *zDb,
  int nIn, const void *pIn,       /* Input changeset */
  int *pnOut, void **ppOut        /* OUT: Inverse of input */
);

Формируйте changeset rebaser объект

int sqlite3rebaser_configure(sqlite3_rebaser*, int nRebase,
                             const void *pRebase);

Важно: Этот интерфейс экспериментален и подлежит изменению без уведомления.

Формируйте объект changeset rebaser, чтобы повторно основывать changesets согласно разрешениям конфликтов, описанным буферной предварительной основой (размером nRebase байт), который был получен от предыдущего вызова sqlite3changeset_apply_v2().


Создайте объект changeset rebaser

int sqlite3rebaser_create(sqlite3_rebaser **ppNew);

Важно: Этот интерфейс экспериментален и подлежит изменению без уведомления.

Ассигнуйте новый объект changeset rebaser. Если успешно, установит (*ppNew), чтобы указать на новый объект и возвратит SQLITE_OK. Иначе, если ошибка происходит, возвратит код ошибки SQLite (например, SQLITE_NOMEM) и установит (*ppNew) в NULL.


Удалите объект changeset rebaser

void sqlite3rebaser_delete(sqlite3_rebaser *p);

Важно: Этот интерфейс экспериментален и подлежит изменению без уведомления.

Удалите объект changeset rebaser и все связанные ресурсы. Должно быть одно обращение к этой функции для каждого успешного вызова sqlite3rebaser_create().


Перебазируйте changeset

int sqlite3rebaser_rebase(sqlite3_rebaser*, int nIn, const void *pIn,
                          int *pnOut, void **ppOut);

Важно: Этот интерфейс экспериментален и подлежит изменению без уведомления.

Аргумент pIn должен указать на буфер, содержащий байты changeset размером nIn. Эта функция ассигнует и наполняет буфер копией changeset, перебазирующегося согласно конфигурации объекта rebaser, переданного как первый аргумент. Если успешно, (*ppOut) укажет на новый буфер, содержащий переоснованный changeset, (*pnOut) на его размер в байтах и возвратит SQLITE_OK. Ответственность вызывающего в конечном счете освободить новый буфер, используя sqlite3_free(). Иначе, если ошибка происходит, (*ppOut) и (*pnOut) установлены в ноль и возвращен код ошибки SQLite.


Присоединить таблицу к объекту сессии

int sqlite3session_attach
(
  sqlite3_session *pSession,      /* Session object */
  const char *zTab                /* Table name */
);

Если zTab не NULL, это название таблицы, чтобы присоединить к объекту сессии, переданному как первый аргумент. Будут зарегистрированы все последующие изменения, внесенные в таблицу в то время, как объект сессии позволен. См. документацию для sqlite3session_changeset().

Если zTab = NULL, изменения зарегистрированы для всех таблиц в базе данных. Если дополнительные таблицы добавляются к базе данных (выполняя "CREATE) после того, как этот вызов сделан, изменения для новых таблиц также зарегистрированы.

Изменения могут быть зарегистрированы только для таблиц, которым определили PRIMARY KEY явно как часть их CREATE TABLE. Не имеет значения, является ли PRIMARY KEY это "INTEGER PRIMARY KEY" (псевдоним rowid) или нет. PRIMARY KEY может состоять из отдельного столбца или может быть составным ключом.

Это не ошибка, если названная таблица не существует в базе данных. И при этом это не ошибка, если у названной таблицы нет PRIMARY KEY. Однако, никакие изменения не будут зарегистрированы ни в одном из этих сценариев.

Изменения не зарегистрированы для отдельных строк, которым сохранили NULL в одну или больше их колонок PRIMARY KEY.

SQLITE_OK возвращен, если обращение заканчивается без ошибки. Если ошибка происходит, код ошибки SQLite (например, SQLITE_NOMEM) возвращен.

Специальная обработка sqlite_stat1

С SQLite version 3.22.0 таблица "sqlite_stat1" это исключение из правил выше. В SQLite схема sqlite_stat1:

CREATE TABLE sqlite_stat1(tbl,idx,stat)

Даже при том, что у sqlite_stat1 нет PRIMARY KEY, изменения зарегистрированы, как будто PRIMARY KEY это (tbl,idx). Кроме того, изменения зарегистрированы для строк, для которых (idx IS NULL) верно. Однако, для таких строк blob нулевой длины (SQL value X'') сохранен в changeset или patchset вместо NULL. Это позволяет такому changesets управляться устаревшими внедрениями sqlite3changeset_invert(), concat() и подобными.

Функция sqlite3changeset_apply() автоматически преобразовывает blob нулевой длины назад в NULL, обновляя таблицу sqlite_stat1. Однако, если применение вызывает sqlite3changeset_new(), sqlite3changeset_old() или sqlite3changeset_conflict на итераторе changeset непосредственно (включая передачу changeset iterator отзыву обработчика конфликта), тогда возвращено значение X''. Применение должно перевести X'' к NULL при необходимости.

Старые (до 3.22.0) версии модуля сессий не могут захватить изменения, внесенные в таблицу sqlite_stat1. Старые версии функции sqlite3changeset_apply() тихо игнорируют любые модификации таблицы sqlite_stat1, которые являются частью changeset или patchset.


Произведите Changeset от объекта сессии

int sqlite3session_changeset
(
  sqlite3_session *pSession,      /* Session object */
  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
  void **ppChangeset              /* OUT: Buffer containing changeset */
);

Получите changeset, содержащий изменения таблиц, приложенных к объекту сессии, переданному как первый аргумент. Если успешно, установит *ppChangeset, чтобы указать на буфер, содержащий changeset, а *pnChangeset к размеру changeset в байтах прежде, чем возвратить SQLITE_OK. Если ошибка происходит, установит *ppChangeset и *pnChangeset в 0 и возвращает код ошибки SQLite.

changeset состоит из ноля или большего количества изменений INSERT, UPDATE и/или DELETE, каждый представляющий изменение единственной строки приложенной таблицы. Изменение INSERT содержит значения каждой области новой строки базы данных. DELETE содержит исходные значения каждой области удаленной строки базы данных. Изменение UPDATE содержит исходные значения каждой области обновленной строки базы данных с обновленными значениями для каждой обновленной колонки непервичного ключа. Для изменения UPDATE невозможно представлять изменение, которое изменяет значения колонок первичного ключа. Если такое изменение внесено, оно представляется в changeset как DELETE, сопровождаемый INSERT.

Изменения не зарегистрированы для строк, которым сохранили NULL в одну или больше их колонок PRIMARY KEY. Если такая строка вставлена или удалена, никакое соответствующее изменение не присутствует в changeset, возвращенном этой функцией. Если существующая строка с одним или более NULL, сохраненными в колонках PRIMARY KEY, обновляется так, чтобы всеми колонками PRIMARY KEY был не-NULL, только INSERT, появляется в changeset. Точно так же, если существующая строка со значениями не-NULL, PRIMARY KEY, обновляется так, чтобы одна или больше колонок PRIMARY KEY были установлены в NULL, получающийся changeset содержит только изменение DELETE.

Содержание changeset может быть пересечено, используя iterator, созданный использованием sqlite3changeset_start() API. changeset может быть применен к базе данных с совместимой схемой, используя sqlite3changeset_apply() API.

В changeset, произведенном этой функцией, группируются все изменения, связанные с единственной таблицей. Другими словами, повторяя через changeset или применяя changeset к базе данных, все изменения, связанные с единственной таблицей, обрабатываются перед прохождением дальше к следующей таблице. Таблицы приведены в порядок в том же самом порядке, в котором они были приложены к объекту. Порядок, в котором, сохранены изменения, связанные с единственной таблицей, не определен.

После успешного вызова этой функции, ответственность вызывающего в конечном счете освобождить буфер, который указывает на *ppChangeset, использованием sqlite3_free().

Создание Changeset

Как только таблица добавлена к объекту сессии, объект сессии пишет значения первичного ключа всех новых строк, вставленных в таблицу. Это также делает запись оригинального первичного ключа и других значений столбцов любых удаленных или обновленных строк. Для каждого уникального значения первичного ключа данные зарегистрированы только однажды, в первый раз, когда строка с первичным ключом вставлена, обновлена или удалена в жизни сессии.

Есть одно исключение к предыдущему параграфу: когда строка вставляется, обновляется или удаляется, если одна или больше его колонок первичного ключа содержат NULL, никакой отчет изменения не сделан.

Объект сессии поэтому накапливает два типа отчетов: которые состоят только из значений первичного ключа (созданы, когда пользователь вставляет новую запись) и те, которые состоят из значений первичного ключа и исходных значений других столбцов таблицы (созданы, когда пользователи удаляют или обновляют записи).

Когда эта функция вызвана, требуемый changeset создается, используя накопленные отчеты и текущее содержание файла базы данных. Определенно:

  • Для каждого отчета, произведенного вставкой, база данных запрашивается для строки с соответствующим первичным ключом. Если она найдена, изменение INSERT добавляется к changeset. Если никакая такая строка не найдена, никакое изменение не добавляется к changeset.

  • Для каждого отчета, произведенного обновлением или удалением, база данных запрашивается для строки с соответствующим первичным ключом. Если такая есть, и одна или больше областей непервичного ключа было изменено от их исходных значений, изменение UPDATE добавляется к changeset. Или, если никакой такой строки не найдена в таблице, изменение DELETE добавляется к changeset. Если есть строка с соответствующим первичным ключом в базе данных, но все области содержат свои исходные значения, никакое изменение не добавляется к changeset.

Это означает среди других вещей, что, если строка вставлена и затем позже удалена, в то время как объект сессии активен, ни вставка, ни удаление не будут присутствовать в changeset. Или если строка будет удален и затем позже строка с теми же самыми значениями первичного ключа вставлена в то время, как объект сессии активен, получающийся changeset будет содержать изменение UPDATE вместо DELETE и INSERT.

Когда объект сессии отключен (см. sqlite3session_enable() API), это не накапливает отчеты, когда строки вставлены, обновлены или удалены. Это, может казаться, имеет некоторые парадоксальные эффекты, если единственная строка написана несколько раз во время сессии. Например, если она будет вставлена в то время, как объект сессии позволен, затем позже удалена в то время, как тот же самый объект сессии отключен, никакой отчет INSERT не появится в changeset, даже при том, что удаление произошло в то время, как сессия была отключена. Или если одна область строки будет обновлена в то время, как сессия отключена, а другая область той же самой строки обновляется в то время, как сессия позволена, получающийся changeset будет содержать изменение UPDATE, которое обновляет обе области.


Возвратите верхний предел для размера Changeset

sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession);

По умолчанию эта функция всегда возвращает 0. Чтобы возвратить полезный результат, объект sqlite3_session должен быть настроен, чтобы позволить этот API, используя sqlite3session_object_config() с SQLITE_SESSION_OBJCONFIG_SIZE.

Когда позволено, эта функция возвращает верхний предел, в байтах, для размера changeset, который мог бы быть произведен, если бы вызвали sqlite3session_changeset(). Финальный размер changeset мог бы быть равным или меньшим, чем размер в байтах, возвращенных этой функцией.


Формируйте глобальные параметры

int sqlite3session_config(int op, void *pArg);

sqlite3session_config() используется, чтобы сделать глобальные изменения конфигурации модуля сессий, чтобы настроить его на определенные потребности применения.

sqlite3session_config() не ориентирован на многопотоковое исполнение. Если это вызвано в то время, как любой другой поток работает в любом другом методе сессий, результаты не определены. Кроме того, если это вызвано после того, как любыми сессиями объекты были созданы, результаты также не определены.

Первым аргументом функции sqlite3session_config() должна быть одна из констант SQLITE_SESSION_CONFIG_XXX, определенных ниже. Интерпретация (void*), переданного как второй параметр, и эффект вызова этой функции зависят от значения первого параметра.

SQLITE_SESSION_CONFIG_STRMSIZE
По умолчанию интерфейсы вытекания модуля сессий пытаются делить данные ввода и вывода на куски приблизительно по 1 кибибит. Этот операнд может использоваться, чтобы установить и запросить значение этого параметра конфигурации. Указатель, переданный как второй аргумент, должен указать на значение типа (int). Если это значение больше 0, оно используется в качестве нового текущего размера куска данных для ввода и вывода. Перед возвращением значение (int), на которое указывает pArg, установлено к окончательному значению текущего интерфейсного размера куска.

Эта функция возвращает SQLITE_OK в случае успеха или код ошибки SQLite иначе.


Создайте новый объект сессии

int sqlite3session_create
(
  sqlite3 *db,                    /* Database handle */
  const char *zDb,                /* Name of db (e.g. "main") */
  sqlite3_session **ppSession     /* OUT: New session object */
);

Создайте новый объект сессии, приложенный к дескриптору базы данных db. Если успешно, указатель на новый объект написан в *ppSession, и SQLITE_OK возвращен. Если ошибка происходит, *ppSession установлен в NULL, а код ошибки SQLite (например, SQLITE_NOMEM) возвращен.

Возможно создать многократные объекты сессии, приложенные к дескриптору единой базы данных.

Объекты сессии, созданные этой функцией, должны быть удалены, используя sqlite3session_delete() до закрытия обработчика базы данных, к которому они присоединены. Если обработчик базы данных закрывается прежде, чем объект сессии удален, то результаты вызова любой функции модуля сессии, включая sqlite3session_delete() на объекте сессии не определены.

Поскольку модуль сессии использует sqlite3_preupdate_hook() API, невозможно для запроса зарегистрировать перехватчик предварительного обновления базы данных, у которой есть один или несколько приложенных объектов сессии. И при этом невозможно создать объект сессии, приложенный к дескриптору базы данных, для которой уже определяется перехватчик перед обновлением. Результаты попытки любой из этих вещей не определены.

Объект сессии будет использоваться, чтобы создать changesets для таблиц в базе данных zDb, где zDb "main", "temp", или название приложенной базы данных. Это не ошибка, если база данных zDb не присоединена к базе данных, когда объект сессии создается.


Удалите объект сессии

void sqlite3session_delete(sqlite3_session *pSession);

Удалите объект сессии ранее ассигнованный использованием sqlite3session_create(). Как только объект сессии был удален, результаты попытки использовать pSession с любой другой функцией модуля сессии не определены.

Объекты сессии должны быть удалены, прежде чем обработчик базы данных, к которой они приложены, закрывается. Обратитесь к документации для sqlite3session_create().


Загрузите различие между таблицами в сессию

int sqlite3session_diff(sqlite3_session *pSession, const char *zFromDb,
                        const char *zTbl, char **pzErrMsg);

Если это еще не присоединено к объекту сессии, переданному как первый аргумент, эта функция прилагает таблицу zTbl таким же образом, как функция sqlite3session_attach(). Если zTbl не существует или если у нее нет первичного ключа, эта функция не делает (но не возвращает ошибку).

zFromDb должно быть название базы данных ("main", "temp", ...) приложенной к тому же самому дескриптору базы данных как объект сессии, который содержит таблицу, совместимую с таблицей, приложенной к сессии этой функцией. Таблицу считают совместимой, если:

  • Имеет то же самое имя
  • Имеет тот же самый набор колонок, объявленных в том же самом порядке
  • Имеет то же самое определение PRIMARY KEY

Если таблицы не совместимы, SQLITE_SCHEMA возвращен. Если таблицы совместимы, но не имеют никаких колонок PRIMARY KEY, это не ошибка, но никакие изменения не добавляются к объекту сессии. Как с другой сессией API, просто проигнорированы таблицы без PRIMARY KEY.

Эта функция добавляет ряд изменений объекта сессии, который мог использоваться, чтобы обновить таблицу в базе данных zFrom (назовите это "from-table") так, чтобы ее содержание совпало с таблицей, приложенной к объекту сессии (назовите это "to-table"):

  • Для каждой строки (первичный ключ), которая существует в to-table, но не в from-table, запись INSERT добавляется к объекту сессии.

  • Для каждой строки (первичный ключ), которая есть в to-table, но не в from-table, запись DELETE добавляется к объекту сессии.

  • Для каждой строки (первичный ключ), которая существует в обоих таблицых, но показывает различные значения non-PK, запись UPDATE добавляется к сессии.

Если эта функция вызвана и затем changeset построен с использованием sqlite3session_changeset(), то после применения этого changeset к базе данных zFrom содержание двух совместимых таблиц будет идентичным.

Это ошибка, если база данных zFrom не существует или не содержит необходимую совместимую таблицу.

Если операция успешна, SQLITE_OK возвращен. Иначе вернется код ошибки SQLite. В этом случае, если аргументом pzErrMsg не является NULL, *pzErrMsg может указать на буфер, содержащий английское языковое сообщение об ошибке. Обязанность вызывающего освободить этот буфер, используя sqlite3_free().


Позвольте или отключите объект сессии

int sqlite3session_enable(sqlite3_session *pSession, int bEnable);

Позвольте или отключите запись изменений объектом сессии. Когда позволено, объект сессии пишет изменения, внесенные в базу данных. Когда отключено, он это не делает. Созданный объект сессии изначально позволен. Обратитесь к документации на sqlite3session_changeset() для получения дальнейшей информации относительно того, как включение объекта сессии затрагивает возможный changeset.

Передача 0 к этой функции отключает сессию. Передача значения больше, чем ноль, включает. Передача значения меньше, чем ноль не делает ничего, но может использоваться, чтобы запросить текущее состояние сессии.

Возвращаемое значение указывает на конечное состояние объекта сессии: 0, если сессия отключена, или 1, если она позволена.


Переключите косвенный флаг изменения

int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);

Каждое изменение, зарегистрированное объектом сессии, отмечено как прямое или косвенное. Изменение отмечено как косвенное, если:

  • Флаг "indirect" объекта сессии установлен, когда изменение внесено
  • Изменение внесено триггером SQL или действием внешнего ключа вместо непосредственно в результате пользовательского SQL-оператора.

Если единственная строка затронута больше, чем одной операцией в сессии, то изменение считают косвенным, если все операции соответствуют критериям для косвенного изменения выше, или прямым иначе.

Эта функция используется, чтобы установить, очистить или запросить косвенный флаг объекта сессии. Если вторым аргументом, переданным к этой функции, является ноль, то косвенный флаг очищен. Если это больше, чем ноль, косвенный флаг установлен. Передача значение меньше, чем ноль, не изменяет текущее значение косвенного флага и может использоваться, чтобы запросить текущее состояние косвенного флага для указанного объекта сессии.

Возвращаемое значение указывает на конечное состояние косвенного флага: 0, если сброшено, или 1, если установлено.


Тест, сделал ли changeset запись каких-либо изменений

int sqlite3session_isempty(sqlite3_session *pSession);

Возвратит не 0, если никакие изменения приложенных таблиц не были зарегистрированы объектом сессии, переданным как первый аргумент. Иначе, если одно или более изменений были зарегистрированы, возвратит ноль.

Даже если эта функция возвращает ноль, возможно, что запрос sqlite3session_changeset() на дескрипторе сессии может все еще возвратить changeset, который не содержит изменений. Это может произойти, когда строка в таблице изменяется, и затем позже исходные значения восстановлены. Однако, если эта функция вернет не 0, то гарантируется, что обращение к sqlite3session_changeset() возвратит changeset, содержащий нулевые изменения.


Сколько памяти кучи используется объектом сессии

sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession);

Этот API возвращает общую сумму памяти кучи в байтах, в настоящее время используемых объектом сессии, переданным как единственный аргумент.


Формируйте объект сессии

int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);

Этот метод используется, чтобы формировать объект сессии после того, как он был создан. В настоящее время единственные действительные значения для второго параметра: SQLITE_SESSION_OBJCONFIG_SIZE и SQLITE_SESSION_OBJCONFIG_ROWID.


Произведите Patchset от объекта сессии

int sqlite3session_patchset
(
  sqlite3_session *pSession,      /* Session object */
  int *pnPatchset,                /* OUT: Size of buffer at *ppPatchset */
  void **ppPatchset               /* OUT: Buffer containing patchset */
);

Различия между patchset и changeset в том, что:

  • Записи DELETE состоят только из областей первичного ключа. Исходные значения других областей опущены.
  • Исходные значения любых измененных областей опущены из записей UPDATE.

patchset blob может использоваться с актуальными версиями всех функций sqlite3changeset_xxx API кроме sqlite3changeset_invert(), которая вернет SQLITE_CORRUPT. Точно так же попытка использовать patchset blob со старыми версиями sqlite3changeset_xxx API также вызывает ошибку SQLITE_CORRUPT.

Поскольку поля "old.*" непервичного ключа опущены, никакие конфликты SQLITE_CHANGESET_DATA нельзя обнаружить или сообщить, если patchset передается к sqlite3changeset_apply() API. Другой конфликт работает таким же образом, как с changeset.

Изменения в patchset упорядочены таким же образом, как в changeset, произведенном sqlite3session_changeset() (то есть, все изменения для единственной таблицы группируются, таблицы появляются в порядке, в котором они были присоединены к объекту сессии).


Установите фильтр таблицы на объекте сессии

void sqlite3session_table_filter
(
  sqlite3_session *pSession,      /* Session object */
  int(*xFilter)
  (
    void *pCtx,                   /* Copy of third arg to _filter_table() */
    const char *zTab              /* Table name */
  ),
  void *pCtx                      /* First argument passed to xFilter */
);

Вторым аргументом (xFilter) является "отзыв фильтра". Для изменений строк в таблицах, которые не присоединены к объекту сессии, фильтр вызывают, чтобы определить, должны ли изменения строк таблицы быть прослежены или нет. Если xFilter возвращает 0, изменения не прослежены. Обратите внимание на то, что, как только таблица добавлена, xFilter больше не вызовут.


Флаги для sqlite3changeset_apply_v2

#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT   0x0001
#define SQLITE_CHANGESETAPPLY_INVERT        0x0002
#define SQLITE_CHANGESETAPPLY_IGNORENOOP    0x0004
#define SQLITE_CHANGESETAPPLY_FKNOACTION    0x0008

Следующие флаги могут передаваться через 9-й параметр sqlite3changeset_apply_v2 и sqlite3changeset_apply_v2_strm:

SQLITE_CHANGESETAPPLY_NOSAVEPOINT
Обычно, модуль сессий прилагает все операции, выполненные единственным обращением к apply_v2() или apply_v2_strm(), в SAVEPOINT. SAVEPOINT передается, если changeset или patchset успешно применены или отменены, если ошибка происходит. Определение этого флага заставляет модуль сессий опускать эту точку сохранения. В этом случае, если у вызывающего есть открытая транзакция или точка сохранения, когда вызвана apply_v2(), это может вернуть частично примененный changeset, отменив его.

SQLITE_CHANGESETAPPLY_INVERT
Инвертируйте changeset прежде, чем применить его. Это эквивалентно инвертированию changeset, используя sqlite3changeset_invert() прежде, чем применить его. Ошибка определить этот флаг с patchset.

SQLITE_CHANGESETAPPLY_IGNORENOOP
Не вызывайте отзыв обработчика конфликта ни для каких изменений, которые на самом деле не изменили бы базу данных, даже если бы они были применены. Это означает, что обработчик конфликта не вызван для:
  • удаления, если удаляемая строка не может быть найдена
  • изменения обновления, если измененные области уже установлены в их новые значения в противоречивой строке
  • изменения вставки, если все области противоречивой строки соответствуют вставляемой строке

SQLITE_CHANGESETAPPLY_FKNOACTION
Если этот флаг задан, все ограничения внешнего ключа в целевой базе данных ведут себя, как будто они были объявлены с "ON UPDATE NO ACTION ON DELETE NO ACTION", даже если они на самом деле CASCADE, RESTRICT, SET NULL или SET DEFAULT.


Константы, возвращенные обработчиком конфликта

#define SQLITE_CHANGESET_OMIT       0
#define SQLITE_CHANGESET_REPLACE    1
#define SQLITE_CHANGESET_ABORT      2

Отзыв обработчика конфликта должен возвратить одно из следующих трех значений.

SQLITE_CHANGESET_OMIT
Если обработчик конфликта возвращает это значение, никакие специальные меры не приняты. Изменение, которое вызвало конфликт, не применяется. Модуль сессии переходит к следующему изменению в changeset.

SQLITE_CHANGESET_REPLACE
Это значение может быть возвращено только если вторым аргументом обработчику конфликта был SQLITE_CHANGESET_DATA или SQLITE_CHANGESET_CONFLICT. Если дело обстоит не так, какие-либо изменения, примененные до сих пор, отменены, и обращение к sqlite3changeset_apply() вернет SQLITE_MISUSE.

Если CHANGESET_REPLACE возвращен обработчиком конфликта SQLITE_CHANGESET_DATA, противоречивая строка обновлена или удалена, в зависимости от типа изменения.

Если CHANGESET_REPLACE возвращен обработчиком конфликта SQLITE_CHANGESET_CONFLICT, то противоречивая строка удален из базы данных, и предпринята вторая попытка применить изменение. Если эта вторая попытка терпит неудачу, оригинальная строка вернется базе данных перед продолжением.

SQLITE_CHANGESET_ABORT
Если это значение возвращено, любые изменения, примененные до сих пор, отменены, и обращение к sqlite3changeset_apply() вернет SQLITE_ABORT.


Константы, переданные обработчику конфликта

#define SQLITE_CHANGESET_DATA        1
#define SQLITE_CHANGESET_NOTFOUND    2
#define SQLITE_CHANGESET_CONFLICT    3
#define SQLITE_CHANGESET_CONSTRAINT  4
#define SQLITE_CHANGESET_FOREIGN_KEY 5

Значения, которые могут быть переданы как второй аргумент обработчику конфликта.

SQLITE_CHANGESET_DATA
Обработчик конфликта вызван с CHANGESET_DATA как второй аргумент, обрабатывая изменение DELETE или UPDATE, если строка с необходимыми областями PRIMARY KEY присутствует в базе данных, но одна или несколько других (не первичный ключ) полей, измененные обновлением, не содержат ожидаемые значения "before".

Противоречивая строка в этом случае является строкой базы данных с соответствующим первичным ключом.

SQLITE_CHANGESET_NOTFOUND
Обработчик конфликта вызван с CHANGESET_NOTFOUND как второй аргумент, обрабатывая изменение DELETE или UPDATE, если строка с необходимыми областями PRIMARY KEY не присутствует в базе данных.

В этом случае нет никакой противоречивой строки. Результаты sqlite3changeset_conflict() API не определены.

SQLITE_CHANGESET_CONFLICT
CHANGESET_CONFLICT передается как второй аргумент обработчику конфликта, обрабатывая изменение INSERT, если операция привела бы к двойным значениям первичного ключа.

Противоречивая строка в этом случае это строка базы данных с соответствующим первичным ключом.

SQLITE_CHANGESET_FOREIGN_KEY
Если обработка внешнего ключа позволена, и применение changeset оставляет базу данных в состоянии , содержащем нарушения внешнего ключа, обработчик конфликта вызван с CHANGESET_FOREIGN_KEY как второй аргумент точно однажды перед тем, как changeset передается. Если обработчик конфликта возвращает CHANGESET_OMIT, изменения, включая те, которые вызвали ограничительное нарушение внешнего ключа, передаются. Если это возвращает CHANGESET_ABORT, changeset отменен.

Никакая информация о строке не обеспечивается. Единственная функция, которая может обратиться к поставляемому дескриптору sqlite3_changeset_iter, это sqlite3changeset_fk_conflicts().

SQLITE_CHANGESET_CONSTRAINT
Если какое-либо другое ограничительное нарушение происходит, применяя изменение (то есть, UNIQUE, CHECK или NOT NULL), обработчик конфликта вызван с CHANGESET_CONSTRAINT как второй аргумент.

В этом случае нет никакой конфликтной строки. Результаты sqlite3changeset_conflict() API не определены.


Опции sqlite3session_object_config

#define SQLITE_SESSION_OBJCONFIG_SIZE  1
#define SQLITE_SESSION_OBJCONFIG_ROWID 2

Следующие значения могут быть переданы как 2-й параметр sqlite3session_object_config().

SQLITE_SESSION_OBJCONFIG_SIZE
Этот выбор используется, чтобы установить, очистить или запросить флаг, который позволяет sqlite3session_changeset_size() API. Поскольку это налагает некоторые вычислительные издержки, этот API отключен по умолчанию. Аргумент pArg должен указать на значение типа (int). Если значение первоначально 0, то sqlite3session_changeset_size() API отключен. Если это больше 0, то тот же самый API позволен. Если начальное значение меньше, чем ноль, никакое изменение не внесено. Во всех случаях переменная (int) установлена в 1, если sqlite3session_changeset_size() API позволен после текущего вызова, или 0 иначе.

Ошибка (SQLITE_MISUSE) попытаться изменить это урегулирование после того, как первая таблица была присоединена к объекту сессии.

SQLITE_SESSION_OBJCONFIG_ROWID
Этот выбор используется, чтобы установить, очистить или запросить флаг, который позволяет сбор данных для таблиц без явного PRIMARY KEY.

Обычно таблицы без явного PRIMARY KEY просто проигнорированы модулем сессий. Однако, если этот флаг установлен, он ведет себя, как будто у таких таблиц есть колонка "_rowid_ INTEGER PRIMARY KEY", вставленная как их крайний левый столбец.

Ошибка (SQLITE_MISUSE) попытаться изменить это урегулирование после того, как первая таблица была присоединена к объекту сессии.


Текущие версии API-функций

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 или меньше. Кроме этого, никакие гарантии не сделаны относительно размера кусков возвращенных данных.


Примените Changeset к базе данных

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

Примените changeset или patchset к базе данных. Эти функции пытаются обновить БД "main", присоединенную к db, с изменениями, найденными в changeset, переданном через второй и третий аргументы.

Четвертый аргумент (xFilter), переданный этим функциям, это "отзыв фильтра". Если это не NULL, то для каждой таблицы, затронутой по крайней мере одним изменением в changeset, отзыв фильтра вызван с именем таблицы как второй аргумент и копией указателя контекста, переданного как шестой аргумент, как первый. Если "отзыв фильтра" возвращает ноль, то никакая попытка не предпринята, чтобы применить любые изменения таблицы. Иначе, если возвращаемое значение отличное от нуля, или аргументом xFilter является NULL, все изменения, связанные с таблицей, предприняты.

Для каждой таблицы, которая не исключена отзывом фильтра, эта функция проверяет, что целевая база данных содержит совместимую таблицу. Ее считают совместимой, если все следующее верно:

  • У таблицы есть то же самое имя как имя, зарегистрированное в changeset
  • У таблицы есть, по крайней мере, столько же колонок, сколько зарегистрировано в changeset
  • У таблицы есть колонки первичного ключа в том же самом положении, как зарегистрировано в changeset

Если нет никакого совместимой таблицы, это не ошибка, но ни одно из изменений, связанных с таблицей, не применяется. Предупреждающее сообщение выпущено через механизм sqlite3_log() с кодом ошибки SQLITE_SCHEMA. Самое большее одно такое предупреждение выпущено для каждой таблицы в changeset.

Для каждого изменения, для которого есть совместимая таблица, предпринята попытка изменить содержание таблицы согласно изменению UPDATE, INSERT или DELETE. Если изменение не может быть применено чисто, функция-обработчик конфликта, переданная как пятый аргумент sqlite3changeset_apply(), может быть вызвана. Описание точно, когда обработчик конфликта вызван для каждого типа изменения, ниже.

В отличие от аргумента xFilter, xConflict не может быть передан NULL. Результаты прохождения чего-либо, кроме действительного указателя функции, как аргумент xConflict не определены.

Каждый раз, когда функция-обработчик конфликта вызвана, она должна возвратить одно из SQLITE_CHANGESET_OMIT , SQLITE_CHANGESET_ABORT или SQLITE_CHANGESET_REPLACE. SQLITE_CHANGESET_REPLACE может быть возвращен только если вторым аргументом, переданным обработчику конфликта, является SQLITE_CHANGESET_DATA или SQLITE_CHANGESET_CONFLICT. Если обработчик конфликта возвращает неправильное значение, любые изменения, уже внесенные, отменены, и обращение к sqlite3changeset_apply() вернет SQLITE_MISUSE. Различные меры приняты sqlite3changeset_apply() в зависимости от значения, возвращенного каждым вызовом функции-обработчика конфликта. Обратитесь к документации для трех доступных возвращаемых значений для деталей.

DELETE
Для каждого изменения DELETE функция проверяет, содержит ли целевая база данных строку с тем же самым значением первичного ключа (или значениями), как первоначальные значения строки, сохраненные в changeset. Если это так, и значения, сохраненные во всех колонках непервичного ключа, также соответствуют значениям, сохраненным в changeset, строка удалена из целевой базы данных.

Если строка с соответствием значениям первичного ключа найдена, но одна или больше областей непервичного ключа содержит значение, отличающееся от первоначального значения строки, сохраненной в changeset, функция-обработчик конфликта вызвана с SQLITE_CHANGESET_DATA как второй аргумент. Если у таблицы базы данных есть больше колонок, чем зарегистрировано в changeset, только значения тех областей непервичного ключа сравнены с текущим содержанием базы данных, любые другие колонки таблицы базы данных проигнорированы.

Если никакой строки с соответствием значениям первичного ключа не найдено в базе данных, функция-обработчик конфликта вызвана с SQLITE_CHANGESET_NOTFOUND, переданным как второй аргумент.

Если операция DELETE предпринята, но SQLite возвращает SQLITE_CONSTRAINT (который может произойти только если ограничение внешнего ключа нарушено), функция-обработчик конфликта вызвана с SQLITE_CHANGESET_CONSTRAINT, переданным как второй аргумент. Это включает случай, где операция DELETE предпринята потому что более раннее обращение к функции-обработчику конфликта вернуло SQLITE_CHANGESET_REPLACE.

INSERT
Для каждого изменения INSERT предпринята попытка вставить новую строку в базу данных. Если changeset содержит меньше областей, чем таблица базы данных, дополнительные области наполнены их значениями по умолчанию.

Если попытка вставить строку терпит неудачу, потому что база данных уже содержит строку с теми же самыми значениями первичного ключа, функция-обработчик конфликта вызвана со вторым аргументом SQLITE_CHANGESET_CONFLICT.

Если попытка вставить строку терпит неудачу из-за некоторого другого ограничительного нарушения (например, NOT NULL или UNIQUE), функция-обработчик конфликта вызвана со вторым аргументом SQLITE_CHANGESET_CONSTRAINT. Это включает случай, где операция INSERT повторно предпринята потому, что более раннее обращение к функции-обработчику конфликта вернуло SQLITE_CHANGESET_REPLACE.

UPDATE
Для каждого изменения UPDATE функция проверяет, содержит ли целевая база данных строку с тем же самым значением первичного ключа (или значениями), как первоначальные значения строки, сохраненные в changeset. Если это так, и значения, сохраненные во всех измененных колонках непервичного ключа также соответствуют значениям, сохраненным в changeset, строка обновляется в целевой базе данных.

Если строка с соответствием значениям первичного ключа найдена, но одна или больше измененных областей непервичного ключа содержит значение, отличающееся от первоначального значения строки, сохраненной в changeset, функция-обработчик конфликта вызвана с вторым параметром SQLITE_CHANGESET_DATA. Так как UPDATE содержит только значения для областей непервичного ключа, которые должны быть изменены, только те области должны соответствовать исходным значениям, чтобы избежать отзыва обработчика конфликта SQLITE_CHANGESET_DATA.

Если никакая строка с соответствием значениям первичного ключа не найдена в базе данных, функция-обработчик конфликта вызвана с SQLITE_CHANGESET_NOTFOUND, переданным как второй аргумент.

Если операция UPDATE предпринята, но SQLite возвращает SQLITE_CONSTRAINT, функция-обработчик конфликта вызвана с SQLITE_CHANGESET_CONSTRAINT, переданным как второй аргумент. Это включает случай, где операция UPDATE предпринята после более раннего обращения к функции-обработчику конфликта, вернувшей SQLITE_CHANGESET_REPLACE .

Безопасно выполнить SQL-операторы, включая тех, которые пишут таблицу, связанную с отзывом, из отзыва xConflict. Это может использоваться, чтобы далее настроить стратегию разрешения конфликтов применения.

Все изменения, внесенные этими функциями, приложены в транзакции точки сохранения. Если какая-либо другая ошибка (кроме ограничительной неудачи, пытаясь написать целевой базе данных) происходит, то транзакция точки сохранения отменена, вернув целевую базу данных к ее исходному состоянию и возвратив код ошибки SQLite.

Если параметры вывода (ppRebase) и (pnRebase) не NULL, а вход changeset (не patchset), то sqlite3changeset_apply_v2() может установить (*ppRebase), чтобы указывать на "rebase", которая может использоваться с буфером sqlite3_rebaser API перед возвращением. В этом случае (*pnRebase) установлен в размер буфера в байтах. Ответственность вызывающего в конечном счете освободить любой такой буфер, используя sqlite3_free(). Буфер ассигнован и наполнен только если с одним или более конфликтами столкнулись, применяя patchset. См. комментарии sqlite3_rebaser API.

Поведение sqlite3changeset_apply_v2() может быть изменено, передав комбинацию поддержанных флагов как 9-й параметр.

Обратите внимание на то, что sqlite3changeset_apply_v2() API все еще экспериментален и поэтому подлежит изменению.


Создайте Iterator, чтобы пересечь Changeset

int sqlite3changeset_start(
  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
  int nChangeset,                 /* Size of changeset blob in bytes */
  void *pChangeset                /* Pointer to blob containing changeset */
);

int sqlite3changeset_start_v2(
  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
  int nChangeset,                 /* Size of changeset blob in bytes */
  void *pChangeset,               /* Pointer to blob containing changeset */
  int flags                       /* SESSION_CHANGESETSTART_* flags */
);

Создайте iterator, используемый, чтобы пройти через содержание changeset. Если успешно, *pp указывает на обработчик iterator, и SQLITE_OK возвращен. Иначе, если ошибка происходит, *pp = 0 и код ошибки SQLite возвращен.

Следующие функции могут использоваться, чтобы продвинуть и запросить changeset iterator, созданный этой функцией:

Обязанность вызывающего в конечном счете разрушить iterator, передавая его sqlite3changeset_finalize(). Буфер, содержащий changeset (pChangeset), должен остаться действительным, пока iterator не будет разрушен.

Предположим, что changeset blob создан одной из функций sqlite3session_changeset(), sqlite3changeset_concat() или sqlite3changeset_invert(), все изменения в changeset, которые относятся к единственной таблице, группируются. Это означает, что, когда применение повторяет через changeset с использованием iterator, созданного этой функцией, все изменения, которые касаются единственной таблицы, посещают последовательно. Нет никакого шанса, что iterator посетит изменение для таблицы X, затем для Y и снова для X.

Поведение sqlite3changeset_start_v2() может быть изменено, передав комбинацию поддержанных флагов как 4-й параметр.

Обратите внимание на то, что sqlite3changeset_start_v2() API все еще экспериментален и поэтому подлежит изменению.