LOB adatok (Large Object) ------------------------- Nagy adatok tárolására a LOB különböző verziói használhatók. Belső LOB-ok -> CLOB, BLOB, NCLOB Külső LOB -> BFILE CREATE TABLE lob_proba (azon NUMBER(4), clob_o CLOB, blob_o BLOB, bf_o BFILE) TABLESPACE users STORAGE (INITIAL 200K) LOB (clob_o) STORE AS clob_seg (TABLESPACE users STORAGE (INITIAL 100K) ) LOB (blob_o) STORE AS blob_seg (TABLESPACE users STORAGE (INITIAL 100K) ); A LOB-ok soron kívül tárolódnak, külön megadhatók rájuk a tárolással kapcsolatos információk. A soron belül egy úgynevezett LOB lokátor tárolódik. (Illetve bizonyos méret alatt magát a lob-ot is tárolhatjuk a soron belül) A külső LOB tárolása előtt a DBA-nak egy DIRECTORY-t kell létrehoznia. CREATE DIRECTORY infokez3 AS '/tmp/INFOKEZ3'; GRANT READ, WRITE ON DIRECTORY infokez3 TO public; A fenti jogosultságok teljesen függetlenek az op. rendszer szinten megadott jogosultságoktól, vagyis még op. rendszer szinten is kell írási/olvasási jog. INSERT INTO lob_proba VALUES(1, NULL, NULL, NULL); INSERT INTO lob_proba VALUES(2, EMPTY_CLOB(), EMPTY_BLOB(), BFILENAME('INFOKEZ3', 'Moricz_Rokonok.txt')); FONTOS!!! Nagy betűvel kell írni a DIRECTORY nevét !!! INSERT INTO lob_proba VALUES(3, 'Ez egy szöveg', EMPTY_BLOB(), NULL); Az üres LOB lokátor nem azonos a NULL értékkel!!! Néhány alábbi példa nem is futna, ha egy olyan oszlopra futtatnánk, ahol NULL van és nem EMPTY_CLOB(). SELECT azon, NVL(clob_o, 'NULL') FROM lob_proba; AZON NVL(CLOB_O,'NULL') ---------- ------------------ 1 NULL 2 3 Ez egy szöveg Sok művelet ugyanúgy használható rájuk mint a VARCHAR2 oszlopokra. pl. UPDATE lob_proba SET clob_o='Blabla uj szoveg' WHERE azon=2; SELECT SUBSTR(clob_o, 1,9) FROM lob_proba WHERE azon=2; INSERT INTO lob_proba SELECT 4, clob_o, NULL, NULL FROM lob_proba WHERE azon=3; UPDATE lob_proba SET clob_o = EMPTY_CLOB() WHERE azon=4; De van egy package is a LOB-ok kezelésére -> DBMS_LOB Egy két példa: DBMS_LOB.append Egy CLOB értéket hozzáfűzünk egy másik végéhez. Zárolni kell a módosítandó sort -> FOR UPDATE !!! Az alábbi példa nem működne ha olyan oszlophoz fűznénk hozzá, ahol NULL van és nem EMPTY_CLOB(). DECLARE dest_lob CLOB; src_lob CLOB; BEGIN SELECT clob_o INTO src_lob FROM lob_proba WHERE azon=3; SELECT clob_o INTO dest_lob FROM lob_proba WHERE azon=2 FOR UPDATE; DBMS_LOB.append(dest_lob, src_lob); COMMIT; END; Beleteszünk egy kicsit hosszabb szöveget. INSERT INTO lob_proba (azon, clob_o) VALUES(5, 'Arra ébredt, hogy a felesége a másik szobában telefonál.' || '- Te Juliska szívem, mi volt abban a pácban, mikor a múltkor nyulat ettünk nálatok?... Az ' || 'akkor nagyon ízlett Pistának.' || 'A szívét valami forró melegség és meghatottság öntötte el. Hát a felesége?... Telefonál... ' || 'megkérdi, a nyulat hogy kell elkészíteni, hogy neki jólessen...' || 'Még könnyféle is szivárgott a szempillái közé.' || 'Mikor orosz fogságban feküdt, akkor senki sem telefonált át egyik barakkból a másikba, ' || 'hogy...' || '- Édesapám nyulat küldött... Nagyon panaszkodik szegény, sokat kell szenvedni most a népek-' || 'kel a háború óta, egész megváltozott a világ, és ő már öregedik... Szerette volna, ha Pista ' || 'átvette volna a birtokot... Nahát, Pistával most... Fiam, úgy udvarolnak neki... mindenki a ' || 'protekcióját lesi... Még alszik, mert az este reggelig tartott ez a városi bankett...' || 'Felkönyökölt az ágyban, úgy leste a felesége hangját, nincsen-e benne valami félelmes... Hogy ' || 'nem kritizálja, nem csúfolja, nem ítéli-e meg. De nem. Lina olyan édes volt, olyan bizakodó, ' || 'annyira boldog, hogy nem hallotta ilyennek nagyon-nagyon régen... Minden tud csalni, de a ' || 'hang színe, az nem... Az őszinte és leleplez minden érzést. Linából most kicsordult valami ' || 'anyás büszkeség, úgy szólott őróla, mintha a nagy fiáról beszélne, akire büszke, mert ' || 'kitüntetéssel tette le az érettségit, vagy megnyerte a versenyét, vagy pénzt hozott a házhoz ' || 'valamiképpen...'); SELECT azon, DBMS_LOB.GETLENGTH(clob_o), NVL(clob_o, 'NULL') FROM lob_proba; DBMS_LOB.read -> beolvas egy részt a LOB-ból Nem kell FOR UPDATE és COMMIT sem. DECLARE src_lob CLOB; buff VARCHAR2(2000); offset_v INTEGER := 5; amount_v INTEGER := 200; BEGIN SELECT clob_o INTO src_lob FROM lob_proba WHERE azon=5; DBMS_LOB.read(src_lob, amount_v, offset_v, buff); dbms_output.put_line(buff); END; DBMS_LOB.write -> felülír egy részt a LOB-ban DECLARE dest_lob CLOB; buff VARCHAR2(10) := 'XXXXXXXXXX'; offset_v INTEGER := 5; amount_v INTEGER := 10; BEGIN SELECT clob_o INTO dest_lob FROM lob_proba WHERE azon=5 FOR UPDATE; DBMS_LOB.write(dest_lob, amount_v, offset_v, buff); COMMIT; END; DBMS_LOB.trim -> levágja a LOB végét DECLARE dest_lob CLOB; uj_hossz INTEGER := 1000; BEGIN SELECT clob_o INTO dest_lob FROM lob_proba WHERE azon=5 FOR UPDATE; DBMS_LOB.trim(dest_lob, uj_hossz); COMMIT; END; DBMS_LOB.copy -> egyik LOB-ból a másikba másol (READ + WRITE) DECLARE dest_lob CLOB; src_lob CLOB := 'YYYYYYYYYY'; dest_offset INTEGER := 5; src_offset INTEGER := 1; amount_v INTEGER := 10; BEGIN SELECT clob_o INTO dest_lob FROM lob_proba WHERE azon=5 FOR UPDATE; DBMS_LOB.copy(dest_lob, src_lob, amount_v, dest_offset, src_offset); COMMIT; END; DBMS_LOB.writeappend -> a LOB végéhez ír valamit DECLARE dest_lob CLOB; buff VARCHAR2(10) := 'ZZZZZZZZZZ'; amount_v INTEGER := 10; BEGIN SELECT clob_o INTO dest_lob FROM lob_proba WHERE azon=5 FOR UPDATE; DBMS_LOB.writeappend(dest_lob, amount_v, buff); COMMIT; END; Külső LOB-ok kezelése (BFILE) ----------------------------- Értékadás egy LOB lokátornak: UPDATE lob_proba SET bf_o = BFILENAME('INFOKEZ3', 'Moricz_Rokonok.txt') WHERE azon=2; Lekérdezése (nem minden kliens jeleníti meg) SELECT azon, bf_o FROM lob_proba; DBMS_LOB.READ -> olvasás BFILE-ból Az olvasás bináris (RAW) formátumban olvas be ... Ezért egy kis konverzió is lesz a kódban. DECLARE bfile_v BFILE := BFILENAME('INFOKEZ3', 'Moricz_Rokonok.txt'); amount_v INTEGER := 100; src_offset INTEGER := 1; buff VARCHAR2(2000); -- implicit RAWTOHEX konverzióval tölti fel az Oracle buff2 VARCHAR2(2000) := ''; -- ebben már karakterek lesznek dest_lob CLOB; BEGIN -- SELECT bf_o INTO bfile_v FROM lob_proba WHERE azon=2; -- Így is lehetne az előző UPDATE után DBMS_LOB.open(bfile_v, dbms_lob.lob_readonly); DBMS_LOB.read(bfile_v, amount_v, src_offset, buff); DBMS_LOB.close(bfile_v); FOR i IN 1..FLOOR(LENGTH(buff)/2) LOOP buff2 := buff2 || CHR(TO_NUMBER(SUBSTR(buff,2*i-1,2), 'xx')); END LOOP; amount_v := LENGTH(buff2); SELECT clob_o INTO dest_lob FROM lob_proba WHERE azon=2 FOR UPDATE; DBMS_LOB.writeappend(dest_lob, amount_v, buff2); COMMIT; END; DBMS_LOB.SUBSTR -> hasonló a substr-hez DECLARE bfile_v BFILE := BFILENAME('INFOKEZ3', 'Moricz_Rokonok.txt'); amount_v INTEGER := 100; offset_v INTEGER := 1; buff VARCHAR2(2000); buff2 VARCHAR2(2000) := ''; BEGIN DBMS_LOB.open(bfile_v, dbms_lob.lob_readonly); buff := RAWTOHEX(DBMS_LOB.substr(bfile_v, amount_v, offset_v)); DBMS_LOB.close(bfile_v); FOR i IN 1..FLOOR(LENGTH(buff)/2) LOOP buff2 := buff2 || CHR(TO_NUMBER(SUBSTR(buff,2*i-1,2), 'xx')); END LOOP; DBMS_OUTPUT. PUT_LINE(buff2); END; DBMS_LOB.LOADFROMFILE -> fájlból CLOB-ba olvas, karakteresen DECLARE bfile_v BFILE := BFILENAME('INFOKEZ3', 'Moricz_Rokonok.txt'); amount_v INTEGER := 100; dest_offset INTEGER := 1; src_offset INTEGER := 100; dest_lob CLOB := EMPTY_CLOB(); BEGIN SELECT clob_o INTO dest_lob FROM lob_proba WHERE azon=2 FOR UPDATE; DBMS_LOB.open(bfile_v, dbms_lob.lob_readonly); DBMS_LOB.loadfromfile(dest_lob, bfile_v, amount_v, dest_offset, src_offset); DBMS_LOB.close(bfile_v); COMMIT; DBMS_OUTPUT.PUT_LINE(substr(dest_lob,1,100)); END;