wtorek, 20 grudnia 2011

Klasy JAVA w Oracle

Pewnych rzeczy nie da się oprogramować w PL/SQL - dajmy na to drukowanie, lub sterowanie zewnętrznym urządzeniem. Wtedy z pomocą przychodzi nam język JAVA. Możemy oprogramować niezbedną funkcjonalność w Javie, załadować ją do bazy, nałożyć taką nakładkę na klasę javową tak by była widoczna jako funkcja PL/SQL i po robocie :) Metody takiej klasy wywołuje się tak jak zwyczajne funkcje napisane w PL/SQL.


Pierwszy krok to klasa w JAVIE:

public class Przyklad {
public static int dawajliczbe() {
return 1;
}
}


Nie musimy jej kompilować. Następnie poleceniem

loadjava -user nazwauzytkownika/jegohaslo sciezkadopliku

ładujemy klasę do bazy. Klasa zostanie załadowana do schematu użytkownika którego nazwę i hasło podaliśmy przy ładowaniu.




Następnie z poziomu tego samego użytkownika robimy sobie nakładkę na metodę w klasie javowej:


create or replace function javova return number
as language java name 'Przyklad.dawajliczbe() return int';


i wywołujemy jak każdą inną funkcję w Oracle :


Ładowanie pliku do kolumny BLOB, CLOB

Zanim podejdziesz do tego artykułu, zapoznaj się z tym : http://andrzejklusiewicz.blogspot.com/2011/12/bfile-referencje-do-plikow-zewnetrznych.html
Wiedza z niego będzie Ci tutaj niezbędna.

Najpierw stwórz (o ile jeszcze nie masz) tabelkę z kolumną typu BLOB :

create table obrazki(
nr number,
obrazek blob
); 



Poniżej kod ładujący plik do kolumny typu danych blob w tabeli. Kilka linii niżej wyjaśnienie.





declare
plik bfile;
bl blob:=empty_blob();
wielkosc number;
nr number;
begin
plik:=bfilename('LOBY','obrazek3.jpeg');
if dbms_lob.fileexists(plik)=1 then
  wielkosc:=dbms_lob.getlength(plik);
  insert into obrazki values (moja.nextval,bl) returning nr, obrazek into nr, bl;
  dbms_lob.open(plik,dbms_lob.lob_readonly);
  dbms_lob.open(bl,dbms_lob.lob_readwrite);
  dbms_lob.loadfromfile(bl,plik, wielkosc);
  dbms_lob.close(bl);
  dbms_lob.close(plik);


  commit;
  dbms_output.put_line('plik znalazl się w tabeli pod numerem '||nr||', zajmuje '||wielkosc||' bajtow');
else dbms_output.put_line('nie znalazlem takiego pliku...'); 
end if;
end;



Pliki ładujemy do formatu BLOB za pośrednictwem formatu BFILE. Taka już uroda tego RDBMS...
Najpierw sekcja deklaracji.
plik bfile; - to będzie referencja do naszego pliku , zmienna plik będzie pośrednikiem w ładowaniu. Musi być typu bfile.
bl blob:=empty_blob(); - typ BLOB jest typem obiektowym, musimy więc użyć konstruktora do zainicjalizowania obiektu.

wielkosc number; - Do zmiennej wielkość trafi wielkość pliku w bajtach. Musisz mieć taką zmienną. Będzie niezbedna przy ładowaniu danych do  tabeli (przy procedure loadfromfile).

nr number; - nie jest konieczne, ja sobie taką zmienną zrobiłem by później do niej załadować wartość pod którą w kluczu głównym tabeli znajdzie się mój wiersz z obiektem blob.

Część wykonawcza:

plik:=bfilename('LOBY','obrazek3.jpeg'); - zmienną plik znanego już z artykułu poprzedniego typu danych bfile podpinamy pod istniejący plik. LOBY to alias katalogu (również omawiane w poprzednim rozdziale).

if dbms_lob.fileexists(plik)=1 - znane z poprzedniego rozdziału. Sprawdzam czy plik istnieje. Zwraca 1 albo 0.

wielkosc:=dbms_lob.getlength(plik); - znane z poprzedniego rozdziału. Pobieram wielkość pliku pod którego podpięta jest moja zmienna typu BFILE.

insert into obrazki values (moja.nextval,bl) returning nr, obrazek into nr, bl; - ładuję do tabeli na razie pusty obiekt BLOB, jednak jest on zwracany poprzez referencję. Taki wymóg konstrukcyjny...


dbms_lob.open(plik,dbms_lob.lob_readonly);
  dbms_lob.open(bl,dbms_lob.lob_readwrite);


Oba obiekty muszę otworzyć. Obiekt typu BFILE w trybie tylko do odczytu, obiekt BLOB w trybie do zapisu i odczytu.


  dbms_lob.loadfromfile(bl,plik, wielkosc); - Faktyczne ładowanie danych. Pierwszy parametr to zmienna typu BLOB (czyli obiekt docelowy) , druga to obiekt typu BFILE  (czyli obiekt źródłowy), trzecia to wielkość pliku który trzeba załadować. Czemu muszę mieć podpięty niejako "dwukrotnie" plik? Pamiętaj że BFILE trzymane są poza bazą a BLOB w niej.

  dbms_lob.close(bl);
  dbms_lob.close(plik);


Jak otworzyłem to muszę zamknąć. Jeśli tego nie zrobię to w końcu dostanę info że przekroczyłem dopuszczalną ilość otwartych referencji do plików.

commit; - Pamiętaj by zatwierdzić zapis. Dane generalnie po odpaleniu procedury loadfromfile znajdują się już w tabeli, niemniej jednak podlegają tranzakcyjności jak wszystkie inne dane.

 Możesz już korzystać ze swoich blobów :) Puść np. takie zapytanie:

select dbms_lob.getlength(obrazek) from obrazki;

 Generalnie  CLOBy ładuje się identycznie. Wszędzie gdzie tutaj wyżej pojawiło się BLOB, piszesz w to miejsce CLOB  :)

wtorek, 13 grudnia 2011

BFILE. Referencje do plików zewnętrznych w Oracle

Czołem,
dziś na tapetę bierzemy typ danych BFILE. Jest to typ służący do przetrzymywania referencji do plików przetrzymywanych poza bazą. Zapytacie , na co komu taki rodzaj danych skoro można przechowywać ścieżkę do pliku w zwykłym varcharze? BFile pozwoli nam np. sprawdzić czy plik istnieje, jaką ma wielkość , porównać dwa pliki.

Początek

Ponieważ BFile trzyma referencję do plików zewnętrznych, stwórz sobie najpierw katalog na dysku, a następnie wrzuć do niego parę plików (wszystko jedno jakich).











Mój katalog znalazł się pod ścieżką "C:\loby".  Następnie {!} z poziomu sysa {!} tworzymy sobie obiekt directory który pozwoli nam na dostęp do tego katalogu z poziomu Oracle. Należy też nadać uprawnienia do korzystania z tego katalogu użytkownikowi z poziomu którego mamy zamiar z tych plików korzystać:

create directory loby as 'c:\loby';
grant read, write on directory loby to testowy;





Ja nadałem uprawnienia użytkownikowi "testowy", a mój katalog w Oracle będzie widoczny pod nazwą "loby".

Sprawdzanie czy plik istnieje

Teraz sprawdzę czy wskazany przeze mnie plik istnieje:




Declare
plik bfile;
Begin
Plik:=Bfilename('LOBY','oko.jpeg');
If Dbms_Lob.Fileexists(Plik)=1 Then
     Dbms_Output.Put_Line('jest taki plik!');
Else Dbms_Output.Put_Line('pliku niet!');
end if;
end;






Wykorzystałem tutaj procedurę fileexists z pakietu dbms_lob. Zwraca ona wartość 0 lub 1 w zależności od
tego czy plik istnieje czy nie. Funkcja (?) bfilename podpina referencję do pliku "oko.jpeg" znajdującego się w katalogu o aliasie "loby" (c:\loby) do na razie jeszcze pustej zmiennej plik. Pamiętać należy by alias katalogu podawać zawsze dużymi literami. Jak widzimy plik o który zapytałem istnieje.


Sprawdzanie wielkości

Poszerzmy teraz nasz test. Sprawdzimy , jeśli istnieje to jaką ma wielkość:




Declare
plik bfile;
Begin
Plik:=Bfilename('LOBY','oko.jpeg');
If Dbms_Lob.Fileexists(Plik)=1 Then
     Dbms_Output.Put_Line('jest taki plik!');
     Dbms_Lob.Fileopen(Plik);
     Dbms_Output.Put_Line('ten plik ma '||Dbms_Lob.Getlength(plik)||' bajtów');
     dbms_lob.fileclose(plik);
Else Dbms_Output.Put_Line('pliku niet!');
end if;
end;





Taki plik możemy otworzyć przy użyciu procedury fileopen z pakietu dbms_lob. Skoro otworzyliśmy to musimy go po wszystkim zamknąć  (dbms_lob.fileclose).
Do sprawdzenia wielkości służy nam procedura getlength z pakietu dbms_lob.
Gdyby Oracle rzucał nam wyjątkiem dotyczącym liczby otwartych plików, należy zmodyfikować parametr session_max_open_files określający ile możemy mieć jednocześnie podpiętych i otwartych plików w sesji.


Przechowywanie

Takie dane  (typu bfile) przechowywać mogę również w tabelkach. Na początek tworzymy sobie tabelkę z kolumną bfile. Przy okazji tworzę też sekwencję która będzie mi za moment potrzebna. Tych dla których pojęcie sekwencji jest nowością odsyłam do rozdziału "sekwencje" w znajdującym się na tej stronie kursie SQL.

Create Table Obrazki (
Nr Number Primary Key,
obrazek bfile
);

Create Sequence Moja
Start With 1 Increment By 1;







Dalej dodaję wiersze do tej tabeli:


insert into obrazki values (moja.nextval, bfilename('LOBY','aniol.jpg') );
insert into obrazki values (moja.nextval, bfilename('LOBY','smerfy.jpg') );
commit;





Na podobnej zasadzie odbywa się update - muszę wykorzystać poznaną już w tym rozdziale funkcję (?) bfilename.
Jeśli na takiej tabeli wykonam select , niewiele uzyskam informacji:




Mogę jednak posługując się funkcjami z pakietu dbms_lob poszerzyć swój zasób wiedzy np.
dowiadując się jaką ma wielkość:








BFILE w PLSQL i sprawdzanie ścieżki

Przy użyciu PL/SQL również mogę obsługiwać taki typ danych. Poszerza to również możliwości o weryfikację nazwy pliku i aliasu katalogu w którym znajduje się plik:



declare
plik bfile;
nazwapliku varchar2(50);
katalog varchar2(50);
begin
select obrazek into plik from Obrazki where nr=2;
dbms_output.put_line('wielkość pliku: '||Dbms_Lob.Getlength(plik));
dbms_lob.filegetname(plik,katalog,nazwapliku);
dbms_output.put_line('plik nazywa się: '||nazwapliku);
dbms_output.put_line('plik znajduje się w katalogu: '||katalog);
end;





Poszerza, ponieważ wykorzystuję procedurę filegetaname (która jest przecież procedurą więc nie mogę jej wykorzystywać w SQLu) która wykorzystuje parametry typu OUT. Zwraca do nich (nazwapliku,katalog) żądane informacje.  Zwracana jest nazwa aliasu, ale jeśli chcesz poznać dokładną ścieżkę to możesz przeszukać słownik all_directories w poszukiwaniu dokładnych informacji na temat danego katalogu.


cdn...