Ошибка при создании триггера.

Совместимость InterBase, Firebird, Yaffil между собой и по версиям

Модераторы: kdv, Alexey Kovyazin

Ответить
aminmsk
Сообщения: 6
Зарегистрирован: 26 июл 2010, 11:52

Ошибка при создании триггера.

Сообщение aminmsk » 12 авг 2010, 12:20

Доброго времени суток.
Ни как не могу разобраться.
Выгружаю триггер через IBExpert из Firebird 1.0 в Firebird 2.0.6. Через создание скрипта, соответственно.
Возникает ошибка :

Код: Выделить всё

/*******************************************************************************
The next statement causes the following error:

can't format message 13:849 -- message system code -4.
attempted update of read-only column.
*******************************************************************************/
По скольку сам программистом не являюсь, понять, что птице не нравится, не могу.
По этому, огромная просьба показать, где ошибка и что конкретно птице не нравится.
Код триггера:

Код: Выделить всё

CREATE OR ALTER TRIGGER IMP_DOC_AU FOR DOC
ACTIVE AFTER UPDATE POSITION 1
AS
  DECLARE VARIABLE NewImpex INTEGER;
  DECLARE VARIABLE p_id INTEGER;
  DECLARE VARIABLE p_eid INTEGER;
  DECLARE VARIABLE tmp INTEGER;
BEGIN
  IF (GEN_ID(switch_replic, 0) = 1) THEN
  BEGIN
    IF (old.dimpex IS NULL) THEN old.dimpex = 0;
    IF (old.dimpex <> 0) THEN
    /* Если поменяли Склад, Нашу фирму, Счет/Касса/Сотрудник то необходимо высылать связанные записи,
       т.к. в предыдущий экспорт это могло не уйти.
       Меняем IMPEX... */
    IF ((new.dconcept IN (6001, 6002, 6003, 6051, 6052, 6053, 6059, 6102, 6103, 6104, 6802, 6803, 6901, 6904, 6951, 6953) AND
         ((old.did2 <> new.did2) OR (old.did4 <> new.did4)))
        OR
        (new.dconcept IN (6801, 6601, 6203, 6204, 6401, 6402) AND
         (old.did2 <> new.did2))
        OR
        (new.dconcept = 6101 AND
         ((old.did1 <> new.did1) OR (old.did4 <> new.did4) OR (old.did2 <> new.did2)))
        OR
        (new.dconcept in (6201, 6202) AND
         ((old.did2 <> new.did2) OR (old.did4 <> new.did4)))
        OR
        (new.dconcept = 6251 AND
         ((old.did2 <> new.did2) OR (old.did9 <> new.did9) OR (old.did1 <> new.did1) OR (old.did4 <> new.did4)))
       ) THEN
    BEGIN
      NewImpex = GEN_ID(genimpex, 0);
      UPDATE lin    SET eimpex  = :NewImpex WHERE eiddoc  = old.did OR eiddoc  = -old.did;
      UPDATE lina   SET eimpexa = :NewImpex WHERE eiddoca = old.did OR eiddoca = -old.did;
      UPDATE his    SET himpex  = :NewImpex WHERE hidrec  = old.did;
      UPDATE docstr SET simpex  = :NewImpex WHERE sidlib  = old.did;
      UPDATE lnk    SET iimpex  = :NewImpex WHERE idid1   = old.did OR idid2   = old.did;
      UPDATE lnka   SET iimpexa = :NewImpex WHERE idid1a  = old.did OR idid2a  = old.did;

      FOR
        SELECT id FROM xstruct
          WHERE flag = 2 AND node = 0 AND UPPER(tname) = 'DOC' AND UPPER(fname) = 'DID' AND shortcut <> 1
          INTO :p_id
      DO
      BEGIN
        UPDATE xecblob SET ximpex = :NewImpex WHERE global = old.did AND concept = :p_id;
        UPDATE xecdate SET ximpex = :NewImpex WHERE global = old.did AND concept = :p_id;
        UPDATE xecint  SET ximpex = :NewImpex WHERE global = old.did AND concept = :p_id;
        UPDATE xecnum  SET ximpex = :NewImpex WHERE global = old.did AND concept = :p_id;
        UPDATE xecvc80 SET ximpex = :NewImpex WHERE global = old.did AND concept = :p_id;
      END

      /* Также поменяем IMPEX на текущий у записей, связанных с LIN... */
      FOR
        SELECT eid FROM lin
          WHERE eiddoc = old.did
          INTO :p_eid
      DO
      BEGIN
        UPDATE idn SET timpex = :NewImpex WHERE teid1 = :p_eid OR teid2 = :p_eid;
        UPDATE rma SET rimpex = :NewImpex WHERE reid1 = :p_eid OR reid2 = :p_eid;

        FOR
          SELECT id FROM xstruct
            WHERE flag = 2 AND node = 0 AND UPPER(tname) = 'LIN' AND UPPER(fname) = 'EID' AND shortcut <> 1
            INTO :p_id
        DO
        BEGIN
          UPDATE xecblob SET ximpex = :NewImpex WHERE global = :p_eid AND concept = :p_id;
          UPDATE xecdate SET ximpex = :NewImpex WHERE global = :p_eid AND concept = :p_id;
          UPDATE xecint  SET ximpex = :NewImpex WHERE global = :p_eid AND concept = :p_id;
          UPDATE xecnum  SET ximpex = :NewImpex WHERE global = :p_eid AND concept = :p_id;
          UPDATE xecvc80 SET ximpex = :NewImpex WHERE global = :p_eid AND concept = :p_id;
        END
      END /* LIN */
      /* Вставим в DEL команду на удаление - если документ не придет на УБД, например, по
         причине того что сменили склад, то он там удалиться, а если придет в этом пакете,
         то команда проигнорируется. */
       INSERT INTO del (DelID, DelTable, DelRecord) VALUES (GEN_ID(gendel, 1), 'DOC', old.did);
    END
  END
END
;
По серверу и по:
OS: CentOS 5.3 Final x32
Server: Firebird CS 2.0.6
Миграция UDF и isc4.gdb -> security2.fdb сделана.
Заранее спасибо тем кто откликнется! :)

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Ошибка при создании триггера.

Сообщение hvlad » 12 авг 2010, 12:29

Триггер кривой, в old нельзя ничего присвоить.
Замени

Код: Выделить всё

    IF (old.dimpex IS NULL) THEN old.dimpex = 0;
    IF (old.dimpex <> 0) THEN
на

Код: Выделить всё

    IF (old.dimpex <> 0 AND old.dimpex IS NOT NULL) THEN

aminmsk
Сообщения: 6
Зарегистрирован: 26 июл 2010, 11:52

Re: Ошибка при создании триггера.

Сообщение aminmsk » 12 авг 2010, 12:47

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

Первое

Код: Выделить всё

IF (old.lconcept < 0) THEN old.lconcept = -old.lconcept;
Второе

Код: Выделить всё

/* Trigger: LIB_AI */
CREATE OR ALTER TRIGGER LIB_AI FOR LIB
ACTIVE AFTER INSERT POSITION 0
AS
BEGIN
  new.ldate = 'now';
END
Третье

Код: Выделить всё

/* Trigger: LIB_AU */
CREATE OR ALTER TRIGGER LIB_AU FOR LIB
ACTIVE AFTER UPDATE POSITION 0
AS
BEGIN
  new.ldate = 'now';
END
И последний вопрос.
По мнению огнептица такое выражение не является правильным:

Код: Выделить всё

new.code_up      = UPPER(trim(new.code, 0) COLLATE PXW_CYRL);
Ругается на ", 0" , на что его можно заменить?

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Ошибка при создании триггера.

Сообщение Dimitry Sibiryakov » 12 авг 2010, 15:00

Первое вообще выкинуть, как бессмысленное.
Второе и третье - RTFM уже Release Notes на предмет CURRENT_TIMESTAMP
Четвёртое - опять же RTFM о синтаксисе встроенной функции TRIM.

aminmsk
Сообщения: 6
Зарегистрирован: 26 июл 2010, 11:52

Re: Ошибка при создании триггера.

Сообщение aminmsk » 12 авг 2010, 15:09

Первое, опять же взято из триггера, который не хочет импортироватся в Firebird 2.

Код: Выделить всё

/*******************************************************************************
The next statement causes the following error:

can't format message 13:849 -- message system code -4.
attempted update of read-only column.
*******************************************************************************/
CREATE OR ALTER TRIGGER IMP_LIB_BD FOR LIB
ACTIVE BEFORE DELETE POSITION 10
AS
BEGIN
  IF (GEN_ID(switch_replic, 0) = 1) THEN
  BEGIN
    IF (old.lconcept < 0) THEN old.lconcept = -old.lconcept;

    INSERT INTO lib
           (lid, lparent, lconcept, lflag, lname, lid1, lid2,
            lid3, lid4, lint1, lint2, lauthor, luser, llast,
            limage, lnum1, lnum2, lnum3, lnum4, lnum5, lnum6,
            lcode, ltext1, ltext2, ltext3, ltext4, linfo, ldate1,
            ldate2, ldate3, ldate, lx, lguid, limpex, lconf)
    VALUES (-old.lid, old.lparent, -old.lconcept, old.lflag, old.lname, old.lid1, old.lid2,
            old.lid3, old.lid4, old.lint1, old.lint2, old.lauthor, old.luser, old.llast,
            old.limage, old.lnum1, old.lnum2, old.lnum3, old.lnum4, old.lnum5, old.lnum6,
            old.lcode, old.ltext1, old.ltext2, old.ltext3, old.ltext4, old.linfo, old.ldate1,
            old.ldate2, old.ldate3, old.ldate, old.lx, old.lguid, -old.limpex, old.lconf);
  END
END
;
Все равно выкидывать?
Про RTFM понял, попробую разобраться...
Все равно, как я понял, настало время учить SQL, потому как наш программист базу вообще поверхностно знает и боиться куда то лезть :)

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Ошибка при создании триггера.

Сообщение kdv » 13 авг 2010, 01:12

Дим, ну он же сам сказал, что не программист. А ты ему такие советы даешь. Поубивает еще работавший код случайно ....
Первое, опять же взято из триггера, который не хочет импортироватся в Firebird 2.
old.lconcept = -old.lconcept;
в before delete запрещено потому что присвоение не будет иметь эффекта, запись же удаляется
то есть, разработчик тут сэкономил на переменной.

Поэтому, разобравшись в SQL, нужно еще и в смысле этого кода разбираться. Очевидно, программист БД хотел вставлять в таблицу old.concept всегда положительным. Зачем ему это было надо, и надо ли было вообще - знает только он.

p.s. как я понимаю, база не Ваша, но Вы самостоятельно сделали обновление версии Firebird? Нахрена, позвольте спросить? Вы уверены, что приложение будет на 100% с ФБ2 работать? Я - нет. Самодеятельность?

aminmsk
Сообщения: 6
Зарегистрирован: 26 июл 2010, 11:52

Re: Ошибка при создании триггера.

Сообщение aminmsk » 13 авг 2010, 10:41

Все гораздо веселее.
Я являюсь админом компании. Программист, который есть, ни разу глубоко не копал и триггеров этих не касался. Всегда делал что то поверх того, что 7 лет назад предоставил разработчик. В итоге сейчас имею картину не из приятнейших. Я бы и сам с удовольствием не переводил базу на Firebird 2 и т.д.
Но! Та железка (новый сервер, который закупили взамен старым. Потому как старые уже сильно храмают в отказоустойчивости, со всеми вытекающими) выполняет важные отчеты в 4 раза медленей. Копавшись в этом, набрел на то что, толи у Firebird 1.0 проблема при работе с оперативкой, толи какие то невиданные силы ему сопротивляются :).
Новый сервер надо сказать далеко не из самых худших, плюс для базы данных специально был приобретен SAS контроллер с хардами, соответственно.
Чуть позже, в один вечер, замучавшись с ковырянием firebird.conf и монитором выполнения отчетов и поведения системы, решил, просто, ради эксперимента- запустить копию базы данных на втором огнептице. И все пролетело просто с скоростью пули, выдав даже правильный отчет (проверял каждую строчку и циферку выданного отчета). Ну собственно так и начался путь к повышению версии.
Перед этим я положил где то недели две, на плотное копание в сервере. После чего выяснил, что Firebird 1, на данном сервере - как и предполагалось, шикарно справляется с математическими действиями. А вот там где надо пройти по всей базе, там труба, что совершенно не оправдано. На втором огнептице такого нет :). И сейчас то мне осталось, всего то привести в порядок 5 триггеров, в чем и прошу о помощи. Моя беда в том, что я даже от части понимаю что написано в коде, ибо было время, когда учил программирование. Но вот как это описать и поправить в данном случае, блин, не знаю....

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Ошибка при создании триггера.

Сообщение Dimitry Sibiryakov » 13 авг 2010, 14:02

aminmsk писал(а):Копавшись в этом, набрел на то что, толи у Firebird 1.0 проблема при работе с оперативкой, толи какие то невиданные силы ему сопротивляются :).
А он точно на CentOS?.. Версию ядра и GLIBC - в студию! А то, ЕМНИП у ядер вплоть до 2.16.18 в дисковом драйвере есть баг, невиданно сопротивляющийся вообще всем дисковым операциям с большими файлами...

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

PPS:
kdv писал(а):Дим, ну он же сам сказал, что не программист. А ты ему такие советы даешь. Поубивает еще работавший код случайно ....
Спокуха: чувак, похоже, небезнадёжный. Копается на копии базы, так что если чего и убьёт, так только заработает экспу. Это обычный путь шамана.

PPPS:
kdv писал(а):Очевидно, программист БД хотел вставлять в таблицу old.concept всегда положительным. Зачем ему это было надо, и надо ли было вообще - знает только он.
Точнее - всегда отрицательным.
Гыыыыы... Вчитался в код триггера... От жеж извращенцы... Дима, уверяю тебя - это ему было надо. :lol: :lol: :lol:
Аффтар, добавь в этот триггер переменную на которой сэкономил тот укуренный разработчик. Примерно так:

Код: Выделить всё

REATE OR ALTER TRIGGER IMP_LIB_BD FOR LIB
ACTIVE BEFORE DELETE POSITION 10
AS
DECLARE VARIABLE tmp_lconcept INTEGER; или какой там тип у lconcept...
BEGIN
  IF (GEN_ID(switch_replic, 0) = 1) THEN
  BEGIN
    IF (old.lconcept < 0) THEN
     tmp_lconcept = old.lconcept;
    ELSE
     tmp_lconcept = -old.lconcept;

    INSERT INTO lib
           (lid, lparent, lconcept, lflag, lname, lid1, lid2,
            lid3, lid4, lint1, lint2, lauthor, luser, llast,
            limage, lnum1, lnum2, lnum3, lnum4, lnum5, lnum6,
            lcode, ltext1, ltext2, ltext3, ltext4, linfo, ldate1,
            ldate2, ldate3, ldate, lx, lguid, limpex, lconf)
    VALUES (-old.lid, old.lparent, tmp_lconcept, old.lflag, old.lname, old.lid1, old.lid2,
            old.lid3, old.lid4, old.lint1, old.lint2, old.lauthor, old.luser, old.llast,
            old.limage, old.lnum1, old.lnum2, old.lnum3, old.lnum4, old.lnum5, old.lnum6,
            old.lcode, old.ltext1, old.ltext2, old.ltext3, old.ltext4, old.linfo, old.ldate1,
            old.ldate2, old.ldate3, old.ldate, old.lx, old.lguid, -old.limpex, old.lconf);
  END
END
;
Я бы, конечно, повесил этот триггер на AFTER DELETE, ну да фиг с ним...

aminmsk
Сообщения: 6
Зарегистрирован: 26 июл 2010, 11:52

Re: Ошибка при создании триггера.

Сообщение aminmsk » 13 авг 2010, 14:53

Да, копаюсь на копии.... :)
Что касаеомо версии линя

Код: Выделить всё

[root@localhost ~]# cat /proc/version
Linux version 2.6.18-164.el5PAE (mockbuild@builder16.centos.org) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)) #1 SMP Thu Sep 3 04:10:44 EDT 2009

[root@localhost ~]# cat /etc/redhat-release
CentOS release 5.4 (Final)
Спасибо за триггер и за подсказку.
Пойду-ка я посмотрю, что там на счет больших файлов ;).

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Ошибка при создании триггера.

Сообщение kdv » 14 авг 2010, 00:55

Та железка (новый сервер, который закупили взамен старым. Потому как старые уже сильно храмают в отказоустойчивости, со всеми вытекающими) выполняет важные отчеты в 4 раза медленей.
убиться можно. На ФБ 2 все залетало только по причине отличий в оптимизаторе, и Вам повезло.
А вот Сибиряков про ядро правильно сказал. Копайте, ответ есть.

По крайней мере я бы сравнил время бэкапа (или рестора) на фб 1 и фб 2.

aminmsk
Сообщения: 6
Зарегистрирован: 26 июл 2010, 11:52

Re: Ошибка при создании триггера.

Сообщение aminmsk » 17 авг 2010, 15:34

Время BackUP=>Restore кстати примерно одинаковое :). Там разница в 5-7 минут....
Спасибо всем за внимание. Доделываю переход на Firebird 2, для опыта и теста работы клиента с огнептицей.
И разбираюсь с ядром, что бы в случае чего переехать на Firebird 1.5.

Avolkov
Сообщения: 1
Зарегистрирован: 17 дек 2010, 13:55

Re: Ошибка при создании триггера.

Сообщение Avolkov » 17 дек 2010, 14:01

aminmsk писал(а):
Второе

Код: Выделить всё

/* Trigger: LIB_AI */
CREATE OR ALTER TRIGGER LIB_AI FOR LIB
ACTIVE AFTER INSERT POSITION 0
AS
BEGIN
  new.ldate = 'now';
END
Третье

Код: Выделить всё

/* Trigger: LIB_AU */
CREATE OR ALTER TRIGGER LIB_AU FOR LIB
ACTIVE AFTER UPDATE POSITION 0
AS
BEGIN
  new.ldate = 'now';
END
Удали эти триггеры вообще, так как они в принципе не отрабатывают. В триггере после инсерта или обновления индус, писавший это, пытался изменить всавляемые поля. fb 2.5 вообще не позволил бы откомпилить такую конструкцию

Ответить