O2SS0343: l'istruzione FORALL con la clausola SAVE EXCEPTION non è supportata (errore)

Questo articolo descrive perché SQL Server Migration Assistant (SSMA) per Oracle non supporta la SAVE EXCEPTIONS clausola FORALL nell'istruzione .

Sfondo

La gestione delle eccezioni è un costrutto del linguaggio di programmazione o un meccanismo progettato per gestire l'occorrenza di eccezioni, condizioni speciali che modificano il normale flusso di esecuzione del programma. In Oracle, l'istruzione consente di eseguire più istruzioni DML in modo molto efficiente e può ripetere una sola istruzione DML, a differenza di un FORALL ciclo per utilizzo FOR generico. SAVE EXCEPTIONS la clausola fa FORALL sì che il ciclo continui anche se alcune operazioni DML hanno esito negativo.

Il modello di eccezione Oracle differisce dal modello SQL Server sia per la generazione di eccezioni che per la gestione delle eccezioni. È preferibile usare il modello di eccezioni SQL Server come parte della migrazione del codice oracle PL/SQL.

Ogni FORALL volta che l'istruzione viene usata con la SAVE EXCEPTIONS clausola , SSMA non la supporta e genera un messaggio di errore.

Esempio

Si consideri l'esempio seguente che usa FORALL un'istruzione con la SAVE EXCEPTIONS clausola .

CREATE TABLE DIVISION_RESULT_Exception (RESULT NUMBER);
/

DECLARE
    TYPE NUMLIST IS TABLE OF NUMBER;
    NUM_TAB NUMLIST := NUMLIST(1000, 0, 100, 0, 10);
    ERRORS NUMBER;
    DML_ERRORS EXCEPTION;
    PRAGMA EXCEPTION_INIT(DML_ERRORS, -24381);
BEGIN
    FORALL i IN NUM_TAB.FIRST..NUM_TAB.LAST
    SAVE EXCEPTIONS
        INSERT INTO DIVISION_RESULT_Exception
        VALUES(1000 / NUM_TAB(i));
EXCEPTION
    WHEN DML_ERRORS THEN
        ERRORS := SQL%BULK_EXCEPTIONS.COUNT;
        DBMS_OUTPUT.PUT_LINE('Number of errors is ' || ERRORS);

        FOR i IN 1..ERRORS LOOP
            DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
            DBMS_OUTPUT.PUT_LINE('SQLERRM: ' ||SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
        END LOOP;
END;

Quando si tenta di convertire il codice precedente in SSMA, viene generato il messaggio di errore seguente:

O2SS0343: l'istruzione FORALL con la clausola SAVE EXCEPTIONS non è supportata

Possibili soluzioni

Una possibile correzione è l'uso del blocco try e catch per gestire le eccezioni in T-SQL usando le funzioni e anziché le ERROR_NUMBER ERROR_MESSAGE funzioni e SQLCODE SQLERRM Oracle. A tale scopo, è necessario aggiornare il codice SQL Server nel modo seguente:

BEGIN
    /* Declaration and initialization of table of input values */
    DECLARE
        @CollectionIndexInt$TYPE varchar(max) = ' TABLE OF DOUBLE'

    DECLARE
        @NUM_TAB dbo.CollectionIndexInt =
            dbo.CollectionIndexInt::[Null]
                .SetType(@CollectionIndexInt$TYPE)
                .AddDouble(1000)
                .AddDouble(0)
                .AddDouble(100)
                .AddDouble(0)
                .AddDouble(10)

    /* Declaration and initialization of other variables */
    DECLARE
        @ERRORS int,
        @DML_ERRORS$exception nvarchar(1000)

    SET @DML_ERRORS$exception = N'ORA-24381%'

    /* Declaration and initialization of temporary variables */
    DECLARE
        @i int

    SET @i = 1

    /* Running the loop for all the input values*/
    WHILE @i <= @NUM_TAB.Count
    BEGIN
        /* Performing the required operation in Try block */
        BEGIN TRY
            INSERT dbo.DIVISION_RESULT_EXCEPTION(RESULT)
            VALUES (1000 / @NUM_TAB.GetDouble(@i))
        END TRY

        /* Catch block to handle exception generated in Try block */
        BEGIN CATCH
            SET @Errors = @Errors + 1;
            PRINT ('SQL error is ' + CONVERT(varchar(20), ERROR_NUMBER()) +
                ':' + CONVERT(varchar(100), ERROR_MESSAGE()))

            PRINT (CONVERT(Varchar(30), ERROR_NUMBER()))
        END CATCH;

        /* Incrementing the loop variable */
        SET @i = @i + 1
    END
END
  • O2SS0282: RAISE senza l'eccezione specificata può essere inserito solo nel gestore eccezioni