Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Oracle - cursor usando dbms_utility.exec_ddl_statement não executando corretamente


DBMS_UTILITY.EXEC_DDL_STATEMENT apenas executa DDL de forma confiável. Se você tentar executá-lo com um bloco PL/SQL, ele falhará silenciosamente e não executará nada.

Isso pode ser demonstrado executando um bloco PL/SQL que obviamente deve falhar. O código abaixo deve gerar ORA-01476: divisor is equal to zero . Mas, em vez disso, não faz nada.
begin
    [email protected](
        q'[declare v_test number; begin v_test := 1/0; end;]'
    );
end;
/

Use um procedimento temporário para executar um bloco PL/SQL remotamente. Crie o procedimento com DBMS_UTILITY.EXEC_DDL_STATEMENT e, em seguida, chame-o com SQL dinâmico nativo.
begin
    [email protected](
        q'[
            create or replace procedure test_procedure
            is
                v_test number;
            begin
                v_test := 1/0;
            end;
        ]'
    );
    execute immediate 'begin [email protected]; end;';
end;
/

RESULTS:

ORA-01476: divisor is equal to zero
ORA-06512: at "JHELLER.TEST_PROCEDURE", line 5
ORA-06512: at line 1
ORA-06512: at line 12

Acho que esse comportamento é um bug. O Oracle deve lançar um erro em vez de simplesmente não fazer nada.

Bem-vindo ao inferno da concatenação. As strings ficam confusas quando estão embutidas em 4 níveis de profundidade. Mas existem algumas coisas que você pode fazer para tornar a vida mais fácil:
  1. Use o mecanismo de cotação alternativa aninhado. Por exemplo, q'[ ... ]' , dentro de um q'< ... >' , etc.
  2. Use strings de várias linhas. Não há necessidade de concatenar várias linhas, basta usar uma única string.
  3. Use espaçamento extra para ajudar a identificar o início e o fim das strings. Quando as coisas ficam tão loucas, vale a pena colocar um delimitador de string em uma linha sozinho, para que tudo seja fácil de alinhar.
  4. Usar REPLACE em vez de concatenação.

Eu reformulei parte do seu código usando essas dicas. O Stackoverflow não entende o mecanismo de cotação alternativo, mas as strings devem ficar melhores em um bom editor Oracle SQL.
declare
    v_db_name varchar2(30) := 'myself';
    sql_update varchar2(32767);
begin
    execute immediate replace(
    q'[
        begin
            [email protected]#DB_NAME#
            (
                q'<
                    create or replace procedure cw_drop_table is
                        sql_drop varchar2(2000);
                    begin
                        sql_drop :=
                        q'{
                            BEGIN
                                EXECUTE IMMEDIATE 'DROP TABLE iSecurity2_dupes_bak';
                            EXCEPTION WHEN OTHERS THEN
                                IF SQLCODE != -942 THEN
                                    NULL;
                                END IF;
                            END;
                        }';
                        execute immediate sql_drop;
                    end;
                >'
            );
            execute immediate 'begin [email protected]#DB_NAME#; end;';
        end;
    ]', '#DB_NAME#', v_db_name);

    sql_update := 'create table iSecurity2_dupes_bak as select * from iSecurity2';
    execute immediate 'begin [email protected]'||v_db_name||
        '(:sql_update);  end;' using sql_update;
    commit;
end;
/