greenadine: (Default)
[personal profile] greenadine

Я не уверен, что правильно понимаю подход, возможно нужно совсем по-другому делать, так что пишите и по этому поводу.

Есть старая программа. В ней есть процедура разбора внешнего файла, распихивание его инфы по разным таблицам. Есть в ней бага: при записи акции проверяем, есть ли в базе эмиттер акции, если ещё нет - создаём эмиттера. Бага в том, что при создании эмиттера (простой insert into) не проверяется, есть ли в базе страна эмиттера, и недавно всё полетело из-за каких-то иранских облигаций.

Что думал сделать я: процедуру create_emmetteur (sorry for my french), которая принимает некоторое количество параметров и пытается создать эмиттера. Если получилось - нормальный возврат, иначе - вылет по exception. Этот exception будет проанализирован внешней процедурой, которая сама решит, куда чего писать, и что делать дальше. Возвращать код я не хочу - во-первых, вся прога написана на exceptions, во-вторых, можно предположить появление других проверок с другими ответными действиями, так что простым да/нет можно не обойтись.

Проблема: exception определённый во внутренней процедуре не виден во внешней. Т.о. я не могу написать raise PAYS_INCONNU во внутренней проге и EXCEPTIONS WHEN PAYS_INCONNU во внешней. Приходится ловить по WHEN OTHERS. Работает, конечно, но некрасиво.
Была идея определить exception во внешней проге и передать параметром во внутреннюю - уродство.
Пока пришла в голову мысль отказаться от именованных exceptions и выкидывать обычное, с неким кодом, по которому потом проверять снаружи. Не очень нравится, нечитаемо.

Да, в oracle я чайник, у нас просто все dba спецы по db2, поэтому можете предполагать, что я не знаю базовых вещей. Я про существование exceptions узнал, разбирая код :-)

Date: 2005-09-26 04:32 pm (UTC)
From: [identity profile] aguti.livejournal.com
Я бы на твоем месте создала триггер на инсерт, который бы делал нужные проверки и в случае проблемы делал бы RAISE ERROR с заранее известным кодом (20001, к примеру). А потом уже в программе-обработчике обрабатывала бы этот эксепшн. То есть твой эксепшн нужно определить только один раз, в программе-обработчике. Понятно написала?

Date: 2005-09-26 04:36 pm (UTC)
From: [identity profile] aguti.livejournal.com
Да, забыла приписать: для того, чтобы было все-таки читаемо, каждый RAISE надо сопровождать мессаджем с причиной и с именем триггера или процедуры, который его бросил. Это во-первых, помогает читать, во-вторых, дает представление, что, собственно происходит, когда ты забудешь словить именно этот эксепшн и получишь его далеко за пределами проблемной процедуры.

Date: 2005-09-27 07:45 am (UTC)
From: [identity profile] greenadine.livejournal.com
Триггер или нет - это уже детали, но ты предлагаешь неименованые exceptions. Никак с именоваными? Я тут копаю в направлении глобальных переменных, типа определить exception на уровне package...

Я когда Лёше Долганову по этому поводу позвонил, он именно к тебе меня направил :-)

Date: 2005-09-27 08:05 am (UTC)
From: [identity profile] aguti.livejournal.com
Я не очень люблю использовать packagе, из-за неочевидности его сопровождения. Но это почти религиозное, возможно в твоем случае это действительно идеальное решение. :)

Date: 2005-09-27 08:45 am (UTC)
From: [identity profile] greenadine.livejournal.com
Можешь в двух словах? А то я в этом ну совсем не секу, а подставлять админов, написав задницу неохота.

Date: 2005-09-27 09:15 am (UTC)
From: [identity profile] aguti.livejournal.com
В двух словах - это хорошая штука, только все изменения в них требуют их выгрузки из памяти, просто пересозданием пэкаджа проблема не решается. То есть при пересоздании надо было чтобы клиенты, его использующие, перелогинились (представь сложность при круглосуточном использовании продукта). Кроме того, они могли при пересоздании перейти в состояние "инвалид" если в них использовались глобальные переменные, и ни с того ни с сего у клиентов начинались проблемы, иногда это приводило к переводу в "инвалид" и использующих их процедур. Чище всего - это остановить продукт, пересоздать пэкадж и только потом давать его в использование.

Короче, для "ремонта на лету" штука обоюдоострая. Но в стабильном виде (все отлажено, все работает) - это очень хорошая фича.

Я сейчас уже смутно помню, и боюсь сказать глупость, в последних разработках на Оракле, что я делала, пэкаджи не использовались по другим причинам. Поэтому не хочу тебя décourager, если создать в пэкадже только конкретные эксепшены, список которых стабилен и не будет меняться, то вполне симпатичное решение.

Date: 2005-09-27 09:34 am (UTC)
From: [identity profile] greenadine.livejournal.com
Ну, у нас контекст попроще. Сервер перегружается каждую ночь (и после каждого ddl script), так что разработчики даже закрытием connections себя не утруждали...

Date: 2005-09-26 04:36 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Много ли на свете стран? Создать их все, и дело с концом.
Или всегда вставлять страну перед эмиттером, на всякий случай. В предположении, что она есть среди параметров.

Date: 2005-09-26 04:45 pm (UTC)
From: [identity profile] aguti.livejournal.com
Вовсе это не просто. Пример: была Чехословакия, а завтра стала Чехия и Словакия. И если ты не поймешь тут же, в чем проблема, проведешь часы (а то и дни) в поисках, где глючит.

Date: 2005-09-26 04:47 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
В этом случае все равно у функции не будет отдельного параметра для Чехии, и отдельного для Словакии, и все остановится. Это непрограммистская проблема. Кто-то в организции должен отвечать за список актуальных стран.

Date: 2005-09-26 04:53 pm (UTC)
From: [identity profile] aguti.livejournal.com
Программисткая проблема - словить эксепшн и передать на обработку. А кому (программе или Специально Обученному Мужику) - зависит от постановки. Если эксепшена нет (или есть WHEN OTHERS) - это уже чисто програмисткая проблема.

Я видела код, в котором стояло WHEN OTHERS NULL, а хозяйка кода удивлялась, почему ее процедура не работает, хоть и не ругается !

Date: 2005-09-27 07:48 am (UTC)
From: [identity profile] greenadine.livejournal.com
Согласен по всем пунктам. Забыл уточнить, что изменение процедуры работы в конторе не предлагать :-)

Date: 2005-09-26 05:00 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Кстати, это читал? Scope Rules for PL/SQL Exceptions

Date: 2005-09-27 07:51 am (UTC)
From: [identity profile] greenadine.livejournal.com
Да, спасибо, у меня это в pdf, это я и читаю.
(deleted comment)

Date: 2005-09-27 07:53 am (UTC)
From: [identity profile] greenadine.livejournal.com
Нет, полный список стран меня не интересует по другим причинам. Мне нужно именно понять, что что-то не так и вернуть именованый exception.

Date: 2005-09-27 04:40 am (UTC)
From: [identity profile] alekro.livejournal.com
Можно тригерами и тому подобное, можно коды стран вписывать.

Я только хочу опровергнуть утв "Проблема: exception определённый во внутренней процедуре не виден во внешней".
Если юзать пакет какой нить, то оттедова усе видать. Рабочий пример тут сварганил:

CREATE OR REPLACE PACKAGE exc_test_pkg
IS
exc_test_name exception;
PRAGMA EXCEPTION_INIT(exc_test_name, -20030);

END;
/

CREATE OR REPLACE procedure test_exc_server is
begin
dbms_output.put_line('test_exc_server');
raise exc_test_pkg.exc_test_name;
end;
/

CREATE OR REPLACE procedure test_exc_client is
begin
dbms_output.put_line('test_exc_client before test_exc_server exception');
test_exc_server;
dbms_output.put_line('test_exc_client after test_exc_server exception');
exception
when exc_test_pkg.exc_test_name then
dbms_output.put_line('exc_test_name raised, he-he');
end;
/
-------------------------------

А терь тестим:
conn user/password@tns_name; -- if you need it
set serveroutput on;

BEGIN
TEST_EXC_CLIENT;
COMMIT;
END;
/

---------------------------
My output result:

test_exc_client before test_exc_server exception
test_exc_server
exc_test_name raised, he-he
--=====================================================

Я думаю, ты сам догадался давно, прост решил вспомнить старое, тряхнуть этим, самым )

Date: 2005-09-27 07:56 am (UTC)
From: [identity profile] greenadine.livejournal.com
Т.е. определить exceptions в package. Я не знал, что при этом процедуры не обязаны быть в этом же package (я их все не перетяну, гемор). Похоже, это решение, спасибо!

Date: 2005-09-27 01:29 pm (UTC)
From: [identity profile] greenadine.livejournal.com
Слушай, а ещё вопрос: нахрена привязывать код именованому exception? Если я не напишу pragma exception_init, чем это мне грозит?

Не грозит особо ничем :)

Date: 2005-09-28 12:44 am (UTC)
From: [identity profile] alekro.livejournal.com
Основная идея - юзать пакеты для плейса там дефинишинов разных.
Согласен, что пакеты - не идеальная хренька, особенно для горяченьких приклад, но для твоего конкретного случая - нормальное решение. Вроде :). Потом ногами не бить!!!!!
Сам я юзаю именованные, чтоб потом легче разбираться было, откуда ноги у бага растут. Залез по ссылке выше, просто копирую(мы сами писать не умеем :):

Associating a PL/SQL Exception with a Number: Pragma EXCEPTION_INIT

To handle error conditions (typically ORA- messages) that have no predefined name, you must use the OTHERS handler or the pragma EXCEPTION_INIT. A pragma is a compiler directive that is processed at compile time, not at run time.

In PL/SQL, the pragma EXCEPTION_INIT tells the compiler to associate an exception name with an Oracle error number. That lets you refer to any internal exception by name and to write a specific handler for it. When you see an error stack, or sequence of error messages, the one on top is the one that you can trap and handle.

You code the pragma EXCEPTION_INIT in the declarative part of a PL/SQL block, subprogram, or package using the syntax

PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);

where exception_name is the name of a previously declared exception and the number is a negative value corresponding to an ORA- error number. The pragma must appear somewhere after the exception declaration in the same declarative section, as shown in the following example:

DECLARE
deadlock_detected EXCEPTION;
PRAGMA EXCEPTION_INIT(deadlock_detected, -60);
BEGIN
... -- Some operation that causes an ORA-00060 error
EXCEPTION
WHEN deadlock_detected THEN
-- handle the error
END;
====================================================

Profile

greenadine: (Default)
greenadine

December 2025

S M T W T F S
 123456
78910111213
141516 17181920
21222324252627
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 11th, 2026 09:03 am
Powered by Dreamwidth Studios