Здравствуйте.
Такая проблема:
На таблице висит триггер, вызывающий функцию, которая "делает свои дела" и, дабы не ушла в бесконечную рекурсию, в этой функции создаётся временная таблица, в которой хранится необходимый признак когда нужно выйти из цикла.
Раньше при запросе:
Select * from pg_tables WHERE tablename = 'my_recursia';
он выдавал 1 строчку, хотя транзакция уже прошла и таблица по идеи должна была быть удалена, НО (!) при попытки снова ручками её создать, таблица создавалась. Знаю, есть такая фишка кэша. Работает - нет проблем.
У нас случился глюк и Postgres 8.4 продолжал считать, что эта временная таблица создана, хотя при добавлении записи, писал что таблица не создана. Я перепробовала кучу способов мыслимых и немыслимых (включая ребут, service postgresql restart, пересоздание БД), но ничего не помогло. Так что последним решением было править системные таблицы. Вот теперь и беда.
Я нашла запись о несчастной 'my_recursia' в таблице pg_class, там и удалила строчку о ней. Функция заработала. Но, видимо, это не всё... Т.к. при попытки ручками создать эту таблицу:
CREATE TEMPORARY TABLE my_Recursia (id integer, priznak text DEFAULT 1 );
Выдаёт ошибку:
ERROR: could not open relation with OID *******
SQL state: XX000
Хотя абсолютно тот же самый запрос выполняется в функции и работает!!!
Ещё нашла её следы в pg_type в поле typname, причём 'my_recursia' и '_my_recursia' на каждого юзера (их всего 2).
Боюсь, как бы не вышло это боком. Так что прошу знатоков сказать где ещё нужно почистить, да так, чтобы не навредить
P.S.: Если есть идея лучше, чем в временной таблицей, то с радостью выслушаю. Но почистить всё равно нужно.
Цитата:НО (!) при попытки
Это не фишка кеша, а фишка временных таблиц. Временная таблица живет не дольше, чем сессия, и доступ к ней имеется только из сессии, в которой была создана. Само собой, в разных сессиях могут жить свои темповые таблицы с идентичными названиями. Не верно вы виновника выявили, и зря полезли в системные таблицы. С ходу даже и не знаю, что вам предложить, бякап до порчи системных таблиц надеюсь есть?
Ради интереса, можете юзера добавить и от его имени попытаться создать данную временную таблицу, должно прокатить. Только вот, кроме как удовлетворения любопытства ничего иного данный процесс не даст.
Что за хитрая рекурсивная тригерная функция? Вы не предоставили никакой информации по функции, как же при таком раскладе подсказать вам иные варианты выхода из рекурсии? Хотя есть один вариант, и его я настоятельно рекомендую. Откажитесь от рекурсии.
Цитата: Временная таблица
Цитата:
Временная таблица живет не дольше, чем сессия, и доступ к ней имеется только из сессии, в которой была создана. Само собой, в разных сессиях могут жить свои темповые таблицы с идентичными названиями.
Это я знаю и это работало. Но в том-то и дело, что сессия была завершена, а он говорил, что таблица до сих пор есть, а при попытки её удалить или записать туда данные, говорил что таблицы нет. Я же писала об этом. Что даже пробовала перезапустить постгрес, сервер, пересоздавала базу, но временная таблица до сих пор считалась существующей!
И, когда я пересоздавала базу (скрипт схема+данные), постгрес мне писал, что этой базы нет! Поясню, что в этой команде сперва удаляется старая БД, а потом создаётся новая, а уж потом заливается схема и данные.
Цитата:
бякап до порчи системных таблиц надеюсь есть?
Есть скрипт данных. В прошлый раз пересоздание БД мне не помогло никак.
Цитата:
Откажитесь от рекурсии.
Я бы с радостью, но начальник прочёл умную книжку по БД и теперь его хрен переубедишь. Взбрело в голову - я теперь мучаюсь. Есть в постгресе глобальные переменные, где можно хранить признак выхода из рекурсии или что-нибудь аналогичное?
Цитата:Это я знаю и это
В общем, есть таблица
В общем, есть таблица объектов и есть таблица точек этих объектов, которые описывают некий многоугольник. Начальнику вздумалось чтобы каждая эта точка имела свой порядковый номер и, если удаляют точку 5, к примеру, а их всего 10, то точки должны автоматически перенумероваться. Вот на таблице точек висит эта функция, которая вызывает сама себя. Если последовательность разорвана, находим точку, которой нужно изменить номер и update (и опять сработает эта же функция).
Приходит ко мне программист (конектится как юзер) и говорит: "У меня не удаляется точка, пишет мол не создана таблица my_recursia". До этого у него несколько месяцев всё прекрасно работало. Я захожу как админ и из СУБД пытаюсь удалить точку - то же самое: сообщение что временная таблица не создана. Открываю код функции и смотрю:
IF NOT EXISTS (Select * from pg_tables WHERE tablename = 'my_recursia') THEN
CREATE TEMPORARY TABLE my_Recursia (id integer, priznak text DEFAULT 1 );
INSERT INTO my_Recursia (id, priznak) VALUES (1, 'first');
END IF;
Именно при добавлении записи вылетает ошибка, т.е. таблица не создана. Делаю:
Select * from pg_tables WHERE tablename = 'my_recursia'
Выдаёт 1 строчку с записью 'my_recursia'. Как это так? Если она есть, то почему не записывается?
Цитата:Именно при добавлении
Странный вывод. Ошибка разве гласит: "relation "my_recursia" does not exist"? Инсерт ведь не только из-за отсутвия таблицы может обламаться, тем более, что на предыдущей строке ее создали.
Что именно выдает этот запрос? Конкретно, итересует значение schemename. Если наименование совпадает с имеющейся схемой в БД, то это стационарная таблица из данной схемы. Для временных таблиц schemename будет иметь вид pg_temp_х.
А без временных таблиц, можно делать выборку изменяемых точек до тех пор, пока выборка не будет нулевой.
Цитата: Ошибка разве гласит:
Цитата:
Ошибка разве гласит: "relation "my_recursia" does not exist"?
Именно!
Цитата:
Что именно выдает этот запрос? Конкретно, итересует значение schemename. (...)Для временных таблиц schemename будет иметь вид pg_temp_х.
Именно! pg_temp_19 было.
Цитата:
А без временных таблиц, можно делать выборку изменяемых точек до тех пор, пока выборка не будет нулевой.
А я и не додумалась... Спасибо
Наверное, все же что-то
Наверное, все же что-то типа
Коли временная таблица пропадает, видимо и ее дроп в тригерной функции имеется? Дело в том, что все экзеплятры тригерной функции запускаются в одной сессии, соответсвенно, обращаются к одной временной таблице. Более того, для одного инсетра/апдейта/делита в одной транзакции. Вследствии этого, один из экзепляров функции пытается обратиться к временной таблице, когда другой экзепляр ее уже грохнул, но в системных таблицах еще не обновлена информация о ее удалении ибо она еще нужна для возможного отказа транзакции. Вот и выходит, инфа о наличии таблицы еть, но ID таблицы уже ведет в никуда.
При обломе же вся транзакция откатывается и никаких следов не остается.
Можно выяснить у разработчика, какие изменения в таблице он пытается сделать, приводящие к крашу. И попытаться понять, чем же они отличаются от работающих изменений.
Можно убрать дроп временной таблицы из тригерной функции. Закончится сессия, закончится и время ее жизни.
Ну и кончено, можно совсем отказаться от использования временной таблицы. Ровно, как и отказаться от рекурсивной функции.
В общем, проблема всё ещё
В общем, проблема всё ещё актуальна:
1. Что это было?
2. Как сделать так, чтобы этого не было?
3. Как исправить то, что сейчас есть? Т.е. где ещё нужно почистить системные таблички, чтобы не было:
ERROR: could not open relation with OID *******
SQL state: XX000
(я в первом посте писала).
Третий вопрос больше всего интересует.
По первым вдум пунктам вроде
По первым вдум пунктам вроде высказал свое мнение.
По третьему, практика показывает, что достаточно почистить pg_class и pg_type. На будущее, не стоит чуть что лезть и вычищать системные таблицы.
Большое спасибо. Испробую в
Большое спасибо. Испробую в понедельник.