EXECUTE IMMEDIATE DROP FUNCTION 导致 Oracle SQL Developer 挂起

EXECUTE IMMEDIATE DROP FUNCTION causes Oracle SQL Developer to hang

我有以下脚本。但是每当我包含 EXECUTE IMMEDIATE 'DROP FUNCTION table_exists'; 行时,SQL 开发人员似乎挂起。知道是什么原因造成的吗?

如果我取消任务,脚本 运行 会完成但不会删除该功能。但是,我可以简单地 运行 DROP FUNCTION table_exists; 在我的数据库连接中,它会丢弃 table 没问题。是 PL/SQL 的怪癖吗?

CREATE OR REPLACE FUNCTION table_exists(table_name VARCHAR2)
RETURN BOOLEAN
AS
    table_count NUMBER := 0;
    exists_sql VARCHAR2(255);
BEGIN
    exists_sql := 'SELECT COUNT(1) FROM tab WHERE tname = :tab_name';
    EXECUTE IMMEDIATE exists_sql INTO table_count USING table_name;

    RETURN table_count > 0;
END;
/

DECLARE
    TYPE tables_array IS VARRAY(2) OF VARCHAR2(25); -- change varray size if running on dev
    tables tables_array;
BEGIN
    tables := tables_array(
        'FOO',
        'BAR'
    );

    FOR table_element IN 1 .. tables.COUNT LOOP
        DBMS_OUTPUT.PUT_LINE('Backing up data for ' || tables(table_element));
        IF table_exists(tables(table_element) || '_ORIGINAL') THEN
            DBMS_OUTPUT.PUT_LINE(tables(table_element) || '_ORIGINAL already exists');
        ELSE
            EXECUTE IMMEDIATE 'CREATE TABLE ' || tables(table_element) || '_ORIGINAL AS SELECT * FROM '|| tables(table_element);
        END IF;
    END LOOP;

    EXECUTE IMMEDIATE 'DROP FUNCTION table_exists';

    COMMIT;

    EXCEPTION
        WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE ('Unexpected error: ' || sqlerrm);
    ROLLBACK;
    RAISE;
END;
/

Oracle 不会删除在此过程中使用的函数。

有解决办法吗?是的,至少一个 - 提交一个将在另一个会话中完成的作业。

示例表(这样程序就不会因此失败)

SQL> create table foo (id number);

Table created.

SQL> create table bar (id number);

Table created.

创建函数:

SQL> CREATE OR REPLACE FUNCTION table_exists(table_name VARCHAR2)
  2  RETURN BOOLEAN
  3  AS
  4      table_count NUMBER := 0;
  5      exists_sql VARCHAR2(255);
  6  BEGIN
  7      exists_sql := 'SELECT COUNT(1) FROM tab WHERE tname = :tab_name';
  8      EXECUTE IMMEDIATE exists_sql INTO table_count USING table_name;
  9
 10      RETURN table_count > 0;
 11  END;
 12  /

Function created.

在吗?是的,它是:

SQL> desc table_Exists;
FUNCTION table_Exists RETURNS BOOLEAN
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 TABLE_NAME                     VARCHAR2                IN

运行主要代码段;请注意 line #4(包含作业编号的变量声明)和 line #21 提交作业。

SQL> DECLARE
  2      TYPE tables_array IS VARRAY(2) OF VARCHAR2(25); -- change varray size if running on dev
  3      tables tables_array;
  4      i number;  -- job number
  5  BEGIN
  6      tables := tables_array(
  7          'FOO',
  8          'BAR'
  9      );
 10
 11      FOR table_element IN 1 .. tables.COUNT LOOP
 12          DBMS_OUTPUT.PUT_LINE('Backing up data for ' || tables(table_element));
 13          IF table_exists(tables(table_element) || '_ORIGINAL') THEN
 14              DBMS_OUTPUT.PUT_LINE(tables(table_element) || '_ORIGINAL already exists');
 15          ELSE
 16              EXECUTE IMMEDIATE 'CREATE TABLE ' || tables(table_element) || '_ORIGINAL AS SELECT * FROM '|| tables(table_element);
 17          END IF;
 18      END LOOP;
 19
 20      -- EXECUTE IMMEDIATE 'DROP FUNCTION table_exists';
 21      dbms_job.submit(i, 'begin execute immediate ''drop function table_exists''; end;');
 22
 23      COMMIT;
 24
 25      EXCEPTION
 26          WHEN OTHERS THEN
 27            DBMS_OUTPUT.PUT_LINE ('Unexpected error: ' || sqlerrm);
 28      ROLLBACK;
 29      RAISE;
 30  END;
 31  /

PL/SQL procedure successfully completed.

这个功能还在吗?不,它被丢弃了。

SQL> desc table_exists;
ERROR:
ORA-04043: object table_exists does not exist


SQL>