Oracle
 sql >> Base de données >  >> RDS >> Oracle

Oracle - le curseur utilisant dbms_utility.exec_ddl_statement ne s'exécute pas correctement

DBMS_UTILITY.EXEC_DDL_STATEMENT exécute uniquement DDL de manière fiable. Si vous essayez de l'exécuter avec un bloc PL/SQL, il échouera silencieusement et n'exécutera rien.

Cela peut être démontré en exécutant un bloc PL/SQL qui devrait évidemment échouer. Le code ci-dessous devrait génère ORA-01476: divisor is equal to zero . Mais à la place, il ne fait rien.

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

Utilisez une procédure temporaire pour exécuter un bloc PL/SQL à distance. Créez la procédure avec DBMS_UTILITY.EXEC_DDL_STATEMENT puis appelez-le avec SQL dynamique natif.

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

Je pense que ce comportement est un bug. Oracle devrait renvoyer une erreur au lieu de simplement ne rien faire.

Bienvenue dans l'enfer de la concaténation. Les chaînes deviennent désordonnées lorsqu'elles sont intégrées à 4 niveaux de profondeur. Mais il y a quelques choses que vous pouvez faire pour vous faciliter la vie :

  1. Utilisez un mécanisme de guillemets alternatifs imbriqués. Par exemple, q'[ ... ]' , à l'intérieur d'un q'< ... >' , etc.
  2. Utilisez des chaînes multilignes. Il n'est pas nécessaire de concaténer plusieurs lignes, utilisez simplement une seule chaîne.
  3. Utilisez des espaces supplémentaires pour faciliter l'identification du début et de la fin des chaînes. Lorsque les choses deviennent aussi folles, cela vaut la peine de mettre un délimiteur de chaîne sur une ligne tout seul, afin que tout soit facile à aligner.
  4. Utilisez REPLACE au lieu de la concaténation.

J'ai reformaté une partie de votre code en utilisant ces conseils. Stackoverflow ne comprend pas le mécanisme de guillemets alternatif, mais les chaînes devraient mieux paraître dans un bon éditeur 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;
/