Источник статьи в оригинале: Oracle Magazine, март-апрель 2016
http://www.oracle.com/technetwork/issue-archive/2016/16-mar/o26plsql-2925919.html
PL/SQL — это мощный и во многих случаях очень прямолинейный язык программирования баз данных. Без преувеличения, PL/SQL — это в точности то, что вам требуется, и ничего больше.
Однако следует признать, что неожиданным образом некоторые особенности поведения PL/SQL могут стать сюрпризом для разработчиков, особенно для новичков в PL/SQL. Эта статья должна пролить свет на некоторые из типичных источников таких сюрпризов. Она построена в форме теста, проверяющего ваши знания и объясняющего особенности работы PL/SQL.
PL/SQL был разработан как простой и мощный язык для безопасного выполнения операций SQL с оптимальной производительностью. Поэтому код на PL/SQL в составе транзакций часто содержит много операций из языка управления данными (DML), таких как вставка, обновление и удаление. Разработчики часто не представляют себе, как ошибки при выполнении операций SQL в программе на PL/SQL влияют на транзакцию в целом.
Выполним следующую операцию:
CREATE TABLE plch_plants ( plant_id INTEGER PRIMARY KEY, plant_name VARCHAR2 (4) ) /
Какой из следующих вариантов после выполнения выводит Count=1?
BEGIN INSERT INTO plch_plants VALUES (1, 'Rose'); BEGIN INSERT INTO plch_plants VALUES (2, 'Kudzu'); EXCEPTION WHEN OTHERS THEN ROLLBACK; END; SELECT COUNT (*) INTO l_count FROM plch_plants; DBMS_OUTPUT.put_line ('Count=' || l_count); END; /
BEGIN INSERT INTO plch_plants VALUES (1, 'Rose'); INSERT INTO plch_plants VALUES (2, 'Kudzu'); EXCEPTION WHEN OTHERS THEN SELECT COUNT (*) INTO l_count FROM plch_plants; DBMS_OUTPUT.put_line ('Count=' || l_count); END; /
BEGIN INSERT INTO plch_plants VALUES (1, 'Kudzu'); INSERT INTO plch_plants VALUES (2, 'Rose'); EXCEPTION WHEN OTHERS THEN SELECT COUNT (*) INTO l_count FROM plch_plants; DBMS_OUTPUT.put_line ('Count=' || l_count); END; /
За редкими исключениями (непроизвольная игра слов), возбуждение исключения не отменяет результаты любой успешно завершенной, но еще не принятой операции управления данными.
Подробнее об обработке и управлении транзакциями.
Блочная структура PL/SQL является одновременно фундаментальным элементом языка и мощным средством разработки прозрачных приложений. Каждый блок состоит из трех секций: секции объявлений, секции выполнения и секции исключений. Взаимодействие между этими секциями не всегда очевидно.
Какой из следующих вариантов после выполнения выводит “Пришла весна!”?
BEGIN RAISE VALUE_ERROR; DBMS_OUTPUT.put_line ('Пришла весна!'); END; /
DECLARE l_number NUMBER (3, 0) := 2016; BEGIN DBMS_OUTPUT.put_line ('Пришла весна!'); EXCEPTION WHEN VALUE_ERROR THEN DBMS_OUTPUT.put_line ('Пришла весна!'); END; /
DECLARE l_number NUMBER (3, 0); BEGIN l_number := 2016; EXCEPTION WHEN VALUE_ERROR THEN DBMS_OUTPUT.put_line ('Пришла весна!'); END; /
Секция исключений блока PL/SQL может поймать только исключение, вызванное в секции выполнения этого блока. Если исключение вызывается в секции объявлений (при попытке присвоить значение по умолчанию переменной или константе), то такое исключение всегда распространяется за пределы блока без обработки.
Подробнее о распространении исключений.
Коллекции в PL/SQL — это структуры, подобные массивам, и существует три — сосчитайте их: три! — разных типа коллекций, каждый со своими характеристиками и способами использования.
Выполним такие операции:
CREATE TYPE plch_numbers_nt IS TABLE OF NUMBER / CREATE TYPE plch_numbers_va IS VARRAY (3) OF NUMBER /
Какой из следующих вариантов после выполнения выводит Count=0?
DECLARE TYPE plch_numbers_aa IS TABLE OF NUMBER INDEX BY PLS_INTEGER; l_numbers plch_numbers_aa; BEGIN l_numbers.delete; DBMS_OUTPUT.put_line ('Count=' || l_numbers.COUNT); END; /
DECLARE l_numbers plch_numbers_nt; BEGIN l_numbers.delete; DBMS_OUTPUT.put_line ('Count=' || l_numbers.COUNT); END; /
DECLARE l_numbers plch_numbers_va; BEGIN l_numbers.delete; DBMS_OUTPUT.put_line ('Count=' || l_numbers.COUNT); END; /
Работая с вложенными таблицами и коллекциями типа varray, вы должны (в большинстве случаев) сначала инициализировать эти коллекции вызовом их функции-конструктора, имя которой совпадает с названием типа коллекции. Однако это не является необходимым при работе с ассоциативными массивами.
Подробнее о коллекциях и записях в PL/SQL.