Вопрос

Я хотел бы создать пакет Oracle и две функции в нем:Общественная функция ( function_public ) и частный ( function_private ).Публичная функция использует частную функцию в операторе sql.

Без прагмы код не компилируется(PLS-00231: function 'FUNCTION_PRIVATE' may not be used in SQL)

CREATE OR REPLACE PACKAGE PRAGMA_TEST AS
  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2;
END PRAGMA_TEST;

CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS
  FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS
  BEGIN
     return 'z';
  END;

  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS
  ret VARCHAR2(100);
  BEGIN
     SELECT 'x' || function_private(x) INTO ret FROM dual;
     return ret;
  END;
END PRAGMA_TEST;

Код компилируется, если я добавляю WNDS, WNPS Прагма для function_private.Мне кажется, что прагму можно использовать только в объявлении пакета, а не в теле пакета, поэтому я должен объявить function_private в упаковке также:

CREATE OR REPLACE PACKAGE PRAGMA_TEST AS
  FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2;
  PRAGMA RESTRICT_REFERENCES( function_private, WNDS, WNPS);
  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2;
END PRAGMA_TEST;

CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS
  FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS
  BEGIN
     return 'z';
  END;

  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS
  ret VARCHAR2(100);
  BEGIN
     SELECT 'x' || function_private(x) INTO ret FROM dual;
     return ret;
  END;
END PRAGMA_TEST;

Это решение делает мой function_private общественность тоже.Есть ли решение добавить прагму к функции, которую можно найти только в теле пакета?

ОБНОВЛЯТЬ: Заменил псевдокод на рабочий (упрощённый) пример.

ОБНОВЛЕНИЕ2:Исправления в коде, предложенные Робом ван Вейком.

Это было полезно?

Решение

Ваша проблема не имеет ничего общего с прагами. Как говорит Роб, современные версии Oracle обрабатывают большую часть этого автоматически.

Проблема в том, что вы не можете назвать частные функции из оператора SQL, Даже из них встроен в другую подпрограмму в том же пакете. Когда PL / SQL выполняет SQL, он передан на SQL Engine для выполнения, и что по существу приведет вас за пределами объема пакета, поэтому он не имеет доступа к частным членам.

Это компилирует хорошо - нет прагма, но делает «частную» функцию общественности:

CREATE OR REPLACE PACKAGE PRAGMA_TEST AS
  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2;
  FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2;
END PRAGMA_TEST;


CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS
  FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS
  BEGIN
     return 'z';
  END;

  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS
     ret VARCHAR2(30);
  BEGIN
     SELECT 'x' || function_private(x) INTO ret FROM dual;
     RETURN ret;
  END;
END PRAGMA_TEST;

Если вы хотите сохранить функцию частным, вам нужно посмотреть, сможете ли вы переписать публичную функцию таким образом, чтобы вызов к личной функции выполнен за пределы оператора SQL:

CREATE OR REPLACE PACKAGE PRAGMA_TEST AS
  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2;
END PRAGMA_TEST;


CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS
  FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS
  BEGIN
     return 'z';
  END;

  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS
     ret VARCHAR2(30);
  BEGIN
     ret := function_private(x);
     SELECT 'x' || ret INTO ret FROM dual;
     RETURN ret;
  END;
END PRAGMA_TEST;

Другие советы

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

Сравните это безопасное заявление (заметьте, я расширил чистоту function_public) ...

SQL> CREATE OR REPLACE PACKAGE PRAGMA_TEST AS
  2    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2;
  3    PRAGMA RESTRICT_REFERENCES( function_public, WNDS, WNPS, RNDS);
  4  END PRAGMA_TEST;
  5  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS
  2    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS
  3    BEGIN
  4       return 'no harm done';
  5    END;
  6
  7    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS
  8    BEGIN
  9       return function_private(x);
 10    END;
 11  END PRAGMA_TEST;
 12  /

Package body created.

SQL>

...с этим небезопасным...

SQL> CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS
  2    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS
  3       rv varchar2(1);
  4    BEGIN
  5       select dummy into rv from dual;
  6       return rv;
  7    END;
  8
  9    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS
 10    BEGIN
 11       return function_private(x);
 12    END;
 13  END PRAGMA_TEST;
 14  /

Warning: Package Body created with compilation errors.

SQL> sho err
Errors for PACKAGE BODY PRAGMA_TEST:

LINE/COL ERROR
-------- -----------------------------------------------------------------
9/3      PLS-00452: Subprogram 'FUNCTION_PUBLIC' violates its associated
         pragma

SQL>

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

редактировать

Ах, теперь, увидев ваш исправленный пример кода, я понимаю, что вы пытаетесь сделать.Это не работает, не будет, не может работать.Нам разрешено использовать только упакованные функции, которые были объявлены в спецификации = общедоступные функции - в SQL.Не имеет значения, написан ли SQL в SQL*Plus или закодирован в другой упакованной процедуре.Причина вполне ясна в стеке ошибок:

SQL> CREATE OR REPLACE PACKAGE PRAGMA_TEST AS
  2        FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2;
  3        PRAGMA RESTRICT_REFERENCES( function_public, WNDS, WNPS);
  4  END PRAGMA_TEST;
  5  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS
  2    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS
  3       rv varchar2(1);
  4    BEGIN
  5       select dummy into rv from dual;
  6       return rv;
  7    END;
  8
  9    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS
 10       rv varchar2(1);
 11    BEGIN
 12       select function_private(x) into rv from dual;
 13       return rv;
 14    END;
 15  END PRAGMA_TEST;
 16  /

Warning: Package Body created with compilation errors.

SQL> sho err
Errors for PACKAGE BODY PRAGMA_TEST:

LINE/COL ERROR
-------- -----------------------------------------------------------------
12/6     PL/SQL: SQL Statement ignored
12/13    PL/SQL: ORA-00904: : invalid identifier
12/13    PLS-00231: function 'FUNCTION_PRIVATE' may not be used in SQL
SQL>

Компилятор выбрасывает ORA-00904: invalid identifier потому что функция не объявлена ​​в спецификации;это не имеет ничего общего с уровнем чистоты,

примечание о сфере применения

PL/SQL не полностью соответствует требованиям его правила области видимости:мы можем использовать частные переменные в нашем упакованном операторе SQL:

SQL> CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS
  2
  3    gv constant varchar2(8) := 'global';
  4
  5    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS
  6       rv varchar2(1);
  7    BEGIN
  8       select dummy into rv from dual;
  9       return rv;
 10    END;
 11
 12    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS
 13       rv varchar2(10);
 14    BEGIN
 15       select gv||'+'||dummy into rv from dual;
 16       return rv;
 17    END;
 18  END PRAGMA_TEST;
 19  /

Package body created.

SQL>

Это просто функции и типы, которые wm должен объявить в спецификации, если мы хотим использовать их в операторах SQL.

Вы пишете «Я хотел бы добавить WNDS, WNPPS Pragma ...». Почему тебе это нравится? С версии 9 (я думаю) Oracle делает этот чек для вас. Единственная причина, по которой вы можете самостоятельно добавить прагму, это когда:

  • Вы знаете, где в операторе SQL вы хотите использовать функцию и

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

  • Вы хотите найти нарушения во время компиляции, а не время выполнения

Самый простой вариант - просто пропустить все декларации в прагме.

Сказав это, вы можете опустить restrict_References Pragma для функции_Private, если вы добавляете ключевое слово доверия к RESTRICT_REFERCES PRAGMA FUNCTION_PUBLEABLE.

http://download.orcle.com/docs/cd/b10501_01/Appdev.920/a96590/adg10pck.htm#21958.

С уважением, Роб.

Oracle делает эту проверку.

Следующий код не скомпилируется, поскольку function_public Имеет прагма RNDS, и это называет function_private который читает стол.

PLS-00452: Подпрограмма «Функция_Public» нарушает связанную с ними прагма

Удалить SELECT от function_private И это работает.


CREATE OR REPLACE PACKAGE pragma_test AS
  FUNCTION function_public RETURN VARCHAR2;
  PRAGMA RESTRICT_REFERENCES( function_public, RNDS );
END pragma_test;

CREATE OR REPLACE PACKAGE BODY pragma_test AS
  FUNCTION function_private RETURN VARCHAR2 IS
    v_return dual.dummy%TYPE;
  BEGIN
     SELECT dummy INTO v_return FROM dual;
     RETURN v_return;
  END;
  --
  FUNCTION function_public RETURN VARCHAR2 IS
    v_return dual.dummy%TYPE;
  BEGIN
     RETURN function_private;
  END;
END pragma_test;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top