临时表的生命周期

发布于 2024-08-13 16:07:38 字数 363 浏览 12 评论 0原文

我有以下过程:

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

I have the following procedure:

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

    -- do something with tempTable here

    DROP TABLE tempTable;
END PROCEDURE;

What happens if there is an exception before the DROP TABLE is called? Will tempTable still be around after foo exits?

If so, foo could fail the next time it is called, because tempTable would already exist. How should that be handled.

EDIT: I am using informix 11.5

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北恋 2024-08-20 16:07:38

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

According to the documentation, temporary tables are dropped when the session ends.

岁月染过的梦 2024-08-20 16:07:38

正如其他人所说,临时表会一直持续到您显式删除它们或会话结束为止。

如果存储过程因表已存在而失败,则 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,创建了表,然后违反了除以零。但第二次,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 在 CREATE 和 DROP 语句中添加了“IF EXISTS”和“IF NOT EXISTS”子句。因此,您可以使用修改后的 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;

As others stated, temporary tables last until you drop them explicitly or the session ends.

If the stored procedure fails because the table already exists, SPL generates an exception.
You can deal with exceptions by adding an ON EXCEPTION clause -— but you are entering one of the more baroque parts of SPL, Stored Procedure Language.

Here is a mildly modified version of your stored procedure - one that generates a divide by zero exception (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.

This shows that the first time through the code executed the SELECT, creating the table, and then ran foul of the divide by zero. The second time, though, the SELECT failed because the temp table already existed, hence the different error message.

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;

The BEGIN/END block limits the exception handling to the trapped statement. Without the BEGIN/END, the exception handling covers the entire procedure, reacting to the divide by zero error too (and therefore letting the DROP TABLE work and the procedure seems to run successfully).

Note that temptable still exists at this point:

+ 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.

This shows that the procedure no longer fails because the temp table is present.

You can limit the ON EXCEPTION block to selected error codes (-958 seems plausible for this one) by:

ON EXCEPTION IN (-958) ...

See the IBM Informix Guide to SQL: Syntax manual, chapter 3 'SPL Statements'.

Note that Informix 11.70 added the 'IF EXISTS' and 'IF NOT EXISTS' clauses to CREATE and DROP statements. Thus, you might use the modified DROP TABLE statement:

DROP TABLE IF EXISTS tempTable;

Thus, with Informix 11.70 or later, the easiest way to write the procedure is:

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;

You could also use this, but then you get the previous definition of the procedure, whatever it was, and it might not be what you expected.

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;
迷你仙 2024-08-20 16:07:38

我最终使用了 Jonathan 和 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;

I finally used a variation of Jonathan's and RET's solution:

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;
再见回来 2024-08-20 16:07:38

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

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

Yes, the temp table will still exist. Temp tables by definition have a lifetime of the session that created them, unless explicitly dropped.

The temp table can only be seen by the session that created it, and there is no impediment to the same procedure being run in parallel by multiple users. Adam's answer to test for the existence of the temp table will return a non-zero result if any user is running the procedure. You need to test that the session that owns the temp table is the current session as well. Given that this question is within the scope of a stored procedure, it might be simpler to add an explicit DROP, wrapped in some exception handling.

百思不得你姐 2024-08-20 16:07:38
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之前删除表。与删除表相同。

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

If w_count is 1, delete table before SELECT ... INTO. Same with DROP TABLE.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文