Имена столбцов в пустом Oracle REF CURSOR - PullRequest
4 голосов
/ 01 июля 2011

В PL / SQL я могу использовать вот такой прием, чтобы найти пары имя / значение для каждого столбца в строке из REF CURSOR:

TO_CHAR типа Oracle PL / SQL TABLE

Это потрясающий трюк. Но он не работает, когда REF CURSOR пусто, например, здесь (это только пример. Реальный курсор не выбирается из DUAL):

OPEN cursor FOR SELECT 1 FROM DUAL WHERE 1 = 0;

Имеет ли пустая REF CURSOR информацию об имени / типе столбца?

Ответы [ 2 ]

2 голосов
/ 01 июля 2011

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

1) Пакет Dbms_sql для получения имен столбцов.

2) Метод tbone для извлечения данных.


Процедура

create or replace procedure demo(sqlText in varchar2) is
    refCur sys_refcursor;
    curId  integer;
    cnt    number;
    ret    dbms_sql.desc_tab;
    recTab dbms_sql.desc_tab;
    FORMAT_STRING constant pls_integer := 20;

    procedure printDescTab(desctab in sys.dbms_sql.desc_tab) is
    begin
        -- do what you want with the columns
        for i in 1 .. desctab.count
        loop
            dbms_output.put(lpad(desctab(i).col_name, FORMAT_STRING));
        end loop;
        dbms_output.new_line;
    end printDescTab;

    procedure PrintCur(cv in sys_refcursor) is
    begin
        for c in ( --select t2.COLUMN_VALUE.getrootelement() name,
                  select EXTRACTVALUE(t2.COLUMN_VALUE, 'node()') value
                  from   table(XMLSEQUENCE(cv)) t
                         ,table(XMLSEQUENCE(EXTRACT(COLUMN_VALUE, '/ROW/node()'))) t2)
        loop
            DBMS_OUTPUT.put(lpad(c.VALUE, FORMAT_STRING));
        end loop;
        dbms_output.new_line;
        dbms_output.new_line;
    end;

begin
    dbms_output.put_line('dynamic sql: ' || sqlText);
    curId := dbms_sql.open_cursor();
    --  checks for sql injection to do...
    dbms_sql.parse(curId, sqlText, dbms_sql.native);
    dbms_sql.describe_columns(curId, cnt, recTab);
    printDescTab(recTab);
    dbms_sql.close_cursor(curId);

    open refCur for sqlText;
    PrintCur(refCur);
    close refCur;
exception
    when others then
        if dbms_sql.is_open(curId) then
           dbms_sql.close_cursor(curId);
        end if;
        if refCur%isopen then
            close RefCur;
        end if;
        dbms_output.put_line(sqlcode || ' - ' || sqlerrm);
end demo;

Тест

declare
    sqlText varchar2(2000);
begin
    sqlText := 'select 1 as one, 2 as two  from  dual where 1=0';
    demo(sqlText);
    sqlText   := 'select name, type || chr(13) type' -- chr(13) specific ASCII Carriage return
                ||' from   user_plsql_object_settings'
                ||' where name not like ''%$%'' and  rownum <= 10';      
    demo(sqlText);   
    sqlText := 'select 1 as one, 2 as two  from  dual ';                  
    demo(sqlText);

exception
    when others then
        dbms_output.put_line(sqlcode || ' - ' || sqlerrm);
end;

Результат

dynamic sql: select 1 as one, 2 as two  from  dual where 1=0
                 ONE                 TWO


dynamic sql: select name, type || chr(13) type from   user_plsql_object_settings where name not like '%$%' and  rownum <= 10
                NAME                TYPE
     ADD_JOB_HISTORY          PROCEDURE
    AFT_INS_TEST_TRG            TRIGGER
    BEF_DEL_TEST_TRG            TRIGGER
    BEF_INS_TEST_TRG            TRIGGER
            BETWNSTR           FUNCTION
                BOOL           FUNCTION
    CACHED_FIBONACCI           FUNCTION
               DEBUG            PACKAGE
               DEBUG       PACKAGE BODY
          DEBUG_TEST          PROCEDURE


dynamic sql: select 1 as one, 2 as two  from  dual 
                 ONE                 TWO
                   1                   2
2 голосов
/ 01 июля 2011

AFAIK, нет способа получить метаданные из REF CURSOR напрямую из PL / SQL. Любопытно, что REF CURSOR отображается на Java ResultSet, который можно запрашивать для метаданных, вызывая его метод ResultSet.getMetaData.

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

Другой вариант - преобразовать курсор в числовой курсор, используя DBMS_SQL.TO_CURSOR_NUMBER (только в 11g), который можно запросить для метаданных с пакетом DBMS_SQL .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...