Verwendung von TEMP TABLE in einer Funktion

Hallo zusammen,

ich erstelle in einer Funktion eine temp tabelle (on commit drop), in welcher ich Daten sammle, bearbeite usw.

Beim ersten Aufruf der Funktion (in einer Session) funktioniert alles wie erwartet, bei den folgenden erhalte ich die Fehlermeldung:
“Relation mit OID yxz existiert nicht”

Es gab hier schon mal ein entsprechendes Thema (http://www.pg-forum.de/pl-pgsql/505-verwendung-von-temporary-tables-relation-oid-does.html), allerdings ist der dortige Link auf die Lösung nicht mehr erreichbar.

Was kann man hier tun?

Verwende EXECUTE für DDL-Befehle innerhalb von plpgsql-Funktionen. Also:

declare sql text;

sql:=‘create table…’;
execute sql;

sql:=drop table…’
execute sql;


Andreas

Funktioniert leider auch nicht. Gleicher Fehler.

Ich habe verschiedene Varianten probiert:

create temp table
create temp table as select
explizit drop table oder auch on commit drop
dynamisches SQL wie empfohlen

alles ohne Erfolg. Wird die Funktion innerhalb einer Session mehrfach aufgerufen, dann kommt es zu o.a. Fehler.

Gruß Pitti

[php]
test=# create or replace function ttable(int) returns int as $$declare sql text;ret int;begin sql:=‘create temporary table ttable(i int)’; execute sql; sql:=‘insert into ttable values(’ || $1 ||‘);’;execute sql; sql='select 5i from ttable;'; execute sql into ret; sql:=‘drop table ttable;’; execute sql; return ret; end; $$ language plpgsql;
CREATE FUNCTION
test=
# select * from ttable(2);
ttable

10
(1 row)

test=*# select * from ttable(3);
ttable

15
(1 row)

test=*# select * from ttable(4);
ttable

20
(1 row)

[/php]


Andreas

Hallo Andreas, zunächst vielen Dank.
Ich habe Dein Beispiel getestet. Allerdings verwendest Du dynamisches SQL nicht nur für DDL sondern auch für DML.
Folgende kleine Änderung funktioniert schon wieder nicht mehr:
create or replace function ttable(int) returns int as
$$
declare sql text;ret int;
begin
sql:=‘create temporary table ttable(i int)’;
execute sql;
insert into ttable values($1);
select 5*i into ret from ttable;
sql:=‘drop table ttable;’;
execute sql;
return ret;
end;
$$ language plpgsql;


Nun ist das hier ein triviales Beispiel. Die Funktionen, welche ich portieren muß sind teilweise sehr komplex, auch werden ggf. mehrere temp Tabellen erzeugt, gejoint usw. Und dann für jeden Schritt sql:= … execute, das macht mich nicht so richtig glücklich. Gibt es denn keine andere Möglichkeit?

Eigentlich müßte es doch reichen, der Funktion irgendwie beizubringen, dass sie den alten Plan nicht verwenden soll. Denn offensichtlich besteht ja genau darin das Problem oder?
Oder gibt es vielleicht noch andere Wege, wie man das tun kann?

Pitti

Gratulation, Du hast eben Plan Invalidation erfunden. Und zu Deinem Glück steht 8.3 schon quasi vor der Haustür…
Merlin’s stuff: PostgreSQL 8.3 Features: Plan Invalidation

Andreas