Общая процедура, которая может выполнять любую процедуру/функцию

ввод
Имя пакета (IN)
имя процедуры (или имя функции) (IN)
Таблица, проиндексированная целым числом, будет содержать значения, которые будут использоваться для выполнения процедуры (ВХОД/ВЫХОД).

Например,
предположим, что мы хотим выполнить описанную ниже процедуру

utils.get_emp_num(emp_name IN VARCHAR
                  emp_last_name IN VARCHAR
                  emp_num OUT NUMBER
                  result  OUT VARCHAR);

Процедура, которую мы создадим, будет иметь в качестве входных данных:

package_name = utils
procedure_name = get_emp_num
table = T[1] -> name
        T[2] -> lastname
        T[3] -> 0   (any value) 
        T[4] -> N   (any value)

run_procedure(package_name,
              procedure_name,
              table)

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

table =  T[1] -> name
         T[2] -> lastname
         T[3] -> 78734 (new value)
         T[4] -> F     (new value)

любая мысль?


person Messady    schedule 19.09.2013    source источник
comment
Похоже, вы перешли к решению, когда должны были описать свою проблему. Я не могу представить, что это хороший способ выполнить что-либо... так в чем ваша проблема?   -  person Ben    schedule 20.09.2013
comment
Сценарий Lua вызовет функцию Pro*c, которая выполнит процедуру и вернет таблицу данных (результат) функции Lua для дальнейшего использования. Я не нашел лучшего способа получить результат процедуры из Lua-скрипта.   -  person Messady    schedule 20.09.2013
comment
Да, но нужно ли вам вызывать каждую процедуру, используя один и тот же вызов. Возможно, было бы более нормальным изменить ваш вызов Pro*C в зависимости от процедуры, которую вам нужно вызвать, а не изменять базу данных, чтобы вызывать все одинаково.   -  person Ben    schedule 20.09.2013
comment
Proc является компилируемым языком, Proc будет содержать основную обработку для всех пользователей (одинаковую), а скрипт Lua будет использоваться как плагин (зависит от пользователя, он будет отличаться ), сценарий будет представлять собой простой файл .Lua (не двоичный) и будет вызываться путем простого указания PATH программе Proc. Это делается для того, чтобы не предоставлять каждому пользователю определенную версию кода Proc и позволить скрипту Lua выполнять любую процедуру/функцию без изменения кода Pro*C.   -  person Messady    schedule 20.09.2013


Ответы (2)


Вы можете добиться этого с помощью EXECUTE IMMEDIATE. По сути, вы создаете оператор SQL следующего вида:

sql := 'BEGIN utils.get_emp_num(:1, :2, :3, :4); END;';

Затем вы выполняете его:

EXECUTE IMMEDIATE sql USING t(1), t(2), OUT t(3), OUT t(4);

Теперь начинается сложная часть: для каждого количества параметров и комбинаций IN/OUT вам нужен отдельный оператор EXECUTE IMMEDIATE. А чтобы выяснить количество параметров и их направление, нужно сначала запросить таблицу ALL_ARGUMENTS.

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

И следующее, что вы должны учитывать: элементы используемой вами таблицы T будут иметь тип: VARCHAR, NUMBER и т. д. Таким образом, текущая смесь, в которой у вас есть и числа, и строки, не будет работать.

Кстати: зачем вам такой механизм динамического вызова?

person Codo    schedule 19.09.2013
comment
Пользователь может написать свой собственный Lua-скрипт и запросить данные из БД, Lua вызовет функцию PRO*C, которая выполнит процедуру и вернет результат (таблицу) в Lua-скрипт. Меня попросили сделать то же самое, создав процедуру, которая позволяет выполнять любой запрос, это было легко с использованием пакета DBMS_SQL, но с процедурой/функцией я обнаружил, что это более сложно. - person Messady; 20.09.2013

Получить из таблицы all_arguments имя_аргумента, тип_данных, входной_выход и позицию

Создайте блок PLSQL

DECLARE
    loop over argument_name and create the declare section
    argument_name data_type if in_out <> OUT then := VALUE OF THE INPUT otherwise NULL
BEGIN

--In the case of function create an additional argument 
function_var:= package_name.procedure_name( loop over argument_name);

--use a table of any_data, declare it as global in the package

if function then
    package_name.ad_table.EXTEND;
    package_name.ad_table(package_name.ad_table.LAST):= function_var;
end if

--loop over argument_name IF IN_OUT <> IN
package_name.ad_table.EXTEND;
package_name.ad_table(package_name.ad_table.LAST):= 

if data_type = VARCHAR2 then := ConvertVarchar2(argument_name)
else if NUMBER then ConvertNumber 
else if DATE then ConvertDate
...

END;

Результат сохраняется в таблице. Чтобы получить значение, используйте функции Access*

person Messady    schedule 10.10.2013