我有以下程序:
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
答案 0 :(得分: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,创建表,然后运行除以零的犯规。但是第二次,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 SQL指南:语法手册”,第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;
答案 1 :(得分:3)
According to the documentation,会话结束时删除临时表。
答案 2 :(得分:3)
我终于使用了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;
答案 3 :(得分:2)
是的,临时表仍然存在。根据定义,临时表具有创建它们的会话的生命周期,除非明确删除。
临时表只能由创建它的会话看到,并且不会阻碍多个用户并行运行相同的过程。如果任何用户正在运行该过程,Adam测试临时表存在的答案将返回非零结果。您需要测试拥有临时表的会话是否也是当前会话。鉴于此问题属于存储过程的范围,添加显式DROP可能更简单,包含在一些异常处理中。
答案 4 :(得分: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相同。