Применение набора изменений к базе данных
Применяет набор изменений или набор исправлений к базе данных. Эти функции пытаются обновить базу данных «main», присоединённую к обработчику 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_REPLACE может быть возвращено только в том случае, если второй аргумент, переданный в обработчик конфликтов, равен либо SQLITE_CHANGESET_DATA, либо SQLITE_CHANGESET_CONFLICT. Если обработчик конфликтов возвращает недопустимое значение, все уже внесённые изменения отменяются, и вызов sqlite3changeset_apply() возвращает SQLITE_MISUSE. Разные действия предпринимаются sqlite3changeset_apply() в зависимости от значения, возвращаемого каждой вызов функции обработчика конфликтов. Обратитесь к документации для трёх доступных возвращаемых значений для получения подробностей.
- Изменения DELETE
- Для каждого изменения DELETE функция проверяет, содержит ли целевая база данных строку с тем же значением (или значениями) первичного ключа, что и исходные значения строки, хранящиеся в наборе изменений. Если это так, и значения, хранящиеся во всех столбцах, не являющихся столбцами первичного ключа, также совпадают со значениями, хранящимися в наборе изменений, строка удаляется из целевой базы данных.
Если строка с соответствующими значениями первичного ключа найдена, но один или несколько столбцов, не являющихся столбцами первичного ключа, содержат значение, отличное от исходного значения строки, хранящейся в наборе изменений, функция обработчика конфликтов вызывается с SQLITE_CHANGESET_DATA в качестве второго аргумента. Если таблица базы данных имеет больше столбцов, чем записано в наборе изменений, для сравнения с текущим содержимым базы данных используются только значения этих столбцов, не являющихся столбцами первичного ключа — любые последующие столбцы таблицы базы данных игнорируются.
Если в базе данных нет строки с соответствующими значениями первичного ключа, функция обработчика конфликтов вызывается с SQLITE_CHANGESET_NOTFOUND, переданным в качестве второго аргумента.
Если операция DELETE выполняется, но SQLite возвращает SQLITE_CONSTRAINT (что может произойти только при нарушении ограничения внешнего ключа), функция обработчика конфликтов вызывается с SQLITE_CHANGESET_CONSTRAINT, переданным в качестве второго аргумента. Это включает случай, когда операция DELETE выполняется, потому что предыдущий вызов функции обработчика конфликтов вернул SQLITE_CHANGESET_REPLACE.
- Изменения INSERT
- Для каждого изменения INSERT предпринимается попытка вставить новую строку в базу данных. Если строка набора изменений содержит меньше полей, чем таблица базы данных, последующие поля заполняются своими значениями по умолчанию.
Если попытка вставить строку терпит неудачу, потому что база данных уже содержит строку с теми же значениями первичного ключа, функция обработчика конфликтов вызывается со вторым аргументом, установленным в SQLITE_CHANGESET_CONFLICT.
Если попытка вставить строку терпит неудачу из-за нарушения другого ограничения (например, NOT NULL или UNIQUE), функция обработчика конфликтов вызывается со вторым аргументом, установленным в SQLITE_CHANGESET_CONSTRAINT. Это включает случай, когда операция INSERT повторяется, потому что предыдущий вызов функции обработчика конфликтов вернул SQLITE_CHANGESET_REPLACE.
- Изменения UPDATE
- Для каждого изменения UPDATE функция проверяет, содержит ли целевая база данных строку с тем же значением первичного ключа (или значениями), что и исходные значения строки, хранящиеся в наборе изменений. Если это так, и значения, хранящиеся во всех изменённых столбцах, не являющихся столбцами первичного ключа, также совпадают со значениями, хранящимися в наборе изменений, строка обновляется в целевой базе данных.
Если строка с соответствующими значениями первичного ключа найдена, но один или несколько изменённых столбцов, не являющихся столбцами первичного ключа, содержат значение, отличное от исходного значения строки, хранящейся в наборе изменений, функция обработчика конфликтов вызывается с 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 и входные данные являются набором изменений (а не набором исправлений), тогда sqlite3changeset_apply_v2() может установить (*ppRebase) на указатель на «перебазирование», которое можно использовать с API sqlite3_rebaser перед возвратом. В этом случае (*pnRebase) устанавливается в размер буфера в байтах. Ответственность за последующее освобождение такого буфера лежит на вызывающей стороне с помощью sqlite3_free(). Буфер выделяется и заполняется только в случае обнаружения одного или нескольких конфликтов при применении набора исправлений. Дополнительные сведения см. в комментариях, окружающих API sqlite3_rebaser.
Поведение sqlite3changeset_apply_v2() и его потокового эквивалента может быть изменено путём передачи комбинации поддерживаемых флагов в качестве девятого параметра.
Обратите внимание, что API sqlite3changeset_apply_v2() всё ещё находится в стадии экспериментальной разработки и, следовательно, может быть изменён.
См. также списки объектов, констант и функций.
SQLite is in the Public Domain.
https://sqlite.org/session/sqlite3changeset_apply.html