Showing posts with label Global temporary tables. Show all posts
Showing posts with label Global temporary tables. Show all posts

Friday, August 03, 2007

A practical example of using global temporary tables within Apex: displaying dbms_output messages

It's late so i am not going to make it longer than necessary.

Some days ago i read an interesting question in the OTN forum and i threw my 50 cent advice (well, honestly it may have been worth 60 or 70 cents as i did some homework before shooting...).

In short, a user was asking for a method for display the messages sent to the DBMS_OUTPUT buffer.

This question eventually aroused my fantasy, so i wrote a generic function for storing dbms_output messages into a generic table (a table in the same schema or in another one, provided the user has INSERT privilege).
Having used up all my fantasy in the development, i decided to call the function STORE_DBMS_OUTPUT.

In my test apex application the staging table is defined as follows:

create global temporary table
staging_table(
id number(5,0),
text varchar2(255)
) on commit delete rows
/
The source code of the function can be downloaded from Yocoya.com.

The function takes 4 parameters and returns a number:

p_owner owner of the staging table, default to current user.
p_table name of the table, mandatory
p_txt_col name of the column for storing messages, typically VARCHAR2(255)
p_cnt_col optional name of the column for storing message sequence number

The last parameter may be omitted if you already have a before-insert trigger on the table where you stuff an oracle sequence.

The function retrieves all the content in the buffer and the value it returns is the number of messages it found.

Although i wrote the function for using within an Apex page, it's completely independent from it and it can be used in different situations.
The table where the messages are going to be stored doesn't necessarily have to be a Global Temporary Table (GTT), although in that case you must devise a method for keeping it clean without interfering with other sessions and/or users.

Users who are interested in looking at a working example of dynamic SQL in combination with FORALL and bulk binds may be interested in this function too.
Note also the n-tier usage of DUAL i talked about some time ago that i use here for initializing a pl/sql table containing the subscripts, i'll probably write something in another posting on this subject.

In case you are interested in using this function inside apex, here is how i did it (please note that this techniques are still under testing).

before header processes
step 10: truncate staging table (just in case) and call the desired procedure returning dbms_output messages (conditional on request=OUTPUT)
step 20: get the dbms_output and store it in a global temporary table (conditional on request=OUTPUT), as follows:

declare
n integer;
begin
n := STORE_DBMS_OUTPUT(
p_owner => :OWNER,
p_table => 'STAGING_TABLE',
p_txt_col => 'TEXT',
p_cnt_col => 'ID');
end;


regions
sequence 10: some region with a button branching to the same page, setting request = OUTPUT
sequence 20: report region on staging table (conditional on request=OUTPUT)
sequence 30: PL/SQL type region truncating the table (conditional on request=OUTPUT), may be omitted altogether if GTT is defined as on commit delete rows.

As you see here i have up to two truncates statements. This is just to avoid having an idle session holding some temporary segment as i related in my previous posting.
If the GTT is defined as on commit delete rows, you can probably omit both truncates, i just prefer to leave a clean table after using it.

That's it.

Thursday, August 02, 2007

ORA-14452: attempt to create, alter or drop an index on temporary table already in use

If you are wondering why you can't drop a global temporary table (defined with ON COMMIT PRESERVE ROWS) that you no longer need, keep in mind that there can be other active sessions holding data in the table.

In such situations you can expect to find one or more rows in V$TEMPSEG_USAGE where column SEGTYPE contains DATA and using the other pointers you can perhaps track back to the session(s) holding these segments.

For instance, in my case i had an oracle session opened by Oracle Application Express (APEX) which was staging data in a global temporary table (a rather uncommon need i must say...) and when i attempted to drop the table i got:

ORA-14452: attempt to create, alter or drop an index on temporary table already in use

This happens because the "standard" user has no control on opening and closing oracle sessions managed by APEX, so one may have closed the page but the oracle sessions behind it is still active and actually it could be recycled for some other web user, so it's not going to disappear any time soon on its own.

For ordinary situations, supposing you are the DBA (and you are not doing this in a production database...) you can try to kill the session in order to reclaim the temporary segments and re-execute the DROP TABLE statement.

See message translations for ORA-14452 and search additional resources.



ORA-14452: tentativo di creazione, modifica o cancellazione di un indice di una tabella temporanea già in uso
ORA-14452: se ha intentado crear, modificar o borrar un índice de una tabla temporal ya en uso
ORA-14452: intent de crear, alterar o eliminar un índex d'una taula temporal que ja està essent utilitzada
ORA-14452: tentative de création, modification ou suppression d'un index sur une table temporaire déjà en cours d'utilisation
ORA-14452: Versuch, einen Index auf einer schon verwendeten temporären Tabelle zu erstellen, zu ändern oder zu löschen
ORA-14452: απόπειρα δημιουργίας, μεταβολής, ή διαγραφής ενός ευρετηρίου προσωρινού πίνακα που ήδη χρησιμοποιείται
ORA-14452: forsøg på at oprette, ændre eller droppe indeks på midlertidig tabel, der allerede er i brug
ORA-14452: försök gjordes att skapa, ändra eller ta bort ett index i temporär tabell som redan används
ORA-14452: forsøk på å opprette, endre eller fjerne en indeks for midlertidig tabell som allerede er i bruk
ORA-14452: jo käytössä olevan väliaikaisen taulun indeksiä yritettiin luoda, muuttaa tai poistaa
ORA-14452: kísérlet egy már használatban lévő ideiglenes tábla indexének létrehozására, módosítására vagy eldobására
ORA-14452: încercare de creare, modificare sau eliminare a unui index, într-un tabel temporar deja în uz
ORA-14452: Poging tot aanmaken, wijzigen of verwijderen van index uit tijdelijke tabel die al in gebruik is.
ORA-14452: tentativa de criar, alterar ou eliminar um índice em uma tabela temporária que já está sendo usada
ORA-14452: tentativa de criar, alterar ou suprimir um índice numa tabela temporária já em utilização
ORA-14452: попытка создать, изменить или удалить индекс в уже используемой временной таблице
ORA-14452: pokus o vytvoření, změnu nebo zrušení indexu v již použité dočasné tabulce
ORA-14452: pokus o vytvorenie, zmenu alebo zrušenie indexu na dočasnú tabuľku, ktorá sa už používa
ORA-14452: próba utworzenia, zmiany lub usunięcia indeksu dla tymczasowej tabeli, która już jest w użyciu
ORA-14452: geçici tabloda bir dizin yaratma, değiştirme veya bırakma denemesi zaten yapılıyor
ORA-14452: attempt to create, alter or drop an index on temporary table already in use

yes you can!

Two great ways to help us out with a minimal effort. Click on the Google Plus +1 button above or...
We appreciate your support!

latest articles