Sqlite trigger error

create-trigger-stmt:

1. Syntax

create-trigger-stmt:

CREATE

TEMP

TEMPORARY

TRIGGER

IF

NOT

EXISTS

schema-name

.

trigger-name

BEFORE

AFTER

INSTEAD

OF

DELETE

INSERT

UPDATE

OF

column-name

,

ON

table-name

FOR

EACH

ROW

WHEN

expr

BEGIN

update-stmt

;

END

insert-stmt

delete-stmt

select-stmt

delete-stmt:

expr:

insert-stmt:

select-stmt:

update-stmt:

2. Description

The CREATE TRIGGER statement is used to add triggers to the
database schema. Triggers are database operations
that are automatically performed when a specified database event
occurs.

Each trigger must specify that it will fire for one of
the following operations: DELETE, INSERT, UPDATE.
The trigger fires once for each row that is deleted, inserted,
or updated. If the «UPDATE OF column-name»
syntax is used, then the trigger will only fire if
column-name appears on the left-hand side of
one of the terms in the SET clause of the UPDATE statement.

Due to an historical oversight, columns named in the «UPDATE OF»
clause do not actually have to exist in the table being updated.
Unrecognized column names are silently ignored.
It would be more helpful if SQLite would fail the CREATE TRIGGER
statement if any of the names in the «UPDATE OF» clause are not
columns in the table. However, as this problem was discovered
many years after SQLite was widely deployed, we have resisted
fixing the problem for fear of breaking legacy applications.

At this time SQLite supports only FOR EACH ROW triggers, not FOR EACH
STATEMENT triggers. Hence explicitly specifying FOR EACH ROW is optional.
FOR EACH ROW implies that the SQL statements specified in the trigger
may be executed (depending on the WHEN clause) for each database row being
inserted, updated or deleted by the statement causing the trigger to fire.

Both the WHEN clause and the trigger actions may access elements of
the row being inserted, deleted or updated using references of the form
«NEW.column-name» and «OLD.column-name«, where
column-name is the name of a column from the table that the trigger
is associated with. OLD and NEW references may only be used in triggers on
events for which they are relevant, as follows:

INSERT NEW references are valid
UPDATE NEW and OLD references are valid
DELETE OLD references are valid

If a WHEN clause is supplied, the SQL statements specified
are only executed if the WHEN clause is true.
If no WHEN clause is supplied, the SQL statements
are executed every time the trigger fires.

The BEFORE or AFTER keyword determines when the trigger actions
will be executed relative to the insertion, modification or removal of the
associated row. BEFORE is the default when neither keyword is present.

An ON CONFLICT clause may be specified as part of an UPDATE or INSERT
action within the body of the trigger.
However if an ON CONFLICT clause is specified as part of
the statement causing the trigger to fire, then conflict handling
policy of the outer statement is used instead.

Triggers are automatically dropped
when the table that they are
associated with (the table-name table) is
dropped. However if the trigger actions reference
other tables, the trigger is not dropped or modified if those other
tables are dropped or modified.

Triggers are removed using the DROP TRIGGER statement.

2.1. Syntax Restrictions On UPDATE, DELETE, and INSERT Statements Within
Triggers

The UPDATE, DELETE, and INSERT
statements within triggers do not support
the full syntax for UPDATE, DELETE, and INSERT statements. The following
restrictions apply:

  • The name of the table to be modified in an UPDATE, DELETE, or INSERT
    statement must be an unqualified table name. In other words, one must
    use just «tablename» not «database.tablename»
    when specifying the table.

  • For non-TEMP triggers,
    the table to be modified or queried must exist in the
    same database as the table or view to which the trigger is attached.
    TEMP triggers are not subject to the same-database rule. A TEMP
    trigger is allowed to query or modify any table in any ATTACH-ed database.

  • The «INSERT INTO table DEFAULT VALUES» form of the INSERT statement
    is not supported.

  • The INDEXED BY and NOT INDEXED clauses are not supported for UPDATE and
    DELETE statements.

  • The ORDER BY and LIMIT clauses on UPDATE and DELETE statements are not
    supported. ORDER BY and LIMIT are not normally supported for UPDATE or
    DELETE in any context but can be enabled for top-level statements
    using the SQLITE_ENABLE_UPDATE_DELETE_LIMIT compile-time option. However,
    that compile-time option only applies to top-level UPDATE and DELETE
    statements, not UPDATE and DELETE statements within triggers.

  • Common table expression are not supported for
    statements inside of triggers.

3. INSTEAD OF triggers

BEFORE and AFTER triggers work only on ordinary tables.
INSTEAD OF triggers work only on views.

If an INSTEAD OF INSERT trigger exists on a view, then it is
possible to execute an INSERT statement against that view. No actual
insert occurs. Instead, the statements contained within the trigger
are run. INSTEAD OF DELETE and
INSTEAD OF UPDATE triggers work the same way for DELETE and UPDATE statements
against views.

Note that the sqlite3_changes() and sqlite3_total_changes() interfaces
do not count INSTEAD OF trigger firings, but the
count_changes pragma does count INSTEAD OF trigger firing.

4. Some Example Triggers

Assuming that customer records are stored in the «customers» table, and
that order records are stored in the «orders» table, the following
UPDATE trigger
ensures that all associated orders are redirected when a customer changes
his or her address:

CREATE TRIGGER update_customer_address UPDATE OF address ON customers 
  BEGIN
    UPDATE orders SET address = new.address WHERE customer_name = old.name;
  END;

With this trigger installed, executing the statement:

UPDATE customers SET address = '1 Main St.' WHERE name = 'Jack Jones';

causes the following to be automatically executed:

UPDATE orders SET address = '1 Main St.' WHERE customer_name = 'Jack Jones';

For an example of an INSTEAD OF trigger, consider the following schema:

CREATE TABLE customer(
  cust_id INTEGER PRIMARY KEY,
  cust_name TEXT,
  cust_addr TEXT
);
CREATE VIEW customer_address AS
   SELECT cust_id, cust_addr FROM customer;
CREATE TRIGGER cust_addr_chng
INSTEAD OF UPDATE OF cust_addr ON customer_address
BEGIN
  UPDATE customer SET cust_addr=NEW.cust_addr
   WHERE cust_id=NEW.cust_id;
END;

With the schema above, a statement of the form:

UPDATE customer_address SET cust_addr=$new_address WHERE cust_id=$cust_id;

Causes the customer.cust_addr field to be updated for a specific
customer entry that has customer.cust_id equal to the $cust_id parameter.
Note how the values assigned to the view are made available as field
in the special «NEW» table within the trigger body.

5. Cautions On The Use Of BEFORE triggers

If a BEFORE UPDATE or BEFORE DELETE trigger modifies or deletes a row
that was to have been updated or deleted, then the result of the subsequent
update or delete operation is undefined. Furthermore, if a BEFORE trigger
modifies or deletes a row, then it is undefined whether or not AFTER triggers
that would have otherwise run on those rows will in fact run.

The value of NEW.rowid is undefined in a BEFORE INSERT trigger in which
the rowid is not explicitly set to an integer.

Because of the behaviors described above, programmers are encouraged to
prefer AFTER triggers over BEFORE triggers.

6. The RAISE() function

A special SQL function RAISE() may be used within a trigger-program,
with the following syntax

raise-function:

RAISE

(

ROLLBACK

,

error-message

)

IGNORE

ABORT

FAIL

When one of RAISE(ROLLBACK,…), RAISE(ABORT,…) or RAISE(FAIL,…)
is called during trigger-program
execution, the specified ON CONFLICT processing is performed and
the current query terminates.
An error code of SQLITE_CONSTRAINT is returned to the application,
along with the specified error message.

When RAISE(IGNORE) is called, the remainder of the current trigger program,
the statement that caused the trigger program to execute and any subsequent
trigger programs that would have been executed are abandoned. No database
changes are rolled back. If the statement that caused the trigger program
to execute is itself part of a trigger program, then that trigger program
resumes execution at the beginning of the next step.

7. TEMP Triggers on Non-TEMP Tables

A trigger normally exists in the same database as the table named
after the «ON» keyword in the CREATE TRIGGER statement. Except, it is
possible to create a TEMP TRIGGER on a table in another database.
Such a trigger will only fire when changes
are made to the target table by the application that defined the trigger.
Other applications that modify the database will not be able to see the
TEMP trigger and hence cannot run the trigger.

When defining a TEMP trigger on a non-TEMP table, it is important to
specify the database holding the non-TEMP table. For example,
in the following statement, it is important to say «main.tab1» instead
of just «tab1»:

CREATE TEMP TRIGGER ex1 AFTER INSERT ON main.tab1 BEGIN ...

Failure to specify the schema name on the target table could result
in the TEMP trigger being reattached to a table with the same name in
another database whenever any schema change occurs.

This page last modified on 2022-09-27 13:16:55 UTC

Привет, посетитель сайта ZametkiNaPolyah.ru! Продолжаем изучать базы данных и наше знакомство с библиотекой SQLite3. Тем в рубрике SQLite осталось не так уж и много. Вернее про SQLite можно писать очень много, долго и упорно, и всё равно часть вопросов останется не освещенной и освещенной не в полной мере. Под словосочетанием «тем осталось немного» я понимаю следующее: мы практически закончили изучать реализацию SQL в библиотеки SQLite. Задачу, которую я сам перед собой поставил, можно озвучить следующим образом: дать начинающему разработчику максимально понятное и подробное представление о языке SQL, а в качестве примера используется библиотека SQLite. В данной теме мы поговорим о том, что собой представляют триггеры в SQL на примере базы данных под управлением SQLite. Тему триггеров я не стал делить на части, поэтому запись получилось довольно объемной(более 4300 слов, поэтому пользуйтесь постраничной навигацией).

Триггеры в SQL на примере базы данных SQLite

Триггеры в SQL на примере базы данных SQLite

Отсутствие деления темы SQL триггеров на части не вызвано желанием написать огромный текст, просто все разделы данной записи очень тесно связаны между собой и я не захотел разбивать эту связь, делая деление на части. Итак, поехали! По традиции небольшая аннотация к записи:

  1. Сначала мы поговорим о назначении триггеров в SQL и реляционных базах данных, попутно рассмотрев синтаксис триггеров в SQLite.
  2. Затем мы поговорим о том, как срабатывают триггеры в базах данных: до возникновения события (триггер BEFORE) и после возникновения события (триггер AFTER) и параллельно разберемся в чем между ними разница.
  3. Далее мы опишем триггеры по событиям, на которые они срабатывают. Событий у нас всего три, так как триггеры в SQLite срабатывают только на операции, которые тем или иным образом изменяют данные в таблицы: UPDATE, INSERT, DELETE.
  4. Далее мы рассмотрим, как составить уточняющее выражение WHEN для триггера.
  5. Рассмотрим особенности INSTEAD OF триггера, который позволяет реализовать команды манипуляции данными для представлений, отметим, что в SQLite представления нельзя редактировать, об этом мы поговорим в следующей теме.
  6. Также мы поговорим про устранение конфликтов и обеспечение целостности данных при помощи триггеров и специальной функции RAISE.
  7. И в завершении публикации вы узнаете о том, как получить информацию о триггерах/списков триггеров в базах данных SQLite3.Рассмотрим явное и неявное удаление триггеров из базы данных SQLite. И разберемся с некоторыми особенностями работы временных триггеров в SQLite.

Что такое триггер в контексте SQL? Использование триггеров в базах данных SQLite

Содержание статьи:

  • Что такое триггер в контексте SQL? Использование триггеров в базах данных SQLite
  • SQL синтаксис триггеров в базах данных SQLite
  • SQL событие BEFORE: выполнение триггера перед запросом
  • SQL событие AFTER: выполнение триггера после запроса
  • INSERT триггеры и DELETE триггеры. Триггеры добавления и удаления данных
  • UPDATE триггеры: AFTER UPDATE и BEFORE UPDATE триггер. Триггеры модификации.
  • Условия срабатывания триггера WHEN. Уточняющие выражения
  • Некоторые особенности триггеров в базах данных SQLite
  • Изменение данных VIEW в SQLite. Редактирование VIEW при помощи INSTEAD OF триггера в SQLite
  • Функция RAISE () и SQL триггеры в библиотеки SQLite3. Устранение конфликтов в базе данных при помощи триггеров
  • Временные триггеры в базах данных SQLite3
  • Получит информацию о триггерах в базе данных SQLite
  • Удаление триггеров из базы данных SQLite

Триггер – это особая разновидность хранимых процедур в базе данных. Особенность триггеров заключается в том, что SQL код, написанные в теле триггера, будет исполнен после того, как в базе данных произойдет какое-либо событие. События в базах данных происходят в результате выполнения DML команд или команд манипуляции данными. Если вы помните, то к командам манипуляции данными относятся: UPDATE, INSERT, DELETE и SELECT.

Команду SELECT мы не берем в расчет из-за того, что она никак не изменяет данные в базе данных, а лишь делает выборку данных. Основное назначение триггеров заключается в обеспечение целостности данных в базе данных, еще при помощи триггеров в SQL можно реализовать довольно-таки сложную бизнес-логику.

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

Для любой СУБД триггер – это в первую очередь объект базы данных, поэтому имя триггера должно быть уникальным во всей базе данных, SQLite в этом плане не исключение. У триггеров в SQL есть момент запуска. Момент запуска триггера можно разделить на два вида: BEFORE и AFTER. Момент запуска триггера AFTER говорит о том, что триггер будет запущен после выполнения какого-либо события в базе данных. Соответственно, момент запуска триггера BEFORE говорит о том, что триггер будет запущен до выполнения события в базе данных.

Мы еще поговорим про представления или VIEW в SQL, и вы узнаете, что SQLite позволяет только читать данные из VIEW, в отличии, скажем, от MySQL или Oracle. Триггеры могут быть назначены для представлений с целью расширить набор операций манипуляции данными того или иного представления.  Такой вид триггеров получил название INSTEAD OF триггер.

Итак, триггеры можно разделить на три вида по их применению:

  • триггер BEFORE, который срабатывает до выполнения какого-либо события в базе данных;
  • триггер AFTER, который срабатывает после выполнения события в базе данных;
  • INSTEAD OF триггер, который используется для манипуляции данными представлений.

Так же мы можем разделить триггеры по типам SQL команд:

  • DELETE триггер. Триггер DELETE запускается при попытке удаления данных/строк из таблицы базы данных;
  • UPDATE триггер. Триггер UPDATE будет запущен при попытке обновления/модификации данных в таблице базы данных;
  • INSERT триггер. Триггер INSERT будет запущен в том случае, если вы попытаетесь вставить/добавить строку в таблицу базы данных.

В некоторых СУБД триггер – это довольно мощное и полезное явление. Будьте аккуратны, используя триггеры, не используйте триггеры в рабочих базах данных. Перед тем, как реализовать триггер, создайте тестовую базу данных и посмотрите, что в итоге получится. Неправильный составленный триггер может навредить вашему проекту, повредив часть данных или удалив данные из базы данных.

Давайте перечислим самые распространенные функции триггеров:

  1. Функция журнализации. Часто при помощи триггеров разработчики создают таблицы-журналы, в которых фиксируются различные изменения в базе данных. Обычно журналы создаются для фиксации изменений, которые вносят различные пользователи базы данных, таким образом можно отследить какой пользователь внес то или иное изменение в ту или иную таблицу базы данных.
  2. Функция согласования данных. Мы уже упоминали, что триггеры используются для обеспечения целостности данных в базе данных. Мы можем связать триггер с той или иной SQL командой, таким образом, чтобы триггер проверял связанные таблицы на согласованность данных, тем самым мы обезопасим данные.
  3. Функция очистки данных. Данная функция является подмножество функции из второго пункта. Например, вы выполняете каскадное удаление данных, в этом случае данные удаляются из таблиц, связанных ограничением внешнего ключа, но что если данные об одном объекте хранятся в несвязанных таблицах? В этом случае нас спасают триггеры. То же самое можно сказать и про операции каскадной модификации данных.
  4. Другие функции триггеров. К сожалению, в SQLite3 нет хранимых процедур за исключением триггеров. В тех СУБД, у которых реализованы хранимые процедуры, мы можем создавать собственные процедуры в теле триггера, которые могут выполнять операции, не связанные с изменением данных.

Давайте приступим к рассмотрению триггеров на примере библиотеки SQLite.

SQL синтаксис триггеров в базах данных SQLite

Здесь мы коротко рассмотрим SQL синтаксис триггеров, реализованный в реляционных базах данных под управлением библиотеки SQLite3. Ранее мы уже говорили о том, как создать триггер, когда разбирались с командой CREATE в SQLite (у нас был раздел CREATE TRIGGER) и мы рассматривали, как удалить триггер, когда разбирались с особенностями команды DROP в SQLite3 (раздел DROP TRIGGER). Давайте повторим и дополним уже имеющуюся информацию о триггерах. Общий SQL синтаксис создания триггеров в SQLite вы можете увидеть на рисунке ниже.

Общий синтаксис создания триггера в базе данных под управлением SQLite3

Общий синтаксис создания триггера в базе данных под управлением SQLite3

Мы видим, что операция по созданию триггера начинается с команды CREATE, как и операция создания таблицы в базе данных, это обусловлено тем, что триггер, как и таблица, является объектом базы данных.

Далее идет модификатор TEMP или TEMPORARY, этот модификатор необязательный и его можно опускать. Временный триггер будет доступен только для того пользователя, который его создали, а существовать временный триггер будет до тех пор, пока пользователь не разорвет соединение или же пока не удалит его.

Далее мы указываем, что хотим создать триггер при помощи ключевого слова TRIGGER. Мы можем воспользоваться оператором EXISTS, чтобы проверить существует ли триггер в базе данных, перед тем как его создать. Данная проверка не является обязательно, но если вы попытаетесь создать триггер, который уже существует в базе данных, то произойдет ошибка, а программный код, отправлявший такой запрос, может быть остановлен.

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

Далее мы указываем как мы хотим, чтобы триггер работал: для VIEW – INSTEAD OF, перед выполнением SQL команды – BEFORE, после выполнения SQL операции – AFTER. После чего мы связываем триггер с той или иной командой. Обратите внимание: для всех трех команд манипуляции данными обязательным является указание таблицы или представления, для которых триггер создается, а вот для команды UPDATE можно указать еще и столбец, который будет отслеживать триггер.

Обратите внимание: мы можем создавать строковые триггеры при помощи конструкции FOR EACH ROW. Обычно триггеры создаются для какой-нибудь команды и, соответственно, выполняются по событию DELETE, UPDATE или INSERT, но мы можем сделать так, чтобы код триггера вызывался после изменения каждой строки таблицы при помощи конструкции FOR EACH ROW.

Так же стоит отметить, что выше мы говорили не совсем правду в контексте SQLite3. Многие СУБД поддерживают две разновидности триггеров: табличные и строчные. Строчные триггеры создаются при помощи конструкции FOR EACH ROW, но в SQLite нет табличных триггеров, поэтому даже если вы не укажите FOR EACH ROW явно, SQLite будет считать триггер строчным.

Также вы можете использовать уточняющую фразу WHEN, с которой мы разберемся на примере ниже. После того, как вы описали триггер, вы можете задать SQL команды, которые будут выполняться по тому или иному событию, другими словами – создать тело триггера. В теле триггера, создаваемого в базе данных SQLite, можно использовать четыре команды манипуляции данными: INSERT, UPDATE, SELECT, DELETE. Команды определения данных, команды определения доступа к данным и команды управления транзакциями в теле триггера SQLite не предусмотрены. Но нам стоит заметить,что триггеры, выполняя команды и отлавливая события сами работают так, как будто это транзакция.

Обратим внимание на то, что перечисленные команды в теле триггера поддерживают свой практически полный синтаксис. Например, вы можете составить сколь угодно сложный SQL запрос SELECT, в котором будете объединять таблицы или объединять результаты запросов. Чтобы сообщить SQLite, что тело триггера закончилось, используйте ключевое слово END.

Итак, мы разобрались с SQL синтаксисом создания триггеров, давайте посмотрим на SQL синтаксис удаления триггеров. SQL синтаксис удаления триггеров, реализованный в SQLite3, представлен на рисунке ниже.

Синтаксис удаления триггеров из базы данных SQLite

Синтаксис удаления триггеров из базы данных SQLite

Для удаления триггера, как и для удаления таблицы из базы данных, используйте команду DROP. Далее идет ключевая фраза TRIGGER, которая сообщает SQLite о том, что вы хотите удалить триггер из базы данных, после чего вы можете сделать проверку IF EXISTS, о которой мы не раз уже говорили. И в конце указываете имя триггера или квалификатор. Как видите, удалить триггер намного проще, чем его создать.

Давайте перейдем к примерам использования триггеров в базах данных под управлением SQLite.

SQL событие BEFORE: выполнение триггера перед запросом

Итак, не забываем, что триггер создается для какой-либо конкретной таблицы и отслеживает события, происходящие с таблицей, для которой он создан. В SQLite нет табличных триггеров, а есть только триггеры строчные, то есть FOR EACH ROW триггеры, которые срабатывают при изменении каждой строки в таблице.

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

CREATE TABLE users(

id INTEGER PRIMARY KEY,

name TEXT NOT NULL,

age INTEGER NOT NULL,

address TEXT NOT NULL,

mydate TEXT NOT NULL

);

CREATE TABLE user_log (

Id_u INTEGER NOT NULL,

u_date TEXT NOT NULL

);

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

Давайте напишем триггер, который будет срабатывать перед тем, как SQLite выполнит запрос:

CREATE TRIGGER my_u_log BEFORE INSERT

ON users

BEGIN

INSERT INTO user_log(id_u, u_date) VALUES (NEW.id, datetime(‘now’));

END;

Этот триггер срабатает перед тем, как новая строка будет добавлена в таблицу users. Давайте в этом убедимся:

INSERT INTO users(name, age, address, mydate)

VALUES (‘Пупкин’, 27, ‘Адрес’, datetime(‘now’));

SELECT * FROM users;

id      name    age     address mydate

1       Пупкин  27      Адрес   20160715 06:58:36

SELECT * FROM user_log;

Id_u    u_date

1      20160715 06:58:36

Мы видим, что данные в таблицу user_log были добавлены автоматически. К сожалению, поле date в данном случае не показывает, что вставка данных в таблицу user_log произошла до того, как были вставлены данные в таблицу users. Но этот факт мы можем заметить по значению столбца id_u, которое равно -1, так как SQLite3 просто не знает: какое значение будет в столбце id таблицы users.

SQL событие AFTER: выполнение триггера после запроса

Давайте теперь изменим наш пример, таблица останется той же, но мы изменим код триггера, только одну его часть: поменяем BEFORE на AFTER, чтобы посмотреть, как сработает триггер после выполнения запроса:

CREATE TRIGGER my_u_log AFTER INSERT

ON users

BEGIN

INSERT INTO user_log(id_u, u_date) VALUES (NEW.id, datetime(‘now’));

END;

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

INSERT INTO users(name, age, address, mydate)

VALUES (‘Пупкин’, 27, ‘Адрес’, datetime(‘now’));

INSERT INTO users(name, age, address, mydate)

VALUES (‘Сумкин’, 17, ‘Адрес2’, datetime(‘now’));

SELECT * FROM users;

id      name    age     address mydate

1       Пупкин  27      Адрес   20160715 07:08:46

2       Сумкин  17      Адрес2  20160715 07:08:46

SELECT * FROM user_log;

Id_u    u_date

1       20160715 07:08:46

2       20160715 07:08:46

Теперь идентификаторы записываются корректно во вторую таблицу. Обратите внимание на модификатор NEW. Модификатор NEW – это ключевое слово, которое используется в теле триггера для того, чтобы сказать СУБД о том, что нужно брать новые значения (значение, которое мы добавляем в таблицу или модифицированный вариант значения). Надеюсь, что вы разобрались в разнице между BEFORE и AFTER.

INSERT триггеры и DELETE триггеры. Триггеры добавления и удаления данных

Ранее мы уже рассмотрели триггеры AFTER INSERT и BEFORE INSERT, поэтому мы не будем уделять здесь им особого внимания и сразу поговорим про триггеры BEFORE  DELETE и AFTER DELETE. Таблица users у нас останется прежней, а вот структуру таблицы user_log мы немного изменим:

CREATE TABLE user_log (

Id_u INTEGER NOT NULL,

u_date TEXT NOT NULL,

operation TEXT NOT NULL

);

Мы добавили столбец operation, в котором будем хранить информацию о том, что мы сделали с пользователем: удалили или добавили. Давайте напишем триггер AFTER DELETE, который у нас будет срабатывать по событию удаления строки из таблицы users:

CREATE TRIGGER after_delete AFTER DELETE

ON users

BEGIN

INSERT INTO user_log(id_u, u_date, operation) VALUES (OLD.id, datetime(‘now’), del);

END;

А теперь давайте посмотрим на то, как будет работать триггер AFTER DELETE:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

INSERT INTO users(name, age, address, mydate)

VALUES (‘Пупкин’, 27, ‘Адрес’, datetime(‘now’));

INSERT INTO users(name, age, address, mydate)

VALUES (‘Сумкин’, 17, ‘Адрес2’, datetime(‘now’));

INSERT INTO users(name, age, address, mydate)

VALUES (‘Иванов’, 37, ‘Адрес3’, datetime(‘now’));

INSERT INTO users(name, age, address, mydate)

VALUES (‘Петров’, 47, ‘Адрес4’, datetime(‘now’));

INSERT INTO users(name, age, address, mydate)

VALUES (‘Сидоров’, 57, ‘Адрес5’, datetime(‘now’));

INSERT INTO users(name, age, address, mydate)

VALUES (‘Парамонов’, 7, ‘Адрес6’, datetime(‘now’));

DELETE FROM users

WHERE id = 4;

SELECT * FROM user_log;

1|20160715 07:29:28|ins

2|20160715 07:29:28|ins

3|20160715 07:29:28|ins

4|20160715 07:29:28|ins

5|20160715 07:29:28|ins

6|20160715 07:29:28|ins

4|20160715 07:29:28|del

SELECT * FROM users;

id      name                         age     address mydate

1       Пупкин                     27      Адрес   20160715 07:29:28

2       Сумкин                     17      Адрес2  20160715 07:29:28

3       Иванов                      37      Адрес3  20160715 07:29:28

5       Сидоров                   57      Адрес5  20160715 07:29:28

6       Парамонов             7        Адрес6  20160715 07:29:28

Чтобы получилась такие результаты, я немного изменил код первого триггера, добавив столбец operation. Но давайте обратим внимание на код триггера AFTER DELETE, в котором мы использовали модификатор OLD, модификатор OLD в SQL и SQLite используется в коде триггера для того, чтобы обратиться к старому значению или к значению, которое хранится в таблице (значение, которое будет изменено или модифицировано).

Теперь мы разобрались с модификаторами OLD и NEW:

  1. NEW позволяет обратиться к значению, которое указано в SQL запросе или же можно сказать, что это значение, которое мы хотим добавить или на которое хотим изменить.
  2. OLD позволяет обратиться к значению, которое хранится в таблице или же можно сказать, что это значение, которое мы хотим удалить или которое хотим изменить.

Также мы разобрались с тем, как работает триггер AFTER DELETE, думаю, вы без труда разберетесь с тем, как работает триггер BEFORE DELETE, просто заменив в примере триггера DELETE AFTER на BEFORE, поэтому демонстрировать триггер BEFORE DELETE мы здесь не будем и перейдем к другим примерам.

UPDATE триггеры: AFTER UPDATE и BEFORE UPDATE триггер. Триггеры модификации.

Теперь рассмотрим триггеры, срабатывающие при событии обновления данных: AFTER UPDATE триггер и BEFORE UPDATE триггер. Давайте напишем AFTER UPDATE триггер, который будет записывать в таблицу логов строки, хранящие информацию о модификации данных в таблице users, сделать это проще простого:

CREATE TRIGGER after_update AFTER UPDATE

ON users

BEGIN

INSERT INTO user_log(id_u, u_date, operation) VALUES (OLD.id, datetime(‘now’), upd);

END;

Таким образом мы создали триггер, который сработает после выполнения команды UPDATE или AFTER UPDATE триггер, давайте в этом убедимся:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

UPDATE users SET name = ‘Марков’

WHERE id = 6;

SELECT * FROM user_log;

Id_u    u_date  operation

1       20160715 07:29:28     ins

…………………………………………………..

6       20160715 07:29:28     ins

4       20160715 07:29:28     del

6       20160715 08:12:44     upd

SELECT * FROM users;

id      name    age     address mydate

1       Пупкин  27      Адрес   20160715 07:29:28

……………………………………………………………………………..

6       Марков  7       Адрес6  20160715 07:29:28

Видим, что триггер сработал и в лог записалась информация о том, что для пользователя с id=6 вносились изменения. Думаю, вы легко разберетесь с тем, как сделать триггер BEFORE UPDATE по примеру AFTER UPDATE, чтобы вносимые изменения фиксировались до того, как они произойдут. Ничего сложно в триггере BEFORE UPDATE нет.

Обратите внимание: триггер модификации или UPDATE триггер может отслеживать изменения не только для всей таблицы, но и для какого-то конкретного столбца, чтобы указать столбец, который будет отслеживать триггер модификации, используйте следующий синтаксис:

CREATE TRIGGER trigg_name AFTER UPDATE

OF (column1, column2)

BEGIN

тело триггера

END;

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

Условия срабатывания триггера WHEN. Уточняющие выражения

Библиотека SQLite, как и многие другие реляционные СУБД, позволяет использовать условие WHEN, которое позволяет задать область применения триггера при помощи SQL выражений. Синтаксис выражения в SQLite показан на рисунке ниже.

Синтаксис использования выражений в базах данных SQLite

Синтаксис использования выражений в базах данных SQLite

Как видим, мы можем задавать очень сложные выражения для условия WHEN, когда мы создаем триггер. Любая СУБД вычисляет это выражение для строки таблицы, к которой привязан триггер? и в том случае, если WHEN вернет значение TRUE, триггер будет выполнен. SQLite не будет вычислять выражение WHEN, если не будет происходить событие, инициирующее выполнение триггера.

Давайте напишем триггер с условием WHEN, который будет срабатывать, как AFTER INSERT:

CREATE TRIGGER after_insert AFTER INSERT

ON users WHEN (SELECT count(*) FROM user_log) > 21

BEGIN

DELETE FROM user_log  WHERE u_date = (SELECT min(u_date) FROM user_log);

INSERT INTO user_log(id_u, u_date, operation) VALUES (NEW.id, datetime(‘now’), ins);

END;

Этот триггер делает очень простую вещь: он ограничивает количество записей в логе до двадцати одной. То есть в таблице user_log будет храниться информация не обо всех модификациях, а только о последних, понятно, что количество записей в таблице можно регулировать.

Попробуйте реализовать данный триггер, чтобы посмотреть, как работает условие WHEN. Демонстрировать его работу здесь мы не будем. Также обратите внимание на то, что теперь в теле триггера выполняется две операции: первая удаляет лишнюю строку из лог-таблицы, вторая добавляет новую строку в таблицу лога.

Некоторые особенности триггеров в базах данных SQLite

Ранее мы говорили, что в теле триггера можно использовать любую команду манипуляции данных с довольно полным синтаксисом. Но ключевая часть выражения здесь: довольно полный синтаксис. Всё дело в том, что синтаксис команд манипуляции данными в теле триггера SQLite поддерживается не полностью. Итак, ваш триггер не будет создан/не будет работать если:

  1. В теле триггера вы не можете использовать квалификаторы для обращения к таблицам базы данных. Можно использовать только имена таблиц.
  2. Когда в деле триггера вы выполняете операцию INSERT, то вы не можете добавлять значения DEFAULT. Добавляемые значения должны быть явно указаны.
  3. Нельзя использовать ключевые слова INDEX BY и NOT INDEXED в командах UPDATE и DELETE.
  4. Клаузулы LIMIT и ORDER BY нельзя использовать с командами UPDATE и DELETE в теле триггера.

Вот такие ограничения накладывает SQLite на команды SQL, которые мы можем использовать в теле триггера.

Изменение данных VIEW в SQLite. Редактирование VIEW при помощи INSTEAD OF триггера в SQLite

В SQLite нет возможности редактировать VIEW. Напомним, что VIEW в SQL – это хранимый запрос, который СУБД выполняет, когда мы обращаемся к представлениям. Но мы можем манипулировать данными VIEW, которые хранятся в представлениях (данное выражение не совсем корректно, так как данные в представлениях не хранятся, это всего лишь результирующая таблица запроса SELECT) при помощи INSTEAD OF триггера.

Стоит заметить, что функция манипулирования данными представлений – это основная функция триггера INSTEAD OF, но не единственная. Триггер INSTEAD OF работает очень интересно, он позволяет выполнять команды INSERT, DELETE и UPDATE над представлениями, но результаты изменений, внесенных триггером INSTEAD OF, никак не отражаются на таблице/таблицах, на основе которых создано VIEW.

Общий синтаксис триггера INSTEAD OF UPDATE для обновления данных представления можно записать как:

CREATE TRIGGER trigg_name

INSTEAD OF UPDATE OF column_name ON view_name

BEGIN

делаем команду UPDATE для таблицы, на основе которой создана VIEW

END;

Синтаксис триггера INSTEAD OF INSERT для добавления строк в представление выглядит так:

CREATE TRIGGER trigg_name

INSTEAD OF INSERT ON view_name

BEGIN

делаем команду INSERT для таблицы, на основе которой создана VIEW

END;

Синтаксис триггера INSTEAD OF DELETE для удаления строк из представления выглядит так:

CREATE TRIGGER trigg_name

INSTEAD OF DELETE ON view_name

BEGIN

делаем команду DELETE для таблицы, на основе которой создана VIEW

END;

Мы познакомились с основным способом применения триггера INSTEAD OF в SQL и базах данных SQLite. Более подробные примеры по редактированию VIEW при помощи INSTEAD OF триггера в SQLite3, вы найдете в следующей теме, в которой речь пойдет о представлениях.

Функция RAISE () и SQL триггеры в библиотеки SQLite3. Устранение конфликтов в базе данных при помощи триггеров

Мы очень много говорили про обеспечение целостности данных и когда рассматривали различные ограничения СУБД SQLite, и когда говорили про нормальные формы в базе данных. Напомню, что первая нормальная форма – самое незащищенное отношение в базе данных. К тому же, первая нормальная форма – это всегда избыточность данных, плюс ко всему – это всевозможные проблемы, которые называются аномалиями. Вторая нормальная форма помогает нам избавиться от избыточности данных.

А третья нормальная форма устраняет всевозможные аномалии и различные зависимости, это всё важно знать и понимать при проектировании базы данных, но, к сожалению, ни одна в мире СУБД не знает, например, что Хемингуэй написал «Старик и море», а Исаак Ньютон – это физик, поэтому когда мы наполняем наши таблицы данными, могут возникать не очевидные ошибки с точки зрения логики реляционных баз данных, от которых не сможет защитить ни одна нормальная форма.

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

Конфликт в базе данных не стоит путать с аномалией, потому что с точки зрения логики СУБД ничего криминального не происходит, а вот с точки зрения человека, знающего предметную область происходит существенная ошибка, которая может ввести человека в ступор.

Избавиться от подобных конфликтов мы можем при помощи триггеров и функции RAISE (). В SQLite есть специальные ключевые слова ON CONFLICT, которые используются для исключения конфликтов, происходящих во время операций манипуляции данными. О устранении конфликтов мы поговорим более подробно отдельно. Сейчас сконцентрируемся на триггерах и функции RAISE (). Отметим, что RAISE () – это специальная функция, которая используется только вместе с триггерами, ее синтаксис вы найдете на рисунке ниже.

Функция RAISE может принимать два аргумента. Первый аргумент описывает действие при возникновении конфликта:

  1. Значение IGNORE. Говорит SQLite3 о том, чтобы она игнорировала строку породившую конфликт и продолжала выполнение последующих операций.
  2. Значение ROLLBACK. ROLLBACK говорит о том, что SQLite должна откатить все операции к исходному состоянию при возникновении конфликта. При этом пользователь может изменить и повторить запрос. Не путайте с командой ROLLBACK, которая откатывая транзакцию
  3. Значение ABORT. Данное значение похоже на ROLLBACK, но разница в том, что оно отменяет не все выполненные ранее SQL запросы, а только тот запрос, при котором возникла конфликтная ситуация.
  4. Значение FAIL. Данное значение говорит СУБД о том, что нужно прервать выполнение текущей операции и сохранить результаты успешных операций, при этом операции, следующие за конфликтной, выполнены не будут.

Вообще тело триггера выполняется как транзакция, мы даже используем похожие команды, например тело триггера начинается после ключевого слова BEGIN, а вот начало транзакции обозначается ключевой фразой BEGIN TRANSACTION. Подтверждение транзакции- COMMIT или END, а завершение тела триггера обозначается при помощи ключевого слова END. А функция RAISE дает возможность триггеру работать, как команда SAVEPOINT.

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

Давайте повторим пример связи многие ко многим:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

PRAGMA foreign_keys=on;

CREATE TABLE books(

Id INTEGER PRIMARY KEY,

title TEXT NOT NULL,

count_page INTEGER NOT NULL CHECK (count_page >0),

price REAL CHECK (price >0)

);

CREATE TABLE auth(

id INTEGER PRIMARY KEY,

name TEXT NOT NULL,

age INTEGER  CHECK (age >16)

);

CREATE TABLE auth_book (

auth_id INTEGER NOT NULL,

books_id INTEGER NOT NULL,

FOREIGN KEY (auth_id) REFERENCES auth(id)

FOREIGN KEY (books_id) REFERENCES books(id)

);

Сперва добавим несколько строк в таблицу книг

INSERT INTO books (id, title, count_page, price)

VALUES (1, ‘Белый клык’, 287, 300.00);

INSERT INTO books (id, title, count_page, price)

VALUES (2, ‘Война и мир’, 806, 780.00);

INSERT INTO books (id, title, count_page, price)

VALUES (3, 12 стульев’, 516, 480.00);

Затем добавим несколько авторов

INSERT INTO auth (id, name, age)

VALUES (1, ‘Джек Лондон’, 40);

INSERT INTO auth (id, name, age)

VALUES (2, ‘Лев Толстой’, 82);

INSERT INTO auth (id, name, age)

VALUES (3, ‘Илья Ильф’, 39);

INSERT INTO auth (id, name, age)

VALUES (4, ‘Евгений Петров’, 38);

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

Давайте сперва реализуем триггер с использованием функции RAISE (), который будет проверять данные перед их вставкой:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

CREATE TRIGGER books_result  BEFORE INSERT

ON auth_book

BEGIN

SELECT RAISE(FAIL, ‘Произошла ошибка, вы неправильно связали автора и книгу’) FROM auth_book

WHERE (NEW.auth_id = 1 AND books_id = 2) OR (NEW.auth_id = 1 AND NEW.books_id = 3) OR

(NEW.auth_id = 2 AND NEW.books_id = 3) OR (NEW.auth_id = 2 AND NEW.books_id = 3) OR

(NEW.auth_id = 3 AND NEW.books_id = 2) OR (NEW.auth_id = 3 AND NEW.books_id = 1) OR

(NEW.auth_id = 4 AND NEW.books_id = 2) OR (NEW.auth_id = 4 AND NEW.books_id = 1);

END;

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

INSERT INTO auth_book (auth_id, books_id)

VALUES (1, 1);

INSERT INTO auth_book (auth_id, books_id)

VALUES (2, 2);

INSERT INTO auth_book (auth_id, books_id)

VALUES (3, 3);

INSERT INTO auth_book (auth_id, books_id)

VALUES (4, 3);

INSERT INTO auth_book (auth_id, books_id)

VALUES (1, 2);

Error: Произошла ошибка, вы неправильно связали автора и книгу

SELECT * FROM auth_book;

auth_id books_id

1       1

2       2

3       3

4       3

Этот триггер срабатывает при каждой операции добавления строки в таблицу, а функция RAISE сравнивает добавляемое значение с исходным, которое мы задавали при помощи SQL операторов AND и OR в условии WHERE. Обратите внимание: и скобки, знак равно – это тоже SQL операторы.

Временные триггеры в базах данных SQLite3

Демонстрировать примеры создания временных триггеров в базах данных SQLite3 мы не будем. Скажем лишь о том, что временный триггер доступен только для создавшего его пользователя и существует временный триггер всё то время, пока пользователь не разорвет сессию, либо не удалит триггер.

Отметим, что временные триггеры могут быть созданы не только для временных таблиц, но и для обычных таблиц.

Получит информацию о триггерах в базе данных SQLite

Вы можете получить информацию о триггерах или посмотреть созданные триггеры в базе данных SQLite при помощи команды SELECT, следующее предложение покажет вам все триггеры в базе данных:

SELECT name FROM sqlite_master

WHERE type = ‘trigger’;

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

SELECT name FROM sqlite_master

WHERE type = ‘trigger’ AND tbl_name = ‘укажите_имя_таблицы’;

Таким образом вы можете получить список триггеров во всей базе данных или для конкретной таблицы в базе данных SQLite. Обратит внимание: в других СУБД эти команды работать не будут.

Удаление триггеров из базы данных SQLite

Поговорим теперь про удаление триггеров из базы данных. Вспомним общий синтаксис удаления триггера из базы данных:

DROP TRIGGER IF EXISTS db_name.trigger_name;

Таким образом мы можем явно удалить триггер из базы данных SQLite. Неявное удаление триггеров происходит при удалении из базы данных таблицы, к которой он привязан. Если вы привязали обычный триггер к временной таблице, то можете смело его считать временным, так как он будет существовать до первого разрыва соединения с базой данных, после чего триггер будет удален, так как таблица перестанет существовать.

«SQLite Последнее обновление 09 апреля 2019 07:16:14 (UTC / GMT +8 часов)

script1adsense2code

script1adsense3code

Введение в триггеры

Триггер — это управляемое событиями действие, которое запускается автоматически, когда указанная операция изменения (оператор INSERT, UPDATE и DELETE) выполняется над указанной таблицей. Триггеры полезны для таких задач, как обеспечение соблюдения бизнес-правил, проверка входных данных и ведение контрольного журнала.

Оглавление

Использует для триггеров

Преимущества использования триггеров в бизнесе

Создать триггеры SQLite

Пример базы данных, таблица, структура таблицы, записи таблицы

Триггер SQLite: пример ПОСЛЕ ВСТАВКИ

Триггер SQLite: пример перед вставкой

Триггер SQLite: пример ПОСЛЕ ОБНОВЛЕНИЯ

Триггер SQLite: пример перед обновлением

Триггер SQLite: пример ПОСЛЕ УДАЛЕНИЯ

Триггер SQLite: пример перед удалением

Триггер SQLite: пример INSERT с использованием INSTEAD OF

Триггер SQLite: пример UPDATE с использованием INSTEAD OF

Триггер SQLite: пример DELETE с использованием INSTEAD OF

Удалить / удалить триггер SQLite

Использует для триггеров:

  • Применять бизнес-правила
  • Проверьте входные данные
  • Создайте уникальное значение для вновь вставленной строки в другом файле.
  • Записывать в другие файлы для целей аудита
  • Запрос из других файлов для перекрестных ссылок
  • Доступ к системным функциям
  • Репликация данных в разные файлы для обеспечения согласованности данных

Преимущества использования триггеров в бизнесе:

  • Ускоренная разработка приложений. Поскольку база данных хранит триггеры, вам не нужно кодировать действия триггера в каждом приложении базы данных.
  • Глобальное обеспечение соблюдения бизнес-правил. Определите триггер один раз, а затем повторно используйте его для любого приложения, которое использует базу данных.
  • Более простое обслуживание. Если бизнес-политика меняется, вам нужно изменить только соответствующую триггерную программу вместо каждой прикладной программы.
  • Улучшить производительность в среде клиент / сервер. Все правила запускаются на сервере до возврата результата.

Реализация триггеров SQL основана на стандарте SQL. Он поддерживает конструкции, которые являются общими для большинства языков программирования. Он поддерживает объявление локальных переменных, операторы для управления потоком процедуры, присвоение результатов выражений переменным и обработку ошибок.

SQLite: создать триггер

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

Вот синтаксис:

Синтаксис:

 СОЗДАТЬ [ТЕМП | TEMPORARY] TRIGGER имя-триггер
[ДО | ПОСЛЕ] событие базы данных ВКЛ [имя-базы-данных.] Имя-таблицы
спусковой механизм действия
Триггер-действие далее определяется как: 
[ДЛЯ КАЖДОГО РЯДА | ДЛЯ КАЖДОГО ЗАЯВЛЕНИЯ] [КОГДА выражение]
НАЧАТЬ
инициировать шаг; [пошаговый шаг;] *
КОНЕЦ

Параметры:

название Описание
Триггер имя Название триггера. Триггер должен отличаться от имени любого другого триггера для той же таблицы. Имя не может быть дополнено схемой — триггер наследует схему своей таблицы.
ДО
ПОСЛЕ
ВМЕСТО
Определяет, вызывается ли функция до, после или вместо события. Триггер ограничения может быть указан только как AFTER.
базы данных событий Один из INSERT, UPDATE, DELETE, который сработает триггер.
имя-таблицы Имя таблицы или представления триггера для.
ДЛЯ КАЖДОГО РЯДА
ЗА КАЖДУЮ ЗАЯВЛЕНИЕ
Указывает, должна ли процедура триггера запускаться один раз для каждой строки, на которую воздействует событие триггера, или только один раз для оператора SQL. Если ни то, ни другое не указано, значение FOR EACH STATEMENT используется по умолчанию.
выражение Булево выражение, которое определяет, будет ли фактически выполняться функция триггера.
Триггер шаг Действие для триггера, это оператор sql.

Существует два расширения SQLite для триггеров « СТАРЫЙ » и « НОВЫЙ ». СТАРЫЙ и НОВЫЙ не чувствительны к регистру.

  • В теле триггера ключевые слова OLD и NEW позволяют получить доступ к столбцам в строках, затронутых триггером.
  • В триггере INSERT можно использовать только NEW.col_name.
  • В триггере UPDATE вы можете использовать OLD.col_name для ссылки на столбцы строки перед ее обновлением и NEW.col_name для ссылки на столбцы строки после ее обновления.
  • В триггере DELETE может использоваться только OLD.col_name; нового ряда нет

Пример базы данных, таблица, структура таблицы, записи таблицы для различных примеров

emp_details

Триггер SQLite: пример ПОСЛЕ ВСТАВКИ

В следующем примере у нас есть две таблицы: emp_details и emp_log. Чтобы вставить некоторую информацию в таблицу emp_logs (которая имеет три поля emp_id и salary и edttime) каждый раз, когда в таблицу emp_details входит INSERT, мы использовали следующий триггер:

Вот триггер ins_same_rec:

CREATE TRIGGER aft_insert AFTER INSERT ON emp_details
BEGIN
INSERT INTO emp_log(emp_id,salary,edittime)
         VALUES(NEW.employee_id,NEW.salary,current_date);
END;

Записи таблицы (по некоторым столбцам): emp_details

 sqlite> ВЫБРАТЬ EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB_ID, SALARY, COMMISSION_PCT FROM emp_details;
ИД сотрудника имя_ фамилии Фамилия задания № зарплаты комиссионное вознаграждение
----------- ---------- ---------- ---------- --------- - --------------
100 Стивен Кинг AD_PRES 24000
101 Neena Kochhar AD_VP 17000
102 Lex De Haan AD_VP 17000
103 Александр Хунольд IT_PROG 9000
104 Брюс Эрнст IT_PROG 6000
105 Дэвид Остин IT_PROG 4800
106 Valli Pataballa IT_PROG 4800
107 Диана Лоренц IT_PROG 4200
108 Нэнси Гринберг FI_MGR 12000
109 Даниэль Фавиет FI_ACCOUNT 9000
110 Джон Чен FI_ACCOUNT 8200
111 Исмаэль Скарра FI_ACCOUNT 7700
112 Хосе Мануэ Урман FI_ACCOUNT 7800

Записи таблицы (все столбцы): emp_log

 sqlite> SELECT * FROM emp_log;
время редактирования зарплаты emp_id
---------- ---------- ----------
100 24000 2011-01-15
101 17000 2010-01-12
102 17000 2010-09-22
103 9000 2011-06-21
104 6000 2012-07-05
105 4800 2011-06-02

Теперь вставьте одну запись в таблицу emp_details, просмотрите записи в таблицах emp_details и emp_log:

INSERT INTO emp_details 
VALUES(236, 'RABI', 'CHANDRA', 'RABI','590.423.45700', '2013-01-12', 'AD_VP', 15000, .5,NULL,NULL);

 sqlite> ВЫБРАТЬ EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB_ID, SALARY, COMMISSION_PCT FROM emp_details;
ИД сотрудника имя_ фамилии Фамилия задания № зарплаты комиссионное вознаграждение
----------- ---------- ---------- ---------- --------- - --------------
100 Стивен Кинг AD_PRES 24000
101 Neena Kochhar AD_VP 17000
102 Lex De Haan AD_VP 17000
103 Александр Хунольд IT_PROG 9000
104 Брюс Эрнст IT_PROG 6000
105 Дэвид Остин IT_PROG 4800
106 Valli Pataballa IT_PROG 4800
107 Диана Лоренц IT_PROG 4200
108 Нэнси Гринберг FI_MGR 12000
109 Даниэль Фавиет FI_ACCOUNT 9000
110 Джон Чен FI_ACCOUNT 8200
111 Исмаэль Скарра FI_ACCOUNT 7700
112 Хосе Мануэ Урман FI_ACCOUNT 7800
236 RABI CHANDRA AD_VP 15000 0,5
 sqlite> SELECT * FROM emp_log;
время редактирования зарплаты emp_id
---------- ---------- ----------
100 24000 2011-01-15
101 17000 2010-01-12
102 17000 2010-09-22
103 9000 2011-06-21
104 6000 2012-07-05
105 4800 2011-06-02
236 15000 2014-10-13

itemscope itemtype = «http://schema.org/WebPageElement/Heading»> Триггер SQLite: пример перед вставкой

В следующем примере перед вставкой новой записи в таблицу emp_details триггер проверяет значение столбца FIRST_NAME, LAST_NAME, JOB_ID и
— Если есть пробелы перед или после FIRST_NAME, функция LAST_NAME, LTRIM () удалит их.
— Значение JOB_ID будет преобразовано в верхний регистр функцией UPPER ().

Вот триггер befo_insert:

CREATE TRIGGER befo_insert BEFORE INSERT ON emp_details
BEGIN
SELECT CASE 
WHEN ((SELECT emp_details . employee_id FROM emp_details WHERE emp_details.employee_id = NEW.employee_id ) ISNULL) 
THEN RAISE(ABORT, 'This is an User Define Error Message - This employee_id does not exist.') 
END; 
END;

Теперь вставьте строку в таблицу emp_details (проверьте столбец employee_id, существует ли она или нет.):

INSERT INTO emp_details(employee_id,first_name,last_name)values(250,'Jeson','Flap');

Теперь вот вывод.

 sqlite> INSERT INTO emp_details (employee_id, first_name, last_name) значения (250, 'Jeson', 'Flap');
Ошибка: это сообщение об ошибке, определяемое пользователем. Этот employee_id не существует.

Триггер SQLite: пример ПОСЛЕ ОБНОВЛЕНИЯ

У нас есть две таблицы student_mast и stu_log. student_mast имеет три столбца: STUDENT_ID, NAME, ST_CLASS. Таблица stu_log имеет два столбца user_id и описание.

 sqlite> SELECT * FROM student_mast;
имя студента
---------- ------------------------------ ----------
1 Стивен Кинг 7
2 Нина Коххар 8
3 Лекс Де Хаан 9
4 Александр Хунольд 10

Пусть мы продвинем всех учеников в следующем классе, т.е. 7 будет 8, 8 будет 9 и так далее. После обновления одной строки в таблице student_mast в таблицу stu_log будет вставлена новая строка, в которой мы будем хранить текущий идентификатор пользователя и небольшое описание текущего обновления. Вот код триггера:

Вот триггер для этого события

CREATE TRIGGER aft_update AFTER UPDATE ON student_mast
BEGIN
INSERT into stu_log (description) values('Update Student Record '||
         OLD.NAME || '    Previous Class : '||OLD.ST_CLASS ||'    Present Class '||
         NEW.st_class);
END;

Теперь обновите таблицу student_mast:

UPDATE student_mast SET st_class = st_class + 1;

Триггер показывает вам обновленные записи в «stu_log». Вот последняя позиция таблиц student_mast и stu_log:

 sqlite> SELECT * FROM student_mast;
имя студента
---------- -------------------- ----------
1 Стивен Кинг 8
2 Неена Коххар 9
3 Лекс Де Хаан 10
4 Александр Хунольд 11
 sqlite> ВЫБРАТЬ описание ОТ stu_log;
описание
-------------------------------------------------- ------------------------------------
Обновление студенческих записей Стивена Кинга Предыдущий класс: 7 Настоящий класс 8
Обновить студенческий билет Neena Kochhar Предыдущий класс: 8 Текущий класс 9
Обновить студенческие записи Lex De Haan Предыдущий класс: 9 Настоящий класс 10
Обновить студенческие записи Александра Хунольда Предыдущий класс: 10 Настоящий класс 11
sqlite> SELECT * FROM student_mast;

Триггер SQLite: пример перед обновлением

У нас есть две таблицы student_mast и student_marks. Вот примеры таблиц ниже. Столбец student_id таблицы student_mast является первичным ключом, а в таблице student_mast это внешний ключ, ссылка на столбец student_id таблицы student_mast.

 Таблица - student_mast;
имя студента
---------- ------------------------------ ----------
1 Стивен Кинг 7
2 Нина Коххар 8
3 Лекс Де Хаан 9
4 Александр Хунольд 10
Таблица - Student_marks
имя студента sub1 sub1 sub2
---------- -------------------- ---------- ---------
1 Стивен Кинг
2 Нина Кочхар
3 Лекс Де Хаан
4 Александр Хунольд

Вот триггер

CREATE TRIGGER befo_update BEFORE UPDATE ON student_mast
BEGIN
SELECT CASE 
WHEN ((SELECT student_id FROM student_marks WHERE student_id = NEW.student_id ) ISNULL) 
THEN RAISE(ABORT, 'This is a User Define Error Message - This ID can not be updated.') 
END; 
END;

Теперь мы собираемся обновить столбец первичного ключа таблицы student_mast и посмотреть результат ниже.

 sqlite> ОБНОВЛЕНИЕ student_mast SET student_id = 10 ГДЕ st_class = 9;
Ошибка: это сообщение об ошибке определения пользователя - этот идентификатор не может быть обновлен.

Триггер SQLite: пример ПОСЛЕ УДАЛЕНИЯ

В нашем примере «AFTER UPDATE» у нас было две таблицы student_mast и stu_log. student_mast состоит из трех столбцов STUDENT_ID, NAME, ST_CLASS и таблица stu_log имеет два столбца user_id и description. Мы хотим сохранить некоторую информацию в таблице stu_log после того, как в таблице student_mast произошла операция удаления. Вот триггер:

Вот триггер

CREATE TRIGGER aft_delete AFTER DELETE ON student_mast 
BEGIN 
INSERT into stu_log (description) VALUES ('Update Student Record '||
         OLD.NAME||' Class : '||OLD.ST_CLASS||' -> Deleted on  '||
         date('NOW')); 
END;

Позвольте удалить студента из student_mast

sqlite> DELETE FROM STUDENT_MAST WHERE STUDENT_ID = 1;

Вот последняя позиция таблиц student_mast, stu_log:

 sqlite> SELECT * FROM STUDENT_MAST;
имя студента
---------- -------------------- ---------
2 Неена Коххар 9
3 Лекс Де Хаан 10
4 Александр Гунольд 11
sqlite> ВЫБРАТЬ описание ОТ stu_log;
описание
-------------------------------------------------- ----------------------------------
Обновление студенческих записей Стивена Кинга Предыдущий класс: 7 Настоящий класс 8
Обновить студенческий билет Neena Kochhar Предыдущий класс: 8 Текущий класс 9
Обновить студенческие записи Lex De Haan Предыдущий класс: 9 Настоящий класс 10
Обновить студенческие записи Александра Хунольда Предыдущий класс: 10 Настоящий класс 11
Обновление студенческого рекорда Стивена Кинга Класс: 8 -> Удалено 2014-10-13

Триггер SQLite: пример перед удалением

У нас есть две таблицы student_mast и student_marks. Вот примеры таблиц ниже. Столбец student_id таблицы student_mast — это первичный ключ, а в таблице student_mast — это внешний ключ, ссылка на столбец student_id таблицы student_mast.

 Таблица - student_mast;
имя студента
---------- ------------------------------ ----------
1 Стивен Кинг 7
2 Нина Коххар 8
3 Лекс Де Хаан 9
4 Александр Хунольд 10
Таблица - Student_marks
имя студента sub1 sub1 sub2
---------- -------------------- ---------- ---------
1 Стивен Кинг
2 Нина Кочхар
3 Лекс Де Хаан
4 Александр Хунольд

Вот триггер

CREATE TRIGGER befo_delete BEFORE DELETE ON student_marks
BEGIN
SELECT CASE 
WHEN (SELECT COUNT(student_id) FROM student_mast WHERE student_id=OLD.student_id) > 0
THEN RAISE(ABORT,
'Foreign Key Violation: student_masts rows reference row to be deleted.')
END; 
END;

Давайте попробуем удалить студента из student_marks и посмотреть результат.

 sqlite> DELETE FROM student_marks WHERE name = 'Стивен Кинг';
Ошибка: Нарушение внешнего ключа: строка_стадии ссылается на строку, подлежащую удалению.

Триггер SQLite с использованием INSTEAD OF

Вот пример таблицы emp_details.

 сотрудник_ид имя_фамилия фамилия электронная почта      
----------- ---------- ---------- ---------- 
100 Стивен Кинг СКИНГ      
101 Нина Кочхар НКОЧХАР   
102 Лекс Де Хаан LDEHAAN    
103 Александр Хунольд AHUNOLD    
104 Брюс Эрнст БЕРНСТ     
105 Дэвид Остин ДАУСТИН    
106 Valli Pataballa VPATABAL   
107 Диана Лоренц ДЛОРЕНЦ   
108 Нэнси Гринберг НГРИНБЕ   
109 Даниэль Фавиет ДФАВЬЕТ    
110 Джон Чен JCHEN      
111 Исмаэль Скиарра ИСКЬАРРА   
112 Хосе Мануэ Урман JMURMAN    
236 РАБИ ЧАНДРА РАБИ       

Теперь создайте имя представления emp_details_view.

CREATE VIEW emp_details_view
AS
SELECT employee_id,first_name,last_name,email
FROM emp_details
ORDER BY first_name,last_name;

Теперь посмотрите только что созданный вид.

 sqlite> ВЫБЕРИТЕ имя ОТ sqlite_master WHERE type = 'view';
название
emp_details_view

Вот мнение.

 сотрудник_ид имя_фамилия фамилия электронная почта
----------- ---------- ---------- ----------
103 Александр Хунольд AHUNOLD
104 Брюс Эрнст БЕРНСТ
109 Даниэль Фавиет ДФАВЬЕТ
105 Дэвид Остин ДАУСТИН
107 Диана Лоренц ДЛОРЕНЦ
111 Исмаэль Скиарра ИСКЬАРРА
110 Джон Чен JCHEN
112 Хосе Мануэ Урман JMURMAN
102 Лекс Де Хаан LDEHAAN
108 Нэнси Гринберг НГРИНБЕ
101 Нина Кочхар НКОЧХАР
236 РАБИ ЧАНДРА РАБИ
100 Стивен Кинг СКИНГ
106 Valli Pataballa VPATABAL

ВСТАВИТЬ ТРИГГЕР, используя INSTEAD OF

Вот пример

CREATE TRIGGER view_ins_trig 
INSTEAD OF INSERT 
ON emp_details_view 
BEGIN
        INSERT INTO emp_details(employee_id,first_name,last_name,email) 
        SELECT new.employee_id, new.first_name,new.last_name,new.email; 
END;

Теперь вставьте строки в emp_details_view, и триггеры распространят эти изменения в базовой таблице.

INSERT INTO emp_details_view (employee_id,first_name,last_name,email) 
VALUES (250,'Andrai', 'Marku','and_mar');

Теперь посмотрим на вид и базовую таблицу

 базовая таблица - emp_details
сотрудник_ид имя_фамилия фамилия электронная почта
-------------------- ---------- ---------- ----------
100 Стивен Кинг СКИНГ
101 Нина Кочхар НКОЧХАР
102 Лекс Де Хаан LDEHAAN
103 Александр Хунольд AHUNOLD
104 Брюс Эрнст БЕРНСТ
105 Дэвид Остин ДАУСТИН
106 Valli Pataballa VPATABAL
107 Диана Лоренц ДЛОРЕНЦ
108 Нэнси Гринберг НГРИНБЕ
109 Даниэль Фавиет ДФАВЬЕТ
110 Джон Чен JCHEN
111 Исмаэль Скиарра ИСКЬАРРА
112 Хосе Мануэ Урман JMURMAN
236 РАБИ ЧАНДРА РАБИ
250 Andrai Marku and_mar
view - emp_details_view
сотрудник_ид имя_фамилия фамилия электронная почта
-------------------- ---------- ---------- ----------
103 Александр Хунольд AHUNOLD
250 Andrai Marku and_mar
104 Брюс Эрнст БЕРНСТ
109 Даниэль Фавиет ДФАВЬЕТ
105 Дэвид Остин ДАУСТИН
107 Диана Лоренц ДЛОРЕНЦ
111 Исмаэль Скиарра ИСКЬАРРА
110 Джон Чен JCHEN
112 Хосе Мануэ Урман JMURMAN
102 Лекс Де Хаан LDEHAAN
108 Нэнси Гринберг НГРИНБЕ
101 Нина Кочхар НКОЧХАР
236 РАБИ ЧАНДРА РАБИ
100 Стивен Кинг СКИНГ
106 Valli Pataballa VPATABAL

ОБНОВИТЬ ТРИГГЕР, используя INSTEAD OF

Вот пример

CREATE TRIGGER view_update_trig 
INSTEAD OF UPDATE 
ON emp_details_view 
BEGIN 
        UPDATE emp_details 
        SET employee_id = new.employee_id, first_name = new.first_name, last_name = new.last_name        
WHERE employee_id = old.employee_id; 
END;

Теперь обновите строки в emp_details_view.

UPDATE emp_details_view SET first_name ='Andrai' 
WHERE first_name ='RABI' AND last_name='CHANDRA';
 

Теперь посмотрим на вид и базовую таблицу

 базовая таблица - emp_details
сотрудник_ид имя_фамилия фамилия электронная почта
-------------------- ---------- ---------- ----------
100 Стивен Кинг СКИНГ
101 Нина Кочхар НКОЧХАР
102 Лекс Де Хаан LDEHAAN
103 Александр Хунольд AHUNOLD
104 Брюс Эрнст БЕРНСТ
105 Дэвид Остин ДАУСТИН
106 Valli Pataballa VPATABAL
107 Диана Лоренц ДЛОРЕНЦ
108 Нэнси Гринберг НГРИНБЕ
109 Даниэль Фавиет ДФАВЬЕТ
110 Джон Чен JCHEN
111 Исмаэль Скиарра ИСКЬАРРА
112 Хосе Мануэ Урман JMURMAN
236 Андрей ЧАНДРА РАБИ
view - emp_details_view
сотрудник_ид имя_фамилия фамилия электронная почта
-------------------- ---------- ---------- ----------
103 Александр Хунольд AHUNOLD
236 Андрей ЧАНДРА РАБИ
104 Брюс Эрнст БЕРНСТ
109 Даниэль Фавиет ДФАВЬЕТ
105 Дэвид Остин ДАУСТИН
107 Диана Лоренц ДЛОРЕНЦ
111 Исмаэль Скиарра ИСКЬАРРА
110 Джон Чен JCHEN
112 Хосе Мануэ Урман JMURMAN
102 Лекс Де Хаан LDEHAAN
108 Нэнси Гринберг НГРИНБЕ
101 Нина Кочхар НКОЧХАР
100 Стивен Кинг СКИНГ
106 Valli Pataballa VPATABAL

УДАЛИТЬ ТРИГГЕРА, используя INSTEAD OF

Вот пример

CREATE TRIGGER view_delete_trig 
INSTEAD OF delete 
ON emp_details_view
BEGIN 
        DELETE FROM emp_details 
		WHERE employee_id = old.employee_id; 
END;

Теперь удалите строку из emp_details_view, которую employee_id равно 106, и посмотрите результат.

DELETE FROM emp_details_view 
WHERE employee_id = 106; 

Теперь посмотрим на вид и базовую таблицу

 базовая таблица - emp_details
сотрудник_ид имя_фамилия фамилия электронная почта
-------------------- ---------- ---------- ----------
100 Стивен Кинг СКИНГ
101 Нина Кочхар НКОЧХАР
102 Лекс Де Хаан LDEHAAN
103 Александр Хунольд AHUNOLD
104 Брюс Эрнст БЕРНСТ
105 Дэвид Остин ДАУСТИН
107 Диана Лоренц ДЛОРЕНЦ
108 Нэнси Гринберг НГРИНБЕ
109 Даниэль Фавиет ДФАВЬЕТ
110 Джон Чен JCHEN
111 Исмаэль Скиарра ИСКЬАРРА
112 Хосе Мануэ Урман JMURMAN
236 Андрей ЧАНДРА РАБИ
view - emp_details_view
сотрудник_ид имя_фамилия фамилия электронная почта
-------------------- ---------- ---------- ----------
103 Александр Хунольд AHUNOLD
236 Андрей ЧАНДРА РАБИ
104 Брюс Эрнст БЕРНСТ
109 Даниэль Фавиет ДФАВЬЕТ
105 Дэвид Остин ДАУСТИН
107 Диана Лоренц ДЛОРЕНЦ
111 Исмаэль Скиарра ИСКЬАРРА
110 Джон Чен JCHEN
112 Хосе Мануэ Урман JMURMAN
102 Лекс Де Хаан LDEHAAN
108 Нэнси Гринберг НГРИНБЕ
101 Нина Кочхар НКОЧХАР
100 Стивен Кинг СКИНГ

Была удалена строка, содержащая идентификатор employee_id 106.

УДАЛИТЬ триггер SQLite

Чтобы удалить или уничтожить триггер, используйте оператор DROP TRIGGER. Для выполнения этой команды текущий пользователь должен быть владельцем таблицы, для которой определен триггер.

Синтаксис:

 DROP TRIGGER имя-триггера

Пример:

Если вы удалите или удалите только что созданный триггер delete_stu, можно использовать следующий оператор:

DROP TRIGGER delete_stu on student_mast;

Триггер delete_stu будет удален.

Предыдущая: Подзапросы
Далее: Упражнения SQLite Введение

Overview

Many of the routines in the SQLite C-language Interface return
numeric result codes indicating either success or failure, and
in the event of a failure, providing some idea of the cause of
the failure. This document strives to explain what each
of those numeric result codes means.

«Error codes» are a subset of «result codes» that indicate that
something has gone wrong. There are only a few non-error result
codes: SQLITE_OK, SQLITE_ROW, and SQLITE_DONE. The term
«error code» means any result code other than these three.

2. Primary Result Codes versus Extended Result Codes

Result codes are signed 32-bit integers.
The least significant 8 bits of the result code define a broad category
and are called the «primary result code». More significant bits provide
more detailed information about the error and are called the
«extended result code»

Note that the primary result code is always a part of the extended
result code. Given a full 32-bit extended result code, the application
can always find the corresponding primary result code merely by extracting
the least significant 8 bits of the extended result code.

All extended result codes are also error codes. Hence the terms
«extended result code» and «extended error code» are interchangeable.

For historic compatibility, the C-language interfaces return
primary result codes by default.
The extended result code for the most recent error can be
retrieved using the sqlite3_extended_errcode() interface.
The sqlite3_extended_result_codes() interface can be used to put
a database connection into a mode where it returns the
extended result codes instead of the primary result codes.

3. Definitions

All result codes are integers.
Symbolic names for all result codes are created using
«#define» macros in the sqlite3.h header file.
There are separate sections in the sqlite3.h header file for
the result code definitions and the extended result code definitions.

Primary result code symbolic names are of the form «SQLITE_XXXXXX» where
XXXXXX is a sequence of uppercase alphabetic characters. Extended
result code names are of the form «SQLITE_XXXXXX_YYYYYYY» where
the XXXXXX part is the corresponding primary result code and the
YYYYYYY is an extension that further classifies the result code.

The names and numeric values for existing result codes are fixed
and unchanging. However, new result codes, and especially new extended
result codes, might appear in future releases of SQLite.

4. Primary Result Code List

The 31 result codes are
defined in sqlite3.h and are listed in
alphabetical order below:

  • SQLITE_ABORT (4)
  • SQLITE_AUTH (23)
  • SQLITE_BUSY (5)
  • SQLITE_CANTOPEN (14)
  • SQLITE_CONSTRAINT (19)
  • SQLITE_CORRUPT (11)
  • SQLITE_DONE (101)
  • SQLITE_EMPTY (16)
  • SQLITE_ERROR (1)
  • SQLITE_FORMAT (24)
  • SQLITE_FULL (13)
  • SQLITE_INTERNAL (2)
  • SQLITE_INTERRUPT (9)
  • SQLITE_IOERR (10)
  • SQLITE_LOCKED (6)
  • SQLITE_MISMATCH (20)
  • SQLITE_MISUSE (21)
  • SQLITE_NOLFS (22)
  • SQLITE_NOMEM (7)
  • SQLITE_NOTADB (26)
  • SQLITE_NOTFOUND (12)
  • SQLITE_NOTICE (27)
  • SQLITE_OK (0)
  • SQLITE_PERM (3)
  • SQLITE_PROTOCOL (15)
  • SQLITE_RANGE (25)
  • SQLITE_READONLY (8)
  • SQLITE_ROW (100)
  • SQLITE_SCHEMA (17)
  • SQLITE_TOOBIG (18)
  • SQLITE_WARNING (28)

5. Extended Result Code List

The 74 extended result codes
are defined in sqlite3.h and are
listed in alphabetical order below:

  • SQLITE_ABORT_ROLLBACK (516)
  • SQLITE_AUTH_USER (279)
  • SQLITE_BUSY_RECOVERY (261)
  • SQLITE_BUSY_SNAPSHOT (517)
  • SQLITE_BUSY_TIMEOUT (773)
  • SQLITE_CANTOPEN_CONVPATH (1038)
  • SQLITE_CANTOPEN_DIRTYWAL (1294)
  • SQLITE_CANTOPEN_FULLPATH (782)
  • SQLITE_CANTOPEN_ISDIR (526)
  • SQLITE_CANTOPEN_NOTEMPDIR (270)
  • SQLITE_CANTOPEN_SYMLINK (1550)
  • SQLITE_CONSTRAINT_CHECK (275)
  • SQLITE_CONSTRAINT_COMMITHOOK (531)
  • SQLITE_CONSTRAINT_DATATYPE (3091)
  • SQLITE_CONSTRAINT_FOREIGNKEY (787)
  • SQLITE_CONSTRAINT_FUNCTION (1043)
  • SQLITE_CONSTRAINT_NOTNULL (1299)
  • SQLITE_CONSTRAINT_PINNED (2835)
  • SQLITE_CONSTRAINT_PRIMARYKEY (1555)
  • SQLITE_CONSTRAINT_ROWID (2579)
  • SQLITE_CONSTRAINT_TRIGGER (1811)
  • SQLITE_CONSTRAINT_UNIQUE (2067)
  • SQLITE_CONSTRAINT_VTAB (2323)
  • SQLITE_CORRUPT_INDEX (779)
  • SQLITE_CORRUPT_SEQUENCE (523)
  • SQLITE_CORRUPT_VTAB (267)
  • SQLITE_ERROR_MISSING_COLLSEQ (257)
  • SQLITE_ERROR_RETRY (513)
  • SQLITE_ERROR_SNAPSHOT (769)
  • SQLITE_IOERR_ACCESS (3338)
  • SQLITE_IOERR_AUTH (7178)
  • SQLITE_IOERR_BEGIN_ATOMIC (7434)
  • SQLITE_IOERR_BLOCKED (2826)
  • SQLITE_IOERR_CHECKRESERVEDLOCK (3594)
  • SQLITE_IOERR_CLOSE (4106)
  • SQLITE_IOERR_COMMIT_ATOMIC (7690)
  • SQLITE_IOERR_CONVPATH (6666)
  • SQLITE_IOERR_CORRUPTFS (8458)
  • SQLITE_IOERR_DATA (8202)
  • SQLITE_IOERR_DELETE (2570)
  • SQLITE_IOERR_DELETE_NOENT (5898)
  • SQLITE_IOERR_DIR_CLOSE (4362)
  • SQLITE_IOERR_DIR_FSYNC (1290)
  • SQLITE_IOERR_FSTAT (1802)
  • SQLITE_IOERR_FSYNC (1034)
  • SQLITE_IOERR_GETTEMPPATH (6410)
  • SQLITE_IOERR_LOCK (3850)
  • SQLITE_IOERR_MMAP (6154)
  • SQLITE_IOERR_NOMEM (3082)
  • SQLITE_IOERR_RDLOCK (2314)
  • SQLITE_IOERR_READ (266)
  • SQLITE_IOERR_ROLLBACK_ATOMIC (7946)
  • SQLITE_IOERR_SEEK (5642)
  • SQLITE_IOERR_SHMLOCK (5130)
  • SQLITE_IOERR_SHMMAP (5386)
  • SQLITE_IOERR_SHMOPEN (4618)
  • SQLITE_IOERR_SHMSIZE (4874)
  • SQLITE_IOERR_SHORT_READ (522)
  • SQLITE_IOERR_TRUNCATE (1546)
  • SQLITE_IOERR_UNLOCK (2058)
  • SQLITE_IOERR_VNODE (6922)
  • SQLITE_IOERR_WRITE (778)
  • SQLITE_LOCKED_SHAREDCACHE (262)
  • SQLITE_LOCKED_VTAB (518)
  • SQLITE_NOTICE_RECOVER_ROLLBACK (539)
  • SQLITE_NOTICE_RECOVER_WAL (283)
  • SQLITE_OK_LOAD_PERMANENTLY (256)
  • SQLITE_READONLY_CANTINIT (1288)
  • SQLITE_READONLY_CANTLOCK (520)
  • SQLITE_READONLY_DBMOVED (1032)
  • SQLITE_READONLY_DIRECTORY (1544)
  • SQLITE_READONLY_RECOVERY (264)
  • SQLITE_READONLY_ROLLBACK (776)
  • SQLITE_WARNING_AUTOINDEX (284)

6. Result Code Meanings

The meanings for all 105
result code values are shown below,
in numeric order.

(0) SQLITE_OK

The SQLITE_OK result code means that the operation was successful and
that there were no errors. Most other result codes indicate an error.

(1) SQLITE_ERROR

The SQLITE_ERROR result code is a generic error code that is used when
no other more specific error code is available.

(2) SQLITE_INTERNAL

The SQLITE_INTERNAL result code indicates an internal malfunction.
In a working version of SQLite, an application should never see this
result code. If application does encounter this result code, it shows
that there is a bug in the database engine.

SQLite does not currently generate this result code.
However, application-defined SQL functions or
virtual tables, or VFSes, or other extensions might cause this
result code to be returned.

(3) SQLITE_PERM

The SQLITE_PERM result code indicates that the requested access mode
for a newly created database could not be provided.

(4) SQLITE_ABORT

The SQLITE_ABORT result code indicates that an operation was aborted
prior to completion, usually be application request.
See also: SQLITE_INTERRUPT.

If the callback function to sqlite3_exec() returns non-zero, then
sqlite3_exec() will return SQLITE_ABORT.

If a ROLLBACK operation occurs on the same database connection as
a pending read or write, then the pending read or write may fail with
an SQLITE_ABORT or SQLITE_ABORT_ROLLBACK error.

In addition to being a result code,
the SQLITE_ABORT value is also used as a conflict resolution mode
returned from the sqlite3_vtab_on_conflict() interface.

(5) SQLITE_BUSY

The SQLITE_BUSY result code indicates that the database file could not
be written (or in some cases read) because of concurrent activity by
some other database connection, usually a database connection in a
separate process.

For example, if process A is in the middle of a large write transaction
and at the same time process B attempts to start a new write transaction,
process B will get back an SQLITE_BUSY result because SQLite only supports
one writer at a time. Process B will need to wait for process A to finish
its transaction before starting a new transaction. The
sqlite3_busy_timeout() and sqlite3_busy_handler() interfaces and
the busy_timeout pragma are available to process B to help it deal
with SQLITE_BUSY errors.

An SQLITE_BUSY error can occur at any point in a transaction: when the
transaction is first started, during any write or update operations, or
when the transaction commits.
To avoid encountering SQLITE_BUSY errors in the middle of a transaction,
the application can use BEGIN IMMEDIATE instead of just BEGIN to
start a transaction. The BEGIN IMMEDIATE command might itself return
SQLITE_BUSY, but if it succeeds, then SQLite guarantees that no
subsequent operations on the same database through the next COMMIT
will return SQLITE_BUSY.

See also: SQLITE_BUSY_RECOVERY and SQLITE_BUSY_SNAPSHOT.

The SQLITE_BUSY result code differs from SQLITE_LOCKED in that
SQLITE_BUSY indicates a conflict with a
separate database connection, probably in a separate process,
whereas SQLITE_LOCKED
indicates a conflict within the same database connection (or sometimes
a database connection with a shared cache).

(6) SQLITE_LOCKED

The SQLITE_LOCKED result code indicates that a write operation could not
continue because of a conflict within the same database connection or
a conflict with a different database connection that uses a shared cache.

For example, a DROP TABLE statement cannot be run while another thread
is reading from that table on the same database connection because
dropping the table would delete the table out from under the concurrent
reader.

The SQLITE_LOCKED result code differs from SQLITE_BUSY in that
SQLITE_LOCKED indicates a conflict on the same database connection
(or on a connection with a shared cache) whereas SQLITE_BUSY indicates
a conflict with a different database connection, probably in a different
process.

(7) SQLITE_NOMEM

The SQLITE_NOMEM result code indicates that SQLite was unable to allocate
all the memory it needed to complete the operation. In other words, an
internal call to sqlite3_malloc() or sqlite3_realloc() has failed in
a case where the memory being allocated was required in order to continue
the operation.

(8) SQLITE_READONLY

The SQLITE_READONLY result code is returned when an attempt is made to
alter some data for which the current database connection does not have
write permission.

(9) SQLITE_INTERRUPT

The SQLITE_INTERRUPT result code indicates that an operation was
interrupted by the sqlite3_interrupt() interface.
See also: SQLITE_ABORT

(10) SQLITE_IOERR

The SQLITE_IOERR result code says that the operation could not finish
because the operating system reported an I/O error.

A full disk drive will normally give an SQLITE_FULL error rather than
an SQLITE_IOERR error.

There are many different extended result codes for I/O errors that
identify the specific I/O operation that failed.

(11) SQLITE_CORRUPT

The SQLITE_CORRUPT result code indicates that the database file has
been corrupted. See the How To Corrupt Your Database Files for
further discussion on how corruption can occur.

(12) SQLITE_NOTFOUND

The SQLITE_NOTFOUND result code is exposed in three ways:

  1. SQLITE_NOTFOUND can be returned by the sqlite3_file_control() interface
    to indicate that the file control opcode passed as the third argument
    was not recognized by the underlying VFS.

  2. SQLITE_NOTFOUND can also be returned by the xSetSystemCall() method of
    an sqlite3_vfs object.

  3. SQLITE_NOTFOUND an be returned by sqlite3_vtab_rhs_value() to indicate
    that the right-hand operand of a constraint is not available to the
    xBestIndex method that made the call.

The SQLITE_NOTFOUND result code is also used
internally by the SQLite implementation, but those internal uses are
not exposed to the application.

(13) SQLITE_FULL

The SQLITE_FULL result code indicates that a write could not complete
because the disk is full. Note that this error can occur when trying
to write information into the main database file, or it can also
occur when writing into temporary disk files.

Sometimes applications encounter this error even though there is an
abundance of primary disk space because the error occurs when writing
into temporary disk files on a system where temporary files are stored
on a separate partition with much less space that the primary disk.

(14) SQLITE_CANTOPEN

The SQLITE_CANTOPEN result code indicates that SQLite was unable to
open a file. The file in question might be a primary database file
or one of several temporary disk files.

(15) SQLITE_PROTOCOL

The SQLITE_PROTOCOL result code indicates a problem with the file locking
protocol used by SQLite. The SQLITE_PROTOCOL error is currently only
returned when using WAL mode and attempting to start a new transaction.
There is a race condition that can occur when two separate
database connections both try to start a transaction at the same time
in WAL mode. The loser of the race backs off and tries again, after
a brief delay. If the same connection loses the locking race dozens
of times over a span of multiple seconds, it will eventually give up and
return SQLITE_PROTOCOL. The SQLITE_PROTOCOL error should appear in practice
very, very rarely, and only when there are many separate processes all
competing intensely to write to the same database.

(16) SQLITE_EMPTY

The SQLITE_EMPTY result code is not currently used.

(17) SQLITE_SCHEMA

The SQLITE_SCHEMA result code indicates that the database schema
has changed. This result code can be returned from sqlite3_step() for
a prepared statement that was generated using sqlite3_prepare() or
sqlite3_prepare16(). If the database schema was changed by some other
process in between the time that the statement was prepared and the time
the statement was run, this error can result.

If a prepared statement is generated from sqlite3_prepare_v2() then
the statement is automatically re-prepared if the schema changes, up to
SQLITE_MAX_SCHEMA_RETRY times (default: 50). The sqlite3_step()
interface will only return SQLITE_SCHEMA back to the application if
the failure persists after these many retries.

(18) SQLITE_TOOBIG

The SQLITE_TOOBIG error code indicates that a string or BLOB was
too large. The default maximum length of a string or BLOB in SQLite is
1,000,000,000 bytes. This maximum length can be changed at compile-time
using the SQLITE_MAX_LENGTH compile-time option, or at run-time using
the sqlite3_limit(db,SQLITE_LIMIT_LENGTH,…) interface. The
SQLITE_TOOBIG error results when SQLite encounters a string or BLOB
that exceeds the compile-time or run-time limit.

The SQLITE_TOOBIG error code can also result when an oversized SQL
statement is passed into one of the sqlite3_prepare_v2() interfaces.
The maximum length of an SQL statement defaults to a much smaller
value of 1,000,000,000 bytes. The maximum SQL statement length can be
set at compile-time using SQLITE_MAX_SQL_LENGTH or at run-time
using sqlite3_limit(db,SQLITE_LIMIT_SQL_LENGTH,…).

(19) SQLITE_CONSTRAINT

The SQLITE_CONSTRAINT error code means that an SQL constraint violation
occurred while trying to process an SQL statement. Additional information
about the failed constraint can be found by consulting the
accompanying error message (returned via sqlite3_errmsg() or
sqlite3_errmsg16()) or by looking at the extended error code.

The SQLITE_CONSTRAINT code can also be used as the return value from
the xBestIndex() method of a virtual table implementation. When
xBestIndex() returns SQLITE_CONSTRAINT, that indicates that the particular
combination of inputs submitted to xBestIndex() cannot result in a
usable query plan and should not be given further consideration.

(20) SQLITE_MISMATCH

The SQLITE_MISMATCH error code indicates a datatype mismatch.

SQLite is normally very forgiving about mismatches between the type of
a value and the declared type of the container in which that value is
to be stored. For example, SQLite allows the application to store
a large BLOB in a column with a declared type of BOOLEAN. But in a few
cases, SQLite is strict about types. The SQLITE_MISMATCH error is
returned in those few cases when the types do not match.

The rowid of a table must be an integer. Attempt to set the rowid
to anything other than an integer (or a NULL which will be automatically
converted into the next available integer rowid) results in an
SQLITE_MISMATCH error.

(21) SQLITE_MISUSE

The SQLITE_MISUSE return code might be returned if the application uses
any SQLite interface in a way that is undefined or unsupported. For
example, using a prepared statement after that prepared statement has
been finalized might result in an SQLITE_MISUSE error.

SQLite tries to detect misuse and report the misuse using this result code.
However, there is no guarantee that the detection of misuse will be
successful. Misuse detection is probabilistic. Applications should
never depend on an SQLITE_MISUSE return value.

If SQLite ever returns SQLITE_MISUSE from any interface, that means that
the application is incorrectly coded and needs to be fixed. Do not ship
an application that sometimes returns SQLITE_MISUSE from a standard
SQLite interface because that application contains potentially serious bugs.

(22) SQLITE_NOLFS

The SQLITE_NOLFS error can be returned on systems that do not support
large files when the database grows to be larger than what the filesystem
can handle. «NOLFS» stands for «NO Large File Support».

(23) SQLITE_AUTH

The SQLITE_AUTH error is returned when the
authorizer callback indicates that an
SQL statement being prepared is not authorized.

(24) SQLITE_FORMAT

The SQLITE_FORMAT error code is not currently used by SQLite.

(25) SQLITE_RANGE

The SQLITE_RANGE error indices that the parameter number argument
to one of the sqlite3_bind routines or the
column number in one of the sqlite3_column
routines is out of range.

(26) SQLITE_NOTADB

When attempting to open a file, the SQLITE_NOTADB error indicates that
the file being opened does not appear to be an SQLite database file.

(27) SQLITE_NOTICE

The SQLITE_NOTICE result code is not returned by any C/C++ interface.
However, SQLITE_NOTICE (or rather one of its extended error codes)
is sometimes used as the first argument in an sqlite3_log() callback
to indicate that an unusual operation is taking place.

(28) SQLITE_WARNING

The SQLITE_WARNING result code is not returned by any C/C++ interface.
However, SQLITE_WARNING (or rather one of its extended error codes)
is sometimes used as the first argument in an sqlite3_log() callback
to indicate that an unusual and possibly ill-advised operation is
taking place.

(100) SQLITE_ROW

The SQLITE_ROW result code returned by
sqlite3_step() indicates that another row of output is available.

(101) SQLITE_DONE

The SQLITE_DONE result code indicates that an operation has completed.
The SQLITE_DONE result code is most commonly seen as a return value
from sqlite3_step() indicating that the SQL statement has run to
completion. But SQLITE_DONE can also be returned by other multi-step
interfaces such as sqlite3_backup_step().

(256) SQLITE_OK_LOAD_PERMANENTLY

The sqlite3_load_extension() interface loads an
extension into a single
database connection. The default behavior is for that extension to be
automatically unloaded when the database connection closes. However,
if the extension entry point returns SQLITE_OK_LOAD_PERMANENTLY instead
of SQLITE_OK, then the extension remains loaded into the process address
space after the database connection closes. In other words, the
xDlClose methods of the sqlite3_vfs object is not called for the
extension when the database connection closes.

The SQLITE_OK_LOAD_PERMANENTLY return code is useful to
loadable extensions that register new VFSes, for example.

(257) SQLITE_ERROR_MISSING_COLLSEQ

The SQLITE_ERROR_MISSING_COLLSEQ result code means that an SQL
statement could not be prepared because a collating sequence named
in that SQL statement could not be located.

Sometimes when this error code is encountered, the
sqlite3_prepare_v2() routine will convert the error into
SQLITE_ERROR_RETRY and try again to prepare the SQL statement
using a different query plan that does not require the use of
the unknown collating sequence.

(261) SQLITE_BUSY_RECOVERY

The SQLITE_BUSY_RECOVERY error code is an extended error code
for SQLITE_BUSY that indicates that an operation could not continue
because another process is busy recovering a WAL mode database file
following a crash. The SQLITE_BUSY_RECOVERY error code only occurs
on WAL mode databases.

(262) SQLITE_LOCKED_SHAREDCACHE

The SQLITE_LOCKED_SHAREDCACHE result code indicates that access to
an SQLite data record is blocked by another database connection that
is using the same record in shared cache mode. When two or more
database connections share the same cache and one of the connections is
in the middle of modifying a record in that cache, then other connections
are blocked from accessing that data while the modifications are on-going
in order to prevent the readers from seeing a corrupt or partially
completed change.

(264) SQLITE_READONLY_RECOVERY

The SQLITE_READONLY_RECOVERY error code is an extended error code
for SQLITE_READONLY. The SQLITE_READONLY_RECOVERY error code indicates
that a WAL mode database cannot be opened because the database file
needs to be recovered and recovery requires write access but only
read access is available.

(266) SQLITE_IOERR_READ

The SQLITE_IOERR_READ error code is an extended error code
for SQLITE_IOERR indicating an I/O error in the VFS layer
while trying to read from a file on disk. This error might result
from a hardware malfunction or because a filesystem came unmounted
while the file was open.

(267) SQLITE_CORRUPT_VTAB

The SQLITE_CORRUPT_VTAB error code is an extended error code
for SQLITE_CORRUPT used by virtual tables. A virtual table might
return SQLITE_CORRUPT_VTAB to indicate that content in the virtual table
is corrupt.

(270) SQLITE_CANTOPEN_NOTEMPDIR

The SQLITE_CANTOPEN_NOTEMPDIR error code is no longer used.

(275) SQLITE_CONSTRAINT_CHECK

The SQLITE_CONSTRAINT_CHECK error code is an extended error code
for SQLITE_CONSTRAINT indicating that a CHECK constraint failed.

(279) SQLITE_AUTH_USER

The SQLITE_AUTH_USER error code is an extended error code
for SQLITE_AUTH indicating that an operation was attempted on a
database for which the logged in user lacks sufficient authorization.

(283) SQLITE_NOTICE_RECOVER_WAL

The SQLITE_NOTICE_RECOVER_WAL result code is
passed to the callback of
sqlite3_log() when a WAL mode database file is recovered.

(284) SQLITE_WARNING_AUTOINDEX

The SQLITE_WARNING_AUTOINDEX result code is
passed to the callback of
sqlite3_log() whenever automatic indexing is used.
This can serve as a warning to application designers that the
database might benefit from additional indexes.

(513) SQLITE_ERROR_RETRY

The SQLITE_ERROR_RETRY is used internally to provoke sqlite3_prepare_v2()
(or one of its sibling routines for creating prepared statements) to
try again to prepare a statement that failed with an error on the
previous attempt.

(516) SQLITE_ABORT_ROLLBACK

The SQLITE_ABORT_ROLLBACK error code is an extended error code
for SQLITE_ABORT indicating that an SQL statement aborted because
the transaction that was active when the SQL statement first started
was rolled back. Pending write operations always fail with this error
when a rollback occurs. A ROLLBACK will cause a pending read operation
to fail only if the schema was changed within the transaction being rolled
back.

(517) SQLITE_BUSY_SNAPSHOT

The SQLITE_BUSY_SNAPSHOT error code is an extended error code
for SQLITE_BUSY that occurs on WAL mode databases when a database
connection tries to promote a read transaction into a write transaction
but finds that another database connection has already written to the
database and thus invalidated prior reads.

The following scenario illustrates how an SQLITE_BUSY_SNAPSHOT error
might arise:

  1. Process A starts a read transaction on the database and does one
    or more SELECT statement. Process A keeps the transaction open.
  2. Process B updates the database, changing values previous read by
    process A.
  3. Process A now tries to write to the database. But process A’s view
    of the database content is now obsolete because process B has
    modified the database file after process A read from it. Hence
    process A gets an SQLITE_BUSY_SNAPSHOT error.

(518) SQLITE_LOCKED_VTAB

The SQLITE_LOCKED_VTAB result code is not used by the SQLite core, but
it is available for use by extensions. Virtual table implementations
can return this result code to indicate that they cannot complete the
current operation because of locks held by other threads or processes.

The R-Tree extension returns this result code when an attempt is made
to update the R-Tree while another prepared statement is actively reading
the R-Tree. The update cannot proceed because any change to an R-Tree
might involve reshuffling and rebalancing of nodes, which would disrupt
read cursors, causing some rows to be repeated and other rows to be
omitted.

(520) SQLITE_READONLY_CANTLOCK

The SQLITE_READONLY_CANTLOCK error code is an extended error code
for SQLITE_READONLY. The SQLITE_READONLY_CANTLOCK error code indicates
that SQLite is unable to obtain a read lock on a WAL mode database
because the shared-memory file associated with that database is read-only.

(522) SQLITE_IOERR_SHORT_READ

The SQLITE_IOERR_SHORT_READ error code is an extended error code
for SQLITE_IOERR indicating that a read attempt in the VFS layer
was unable to obtain as many bytes as was requested. This might be
due to a truncated file.

(523) SQLITE_CORRUPT_SEQUENCE

The SQLITE_CORRUPT_SEQUENCE result code means that the schema of
the sqlite_sequence table is corrupt. The sqlite_sequence table
is used to help implement the AUTOINCREMENT feature. The
sqlite_sequence table should have the following format:

  CREATE TABLE sqlite_sequence(name,seq);
  

If SQLite discovers that the sqlite_sequence table has any other
format, it returns the SQLITE_CORRUPT_SEQUENCE error.

(526) SQLITE_CANTOPEN_ISDIR

The SQLITE_CANTOPEN_ISDIR error code is an extended error code
for SQLITE_CANTOPEN indicating that a file open operation failed because
the file is really a directory.

(531) SQLITE_CONSTRAINT_COMMITHOOK

The SQLITE_CONSTRAINT_COMMITHOOK error code
is an extended error code
for SQLITE_CONSTRAINT indicating that a
commit hook callback returned non-zero that thus
caused the SQL statement to be rolled back.

(539) SQLITE_NOTICE_RECOVER_ROLLBACK

The SQLITE_NOTICE_RECOVER_ROLLBACK result code is
passed to the callback of
sqlite3_log() when a hot journal is rolled back.

(769) SQLITE_ERROR_SNAPSHOT

The SQLITE_ERROR_SNAPSHOT result code might be returned when attempting
to start a read transaction on an historical version of the database
by using the sqlite3_snapshot_open() interface. If the historical
snapshot is no longer available, then the read transaction will fail
with the SQLITE_ERROR_SNAPSHOT. This error code is only possible if
SQLite is compiled with -DSQLITE_ENABLE_SNAPSHOT.

(773) SQLITE_BUSY_TIMEOUT

The SQLITE_BUSY_TIMEOUT error code indicates that a blocking Posix
advisory file lock request in the VFS layer failed due to a timeout.
Blocking Posix advisory locks are only
available as a proprietary SQLite extension and even then are only
supported if SQLite is compiled with the SQLITE_EANBLE_SETLK_TIMEOUT
compile-time option.

(776) SQLITE_READONLY_ROLLBACK

The SQLITE_READONLY_ROLLBACK error code is an extended error code
for SQLITE_READONLY. The SQLITE_READONLY_ROLLBACK error code indicates
that a database cannot be opened because it has a hot journal that
needs to be rolled back but cannot because the database is readonly.

(778) SQLITE_IOERR_WRITE

The SQLITE_IOERR_WRITE error code is an extended error code
for SQLITE_IOERR indicating an I/O error in the VFS layer
while trying to write into a file on disk. This error might result
from a hardware malfunction or because a filesystem came unmounted
while the file was open. This error should not occur if the filesystem
is full as there is a separate error code (SQLITE_FULL) for that purpose.

(779) SQLITE_CORRUPT_INDEX

The SQLITE_CORRUPT_INDEX result code means that SQLite detected
an entry is or was missing from an index. This is a special case of
the SQLITE_CORRUPT error code that suggests that the problem might
be resolved by running the REINDEX command, assuming no other
problems exist elsewhere in the database file.

(782) SQLITE_CANTOPEN_FULLPATH

The SQLITE_CANTOPEN_FULLPATH error code is an extended error code
for SQLITE_CANTOPEN indicating that a file open operation failed because
the operating system was unable to convert the filename into a full pathname.

(787) SQLITE_CONSTRAINT_FOREIGNKEY

The SQLITE_CONSTRAINT_FOREIGNKEY error code
is an extended error code
for SQLITE_CONSTRAINT indicating that a foreign key constraint failed.

(1032) SQLITE_READONLY_DBMOVED

The SQLITE_READONLY_DBMOVED error code is an extended error code
for SQLITE_READONLY. The SQLITE_READONLY_DBMOVED error code indicates
that a database cannot be modified because the database file has been
moved since it was opened, and so any attempt to modify the database
might result in database corruption if the processes crashes because the
rollback journal would not be correctly named.

(1034) SQLITE_IOERR_FSYNC

The SQLITE_IOERR_FSYNC error code is an extended error code
for SQLITE_IOERR indicating an I/O error in the VFS layer
while trying to flush previously written content out of OS and/or
disk-control buffers and into persistent storage. In other words,
this code indicates a problem with the fsync() system call in unix
or the FlushFileBuffers() system call in windows.

(1038) SQLITE_CANTOPEN_CONVPATH

The SQLITE_CANTOPEN_CONVPATH error code is an extended error code
for SQLITE_CANTOPEN used only by Cygwin VFS and indicating that
the cygwin_conv_path() system call failed while trying to open a file.
See also: SQLITE_IOERR_CONVPATH

(1043) SQLITE_CONSTRAINT_FUNCTION

The SQLITE_CONSTRAINT_FUNCTION error code is not currently used
by the SQLite core. However, this error code is available for use
by extension functions.

(1288) SQLITE_READONLY_CANTINIT

The SQLITE_READONLY_CANTINIT result code originates in the xShmMap method
of a VFS to indicate that the shared memory region used by WAL mode
exists buts its content is unreliable and unusable by the current process
since the current process does not have write permission on the shared
memory region. (The shared memory region for WAL mode is normally a
file with a «-wal» suffix that is mmapped into the process space. If
the current process does not have write permission on that file, then it
cannot write into shared memory.)

Higher level logic within SQLite will normally intercept the error code
and create a temporary in-memory shared memory region so that the current
process can at least read the content of the database. This result code
should not reach the application interface layer.

(1290) SQLITE_IOERR_DIR_FSYNC

The SQLITE_IOERR_DIR_FSYNC error code is an extended error code
for SQLITE_IOERR indicating an I/O error in the VFS layer
while trying to invoke fsync() on a directory. The unix VFS attempts
to fsync() directories after creating or deleting certain files to
ensure that those files will still appear in the filesystem following
a power loss or system crash. This error code indicates a problem
attempting to perform that fsync().

(1294) SQLITE_CANTOPEN_DIRTYWAL

The SQLITE_CANTOPEN_DIRTYWAL result code is not used at this time.

(1299) SQLITE_CONSTRAINT_NOTNULL

The SQLITE_CONSTRAINT_NOTNULL error code
is an extended error code
for SQLITE_CONSTRAINT indicating that a NOT NULL constraint failed.

(1544) SQLITE_READONLY_DIRECTORY

The SQLITE_READONLY_DIRECTORY result code indicates that the database
is read-only because process does not have permission to create
a journal file in the same directory as the database and the creation of
a journal file is a prerequisite for writing.

(1546) SQLITE_IOERR_TRUNCATE

The SQLITE_IOERR_TRUNCATE error code is an extended error code
for SQLITE_IOERR indicating an I/O error in the VFS layer
while trying to truncate a file to a smaller size.

(1550) SQLITE_CANTOPEN_SYMLINK

The SQLITE_CANTOPEN_SYMLINK result code is returned by the
sqlite3_open() interface and its siblings when the
SQLITE_OPEN_NOFOLLOW flag is used and the database file is
a symbolic link.

(1555) SQLITE_CONSTRAINT_PRIMARYKEY

The SQLITE_CONSTRAINT_PRIMARYKEY error code
is an extended error code
for SQLITE_CONSTRAINT indicating that a PRIMARY KEY constraint failed.

(1802) SQLITE_IOERR_FSTAT

The SQLITE_IOERR_FSTAT error code is an extended error code
for SQLITE_IOERR indicating an I/O error in the VFS layer
while trying to invoke fstat() (or the equivalent) on a file in order
to determine information such as the file size or access permissions.

(1811) SQLITE_CONSTRAINT_TRIGGER

The SQLITE_CONSTRAINT_TRIGGER error code
is an extended error code
for SQLITE_CONSTRAINT indicating that a RAISE function within
a trigger fired, causing the SQL statement to abort.

(2058) SQLITE_IOERR_UNLOCK

The SQLITE_IOERR_UNLOCK error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within xUnlock method on the sqlite3_io_methods object.

(2067) SQLITE_CONSTRAINT_UNIQUE

The SQLITE_CONSTRAINT_UNIQUE error code
is an extended error code
for SQLITE_CONSTRAINT indicating that a UNIQUE constraint failed.

(2314) SQLITE_IOERR_RDLOCK

The SQLITE_IOERR_UNLOCK error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within xLock method on the sqlite3_io_methods object while trying
to obtain a read lock.

(2323) SQLITE_CONSTRAINT_VTAB

The SQLITE_CONSTRAINT_VTAB error code is not currently used
by the SQLite core. However, this error code is available for use
by application-defined virtual tables.

(2570) SQLITE_IOERR_DELETE

The SQLITE_IOERR_UNLOCK error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within xDelete method on the sqlite3_vfs object.

(2579) SQLITE_CONSTRAINT_ROWID

The SQLITE_CONSTRAINT_ROWID error code
is an extended error code
for SQLITE_CONSTRAINT indicating that a rowid is not unique.

(2826) SQLITE_IOERR_BLOCKED

The SQLITE_IOERR_BLOCKED error code is no longer used.

(2835) SQLITE_CONSTRAINT_PINNED

The SQLITE_CONSTRAINT_PINNED error code
is an extended error code
for SQLITE_CONSTRAINT indicating that an UPDATE trigger attempted
do delete the row that was being updated in the middle of the update.

(3082) SQLITE_IOERR_NOMEM

The SQLITE_IOERR_NOMEM error code is sometimes returned by the VFS
layer to indicate that an operation could not be completed due to the
inability to allocate sufficient memory. This error code is normally
converted into SQLITE_NOMEM by the higher layers of SQLite before
being returned to the application.

(3091) SQLITE_CONSTRAINT_DATATYPE

The SQLITE_CONSTRAINT_DATATYPE error code
is an extended error code
for SQLITE_CONSTRAINT indicating that an insert or update attempted
to store a value inconsistent with the column’s declared type
in a table defined as STRICT.

(3338) SQLITE_IOERR_ACCESS

The SQLITE_IOERR_ACCESS error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within the xAccess method on the sqlite3_vfs object.

(3594) SQLITE_IOERR_CHECKRESERVEDLOCK

The SQLITE_IOERR_CHECKRESERVEDLOCK error code is
an extended error code
for SQLITE_IOERR indicating an I/O error
within the xCheckReservedLock method on the sqlite3_io_methods object.

(3850) SQLITE_IOERR_LOCK

The SQLITE_IOERR_LOCK error code is an extended error code
for SQLITE_IOERR indicating an I/O error in the
advisory file locking logic.
Usually an SQLITE_IOERR_LOCK error indicates a problem obtaining
a PENDING lock. However it can also indicate miscellaneous
locking errors on some of the specialized VFSes used on Macs.

(4106) SQLITE_IOERR_CLOSE

The SQLITE_IOERR_ACCESS error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within the xClose method on the sqlite3_io_methods object.

(4362) SQLITE_IOERR_DIR_CLOSE

The SQLITE_IOERR_DIR_CLOSE error code is no longer used.

(4618) SQLITE_IOERR_SHMOPEN

The SQLITE_IOERR_SHMOPEN error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within the xShmMap method on the sqlite3_io_methods object
while trying to open a new shared memory segment.

(4874) SQLITE_IOERR_SHMSIZE

The SQLITE_IOERR_SHMSIZE error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within the xShmMap method on the sqlite3_io_methods object
while trying to enlarge a «shm» file as part of
WAL mode transaction processing. This error may indicate that
the underlying filesystem volume is out of space.

(5130) SQLITE_IOERR_SHMLOCK

The SQLITE_IOERR_SHMLOCK error code is no longer used.

(5386) SQLITE_IOERR_SHMMAP

The SQLITE_IOERR_SHMMAP error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within the xShmMap method on the sqlite3_io_methods object
while trying to map a shared memory segment into the process address space.

(5642) SQLITE_IOERR_SEEK

The SQLITE_IOERR_SEEK error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within the xRead or xWrite methods on the sqlite3_io_methods object
while trying to seek a file descriptor to the beginning point of the
file where the read or write is to occur.

(5898) SQLITE_IOERR_DELETE_NOENT

The SQLITE_IOERR_DELETE_NOENT error code
is an extended error code
for SQLITE_IOERR indicating that the
xDelete method on the sqlite3_vfs object failed because the
file being deleted does not exist.

(6154) SQLITE_IOERR_MMAP

The SQLITE_IOERR_MMAP error code is an extended error code
for SQLITE_IOERR indicating an I/O error
within the xFetch or xUnfetch methods on the sqlite3_io_methods object
while trying to map or unmap part of the database file into the
process address space.

(6410) SQLITE_IOERR_GETTEMPPATH

The SQLITE_IOERR_GETTEMPPATH error code is an extended error code
for SQLITE_IOERR indicating that the VFS is unable to determine
a suitable directory in which to place temporary files.

(6666) SQLITE_IOERR_CONVPATH

The SQLITE_IOERR_CONVPATH error code is an extended error code
for SQLITE_IOERR used only by Cygwin VFS and indicating that
the cygwin_conv_path() system call failed.
See also: SQLITE_CANTOPEN_CONVPATH

(6922) SQLITE_IOERR_VNODE

The SQLITE_IOERR_VNODE error code is a code reserved for use
by extensions. It is not used by the SQLite core.

(7178) SQLITE_IOERR_AUTH

The SQLITE_IOERR_AUTH error code is a code reserved for use
by extensions. It is not used by the SQLite core.

(7434) SQLITE_IOERR_BEGIN_ATOMIC

The SQLITE_IOERR_BEGIN_ATOMIC error code indicates that the
underlying operating system reported and error on the
SQLITE_FCNTL_BEGIN_ATOMIC_WRITE file-control. This only comes
up when SQLITE_ENABLE_ATOMIC_WRITE is enabled and the database
is hosted on a filesystem that supports atomic writes.

(7690) SQLITE_IOERR_COMMIT_ATOMIC

The SQLITE_IOERR_COMMIT_ATOMIC error code indicates that the
underlying operating system reported and error on the
SQLITE_FCNTL_COMMIT_ATOMIC_WRITE file-control. This only comes
up when SQLITE_ENABLE_ATOMIC_WRITE is enabled and the database
is hosted on a filesystem that supports atomic writes.

(7946) SQLITE_IOERR_ROLLBACK_ATOMIC

The SQLITE_IOERR_ROLLBACK_ATOMIC error code indicates that the
underlying operating system reported and error on the
SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE file-control. This only comes
up when SQLITE_ENABLE_ATOMIC_WRITE is enabled and the database
is hosted on a filesystem that supports atomic writes.

(8202) SQLITE_IOERR_DATA

The SQLITE_IOERR_DATA error code is an extended error code
for SQLITE_IOERR used only by checksum VFS shim to indicate that
the checksum on a page of the database file is incorrect.

(8458) SQLITE_IOERR_CORRUPTFS

The SQLITE_IOERR_CORRUPTFS error code is an extended error code
for SQLITE_IOERR used only by a VFS to indicate that a seek or read
failure was due to the request not falling within the file’s boundary
rather than an ordinary device failure. This often indicates a
corrupt filesystem.

This page last modified on 2022-02-08 12:34:22 UTC

Коды результатов и ошибок

Overview

Многие подпрограммы в интерфейсе на языке C SQLite возвращают числовые коды результатов, указывающие на успех или неудачу, а в случае неудачи — на некоторое представление о причине сбоя. В этом документе делается попытка объяснить, что означает каждый из этих числовых кодов результатов.

1.Коды результатов против кодов ошибок

«Коды ошибок» — это подмножество «результирующих кодов», которые указывают на то, что что-то пошло не так. Есть только несколько кодов результатов без ошибок: SQLITE_OK , SQLITE_ROW и SQLITE_DONE . Термин «код ошибки» означает любой код результата, отличный от этих трех.

2.Коды первичных результатов по сравнению с кодами расширенных результатов

Коды результата-это подписанные 32-битные целые числа.Наименее значащие 8 бит кода результата определяют широкую категорию и называются «первичным кодом результата».Более значащие биты дают более подробную информацию об ошибке и называются «расширенным кодом результата».

Обратите внимание,что первичный код результата всегда является частью расширенного кода результата.При полном 32-битном расширенном результирующем коде приложение всегда может найти соответствующий код первичного результата,просто извлекая из расширенного результирующего кода наименее значащие 8 бит.

Все расширенные коды результатов также являются кодами ошибок.Поэтому термины «расширенный код результата» и «расширенный код ошибки» являются взаимозаменяемыми.

Для исторической совместимости интерфейсы на языке C по умолчанию возвращают первичные коды результатов. Расширенный код результата для самой последней ошибки можно получить с помощью интерфейса sqlite3_extended_errcode () . Интерфейс sqlite3_extended_result_codes () можно использовать для перевода соединения с базой данных в режим, в котором он возвращает расширенные коды результатов вместо основных кодов результатов.

3. Definitions

Все коды результатов — целые числа. Символические имена для всех результирующих кодов создаются с помощью макроса «#define» в заголовочном файле sqlite3.h. В заголовочном файле sqlite3.h есть отдельные разделы для определений кода результата и расширенных определений кода результата .

Код первичного результата-символические имена формы «SQLITE_XXXXXX»,где XXXXXX-это последовательность заглавных алфавитных символов.Расширенные кодовые имена результата относятся к форме «SQLITE_XXXXXX_YYYYYYY»,где XXXXXX часть является соответствующим первичным кодом результата,а YYYYYY является расширением,которое далее классифицирует код результата.

Названия и числовые значения для существующих кодов результатов являются фиксированными и неизменными.Однако в будущих релизах SQLite могут появиться новые коды результатов,и особенно новые расширенные коды результатов.

4.Перечень кодов первичных результатов

31 код результата определены в sqlite3.h и перечислены в алфавитном порядке ниже:

  • SQLITE_ABORT (4)
  • SQLITE_AUTH (23)
  • SQLITE_BUSY (5)
  • SQLITE_CANTOPEN (14)
  • SQLITE_CONSTRAINT (19)
  • SQLITE_CORRUPT (11)
  • SQLITE_DONE (101)
  • SQLITE_EMPTY (16)
  • SQLITE_ERROR (1)
  • SQLITE_FORMAT (24)
  • SQLITE_FULL (13)
  • SQLITE_INTERNAL (2)
  • SQLITE_INTERRUPT (9)
  • SQLITE_IOERR (10)
  • SQLITE_LOCKED (6)
  • SQLITE_MISMATCH (20)
  • SQLITE_MISUSE (21)
  • SQLITE_NOLFS (22)
  • SQLITE_NOMEM (7)
  • SQLITE_NOTADB (26)
  • SQLITE_NOTFOUND (12)
  • SQLITE_NOTICE (27)
  • SQLITE_OK (0)
  • SQLITE_PERM (3)
  • SQLITE_PROTOCOL (15)
  • SQLITE_RANGE (25)
  • SQLITE_READONLY (8)
  • SQLITE_ROW (100)
  • SQLITE_SCHEMA (17)
  • SQLITE_TOOBIG (18)
  • SQLITE_WARNING (28)

5.Расширенный список кодов результатов

74 расширенных кода результатов определены в sqlite3.h и перечислены в алфавитном порядке ниже:

  • SQLITE_ABORT_ROLLBACK (516)
  • SQLITE_AUTH_USER (279)
  • SQLITE_BUSY_RECOVERY (261)
  • SQLITE_BUSY_SNAPSHOT (517)
  • SQLITE_BUSY_TIMEOUT (773)
  • SQLITE_CANTOPEN_CONVPATH (1038)
  • SQLITE_CANTOPEN_DIRTYWAL (1294)
  • SQLITE_CANTOPEN_FULLPATH (782)
  • SQLITE_CANTOPEN_ISDIR (526)
  • SQLITE_CANTOPEN_NOTEMPDIR (270)
  • SQLITE_CANTOPEN_SYMLINK (1550)
  • SQLITE_CONSTRAINT_CHECK (275)
  • SQLITE_CONSTRAINT_COMMITHOOK (531)
  • SQLITE_CONSTRAINT_DATATYPE (3091)
  • SQLITE_CONSTRAINT_FOREIGNKEY (787)
  • SQLITE_CONSTRAINT_FUNCTION (1043)
  • SQLITE_CONSTRAINT_NOTNULL (1299)
  • SQLITE_CONSTRAINT_PINNED (2835)
  • SQLITE_CONSTRAINT_PRIMARYKEY (1555)
  • SQLITE_CONSTRAINT_ROWID (2579)
  • SQLITE_CONSTRAINT_TRIGGER (1811)
  • SQLITE_CONSTRAINT_UNIQUE (2067)
  • SQLITE_CONSTRAINT_VTAB (2323)
  • SQLITE_CORRUPT_INDEX (779)
  • SQLITE_CORRUPT_SEQUENCE (523)
  • SQLITE_CORRUPT_VTAB (267)
  • SQLITE_ERROR_MISSING_COLLSEQ (257)
  • SQLITE_ERROR_RETRY (513)
  • SQLITE_ERROR_SNAPSHOT (769)
  • SQLITE_IOERR_ACCESS (3338)
  • SQLITE_IOERR_AUTH (7178)
  • SQLITE_IOERR_BEGIN_ATOMIC (7434)
  • SQLITE_IOERR_BLOCKED (2826)
  • SQLITE_IOERR_CHECKRESERVEDLOCK (3594)
  • SQLITE_IOERR_CLOSE (4106)
  • SQLITE_IOERR_COMMIT_ATOMIC (7690)
  • SQLITE_IOERR_CONVPATH (6666)
  • SQLITE_IOERR_CORRUPTFS (8458)
  • SQLITE_IOERR_DATA (8202)
  • SQLITE_IOERR_DELETE (2570)
  • SQLITE_IOERR_DELETE_NOENT (5898)
  • SQLITE_IOERR_DIR_CLOSE (4362)
  • SQLITE_IOERR_DIR_FSYNC (1290)
  • SQLITE_IOERR_FSTAT (1802)
  • SQLITE_IOERR_FSYNC (1034)
  • SQLITE_IOERR_GETTEMPPATH (6410)
  • SQLITE_IOERR_LOCK (3850)
  • SQLITE_IOERR_MMAP (6154)
  • SQLITE_IOERR_NOMEM (3082)
  • SQLITE_IOERR_RDLOCK (2314)
  • SQLITE_IOERR_READ (266)
  • SQLITE_IOERR_ROLLBACK_ATOMIC (7946)
  • SQLITE_IOERR_SEEK (5642)
  • SQLITE_IOERR_SHMLOCK (5130)
  • SQLITE_IOERR_SHMMAP (5386)
  • SQLITE_IOERR_SHMOPEN (4618)
  • SQLITE_IOERR_SHMSIZE (4874)
  • SQLITE_IOERR_SHORT_READ (522)
  • SQLITE_IOERR_TRUNCATE (1546)
  • SQLITE_IOERR_UNLOCK (2058)
  • SQLITE_IOERR_VNODE (6922)
  • SQLITE_IOERR_WRITE (778)
  • SQLITE_LOCKED_SHAREDCACHE (262)
  • SQLITE_LOCKED_VTAB (518)
  • SQLITE_NOTICE_RECOVER_ROLLBACK (539)
  • SQLITE_NOTICE_RECOVER_WAL (283)
  • SQLITE_OK_LOAD_PERMANENTLY (256)
  • SQLITE_READONLY_CANTINIT (1288)
  • SQLITE_READONLY_CANTLOCK (520)
  • SQLITE_READONLY_DBMOVED (1032)
  • SQLITE_READONLY_DIRECTORY (1544)
  • SQLITE_READONLY_RECOVERY (264)
  • SQLITE_READONLY_ROLLBACK (776)
  • SQLITE_WARNING_AUTOINDEX (284)

6.Значения кода результата

Значения всех 105 значений кода результата показаны ниже в цифровом порядке.

(0) SQLITE_OK

Код результата SQLITE_OK означает,что операция прошла успешно и ошибок не было.Большинство других кодов результатов указывают на ошибку.

(1) SQLITE_ERROR

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

(2) SQLITE_INTERNAL

Код результата SQLITE_INTERNAL указывает на внутреннюю неисправность.В рабочей версии SQLite приложение никогда не должно видеть такой код результата.Если приложение все же столкнется с таким кодом результата,это свидетельствует о наличии ошибки в движке БД.

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

(3) SQLITE_PERM

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

(4) SQLITE_ABORT

Код результата SQLITE_ABORT указывает, что операция была прервана до завершения, обычно это запрос приложения. См. Также: SQLITE_INTERRUPT .

Если функция обратного вызова sqlite3_exec () возвращает ненулевое значение, тогда sqlite3_exec () вернет SQLITE_ABORT.

Если операция ROLLBACK происходит в том же соединении с базой данных, что и ожидающее чтение или запись, то ожидающее чтение или запись может завершиться ошибкой SQLITE_ABORT или SQLITE_ABORT_ROLLBACK .

Помимо того, что это код результата, значение SQLITE_ABORT также используется в качестве режима разрешения конфликтов, возвращаемого интерфейсом sqlite3_vtab_on_conflict () .

(5) SQLITE_BUSY

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

Например, если процесс A находится в середине большой транзакции записи и в то же время процесс B пытается начать новую транзакцию записи, процесс B вернет результат SQLITE_BUSY, потому что SQLite поддерживает только одну запись за раз. Процессу B нужно будет дождаться, пока процесс A завершит свою транзакцию, прежде чем начинать новую транзакцию. Интерфейсы sqlite3_busy_timeout () и sqlite3_busy_handler () и прагма busy_timeout доступны для процесса B, чтобы помочь ему справиться с ошибками SQLITE_BUSY.

Ошибка SQLITE_BUSY может возникнуть в любой момент транзакции: при первом запуске транзакции, во время любых операций записи или обновления или при фиксации транзакции. Чтобы избежать ошибок SQLITE_BUSY в середине транзакции, приложение может использовать BEGIN IMMEDIATE вместо просто BEGIN для запуска транзакции. Команда BEGIN IMMEDIATE может сама вернуть SQLITE_BUSY, но в случае успеха SQLite гарантирует, что никакие последующие операции с той же базой данных через следующую COMMIT не вернут SQLITE_BUSY.

См. Также: SQLITE_BUSY_RECOVERY и SQLITE_BUSY_SNAPSHOT .

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

(6) SQLITE_LOCKED

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

Например, оператор DROP TABLE не может быть запущен, пока другой поток читает из этой таблицы в том же соединении с базой данных, потому что при удалении таблицы таблица будет удалена из-под одновременного чтения.

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

(7) SQLITE_NOMEM

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

(8) SQLITE_READONLY

Код результата SQLITE_READONLY возвращается при попытке изменить некоторые данные,на которые текущее подключение к БД не имеет права записи.

(9) SQLITE_INTERRUPT

Код результата SQLITE_INTERRUPT указывает, что операция была прервана интерфейсом sqlite3_interrupt () . См. Также: SQLITE_ABORT

(10) SQLITE_IOERR

Код результата SQLITE_IOERR говорит,что операция не может быть завершена,так как операционная система сообщает об ошибке ввода/вывода.

Полный диск обычно дает ошибку SQLITE_FULL, а не ошибку SQLITE_IOERR.

Существует много различных расширенных кодов результатов для ошибок ввода/вывода,которые идентифицируют конкретную операцию ввода/вывода,которая не удалась.

(11) SQLITE_CORRUPT

Код результата SQLITE_CORRUPT указывает на то, что файл базы данных поврежден. См. Как повредить файлы базы данных для дальнейшего обсуждения того, как может произойти повреждение.

(12) SQLITE_NOTFOUND

Код результата SQLITE_NOTFOUND раскрывается тремя способами:

  1. SQLITE_NOTFOUND может быть возвращен интерфейсом sqlite3_file_control() , чтобы указать, что код операции управления файлом, переданный в качестве третьего аргумента, не был распознан базовой VFS .

  2. SQLITE_NOTFOUND также может быть возвращен методом xSetSystemCall() объекта sqlite3_vfs .

  3. SQLITE_NOTFOUND возвращается функцией sqlite3_vtab_rhs_value() , чтобы указать, что правый операнд ограничения недоступен для метода xBestIndex , выполнившего вызов.

Код результата SQLITE_NOTFOUND также используется внутри реализации SQLite,но эти внутренние использования не подвержены приложению.

(13) SQLITE_FULL

Код результата SQLITE_FULL указывает, что запись не может быть завершена из-за переполнения диска. Обратите внимание, что эта ошибка может возникнуть при попытке записать информацию в основной файл базы данных или при записи во временные файлы на диске .

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

(14) SQLITE_CANTOPEN

Код результата SQLITE_CANTOPEN указывает, что SQLite не удалось открыть файл. Рассматриваемый файл может быть основным файлом базы данных или одним из нескольких временных файлов на диске .

(15) SQLITE_PROTOCOL

Код результата SQLITE_PROTOCOL указывает на проблему с протоколом блокировки файлов, используемым SQLite. Ошибка SQLITE_PROTOCOL в настоящее время возвращается только при использовании режима WAL и попытке начать новую транзакцию. Когда два отдельных соединения с базой данных одновременно пытаются запустить транзакцию в режиме WAL, возникает состояние гонки . Проигравший в гонке отступает и пытается снова после небольшой задержки. Если одно и то же соединение десятки раз проигрывает в гонке блокировок в течение нескольких секунд, оно в конечном итоге завершится и вернет SQLITE_PROTOCOL. Ошибка SQLITE_PROTOCOL должна появляться на практике очень, очень редко и только тогда, когда существует множество отдельных процессов, все из которых активно конкурируют за запись в одну и ту же базу данных.

(16) SQLITE_EMPTY

В настоящее время код результата SQLITE_EMPTY не используется.

(17) SQLITE_SCHEMA

Код результата SQLITE_SCHEMA указывает, что схема базы данных изменилась. Этот код результата может быть возвращен из sqlite3_step () для подготовленного оператора, который был сгенерирован с помощью sqlite3_prepare () или sqlite3_prepare16 () . Если схема базы данных была изменена каким-то другим процессом между временем подготовки оператора и временем его выполнения, может возникнуть эта ошибка.

Если подготовленный оператор генерируется из sqlite3_prepare_v2() , то он автоматически повторно подготавливается при изменении схемы до SQLITE_MAX_SCHEMA_RETRY раз (по умолчанию: 50). Интерфейс sqlite3_step() вернет SQLITE_SCHEMA обратно в приложение только в том случае, если сбой сохраняется после этих многочисленных попыток.

(18) SQLITE_TOOBIG

Код ошибки SQLITE_TOOBIG указывает, что строка или большой двоичный объект слишком велики. По умолчанию максимальная длина строки или большого двоичного объекта в SQLite составляет 1 000 000 000 байт. Эту максимальную длину можно изменить во время компиляции с помощью параметра времени компиляции SQLITE_MAX_LENGTH или во время выполнения с помощью интерфейса sqlite3_limit (db, SQLITE_LIMIT_LENGTH , …). Ошибка SQLITE_TOOBIG возникает, когда SQLite встречает строку или большой двоичный объект, превышающий предел времени компиляции или времени выполнения.

Код ошибки SQLITE_TOOBIG также может появиться, когда оператор SQL слишком большого размера передается в один из интерфейсов sqlite3_prepare_v2() . Максимальная длина оператора SQL по умолчанию составляет гораздо меньшее значение, равное 1 000 000 000 байт. Максимальная длина оператора SQL может быть установлена ​​во время компиляции с помощью SQLITE_MAX_SQL_LENGTH или во время выполнения с помощью sqlite3_limit (db, SQLITE_LIMIT_SQL_LENGTH ,…).

(19) SQLITE_CONSTRAINT

Код ошибки SQLITE_CONSTRAINT означает, что при попытке обработать оператор SQL произошло нарушение ограничения SQL. Дополнительную информацию о неудавшемся ограничении можно найти, просмотрев сопроводительное сообщение об ошибке (возвращаемое через sqlite3_errmsg () или sqlite3_errmsg16 () ) или просмотрев расширенный код ошибки .

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

(20) SQLITE_MISMATCH

Код ошибки SQLITE_MISMATCH указывает на несовпадение типа данных.

SQLite,как правило,очень забывает о несоответствиях между типом значения и объявленным типом контейнера,в котором это значение должно храниться.Например,SQLite позволяет приложению хранить большой BLOB в столбце с объявленным типом BOOLEAN.Но в некоторых случаях SQLite строго относится к типам.Ошибка SQLITE_MISMATCH возвращается в тех немногих случаях,когда типы не совпадают.

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

(21) SQLITE_MISUSE

Код возврата SQLITE_MISUSE может быть возвращен, если приложение использует какой-либо интерфейс SQLite способом, который не определен или не поддерживается. Например, использование подготовленного оператора после того, как этот подготовленный оператор был завершен, может привести к ошибке SQLITE_MISUSE.

SQLite пытается обнаружить злоупотребление и сообщить о нем,используя данный код результата.Однако,нет никакой гарантии,что обнаружение неправильного использования будет успешным.Обнаружение неправильного использования является вероятностным.Приложения никогда не должны зависеть от возвращаемого значения SQLITE_MISUSE.

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

(22) SQLITE_NOLFS

Ошибка SQLITE_NOLFS может быть возвращена на системах,которые не поддерживают большие файлы,когда база данных становится больше,чем та,с которой может справиться файловая система.»NOLFS» означает «NO Large File Support».

(23) SQLITE_AUTH

Ошибка SQLITE_AUTH возвращается, когда обратный вызов авторизатора указывает, что подготавливаемый оператор SQL не авторизован.

(24) SQLITE_FORMAT

Код ошибки SQLITE_FORMAT в настоящее время не используется SQLite.

(25) SQLITE_RANGE

Ошибка SQLITE_RANGE указывает на то, что аргумент номера параметра для одной из подпрограмм sqlite3_bind или номер столбца в одной из подпрограмм sqlite3_column находится вне допустимого диапазона.

(26) SQLITE_NOTADB

При попытке открыть файл ошибка SQLITE_NOTADB указывает на то,что открываемый файл не является файлом базы данных SQLite.

(27) SQLITE_NOTICE

Код результата SQLITE_NOTICE не возвращается ни одним интерфейсом C / C ++. Однако SQLITE_NOTICE (или, скорее, один из его расширенных кодов ошибок ) иногда используется в качестве первого аргумента в обратном вызове sqlite3_log (), чтобы указать, что происходит необычная операция.

(28) SQLITE_WARNING

Код результата SQLITE_WARNING не возвращается ни одним интерфейсом C / C ++. Однако SQLITE_WARNING (или, скорее, один из его расширенных кодов ошибок ) иногда используется в качестве первого аргумента в обратном вызове sqlite3_log (), чтобы указать, что имеет место необычная и, возможно, непродуманная операция.

(100) SQLITE_ROW

Код результата SQLITE_ROW, возвращаемый sqlite3_step (), указывает, что доступна другая строка вывода.

(101) SQLITE_DONE

Код результата SQLITE_DONE указывает, что операция завершена. Код результата SQLITE_DONE чаще всего рассматривается как возвращаемое значение от sqlite3_step (), указывающее, что оператор SQL выполнен до конца. Но SQLITE_DONE также может возвращаться другими многоступенчатыми интерфейсами, такими как sqlite3_backup_step () .

(256) SQLITE_OK_LOAD_PERMANENTLY

Интерфейс sqlite3_load_extension () загружает расширение в одно соединение с базой данных. По умолчанию это расширение автоматически выгружается при закрытии соединения с базой данных. Однако, если точка входа расширения возвращает SQLITE_OK_LOAD_PERMANENTLY вместо SQLITE_OK, тогда расширение остается загруженным в адресное пространство процесса после закрытия соединения с базой данных. Другими словами, методы xDlClose объекта sqlite3_vfs не вызываются для расширения при закрытии соединения с базой данных.

Код возврата SQLITE_OK_LOAD_PERMANENTLY полезен, например, для загружаемых расширений, которые регистрируют новые VFS .

(257) SQLITE_ERROR_MISSING_COLLSEQ

Код результата SQLITE_ERROR_MISSING_COLLSEQ означает,что SQL-оператор не может быть подготовлен из-за того,что не может быть найдена коллекционная последовательность,названная в этом SQL-операторе.

Иногда, когда встречается этот код ошибки, процедура sqlite3_prepare_v2 () преобразует ошибку в SQLITE_ERROR_RETRY и снова пытается подготовить оператор SQL, используя другой план запроса, который не требует использования неизвестной последовательности сортировки.

(261) SQLITE_BUSY_RECOVERY

Код ошибки SQLITE_BUSY_RECOVERY — это расширенный код ошибки для SQLITE_BUSY, который указывает, что операция не может быть продолжена, поскольку другой процесс занят восстановлением файла базы данных в режиме WAL после сбоя. Код ошибки SQLITE_BUSY_RECOVERY возникает только в базах данных в режиме WAL .

(262) SQLITE_LOCKED_SHAREDCACHE

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

(264) SQLITE_READONLY_RECOVERY

Код ошибки SQLITE_READONLY_RECOVERY — это расширенный код ошибки для SQLITE_READONLY . Код ошибки SQLITE_READONLY_RECOVERY указывает, что база данных в режиме WAL не может быть открыта, потому что файл базы данных необходимо восстановить, а для восстановления требуется доступ для записи, но доступен только доступ для чтения.

(266) SQLITE_IOERR_READ

Код ошибки SQLITE_IOERR_READ — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода на уровне VFS при попытке чтения из файла на диске. Эта ошибка может возникнуть из-за неисправности оборудования или из-за того, что файловая система была отключена, пока файл был открыт.

(267) SQLITE_CORRUPT_VTAB

Код ошибки SQLITE_CORRUPT_VTAB — это расширенный код ошибки для SQLITE_CORRUPT, используемый виртуальными таблицами . Виртуальная таблица может вернуться SQLITE_CORRUPT_VTAB , чтобы указать , что содержание в виртуальной таблице повреждено.

(270) SQLITE_CANTOPEN_NOTEMPDIR

Код ошибки SQLITE_CANTOPEN_NOTEMPDIR больше не используется.

(275) SQLITE_CONSTRAINT_CHECK

Код ошибки SQLITE_CONSTRAINT_CHECK — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий на сбой ограничения CHECK .

(279) SQLITE_AUTH_USER

Код ошибки SQLITE_AUTH_USER — это расширенный код ошибки для SQLITE_AUTH , указывающий, что была предпринята операция в базе данных, для которой вошедший в систему пользователь не имеет достаточной авторизации.

(283) SQLITE_NOTICE_RECOVER_WAL

Код результата SQLITE_NOTICE_RECOVER_WAL передается в обратный вызов sqlite3_log () при восстановлении файла базы данных в режиме WAL .

(284) SQLITE_WARNING_AUTOINDEX

Код результата SQLITE_WARNING_AUTOINDEX передается в обратный вызов sqlite3_log () всякий раз, когда используется автоматическое индексирование . Это может служить предупреждением для разработчиков приложений о том, что для базы данных могут быть полезны дополнительные индексы.

(513) SQLITE_ERROR_RETRY

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

(516) SQLITE_ABORT_ROLLBACK

Код ошибки SQLITE_ABORT_ROLLBACK — это расширенный код ошибки для SQLITE_ABORT, указывающий на то, что выполнение инструкции SQL было прервано из- за отката транзакции, которая была активной при первом запуске инструкции SQL. При откате отложенные операции записи всегда завершаются сбоем с этой ошибкой. ОТКАТА вызовет отложенное чтение не выполняется операция , только если схема была изменена в пределах сделки будет произведен откатом.

(517) SQLITE_BUSY_SNAPSHOT

Код ошибки SQLITE_BUSY_SNAPSHOT — это расширенный код ошибки для SQLITE_BUSY, который возникает в базах данных в режиме WAL, когда соединение с базой данных пытается преобразовать транзакцию чтения в транзакцию записи, но обнаруживает, что другое соединение с базой данных уже записано в базу данных и, таким образом, делает недействительными предыдущие чтения.

Следующий сценарий иллюстрирует,как может возникнуть ошибка SQLITE_BUSY_SNAPSHOT:

  1. Процесс A запускает прочитанную транзакцию по базе данных и выполняет один или несколько SELECT-запросов.Процесс A держит транзакцию открытой.
  2. Процесс B обновляет базу данных,изменяя значения,ранее прочитанные процессом A.
  3. Процесс A теперь пытается записать в базу данных.Но представление процесса A о содержимом базы данных теперь устарело,потому что процесс B изменил файл базы данных после того,как процесс A прочитал из него.Поэтому процесс A получает ошибку SQLITE_BUSY_SNAPSHOT.
(518) SQLITE_LOCKED_VTAB

Код результата SQLITE_LOCKED_VTAB не используется ядром SQLite,но доступен для использования расширениями.Реализации виртуальных таблиц могут возвращать этот код результата,чтобы показать,что они не могут завершить текущую операцию из-за блокировок,удерживаемых другими потоками или процессами.

Расширение R-Tree возвращает этот код результата, когда делается попытка обновить R-Tree, когда другой подготовленный оператор активно читает R-Tree. Обновление не может быть продолжено, потому что любое изменение R-дерева может включать перестановку и перебалансировку узлов, что нарушит работу курсоров чтения, в результате чего некоторые строки будут повторяться, а другие строки будут пропущены.

(520) SQLITE_READONLY_CANTLOCK

Код ошибки SQLITE_READONLY_CANTLOCK — это расширенный код ошибки для SQLITE_READONLY . Код ошибки SQLITE_READONLY_CANTLOCK указывает, что SQLite не может получить блокировку чтения для базы данных в режиме WAL, поскольку файл с общей памятью, связанный с этой базой данных, доступен только для чтения.

(522) SQLITE_IOERR_SHORT_READ

Код ошибки SQLITE_IOERR_SHORT_READ — это расширенный код ошибки для SQLITE_IOERR, указывающий, что при попытке чтения на уровне VFS не удалось получить столько байтов, сколько было запрошено. Это могло произойти из-за обрезанного файла.

(523) SQLITE_CORRUPT_SEQUENCE

Код результата SQLITE_CORRUPT_SEQUENCE означает, что схема таблицы sqlite_sequence повреждена. Таблица sqlite_sequence используется для помощи в реализации функции AUTOINCREMENT . Таблица sqlite_sequence должна иметь следующий формат:

  CREATE TABLE sqlite_sequence(name,seq);
  

Если SQLite обнаруживает,что таблица sqlite_sequence имеет другой формат,он возвращает ошибку SQLITE_CORRUPT_SEQUENCE.

(526) SQLITE_CANTOPEN_ISDIR

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

(531) SQLITE_CONSTRAINT_COMMITHOOK

Код ошибки SQLITE_CONSTRAINT_COMMITHOOK — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий, что обратный вызов ловушки фиксации вернул ненулевое значение, что, таким образом, вызвало откат оператора SQL.

(539) SQLITE_NOTICE_RECOVER_ROLLBACK

Код результата SQLITE_NOTICE_RECOVER_ROLLBACK передается в обратный вызов sqlite3_log () при откате горячего журнала .

(769) SQLITE_ERROR_SNAPSHOT

Код результата SQLITE_ERROR_SNAPSHOT может быть возвращен при попытке начать транзакцию чтения в исторической версии базы данных с помощью интерфейса sqlite3_snapshot_open() . Если исторический моментальный снимок больше недоступен, транзакция чтения завершится с ошибкой SQLITE_ERROR_SNAPSHOT. Этот код ошибки возможен только в том случае, если SQLite скомпилирован с параметром -DSQLITE_ENABLE_SNAPSHOT .

(773) SQLITE_BUSY_TIMEOUT

Код ошибки SQLITE_BUSY_TIMEOUT указывает на то,что запрос блокировки Posix advisory file lock на уровне VFS не прошел из-за таймаута.Блокирующие консультативные блокировки Posix доступны только как собственное расширение SQLite,и даже тогда они поддерживаются только в том случае,если SQLite скомпилирован с опцией времени компиляции SQLITE_EANBLE_SETLK_TIMEOUT.

(776) SQLITE_READONLY_ROLLBACK

Код ошибки SQLITE_READONLY_ROLLBACK — это расширенный код ошибки для SQLITE_READONLY . Код ошибки SQLITE_READONLY_ROLLBACK указывает на то, что базу данных нельзя открыть, потому что у нее есть горячий журнал, который необходимо откатить, но не может, потому что база данных доступна только для чтения.

(778) SQLITE_IOERR_WRITE

Код ошибки SQLITE_IOERR_WRITE — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода на уровне VFS при попытке записи в файл на диске. Эта ошибка может возникнуть из-за неисправности оборудования или из-за того, что файловая система была отключена, пока файл был открыт. Эта ошибка не должна возникать, если файловая система заполнена, поскольку для этой цели существует отдельный код ошибки (SQLITE_FULL).

(779) SQLITE_CORRUPT_INDEX

Код результата SQLITE_CORRUPT_INDEX означает, что SQLite обнаружил, что запись отсутствует или отсутствует в индексе. Это особый случай кода ошибки SQLITE_CORRUPT, который предполагает, что проблема может быть решена с помощью команды REINDEX , при условии, что в другом месте файла базы данных нет других проблем.

(782) SQLITE_CANTOPEN_FULLPATH

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

(787) SQLITE_CONSTRAINT_FOREIGNKEY

Код ошибки SQLITE_CONSTRAINT_FOREIGNKEY — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий на сбой ограничения внешнего ключа .

(1032) SQLITE_READONLY_DBMOVED

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

(1034) SQLITE_IOERR_FSYNC

Код ошибки SQLITE_IOERR_FSYNC — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода на уровне VFS при попытке сбросить ранее записанный контент из буферов ОС и / или управления диском в постоянное хранилище. Другими словами, этот код указывает на проблему с системным вызовом fsync () в unix или системным вызовом FlushFileBuffers () в Windows.

(1038) SQLITE_CANTOPEN_CONVPATH

Код ошибки SQLITE_CANTOPEN_CONVPATH — это расширенный код ошибки для SQLITE_CANTOPEN, используемый только Cygwin VFS и указывающий на то, что системный вызов cygwin_conv_path () завершился неудачно при попытке открыть файл. См. Также: SQLITE_IOERR_CONVPATH

(1043) SQLITE_CONSTRAINT_FUNCTION

Код ошибки SQLITE_CONSTRAINT_FUNCTION в настоящее время не используется ядром SQLite.Однако этот код ошибки доступен для использования функциями расширения.

(1288) SQLITE_READONLY_CANTINIT

Код результата SQLITE_READONLY_CANTINIT берет начало в методе xShmMap VFS, чтобы указать, что область разделяемой памяти, используемая режимом WAL, существует, но ее содержимое ненадежно и непригодно для использования текущим процессом, поскольку текущий процесс не имеет разрешения на запись в область разделяемой памяти. (Область общей памяти для режима WAL обычно представляет собой файл с суффиксом «-wal», который отображается в пространстве процесса. Если текущий процесс не имеет разрешения на запись в этот файл, он не может записывать в общую память.)

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

(1290) SQLITE_IOERR_DIR_FSYNC

Код ошибки SQLITE_IOERR_DIR_FSYNC — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода на уровне VFS при попытке вызвать fsync () в каталоге. Unix VFS пытается открыть каталоги fsync () после создания или удаления определенных файлов, чтобы гарантировать, что эти файлы по-прежнему будут отображаться в файловой системе после отключения питания или сбоя системы. Этот код ошибки указывает на проблему при попытке выполнить эту fsync ().

(1294) SQLITE_CANTOPEN_DIRTYWAL

В настоящее время код результата SQLITE_CANTOPEN_DIRTYWAL не используется.

(1299) SQLITE_CONSTRAINT_NOTNULL

Код ошибки SQLITE_CONSTRAINT_NOTNULL — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий на сбой ограничения NOT NULL .

(1544) SQLITE_READONLY_DIRECTORY

Код результата SQLITE_READONLY_DIRECTORY указывает на то,что БД доступна только для чтения,так как процесс не имеет права создавать файл журнала в том же каталоге,что и БД,и создание файла журнала является обязательным условием для записи.

(1546) SQLITE_IOERR_TRUNCATE

Код ошибки SQLITE_IOERR_TRUNCATE — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода на уровне VFS при попытке усечь файл до меньшего размера.

(1550) SQLITE_CANTOPEN_SYMLINK

Код результата SQLITE_CANTOPEN_SYMLINK возвращается интерфейсом sqlite3_open () и его родственниками, когда используется флаг SQLITE_OPEN_NOFOLLOW и файл базы данных является символической ссылкой.

(1555) SQLITE_CONSTRAINT_PRIMARYKEY

Код ошибки SQLITE_CONSTRAINT_PRIMARYKEY — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий на сбой ограничения PRIMARY KEY .

(1802) SQLITE_IOERR_FSTAT

Код ошибки SQLITE_IOERR_FSTAT — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода на уровне VFS при попытке вызвать fstat () (или эквивалент) для файла, чтобы определить такую ​​информацию, как размер файла или права доступа.

(1811) SQLITE_CONSTRAINT_TRIGGER

Код ошибки SQLITE_CONSTRAINT_TRIGGER — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий, что сработала функция RAISE в триггере , в результате чего оператор SQL был прерван.

(2058) SQLITE_IOERR_UNLOCK

Код ошибки SQLITE_IOERR_UNLOCK — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xUnlock объекта sqlite3_io_methods .

(2067) SQLITE_CONSTRAINT_UNIQUE

Код ошибки SQLITE_CONSTRAINT_UNIQUE — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий на сбой ограничения UNIQUE .

(2314) SQLITE_IOERR_RDLOCK

Код ошибки SQLITE_IOERR_UNLOCK — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xLock объекта sqlite3_io_methods при попытке получить блокировку чтения.

(2323) SQLITE_CONSTRAINT_VTAB

Код ошибки SQLITE_CONSTRAINT_VTAB в настоящее время не используется ядром SQLite. Однако этот код ошибки доступен для использования виртуальными таблицами, определяемыми приложением .

(2570) SQLITE_IOERR_DELETE

Код ошибки SQLITE_IOERR_UNLOCK — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xDelete объекта sqlite3_vfs .

(2579) SQLITE_CONSTRAINT_ROWID

Код ошибки SQLITE_CONSTRAINT_ROWID — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий, что идентификатор строки не является уникальным.

(2826) SQLITE_IOERR_BLOCKED

Код ошибки SQLITE_IOERR_BLOCKED больше не используется.

(2835) SQLITE_CONSTRAINT_PINNED

Код ошибки SQLITE_CONSTRAINT_PINNED — это расширенный код ошибки для SQLITE_CONSTRAINT, указывающий, что попытка триггера UPDATE удаляет строку, которая обновлялась в середине обновления.

(3082) SQLITE_IOERR_NOMEM

Код ошибки SQLITE_IOERR_NOMEM иногда возвращается уровнем VFS, чтобы указать, что операция не может быть завершена из-за невозможности выделить достаточно памяти. Этот код ошибки обычно преобразуется в SQLITE_NOMEM более высокими уровнями SQLite перед возвратом в приложение.

(3091) SQLITE_CONSTRAINT_DATATYPE

Код ошибки SQLITE_CONSTRAINT_DATATYPE — это расширенный код ошибки для SQLITE_CONSTRAINT , указывающий на попытку вставки или обновления сохранить значение, несовместимое с объявленным типом столбца в таблице, определенной как STRICT.

(3338) SQLITE_IOERR_ACCESS

Код ошибки SQLITE_IOERR_ACCESS — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xAccess объекта sqlite3_vfs .

(3594) SQLITE_IOERR_CHECKRESERVEDLOCK

Код ошибки SQLITE_IOERR_CHECKRESERVEDLOCK — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xCheckReservedLock в объекте sqlite3_io_methods .

(3850) SQLITE_IOERR_LOCK

Код ошибки SQLITE_IOERR_LOCK — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в логике блокировки рекомендательного файла. Обычно ошибка SQLITE_IOERR_LOCK указывает на проблему с получением блокировки PENDING . Однако он также может указывать на различные ошибки блокировки на некоторых специализированных VFS, используемых на компьютерах Mac.

(4106) SQLITE_IOERR_CLOSE

Код ошибки SQLITE_IOERR_ACCESS — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xClose объекта sqlite3_io_methods .

(4362) SQLITE_IOERR_DIR_CLOSE

Код ошибки SQLITE_IOERR_DIR_CLOSE больше не используется.

(4618) SQLITE_IOERR_SHMOPEN

Код ошибки SQLITE_IOERR_SHMOPEN — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xShmMap объекта sqlite3_io_methods при попытке открыть новый сегмент разделяемой памяти.

(4874) SQLITE_IOERR_SHMSIZE

Код ошибки SQLITE_IOERR_SHMSIZE — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xShmMap в объекте sqlite3_io_methods при попытке увеличить файл «shm» как часть обработки транзакции в режиме WAL . Эта ошибка может указывать на то, что на томе базовой файловой системы не хватает места.

(5130) SQLITE_IOERR_SHMLOCK

Код ошибки SQLITE_IOERR_SHMLOCK больше не используется.

(5386) SQLITE_IOERR_SHMMAP

Код ошибки SQLITE_IOERR_SHMMAP — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методе xShmMap объекта sqlite3_io_methods при попытке сопоставить сегмент общей памяти в адресное пространство процесса.

(5642) SQLITE_IOERR_SEEK

Код ошибки SQLITE_IOERR_SEEK — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методах xRead или xWrite в объекте sqlite3_io_methods при попытке поиска файлового дескриптора до начальной точки файла, где должно произойти чтение или запись.

(5898) SQLITE_IOERR_DELETE_NOENT

Код ошибки SQLITE_IOERR_DELETE_NOENT — это расширенный код ошибки для SQLITE_IOERR, указывающий, что метод xDelete объекта sqlite3_vfs завершился неудачно, поскольку удаляемый файл не существует.

(6154) SQLITE_IOERR_MMAP

Код ошибки SQLITE_IOERR_MMAP — это расширенный код ошибки для SQLITE_IOERR, указывающий на ошибку ввода-вывода в методах xFetch или xUnfetch объекта sqlite3_io_methods при попытке сопоставить или отменить сопоставление части файла базы данных в адресное пространство процесса.

(6410) SQLITE_IOERR_GETTEMPPATH

Код ошибки SQLITE_IOERR_GETTEMPPATH — это расширенный код ошибки для SQLITE_IOERR, указывающий, что VFS не может определить подходящий каталог для размещения временных файлов.

(6666) SQLITE_IOERR_CONVPATH

Код ошибки SQLITE_IOERR_CONVPATH — это расширенный код ошибки для SQLITE_IOERR, который используется только Cygwin VFS и указывает на сбой системного вызова cygwin_conv_path (). См. Также: SQLITE_CANTOPEN_CONVPATH

(6922) SQLITE_IOERR_VNODE

Код ошибки SQLITE_IOERR_VNODE-это код,зарезервированный для использования расширениями.Он не используется ядром SQLite.

(7178) SQLITE_IOERR_AUTH

Код ошибки SQLITE_IOERR_AUTH-это код,зарезервированный для использования расширениями.Он не используется ядром SQLite.

(7434) SQLITE_IOERR_BEGIN_ATOMIC

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

(7690) SQLITE_IOERR_COMMIT_ATOMIC

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

(7946) SQLITE_IOERR_ROLLBACK_ATOMIC

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

(8202) SQLITE_IOERR_DATA

Код ошибки SQLITE_IOERR_DATA — это расширенный код ошибки для SQLITE_IOERR, используемый только прокладкой контрольной суммы VFS, чтобы указать, что контрольная сумма на странице файла базы данных неверна.

(8458) SQLITE_IOERR_CORRUPTFS

Код ошибки SQLITE_IOERR_CORRUPTFS — это расширенный код ошибки для SQLITE_IOERR, используемый только VFS для указания того, что сбой поиска или чтения произошел из-за того, что запрос не попадает в границы файла, а не из-за обычного сбоя устройства. Это часто указывает на поврежденную файловую систему.


SQLite

3.40

  • Причуды,пещеры и ловушки в SQLite.

    Язык SQL является «стандартным».

  • Расширение RBU

    Расширение RBU-это надстройка для SQLite,предназначенная для использования с большими файлами баз данных маломощных устройств на границе сети.

  • Rowid Tables

    «Таблица rowid» — это любая в схеме SQLite, которую таблицы Rowid отличают тем, что все они используют уникальное, ненулевое, подписанное 64-битное целое число.

  • Row Values

    «Значение» — это одиночное число, строка, BLOB или NULL.

SQLite Logo

Small. Fast. Reliable.
Choose any three.

SQL As Understood By SQLite

[Top]

create-trigger-stmt:

syntax diagram create-trigger-stmt

delete-stmt:

expr:

insert-stmt:

select-stmt:

update-stmt:

The CREATE TRIGGER statement is used to add triggers to the
database schema. Triggers are database operations
that are automatically performed when a specified database event
occurs.

A trigger may be specified to fire whenever a DELETE, INSERT,
or UPDATE of a
particular database table occurs, or whenever an UPDATE occurs on
on one or more specified columns of a table.

At this time SQLite supports only FOR EACH ROW triggers, not FOR EACH
STATEMENT triggers. Hence explicitly specifying FOR EACH ROW is optional.
FOR EACH ROW implies that the SQL statements specified in the trigger
may be executed (depending on the WHEN clause) for each database row being
inserted, updated or deleted by the statement causing the trigger to fire.

Both the WHEN clause and the trigger actions may access elements of
the row being inserted, deleted or updated using references of the form
«NEW.column-name» and «OLD.column-name«, where
column-name is the name of a column from the table that the trigger
is associated with. OLD and NEW references may only be used in triggers on
events for which they are relevant, as follows:

INSERT NEW references are valid
UPDATE NEW and OLD references are valid
DELETE OLD references are valid

If a WHEN clause is supplied, the SQL statements specified
are only executed for rows for which the WHEN
clause is true. If no WHEN clause is supplied, the SQL statements
are executed for all rows.

The BEFORE or AFTER keyword determines when the trigger actions
will be executed relative to the insertion, modification or removal of the
associated row.

An ON CONFLICT clause may be specified as part of an UPDATE or INSERT
action within the body of the trigger.
However if an ON CONFLICT clause is specified as part of
the statement causing the trigger to fire, then conflict handling
policy of the outer statement is used instead.

Triggers are automatically dropped
when the table that they are
associated with (the table-name table) is
dropped. However if the trigger actions reference
other tables, the trigger is not dropped or modified if those other
tables are dropped or modified.

Triggers are removed using the DROP TRIGGER statement.

Syntax Restrictions On UPDATE, DELETE, and INSERT Statements Within
Triggers

The UPDATE, DELETE, and INSERT
statements within triggers do not support
the full syntax for UPDATE, DELETE, and INSERT statements. The following
restrictions apply:

  • The name of the table to be modified in an UPDATE, DELETE, or INSERT
    statement must be an unqualified table name. In other words, one must
    use just «tablename» not «database.tablename»
    when specifying the table. The table to be modified must exist in the
    same database as the table or view to which the trigger is attached.

  • The «INSERT INTO table DEFAULT VALUES» form of the INSERT statement
    is not supported.

  • The INDEXED BY and NOT INDEXED clauses are not supported for UPDATE and
    DELETE statements.

  • The ORDER BY and LIMIT clauses on UPDATE and DELETE statements are not
    supported. ORDER BY and LIMIT are not normally supported for UPDATE or
    DELETE in any context but can be enabled for top-level statements
    using the SQLITE_ENABLE_UPDATE_DELETE_LIMIT compile-time option. However,
    that compile-time option only applies to top-level UPDATE and DELETE
    statements, not UPDATE and DELETE statements within triggers.

INSTEAD OF triggers

Triggers may be created on views, as well as ordinary tables, by
specifying INSTEAD OF in the CREATE TRIGGER statement.
If one or more ON INSERT, ON DELETE
or ON UPDATE triggers are defined on a view, then it is not an
error to execute an INSERT, DELETE or UPDATE statement on the view,
respectively. Instead,
executing an INSERT, DELETE or UPDATE on the view causes the associated
triggers to fire. The real tables underlying the view are not modified
(except possibly explicitly, by a trigger program).

Note that the sqlite3_changes() and sqlite3_total_changes() interfaces
do not count INSTEAD OF trigger firings, but the
count_changes pragma does count INSTEAD OF trigger firing.

Some Example Triggers

Assuming that customer records are stored in the «customers» table, and
that order records are stored in the «orders» table, the following
UPDATE trigger
ensures that all associated orders are redirected when a customer changes
his or her address:

CREATE TRIGGER update_customer_address UPDATE OF address ON customers 
  BEGIN
    UPDATE orders SET address = new.address WHERE customer_name = old.name;
  END;

With this trigger installed, executing the statement:

UPDATE customers SET address = '1 Main St.' WHERE name = 'Jack Jones';

causes the following to be automatically executed:

UPDATE orders SET address = '1 Main St.' WHERE customer_name = 'Jack Jones';

For an example of an INSTEAD OF trigger, consider the following schema:

CREATE TABLE customer(
  cust_id INTEGER PRIMARY KEY,
  cust_name TEXT,
  cust_addr TEXT
);
CREATE VIEW customer_address AS
   SELECT cust_id, cust_addr FROM customer;
CREATE TRIGGER cust_addr_chng
INSTEAD OF UPDATE OF cust_addr ON customer_address
BEGIN
  UPDATE customer SET cust_addr=NEW.cust_addr
   WHERE cust_id=NEW.cust_id;
END;

With the schema above, a statement of the form:

UPDATE customer_address SET cust_addr=$new_address WHERE cust_id=$cust_id;

Causes the customer.cust_addr field to be updated for a specific
customer entry that has customer.cust_id equal to the $cust_id parameter.
Note how the values assigned to the view are made available as field
in the special «NEW» table within the trigger body.

Cautions On The Use Of BEFORE triggers

If a BEFORE UPDATE or BEFORE DELETE trigger modifies or deletes a row
that was to have been updated or deleted, then the result of the subsequent
update or delete operation is undefined. Furthermore, if a BEFORE trigger
modifies or deletes a row, then it is undefined whether or not AFTER triggers
that would have otherwise run on those rows will in fact run.

The value of NEW.rowid is undefined in a BEFORE INSERT trigger in which
the rowid is not explicitly set to an integer.

Because of the behaviors described above, programmers are encouraged to
prefer AFTER triggers over BEFORE triggers.

The RAISE() function

A special SQL function RAISE() may be used within a trigger-program,
with the following syntax

raise-function:

syntax diagram raise-function

When one of RAISE(ROLLBACK,…), RAISE(ABORT,…) or RAISE(FAIL,…)
is called during trigger-program
execution, the specified ON CONFLICT processing is performed
the current query terminates.
An error code of SQLITE_CONSTRAINT is returned to the application,
along with the specified error message.

When RAISE(IGNORE) is called, the remainder of the current trigger program,
the statement that caused the trigger program to execute and any subsequent
trigger programs that would have been executed are abandoned. No database
changes are rolled back. If the statement that caused the trigger program
to execute is itself part of a trigger program, then that trigger program
resumes execution at the beginning of the next step.

TEMP Triggers on Non-TEMP Tables

A trigger normally exists in the same database as the table named
after the «ON» keyword in the CREATE TRIGGER statement. Except, it is
possible to create a TEMP TRIGGER on a table in another database.
Such a trigger will only fire when changes
are made to the target table by the application that defined the trigger.
Other applications that modify the database will not be able to see the
TEMP trigger and hence cannot run the trigger.

When defining a TEMP trigger on a non-TEMP table, it is important to
specify the database holding the non-TEMP table. For example,
in the following statement, it is important to say «main.tab1» instead
of just «tab1»:

CREATE TEMP TRIGGER ex1 AFTER INSERT ON main.tab1 BEGIN ...

Failure to specify the database name on the target table could result
in the TEMP trigger being reattached to a table with the same name in
another database whenever any schema change occurs.

Автор: Роман Чернышов (RXL)
Дата написания: 8.10.2011

  • Вводная
  • Объект с историей
    • Таблица jobcards__history
    • Таблица jobcards__index
    • Представление jobcards
  • Триггеры «INSTEAD OF» для представления
    • Триггер вставки
    • Триггер обновления
    • Триггер удаления

Некоторое время назад я заинтересовался SQLite. Это очень легкая встраиваемая реляционная база данных. Многие пользуются базами данных SQLite и даже не догадываются об этом. Примеры широко распространенных приложений, использующих SQLite — Mozilla Firefox (и другие продукты на платформе XUL), фремворк Qt и Skype. Также SQLite используется в API платформы Android.

Раньше мне вполне хватало MySQL для web-проектов и приложений небольшого масштаба (для больших приложений хорошо подходит Oracle). Но для малых приложений, работающих на одном хосте с базой данных, это не всегда удобно, так как, во-первых, СУБД MySQL нужно устанавливать и настраивать (от правильной настройки зависит производительность), во-вторых, нужны административные действия по управлению базами и пользователями. В таких случаях применяют встраиваемые базы данных. SQLite — одна из них.

Вкратце распишу достоинства SQLite:

  • Открытый исходный код и лицензия LGPL, позволяющая использовать библиотеки SQLite даже с коммерческими программами.
  • Стандартный язык SQL.
  • Поддержка весьма больших для встраиваемых баз объемов (штатно — до 64 ТБ, еще больших — через компиляцию с нужными параметрами).
  • Очень приличные лимиты (SQLite — Ограничения). Самым жестким из них является ограничение на 10 баз данных на одно подключение к библиотеке.
  • Поддержка доступа к файлу базы данных от нескольких потоков и процессов.
  • Поддержка транзакций и точек сохранения, два варианта логов отката и автоматическое управление им.
  • Поддержка расширений (доступен API).
  • Поддержка UDF-функций, находящихся в самом приложении.
  • Поддержка индексов — уникальных и не уникальных, с прямой и обратной сортировкой. Через расширение можно создать индекс полнотекстового поиска.
  • Поддержка вложенных запросов, представлений, триггеров, внешних ключей и автоматической нумерации новых строк (autoincrement).
  • Хранение строк таблицы в двоичном дереве. Каждая строка имеет идентификатор, по которому она находится в дереве быстрее, чем по индексам. В определенных условиях rowid совпадает с первичным ключом.
  • Поддержка таблиц статистики.
  • Поддержка баз только для чтения.
  • Поддержка UTF-8 и UTF-16.
  • Поддержка баз данных в файлах и в памяти.
  • Простота создания копий (что весьма часто приходится делать при тестировании приложения): просто скопировать файл.
  • Имеет поддержку для различных популярных языков программирования.
  • Есть механизм подготовленных запросов с поддержкой именованных и неименованных параметров.

Но самое главное достоинство SQLite — скорость работы. А если отключить поддержку логов отката (и транзакций, соответственно), то скорость работы возрастет еще на 1-2 порядка. Конечно, на больших объемах и нагрузках серьезные СУБД будут намного быстрее и эффективнее. На их нишу SQLite не претендует.

Конечно, есть у SQLite и минусы:

  • Система блокировок: shared или exclusive блокировка ставится на весь файл базы данных. Штатный режим работы транзакций — SERIALIZABLE. Хотя поддерживается и READ UNCOMMITED (соответственно, без блокировок). Но в режиме WAL возможны одновременные множественные запись и чтение в своих транзакциях.
  • Ограниченный набор типов столбцов: INTEGER, REAL, TEXT и BLOB. Дату и время хранят в одном из первых трех перечисленных типов.
  • Скудный набор встроенных функций.
  • Нет пользовательских процедур и функций — только через UDF.
  • ALTER TABLE допускает только добавление столбцов.
  • Нет пользовательских переменных.

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

Рекомендую использовать SQLite не ниже версии 3.7.0. У меня в тестах использовалась именно эта версия.

В приложениях нередко требуется хранение полной истории объектов (таблиц). С увеличением количества объектов работа с ними становится сложнее, а запросы к базе данных становятся громоздкими и медленными. Приведу пример объекта jobcards (можно понимать как «заявки на выполнение работ» или «заявка-наряд»). В примерах я показываю два столбца «полезной нагрузки» только для наглядности.

CREATE TABLE jobcards
(
    jobcard_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    ctime REAL NOT NULL,
    data1 TEXT,
    data2 TEXT
);

Запрос выборки:

SELECT *
  FROM jobcards
  WHERE jobcard_id = :JOBCARD_ID

Данный пример не поддерживает истории — возможна только одна строка на один идентификатор. Изменим таблицу:

CREATE TABLE jobcards
(
    jobcard_id INTEGER NOT NULL,
    ctime REAL NOT NULL,
    data1 TEXT,
    data2 TEXT,
    PRIMARY KEY (jobcard_id, ctime)
);

Теперь, чтобы выбрать последнее состояние объекта, потребуется такой запрос:

SELECT *
  FROM jobcards j1
  WHERE j1.jobcard_id = :JOBCARD_ID
    AND j1.ctime = (
      SELECT MAX(t2.ctime)
      FROM jobcards j2
      WHERE j2.jobcard_id = j1.jobcard_id
    )

Для первоначального состояния:

SELECT *
  FROM jobcards j1
  WHERE j1.jobcard_id = :JOBCARD_ID
    AND j1.ctime = (
      SELECT MIN(t2.ctime)
      FROM jobcards j2
      WHERE j2.jobcard_id = j1.jobcard_id
    )

Когда таблиц будет много, то описывать взаимосвязь станет еще сложнее. От написания громоздких, плохо читаемых запросов нас спасут представления (VIEW), а чтобы не искать каждый раз MAX — индексная таблица.

CREATE TABLE jobcards__history
(
    rowid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    jobcard_id INTEGER NOT NULL,
    ctime REAL NOT NULL DEFAULT CURRENT_TIMESTAMP,
    data1 TEXT,
    data2 TEXT
);

CREATE TABLE jobcards__index
(
    jobcard_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    deleted INTEGER(1) NOT NULL DEFAULT 0,
    first_rowid INTEGER NOT NULL DEFAULT 0,
    last_rowid INTEGER NOT NULL DEFAULT 0
);

CREATE VIEW jobcards AS
    SELECT jci.jobcard_id, jch.ctime, jch.data1, jch.data2
    FROM jobcards__index jci, jobcards__history jch
    WHERE jch.rowid = jci.last_rowid
        AND jci.deleted = 0;

Давайте прокомментирую некоторые моменты вышеприведенного кода.

Так как доступ по rowid быстрее и проще, то вместо индекса (jobcard_id, ctime) я сделал индекс по отдельному идентификатору. В SQLite столбец типа INTEGER и являющийся первичным ключом объединяется с rowid. По сути, вместо отдельного столбца через имя этого столбца осуществляется работа с rowid. Конечно, rowid нет необходимости объявлять — он есть у любой таблицы, но приведенная форма дает существенный плюс: значение rowid жестко зафиксировано за строкой. Для других случаев значение не фиксировано. Оно означает позицию строки в двоичном дереве и при выполнении команды VACUUM может поменяться (при этом происходит полное пересоздание базы данных и построение деревьев таблиц заново), а также, если сделать экспорт таблицы в SQL, то идентификатор не сохранится и связи будут неверными. Это все нужно для того, чтобы можно было надежно ссылаться на конкретные строки таблицы из других таблиц. Также отпадает нужда в других индексах (по крайне мере в рамках этой статьи). Штатный rowid доступен в запросах по следующим именам: rowid, oid и _rowid_. Любое из этих имен может быть использовано в качестве имени столбца — в этом случае оно не связано с настоящим rowid. В данном примере rowid и столбец — одно и тоже.

В нее я поместил два значения jobcards__history.rowid — для первой и последней строки истории объекта. Также добавил признак того, что объект завершил свое существование и в текущей ревизии списка отсутствует.

Интерфейс у него такой же, как и у первого варианта без поддержки истории. Но у нас есть «теневые» таблицы, и историю мы всегда сможем увидеть.

С такой моделью хранения данных можно работать по разному:

  • Вариант 1: читать из jobcards, писать в jobcards__history и вручную или по триггеру корректировать jobcards__index, следить за тем, пишется ли в таблицу первое состояние объекта, или уже есть история, а также «удалять» объект через jobcards__index.
  • Вариант 2: читать, вставлять, обновлять и удалять через jobcards с помощью набора триггеров «INSTEAD OF».

В SQLite в триггерах допустимы только DML-операторы SELECT, INSERT, UPDATE и DELETE. Причем переменных в SQLite нет и, соответственно, форма SELECT INTO не поддерживается.

Напрашивается вопрос: зачем вообще тут SELECT? Ответ неожиданный: для выполнения проверок и генерации исключений посредством функции RAISE.

В коде всех триггеров я опустил слова «FOR EACH ROW», так как они подразумеваются и другой формы SQLite не поддерживает.

Первая его задача — проверить, что строки с указанным идентификатором нет. За исключением случая, когда NEW.jobcard_id равен NULL. В этом случае генерируется новый уникальный номер посредством AUTOINCREMENT. Значение для ctime просто игнорируем — оно автоматически сгенерируется при вставке в jobcards__history.

CREATE TRIGGER jobcards__ii_update_index INSTEAD OF INSERT ON jobcards
BEGIN
    SELECT
            CASE
                WHEN NEW.jobcard_id IS NOT NULL AND MIN(rowid) IS NOT NULL
                    THEN RAISE(ABORT, ‘duplicate key’)
            END
        FROM jobcards__index
        WHERE jobcard_id = NEW.jobcard_id;
    INSERT INTO jobcards__index (jobcard_id) VALUES (NEW.jobcard_id);
    INSERT INTO jobcards__history
        (jobcard_id, data1, data2)
        VALUES (
            IFNULL(NEW.jobcard_id, last_insert_rowid()),
            NEW.data1,
            NEW.data2
        );
    UPDATE jobcards__index
        SET first_rowid = last_insert_rowid(),
            last_rowid = last_insert_rowid()
        WHERE jobcard_id = (
                SELECT jobcard_id
                FROM jobcards__history
                WHERE rowid = last_insert_rowid()
            );
END;

Протестируем триггер. Теневые таблицы пустые.

sqlite> INSERT INTO jobcards (data1, data2) VALUES (‘aaa’, ‘bbb’);
sqlite> INSERT INTO jobcards (data1, data2) VALUES (‘ccc’, ‘ddd’);
sqlite> SELECT * FROM jobcards__history;
rowid|jobcard_id|ctime|data1|data2
1|1|2011-10-08 13:56:24|aaa|bbb
2|2|2011-10-08 13:56:35|ccc|ddd
sqlite> SELECT * FROM jobcards__index;
jobcard_id|deleted|first_rowid|last_rowid
1|0|1|1
2|0|2|2
sqlite> SELECT * FROM jobcards;
jobcard_id|ctime|data1|data2
1|2011-10-08 13:56:24|aaa|bbb
2|2011-10-08 13:56:35|ccc|ddd
sqlite> INSERT INTO jobcards (jobcard_id, data1, data2) VALUES (1, ‘ccc’, ‘ddd’);
Error: duplicate key

Интересный факт: библиотека SQLite догадалась, что столбец REAL нужно интерпретировать как DATETIME. Видимо, по DEFAULT CURRENT_TIMESTAMP в описании таблицы. Подсветка строк — моих рук дело, утилита sqlite3 этим не занимается.

Должен проверить входные данные на следующие ошибки:

  • Нельзя изменять идентификатор.
  • Нельзя изменять дату.
  • Если строка не существует, то молча выходим.

CREATE TRIGGER jobcards__iu_update_index
    INSTEAD OF UPDATE OF data1, data2
    ON jobcards
BEGIN
    SELECT
            CASE
                WHEN NEW.jobcard_id != OLD.jobcard_id
                    THEN RAISE(ABORT, ‘no change key’)
                WHEN NEW.ctime != OLD.ctime
                    THEN RAISE(ABORT, ‘no change timestamp’)
            END;
    SELECT
            CASE
                WHEN MIN(rowid) IS NULL
                    THEN RAISE(IGNORE)
            END
        FROM jobcards__index
        WHERE jobcard_id = NEW.jobcard_id;
    INSERT INTO jobcards__history
        (jobcard_id, data1, data2)
        VALUES (
            NEW.jobcard_id,
            NEW.data1,
            NEW.data2
        );
    UPDATE jobcards__index
        SET last_rowid = last_insert_rowid()
        WHERE jobcard_id = NEW.jobcard_id;
END;

Тестируем триггер. Проверим на штатную ситуацию:

sqlite> UPDATE jobcards SET data1 = ‘eee’ WHERE jobcard_id = 1;
sqlite> SELECT * FROM jobcards__history;
rowid|jobcard_id|ctime|data1|data2
1|1|2011-10-08 13:56:24|aaa|bbb
2|2|2011-10-08 13:56:35|ccc|ddd
3|1|2011-10-08 14:10:05|eee|bbb
sqlite> SELECT * FROM jobcards__index;
jobcard_id|deleted|first_rowid|last_rowid
1|0|1|3
2|0|2|2

Проверим ошибочные ситуации:

sqlite> UPDATE jobcards SET ctime = CURRENT_TIMESTAMP WHERE jobcard_id = 1;
Error: cannot modify jobcards because it is a view
sqlite> UPDATE jobcards SET data1 = ‘qqq’, ctime = CURRENT_TIMESTAMP WHERE jobcard_id = 1;
Error: no change timestamp
sqlite> UPDATE jobcards SET jobcard_id = 111 WHERE jobcard_id = 1;
Error: cannot modify jobcards because it is a view
sqlite> UPDATE jobcards SET data1 = ‘qqq’, jobcard_id = 111 WHERE jobcard_id = 1;
Error: no change key

Отработало правильно. Обратите внимание на первый и третий оператор — это не мой триггер нашел ошибки, а SQLite сам так решил, на основе предоставленных ему инструкций: изменяемые столбцы перечислены в определении триггера. Второй и четвертый оператор — явная бага (или фича?) SQLite. Значит проверки на изменение запрещенных полей нужны обязательно.

В триггере удаления объекта возможны три варианта:

  • Удалить всю историю объекта.
  • Запретить удаление, вызвав исключение.
  • Пометить объект удаленным, чтобы он был недоступен на чтение через представление.

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

— Вариант 1: удалить историю и индекс.
CREATE TRIGGER jobcards__id_update_index INSTEAD OF DELETE ON jobcards
BEGIN
    DELETE FROM jobcards__index
        WHERE jobcard_id = OLD.jobcard_id;
    DELETE FROM jobcards__history
        WHERE jobcard_id = OLD.jobcard_id;
END;

— Вариант 2: запретить удаление.
CREATE TRIGGER jobcards__id_update_index INSTEAD OF DELETE ON jobcards
BEGIN
    SELECT RAISE(ABORT, ‘deletion disabled’);
END;

— Вариант 3: пометить виртуальную запись как удаленную.
CREATE TRIGGER jobcards__id_update_index INSTEAD OF DELETE ON jobcards
BEGIN
    UPDATE jobcards__index
        SET deleted = 1
        WHERE jobcard_id = OLD.jobcard_id;
END;

Я выбираю вариант 3. Тестируем…

sqlite> DELETE FROM jobcards WHERE jobcard_id = 1;
sqlite> SELECT * FROM jobcards__history;
rowid|jobcard_id|ctime|data1|data2
1|1|2011-10-08 13:56:24|aaa|bbb
2|2|2011-10-08 13:56:35|ccc|ddd
3|1|2011-10-08 14:10:05|eee|bbb
sqlite> SELECT * FROM jobcards__index;
jobcard_id|deleted|first_rowid|last_rowid
1|1|1|3
2|0|2|2
sqlite> SELECT * FROM jobcards;
jobcard_id|ctime|data1|data2
2|2011-10-08 13:56:35|ccc|ddd

Обратите внимание: поле deleted приняло значение 1 и в представлении строка не отображается.

Если кто заметит ошибки или у вас есть, что сказать по теме — прошу писать в обсуждение статьи.

Last update on August 19 2022 21:50:40 (UTC/GMT +8 hours)

Introduction on Triggers

A trigger is an event-driven action that is run automatically when a specified change operation ( INSERT, UPDATE, and DELETE statement) is performed on a specified table. Triggers are useful for tasks such as enforcing business rules, validating input data, and keeping an audit trail.

Table of contents

Uses for triggers

Benefits of using triggers in business

Create SQLite triggers

Sample database, table, table structure, table records

SQLite Trigger : Example AFTER INSERT

SQLite Trigger : Example BEFORE INSERT

SQLite Trigger : Example AFTER UPDATE

SQLite Trigger : Example BEFORE UPDATE

SQLite Trigger : Example AFTER DELETE

SQLite Trigger : Example BEFORE DELETE

SQLite Trigger : Example INSERT using INSTEAD OF

SQLite Trigger : Example UPDATE using INSTEAD OF

SQLite Trigger : Example DELETE using INSTEAD OF

Drop/Delete a SQLite trigger

Uses for triggers:

  • Enforce business rules
  • Validate input data
  • Generate a unique value for a newly-inserted row in a different file.
  • Write to other files for audit trail purposes
  • Query from other files for cross-referencing purposes
  • Access system functions
  • Replicate data to different files to achieve data consistency

Benefits of using triggers in business:

  • Faster application development. Because the database stores triggers, you do not have to code the trigger actions into each database application.
  • Global enforcement of business rules. Define a trigger once and then reuse it for any application that uses the database.
  • Easier maintenance. If a business policy changes, you need to change only the corresponding trigger program instead of each application program.
  • Improve performance in client/server environment. All rules run on the server before the result returns.

Implementation of SQL triggers is based on the SQL standard. It supports constructs that are common to most programming languages. It supports the declaration of local variables, statements to control the flow of the procedure, assignment of expression results to variables, and error handling.

SQLite: Create trigger

A trigger is a named database object that is associated with a table, and it activates when a particular event (e.g. an insert, update or delete) occurs for the table/views. The statement CREATE TRIGGER creates a new trigger in SQLite. The CREATE TRIGGER statement is used to add triggers to the database schema. Triggers are database operations that are automatically performed when a specified database event occurs.

Here is the syntax :

Syntax:

CREATE [TEMP | TEMPORARY] TRIGGER trigger-name

[BEFORE | AFTER] database-event ON [database-name .]table-name
trigger-action

trigger-action is further defined as: 

[FOR EACH ROW | FOR EACH STATEMENT] [WHEN expression]
BEGIN
trigger-step; [trigger-step;] *
END

Parameters:

Name Description
trigger-name The name of the trigger. A trigger  must be distinct from the name of any other trigger for the same table. The name cannot be schema-qualified — the trigger inherits the schema of its table. 
BEFORE
AFTER
INSTEAD OF
Determines whether the function is called before, after, or instead of the event. A constraint trigger can only be specified as AFTER.
database-event One of the INSERT, UPDATE, DELETE that will fire the trigger.
table-name The name of the table or view the trigger is for.
FOR EACH ROW
FOR EACH STATEMENT
Specifies whether the trigger procedure should be fired once for every row affected by the trigger event, or just once per SQL statement. If neither is specified, FOR EACH STATEMENT is the default.
expression A Boolean expression that determines whether the trigger function will actually be executed.
trigger-step Action for the trigger, it is the sql statement.

There is two SQLite extension to triggers ‘OLD‘ and ‘NEW‘. OLD and NEW are not case sensitive.

  • Within the trigger body, the OLD and NEW keywords enable you to access columns in the rows affected by a trigger
  • In an INSERT trigger, only NEW.col_name can be used.
  • In a UPDATE trigger, you can use OLD.col_name to refer to the columns of a row before it is updated and NEW.col_name to refer to the columns of the row after it is updated.
  • In a DELETE trigger, only OLD.col_name can be used; there is no new row.

Sample database, table, table structure, table records for various examples

emp_details

SQLite Trigger: Example AFTER INSERT

In the following example, we have two tables : emp_details and emp_log. To insert some information into emp_logs table (which have three fields emp_id and salary and edttime) every time, when an INSERT happen into emp_details table we have used the following trigger :

Here is the trigger ins_same_rec:

CREATE TRIGGER aft_insert AFTER INSERT ON emp_details
BEGIN
INSERT INTO emp_log(emp_id,salary,edittime)
         VALUES(NEW.employee_id,NEW.salary,current_date);
END;

Records of the table (on some columns): emp_details

sqlite> SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB_ID, SALARY, COMMISSION_PCT FROM emp_details;

employee_id  first_name  last_name   job_id      salary      commission_pct
-----------  ----------  ----------  ----------  ----------  --------------
100          Steven      King        AD_PRES     24000
101          Neena       Kochhar     AD_VP       17000
102          Lex         De Haan     AD_VP       17000
103          Alexander   Hunold      IT_PROG     9000
104          Bruce       Ernst       IT_PROG     6000
105          David       Austin      IT_PROG     4800
106          Valli       Pataballa   IT_PROG     4800
107          Diana       Lorentz     IT_PROG     4200
108          Nancy       Greenberg   FI_MGR      12000
109          Daniel      Faviet      FI_ACCOUNT  9000
110          John        Chen        FI_ACCOUNT  8200
111          Ismael      Sciarra     FI_ACCOUNT  7700
112          Jose Manue  Urman       FI_ACCOUNT  7800

Records of the table (all columns): emp_log

sqlite> SELECT * FROM emp_log;
emp_id      salary      edittime
----------  ----------  ----------
100         24000       2011-01-15
101         17000       2010-01-12
102         17000       2010-09-22
103         9000        2011-06-21
104         6000        2012-07-05
105         4800        2011-06-02

Now insert one record in emp_details table see the records both in emp_details and emp_log tables :

INSERT INTO emp_details 
VALUES(236, 'RABI', 'CHANDRA', 'RABI','590.423.45700', '2013-01-12', 'AD_VP', 15000, .5,NULL,NULL);

sqlite>  SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB_ID, SALARY, COMMISSION_PCT FROM emp_details;
employee_id  first_name  last_name   job_id      salary      commission_pct
-----------  ----------  ----------  ----------  ----------  --------------
100          Steven      King        AD_PRES     24000
101          Neena       Kochhar     AD_VP       17000
102          Lex         De Haan     AD_VP       17000
103          Alexander   Hunold      IT_PROG     9000
104          Bruce       Ernst       IT_PROG     6000
105          David       Austin      IT_PROG     4800
106          Valli       Pataballa   IT_PROG     4800
107          Diana       Lorentz     IT_PROG     4200
108          Nancy       Greenberg   FI_MGR      12000
109          Daniel      Faviet      FI_ACCOUNT  9000
110          John        Chen        FI_ACCOUNT  8200
111          Ismael      Sciarra     FI_ACCOUNT  7700
112          Jose Manue  Urman       FI_ACCOUNT  7800
236          RABI        CHANDRA     AD_VP       15000       0.5
sqlite> SELECT * FROM emp_log;
emp_id      salary      edittime
----------  ----------  ----------
100         24000       2011-01-15
101         17000       2010-01-12
102         17000       2010-09-22
103         9000        2011-06-21
104         6000        2012-07-05
105         4800        2011-06-02
236         15000       2014-10-13

itemscope itemtype=»http://schema.org/WebPageElement/Heading»>SQLite Trigger : Example BEFORE INSERT

In the following example, before inserting a new record in emp_details table, a trigger check the column value of FIRST_NAME, LAST_NAME, JOB_ID and
— If there are any space(s) before or after the FIRST_NAME, LAST_NAME, LTRIM() function will remove those.
— The value of the JOB_ID will be converted to upper cases by UPPER() function.

Here is the trigger befo_insert:

CREATE TRIGGER befo_insert BEFORE INSERT ON emp_details
BEGIN
SELECT CASE 
WHEN ((SELECT emp_details . employee_id FROM emp_details WHERE emp_details.employee_id = NEW.employee_id ) ISNULL) 
THEN RAISE(ABORT, 'This is an User Define Error Message - This employee_id does not exist.') 
END; 
END;

Now insert a row into emp_details table (check the employee_id column, whether it is exists or not.) :

INSERT INTO emp_details(employee_id,first_name,last_name)values(250,'Jeson','Flap');

Now, here is the output.

sqlite> INSERT INTO emp_details(employee_id,first_name,last_name)values(250,'Jeson','Flap');
Error: This is an User Define Error Message - This employee_id does not exist.

SQLite Trigger: Example AFTER UPDATE

We have two tables student_mast and stu_log. student_mast have three columns STUDENT_ID, NAME, ST_CLASS. stu_log table has two columns user_id and description.

sqlite> SELECT * FROM student_mast;
student_id  name                            st_class
----------  ------------------------------  ----------
1           Steven King                     7
2           Neena  Kochhar                  8
3           Lex  De Haan                    9
4           Alexander Hunold                10

Let we promote all the students in next class i.e. 7 will be 8, 8 will be 9 and so on. After updating a single row in student_mast table a new row will be inserted in stu_log table where we will store the current user id and a small description regarding the current update. Here is the trigger code :

Here is the trigger for that event-

CREATE TRIGGER aft_update AFTER UPDATE ON student_mast
BEGIN
INSERT into stu_log (description) values('Update Student Record '||
         OLD.NAME || '    Previous Class : '||OLD.ST_CLASS ||'    Present Class '||
         NEW.st_class);
END;

Now update the student_mast table:

UPDATE student_mast SET st_class = st_class + 1;

The trigger shows you the updated records in ‘stu_log’. Here is the latest position of student_mast and stu_log tables :

sqlite> SELECT * FROM student_mast;
student_id  name                  st_class
----------  --------------------  ----------
1           Steven King           8
2           Neena  Kochhar        9
3           Lex  De Haan          10
4           Alexander Hunold      11
sqlite> SELECT description FROM stu_log;
description
--------------------------------------------------------------------------------------
Update Student Record Steven King    Previous Class : 7    Present Class 8
Update Student Record Neena  Kochhar    Previous Class : 8    Present Class 9
Update Student Record Lex  De Haan    Previous Class : 9    Present Class 10
Update Student Record Alexander Hunold    Previous Class : 10    Present Class 11
sqlite> SELECT * FROM student_mast;

SQLite Trigger: Example BEFORE UPDATE

We have two tables student_mast and student_marks. Here are the sample tables below. The student_id column of student_mast table is the primary key and in student_marks table, it is a foreign key, the reference to student_id column of student_mast table.

Table - student_mast;
student_id  name                            st_class
----------  ------------------------------  ----------
1           Steven King                     7
2           Neena  Kochhar                  8
3           Lex  De Haan                    9
4           Alexander Hunold                10


Table - student_marks
student_id  name                  sub1        sub2
----------  --------------------  ----------  ---------
1           Steven King
2           Neena  Kochhar
3           Lex De Haan
4           Alexander Hunold

Here is the trigger

CREATE TRIGGER befo_update BEFORE UPDATE ON student_mast
BEGIN
SELECT CASE 
WHEN ((SELECT student_id FROM student_marks WHERE student_id = NEW.student_id ) ISNULL) 
THEN RAISE(ABORT, 'This is a User Define Error Message - This ID can not be updated.') 
END; 
END;

Now we are going to update the primary key column of student_mast table and look the result below.

sqlite> UPDATE student_mast SET student_id=10 WHERE st_class=9;
Error: This is an User Define Error Message - This ID can not be updated.

SQLite Trigger: Example AFTER DELETE

In our ‘AFTER UPDATE’ example, we had two tables student_mast and stu_log. student_mast have three columns STUDENT_ID, NAME, ST_CLASS and stu_log table has two columns user_id and description. We want to store some information in stu_log table after a delete operation happened on student_mast table. Here is the trigger :

Here is the trigger

CREATE TRIGGER aft_delete AFTER DELETE ON student_mast 
BEGIN 
INSERT into stu_log (description) VALUES ('Update Student Record '||
         OLD.NAME||' Class : '||OLD.ST_CLASS||' -> Deleted on  '||
         date('NOW')); 
END;

Let delete a student from student_mast

sqlite> DELETE FROM STUDENT_MAST WHERE STUDENT_ID = 1;

Here is the latest position of student_mast, stu_log tables :

sqlite>  SELECT * FROM STUDENT_MAST;
student_id  name                  st_class
----------  --------------------  ---------
2           Neena  Kochhar        9
3           Lex  De Haan          10
4           Alexander Hunold      11

sqlite> SELECT description FROM stu_log;
description
------------------------------------------------------------------------------------
Update Student Record Steven King    Previous Class : 7    Present Class 8
Update Student Record Neena  Kochhar    Previous Class : 8    Present Class 9
Update Student Record Lex  De Haan    Previous Class : 9    Present Class 10
Update Student Record Alexander Hunold    Previous Class : 10    Present Class 11
Update Student Record Steven King Class : 8 -> Deleted on  2014-10-13

SQLite Trigger: Example BEFORE DELETE

We have two tables student_mast and student_marks. Here are the sample tables below. The student_id column of student_mast table is the primary key and in student_marks table, it is a foreign key, a reference to student_id column of student_mast table.

Table - student_mast;
student_id  name                            st_class
----------  ------------------------------  ----------
1           Steven King                     7
2           Neena  Kochhar                  8
3           Lex  De Haan                    9
4           Alexander Hunold                10


Table - student_marks
student_id  name                  sub1        sub2
----------  --------------------  ----------  ---------
1           Steven King
2           Neena  Kochhar
3           Lex De Haan
4           Alexander Hunold

Here is the trigger

CREATE TRIGGER befo_delete BEFORE DELETE ON student_marks
BEGIN
SELECT CASE 
WHEN (SELECT COUNT(student_id) FROM student_mast WHERE student_id=OLD.student_id) > 0
THEN RAISE(ABORT,
'Foreign Key Violation: student_masts rows reference row to be deleted.')
END; 
END;

Let try to delete a student from student_marks and see the result.

sqlite> DELETE FROM student_marks WHERE name='Steven King';
Error: Foreign Key Violation: student_masts rows reference row to be deleted.

SQLite trigger using INSTEAD OF

Here is the sample table emp_details.

employee_id  first_name  last_name   email      
-----------  ----------  ----------  ---------- 
100          Steven      King        SKING      
101          Neena       Kochhar     NKOCHHAR   
102          Lex         De Haan     LDEHAAN    
103          Alexander   Hunold      AHUNOLD    
104          Bruce       Ernst       BERNST     
105          David       Austin      DAUSTIN    
106          Valli       Pataballa   VPATABAL   
107          Diana       Lorentz     DLORENTZ   
108          Nancy       Greenberg   NGREENBE   
109          Daniel      Faviet      DFAVIET    
110          John        Chen        JCHEN      
111          Ismael      Sciarra     ISCIARRA   
112          Jose Manue  Urman       JMURMAN    
236          RABI        CHANDRA     RABI       

Now create a view name emp_details_view.

CREATE VIEW emp_details_view
AS
SELECT employee_id,first_name,last_name,email
FROM emp_details
ORDER BY first_name,last_name;

Now see the just created view .

sqlite> SELECT name FROM sqlite_master WHERE type='view';
name
emp_details_view

Here is the view.

employee_id  first_name  last_name   email
-----------  ----------  ----------  ----------
103          Alexander   Hunold      AHUNOLD
104          Bruce       Ernst       BERNST
109          Daniel      Faviet      DFAVIET
105          David       Austin      DAUSTIN
107          Diana       Lorentz     DLORENTZ
111          Ismael      Sciarra     ISCIARRA
110          John        Chen        JCHEN
112          Jose Manue  Urman       JMURMAN
102          Lex         De Haan     LDEHAAN
108          Nancy       Greenberg   NGREENBE
101          Neena       Kochhar     NKOCHHAR
236          RABI        CHANDRA     RABI
100          Steven      King        SKING
106          Valli       Pataballa   VPATABAL

INSERT TRIGGER using INSTEAD OF

Here is the example

CREATE TRIGGER view_ins_trig 
INSTEAD OF INSERT 
ON emp_details_view 
BEGIN
        INSERT INTO emp_details(employee_id,first_name,last_name,email) 
        SELECT new.employee_id, new.first_name,new.last_name,new.email; 
END;

Now insert the rows in the emp_details_view and the triggers will propagate those changes to the underlying table..

INSERT INTO emp_details_view (employee_id,first_name,last_name,email) 
VALUES (250,'Andrai', 'Marku','and_mar');

Now look the view and the base table

base table - emp_details
employee_id           first_name  last_name   email
--------------------  ----------  ----------  ----------
100                   Steven      King        SKING
101                   Neena       Kochhar     NKOCHHAR
102                   Lex         De Haan     LDEHAAN
103                   Alexander   Hunold      AHUNOLD
104                   Bruce       Ernst       BERNST
105                   David       Austin      DAUSTIN
106                   Valli       Pataballa   VPATABAL
107                   Diana       Lorentz     DLORENTZ
108                   Nancy       Greenberg   NGREENBE
109                   Daniel      Faviet      DFAVIET
110                   John        Chen        JCHEN
111                   Ismael      Sciarra     ISCIARRA
112                   Jose Manue  Urman       JMURMAN
236                   RABI        CHANDRA     RABI
250                   Andrai      Marku       and_mar

view - emp_details_view
employee_id           first_name  last_name   email
--------------------  ----------  ----------  ----------
103                   Alexander   Hunold      AHUNOLD
250                   Andrai      Marku       and_mar
104                   Bruce       Ernst       BERNST
109                   Daniel      Faviet      DFAVIET
105                   David       Austin      DAUSTIN
107                   Diana       Lorentz     DLORENTZ
111                   Ismael      Sciarra     ISCIARRA
110                   John        Chen        JCHEN
112                   Jose Manue  Urman       JMURMAN
102                   Lex         De Haan     LDEHAAN
108                   Nancy       Greenberg   NGREENBE
101                   Neena       Kochhar     NKOCHHAR
236                   RABI        CHANDRA     RABI
100                   Steven      King        SKING
106                   Valli       Pataballa   VPATABAL

UPDATE TRIGGER using INSTEAD OF

Here is the example

CREATE TRIGGER view_update_trig 
INSTEAD OF UPDATE 
ON emp_details_view 
BEGIN 
        UPDATE emp_details 
        SET employee_id = new.employee_id, first_name = new.first_name, last_name = new.last_name        
WHERE employee_id = old.employee_id; 
END;

Now update the rows in the emp_details_view.

UPDATE emp_details_view SET first_name = 'Andrai' 
WHERE first_name = 'RABI' AND last_name= 'CHANDRA';
 

Now look the view and the base table

base table - emp_details
employee_id           first_name  last_name   email
--------------------  ----------  ----------  ----------
100                   Steven      King        SKING
101                   Neena       Kochhar     NKOCHHAR
102                   Lex         De Haan     LDEHAAN
103                   Alexander   Hunold      AHUNOLD
104                   Bruce       Ernst       BERNST
105                   David       Austin      DAUSTIN
106                   Valli       Pataballa   VPATABAL
107                   Diana       Lorentz     DLORENTZ
108                   Nancy       Greenberg   NGREENBE
109                   Daniel      Faviet      DFAVIET
110                   John        Chen        JCHEN
111                   Ismael      Sciarra     ISCIARRA
112                   Jose Manue  Urman       JMURMAN
236                   Andrai      CHANDRA     RABI

view - emp_details_view
employee_id           first_name  last_name   email
--------------------  ----------  ----------  ----------
103                   Alexander   Hunold      AHUNOLD
236                   Andrai      CHANDRA     RABI
104                   Bruce       Ernst       BERNST
109                   Daniel      Faviet      DFAVIET
105                   David       Austin      DAUSTIN
107                   Diana       Lorentz     DLORENTZ
111                   Ismael      Sciarra     ISCIARRA
110                   John        Chen        JCHEN
112                   Jose Manue  Urman       JMURMAN
102                   Lex         De Haan     LDEHAAN
108                   Nancy       Greenberg   NGREENBE
101                   Neena       Kochhar     NKOCHHAR
100                   Steven      King        SKING
106                   Valli       Pataballa   VPATABAL

DELETE TRIGGER using INSTEAD OF

Here is the example

CREATE TRIGGER view_delete_trig 
INSTEAD OF delete 
ON emp_details_view
BEGIN 
        DELETE FROM emp_details 
		WHERE employee_id = old.employee_id; 
END;

Now delete the row from the emp_details_view which employee_id is 106, and look the result.

DELETE FROM emp_details_view 
WHERE employee_id = 106; 

Now look the view and the base table

base table - emp_details
employee_id           first_name  last_name   email
--------------------  ----------  ----------  ----------
100                   Steven      King        SKING
101                   Neena       Kochhar     NKOCHHAR
102                   Lex         De Haan     LDEHAAN
103                   Alexander   Hunold      AHUNOLD
104                   Bruce       Ernst       BERNST
105                   David       Austin      DAUSTIN
107                   Diana       Lorentz     DLORENTZ
108                   Nancy       Greenberg   NGREENBE
109                   Daniel      Faviet      DFAVIET
110                   John        Chen        JCHEN
111                   Ismael      Sciarra     ISCIARRA
112                   Jose Manue  Urman       JMURMAN
236                   Andrai      CHANDRA     RABI


view - emp_details_view
employee_id           first_name  last_name   email
--------------------  ----------  ----------  ----------
103                   Alexander   Hunold      AHUNOLD
236                   Andrai      CHANDRA     RABI
104                   Bruce       Ernst       BERNST
109                   Daniel      Faviet      DFAVIET
105                   David       Austin      DAUSTIN
107                   Diana       Lorentz     DLORENTZ
111                   Ismael      Sciarra     ISCIARRA
110                   John        Chen        JCHEN
112                   Jose Manue  Urman       JMURMAN
102                   Lex         De Haan     LDEHAAN
108                   Nancy       Greenberg   NGREENBE
101                   Neena       Kochhar     NKOCHHAR
100                   Steven      King        SKING

The row has been deleted which contain the employee_id 106.

DROP an SQLite trigger

To delete or destroy a trigger, use a DROP TRIGGER statement. To execute this command, the current user must be the owner of the table for which the trigger is defined.

Syntax:

DROP TRIGGER trigger_name

Example:

If you delete or drop the just created trigger delete_stu the following statement can be used:

DROP TRIGGER delete_stu on student_mast;

The trigger delete_stu will be deleted.

Previous:
Subqueries

Next:
SQLite Exercises Introduction

Понравилась статья? Поделить с друзьями:
  • Sqlite returning syntax error
  • Sqlite raise error
  • Sqlite near with syntax error
  • Sqlite error unrecognized token
  • Sql state hy010 function sequence error