2015-10-16 27 views
10

per fare una lunga storia breve mi propongo di discutere il codice che vedi qui sotto.Oracle 12 ha problemi con i tipi di raccolta locali in SQL?

Quando si esegue esso:

  • Oracle 11 compilatore genera

    "PLS-00306: numero errato o tipi di argomenti suggerimenti in chiamata a 'PIPE_TABLE'"

    "PLS -00642: Tipi di raccolta locali non consentiti nell'istruzione SQL "

  • Oracle 12 compila il seguente pacchetto con tali avvertimenti, ma abbiamo una sorpresa in runtime

    durante l'esecuzione del blocco anonimo come è - tutto va bene (potremmo tubo di alcune righe nella funzione pipe_table - doesn 't effetto)

    ora diamo il commento dalla riga con hello; o mettere lì una chiamata a qualsiasi procedura, ed eseguire il blocco anonumous cambiato di nuovo otteniamo "oRA-22163: la mano sinistra e collezioni lato destro non sono dello stesso tipo"

E la domanda è: Ha Oracle 12 permette tipi di raccolta locali in SQL? Se sì allora cosa c'è di sbagliato con il codice di PACKAGE buggy_report?

CREATE OR REPLACE PACKAGE buggy_report IS 

    SUBTYPE t_id IS NUMBER(10); 
    TYPE t_id_table IS TABLE OF t_id; 

    TYPE t_info_rec IS RECORD (first NUMBER); 
    TYPE t_info_table IS TABLE OF t_info_rec; 
    TYPE t_info_cur IS REF CURSOR RETURN t_info_rec; 

    FUNCTION pipe_table(p t_id_table) RETURN t_info_table PIPELINED; 

    FUNCTION get_cursor RETURN t_info_cur; 

END buggy_report; 
/

CREATE OR REPLACE PACKAGE BODY buggy_report IS 

    FUNCTION pipe_table(p t_id_table) RETURN t_info_table PIPELINED IS 
    l_table t_id_table; 
    BEGIN 
     l_table := p; 
    END; 

    FUNCTION get_cursor RETURN t_info_cur IS 
    l_table t_id_table; 
    l_result t_info_cur; 
    BEGIN 

     OPEN l_result FOR SELECT * FROM TABLE (buggy_report.pipe_table(l_table)); 

     RETURN l_result; 
    END; 
END; 
/

DECLARE 
    l_cur buggy_report.t_info_cur; 
    l_rec l_cur%ROWTYPE; 
    PROCEDURE hello IS BEGIN NULL; END; 
BEGIN 

    l_cur := buggy_report.get_cursor(); 

    -- hello; 

    LOOP 
    FETCH l_cur INTO l_rec; 
    EXIT WHEN l_cur%NOTFOUND; 
    END LOOP; 

    CLOSE l_cur; 

    dbms_output.put_line('success'); 
END; 
/

risposta

0

In ulteriori esperimenti abbiamo scoperto che i problemi sono ancora più profondi di quanto si pensi.

Ad esempio, vari elementi utilizzati nel pacchetto buggy_report è possibile ottenere ORA-03113: end-of-file on communication channel durante l'esecuzione dello script (nella domanda). Può essere fatto cambiando il tipo di t_id_table a VARRAY o TABLE .. INDEX BY ... Ci sono molti modi e variazioni che ci portano a diverse eccezioni, che sono fuori tema per questo post.

L'altra cosa interessante è che il tempo di compilazione delle specifiche del pacchetto buggy_report può richiedere fino a 25 secondi, quando normalmente occorrono circa 0,05 secondi. Posso sicuramente dire che dipende dalla presenza del parametro TYPE t_id_table nella dichiarazione della funzione pipe_table e che la "compilazione da molto tempo" si verifica nel 40% dei casi di installazione. Quindi sembra che il problema con local collection types in SQL compaia latente durante la compilazione.

Quindi vediamo che Oracle 12.1.0.2 ha ovviamente un bug nella realizzazione dell'utilizzo di tipi di raccolta locali in SQL.

Gli esempi minimi per ottenere ORA-22163 e ORA-03113 seguono. Lì assumiamo lo stesso pacchetto buggy_report come nella domanda.

-- produces 'ORA-03113: end-of-file on communication channel' 
DECLARE 
    l_cur buggy_report.t_info_cur; 

    FUNCTION get_it RETURN buggy_report.t_info_cur IS BEGIN RETURN buggy_report.get_cursor(); END;  
BEGIN 
    l_cur := get_it(); 

    dbms_output.put_line(''); 
END; 
/

-- produces 'ORA-22163: left hand and right hand side collections are not of same type' 
DECLARE 
    l_cur buggy_report.t_info_cur; 

    PROCEDURE hello IS BEGIN NULL; END; 
BEGIN 
    l_cur := buggy_report.get_cursor; 

    -- comment `hello` and exception disappears 
    hello; 

    CLOSE l_cur; 
END; 
/
+0

Gli esempi includono due funzionalità Oracle insolite: raccolte locali e funzioni pipeline. Potrebbe essere altrettanto valido dire "Oracle ha un bug con le funzioni pipeline". Nella mia esperienza, le implementazioni che utilizzano le funzioni pipeline di solito avranno comunque problemi; a causa di bug Oracle o a causa delle limitazioni dell'elaborazione riga per fila. –

0

Sì, in Oracle 12c è possibile utilizzare i tipi di raccolta locali in SQL.

Documentazione Database New Features Guide dice:

PL/SQL specifiche dei tipi di dati ammessi Dall'altra parte del PL/SQL-to-SQL Interface

L'operatore tavolo possono ora essere utilizzati in PL/SQL programma su una raccolta il cui tipo di dati è dichiarato in PL/SQL. Ciò consente inoltre al tipo di dati di essere un array associativo PL/SQL. (Nelle versioni precedenti, il tipo di dati della raccolta doveva essere dichiarato a livello di schema.)

Tuttavia, non so perché il tuo codice non funziona, forse questa nuova funzionalità ha ancora un bug.

0

I giocherellava intorno al vostro esempio. Il trucco come Oracle 12c può usare collezioni PL/SQL in istruzioni SQL è che Oracle crea tipi di oggetti dello schema surrogate con attributi di tipo SQL compatibile e utilizza questi tipi di surrogati in una query. Il tuo caso sembra un insetto. Ho tracciato l'esecuzione e i tipi surrogati vengono creati una sola volta se non esistono. Quindi il tipo effettivo non cambia né ricompila (non so se la ricompilazione implicita viene eseguita usando l'istruzione ALTER) durante l'esecuzione della funzione pipeline. E il problema si verifica solo se si utilizza il parametro p nella funzione pipe_table. Se non si chiama l_table := p;, il codice viene eseguito correttamente anche con la chiamata di metodo abilitata.

+0

Per "problema si verifica solo se si utilizza il parametro p" si intende "Non userò il parametro p"? Pensa, perché lo passo anche lì - volevo usarlo. Scavando sul tavolo 'p 'ho dovuto affrontare un problema (forse anche tu l'hai trovato). E questo asserimento 'l_table: = p;' è solo il codice minimale che riproduce il bug. Ora conosco due cose: 1. L'esempio senza trucchi mostra l'uso più semplice della "nuova funzionalità" dichiarata in v12.1.0.1; 2. Il codice non funziona come previsto anche su v12.1.0.2. Voglio credere che gli sviluppatori Oracle testano il loro codice molto più di me. Quindi perché succede? – diziaq

+0

No, era solo un'osservazione. Puoi invece creare il tipo di schema ('CREATE O REPLACE TYPE t_id_table IS TABLE OF NUMBER (10)'), quindi sembra funzionare. – Husqvik