Мне нужно написать функцию PLSQL, которая должна работать как с входными данными CLOB, так и с VARCHAR2 и возвращать CLOB или VARCHAR2 соответственно. Но функциональность, реализованная функцией, одинакова (она выполняет ряд вызовов REGEXP_REPLACE) независимо от типа ввода. Можно ли написать функцию, которая может одновременно принимать и CLOB, и VARCHAR2 и возвращать полученный тип? Я хочу избежать написания двух очень похожих функций, дублирующих код.
Моя первая функция выглядит примерно так:
FUNCTION Test(i_text CLOB) RETURN CLOB IS
v_text CLOB;
BEGIN
v_text := i_text;
... a series of REGEXP_REPLACE calls like v_text := REGEXP_REPLACE(v_text,...)
RETURN v_text
END;
И моя другая функция:
FUNCTION Test(i_text VARCHAR2) RETURN VARCHAR2 IS
v_text VARCHAR2;
BEGIN
v_text := i_text;
... a series of REGEXP_REPLACE calls like v_text := REGEXP_REPLACE(v_text,...)
RETURN v_text
END;
Поскольку внутри функций есть большое количество вызовов REGEXP_REPLACE, я бы предпочел иметь только одну функцию - если это возможно.
Входные данные CLOB могут иметь значительный размер, поэтому преобразование CLOB в VARCHAR2 перед вызовом функции невозможно.
Даже REGEXP_REPLACE работает с различными входными данными, такими как CHAR, VARCHAR2, NCHAR, NVARCHAR2, CLOB или NCLOB. Вот почему я надеюсь, что есть решение для этой потребности.
Вы можете создать пакет с двумя функциями Test
(Перегрузка в пакетах), такими как
CREATE OR REPLACE PACKAGE Pkg_Test IS
FUNCTION Test (i_text VARCHAR2) RETURN VARCHAR2
FUNCTION Test (i_text CLOB) RETURN CLOB;
END;
/
CREATE OR REPLACE PACKAGE BODY Pkg_Test IS
FUNCTION Test (i_text VARCHAR2) RETURN VARCHAR2 IS
val VARCHAR2;
BEGIN
SELECT ...
INTO val
FROM tab t
WHERE t.col1 = i_text;
RETURN val;
END;
FUNCTION Test (i_text CLOB) RETURN CLOB IS
val CLOB;
BEGIN
SELECT ....
INTO val
FROM tab t
WHERE t.col2 = i_text;
RETURN val;
END;
END;
/
и вызовите с тем же именем, что и ниже, независимо от типа данных параметра
BEGIN
:result := Pkg_Test.test(:prm);
END;
/
Да, я знаю о перегрузке процедур, этим сейчас и занимаюсь. Но даже в этом случае мне придется дублировать длинную серию вызовов (REGEXP_REPLACE или что-то еще). Потому что даже в этом случае у вас есть две отдельные функции с двумя отдельными телами. И оба будут иметь одинаковый большой набор вызовов внутри тела. Это то, чего я пытаюсь как-то избежать.
@BarbarosOzhan прав, что вам нужен пакет, чтобы получить возможность перегрузки. Но дублировать код не нужно. Хотя вы правы в том, что преобразование CLOB в VARCHAR2 невозможно, ничто не мешает вам преобразовать VARCHAR2 в CLOB. Затем, если вы не увеличиваете длину регулярных выражений, преобразуйте результат обратно в VARCHAR2. Затем функция, обрабатывающая varchar2, становится просто оболочкой, которая просто обрабатывает преобразования.
create or replace package test_pkg is
function test(i_text clob) return clob;
function test(i_text varchar2) return varchar2;
end test_pkg;
/
create or replace package body test_pkg is
function test(i_text clob) return clob is
v_text clob;
begin
v_text := i_text;
--...
return v_text;
end test;
function test(i_text varchar2) return varchar2 is
v_text clob;
v_res varchar2(32767); -- 4000 is actually used in SQL statement
begin
v_text := cast(i_text as clob);
v_res := cast (test(v_text) as varchar2);
return v_res;
end test;
end test_pkg;
Ваша подпрограмма вызова должна ожидать и обрабатывать исключение «ORA-06502: PL/SQL: числовая ошибка или ошибка значения: буфер символьной строки слишком мал»
Спасибо @Belayer. Это здорово, я не знал, что кастинг из VARCHAR2 в CLOB так прост. Это решило мою проблему.
Рад, что смог помочь. Я тоже этого не знал - никогда этого не делал. Но это казалось логичным, в конце концов, CLOB — это очень длинный VARCHAR2. Много лет назад я изучил очень полезную технику, она называется «выдача желаемого за действительное». Это происходит из психологии, но для разработки это в основном переводится как «Хотел бы я сделать X», поэтому напишите фрагмент кода, который делает X. Если он работает, вы можете это сделать; если не двигаться дальше.
Мне нравится такое позитивное мышление :)
Имейте в виду, что операции регулярных выражений будут очень медленными на clobs. Использование встроенных возможностей, предоставляемых DBMS_LOB, может быть более эффективным (в зависимости от того, как вы хотите манипулировать входной строкой). Учитывая, что вам следует подумать, перевешивают ли преимущества производительности двух разных функций накладные расходы на обслуживание.