Базы данных Oracle - статьи

         

Как сделать функцию невидимой


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

К счастью, проблема неожидаемой маскировки объекта в БД, о которой пойдет речь, довольно специфична. Однако ж она вполне реальна.

Рассмотрим пример функции в схеме SCOTT:

SQL> CREATE FUNCTION ename RETURN VARCHAR2 AS 2 BEGIN RETURN 'I am a function'; END; 3 /

Function created.

Это не запрещено, несмотря на наличия поля ENAME в одной из таблиц схемы, так как пространства имен функций и столбцов не пересекаются (и правильно !). Но что произойдет, если к ней обратиться при выборке данных из таблицы EMP ? Если выполнить следующий запрос, что мы увидим: столбец или функцию ?

SELECT ename FROM emp;

Правильный ответ дает документация, где в одном из бесчисленных закоулков перечислена последовательность обработки имен объектов в предложениях SQL. Однако в данном случае гораздо проще изматывающего поиска в документации поставить эксперимент и убедиться, что по принципу "своя рубашка ближе к телу" СУБД выдаст значения столбца таблицы.

Закономерно возникает вопрос: а как при обращении к EMP выдать значение функции ENAME ? Несложные эксперименты приводят к необходимости указать полное имя функции, снабдив его именем схемы:

SELECT scott.ename, ename FROM emp;

Или же (что в некоторых смыслах более правильно)

SELECT scott.ename, emp.ename FROM emp;

Крайне неудачная система обозначений (в SCOTT.ENAME SCOTT - это имя схемы, а в такой же по виду записи EMP.ENAME EMP - это имя таблицы), но свое дело она делает. К сожалению, этим дело не кончается. Пространства имен схем и пакетов тоже разные, что тоже правильно. Рассмотрим теперь следующее:

CREATE OR REPLACE PACKAGE scott IS FUNCTION ename
RETURN varchar2; END scott; /

CREATE OR REPLACE PACKAGE BODY scott IS FUNCTION ename RETURN varchar2 IS BEGIN RETURN 'I am a package function'; END ename; END scott; /

SELECT scott.ename FROM emp;

Убедитесь, что получим 'I am a package function'. Но теперь, обращаясь к EMP мы никогда не увидим результат самостоятельной (не пакетированной) функции ENAME ! Если в вашем приложении были запросы типа SELECT scott.ename FROM emp, то после создания пакета они начнут выдавать попросту другой ответ.

Способ формирования составных имен не идеален и в других языках. Например, даже в таком архитектурно продуманном языке, как Java, понять по тексту смысл каждой компоненты в имени java.lang.System.out.println без дополнительной информации невозможно. Но другой системы, кроме Oracle, где допускалось бы исчезновение видимости имени одного объекта вследствие вполне законного заведения других, мне неизвестно.



Содержание раздела