Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle - Cursor, der dbms_utility.exec_ddl_statement verwendet, wird nicht richtig ausgeführt

DBMS_UTILITY.EXEC_DDL_STATEMENT läuft nur zuverlässig DDL. Wenn Sie versuchen, es mit einem PL/SQL-Block auszuführen, schlägt es stillschweigend fehl und es wird nichts ausgeführt.

Dies kann demonstriert werden, indem ein PL/SQL-Block ausgeführt wird, der offensichtlich fehlschlagen sollte. Der folgende Code sollte generieren ORA-01476: divisor is equal to zero . Aber stattdessen tut es nichts.

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

Verwenden Sie eine temporäre Prozedur, um einen PL/SQL-Block remote auszuführen. Erstellen Sie die Prozedur mit DBMS_UTILITY.EXEC_DDL_STATEMENT und rufen Sie es dann mit nativem dynamischem SQL auf.

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

Ich halte dieses Verhalten für einen Bug. Oracle sollte einen Fehler ausgeben, anstatt einfach nichts zu tun.

Willkommen in der Verkettungshölle. Strings werden unordentlich, wenn sie 4 Ebenen tief eingebettet sind. Aber es gibt ein paar Dinge, die Sie tun können, um das Leben einfacher zu machen:

  1. Verwenden Sie einen verschachtelten alternativen Zitiermechanismus. Beispiel:q'[ ... ]' , innerhalb eines q'< ... >' usw.
  2. Verwenden Sie mehrzeilige Zeichenfolgen. Es ist nicht nötig, mehrere Zeilen zu verketten, verwenden Sie einfach einen einzelnen String.
  3. Verwenden Sie zusätzliche Leerzeichen, um den Anfang und das Ende von Zeichenfolgen zu identifizieren. Wenn die Dinge so verrückt werden, lohnt es sich, ein String-Trennzeichen ganz allein auf eine Zeile zu setzen, damit alles einfach aneinandergereiht werden kann.
  4. Verwenden Sie REPLACE statt Verkettung.

Ich habe einen Teil Ihres Codes mit diesen Tipps neu formatiert. Stackoverflow versteht den alternativen Quoting-Mechanismus nicht, aber die Strings sollten in einem guten Oracle SQL-Editor besser aussehen.

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;
/