10

我有以下程序:

CREATE PROCEDURE foo ()
    SELECT * FROM fooBar INTO TEMP tempTable;

    -- do something with tempTable here

    DROP TABLE tempTable;
END PROCEDURE;

如果在调用 DROP TABLE 之前出现异常会发生什么?foo 退出后 tempTable 还会存在吗?

如果是这样,下次调用 foo 时可能会失败,因为 tempTable 已经存在。那应该怎么处理。

编辑:我正在使用informix 11.5

4

5 回答 5

5

根据文档,会话结束时会删除临时表。

于 2009-12-02T18:05:59.297 回答
4

正如其他人所说,临时表会持续到您明确删除它们或会话结束。

如果存储过程因表已存在而失败,则 SPL 会生成异常。您可以通过添加一个 ON EXCEPTION 子句来处理异常——但是您正在输入 SPL 中更巴洛克的部分之一,即存储过程语言。

这是您的存储过程的轻微修改版本 - 生成除以零异常 (SQL -1202) 的版本:

CREATE PROCEDURE foo ()
    define i integer;
    SELECT * FROM 'informix'.systables INTO TEMP tempTable;

    -- do something with tempTable here
    let i = 1 / 0;

    DROP TABLE tempTable;
END PROCEDURE;

execute procedure foo();
SQL -1202: An attempt was made to divide by zero.

execute procedure foo();
SQL -958: Temp table temptable already exists in session.

这表明第一次通过代码执行了 SELECT,创建了表,然后执行了除以零的错误。但是,第二次选择失败,因为临时表已经存在,因此出现了不同的错误消息。

drop procedure foo;
CREATE PROCEDURE foo()
    define i integer;

    BEGIN
        ON EXCEPTION
            DROP TABLE tempTable;
            SELECT * FROM 'informix'.systables INTO TEMP tempTable;
        END EXCEPTION WITH RESUME;
        SELECT * FROM 'informix'.systables INTO TEMP tempTable;
    END;

    -- do something with tempTable here
    let i = 1 / 0;

    DROP TABLE tempTable;
END PROCEDURE;

BEGIN/END 块将异常处理限制为捕获语句。如果没有 BEGIN/END,异常处理会覆盖整个过程,也会对除以零错误做出反应(因此让 DROP TABLE 工作并且过程似乎运行成功)。

注意 temptable 此时仍然存在:

+ execute procedure foo();
SQL -1202: An attempt was made to divide by zero.
+ execute procedure foo();
SQL -1202: An attempt was made to divide by zero.

这表明该过程不再失败,因为临时表存在。

您可以通过以下方式将 ON EXCEPTION 块限制为选定的错误代码(-958 似乎对此很合理):

ON EXCEPTION IN (-958) ...

请参阅 IBM Informix Guide to SQL: Syntax 手册,第 3 章“SPL 语句”。

请注意,Informix 11.70 将“IF EXISTS”和“IF NOT EXISTS”子句添加到 CREATE 和 DROP 语句中。因此,您可以使用修改后的DROP TABLE语句:

DROP TABLE IF EXISTS tempTable;

因此,对于 Informix 11.70 或更高版本,编写过程的最简单方法是:

DROP PROCEDURE IF EXISTS foo;

CREATE PROCEDURE foo()
    define i integer;
    DROP TABLE IF EXISTS tempTable;

    SELECT * FROM 'informix'.systables INTO TEMP tempTable;

    -- do something with tempTable here
    let i = 1 / 0;

    DROP TABLE tempTable;  -- Still a good idea
END PROCEDURE;

您也可以使用它,但随后您将获得该过程的先前定义,无论它是什么,它可能不是您所期望的。

CREATE PROCEDURE IF NOT EXISTS foo()
    define i integer;
    DROP TABLE IF EXISTS tempTable;

    SELECT * FROM 'informix'.systables INTO TEMP tempTable;

    -- do something with tempTable here
    let i = 1 / 0;

    DROP TABLE tempTable;  -- Still a good idea
END PROCEDURE;
于 2009-12-03T00:31:07.890 回答
3

我终于使用了乔纳森和 RET 解决方案的变体:

CREATE PROCEDURE foo ()
    ON EXCEPTION IN (-206)
    END EXCEPTION WITH RESUME;

    DROP TABLE tempTable;    

    SELECT * FROM fooBar INTO TEMP tempTable;

    -- do something with tempTable here

    DROP TABLE tempTable;
END PROCEDURE;
于 2009-12-03T18:27:10.190 回答
2

是的,临时表仍然存在。根据定义,临时表具有创建它们的会话的生命周期,除非显式删除。

临时表只能由创建它的会话看到,并且多个用户并行运行同一过程没有任何障碍。如果任何用户正在运行该过程,Adam 测试临时表是否存在的答案将返回非零结果。您需要测试拥有临时表的会话是否也是当前会话。鉴于这个问题在存储过程的范围内,添加显式 DROP 可能更简单,并包含在一些异常处理中。

于 2009-12-02T20:52:21.153 回答
1
SELECT count(*) 
INTO w_count 
FROM sysmaster:systabnames s,sysmaster:systabinfo i
WHERE i.ti_partnum = s.partnum
AND sysmaster:BITVAL(i.ti_flags,'0x0020') = 1
AND s.tabname = 'tempTable' ;

如果 w_count 为 1,则在 SELECT ... INTO 之前删除表。与 DROP TABLE 相同。

于 2009-12-02T18:16:12.043 回答