PIPELINED & ORA-21700

derwulf13
Дата: 01.12.2012 16:09:53
Доброго всем дня. Подскажите пож. кто знает и сталкивался.

вопрос значит следующий.
имеем пакет в спецификации которого объявлено следующее

 
TYPE RESULT_TYPE IS RECORD (REPORT_CODE     VARCHAR2(15),
                                           REPORT_NAME     VARCHAR2(255)
                                          );

TYPE RESULT_NT IS TABLE OF RESULT_TYPE;

RESULT_ RESULT_NT;

FUNCTION GET_RESULT RETURN RESULT_NT PIPELINED;

FUNCTION COLLECTION_DATA (P_DATE IN TIMESTAMP,P_FORM IN NUMBER DEFAULT 0, P_QRS_CURSOR OUT sys_refcursor) RETURN NUMBER;


в теле пакета

    FUNCTION GET_RESULT RETURN RESULT_NT PIPELINED
    IS
        l_row  RESULT_TYPE;
        
    BEGIN
        
        IF RESULT_ IS NOT EMPTY
        THEN 
            
            FOR i IN RESULT_.FIRST .. RESULT_.LAST
            LOOP
                SELECT RESULT_(i).REPORT_CODE,RESULT_(i).REPORT_NAME
                INTO l_row
                FROM DUAL;

                PIPE ROW (l_row);
            END LOOP;
         END IF;   

        RETURN;
    END;


функция COLLECTION_DATA заполняет RESULT_ после чего вызывается COLLECTION_DATA и передает это все в курсор

 OPEN P_QRS_CURSOR FOR
 SELECT REPORT_CODE,REPORT_NAME
            FROM TABLE(GET_RESULT)
  ORDER BY REPORT_CODE;


все замечательно работает и все бы хорошо, но есть одно но ! в функции COLLECTION_DATA есть переменная P_FORM в зависимости от которой данные будут разные, притом их желательно было бы использовать в запросе одновременно. в связи с этим были произведены следующие модификации.

спецификация

 FUNCTION GET_RESULT (p_STREAM IN RESULT_NT) RETURN RESULT_NT PIPELINED;


тело

    FUNCTION GET_RESULT (p_STREAM IN RESULT_NT) RETURN RESULT_NT PIPELINED
    IS
        l_row  RESULT_TYPE;

    BEGIN
        
        IF p_STREAM IS NOT EMPTY
        THEN 
            
            FOR i IN p_STREAM.FIRST .. p_STREAM.LAST
            LOOP
                SELECT p_STREAM(i).REPORT_CODE,p_STREAM(i).REPORT_NAME
                INTO l_row
                FROM DUAL;

                PIPE ROW (l_row);
            END LOOP;
         END IF;   

        RETURN;
    END;


OPEN P_QRS_CURSOR FOR
SELECT REPORT_CODE,REPORT_NAME
           FROM TABLE(GET_RESULT (p_STREAM=>RESULT_))
ORDER BY REPORT_CODE;

в общем сделано это для того чтобы
вызовом COLLECTION_DATA (P_FORM=>0) заполнить RESULT_0 , вызовом COLLECTION_DATA (P_FORM=>1) заполнить RESULT_1 , объявленные как RESULT_NT

а затем
select  t1.REPORT_CODE,t1.REPORT_NAME,t2.REPORT_CODE,t2.REPORT_NAME
FROM TABLE(GET_RESULT (p_STREAM=>RESULT_0)) t1
JOIN TABLE(GET_RESULT (p_STREAM=>RESULT_1)) t2 on t2.REPORT_CODE=t1.REPORT_CODE


Но, при открытии курсора получаем ORA-21700
-2-
Дата: 01.12.2012 16:14:40
derwulf13,

ты почитал, к аргументы какого типа поддерживаются оператором is [not] empty? или копипастил интернет через слово.
derwulf13
Дата: 01.12.2012 16:29:47
уважаемый -2-, мне кажется Ваш вопрос не по существу, т.к. в обоих случаях RESULT_ и p_STREAM одного типа RESULT_NT (nested table)

забыл добавить. в обоих случаях код компилится, но первый отрабатывает, а второй - нет.
-2-
Дата: 01.12.2012 16:44:04
derwulf13
одного типа
одного, но не того, что работает с sql-оператором. да вообще познания надо отлаживать на примерах из книжек, а не публиковать говнокод на форумах.

derwulf13
но первый отрабатывает, а второй - нет.
а кто из них второй?
derwulf13
Дата: 01.12.2012 16:49:44
-2-,
вопрос был задан, и если бы внимательно почитал , то понял бы где первый вариант, а где второй
проще конечно "пальцы гнуть"... когда по существу сказать нечего.
SY
Дата: 01.12.2012 17:42:30
derwulf13,

Вообще непонятно зачем запихивать данные в коллекцию а затем делать pipelined из коллекции. Да и уровень кода ещё тот:

            FOR i IN RESULT_.FIRST .. RESULT_.LAST
            LOOP
                SELECT RESULT_(i).REPORT_CODE,RESULT_(i).REPORT_NAME
                INTO l_row
                FROM DUAL;

                PIPE ROW (l_row);
            END LOOP;


не что иное как:

            FOR i IN RESULT_.FIRST .. RESULT_.LAST
            LOOP
                PIPE ROW (RESULT_(i));
            END LOOP;


SY.
derwulf13
Дата: 01.12.2012 18:31:33
SY
derwulf13,

Вообще непонятно зачем запихивать данные в коллекцию а затем делать pipelined из коллекции. Да и уровень кода ещё тот:

            FOR i IN RESULT_.FIRST .. RESULT_.LAST
            LOOP
                SELECT RESULT_(i).REPORT_CODE,RESULT_(i).REPORT_NAME
                INTO l_row
                FROM DUAL;

                PIPE ROW (l_row);
            END LOOP;


не что иное как:

            FOR i IN RESULT_.FIRST .. RESULT_.LAST
            LOOP
                PIPE ROW (RESULT_(i));
            END LOOP;


SY.


Спасибо за поправку. Можно и без PIPELINED, но TABLE(CAST(RESULT_ AS RESULT_NT)) прокатывает только когда тип на уровне схемы создан.
Серафимный Шестикрыл
Дата: 01.12.2012 20:28:09
derwulf13
Спасибо за поправку. Можно и без PIPELINED, но TABLE(CAST(RESULT_ AS RESULT_NT)) прокатывает только когда тип на уровне схемы создан.


Ты страшно удивишься, но когда ты используешь тип таким образом в пакете,
Oracle неявно создает соответствующий тип "на уровне схемы".
Так что сие иллюзия есмь.