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 :
Zbiór bezpłatnych tutoriali związanych z bazami danych Oracle. Tutoriale po polsku. Autor : Andrzej Klusiewicz
wtorek, 20 grudnia 2011
Ł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 :)
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...
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...
Subskrybuj:
Posty (Atom)