Oracle кто изменил пакет

Обновлено: 05.07.2024

У нас есть пакет, который является зависимостью другого пакета, иногда внесение изменений в "родительский" пакет приводит к тому, что зависимый пакет становится недействительным, но иногда это не так.

это застало нас врасплох раньше.

было бы очень полезно просто понять, что вызывает недействительность, чтобы я мог предсказать/спланировать ее.

изменение любого объекта, на который опирается пакет (например, таблицы, представления, триггеры, другие пакеты), автоматически помечает пакет как недопустимый. Как отмечает tuinstoel выше, Oracle достаточно умен, чтобы перекомпилировать пакет при его первом использовании.

или вы можете запросить следующую таблицу, чтобы узнать, какие зависимости у вас есть

Это покажет все зависимости. Для ваших объектов запросите user_dependencies.

кстати, если я полностью ошибаюсь в ситуации. заранее извиняюсь

Не уверен, каковы последствия этого.

что-то сломалось в производстве?

Что именно произошло?

опять же я подозреваю, что это так, и если да, давайте просто разберемся с этим вместо списка изменений, которые, как я поставил в комментарии, специфичны для версии. (Например, 11g отслеживает зависимость до столбца таблицы вместо таблицы в целом).

Это не может показаться вам важной ошибкой если вы не используете пакет государство. Если бы это было так, это была бы важная ошибка, и вы бы не удивились, так что, полагаю, это не так.

Так как вы не эта ошибка нормально игнорировать. Поскольку вы можете безопасно игнорировать его, вы можете закодировать клиентское приложение, чтобы игнорировать эту ошибку и повторить вызов, потому что, как указывали другие, Oracle перекомпилирует ваш пакет для вас. Это полезное упражнение. Потому что вместо того, чтобы знать все возможные вещи, вам нужно беспокоиться о том, когда вы делаете изменения, и затем в экстренном исправлении вы забудете один из них, ваше приложение просто справится с ним и двинется дальше, не волнуясь.

Я согласен с Томасом Джонсом-низким, однако есть еще пара вопросов, связанных с длинными сессиями и перекомпиляцией.

Если вы ссылаетесь на пакет в сеансе, и этот пакет (или зависимый пакет) перекомпилируется во время того же сеанса, вы получите ошибку oracle "ORA-06508: PL/SQL: не удалось найти программный блок, который называется"

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

в дополнение к ответу Томаса Джонса-Лоу, если вы только измените тело пакета, зависимый объект не может быть помечен как недопустимый.

однако, как только вы измените спецификацию пакета, это обязательно произойдет.

Если попытаться выполнить недопустимый пакет Oracle, Oracle попытается его скомпилировать. Только если он остается недействительным после компиляции Oracle выдаст исключение.

1. Делается GUI-приложение, в котором имеется возможность на основе метаинформации о базе данных (информации о структуре базы) выбирать какие схемы / таблицы / поля отслеживать. Названия объектов за которыми происходит слежение заносится в некую таблицу (ну или список таблиц, неважно).
Также GUI включает в себя средство просмотра самой информации по изменению таблиц в удобном виде (фильтрация и прочее).

2. Существует скрипт БД. Что он делает - проходит по всей базе (по всем схемам или как вариант по некоторым схемам) и к каждой таблице добавляет триггер на insert, update, delete. При срабатывании этого тригера идет запрос к таблицам описания слежения и проверяется, нужно ли вести историю этой таблицы, полей этой таблицы. Если нужно - то старая информация скидывается в дублирующую таблицу (структура которой включает в себя полностью структуру таблицы за которой идет слежение). Таким образом в дублирующей таблице будет история изменения записей.
По прошествии времени, каких-то условий, информация из дублирующих таблиц будет скидываться в дамп и отправляться в архив.
Думаю, в целом принцип ясен, если что - задавайте вопросы.

Некоторые моменты. Почему ко всем таблицам прилепляются триггеры? Чтобы не мучатся с синхронизацией метаописания слежения и реальным положением в базе, не делать сверки и подобное. Что-то не так - бац, пересоздал триггер для всех таблиц, текст триггера однотипный достаточно, для всех таблиц может иметь одинаковое названия типа "__history_trigger". Да, мы понимаем, что это замедляет работу со вставкой, удалением и апдейтом данных, по нашим экспериментам в несколько раз, но это допустимо, железо перекрывает потребности в производительности, а задача такая стоит.

Но такое количество триггеров, конечно, в какой-то степени удручает (особенно, если слежение производится за 15 таблицами, а всего таблиц 500 и получается 500 триггеров). Возможно, есть какие-то триггеры на схему? Вроде бы есть триггер на всю БД, но он сильно системный и туда попадает множество лишней информации, типа создание таблиц, дропа, создание хранимок, триггеров ну и прочее.

Знаем, что в oracle есть трейс, куда скидывается в текстовом виде информация об изменении данных. Но информация текстовая, распарсивать оочень не хочется. И есть подозрение, что включать трейс на промышленной, боевой БД все таки не стоит.

Также есть подозрение, что задача не уникальная и встречались с ней многие. Возможно, есть выработанные стандартизированные методы подхода? На настоящее время с кем общались - все делали кто во что горазд. Зачастую это делается системной вещью, типа налепить триггеров и они будут скидывать информацию об обновлении. Когда потребуется разборка - в руки любимый софт для работы с БД и вручную разбираться что и когда. У нас, к сожалению, стоит задача сделать немного в более удобном виде, с управлением через GUI и просмотром истории там же.

Таким образом принимается любая критика по описанному подходу, какие подводные камни могут встретиться, опыт по созданию такой системы мониторинга может у кого есть? Какие места будут сложные в реализации, что стоит учесть в самом начале? Возможно, существуют совершенно другие подходы к реализации этой задачи, возможно основанные на специфике оракла, возможно там даже с написанием каких-то системных плагинов расширения (DLL, so или подобное). Любые мысли, пожалуйста :-)

1) поскольку триггеры создаются ко всем таблицам - исчезает проблема синхронизации. Но остается проблема создания и поддержания в актуальном виде дублирующих таблиц. Конечно, можно КАЖДОЙ таблице делать дублирующую историческую таблицу (даже если нет слежения за этой таблицей), но это, наверное, уже перебор. Но иначе нужно как-то следить. Тут стоить представить процесс разработки. Допустим, перерисовали таблицу под измененные бизнес-требования в каком-нибудь редакторе структуры таблиц. Внесли изменение в таблицу, внесли изменение в клиентское ПО, сделали скрипт обновления структуры для обновления до новой версии ПО.
А вот дублирующую таблицу изменить забыли. В результате триггер исторический может начать плеваться exception и застопорить вставку, обновление и удаление данных. И пятая точка чует, что таких косячков будет немало. Очень интересен опыт тех, кто внедрял подобную систему, с чем больше всего намучались, насколько это усложнило разработку и главное ПОДДЕРЖКУ систем?

2) чисто техническая фишка. По идее триггер должен сработать САМЫМ первым, чтобы унести в историческую дублирующую таблицу старые данные. Ибо если перед ним сработает другой триггер, то там уже могут оказаться не реальные старые данные, а какие-нибудь данные сформированные триггером, сработавшим раньше. ну или что-то в этом роде.

Сугубо ИМХО все.
Вместо нормальной работы по контролю доступа, разграничению прав и проработки бизнес логики предлагается глобальная шняга, которая, если заработает, будет жрать диски и другие ресурсы со скоростью на порядки превышающей нормальную.

Для простейшего контроля достаточно добавить в критические таблицы 2 поля - временнУю метку и юзернейм последнего редактирования записи.

для дешевых применений написать триггер, который записывает значения в сделанные руками таблицу аудита.


> Вместо нормальной работы по контролю доступа, разграничению
> прав и проработки бизнес логики предлагается глобальная
> шняга

это имеет крайне посредственное отношение к разграничению доступа и правам. Человек вполне может иметь права сделать ДЕЙСТВИЕ, но это не отменяет задачи при наличии желания узнать КТО конкретно сделал этот действие.

вроде ссылок надавали.
Кайта еще читать не повредит

А вы могли бы навскидку перечислить основные минусы, плюсы подходов:


> без админских прав? шо, серьезно?

Без админских, а что ? Прав владельца хватает.


> ну тогда ораклу надо выкрасить и быбросить.

Я ничего не придумываю. Я описываю варианты. Твое описание подходит под "мой" вариант №2
> Если все нормально, но нужна история изменения - значит система просто недоработана. Причем именно в этом месте, а не вообще.

Охота вместо фиксации юзера/времени в критической таблице делать систему глобального аудита - флаг в руки. Я сразу заявил, что

> Сугубо ИМХО все.

так вот, без всякого трындежа, залезу под юзером безправным, который пользует одну табличку по чтению/записи, и у котрой есть триггер. и убЪю гада! без трындежа? так таки убью? или не стоит руки марать?


> а можешь матчасть почитать

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


> я много чего могу. теоретически. даже в космос летать. если
> мне это действительно надо, или за это платят. а так - многа
> букав, ниасилю. и потом, методом научного тыка - тоже неплохо
> получается.

зы. а юзер таки нифига не видит. и это правильно.


> хотелось простоты и красивости

думается, исходную запись собрать можно, причем, они правильно сделали, фиксятся только изменения полей. долго запрос нарисовать, чтобы было всю сущность посмотреть со всей историей?

Владелец - это тот, кто создал объект (таблицу, триггер, еще что-нибудь).
Владелец же может дать права на таблицу, триггер, еще что-нибудь, кому угодно. Причем, права разные - от чтения до модификации и выполнения.


> ежели права владельца раздавать всем, кому не попадя, то
> кто кому доктор?

Права владельца не раздаются, они существуют и раздать их нельзя, насколько мне известно.

Существуют права, которое плюют на владельца, в их названии присутствует слово ANY (например, DROP ANY TRIGGER), такие права тоже могут быть даны кому угодно (но даются редко)

Кто такой юзер в этом контексте - я не понимаю. Если просто посторонний по отношению к владельцу объекта, так он объекта даже не увидит, не говоря о том, чтобы изменить, удалить и прочее, опять же, если владелец не предоставил права любому (PUBLIC)


> Существуют права, которое плюют на владельца

видимо, что-то типа SYSDBA, правда, я под ним не ходил(и аудит из-под него-же, наскоько я понимаю). Игорь, согласись, глупо отлавливать тех, кто наделен полными полномочиями по отношению к объекту (подразумеваются данные в таблицах, опять же). ну, как правило. я так понимаю, что такими правами наделяют людей вполне адекватных? хотя, их тоже можно ловить, но это уже именно из админа.

Когда задача решена, все изменения в БД переносятся из девелоперской схемы в тестовую, но при этом раздаются нужные права, а владельцем новых объектов БД становится админ. В тестовой схеме разработчик имеет ограниченные права - лишь те, что нужны ему для тестирования (например, права конечного юзера плюс права на просмотр чего-то). Тем самым, в процессе тестирования проверяется как новый функционал, так и правильность скриптов переноса из схемы в схему и раздачи прав.

Работа с данными пакета (package) PL/SQL

Данные пакета PL/SQL состоят из переменных и констант, определенных на уровне пакета, а не в конкретной его функции или процедуре. Их областью видимости является не отдель­ная программа, а весь пакет. Структуры данных пакета существуют (и сохраняют свои значения) на протяжении всего сеанса, а не только во время выполнения программы. Если данные пакета объявлены в его теле, они сохраняются в течение сеанса, но до­ступны только элементам пакета (то есть являются приватными).

Если данные пакета объявлены в его спецификации, они также сохраняются в те­чение всего сеанса, но их чтение и изменение разрешено любой пользовательской программе, обладающей привилегией EXECUTE для пакета. Общие данные пакета похожи на глобальные переменные Oracle Forms (а их использование сопряжено с таким же риском).

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

Глобальные данные в сеансе Oracle

В среде PL/SQL структуры данных пакета функционируют как глобальные. Однако следует помнить, что они доступны только в пределах одного сеанса или подключения к базе данных Oracle и не могут совместно использоваться несколькими сеансами. Если доступ к данным нужно обеспечить для нескольких сеансов Oracle, используйте пакет DBMS_PIPE (его описание имеется в документации Oracle Built-In Packages).

Будьте осторожны с предположением о том, что разные части приложения всегда работают с Oracle через одно подключение. В некоторых случаях среда, из которой выполняется компонент приложения, устанавливает для него новое подключение. При этом данные пакета, записанные первым подключением, будут недоступны для второго.

Допустим, приложение Oracle Forms сохранило значение в пакетной структуре данных. Когда форма вызывает хранимую процедуру, эта процедура может обращаться к тем же пакетным переменным и значениям, что и форма, потому что они используют одно подключение к базе данных. Но допустим, форма генерирует отчет с использованием Oracle Reports. По умолчанию Oracle Reports создает для отчета отдельное подключе­ние к базе данных с тем же именем пользователя и паролем. Даже если отчет обратится к тому же пакету и структурам данных, что и форма, значения, хранимые в структурах данных, доступных форме и отчету, будут разными, поскольку сеанс отчета имеет свой экземпляр пакета и всех его структур.

По аналогии с двумя типами структур данных в пакетах (общедоступные и приватные) также существуют два типа глобальных данных пакетов: глобальные общедоступные данные и глобальные приватные данные. В следующих трех разделах статьи рассматриваются различные способы использования данных пакетов.

Глобальные общедоступные данные

Любая структура данных, объявленная в спецификации пакета, является глобальной общедоступной структурой данных; это означает, что к ней может обратиться любая

программа за пределами пакета. Например, вы можете определить коллекцию PL/ SQL в спецификации пакета и использовать ее для ведения списка работников, заслу­живших повышение. Вы также можете создать пакет с константами, которые должны использоваться во всех программах. Другие разработчики будут ссылаться на пакетные константы вместо использования фиксированных значений в программах. Глобальные общедоступные структуры данных также могут изменяться, если только они не были объявлены с ключевым словом CONSTANT .

Глобальные данные обычно считаются источником повышенной опасности в програм­мировании. Их очень удобно объявлять, они прекрасно подходят для того, чтобы вся информация была доступна в любой момент времени — однако зависимость от глобаль­ных структур данных приводит к созданию неструктурированного кода с множеством побочных эффектов.

Вспомните, что спецификация модуля должна сообщать полную информацию, не­обходимую для вызова и использования этого модуля. Однако по спецификации па­кета невозможно определить, выполняет ли пакет чтение и/или запись в глобальные структуры данных. По этой причине вы не можете быть уверены в том, что происходит в приложении и какая программа изменяет те или иные данные.

Передачу данных модулям и из них всегда рекомендуется осуществлять через параме­тры. В этом случае зависимость от структур данных документируется в спецификации и может учитываться разработчиками. С другой стороны, именованные глобальные структуры данных должны создаваться для информации, действительно глобальной по отношению к приложению — например, констант и параметров конфигурации.

Такие данные следует разместить в централизованном пакете. Однако учтите, что при такой архитектуре в приложении возникает «единая точка перекомпиляции»: каждый раз, когда вы вносите изменение в пакет и перекомпилируете спецификацию, многие программы приложения теряют работоспособность.

Пакетные курсоры

Одним из самых интересных типов пакетных данных является явный курсор PL/SQL. Его можно объявить в теле либо в спецификации пакета. Состояние курсора (открыт или закрыт), а также указатель на его набор данных сохраняются в течение всего сеанса. Это означает, что открыть пакетный курсор можно в одной программе, выбрать из него данные — в другой, а закрыть — в третьей. Такая гибкость курсоров предоставляет большие возможности, но в то же время она может стать источником проблем. Сначала мы рассмотрим некоторые тонкости объявления пакетных курсоров, а затем перейдем к открытию, выборке данных и закрытию таких курсоров.

Объявление пакетных курсоров

Явный курсор в спецификации пакета можно объявлять двумя способами:

  • Полностью (заголовок курсора и запрос). Именно так объявляются курсоры в ло­кальных блоках PL/SQL .
  • Частично (только заголовок курсора). В этом случае запрос определяется в теле пакета, поэтому реализация курсора скрыта от использующего пакет разработчика. При использовании второго способа в объявление нужно добавить секцию RETURN , ука­зывающую, какие данные будут возвращены при выборке из курсора. На самом деле эти данные определяются инструкцией SELECT , которая присутствует только в теле, но не в спецификации

В секции RETURN можно задать одну из следующих структур данных:

  • О запись, объявленная на основе таблицы базы данных с использованием атрибута %rowtype ;
  • О запись, определенная программистом.

Объявление курсора в теле пакета осуществляется так же, как в локальном блоке PL/ SQL . Следующий пример спецификации пакета демонстрирует оба подхода:

Логика программы описана в следующей таблице.

Строки Описание
3-9 Типичное определение явного курсора, полностью заданное в спецификации пакета
11-13 Определение курсора без запроса. Спецификация указывает, что открыв курсор и выбрав
из него данные, пользователь получит одну строку из таблицы books под действием заданного фильтра
15-18 Определение нового типа записи для хранения информации об авторе
20-22 Объявление курсора, возвращающего сводную информацию о заданном авторе (всего три
значения)

Рассмотрим тело пакета и выясним, какой код необходимо написать для работы с каждым из этих курсоров:

Работа с пакетными курсорами

Теперь давайте посмотрим, как пользоваться пакетными курсорами. Прежде всего для открытия, выборки данных и закрытия вам не придется изучать новый синтаксис — нужно только задать имя пакета перед именем курсора. Например, чтобы запросить информацию о книгах по PL/SQL, можно выполнить такой блок кода:

Как видите, на основе пакетного курсора точно так же можно объявить переменную с использованием %ROWTYPE и проверить атрибуты. Ничего нового!

Однако и в этом простом фрагменте кода есть скрытый нюанс. Поскольку курсор объ­явлен в спецификации пакета, его область видимости не ограничивается конкретным блоком PL/SQL . Предположим, мы выполняем следующий код:

Дело в том, что блок, выполненный первым, не закрыл курсор, и по завершении его работы курсор остался открытым.

При работе с пакетными курсорами необходимо всегда соблюдать следующие правила:

  • Никогда не рассчитывайте на то, что курсор закрыт (и готов к открытию).
  • Никогда не рассчитывайте на то, что курсор открыт (и готов к закрытию).
  • Всегда явно закрывайте курсор после завершения работы с ним. Эту логику также необходимо включить в обработчики исключений; убедитесь в том, что курсор за­крывается на всех путях выхода из программы.

Если пренебречь этими правилами, то ваши приложения будут работать нестабильно, а в процессе их функционирования могут появиться неожиданные необработанные исклю­чения. Поэтому лучше написать процедуры, которые открывают и закрывают курсоры и учитывают все возможные их состояния. Этот подход реализован в следующем пакете:

Как видите, вместе с курсором объявлены две сопутствующие процедуры для его от­крытия и закрытия. Если нам, скажем, потребуется перебрать в цикле строки курсора, это можно сделать так:

В этом фрагменте не используются явные вызовы OPEN и CLOSE . Вместо них вызываются соответствующие процедуры, скрывающие особенности работы с пакетными курсорами.

Можно взглянуть на ситуацию под другим углом:

. Вместо того чтобы работать с пакетными курсорами, можно добиться точно такого же эффекта посредством инкапсуляции логики и данных в представлениях и опубликовать их для разработчиков. В этом случае разработчики будут нести ответственность за сопровождение своих курсоров; дело в том, что обеспечить нор­мальное сопровождение с инструментарием, существующим для общедоступных пакетных курсоров, невозможно. А именно, насколько мне известно, невозможно гарантировать использование процедур открытия/закрытия, но курсор всегда будет оставаться видимым для разработчика, который открывает/закрывает его напря­мую; следовательно, такая конструкция остается уязвимой. Проблема усугубляется тем, что использование общедоступных пакетных курсоров и процедур открытия/ закрытия может породить в группе ложное чувство безопасности и защищенности».

Пакетное создание курсоров и предоставление доступа к ним всем разработчикам, участвующим в проекте, приносит большую пользу. Проектирование оптимальных структур данных приложения — непростая и кропотливая работа. Эти структуры — и хра­нящиеся в них данные — используются в программах PL/SQL, а работа с ними почти всегда осуществляется через курсоры. Если вы не определите свои курсоры в пакетах и не предоставите их «в готовом виде» всем разработчикам, то каждый будет писать собственную реализацию курсора, а это создаст массу проблем с производительностью и сопровождением кода. Пакетные курсоры являются лишь одним из примеров инкап­суляции доступа к структурам данных.

Повторно инициализируемые пакеты

По умолчанию пакетные данные сохраняются в течение всего сеанса (или до переком­пиляции пакета). Это исключительно удобное свойство пакетов, но и у него имеются определенные недостатки:

  • Постоянство глобально доступных (общих и приватных) структур данных сопро­вождается нежелательными побочными эффектами. В частности, можно случайно оставить пакетный курсор открытым, а в другой программе попытаться открыть его без предварительной проверки, что приведет к ошибке.
  • Если данные хранятся в структурах уровня пакетов, то программа может занять слишком большой объем памяти, не освобождая ее.

Для оптимизации использования памяти при работе с пакетами можно использовать директиву SERIALLY_REUSABLE . Она указывает Oracle, что пакет является повторно инициализируемым, то есть его состояние (состояние переменных, открытых пакетных курсоров и т. п.) нужно сохранять не на протяжении сеанса, а на время одного вызова пакетной программы.

Рассмотрим действие этой директивы на примере пакета book_info . В нем имеются две отдельные программы: для заполнения списка книг и для вывода этого списка.

Как видно из приведенного ниже тела пакета, список объявляется как приватный гло­бальный ассоциативный массив:

Чтобы увидеть, как работает эта директива, заполним список и выведем его на экран. В первом варианте оба шага выполняются в одном блоке:

Заполнение и вывод в одном блоке:

Во второй версии заполнение и вывод списка производятся в разных блоках. В резуль­тате коллекция окажется пустой:

Заполнение в первом блоке

Вывод во втором блоке:

Работая с повторно инициализируемыми пакетами, необходимо учитывать некоторые особенности:

В Oracle PL/SQL набор элементов: процедур, функций, определения типов; объявления переменных, констант можно объединить в пакет. После написания пакет PL/SQL компилируется, а затем сохраняется в базе данных Oracle, где его содержимое может использоваться многими приложениями.

Что такое пакет Oracle PL/SQL?

Пакет Oracle PL/SQL - это объект схемы, который группирует логически связанные типы, элементы и подпрограммы. Пакеты обычно состоят из двух частей: спецификации и тела, хотя иногда тело не нужно. Спецификация - это интерфейс для ваших приложений.
В спицификации пакета объявляются типы, переменные, константы, исключения, курсоры и подпрограммы, доступные для использования.
Тело пакета полностью определяет курсоры и подпрограммы и реализует спецификацию.

Пакеты Oracle PL/SQL

Как показано на рисунке, вы можете думать о спецификации как о рабочем интерфейсе, а о теле - как о «черном ящике». Вы можете отлаживать, улучшать или изменять тело пакета без изменения интерфейса (спецификации) пакета.

Для создания пакетов используйте оператор CREATE PACKAGE.

Синтаксис

Синтаксис CREATE PACKAGE в Oracle PL/SQL:

CREATE [OR REPLACE] PACKAGE package_name
[AUTHID ]

[PRAGMA SERIALLY_REUSABLE;]
[collection_type_definition . ]
[record_type_definition . ]
[subtype_definition . ]
[collection_declaration . ]
[constant_declaration . ]
[exception_declaration . ]
[object_declaration . ]
[record_declaration . ]
[variable_declaration . ]
[cursor_spec . ]
[function_spec . ]
[procedure_spec . ]
[call_spec . ]
[PRAGMA RESTRICT_REFERENCES(assertions) . ]
END [package_name];

[CREATE [OR REPLACE] PACKAGE BODY package_name
[PRAGMA SERIALLY_REUSABLE;]
[collection_type_definition . ]
[record_type_definition . ]
[subtype_definition . ]
[collection_declaration . ]
[constant_declaration . ]
[exception_declaration . ]
[object_declaration . ]
[record_declaration . ]
[variable_declaration . ]
[cursor_body . ]
[function_spec . ]
[procedure_spec . ]
[call_spec . ]
[BEGIN
sequence_of_statements]
END [package_name];]

collection_type_definition - определение типа коллекции
record_type_definition - определение типа записи
subtype_definition - определение подтипа
collection_declaration - объявление коллекции
constant_declaration - объявление константы
exception_declaration - объявление исключения
object_declaration - объявление объекта
record_declaration - объявление записи
variable_declaration - объявление переменной
cursor_spec - спецификация курсора
function_spec - спецификация функции
procedure_spec - спецификация процедуры
call_spec - спецификация вызова

Спецификация пакета содержит публичные объявления, которые видны вашему приложению. Вы должны объявить подпрограммы в конце спецификации после всех других элементов (кроме прагм, которые вызывают конкретную функцию; такие прагмы должны следовать спецификации функции).

Тело пакета содержит детали реализации и приватные объявления, которые скрыты от вашего приложения. За декларативной частью тела пакета следует необязательная часть инициализации, которая обычно содержит операторы, которые инициализируют переменные пакета.

Пример пакета Oracle PL/SQL

В приведенном ниже примере, вы определяете тип запись, курсор и две процедуры по трудоустройству. Обратите внимание, что процедура hire_employee использует последовательность базы данных empno_seq и функцию SYSDATE для вставки нового номера сотрудника и дату приема на работу соответственно.

Читайте также: