November 2019

S M T W T F S
      12
34 5 678 9
10111213141516
17181920212223
24252627282930

Style Credit

Expand Cut Tags

No cut tags
dil: (Default)
Wednesday, December 5th, 2012 09:35 pm

Имеется скрипт. Выполняет довольно простую работу:
соединяется с базой данных (Informix, как водится), создаёт временную таблицу, заполняет её данными из других таблиц.
Потом запускает на эту таблицу SELECT COUNT(*), ну так, чисто для отчётности, и выводит это количество в лог.
Потом создаёт в таблице индекс для ускорения последующих операций и запускает UPDATE STATISTICS, чтоб индекс заработал.
Затем удаляет из таблицы некоторые ненужные данные посредством DELETE, опять запускает SELECT COUNT(*) и… внезапно случается облом:

execute failed: SQL: -710: Table has been dropped, altered or renamed.

Сначала подумали, что в скрипте что-то не то. Но его не меняли уже больше года, а ошибка появилась лишь несколько месяцев назад, до этого всё нормально работало.

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

Потом подумали, что может это на сервере регулярно проводятся какие-то работы как раз когда скрипт по крону запускается. Но нифига, он падает в одном и том же месте в любое время дня и ночи. Вот пока идёт первоначальный INSERT, таблица есть, первый SELECT — есть, DELETE — всё ещё есть, а на следующем SELECT‘е через пару секунд — уже нет. Мистика какая-то..

Чудес не бывает. Через пару недель исследований грабли были найдены. Они оказались очень красивыми. Естественно, я не смог мимо них пройти, не наступив. Попробуйте угадать, что это было.

Подсказка: скрипт использует перловый DBI. То есть, запросы сначала подготавливаются посредством prepare(), а потом уже выполняются вызовом execute(). Запрос про SELECT COUNT(*) запускается несколько раз, после каждого изменения в таблице, но он всегда одинаковый, поэтому для него применяется prepare_cached(), это немножко ускоряет работу.

Оригинал этой записи в личном блоге.
Любые материалы из этого блога запрещается использовать на сайте livejournal.ru в любой форме и любом объёме.

dil: (Default)
Wednesday, March 24th, 2010 06:51 pm

Пишем простейшую хранимую процедуру, которая умеет иногда генерировать исключения:

CREATE PROCEDURE tmp_proc (
  p_foo int
)
  IF p_foo = 0 THEN
    RAISE EXCEPTION -746, 0, "tmp_proc-raised exception";
  END IF
END PROCEDURE;

Вызываем её из перла посредством DBD::Informix:
“EXECUTE PROCEDURE tmp_proc (p_foo = ?)”, prepare, execute..

Как ожидалось, получаем

DBI::err = '-746', DBI::errstr='SQL: -746: tmp_proc-raised exception'

Преобразуем процедуру в функцию:

CREATE PROCEDURE tmp_func (
  p_foo int
)
RETURNING int;
  DEFINE foo int;
  IF p_foo = 0 THEN
    RAISE EXCEPTION -746, 0, "tmp_func-raised exception";
  END IF
  LET foo = p_foo+1;
RETURN foo;
END PROCEDURE;

“EXECUTE PROCEDURE tmp_func (p_foo = ?)”, prepare, execute..

И фиг там. execute успешно отрабатывает, возвращает 0E0, DBI::err и DBI::errstr совершенно undefined, всё прекрасно, никаких ошибок.

А вот если потом вызвать fetchrow_array(), то только тогда

DBI::err = '-746', DBI::errstr='SQL: -746: tmp_func-raised exception'.

Что совсем плохо, если какой-нибудь fetch() совсем не вызывать, то функция, похоже, совсем не запускается. Либо результаты её работы откатываются. Потому что изначально я на это наткнулся на функции, которая проверяет данные, добавляет строку в таблицу и возвращает ID от добавленной строки. Вот если этот ID потом не считать с помощью fetch, то данные в таблицу вообще не попадают.

Я даже не понимаю, куда тут копать..

Оригинал этой записи. Комментировать можно тут или там.

Любые материалы из этого блога запрещается использовать на сайте livejournal.ru в любой форме и любом объёме