Не выполняется процедура oracle
У меня проблема с одной из хранимых процедур, которые я пытаюсь создать в базе данных Oracle.
Цель состоит в том, чтобы обновить каждую таблицу, в которой есть indiv столбец.
Я попытался удалить код из хранимой процедуры. И там это работает. Только начало меняется на:
Таким образом, он отлично работает и делает именно то, что должен делать.
Поскольку единственная разница заключается в назначении переменной, я думаю, что у меня может быть проблема с объявлением моей процедуры, но я не могу найти решение. Сборка в порядке.
Абсолютно, я использую dbeaver. Для «возврата 1» это тест, который я пытался и забыл удалить, когда писал этот вопрос. Его нет в сп.
Ваша обновленная процедура отлично работает для меня. Может быть, покажите нам более подробную информацию о том, как вы его запускаете. Какие имена таблиц он обновляет? Являются ли какие-либо из них чувствительными к регистру?
То, как я запускаю его, просто ниже. Простой "exec sp_majUserOnAllK('test','reset');". Он возвращает кучу таблиц. Не могу дать никаких подробностей, потому что я работаю над проприетарным приложением. Мне нужно обновить пользователя. Но если я это сделаю, поскольку они не являются внешними ключами, мы потеряем много информации. Но я знаю, что в каждой таблице столбец indinv имеет ключ. Поэтому я перебираю эти таблицы, чтобы выполнить каскадное обновление.
Независимо от того, как (или даже «если») вы сможете решить свою текущую проблему, собираетесь ли вы когда-нибудь решить ее первопричину? Вы используете продукт реляционной базы данных (Oracle); почему в ваших таблицах нет внешних ключей?
Синтаксис вашей процедуры неверен. Попробуй это.
Получил "REQ" как объявленную ошибку. Пытался добавить DECLARE, но вернулся к старой ошибке. Люблю удаление курсора, хотя ^^
Компилируется для меня. Это на самом деле неверно, или просто dBeaver не понимает PL/SQL? Вам не нужно добавлять declare раздел в любом случае, он уже есть (объявите, что вы хотите выше begin ). Курсор не удаляется, он встроен как часть цикла.
Чтобы устранить эту проблему, я попытался полностью удалить переменную. Я выполняю запрос напрямую. Я тоже компилирую, но при выполнении все та же ошибка. Я отредактировал первый пост, чтобы отразить изменения.
Пятисекундный поиск в Google по запросу «dbeaver exec command» выдал это среди первых нескольких результатов:
В нем мы узнаем, что EXEC не поддерживается dbeaver.
EXEC это команда SQL*Plus. Это не Oracle SQL и не PL/SQL. SQL*Plus — это своего рода оболочка для взаимодействия с базами данных Oracle; у него есть собственный язык, отличный от SQL и PL/SQL.
SQL Developer и Toad (и, возможно, другие подобные программы) поддерживают (большую часть) SQL*Plus, но, по-видимому, dbeaver (с которым я не знаком) не поддерживает.
Ссылка, которую я скопировал выше, предлагает CALL вместо этого использовать команду. Смотрите ссылку для примеров.
Кстати, когда мы используем EXEC SQL*Plus и SQL Developer, в конце вызова процедуры нет точки с запятой. Однако добавление ненужной точки с запятой не приводит к ошибке (по-видимому, SQL*Plus достаточно умен, чтобы просто игнорировать ее).
Если захожу в процедуру в PL/SQL Developer через Debug по шагам, то процедура выполняется нормально и отрабатывает корректно. Все используемые пакеты имеют статус VALID .
Подскажите, в чем может быть проблема?
посмотрите , может что-то неверно скомпилировалось из объектов или пакетов, которые используются у вас в процедуре: select comp_id, comp_name, version, status, namespace, schema from dba_registry;
Заголовок процедуры
Часть определения процедуры, предшествующая ключевому слову IS, называется заголовком процедуры, или сигнатурой. Заголовок предоставляет программисту всю информацию, необходимую для вызова процедуры:
- Имя процедуры.
- Условие AUTHID (если имеется).
- Список параметров (если имеется).
- Список ACCESSIBLE BY (если имеется — новая возможность Oracle Database 12c).
В идеале программист при виде заголовка процедуры должен понять, что делает эта процедура и как она вызывается.
Заголовок процедуры apply_discount из предыдущего раздела выглядит так:
Он состоит из типа модуля, имени и списка из двух параметров.
PLW-05004: идентификатор также объявлен в пакете STANDARD или является встроенным в SQL
Многие разработчики PL/SQL не знают о пакете STANDARD и его влиянии на код PL/ SQL . Например, многие программисты считают, что такие имена, как INTEGER и TO_CHAR , являются зарезервированными словами языка PL/SQL . Однако на самом деле это тип данных и функция, объявленные в пакете STANDARD .
standard — один из двух пакетов по умолчанию в PL/SQL (другой — DBMS_STANDARD ). Поскольку STANDARD является пакетом по умолчанию, вам не нужно уточнять ссылки на такие типы данных, как INTEGER, NUMBER, PLS_INTEGER и т. д., именем STANDARD — хотя при желании это можно сделать.
Предупреждение PLW-5004 сообщает об объявлении идентификатора с таким же именем, как у элемента STANDARD (или встроенным именем SQL; многие встроенные имена, хотя и не все, объявляются в STANDARD ).
Рассмотрим эту процедуру:
Для этой процедуры компилятор выводит следующие предупреждения:
Старайтесь избегать использования имен элементов, определенных в пакете STANDARD , если только у вас нет для этого очень веских причин.
Тело процедуры
В теле процедуры содержится код, необходимый для реализации этой процедуры; тело состоит из объявления, исполняемого раздела и раздела исключений этой процедуры. Все, что следует за ключевым словом IS, образует тело процедуры. Разделы исключений и объявлений не являются обязательными. Если обработчики исключений отсутствуют, опустите ключевое слово EXCEPTION и завершите процедуру командой END .
Некоторые полезные предупреждения PL/SQL
В следующих разделах я представлю небольшую подборку предупреждений, реализованных Oracle , — с примерами кода, для которого они выдаются, и описаниями особенно интересного поведения.
Чтобы просмотреть полный список предупреждений для любой конкретной версии Oracle , найдите раздел PLW в книге "Error Messages" документации Oracle.
PLW-05003: фактический параметр с IN и NOCOPY может иметь побочные эффекты
Используя NOCOPY с параметром IN OUT , вы приказываете PL/SQL передавать аргумент по ссылке, а не по значению. Это означает, что любые изменения в аргументе вносятся непосредственно в переменную во внешней области действия. С другой стороны, при передаче «по значению» (ключевое слово NOCOPY отсутствует, или компилятор игнорирует рекомендацию NOCOPY ) изменения вносятся в локальную копию параметра IN OUT . Когда программа завершается, изменения копируются в фактический параметр. (Если произойдет ошибка, измененные значения не копируются в фактический параметр.) Рекомендация NOCOPY повышает вероятность совмещения имен аргументов, то есть ссылки на один блок памяти по двум разным именам.
Совмещение имен усложняет понимание и отладку кода; предупреждение компилятора, выявляющее эту ситуацию, будет чрезвычайно полезным.
Возьмем следующую программу:
Программа достаточно проста: передаются три строки, две из которых объявлены как IN OUT ; аргументам IN OUT присваиваются значения; после каждого присваивания выводится значение первого аргумента IN . Теперь я запускаю процедуру и передаю одну локальную переменную во всех трех параметрах:
Хотя процедура very_confusing продолжает выполняться, присваивание arg2 не отражается на значении аргумента arg1 . Однако когда значение присваивается arg3 , значение arg1 (аргумент IN) заменяется на « Third value »! Более того, при завершении very_confusing присваивание arg2 было применено к переменной str . Таким образом, при возврате управления во внешний блок переменной str присваивается значение « Second value », фактически заменяющее результат присваивания « Third value ».
Как говорилось ранее, совмещение имен параметров может порождать очень запутанные ситуации. Если включить предупреждения компилятора, в таких программах, как plw5003, могут быть выявлены потенциальные проблемы совмещения имен:
Включение предупреждений компилятора PL/SQL
Oracle позволяет включать и отключать предупреждения компилятора, а также указывать, какие виды предупреждений представляют интерес. Предупреждения делятся на три категории:
- Критичные — ситуации, которые могут привести к неожиданному поведению или получению неверных результатов (как, например, проблемы с псевдонимами параметров).
- Производительные — ситуации, способные вызвать проблемы с производительностью (например, указание значения VARCHAR2 для столбца NUMBER в команде UPDATE ).
- Информационные — ситуации, не влияющие на производительность или правильность выполнения кода, но которые стоит изменить ради того, чтобы упростить сопровождение.
Oracle позволяет включать и отключать предупреждения конкретной категории, всех категорий и даже конкретные предупреждения. Для этого используется команда ALTER DDL или встроенный пакет DBMS_WARNING .
Следующая команда включает предупреждения компиляции для системы в целом:
А следующая команда, например, включает предупреждения в вашей системе для всех категорий:
Это значение особенно полезно во время разработки, потому что оно позволит обнаружить наибольшее количество потенциальных проблем в вашем коде.
Чтобы включить предупреждения в сеансе только для критичных проблем, введите следующую команду:
А для изменения настройки предупреждений компилятора для конкретной, уже откомпилированной программы вводится команда следующего вида:
Обязательно включите секцию REUSE SETTINGS , чтобы команда ALTER не влияла на все остальные настройки (например, уровень оптимизации).
Объединяя разные параметры, можно уточнять настройки с очень высоким уровнем детализации. Допустим, я хочу знать обо всех проблемах, относящихся к производительности, на данный момент не желаю отвлекаться на серверные проблемы, а предупреждение PLW-05005 (выход из функции без RETURN ) должно рассматриваться как ошибка компиляции. Для этого вводится следующая команда:
Особенно полезна возможность интерпретации предупреждений как ошибок. Возьмем предупреждение PLW-05005; если оставить его без внимания при компиляции функции no_return (см. ниже), программа откомпилируется, и я смогу использовать ее в приложении:
Если теперь изменить интерпретацию ошибки приведенной выше командой ALTER SESSION и перекомпилировать no_return , компилятор немедленно остановит попытку:
Кстати говоря, настройки также можно изменить только для конкретной программы и пометить предупреждение как ошибку командой следующего вида:
Во всех этих разновидностях команды ALTER ключевое слово ALL может использоваться как простое и удобное обозначение всех категорий предупреждений:
Oracle также предоставляет пакет DBMS_WARNING со сходными возможностями по установке и изменению параметров компиляции через PL/SQL API . В отличие от команды ALTER, DBMS_WARNING позволяет вносить изменения в конфигурацию тех предупреждений, которые вас интересуют, оставляя другие без изменений. Также после завершения работы можно легко восстановить исходные настройки.
Пакет DBMS_WARNING проектировался для использования в установочных сценариях, в которых может возникнуть необходимость отключения некоторых предупреждений или интерпретации предупреждения как ошибки для отдельных компилируемых программ. Может оказаться, что некоторые сценарии (внешние по отношению к тем, за которые вы отвечаете) вам неподконтрольны. Автор каждого сценария должен иметь возможность задать нужную конфигурацию предупреждений, наследуя более широкий спектр настроек из глобальной области действия.
PLW-06002: недостижимый код
База данных Oracle теперь умеет проводить статический анализ программы для выявления строк кода, которые ни при каких условиях не получат управление во время выполнения. Это исключительно ценная информация, но иногда компилятор предупреждает о наличии проблемы в строках, которые на первый взгляд недостижимыми вовсе не являются. Более того, в описании действий, предпринимаемых для этой ошибки, говорится, что «предупреждение следует отключить, если большой объем кода был сделан недостижимым намеренно, а предупреждение приносит больше раздражения, чем пользы».
Пример такого предупреждения приводился ранее в разделе «Пример». Теперь рассмотрим следующий код:
В Oracle Database 10g и выше для этой программы выдаются следующие предупреждения:
Понятно, почему строка 7 помечена как недостижимая: l_checking присваивается значение FALSE , поэтому строка 7 выполняться не будет. Но почему строка 5 помечена как недостижимая? На первый взгляд этот код будет выполняться всегда! Более того, строка 13 тоже должна выполняться всегда, потому что GOTO передает управление этой строке по метке. И все же эта строка тоже помечена как недостижимая.
Такое поведение объясняется тем, что до выхода Oracle Database 11g предупреждение о недостижимости кода генерируется после его оптимизации. В Oracle Database 11g и выше анализ недостижимого кода стал намного более понятным и полезным.
Компилятор не вводит вас в заблуждение; говоря, что строка N недостижима, он сообщает, что она никогда не будет выполняться в соответствии со структурой оптимизированного кода.
Некоторые ситуации с недостижимым кодом не обнаруживаются компилятором. Пример:
Разумеется, вызов DBMS_OUTPUT.PUT_LINE недостижим, но в настоящее время компилятор не обнаруживает это обстоятельство — до версии 12.1.
PLW-05005: функция возвращает управление без значения
Очень полезное предупреждение — функция, не возвращающая значение, явно очень плохо спроектирована. Это одно из предупреждений, которые я бы рекомендовал интерпретировать как ошибку (синтаксис « ERROR:5005 ») в настройках PLSQL_WARNINGS . Мы уже рассматривали один пример такой функции: no_return. Тот код был тривиальным; во всем исполняемом разделе не было ни одной команды RETURN . Конечно, код может быть и более сложным. Тот факт, что команда RETURN не выполняется, может быть скрыт за завесой сложной условной логики.
Впрочем, по крайней мере иногда в подобных ситуациях база данных способна обнаружить проблему, как в следующей программе:
База данных обнаружила логическую ветвь, не приводящую к выполнению RETURN , поэтому для программы выдается предупреждение. Файл plw5005.sql на сайте github содержит более сложную условную логику, которая демонстрирует, что предупреждение выдается и в более сложных программных структурах.
PLW-07203: рекомендация NOCOPY может принести пользу в объявлении параметра
Как упоминалось ранее в отношении PLW-05005 , использование NOCOPY для сложных, больших параметров IN OUT может улучшить производительность программ в некоторых условиях. Это предупреждение выдается для программ, у которых включение NOCOPY для параметров IN OUT может повысить эффективность выполнения. Пример такой программы:
Это еще одно предупреждение, которое будет генерироваться во многих программах и вскоре начнет раздражать. Безусловно, предупреждение вполне справедливо, но в большинстве случаев последствия такой оптимизации останутся незамеченными. Более того, вряд ли вам удастся переключиться на NOCOPY без внесения изменений для обработки ситуаций с аварийным завершением программы, при котором данные остаются в неопределенном состоянии.
Команда RETURN
Ключевое слово RETURN обычно ассоциируется с функциями, поскольку они должны возвращать значения. Однако PL/SQL позволяет использовать команду RETURN в процедурах. Версия этой команды для процедур не принимает выражений и не может возвращать значения в вызывающий программный модуль — она просто прекращает выполнение процедуры и возвращает управление вызывающему коду.
Использовать эту разновидность RETURN не рекомендуется, поскольку в этом случае в процедуре появляются две и более точки выхода, а это усложняет логику выполнения. Избегайте использования RETURN и GOTO для обхода нормальной управляющей структуры в программных элементах.
Это один из наиболее часто задаваемых вопросов Планировщику. Здесь мы перечисляем некоторые из распространенных проблем и способы их решения.
1) job_queue_processes может быть слишком низким (это наиболее распространенная проблема) Значение job_queue_processes ограничивает общее количество dbms_scheduler и задания dbms_job, которые могут выполняться в заданное время. Чтобы проверить, так ли это, проверьте текущее значение job_queue_processes с SQL> выберите значение из параметра v $, где name = 'job_queue_processes'; Затем проверьте количество запущенных заданий. SQL> выберите количество () из dba_scheduler_running_jobs; SQL> выберите количество () из dba_jobs_running;
Если это проблема, вы можете увеличить параметр, используя SQL> alter system set job_queue_processes = 1000;
2) max_job_slave_processes может быть слишком низким. Если этот параметр не равен NULL, он ограничивает количество заданий dbms_scheduler, которые могут выполняться одновременно. Чтобы проверить, является ли это проблемой, проверьте текущее значение с помощью SQL> выберите значение из dba_scheduler_global_attribute, где attribute_name = 'MAX_JOB_SLAVE_PROCESSES'; Затем проверьте количество выполняемых заданий. SQL> выберите количество (*) из dba_scheduler_running_jobs;
Если это проблема, вы можете увеличить число или просто обнулить его, используя SQL> exec dbms_scheduler.set_scheduler_attribute ('max_job_slave_processes', null)
3) количество сеансов может быть слишком низким. Этот параметр ограничивает количество сеансов в любое время. Для каждого задания планировщика требуется 2 сеанса. Чтобы проверить, является ли это проблемой, проверьте текущее значение с помощью SQL> выберите значение из параметра v $, где name = 'sessions'; Затем проверьте текущее количество сеансов с помощью SQL> выберите count (*) from v $ session;
Если числа слишком близки, вы можете увеличить максимум, используя SQL> alter system set job_queue_processes = 200;
4) Применяли ли вы недавно патч обновления часового пояса или обновляли ли базу данных до версии с более новой информацией о часовом поясе? Если вы пропустили какие-либо шаги при обновлении информации о часовом поясе, задания могут не выполняться. Чтобы проверить, так ли это, попробуйте выполнить SQL> select * from sys.scheduler $ _job; и SQL> выберите * из sys.scheduler $ _window; и убедитесь, что они закончили без ошибок.
Если он выдает предупреждение о часовом поясе, повторно примените обновление или исправление часового пояса, убедившись, что вы выполнили все шаги.
5) База данных работает в ограниченном режиме? Если база данных работает в ограниченном режиме, никакие задания не будут выполняться (если вы не используете 11g и не используете атрибут ALLOW_RUNS_IN_RESTRICTED_MODE). Чтобы проверить это, используйте SQL> выберите логины из v $ instance;
Если вход в систему ограничен, вы можете отключить ограниченный режим, используя SQL> ALTER SYSTEM DISABLE RESTRICTED SESSION;
6) Запланировано ли выполнение задания на неработающем экземпляре?
Вы можете проверить это, посмотрев, установлен ли instance_id для задания (проверьте представление dba_scheduler_jobs), и если да, то вы должны проверить, запущен ли этот экземпляр.
7) Запланировано ли выполнение задания для службы, которая не была запущена ни на одном экземпляре?
Вы можете проверить это, проверив, на какой job_class указывает задание, а затем проверив, указывает ли этот класс на службу. Если это так, убедитесь, что служба запущена хотя бы на одном работающем экземпляре. Вы можете запустить службу на экземпляре с помощью dbms_service.start_service.
8) Действует ли диспетчер ресурсов с ограниченным планом ресурсов?
Если действует ограничительный план ресурсов, для заданий планировщика может не хватать выделенных ресурсов, поэтому они могут не выполняться. Вы можете проверить, какой план ресурсов действует, выполнив
SQL> выберите имя из V $ RSRC_PLAN;
Если план не действует или действует план INTERNAL_PLAN, то диспетчер ресурсов не действует. Если диспетчер ресурсов действует, вы можете отключить его, выполнив
SQL> изменить системный набор resource_manager_plan = '';
9) Планировщик отключен? Это не поддерживаемое действие, но возможно, что кто-то все равно его выполнил. Чтобы проверить это, выполните SQL> выберите значение из dba_scheduler_global_attribute, где attribute_name = 'SCHEDULER_DISABLED'
Причины опоздания с вакансиями
1) Первое, что нужно проверить, - это часовой пояс, в котором задание запланировано с помощью SQL> выберите владельца, имя_задания, дату_следующего_пуска из dba_scheduler_jobs;
Если задания находятся в неправильном часовом поясе, они могут не выполняться в ожидаемое время. Если next_run_date использует абсолютное смещение часового пояса (например, +08: 00) вместо именованного часового пояса (например, US / PACIFIC), тогда задания могут выполняться не так, как ожидалось, если действует летнее время - они могут выполняться на час раньше или позже. .
2) Может случиться так, что в то время, когда задание было запланировано для запуска, одно из нескольких указанных выше ограничений могло быть временно достигнуто, что привело к задержке задания. Убедитесь, что указанные выше пределы достаточно высоки, и, если возможно, проверьте их во время задержки задания.
3) Одна из возможных причин, по которой может быть превышен один из вышеуказанных пределов, заключается в том, что, возможно, вступил в силу интервал обслуживания. Окна обслуживания - это окна планировщика Oracle, которые принадлежат группе окон с именем MAINTENANCE_WINDOW_GROUP. Во время планового окна обслуживания несколько задач обслуживания запускаются с помощью заданий. Это может привести к срабатыванию одного из перечисленных выше ограничений и задержке пользовательских заданий. Дополнительную информацию об этом см. В руководстве администратора (глава 24).
Чтобы получить список окон обслуживания, используйте SQL> выберите * from dba_scheduler_wingroup_members;
Чтобы увидеть, когда запускаются окна, используйте SQL> выберите * from dba_scheduler_windows;
Диагностика других проблем
Если ничего из этого не сработает, вот еще несколько шагов, которые вы можете предпринять, чтобы попытаться выяснить, что происходит.
1) Проверьте, нет ли ошибок в журнале предупреждений. Если у базы данных возникли проблемы с выделением памяти, закончилось место на диске или возникли другие катастрофические ошибки, вы должны сначала устранить их. Вы можете найти местоположение журнала предупреждений, используя SQL> выберите значение из параметра v $, где name = 'background_dump_dest'; Журнал предупреждений будет находиться в этом каталоге с именем, начинающимся с "предупреждения".
2) Проверьте, есть ли файл трассировки координатора заданий, и если он есть, проверьте, содержит ли он какие-либо ошибки. Если он существует, он будет расположен в каталоге 'background_dump_dest', который вы можете найти, как указано выше, и будет выглядеть примерно как SID-cjq0_nnnn.trc. Если здесь есть какие-либо ошибки, они могут намекнуть, почему задания не выполняются.
3) Если любое из вышеперечисленных указывает, что табличное пространство SYSAUX (где планировщик хранит свои таблицы журналирования) заполнено, вы можете использовать процедуру dbms_scheduler.purge_log для очистки старых записей журнала.
4) Посмотрите, открыто ли в данный момент окно. Если есть, вы можете попробовать закрыть его, чтобы посмотреть, поможет ли это.
5) попробуйте запустить простое однократное задание и посмотрите, работает ли оно
6) Если простое однократное задание не запускается, вы можете попробовать перезапустить планировщик следующим образом.
В многопользовательской среде контейнер также должен иметь правильное значение для job_queue_processes.
PLW-05001: предыдущее использование строки противоречит этому использованию
Предупреждение проявляется при объявлении нескольких переменных или констант с одинаковыми именами. Оно также может проявиться в том случае, если список параметров программы, определенный в спецификации пакета, отличается от списка в определении из тела пакета.
Возможно, вы скажете: «Да, я видел эту ошибку, но это именно ошибка компиляции, а не предупреждение». Собственно, вы правы — следующая программа не откомпилируется:
Компилятор выдает ошибку PLS-00371 (в разделе объявлений разрешено не более одного объявления ‘A’).
Почему же для этой ситуации создано предупреждение? Попробуем удалить присваивание переменной с именем a:
Программа откомпилируется! База данных не выдает ошибку PLS-00371 , потому что я не использую ни одну из переменных в своем коде. Предупреждение PLW -05001 устраняет этот недостаток, сообщая о том, что я объявляю одноименные переменные без использования:
2 ответа 2
Это поведение свазано с состоянем пакета. Обратимся к подглаве Package State:
The values of the variables, constants, and cursors that a package declares (in either its specification or body) comprise its package state.
If a PL/SQL package declares at least one variable, constant, or cursor, then the package is stateful; otherwise, it is stateless.
Если в пакете определена как минимум одна переменная, константа или курсор, то пакет после инициализаци получает состояние, которое сохраняется до окончания сессии. Состояние пакета может стать недействительным, одной из причин этого является рекомпиляция пакета:
The package body is recompiled.
If the body of an instantiated, stateful package is recompiled (either explicitly, with the "ALTER PACKAGE Statement", or implicitly), the next invocation of a subprogram in the package causes Oracle Database to discard the existing package state and raise the exception ORA-04068.
After PL/SQL raises the exception, a reference to the package causes Oracle Database to re-instantiate the package, which re-initializes it. Therefore, previous changes to the package state are lost.
После возникновения ошибки, пакеты автоматически реинициализируются, старое их состояние теряется и появляется новое.
Возможное решение, пересмотреть дизайн кода и убрать все переменные, константы или курсоры, объявленные вне функций или процедур, другими словами создать пакет без состояния. Но ничего страшного, если это не предоставляется возможным, при повторном запуске ошибка не должна возникнуть.
В другой сессии заново скомпилируем пакет:
Теперь, в первой сессии вызов вызовет ошибку, так как состояние пакета pack1 потеряно:
Предупреждения во время компиляции способны существенно упростить сопровождение вашего кода и снизить вероятность ошибок. Не путайте предупреждения компилятора с ошибками; с предупреждениями ваша программа все равно будет компилироваться и работать. Тем не менее при выполнения кода, для которого выдавались предупреждения, возможно неожиданное поведение или снижение производительности.
В этой заметке моего блога вы узнаете, как работают предупреждения компилятора и какие проблемы выявляются в текущих версиях. Начнем с краткого примера применения предупреждений времени компиляции в сеансе.
Метка END
Вы можете указать имя процедуры за завершающим ключевым словом END :
Имя служит меткой, явно связывающей конец программы с ее началом. Привыкните к использованию метки END . Она особенно полезна для процедур, занимающих несколько страниц или входящих в серию процедур и функций в теле пакета.
PLW-06009: обработчик OTHERS не завершается вызовом RAISE или RAISE_APPLICATION_ERROR
Это предупреждение (добавленное в Oracle Database 11g) выводится тогда, когда в обработчике исключений OTHERS не выполняется та или иная форма RAISE (повторное инициирование того же исключения или инициирование другого исключения), и не вызывается RAISE_APPLICATI0N_ERR0R . Другими словами, существует большая вероятность того, что программа «поглощает» исключение и игнорирует его. Ситуации, в которых ошибки действительно должны игнорироваться, встречаются довольно редко. Чаще исключение должно передаваться во внешний блок:
Процедура представляет собой модуль, выполняющий одно или несколько действий. Поскольку вызов процедуры в PL/SQL является отдельным исполняемым оператором, блок кода PL/SQL может состоять только из вызова процедуры. Процедуры относятся к числу ключевых компонентов модульного кода, обеспечивающих оптимизацию и повторное использование программной логики.
Общий формат процедуры PL/SQL выглядит так:
Основные элементы этой структуры:
- схема — имя схемы, которой будет принадлежать процедура (необязательный аргумент). По умолчанию применяется имя схемы текущего пользователя. Если значение схемы отлично от имени схемы текущего пользователя, то этот пользователь должен обладать привилегиями для создания процедуры в другой схеме.
- имя — имя процедуры.
- параметр — необязательный список параметров, которые применяются для передачи данных в процедуру и возврата информации из процедуры в вызывающую программу.
- AUTHID — определяет, с какими разрешениями будет вызываться процедура: создателя (владельца) или текущего пользователя. В первом случае процедура выполняется с правами создателя, во втором — с правами вызывающего.
- объявления — объявления локальных идентификаторов этой процедуры. Если объявления отсутствуют, между ключевыми словами IS и BEGIN не будет никаких выражений.
- ACCESSIBLE BY (Oracle Database 12c) — ограничивает доступ к процедуре программными модулями, перечисленными в круглых скобках.
- исполняемые команды — команды, выполняемые процедурой при вызове. Между ключевыми словами BEGIN и END или EXCEPTION должна находиться по крайней мере одна исполняемая команда.
- обработчики исключений — необязательные обработчики исключений для процедуры. Если процедура не обрабатывает никаких исключений, слово EXCEPTION можно опустить и завершить исполняемый раздел ключевым словом END .
На рис. 1 показан код процедуры apply_discount , который содержит все четыре раздела, характерных для именованных блоков PL/SQL.
Рис. 1. Код процедуры
PLW-05000: несовпадение в NOCOPY между спецификацией и телом
Рекомендация NOCOPY сообщает базе данных Oracle, что вы, если это возможно, предпочли бы не создавать копии аргументов IN OUT . Отказ от копирования может повысить производительность программ, передающих большие структуры данных — например, коллекции или CLOB .
Рекомендация NOCOPY должна быть включена как в спецификацию, так и в тело программы (актуально для пакетов и объектных типов). Если рекомендация не присутствует в обоих местах, база данных применяет настройку, указанную в спецификации.
Пример кода, генерирующего это предупреждение:
Предупреждения компилятора отображаются в следующем виде:
Пример
Очень полезное предупреждением компилятора PLW-06002 сообщает о наличии недостижимого кода. Рассмотрим следующую программу. Так как переменная salary инициализируется значением 10 000, условная команда всегда будет отправлять меня на строку 9. Строка 7 выполняться не будет:
Если откомпилировать этот код в любой версии до Oracle Database 10g , компилятор просто сообщит о том, что процедура создана. Но если включить предупреждения компиляции в сеансе этой или более поздней версии, то при попытке откомпилировать процедуру будет получен следующий ответ от компилятора:
С этим предупреждением я могу вернуться к указанной строке, определить, почему она недостижима, и внести необходимые исправления.
PLW-07204: преобразование типа столбца может привести к построению неоптимального плана запроса
Предупреждение выдается при вызове команд SQL из PL/SQL, при котором происходят неявные преобразования. Пример:
С этим предупреждением тесно связано предупреждение PLW-7202 (тип передаваемого параметра приводит к преобразованию типа столбца).
Вызов процедуры
Процедура вызывается как исполняемая команда PL/SQL. Другими словами, ее вызов должен заканчиваться точкой с запятой (;) и может предшествовать другим командам SQL либо PL/SQL (если таковые имеются) в исполняемом разделе блока PL/SQL или следовать за ними:
Если процедура не имеет параметров, она может вызываться с пустыми круглыми скобками или без них:
Читайте также: