15.11.2013

Пример реализации Virtual Private Database (VPD)

Cуть технологии в том, что к запросу данных из защищенной таблицы или представления динамически добавляется предикат. Предикат формируется в заранее определенном методе.
Создадим тестовую таблицу с данными:
create table apps.test_users_all (
       id    number not null,
       name  varchar2(255)
       )
/   
create or replace synonym apps.test_users for apps.test_users_all
/
insert into apps.test_users_all (id, name)
values (1, user)
/
insert into apps.test_users_all (id, name)
values (2, 'SCOTT')
/
insert into apps.test_users_all (id, name)
values (3, 'TIGER')
/
Обратимся за данными к синониму:
SQL> select * from test_users
  2  /
        ID NAME
        ---------- -----------
         1 APPS
         2 SCOTT
         3 TIGER
Настроим ограничение так, чтобы отображались только строки, в которых name = user. В данном случае этому ограничению соответствует одна строка с ID = 1.
Создадим пакет с функциями, реализующими предикат:
create or replace package XXTEST_VPD is
 function users_security (obj_schema varchar2, 
                          obj_name   varchar2) return varchar2; 
end XXTEST_VPD
/
create or replace package body XXTEST_VPD is
 function users_security (obj_schema varchar2, 
                          obj_name   varchar2) return varchar2
 is
 begin
   return 'name = user';
 end users_security; 
end XXTEST_VPD
/ 
Применим политику безопасности:
declare
  l_tmp number;
begin
  begin
    select 1
     into l_tmp
     from dual
     where not exists 
     (select null
            from dba_policies p
            where p.object_name = 'TEST_USERS');
  exception
    when NO_DATA_FOUND then
      dbms_rls.drop_policy(object_schema => 'APPS',
                           object_name   => 'TEST_USERS',
                           policy_name   => 'USERS_SECURITY');
  end;
  dbms_rls.add_policy(object_schema   => 'APPS',
                      object_name     => 'TEST_USERS',
                      policy_name     => 'USERS_SECURITY',
                      policy_function => 'XXTEST_VPD.USERS_SECURITY',
                      function_schema => 'APPS');
end; 
Здесь мы применяем ограничение на синоним TEST_USERS. Пробуем выполнить запрос к защищенной таблице:
SQL> select * from test_users
  2  /
        ID NAME
        ---------- ----------
         1 APPS
Мы видим, что синоним ограничен по определенному нами предикату.

09.09.2013

Канкарент на основе Java-класса

По шагам:
1. Создаем наш класс
package oracle.apps.test;

import java.io.IOException;

import java.io.PrintWriter;
import java.io.StringWriter;

import java.lang.reflect.InvocationTargetException;

import java.sql.Connection;
import java.sql.SQLException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;

import oracle.apps.fnd.common.Message;
import oracle.apps.fnd.cp.request.CpContext;
import oracle.apps.fnd.cp.request.JavaConcurrentProgram;
import oracle.apps.fnd.cp.request.LogFile;
import oracle.apps.fnd.cp.request.ReqCompletion;

public class MyJavaTest implements JavaConcurrentProgram {
    public static final String APPLICATION_SHORT_NAME = "XXXX";
    public static final String CONCURRENT_PROGRAM_NAME = "MY_CONC_PROGRAM";
    
    private Connection connection;
    private int requestId;
    private LogFile logFile;
    private ReqCompletion reqCompletion;

    public void initialize(CpContext cpContext) throws SQLException, 
                                                       XMLParseException, 
                                                       SAXException, 
                                                       IOException, 
                                                       InstantiationException, 
                                                       IllegalAccessException, 
                                                       ClassNotFoundException, 
                                                       NoSuchMethodException, 
                                                       InvocationTargetException {
        connection = cpContext.getJDBCConnection();
        requestId = cpContext.getReqDetails().getRequestId();
        logFile = cpContext.getLogFile();
        reqCompletion = cpContext.getReqCompletion();

        Enumeration params = cpContext.getReqDetails().getParaInfo().elements();
        String Value = (String)params.nextElement();
        int fileId = Integer.parseInt(Value);
        // some code
    }

    public void runProgram(CpContext cpContext) {
        try {
            initialize(cpContext);
            // some code
            connection.commit();

            // успешное заверщение канкарента
            Message normComplMessage = new Message("FND", "CONC-CP SUCCESSFUL TERMINATION");
            reqCompletion.setCompletion(ReqCompletion.NORMAL, normComplMessage.getMessageText(cpContext.getResourceStore()));
        } catch (Exception e) {
            reqCompletion.setCompletion(ReqCompletion.ERROR, e.getMessage());
            StringWriter errStringWriter = new StringWriter();
            PrintWriter errPrintWriter = new PrintWriter(errStringWriter, true);
            e.printStackTrace(errPrintWriter);
            logFile.writeln(errStringWriter.toString(), LogFile.ERROR);
        } finally {
            cpContext.releaseJDBCConnection();
        }
    }

}
2. Создаем канкарент


05.09.2013

Пример типа с коллекциями


Например, нужно реализовать настройку в виде нескольких списков (списки товаров и торговых точек, где применяется акция). ID товаров и точек будем хранить в таблице со структурой (Тип сущности {Товар, Точка}, ID). С помощью приведенной ниже методики мы можем хранить оба списка в одном объекте и легко к ним обращаться как к коллекциям. Алгоритм сбора данных инкапсулируется в самом объекте, а выполняется в конструкторе, что позволяет выполнить сбор данных одной строкой кода.
Итак:
Тип строки
create or replace type MY_COLLECTION_ROW is
       object(
          value varchar2(150)
       );
Табличный тип
create or replace type MY_COLLECTION is
       table of MY_COLLECTION_ROW 
Новый тип, содержащий объекты типа MY_COLLECTION
create or replace type MY_COLLECTION_TYPE as object (

       GOODS_LIST                MY_COLLECTION,
       SHOPS_LIST                MY_COLLECTION,

       constructor function MY_COLLECTION_TYPE return self as result,

       member      procedure init_SHOPS_LIST_collection(p_list in out MY_COLLECTION),
       member      procedure init_GOODS_LIST_collection(p_list in out MY_COLLECTION)
)
create or replace type body MY_COLLECTION_TYPE is

       constructor function MY_COLLECTION_TYPE return self as result
       is
       begin
          GOODS_LIST                := new MY_COLLECTION(null); 
          SHOPS_LIST                := new MY_COLLECTION(null);

          init_GOODS_LIST_collection(p_list => GOODS_LIST);
          init_SHOPS_LIST_collection(p_list => SHOPS_LIST);
         return;
       end MY_COLLECTION_TYPE;
       --
       member      procedure init_GOODS_LIST_collection(p_list in out MY_COLLECTION)
       is
         l_line varchar2(150);
         cursor cur is
                    select rownum
                           from dual
                           connect by rownum < 10;
       begin
         open cur;
         loop
           fetch cur into l_line;
           exit when cur%NOTFOUND;
                 p_list.extend;
                 p_list(p_list.last) := MY_COLLECTION_ROW(l_line);
           end loop;
           close cur;
       end init_GOODS_LIST_collection;
       --
       member      procedure init_SHOPS_LIST_collection(p_list in out MY_COLLECTION)
       is
         l_line varchar2(150);
         cursor cur is
                    select rownum
                           from dual
                           connect by rownum < 10;
       begin
         open cur;
         loop
           fetch cur into l_line;
           exit when cur%NOTFOUND;
                 p_list.extend;
                 p_list(p_list.last) := MY_COLLECTION_ROW(l_line);
           end loop;
           close cur;
       end init_SHOPS_LIST_collection;
end;
Обращаемся к данным
declare 
  l_options         MY_COLLECTION_TYPE;
  cursor cur(obj MY_COLLECTION) is select * from table(obj);
  l_tmp_coll        varchar2(150);           
begin
  l_options := new MY_COLLECTION_TYPE();
  open cur(obj => l_options.GOODS_LIST);
  loop
        fetch cur into l_tmp_coll;
        exit when cur%NOTFOUND;
           dbms_output.put_line(l_tmp_coll);
  end loop;
  close cur;
end;

08.07.2013

Ошибка ORA-08103 и партиционирование

Причины появления ошибки ORA-08103: object no longer exists при работе с партиционированными таблицами.

22.06.2013

ООП на PL/SQL: введение

В который раз не знаю, что писать в заголовок поста. Ну, давай начнем так: "реализация ООП впервые появилась в РСУБД Oracle 9g".

20.05.2013

Колонки с однотипными флагами в hGrid

На пути отображения структуры вида <Attribute, AttributeValue> в транспонированном виде с помощью hGrid возникла определенная сложность. Ниже описана методика её преодоления.

10.04.2013

OAF: Реализация механизма связывания страниц train

Последовательность действий для реализации train

26.03.2013

OAF: Атрибут VO как хинт к бину image

Возникла задача присвоить значкам типа image различные всплывающие подсказки из ViewObject. Один из вариантов реализации  - через JavaScript.

11.03.2013

Использование JavaScript в OAF

Примеры использования JS в Oracle Applications Framework. Вызов JAVA-методов из кода JavaScript

14.02.2013

Динамическое условие required в параметре канкарента

Если выбрали А = 1, то должны заполнить параметр B,
Если выбрали А != 1, то параметр В должен быть неактивен.

13.02.2013

XML Publisher: кое-что о больших отчетах

Почему стоит отказаться от гигантских отчетов.

06.02.2013

Трассировка concurrent-процесса

Получение трассы с последующим чтением с помощью TKPROF

22.01.2013

Мелкий траблшутинг: задвоение в SYS_REFCURSOR

Бывает, звезды сложатся так, что последняя запись задваивается.

17.01.2013

Адресация на элементы дерева hGrid

Построить дерево hGrid с определенного элемента можно с помощью метода OAHGridBean.setInitialFocusPath(intArr), где intArr - массив элементов типа int. Как его, массив, формировать?

06.01.2013

Установка и настройка Oracle 11g под RHEL 5

Цель: установить и настроить Oracle 11g под RHEL 5 (OEL) x64, создать пользователя, подключиться к экземпляру с windows-машины и создать тестовую таблицу emp.