sql >> Base de Datos >  >> RDS >> Oracle

Oracle:el cursor que usa dbms_utility.exec_ddl_statement no se ejecuta correctamente

DBMS_UTILITY.EXEC_DDL_STATEMENT solo ejecuta de manera confiable DDL. Si intenta ejecutarlo con un bloque PL/SQL, fallará silenciosamente y no ejecutará nada.

Esto se puede demostrar ejecutando un bloque PL/SQL que obviamente debería fallar. El siguiente código debería generar ORA-01476: divisor is equal to zero . Pero en cambio no hace nada.

begin
    [email protected](
        q'[declare v_test number; begin v_test := 1/0; end;]'
    );
end;
/

Utilice un procedimiento temporal para ejecutar un bloque PL/SQL de forma remota. Cree el procedimiento con DBMS_UTILITY.EXEC_DDL_STATEMENT y luego llamarlo con 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

Creo que este comportamiento es un error. Oracle debería arrojar un error en lugar de simplemente no hacer nada.

Bienvenido al infierno de la concatenación. Las cuerdas se ensucian cuando están incrustadas a 4 niveles de profundidad. Pero hay algunas cosas que puede hacer para facilitarle la vida:

  1. Utilice un mecanismo de cotización alternativa anidada. Por ejemplo, q'[ ... ]' , dentro de un q'< ... >' , etc.
  2. Utilice cadenas de varias líneas. No es necesario concatenar varias líneas, solo use una sola cadena.
  3. Utilice espacios adicionales para ayudar a identificar el inicio y el final de las cadenas. Cuando las cosas se ponen tan locas, vale la pena poner un delimitador de cadena en una línea solo, para que todo sea fácil de alinear.
  4. Utilice REPLACE en lugar de concatenación.

Volví a formatear parte de su código usando esos consejos. Stackoverflow no comprende el mecanismo de cotización alternativo, pero las cadenas deberían verse mejor en un buen editor de 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;
/