2009-12-02 34 views
9

Tengo el siguiente procedimiento:vida útil de tabla temporal

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

    -- do something with tempTable here 

    DROP TABLE tempTable; 
END PROCEDURE; 

¿Qué pasa si hay una excepción antes de que el DROP TABLE se llama? ¿Continuará WillTable después de las salidas de Foo?

Si es así, foo podría fallar la próxima vez que se invoque, porque la tabla de tentación ya existiría. ¿Cómo se debe manejar eso?

EDIT: Estoy utilizando Informix 11,5

Respuesta

3

finalmente utilizó una variación de Jonathan y de la solución de 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; 
+0

Lo que tienes aquí - descarta la tabla pero ignora el error si no existe - es una buena forma de hacerlo. En circunstancias normales, la tabla temporal falta tanto antes de ejecutarse como una vez completada. Sería posible ajustar el alcance de la excepción, pero eso debería funcionar bien. –

+0

Tenga en cuenta que Informix moderno admite las cláusulas IF EXISTS y IF NOT EXISTS en sentencias como DROP TABLE. Por lo tanto, en estos días, puede escribir: 'DROP TABLE IF EXISTS tempTable;' que soltará la tabla si está presente (y usted tiene permiso, etc.) y no hará nada si la tabla no existe. –

3

According to the documentation, tablas temporales se eliminan al terminar la sesión.

+0

supongo, mi preocupación es que la sesión termina cuando se cierra la conexión (? Derecha). Entonces, si se llama a foo varias veces antes de que se cierre la conexión, y la primera invocación a foo arrojó una excepción y no limpió la tabla temporal, la siguiente invocación de foo fallará, porque la tabla temporal ya existe. ¿Cuál es la mejor práctica para codificar para proteger de esto. ¿Necesitamos verificar si la tabla temporal existe y soltarla? – rouble

+0

Ingresé el código "verificar si la tabla existe" para verificar antes de crear y soltar. ¿Informix tiene una estructura de tabla temporal por la cual una tabla solo puede verse en la sesión específica? SQL Server tiene esta funcionalidad. – adamcodes

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

Si w_count es 1, elimine la tabla antes de SELECT ... INTO. Lo mismo con DROP TABLE.

2

Sí, la tabla temporal seguirá existiendo. Las tablas temporales, por definición, tienen una duración de la sesión que las creó, a menos que se descarten explícitamente.

La tabla temporal solo puede ser vista por la sesión que la creó, y no hay ningún impedimento para que varios usuarios ejecuten el mismo procedimiento en paralelo. La respuesta de Adam para probar la existencia de la tabla temporal arrojará un resultado distinto de cero si algún usuario está ejecutando el procedimiento. Debe probar que la sesión que posee la tabla temporal es también la sesión actual. Dado que esta pregunta está dentro del alcance de un procedimiento almacenado, podría ser más simple agregar un DROP explícito, envuelto en algún manejo de excepciones.

+0

Supongo que quiere decir algo como esto: CREAR PROCEDIMIENTO droptempTtable() EN EXCEPCIÓN EN (-206) EXCEPCIÓN FINAL; DROP TABLE temptable; PROCEDIMIENTO DE FINALIZACIÓN; ¿Hay alguna forma que conozcas para especificar el nombre de la tabla, para hacer este procedimiento genérico? – rouble

4

Como han dicho otros, las tablas temporales duran hasta que las suelta explícitamente o la sesión finaliza.

Si el procedimiento almacenado falla porque la tabla ya existe, SPL genera una excepción. Puede resolver excepciones agregando una cláusula ON EXCEPTION, pero está ingresando una de las partes más barrocas de SPL, Stored Procedure Language.

Aquí es una versión ligeramente modificada de su procedimiento almacenado - uno que genera una división por cero excepción (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. 

Esto muestra que la primera vez a través del código que se ejecuta la instrucción SELECT, creando la mesa, y luego corrieron falta de la división por cero. La segunda vez, sin embargo, SELECT falló porque la tabla temporal ya existía, de ahí el mensaje de error diferente.

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; 

El bloque BEGIN/END limita el manejo de excepciones a la instrucción atrapada. Sin BEGIN/END, el manejo de excepciones cubre todo el procedimiento, reaccionando también a la división por error cero (y por lo tanto, permitiendo que la TABLA DE DESCARGA funcione y el procedimiento parece ejecutarse con éxito).

Tenga en cuenta que todavía TempTable existe en este punto:

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

Esto demuestra que el procedimiento ya no falla porque la tabla temporal está presente.

Puede limitar el bloque de excepción ON para códigos de error seleccionados (-958 parece plausible para éste) por:

ON EXCEPTION IN (-958) ... 

consulte el manual IBM Informix a SQL: sintaxis manual, capítulo 3 'Declaraciones de SPL' .

Tenga en cuenta que Informix 11.70 añadió el 'SI EXISTE' y 'SI NO EXISTE' cláusulas para crear y Declaraciones DROP. Por lo tanto, es posible utilizar el DROP TABLE declaración modificada:

DROP TABLE IF EXISTS tempTable; 

Por lo tanto, con Informix 11.70 o más tarde, la forma más fácil de escribir el procedimiento es:

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; 

También es posible usar esto, pero entonces obtenga la definición previa del procedimiento, sea lo que sea, y puede que no sea lo que esperaba.

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; 
+0

@Jonathan Usé una variación de lo que sugirió aquí. Envié lo que utilicé como respuesta. Avíseme si tiene algún comentario sobre ese spl/sql. – rouble