Последняя, не по значимости, а по порядку изложения!
Стоит отметить, что она имеет очень большую практическую ценность, - и, по большому счету, ее очень не хватало.
Если рассмотреть нижеприведенный анонимный блок, выполненный в среде Oracle Database 11g (11.2.0.4):
[oracle@localhost]$ sqlplus rscott/rtiger
SQL*Plus: Release 11.2.0.4.0 Production on Sun May 3 00:07:27 2015
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> DECLARE
b BOOLEAN;
BEGIN
EXECUTE IMMEDIATE
'begin :x := true; end;'
USING
OUT b;
END;
/
OUT b;
*
ERROR at line 7:
ORA-06550: line 7, column 9:
PLS-00457: expressions have to be of SQL types
ORA-06550: line 4, column 3:
PL/SQL: Statement ignored
SQL>
можно увидеть, что ошибка при передаче в динамический блок кода возникает даже когда переменная типа BOOLEAN передается именно в PL/SQL-блок.
Очевидно, что исполняющая среда PL/SQL предполагает, что исполняться будет именно SQL-выражение.
Для того, чтобы обойти это ограничение, приходилось применять вот примерно такой дорогостоящий workaround, связанный с преобразованиями значения из PL/SQL-типа в SQL-тип, и затем обратно:
SQL> create function CharToBoolean(v_pValue in char) return boolean is
begin
if v_pValue = 'Y' then
return true;
end if;
return false;
end;
/
Function created.
SQL> create function BooleanToChar(v_pValue in boolean) return char is
begin
if v_pValue then
return 'Y';
end if;
return 'N';
end;
/
Function created.
SQL> DECLARE
b BOOLEAN;
s char(1);
BEGIN
EXECUTE IMMEDIATE
'begin :x := BooleanToChar(true); end;'
USING
OUT s;
b := CharToBoolean(s);
END;
/
PL/SQL procedure successfully completed.
SQL>
Конечно-же, это усложняло понимание кода и дальнейшее его сопровождение.
Наконец-то, это ограничение снято в Oracle Database 12c, и приведеный выше первоначальный код теперь выполняется без ошибок:
Причем теперь, стало возможным передавать в динамический блок кода не только переменные типа BOOLEAN, но также PL/SQL-записи и PL/SQL-массивы:
[oracle@localhost Desktop]$ sqlplus / as sysdba
SQL*Plus: Release 12.1.0.2.0 Production on Sun May 3 00:10:28 2015
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
SQL> DECLARE
b BOOLEAN;
BEGIN
EXECUTE IMMEDIATE
'begin :x := true; end;'
USING
OUT b;
END;
/
PL/SQL procedure successfully completed.
SQL>
Также поддерживается ситуация, когда передача параметра, имеющего PL/SQL, производится в SQL-выражение:
SQL> create or replace package Account_service is
type
TArrayOfVarchar2 is table of Varchar2(32) index by pls_integer;
end;
/
Package created.
set serveroutput on
DECLARE
v_xArray Account_service.TArrayOfVarchar2;
BEGIN
v_xArray(1) := 'First'; v_xArray(2) := 'Second';
EXECUTE IMMEDIATE
'begin
for v_xIndex in 1..:v_xCount
loop
dbms_output.put_line(:v_pArray(v_xIndex));
end loop;
end;'
USING
IN v_xArray.Count,v_xArray;
END;
/
First
Second
PL/SQL procedure successfully completed.
SQL>
К сожалению, хэш-массивы (PL/SQL-массивы c INDEX BY VARCHAR2) пока не поддерживаются.
SQL> create or replace function printArray(v_pArray in Account_service.TArrayOfVarchar2) return number is
begin
for v_xIndex in 1..v_pArray.count
loop
dbms_output.put_line(v_pArray(v_xIndex));
end loop;
return 1;
end;
/
Function created.
SQL>DECLARE
v_xArray Account_service.TArrayOfVarchar2;
n number;
BEGIN
v_xArray(1) := 'First'; v_xArray(2) := 'Second';
EXECUTE IMMEDIATE
'SELECT printArray(:v_pArray) FROM dual'
INTO
n
USING
IN v_xArray;
END;
/
First
Second
PL/SQL procedure successfully completed.
SQL>
И необходимо помнить, что динамический блок кода не является замыканием (closure), то есть используемый тип должен быть определен на уровне всей схемы - в спецификации пакета.
Поддержка передачи (и возвращения тоже!) в динамический SQL переменных имеющих PL/SQL-типы - это новая впечатляющая возможность Oracle Database 12c, которая позволяет упростить Ваш код, тем самым сделать его более читабельным и легким в сопровождении.
Спасибо большое за разъяснения.
ОтветитьУдалитьСпасибо за статью!
ОтветитьУдалитьОграничение на передачу хэш-массива можно обойти, если завернуть его в обычный nested table, также объявленный на уровне спецификации.
Спасибо за комментарий.
УдалитьМожете, пожалуйста, привести пример?