plik


ÿþIDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ Oracle PL/SQL. SPIS TRE CI SPIS TRE CI Wprowadzenie KATALOG KSI¥¯EK KATALOG KSI¥¯EK Oracle PL/SQL. Wprowadzenie KATALOG ONLINE KATALOG ONLINE Autorzy: Bill Pribyl, Steven Feuerstein T³umaczenie: Bart³omiej Garbacz ISBN: 83-7197-727-1 ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG Tytu³ orygina³u: Learning Oracle PL/SQL Format: B5, stron: 412 TWÓJ KOSZYK Przyk³ady na ftp: 118 kB TWÓJ KOSZYK PL-SQL  jêzyk programowania systemu Oracle, przeznaczony do tworzenia procedur DODAJ DO KOSZYKA DODAJ DO KOSZYKA magazynowanych  zapewnia ogromne mo¿liwo ci pisz¹cym oprogramowanie baz danych. PL/SQL rozszerza standard jêzyka relacyjnych baz danych SQL poprzez umo¿liwienie korzystania z takich konstrukcji, jak: pêtle, instrukcje IF-THEN, z³o¿one CENNIK I INFORMACJE CENNIK I INFORMACJE struktury danych czy szerokie mo¿liwo ci kontroli operacji transakcyjnych. Wszystkie z nich s¹ ci le zintegrowane z serwerem bazy danych Oracle. ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWO CIACH O NOWO CIACH  Oracle PL/SQL. Wprowadzenie daje Czytelnikowi mo¿liwo æ pe³nego zrozumienia jêzyka PL/SQL bez wzglêdu na to, czy jest pocz¹tkuj¹cym, czy do wiadczonym ZAMÓW CENNIK programist¹. W niniejszej ksi¹¿ce przedstawiono nastêpuj¹ce zagadnienia: ZAMÓW CENNIK " cechy jêzyka PL/SQL i korzy ci wynikaj¹cych z jego u¿ywania; " sk³adnia i przyk³ady zastosowania wszystkich g³ównych konstrukcji jêzyka; CZYTELNIA CZYTELNIA " tworzenie i wykorzystywanie procedur, funkcji oraz pakietów magazynowanych; " tworzenie aplikacji opartych na sieci Internet; FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE " zabezpieczanie programów w jêzyku PL/SQL przed atakami z zewn¹trz; " korzy ci wynikaj¹ce z wykorzystania narzêdzi wspomagaj¹cych programowanie, pochodz¹cych od innych dostawców; " wykorzystanie jêzyka PL/SQL do programowania zadañ zwi¹zanych z u¿yciem poczty elektronicznej, jêzyka Java oraz sieci Internet.  Oracle PL/SQL. Wprowadzenie zawiera szczegó³owy opis konstrukcji jêzyka we wszystkich wersjach od Oracle7 do Oracle9i, podparty przyk³adami programów dostêpnych tak¿e pod adresem http://oracle.oreilly.com. Autorami jej s¹ eksperci jêzyka PL/SQL Bill Pribyl oraz Steven Feuerstein. Ksi¹¿ka daje solidne podstawy ka¿demu programi cie baz danych i administratorowi, który zmuszony jest do poznania jêzyka PL/SQL. Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: helion@helion.pl RozdziaB 1. Podstawy j¹zyka PL/SQL ........................................................................................................ 19 Zalety j¹zyka PL/SQL ............................................................................................................. 27 Wymagania dotyczce stosowania j¹zyka PL/SQL ................................................................ 33 RozdziaB 2. Podstawy skBadni ..................................................................................................................... 38 Pierwszy program w PL/SQL.................................................................................................. 40 Wprowadzenie do budowy programu...................................................................................... 44 Zmienne ................................................................................................................................... 48 Podstawowe operatory............................................................................................................. 56 Wyra|enia warunkowe ............................................................................................................ 63 Instrukcje wykonywania w p¹tlach ......................................................................................... 67 Formatowanie kodu: wymagania i wskazówki ....................................................................... 73 Podstawy bardziej zBo|onych zagadnieD ................................................................................. 75 RozdziaB 3. Informacje o programie przykBadowym .................................................................................. 81 Pierwsze zadanie programistyczne.......................................................................................... 83 Pobieranie informacji o liczbie ksi|ek za pomoc funkcji .................................................... 97 Tworzenie elastycznego kodu................................................................................................ 102 Wykorzystanie pakietów PL/SQL w celu organizacji kodu.................................................. 108 Przej[cie na wy|szy poziom .................................................................................................. 117 Dalsza droga .......................................................................................................................... 122 RozdziaB 4. Wprowadzenie do HTML...................................................................................................... 124 Tworzenie stron internetowych za pomoc j¹zyka PL/SQL ................................................. 134 Inne zagadnienia .................................................................................................................... 167 RozdziaB 5. Wprowadzenie ....................................................................................................................... 170 Prosta metoda: pobierania danych z jednego wiersza ........................................................... 170 Pobieranie wielu wierszy za pomoc kursora........................................................................ 172 Prezentowanie wyników zapytania na stronie WWW .......................................................... 184 Tworzenie strony WWW sBu|cej do wyszukiwania za pomoc mechanizmu dynamicznego SQL ..................................................................... 188 Zaawansowane zagadnienia zwizane z pobieraniem danych .............................................. 205 RozdziaB 6. Organizowanie kodu.............................................................................................................. 215 Narz¹dzia pomagajce w efektywnym programowaniu........................................................ 228 RozdziaB 7. Podstawy bezpieczeDstwa w systemie Oracle....................................................................... 246 Organizowanie kont w celu zwi¹kszenia poziomu zabezpieczeD ......................................... 255 Analiza wymagaD systemu bibliotecznego............................................................................ 267 Zledzenie zmian w bazie danych ........................................................................................... 273 Szczególne kwestie bezpieczeDstwa zwizane z programowaniem w PL/SQL ................... 281 RozdziaB 8. WysyBanie wiadomo[ci poczt elektroniczn za pomoc PL/SQL ....................................... 288 Wykorzystanie narz¹dzia sBu|cego do wysyBania wiadomo[ci elektronicznych w systemie bibliotecznym ................................................................................................... 293 Odbieranie wiadomo[ci z poziomu bazy danych .................................................................. 296 Pobieranie danych ze zdalnych stron internetowych............................................................. 305 Integracja z innymi j¹zykami programowania ...................................................................... 317 RozdziaB 9. Cykle istnienia oprogramowania ........................................................................................... 324 Listy obiektów (kolekcje) w j¹zyku PL/SQL ........................................................................ 326 Pakiety obsBugi wyjtków...................................................................................................... 339 Kontrola transakcji................................................................................................................. 343 Kompilator PL/SQL............................................................................................................... 349 Zarzdzanie uprawnieniami czytelników i bibliotekarzy...................................................... 352 Inne cechy PL/SQL................................................................................................................ 372 Programowanie a bazy danych .............................................................................................. 381 Fakty ...................................................................................................................................... 381 W niniejszym rozdziale omówiono nastpujce zagadnienia: " Informacje o programie przykBadowym " Pierwsze zadanie programistyczne " Pobieranie informacji o liczbie ksi|ek za pomoc funkcji " Tworzenie elastycznego kodu " Wykorzystanie pakietów PL/SQL w celu organizacji kodu " Przej[cie na wy|szy poziom " Dalsza droga Po zapoznaniu si¹ z podstawami j¹zyka PL/SQL Czytelnik jest przygotowany do tworzenia pro- gramów bardziej rozbudowanych ni| zwykBe wy[wietlanie komunikatu. W niniejszym rozdziale przedstawiono sposób rozpocz¹cia tworzenia aplikacji obsBugi katalogu biblioteki. W kolejnych cz¹- [ciach ksi|ki opisano sposób jej dalszej rozbudowy. Nowymi elementami j¹zyka PL/SQL, które przedstawiono w niniejszym rozdziale, s procedury (procedures), funkcje (functions) oraz pakiety (packages). Czytelnik dowie si¹, do czego te elementy sBu|, jak je konstruowa oraz w jaki spo- sób u|ywa w celu osigni¹cia wymaganych celów. PrzykBadowe zadanie programistyczne, opisane w niniejszej ksi|ce, polega na próbie utworzenia systemu, który sBu|yBby do katalogowania oraz wyszukiwania ksi|ek w bibliotece  jest to rodzaj elektronicznego katalogu. W przypadku tej hipotetycznej biblioteki zakBada si¹, |e wszelkie dane operacyjne znajduj si¹ w bazie danych Oracle. Istnieje wi¹cej ni| jeden sposób gromadzenia danych  dotyczcych tytuBów, autorów itp.  w bazie danych. Jednym z nich jest r¹czne wpisywanie danych przez bibliotekarza. W kolejnych rozdziaBach zostan opisane metody automatycznego Ba- dowania danych z odlegBych zródeB oraz metody wyszukiwania przez u|ytkownika danych znajduj- cych si¹ w katalogu. Istnieje konieczno[ speBnienia dwóch wymagaD o podstawowym znaczeniu dla dziaBania opisywa- nej aplikacji: " Nale|y umo|liwi tworzenie wpisów do katalogu dla ka|dej nowej ksi|ki. " Nale|y udost¹pni mo|liwo[ okre[lania liczby egzemplarzy danej ksi|ki, znajdujcych si¹ w zasobach biblioteki. W celu speBnienia pierwszego wymagania nale|y utworzy procedur¹ PL/SQL, sBu|c do wprowa- dzania danych do bazy danych. Program umo|liwiajcy speBnienie drugiego warunku wymaga za- stosowania funkcji PL/SQL. Przed opisaniem sposobu tworzenia tych elementów nale|y najpierw przedstawi metody projektowania struktury samej bazy danych. Podobnie jak w przypadku wi¹kszo[ci projektów tworzonych przez programistów PL/SQL, struktura bazy danych dotyczcych ksi|ek w bibliotece zostaBa wcze[niej zaprojektowana i utworzona na podstawie wymagaD postawionych przez przyszBego u|ytkownika. Podzbiór logicznego projektu bazy danych, zwizany ze wspomnianymi wcze[niej wymaganiami, mo|na ograniczy do infor- macji o ka|dym egzemplarzu ksi|ki w bibliotece. Rysunek 3.1 przedstawia tak zwany diagram zwizków encji (entity-relationship diagram, ERD). Rysunek 3.1. Zale|no[ midzy wpisem (informacj) dotyczcym ksi|ki a jej fizycznie istniejcymi egzemplarzami Diagramy takie w zwi¹zBej i uproszczonej formie prezentuj informacje o realnym [wiecie. Opisane w odpowiedni sposób prostokty s encjami (entities) bazy danych, a linie pomi¹dzy nimi ozna- czaj zwizki (relationships) pomi¹dzy encjami. Relacyjne bazy danych przedstawiaj rzeczywi- sto[ w formie zbioru struktur danych (które przechowuj informacje o pewnych obiektach) oraz zbio- ru metod (które definiuj powizania mi¹dzy obiektami). Encja book reprezentuje podstawowe informacje o ksi|ce (tytuB, autor itd.), które zawiera ka|da biblioteka. Encja book_copy zawiera informacje o fizycznie istniejcych egzemplarzach danej ksi|ki. Pewne zdziwienie mo|e wywoBa fakt, |e caBo[ rozdzielono na dwie encje zamiast u|ycia jednej. Wy- korzystanie tylko jednej encji spowodowaBaby jednak problemy w pózniejszym czasie, poniewa| wy- stpiBaby konieczno[ kopiowania informacji dotyczcych ksi|ki razem z informacjami dotyczcymi jej pojedynczych egzemplarzy, co z pewno[ci byBoby niewBa[ciwym sposobem wykorzystania zaso- bów komputera i wysiBku ludzkiego. PeBna dyskusja na temat normalizacji (normalization) baz danych (procesu organizowania danych w postaci tabel zgodnie z ich wewn¹trzn struktur) wykracza poza zakres tre[ci niniejszej ksi|ki. Warto jednak podkre[li, |e gBówna idea polega na przechowywaniu wa|nych informacji w jednym i tylko w jednym miejscu. Ka|dy kolejny egzemplarz danej ksi|ki wy- maga utworzenia jedynie dodatkowego rekordu zawierajcego identyfikator, który w powy|szym przy- padku jest numerem identyfikacyjnym pochodzcym z samoprzylepnej naklejki z kodem kreskowym. W tym miejscu nale|y wyja[ni znaczenie linii przedstawiajcych relacj¹, pokazan na rysunku 3.1. Z tre[ci tego rysunku wynikaj nast¹pujce fakty dotyczce realnej sytuacji: " Ka|dy egzemplarz danej ksi|ki jest egzemplarzem tyko jednej ksi|ki. " Ka|da ksi|ka mo|e posiada jeden lub wi¹ksz liczb¹ swoich egzemplarzy. Relacja taka jest znana jako relacja jeden-do-wielu (one-to-many relationship): jedna pozycja ksi|- kowa i wiele egzemplarzy danej ksi|ki. Fakty powy|sze wydaj si¹ by truizmem. Jednak przed przystpieniem do wBa[ciwego projektowa- nia bazy danych nale|y dokona analizy rozwizywanego problemu na takim wBa[nie, podstawowym poziomie. RozBo|enie informacji dotyczcych projektowanej aplikacji na szereg pozornie banalnych faktów i ustalenie wszystkich podstawowych zwizków pomi¹dzy jej elementami z pewno[ci uBatwi prac¹ podczas tworzenia kodu programu. Faktyczna struktura bazy danych odzwierciedla model zwizków encji  ka|da encja odpowiada ta- beli w bazie danych. Poni|ej przedstawiono kod w j¹zyku SQL, sBu|cy do utworzenia takiej tabeli: CREATE TABLE books ( isbn VARCHAR2(13) NOT NULL PRIMARY KEY, title VARCHAR2(200), summary VARCHAR2(2000), author VARCHAR2(200), date_published DATE, page_count NUMBER ); CREATE TABLE book_copies( barcode_id VARCHAR2(100) NOT NULL PRIMARY KEY, isbn VARCHAR2(13) NOT NULL, CONSTRAINT book_copies_isbn_fk FOREIGN KEY (isbn) REFERENCES books (isbn) ); Z powodów zrozumiaBych dla specjalistów od modelowania danych, encjom nadaje si¹ nazwy w for- mie rzeczowników w liczbie pojedynczej (book, book_copy), natomiast tabelom  w liczbie mnogiej (books, book_copies). Ponadto warto wykona graficzn reprezentacj¹ tabeli  na rysunku 3.2 przedstawiono mo|liw posta zdefiniowanych tabel zapeBnionych pewnymi danymi. Zapoznawszy si¹ z danymi zawartymi w tabelach, Czytelnik z pewno[ci zwróciB uwag¹ na pewne problemy. PrzykBadowo, dane w kolumnie author s nieprawidBowe i nie jest mo|liwe poprawne przechowanie informacji o kilku autorach jednej ksi|ki. W dalszej cz¹[ci niniejszej ksi|ki zosta- nie opisany sposób poprawienia tych wad. Pierwszym, przykBadowym zadaniem b¹dzie utworzenie programu w j¹zyku PL/SQL, który posBu- |y do dodawania nowych ksi|ek do bazy danych. Oczywi[cie, zamiast takiego programu mo|na po prostu wykona instrukcj¹ INSERT (lub dwie takie instrukcje) j¹zyka SQL: Rysunek 3.2. PrzykBad danych w postaci relacyjnej, rozbitych na wiersze i kolumny INSERT INTO books (isbn, title, author) VALUES ('0-596-00180-0', 'Oracle PL/SQL. Wprowadzenie', 'Bill Pribyl, Steven Feuerstein'); W zwizku z powy|szym Czytelnik z pewno[ci zastanawia si¹ nad sensem tworzenia programu w j¹zyku PL/SQL. Nale|y zaBo|y, |e istnieje konieczno[ zapewnienia stosowania dwóch sposobów dodawania ksi- |ek do katalogu: po pierwsze w sposób interaktywny, poprzez r¹czne wpisanie danych, po drugie w sposób automatyczny, pobierajc informacje o ksi|ce z innej bazy danych. Nasuwa si¹ zatem py- tanie, czy w takiej sytuacji nale|y skopiowa instrukcje INSERT do dwóch programów. Jednak|e pózniej mo|e pojawi si¹ potrzeba napisania trzeciego programu, który dodawaBby informacje o ksi|- kach, przykBadowo, odczytujc je z pByty CD-ROM. A zatem nale|aBoby uwzgl¹dni kolejne ko- piowanie instrukcji INSERT. ZakBadajc jednak, |e zaistnieje potrzeba zmiany struktury tabel, trzeba by wówczas wszystkie dotd utworzone programy oddzielnie uaktualni. Istnieje kilka powodów, dla których instrukcje INSERT warto umie[ci w programie PL/SQL. Poni- |ej wymieniono najwa|niejsze z nich: " Umo|liwia to ograniczenie, a nawet wyeliminowanie m¹czcej pracy zwizanej z aktualizacj oprogramowania po zmianie struktury bazy danych, podczas wykonywania której istnieje mo|liwo[ popeBniania bB¹dów. " Pozwala to na zwi¹kszenie wydajno[ci dziaBania serwera bazy danych. " Pozwala to umie[ci rozwizanie problemu programistycznego w tylko jednym miejscu. Tworzenie poprawnych instrukcji w j¹zyku SQL mo|e wymaga interpretowania oraz zapisywa- nia w formie kodu wielu skomplikowanych reguB zarzdzania. Ewentualna konieczno[ dokonania zmian we wszystkich napisanych programach oddzielnie oznacza bezzasadne marnotrawstwo cza- su i wysiBku. Ogólna zasada mówi, |e: Instrukcje SQL nale|y umieszcza w jednym, mo|liwym do wielokrotnego wykorzystania, programie napisanym w jzyku PL/SQL, a nie kopiowa je w wielu aplikacjach. Nawet je[li Czytelnik jest jedynym programist w swoim miejscu pracy, powinien trzyma si¹ tej zasady. Nie ogranicza si¹ ona zreszt tylko do wykorzystania j¹zyka SQL  wszelkie zadania programistyczne powinno si¹ zapisywa tylko raz, a potem w razie konieczno[ci jedynie wykonywa odpowiedni program. Przez definiowanie czynno[ci wykonywanych przez ka|d jednostk¹ progra- mu, któr mo|na wielokrotnie wywoBywa, mo|na utworzy wBasny interfejs tworzenia oprogramo- wania (application programming interface, API). Tak prosty, jak to mo|liwe, ale nie prostszy Prawdziwy bibliotekarz uznaBby niniejszy model za banalnie prosty, nawet nie biorc pod uwag nie uwzgldnionych w nim kwestii zwizanych z czytelnikami, operacjami wypo|yczenia/ oddawania i kupowania ksi|ek. W rzeczywisto[ci funkcjonowanie biblioteki jest znacznie bar- dziej skomplikowane: " Poza przechowywaniem ksi|ek biblioteki magazynuj tak|e gazety i czasopisma, nagrania muzyczne i kasety wideo. " Wiele dzieB, na przykBad starsze ksi|ki, nie posiada numeru ISBN (International Standard Book Number), co ogranicza jego zastosowanie jako jednoznacznego identyfikatora. " DzieBa mog mie ró|ne tytuBy i wielu autorów. " Nale|y przechowywa o wiele wicej informacji: o dziaBach, wydawcach, ilustratorach, wydaniach, dzieBach wielotomowych i pochodnych. " Biblioteki zazwyczaj udostpniaj sobie nawzajem swoje katalogi drog elektronicznej wymiany. Podobnych przykBadów jest wicej, dlatego nale|y wyja[ni powody uwzgldnienia w niniejszej ksi|ce tak prostego przykBadu. Wykonanie bazy danych, której schemat pokazano na rysunku 3.1, w zasadzie jest zbyt skom- plikowanym zadaniem dla zupeBnie pocztkujcych programistów. Relacja jeden do wielu stanowi podstaw wikszo[ci aspektów projektowania baz danych (tyle |e w realnych sytuacjach chodzi o wiele takich relacji) oraz programowania w jzyku PL/SQL. W dalszej cz[ci niniejszej ksi|ki zostanie opisany sposób rozszerzania funkcjonalno[ci projektowanej bazy danych, a tak|e spo- soby wykorzystania PL/SQL w bardziej  realnych zadaniach. Innym powodem wprowadzenia pewnych uproszczeD jest fakt, |e nauka nowego materiaBu przychodzi najBatwiej, je[li mo|na studiowa jedno zagadnienie w jednym czasie. W przeciwnym razie nauka przychodzi du|o trudniej. W niniejszym rozdziale przedstawiono informacje o sposobach lokalizowania kodu SQL (stosowanie kodu w jednym miejscu) za pomoc obwolut tabel (table wrappers), które s programami odpo- wiedzialnymi za wszelkie operacje zmiany zawarto[ci ka|dej z tabel bazy danych. Zapewne wi¹kszo[ programistów, niezale|nie od stopnia zaawansowania, odczuwa niepewno[ w sytuacji, gdy ma napisa program od podstaw. Z reguBy w takiej sytuacji mo|na rozpocz prac¹ od przerabiania ju| istniejcych lub przykBadowych programów. W tym przypadku zostanie przed- stawiony sposób tworzenia programu od samego pocztku, ale prawdopodobnie Czytelnik rzadko b¹dzie do tego zmuszony. Godnym polecenia zwyczajem jest rozpocz¹cie tworzenia programu od narysowania schematu. Ry- sunek 3.3 przedstawia mo|liw reprezentacj¹ graficzn omawianego programu oraz jego danych wej- [ciowych i wyj[ciowych. Rysunek 3.3. Schemat programu sBu|cego do dodawania ksi|ek do bazy danych W przeciwieDstwie do wcze[niej prezentowanego diagramu zwizków i encji, powy|szy diagram nie zostaB skonstruowany zgodnie z jakimi[ zasadami projektowania. Najwa|niejsz rzecz jest przedstawienie najbardziej znaczcych elementów. Z powy|szego rysunku wynika, |e trzeba skon- struowa program zdolny do pobierania pewnych informacji, a nast¹pnie do umieszczania ich w ta- belach bazy danych. Cho zapewne nie jest to oczywiste, uwzgl¹dniono mo|liwo[ poszerzenia funk- cjonalno[ci aplikacji w przyszBo[ci. Ogólnie rzecz biorc, jednostka programu powinna sBu|y do wykonania jednego, konkretnego zadania i nale|y zapewni prawidBowe dziaBanie tej jednostki w swoim zakresie. Wskazane jest, aby miaBa on niewielki rozmiar  uBatwi to jej zapis i pózniejsze modyfikacje. Trzeba jeszcze znalez odpowiedz na pytanie, jakiej konstrukcji j¹zyka PL/SQL nale|aBoby u|y w celu zdefiniowania operacji dodawania ksi|ki add_book. Z uwagi na fakt, |e program nie b¹- dzie zwracaB |adnej warto[ci, najbardziej rozsdnym rozwizaniem jest zastosowanie procedury. W tym podrozdziale zostanie przedstawiony sposób napisania procedury, która ma wstawia infor- macje na temat danej ksi|ki do bazy danych. Procedura taka mo|e by nazwana obwolut. Mo|na te| powiedzie, u|ywajc terminologii pochodzcej z j¹zyka greckiego, |e b¹d wykorzystywane abstrakcje (abstraction), procesy enkapsulacji (encapsulation) oraz ukrywania informacji (informa- tion hiding)  definicje wymienionych poj¹ znajduj si¹ w SBowniczku. Na rysunku 3.4 przedsta- wiono wi¹cej szczegóBów dotyczcych takiego rozwizania. Rysunek 3.4. Jedynie z poziomu programu PL/SQL bdzie mo|liwe dodawanie informacji o ksi|ce do bazy danych U|ytkownicy gotowego programu nie musz wiedzie na jego temat zbyt wiele, jednak twórca danej aplikacji musi z pewno[ci posiada gruntown wiedz¹ dotyczc struktury bazy danych. Dlatego te| pierwsz rzecz, jak nale|y wykona, jest okre[lenie tabel i ich kolumn zwizanych z procesem wykonania reguBy zarzdzania (w tym przypadku  dodania ksi|ki). Trzeba odpowiedzie sobie na pytanie, jakie informacje s potrzebne do manipulowania zawarto[ci tych tabel. W celu okre[lenia istotnych dla wykonania planowanej operacji tabel i kolumn trzeba przyjrze si¹ projektowi bazy danych (przedstawionemu we wcze[niejszej cz¹[ci niniejszego rozdziaBu). List¹ tych kolumn mo|na z Batwo[ci utworzy za pomoc instrukcji DESCRIBE, dost¹pnej w SQL*Plus (w for- mie skróconej DESC): SQL> DESC ksiazki Name Null? Type -------------------------------------------- -------- ----------------------- ISBN NOT NULL VARCHAR2(13) TITLE VARCHAR2(200) SUMMARY VARCHAR2(2000) AUTHOR VARCHAR2(200) DATE_PUBLISHED DATE PAGE_COUNT NUMBER SQL> DESC egzemplarze_ksiazki Name Null? Type -------------------------------------------- -------- ----------------------- BARCODE_ID NOT NULL VARCHAR2(100) ISBN VARCHAR2(13) Po przeanalizowaniu listy kolumn mo|na przyj, |e wi¹kszo[ zawartych w nich informacji powin- na by znana osobie wykonujcej katalogowanie i dlatego nie trzeba niczego syntetyzowa, spraw- dza lub oblicza. Procedura b¹dzie wi¹c bardzo prosta. Podstawowym problemem do rozwizania jest podj¹cie decyzji, czy u|ytkownik b¹dzie wstawiaB dane do obydwóch tabel jednocze[nie, czy te| oddzielnie. Na tym etapie pracy odpowiedz na to pytanie jest jeszcze nieznana. Najprawdopodobniej w bibliotekach odbywa si¹ to w ten sposób, |e informacje o ksi|kach s dodawane do bazy danych w momencie pojawienia si¹ pierwszego eg- zemplarza. Dlatego te| podczas dodawania danej ksi|ki po raz pierwszy wszystkie informacje wymagane dla wypeBnienia obydwóch tabel s od razu znane: od numeru ISBN po identyfikator kodu kreskowego. Jednak istnieje tak|e konieczno[ katalogowania nowych egzemplarzy ksi|ki ju| znajdujcej si¹ w zbiorach biblioteki  t¹ potrzeb¹ równie| nale|y uwzgl¹dni podczas pla- nowania programu. Rozpoczynajc opracowywanie nowego projektu wielu programistów zapisuje tzw. pseudokod w postaci zwykBych zdaD, które opisuj z grubsza dziaBanie programu. W tym przypadku mo|na by napisa: Sprawdz, czy dane wej[ciowe s prawidBowe. Wstaw nowy rekord do tabeli "books". Wstaw nowy rekord do tabeli "book_copies". Kolejnym etapem b¹dzie przedstawienie skBadni konstrukcji j¹zykowych potrzebnych do utworze- nia procedury. Nast¹pnie zapisany pseudokod zostanie zamieniony na konkretne instrukcje. Poni|ej znajduje si¹ opis ró|nych cz¹[ci skBadowych procedury. Zazwyczaj procedury tworzy si¹ za pomoc instrukcji o nast¹pujcej skBadni: CREATE [ OR REPLACE ] PROCEDURE nazwa_procedury (parametr1 TRYB TYP_DANYCH [ DEFAULT wyra|enie ], parametr2 TRYB TYP_DANYCH [ DEFAULT wyra|enie ], ...) AS [ zmienna1 TYP_DANYCH; zmienna2 TYP_DANYCH; ... ] BEGIN instrukcje_wykonawcze [ EXCEPTION WHEN nazwa_wyjtku THEN instrukcje_wykonawcze ] END; / Powy|szy wzorzec zawiera kombinacj¹ sBów kluczowych j¹zyka PL/SQL (pisane du|ymi literami i nie kursyw) oraz wyra|eD do zastpienia (pisane kursyw) w kodzie tworzonego programu. CREATE [ OR REPLACE ] Jest to szczególna instrukcja SQL, sBu|ca do utworzenia procedury. Fraza OR REPLACE (lub zastp) jest opcjonalna i pozwala na unikni¹cie konieczno[ci usuwania ju| istniejcej procedury w przypadku tworzenia jej nowej wersji. Zastosowanie wyra|enia OR REPLACE zachowuje tak|e wszelkie synonimy (synonyms) oraz granty (grants), jakie zostaBy uprzednio utworzone, a s zale|ne od dziaBania procedury. Jest to du|a zaleta. PROCEDURE nazwa_procedury W sekcji nagBówka podaje rodzaj tworzonej jednostki programowej (w tym wypadku  procedura) oraz nadaje si¹ jej nazw¹. parametr1 TRYB TYP_DANYCH [ DEFAULT wyra|enie ] Aby umo|liwi u|ytkownikowi podawanie parametrów wywoBania procedury, nale|y utworzy list¹ definicji parametrów oddzielonych przecinkami, a caB list¹ obj w nawiasy. TRYB mo|e mie warto[: IN, OUT lub IN OUT. Poni|ej znajduje si¹ opis wszystkich opcji. IN SBowo kluczowe oznaczajce tryb tylko do odczytu. WywoBujcy procedur¹ podaje warto[ parametru, a PL/SQL nie pozwala na jej zmian¹ wewntrz programu. OUT SBowo kluczowe oznaczajce tryb tylko do zapisu. Oznacza to, |e procedura nadaje parametrowi pewn warto[, która jest odczytywana przez program wywoBujcy. Podanie jakiejkolwiek warto[ci takiego parametru podczas wywoBania procedury jest ignorowane. IN OUT SBowo kluczowe oznaczajce tryb do odczytu lub zapisu. SBowo to jest u|ywane w sytuacji, gdy warto[ zmiennej, przekazywanej do procedury jako parametr, ma by zarówno odczytywana, jak i zmieniana, a nast¹pnie zwracana do programu wywoBujcego. TYP_DANYCH Znaczenie tego parametru przedstawiono w rozdziale 2.  dopuszczalnymi warto[ciami s na przykBad: NUMBER, INTEGER, VARCHAR2, DATE. Jedyna ró|nica polega na tym, |e w tym miejscu nale|y poda jedynie rodzaj typu, bez jego dokBadnej specyfikacji. Innymi sBowy, nale|y u|y VARCHAR2 zamiast VARCHAR2(30) i NUMBER zamiast NUMBER(10,2). DEFAULT wyra|enie Pozwala na przypisanie parametrowi warto[ci domy[lnej w przypadku, gdy wywoBanie procedury jej nie okre[la. Mo|na tak|e u|y symbolu  := (dwukropek i znak równo[ci) zamiast sBowa kluczowego DEFAULT. AS SBowo kluczowe AS oddziela nagBówek od reszty jednostki programowej. Opcjonalnie mo|na u|y sBowa kluczowego IS, które jest równowa|ne AS. BEGIN..END SBowa BEGIN i END oddzielaj zwykBe, czyli wykonawcze instrukcje od reszty programu. EXCEPTION Oznacza pocztek kodu obsBugi wyjtku  tej cz¹[ci programu, która jest wykonywana tylko w przypadku przechwycenia wyjtku w sekcji wykonawczej. Wszystkie elementy umieszczone po sBowie kluczowym EXCEPTION i przed instrukcj END s cz¹[ci obsBugi wyjtku. WHEN nazwa_wyjtku THEN instrukcje_wykonawcze Mo|liwym do wystpienia sytuacjom bB¹dnego dziaBania programu zazwyczaj s nadawane nazwy  albo przez system Oracle, albo przez programist¹. Dzi¹ki temu mo|na w kodzie programu zapisa instrukcje  wychwytujce te sytuacje i umo|liwi odpowiedni na nie reakcj¹, któr jest wykonanie pewnego fragmentu kodu. Je[li taka nazwa jest nieznana lub w celu wychwytywania bB¹dów, które nie zostaBy nazwane, mo|na posBu|y si¹ sBowem OTHERS, które dotyczy wszystkich sytuacji wyjtkowych. W zapisie wygldaBoby to nast¹pujco: WHEN OTHERS THEN.... Pewne elementy kodu procedury s opcjonalne. Najprostsza, mo|liwa do utworzenia procedura po- siada nast¹pujc form¹: CREATE PROCEDURE nie_rob_nic AS BEGIN NULL; END; Z powy|szego wynika, |e parametry, zmienne i kod obsBugi wyjtków s opcjonalne. SBowo kluczowe NULL zostaBo tutaj zastosowane jako instrukcja wykonawcza. Oznacza ona tyle, co  nie rób nic . Korzystajc z potrzebnych elementów podanego wcze[niej wzorca mo|na zapisa pseudokod w for- mie prawdziwego kodu: CREATE OR REPLACE PROCEDURE add_book (isbn_in IN VARCHAR2, barcode_id_in IN VARCHAR2, title_in IN VARCHAR2, author_in IN VARCHAR2, page_count_in IN NUMBER, summary_in IN VARCHAR2 DEFAULT NULL, date_published_in IN DATE DEFAULT NULL) AS BEGIN /* sprawdzenie poprawno[ci danych wej[ciowych */ IF isbn_in IS NULL THEN RAISE VALUE_ERROR; END IF; /* wstawienie rekordu do tabeli "books" */ INSERT INTO books (isbn, title, summary, author, date_published, page_count) VALUES (isbn_in, title_in, summary_in, author_in, date_published_in, page_count_in); /* je[li to konieczne, wstawienie rekordu do tabeli "book_copies" */ IF barcode_id_in IS NOT NULL THEN INSERT INTO book_copies (isbn, barcode_id) VALUES (isbn_in, barcode_id_in); END IF; END add_book; / Poni|ej znajduje si¹ opis dziaBania utworzonej procedury. Nazwa procedury i kolejno[ parametrów. Nazw procedury jest wyra|enie czasownikowe, które opisuje dziaBanie tej procedury. Podano tu tak|e parametry wej[ciowe  na ka|d z kolumn tabel, do których maj by wprowadzane dane, przypada jeden parametr. W celu wyeksponowania naj- wa|niejszych parametrów (isbn_in czy barcode_id_in) oraz w celu umieszczenia parame- trów o warto[ciach domy[lnych na koDcu, zmieniono nieco ich kolejno[ w odniesieniu do kolej- no[ci kolumn w tabelach. Nazwy parametrów. Warto przyj pewn konwencj¹ nazewnictwa w programowaniu i do nazw parametrów doda si¹ nazw¹ ich trybu (IN, OUT lub IN OUT). Poniewa| wszystkie parametry procedury add_book s parametrami w trybie IN, ich nazwy zawieraj koDcówk¹ _in. Taka konwencja nadawania nazw nie jest obowizkowa, ale jest pomocna w unikaniu konfliktów z na- zwami kolumn podczas u|ywania instrukcji SQL. Gdyby pozostaBy one identyczne, otrzymana in- strukcja miaBaby nast¹pujc posta: INSERT INTO book_copies (barcode_id, isbn) VALUES (barcode_id, isbn); W takim przypadku odró|nianie nazwy kolumn od nazw zmiennych podczas odczytywania kodu mogBoby okaza si¹ problematyczne nawet dla do[wiadczonego programisty. Jednak|e sama in- strukcja zostaBaby wykonana prawidBowo, gdy| PL/SQL zinterpretowaBby wszystko nast¹pujco: INSERT INTO book_copies (barcode_id, isbn) /* nazwy kolumn */ VALUES (barcode_id, isbn); /* zmienne PL/SQL */ Jednak|e instrukcja: UPDATE ksiazki SET summary = summary /* BBd! */ WHERE isbn = isbn; /* Nie wolno tak robi! */ nie zostanie wykonana prawidBowo. PL/SQL zinterpretuje ka|de wystpienie summary oraz isbn jako nazwy kolumn. Weryfikacja danych wej[ciowych. Zapis pierwszej linii zaprezentowanego wcze[niej pseudoko- du mówiB:  Sprawdz, czy dane wej[ciowe s prawidBowe . Konieczne jest jednak podj¹cie jeszcze kilku ustaleD. PrzykBadowo, mo|na zaBo|y, |e u|ytkownicy systemu b¹d domaga si¹ minimalnych wymagaD ze strony procedury w momencie jej wywoBywania. Mo|e to oznacza, |e jedynym ab- solutnie wymaganym parametrem tworzonej procedury jest ISBN. Std te| sekcja weryfikacji da- nych wej[ciowych zostaBa zapisana jako: IF isbn_in IS NULL THEN RAISE VALUE_ERROR; END IF; Bez dokBadniejszej znajomo[ci powy|szych identyfikatorów nie jest mo|liwe przeprowadzenie bar- dziej wymy[lnej weryfikacji poprawno[ci danych wej[ciowych. Przedstawiony wy|ej fragment kodu oznacza, |e brak ISBN powoduje zatrzymanie wykonywania programu. W dalszej cz¹[ci kodu jest tak|e wykonywane sprawdzenie kodu kreskowego. Program zostaB skon- struowany w ten sposób, aby unikn wykonania niepoprawnej instrukcji INSERT, co spowodo- waBoby bBd. W rozdziale 2. wyja[niono, |e w razie wystpienia bB¹du PL/SQL zatrzymuje wykonywanie progra- mu za pomoc mechanizmu zwanego przechwytywaniem wyjtku (raising an exception). Jak wy- nika z rysunku 3.5, instrukcja: RAISE VALUE_ERROR zatrzymuje wykonywanie instrukcji sekcji wykonawczej i przekazuje sterowanie do kodu obsBugi wyjtku. Je[li taki kod nie istnieje, wyjtek zwraca pewien bBd do programu wywoBujcego, a ten reaguje w okre[lony przez programist¹ sposób. Rysunek 3.5. Prosty przykBad obsBugi wyjtku Wyjtek VALUE_EXCEPTION nale|y do grupy wyjtków wewn¹trznych, które w pewnych sytu- acjach s przechwytywane przez system Oracle. Program wywoBujcy procedur¹ add_book po- winien umo|liwia obsBug¹ wszelkich mo|liwych do przewidzenia wyjtków i na podstawie infor- macji dotyczcych napotkanego bB¹du zdecydowa o dalszym funkcjonowaniu programu. W tym przypadku po|danym dziaBaniem byBoby przerwanie procesu dodawania do bazy danych niekom- pletnych informacji. Najlepiej byBoby, gdyby program wywoBujcy zwracaB u|ytkownikowi infor- macj¹ o bB¹dzie. By mo|e Czytelnik zastanawia si¹ na celowo[ci podejmowania takich dziaBaD zamiast, przykBa- dowo, umo|liwienia samej procedurze add_book wy[wietlania komunikatu o napotkanym bB¹- dzie. Celowo[ u|ycia mechanizmu wyjtków staje si¹ jasna po u[wiadomieniu sobie, |e przeka- zanie obsBugi sytuacji wyjtkowych do procedury ograniczyBoby w znacznym stopniu mo|liwo[ci jej ponownego wykorzystania. Je[li procedura add_book obsBuguje wyjtek i wy[wietla komunikat o bB¹dzie, niemo|liwe jest wykorzystanie jej przez program, dla którego dziaBania takie komuni- katy s niewskazane. PrzykBadowo, mo|na zaBo|y istnienie programu, który odczytuje informacje o ksi|kach z pliku i jednorazowo wprowadza do bazy danych informacje dotyczce tysi¹cy ksi|ek. Program ten ma wywoBywa procedur¹ add_book dla ka|dej kolejnej pozycji i w razie wyst- pienia bB¹du zapami¹ta informacj¹ o jego przyczynie, nie przerywajc jednak swojego dziaBania, a| do zakoDczenia wprowadzania danych dotyczcych ostatniej ksi|ki. Dopiero wówczas mo|na by przedstawi u|ytkownikowi podsumowanie informacji o napotkanych problemach. Wykorzysta- nie procedury add_book w taki sposób jest mo|liwe jedynie poprzez propagacj¹ wyjtków na ze- wntrz  do programu wywoBujcego. Uogólniajc, je[li istnieje prawdopodobieDstwo napotkania przez program bB¹du, którego nie da si¹ naprawi w prosty sposób, nale|y zapewni mo|liwo[ przechwycenia wyjtku. W dalszej cz¹[ci niniejszej ksi|ki opisano wyjtki, które nale|y bra pod uwag¹. Je|eli weryfikacja poprawno[ci danych wej[ciowych przebiega pomy[lnie, program kontynuuje swoje dziaBanie wykonujc instrukcje INSERT j¹zyka SQL. Nie ma potrzeby zwracania jakichkolwiek danych do programu wywoBujcego. Jednak gdyby zaszBa taka konieczno[, mo|na uwzgl¹dni jedn z dwóch mo|liwo[ci: zastosowanie funkcji zamiast procedury lub wykorzystanie parametrów w trybie OUT. Wi¹cej informacji Czytelnik znajdzie w dalszej cz¹[ci niniejszego rozdziaBu. NajBatwiejszym sposobem wywoBania procedury z poziomu kodu PL/SQL jest napisanie jej nazwy wraz z potrzebnymi argumentami, umieszczonymi w nawiasach i oddzielonymi przecinkami: BEGIN nazwa_procedury (argument1, argument2, ...); END; PrzykBadowo, aby doda do katalogu now ksi|k¹, nale|y napisa: BEGIN add_book('1-56592-335-9', '100000001', 'Programowanie w Oracle PL/SQL', 'Feuerstein, Steven, Bill Pribyl', 987, 'Kompendium informacji o jzyku PL/SQL, ' || 'wraz z przykBadami i poradami na temat programowania.', TO_DATE('01-WRZ-1997','DD-MON-YYYY')); END; / Takie wywoBanie procedury spowoduje wstawienie po jednym rekordzie do tabel books oraz book_ copies. W powy|szym przykBadzie argumentami s tak zwane wyra|enia literalne, a PL/SQL przekazuje te warto[ci do programu jako parametry wej[ciowe1, zgodnie z ich kolejno[ci. Ozna- cza to, |e zazwyczaj warto[ci trzeba podawa w takiej samej kolejno[ci, w jakiej wyst¹puj parame- try w programie wywoBywanym. Informacje te przedstawiono w poni|szej tabeli: 1 Wyra|enie przekazywane przez program wywoBujcy nosi nazw¹ argumentu lub parametru aktualnego, podczas gdy zmienne zdefiniowane w nagBówku programu wywoBujcego s nazywane parametrami formalnymi lub po prostu parametrami. W tym kontek[cie  formalny oznacza  formujcy posta zmiennej. Pozycja Nazwa parametru Typ danych Warto[ u|yta w przykBadowym wywoBaniu parametru isbn_in '1-56592-335-9' 1 VARCHAR2 barcode_id_in '100000001' 2 VARCHAR2 title_in 'Programowanie w Oracle PL/SQL' 3 VARCHAR2 author_in 'Feuerstein, Steven, Bill Pribyl' 4 VARCHAR2 page_count_in 987 5 NUMBER summary_in 'Kompendium informacji o jzyku 6 VARCHAR2 PL/SQL wraz z przykBadami i poradami na temat programowania.' date_published_in TO_DATE('01-WRZ-1997','DD-MON-YYYY') 7 DATE Warto zwróci uwag¹, |e podane warto[ci s zgodne z typami danych, jakich wymaga procedura. Oznacza to, |e ka|demu parametrowi typu VARCHAR2 odpowiada cig znakowy, parametrowi typu NUMBER odpowiada seria cyfr. Czytelnik zapewne zauwa|yB, |e parametrowi typu DATE odpo- wiada warto[ o do[ dziwnym wygldzie. Parametr date_published_in wymaga podania warto[ci typu DATE systemu Oracle. W rze- czywisto[ci jest to seria bitów o skomplikowanym formacie wewn¹trznym  z pewno[ci nie jest to zwykle u|ywana kombinacja roku, miesica i dnia. Cz¹sto stosowan metod otrzymania takiej warto[ci jest wykorzystanie wewn¹trznej funkcji systemu Oracle o nazwie TO_DATE. Podczas wywoBywania tej funkcji nale|y poda dat¹, zapisan w formie cigu znakowego (w tym przypadku  '01-WRZ-1997'), oraz dodatkowy element, zwany mask formatu (format mask)  'DD- -MON-YYYY'. Funkcja TO_DATE próbuje dopasowa do siebie poszczególne elementy wyspecy- fikowanego cigu znaków z odpowiednimi elementami maski formatujcej. W przypadku pomy[l- nego wykonania funkcja TO_DATE zwraca warto[ binarn, któr system Oracle rozpoznaje jako warto[ typu DATE. W przeciwnym przypadku nast¹puje przechwycenie wyjtku. Wrómy do omawianego przykBadu: funkcja TO_DATE przekazuje wspomnian warto[ binarn jako argument do procedury add_book. Dla tej procedury sposób utworzenia warto[ci typu DATE jest bez znaczenia  bezpo[rednie podawanie warto[ci literaBów jest równie dobrym roz- wizaniem, co uwzgl¹dnienie wyniku dziaBania funkcji, takiej jak na przykBad TO_DATE. Zastosowanie funkcji TO_DATE nie zawsze jest konieczne, poniewa| system Oracle automatycznie podejmuje prób¹ konwersji cigu znakowego na dat¹. W sytuacji takiej trzeba opiera si¹ na domy[lnej masce formatu systemu Oracle, która mo|e zosta zmieniona przez administratora bazy danych. Zwi¹ksza to prawdopodobieDstwo wystpienia pewnych problemów, jak na przykBad interpretacja warto[ci roku (jaki rok jest oznaczony warto[ci '00'?). Ogólnie mo|na powiedzie, |e w celu konwersji na format daty systemu Oracle nale|y skorzysta z funkcji TO_DATE. Powy|szy fragment kodu zawiera argumenty podane w formie literaBów (literals), to znaczy z za- stosowaniem konkretnych warto[ci. Jest to dobry sposób w przypadku przeprowadzania testów, jednak|e podczas programowania w j¹zyku PL/SQL zazwyczaj u|ywa si¹ zmiennych w wywoBa- niach. Warto[ci zmiennych s zazwyczaj ustalane nie poprzez bezpo[redni zapis w kodzie programu, ale na przykBad przez u|ytkownika korzystajcego z klawiatury i ekranu, wy[wietlajcego odpowied- nie informacje. Warto si¹ zastanowi nad sposobem wywoBywania procedury w przypadku posiadania niepeBnej informacji dotyczcej dodawanej ksi|ki  na przykBad w przypadku braku daty wydania lub opisu. PrzykBadowo, w takim przypadku mo|na poda warto[ci NULL dla tych parametrów i sprawdzi, czy nie spowoduje to problemów z wykonywaniem programu:2 add_book('1-56592-335-9', '100000001', 'Programowanie w Oracle PL/SQL', 'Feuerstein, Steven, Bill Pribyl', 987, NULL, NULL); Jest to jedna z mo|liwo[ci. Mo|na tak|e w ogóle nie podawa warto[ci argumentów i oprze si¹ na warto[ciach domy[lnych. W tym przypadku b¹dzie to wywoBanie poprawne, gdy| w sekcji nagBów- kowej procedury dla dwóch ostatnich parametrów zdefiniowano warto[ci domy[lne: ...summary_in IN VARCHAR2 DEFAULT NULL, date_published_in IN DATE DEFAULT NULL); Warto[ci NULL w tym kontek[cie s w peBni poprawnymi warto[ciami. Korzystajc z warto[ci domy[lnych, mo|na przedstawione powy|ej wywoBanie upro[ci i pomin ostatnie dwa argumenty: add_book('1-56592-335-9', '100000001', 'Programowanie w Oracle PL/SQL', 'Feuerstein, Steven, Bill Pribyl', 987); W tym przypadku mechanizm odpowiedzialny za wykonanie kodu PL/SQL w miejsce brakujcych argumentów podstawi warto[ci domy[lne i wykonanie procedury odb¹dzie si¹ identycznie, jak we wcze[niejszym przypadku. Mo|liwo[ pomijania argumentów dla parametrów posiadajcych warto[ domy[ln jest niezwykle przydatn cech j¹zyka PL/SQL, poniewa| umo|liwia prawidBowe dziaBanie jednostki programowej nawet bez podania tych argumentów. Ponadto mechanizm ten mo|e w ogromnym stopniu zredukowa negatywny wpByw ewentualnych, przyszBych modyfikacji. PrzykBadowo, je[li zaistnieje potrzeba dodania do programu pewnych parametrów, to dzi¹ki zdefiniowaniu ich warto[ci domy[lnych nie b¹dzie trzeba przeglda caBego kodu, aby zmieni ka|de wyst¹pujce w nim wywoBanie. 2 Ze wzgl¹du na oszcz¹dno[ miejsca w niniejszej ksi|ce nie zawsze jest przedstawiany peBny kod programu. W tym przypadku nale|aBoby doda instrukcj¹ EXECUTE lub obj wywoBanie sBowami kluczowymi BEGIN i END oraz doda koDcowe  / w celu uruchomienia tej procedury z poziomu SQL*Plus. Warto te| wiedzie, |e wywoBujc procedur¹ mo|na jednocze[nie pomija parametry posiadajce warto[ci domy[lne oraz podawa warto[ci NULL: add_book('1-56592-335-9', '100000001', 'Programowanie w Oracle PL/SQL', NULL, 987); Czytelnik by mo|e ma pewne problemy z zapami¹taniem, która warto[ odpowiada któremu ar- gumentowi, ale jest to rzecz normalna w przypadku notacji pozycyjnej (positional notation), co ozna- cza konieczno[ podawania argumentów w takiej samej kolejno[ci, w jakiej zapisano dane parametry w kodzie programu. Rozwizaniem tych problemów mo|e by zastosowanie innego, bardzo u|ytecznego mechanizmu  notacji imiennej (named notation). Sposób dziaBania notacji imiennej najlepiej mo|na wyja[ni na przykBadzie. W przypadku poni|szego wywoBania procedury add_book wykorzystano wBa[nie ten mechanizm: add_book(isbn_in => '1-56592-335-9', title_in => 'Programowanie w Oracle PL/SQL', summary_in => 'Kompendium informacji o jzyku PL/SQL, ' || 'wraz z przykBadami i poradami na temat programowania.', author_in => 'Feuerstein, Steven, Bill Pribyl', date_published_in => NULL, page_count_in => 987, barcode_id_in => '100000001'); Z powy|szego wynika, |e dla ka|dego argumentu podaje si¹ nazw¹ parametru zdefiniowanego w pro- cedurze add_book, symbol => oraz warto[ danego parametru. Zalet tej metody jest to, |e po- szczególne argumenty mo|na podawa w dowolnej kolejno[ci  nie trzeba pami¹ta kolejno[ci, w jakiej zdefiniowano parametry w procedurze. Wybór metody caBkowicie zale|y od programisty  dla kompilatora jest to bez znaczenia. Argu- mentem przemawiajcym za stosowaniem notacji imiennej mo|e by fakt, |e w ten sposób kod staje si¹ du|o bardziej przejrzysty. Znaczenie wyra|enia page_count => 987 nie pozostawia wt- pliwo[ci, a na pewno nie jest tak w przypadku podania samej warto[ci 987. Mo|na tak|e, oczywi- [cie, pomija parametry opcjonalne (domy[lne)  w tym przypadku mo|e to by, przykBadowo, date_published_in: add_book(isbn_in => '1-56592-335-9', title_in => 'Programowanie w Oracle PL/SQL', summary_in => 'Kompendium informacji o jzyku PL/SQL, ' || 'wraz z przykBadami i poradami na temat programowania.', author_in => 'Feuerstein, Steven, Bill Pribyl', page_count_in => 987, barcode__is_in => '100000001'); Poza konieczno[ci pisania wi¹kszej ilo[ci kodu istnieje tak|e pewna niedogodno[, wynikajca ze stosowania tej notacji. W razie potrzeby zmiany nazwy parametru konieczne jest uaktualnienie nie tylko samej procedury, ale tak|e ka|dego jej wywoBania w notacjiimiennej. Z drugiej jednak stro- ny zmiana nazwy parametru jest raczej rzadko wykonywan operacj. Istnieje tak|e mo|liwo[ wykorzystania obydwóch notacji w jednym wywoBaniu. Nale|y pami¹ta jedynie o paru zasadach. Nale|y zacz od notacji pozycyjnej, a po przej[ciu do notacji imiennej trzeba przy niej pozosta do koDca. Oto przykBad: add_book('1-56592-335-9', '100000001', 'Programowanie w Oracle PL/SQL', summary_in => NULL, author_in => 'Feuerstein, Steven, Bill Pribyl', page_count_in => 987); U|ywanie notacji imiennej W razie konieczno[ci dokonania wyboru nale|y stosowa notacj wymieniajc wszdzie tam, gdzie znaczenie poszczególnych argumentów nie jest oczywiste. PrzykBadowo: uaktualnij_moj_profil(ulub_ksiazka_isbn => '1-56592-335-9'); Notacji pozycyjnej nale|y u|ywa w przypadku czsto u|ywanych programów u|ytkowych, które posiadaj jeden lub dwa parametry, a znaczenie tych parametrów jest oczywiste: DBMS_OUTPUT.PUT_LINE('Witaj Muddah.'); Zastosowanie obydwóch notacji mo|e okaza si przydatne w sytuacji, gdy na przykBad pierwszy argument jest oczywisty, za[ kolejne nie: moje_put_line('Witaj Fadduh.', linie_do_pominiecia => 2); W tym podrozdziale przedstawiono przykBad konstruowania i wykorzystywania procedury magazy- nowanej j¹zyka PL/SQL, która wykonuje pojedyncze zadanie. Zadanie to polega na dodaniu do bazy danych informacji o ksi|ce identyfikowanej za pomoc odpowiedniego kodu kreskowego. Kolej- ne zadanie polega na okre[leniu liczby egzemplarzy danej ksi|ki. Potrzeba pobierania informacji o takiej pojedynczej warto[ci stanowi idealn sposobno[ wykorzystania funkcji j¹zyka PL/SQL, która ze swej definicji zwraca jak[ warto[ (lub koDczy dziaBanie nie obsBu|onym wyjtkiem). Przed podj¹ciem próby zapisania kodu funkcji trzeba najpierw zapozna si¹ z ogóln skBadni two- rzenia funkcji. Funkcje stanowi drugi typ programów magazynowanych. Poni|ej przedstawiono wzorzec definiowania funkcji. Elementy, które oznaczono za pomoc czcion- ki pogrubionej, mog by jeszcze Czytelnikowi nieznane. CREATE [ OR REPLACE ] FUNCTION nazwa_funkcji (parametr1 TRYB TYP_DANYCH [ DEFAULT wyra|enie ], parametr2 TRYB TYP_DANYCH [ DEFAULT wyra|enie ], ...) RETURN TYP_DANYCH AS [ zmienna1 TYP_DANYCH; zmienna2 TYP_DANYCH; ... ] BEGIN instrukcje_wykonawcze; RETURN wyra|enie; [ EXCEPTION WHEN nazwa_wyjtku THEN instrukcje_wykonawcze ] END; / Ró|nice pomi¹dzy wzorcem dotyczcym funkcji i wzorcem procedury s minimalne. Poza zamian sBowa kluczowego PROCEDURE na FUNCTION w instrukcji CREATE, kod ró|ni si¹ tylko w dwóch miejscach. Pierwszym z nich jest nagBówek, gdzie podaje si¹ zwracany typ danych, a drugim jest cz¹[ wykonawcza, gdzie nast¹puje bezpo[rednie przekazanie zwracanej warto[ci do programu wy- woBujcego. RETURN TYP_DANYCH W nagBówku wyra|enie RETURN stanowi cz¹[ deklaracji funkcji. Jest to informacja o typie danych warto[ci, które maj by zwracane w wyniku wywoBania funkcji. RETURN wyra|enie Wewntrz sekcji wykonawczej wyra|enie RETURN jest instrukcj i oznacza, |e dziaBania zostaBy zakoDczone i |e nale|y zwróci (return) warto[, któr definiuje wyra|enie. Instrukcja RETURN mo|e znalez si¹ tak|e w sekcji EXCEPTION. Obydwie wymienione instrukcje s wymagane. W nast¹pnym podrozdziale przedstawiono kod go- towej funkcji. Funkcja book_copy_qty zwraca liczb¹ ksi|ek, których numer ISBN odpowiada podanemu. W poni|szym, przykBadowym kodzie funkcji do pobrania danych z bazy danych wykorzystano kursor (cursor). SzczegóBowe omówienie tej struktury znajduje si¹ dopiero w rozdziale 5. Uogólnia- jc, kursor jest okre[lonym miejscem w pami¹ci, do którego program mo|e przenie[ pewne dane po- brane z bazy danych. W sekcji deklaracji nast¹puje powizanie pewnej instrukcji SELECT z kur- sorem. Powizanie to zachodzi za pomoc instrukcji CURSOR. Warto zwróci uwag¹, |e parametr wej[ciowy isbn_in wyst¹puje po prawej stronie wyra|enia WHERE. W celu pobrania danych nale- |y kursor otworzy (open), pobra (fetch) z niego dane, a w koDcu go zamkn (close). CREATE OR REPLACE FUNCTION book_copy_qty(isbn_in IN VARCHAR2) RETURN NUMBER AS number_o_copies NUMBER := 0; CURSOR bc_cur IS SELECT COUNT(*) FROM book_copies WHERE isbn = isbn_in; BEGIN IF isbn_in IS NOT NULL THEN OPEN bc_cur; FETCH bc_cur INTO number_o_copies; CLOSE bc_cur; END IF; RETURN number_o_copies; END; / Konstrukcja funkcji niewiele odbiega od procedury. Ró|ni si¹ one jednak swoim zachowaniem  szczegóBy dotyczce dziaBania funkcji przedstawiono na rysunku 3.6. Rysunek 3.6. Wykorzystanie funkcji jzyka PL/SQL w celu zwrócenia pewnej warto[ci do programu wywoBujcego; dla danej warto[ci ISBN funkcja zwraca liczb egzemplarzy znajdujcych si w bazie danych Zasadnicza ró|nica pomi¹dzy wywoBaniem funkcji i procedury wynika z tego, |e funkcje zwracaj pewn warto[. Najprostszym sposobem wykorzystania warto[ci wynikowej, zwracanej przez funkcj¹, jest jej przy- pisanie do pewnej zmiennej, której typ odpowiada typowi zwracanej warto[ci. Zwykle wyglda to w nast¹pujcy sposób: DECLARE zmienna_lokalna TYP_DANYCH; BEGIN zmienna_lokalna := nazwa_funkcji (argument1, argument2, ...); END; / Jest to zatem typowa instrukcja przypisania, gdzie wywoBanie funkcji znajduje si¹ po prawej stronie operatora przypisania, a zmienna lokalna po lewej. Mo|na wi¹c napisa: DECLARE ile INTEGER; BEGIN ile := book_copy_qty('1.56592-335-9'); END; / Z informacji przedstawionych w rozdziale 1. wynika, |e w celu wy[wietlenia wyników na ekranie mo|na przekaza je do funkcji DBMS_OUTPUT.PUT_LINE: SET SERVEROUTPUT ON BEGIN DBMS_OUTPUT.PUT_LINE('Liczba kopii 1-56592-335-9: ' || book_copy_qty('1-56592-335-9')); END; / Funkcja book_copy_qty zwraca warto[ typu VARCHAR2, co umo|liwia konkatenacj¹ z innym cigiem znaków i u|ycie funkcji PUT_LINE. Takie zagnie|d|anie funkcji wewntrz innych in- strukcji jest cz¹sto stosowan technik. Poni|ej wymieniono kilka wartych zapami¹tania zasad dotyczcych wykorzystania funkcji: 1. Nie mo|na tworzy niezale|nych (standalone) funkcji o takich samych nazwach, jakie nosz niezale|ne procedury. Jednak|e przyj¹cie konwencji nazywania procedur wyra|eniem czasownikowym, a funkcji  wyra|eniem rzeczownikowym mo|e uchroni przed potencjalnymi problemami. 2. Nieuwzgl¹dnienie w nagBówku wyra|enia RETURN spowoduje, |e funkcja nie zostanie skompilowana. Jest to dziaBanie pozytywne, gdy| bB¹dy czasu kompilacji uwa|a si¹ za metod¹ wczesnego ostrzegania przed ewentualnymi problemami. Je[li jednak sBowo kluczowe RETURN zostanie pomini¹te w sekcji wykonawczej, system Oracle poinformuje o tym dopiero po uruchomieniu funkcji. Zostanie wtedy wygenerowany komunikat o bB¹dzie ORA-06503: PL/SQL: Function returned without value. Dlatego zawsze warto przeprowadza dogB¹bne testy napisanych programów. Procedury a funkcje Uogólniajc, funkcja sBu|y do przeprowadzenia pewnych operacji, których celem jest otrzyma- nie pewnej warto[ci. Oczywi[cie, jest mo|liwe wykorzystanie procedury zamiast funkcji i za- stosowanie pojedynczego parametru OUT, jednak takie postpowanie nie jest zalecane. Warto te| pamita, |e nie nale|y pisa programów, które zwracaj warto[ informujc o stanie zakoDczenia. Postpowanie takie jest uzasadnione w jzyku takim jak C, lecz w przypadku PL/SQL informowanie o bBdach powinno si odbywa poprzez przechwytywanie wyjtków. Je[li program magazynowany nie przechwyci wyjtku, zakBada si, |e podczas wykonania tego programu nie napotkano |adnych problemów. Czasami okazuje si, |e istnieje potrzeba zwrócenia wicej ni| jednej warto[ci  w takim przy- padku nale|y utworzy procedur. W celu zwrócenia wielu warto[ci trzeba wykorzysta kilka parametrów w trybie OUT lub IN OUT, których warto[ mo|e by odczytana przez program wywoBujcy po zakoDczeniu dziaBania procedury. Zdefiniowanie kilku parametrów w trybie OUT mo|e wprowadzi nieco zamieszania, jednak istnieje metoda zapisywania programów, któ- re musz zwraca wiksz ilo[ danych w bardziej czytelny sposób. Mo|na bowiem ró|ne ele- menty poBczy w jedn caBo[ przez zastosowanie jednego ze zBo|onych typów danych, jak na przykBad rekord, kolekcja lub tak zwany typ obiektowy. Zagadnienia te opisano w rozdziale 5. 3. Program wywoBujcy po wywoBaniu funkcji musi w jaki[ sposób wykorzysta zwrócon warto[, na przykBad przypisa j pewnej zmiennej. PL/SQL, w przeciwieDstwie do j¹zyka C, nie dopuszcza wywoBania funkcji i zignorowania zwracanej warto[ci. 4. Po wykonaniu instrukcji RETURN w sekcji wykonawczej do programu wywoBujcego zostaje przekazana nie tylko warto[, ale tak|e sterowanie wykonaniem programu. Innymi sBowy, kod zapisany po instrukcji RETURN nie jest wykonywany. Warto równie| zwraca uwag¹ na stosowan terminologi¹. Czasami, gdy kto[ mówi o  procedurach magazynowanych , naprawd¹ ma na my[li programy magazynowane, czyli albo procedury, albo funkcje. Z drugiej jednak strony, mo|e chodzi wBa[nie o procedury, nie za[ funkcje. Je[li ogólny kontekst rozmowy nie pozwala na rozpoznanie, o któr mo|liwo[ chodzi, z pewno[ci pro[ba o wyja[nienie nie b¹dzie objawem dyletanctwa. Powy|ej przedstawiono nast¹pujcy sposób wywoBania funkcji: DECLARE ile INTEGER; BEGIN ile := book_copy_qty('1-56592-335-9'); END; / WydawaBoby si¹, |e powy|szy kod mo|na zapisa w bardziej zwi¹zBy sposób poprzez wywoBanie funkcji podczas inicjalizacji zmiennej: DECLARE ile INTEGER := book_copy_qty('xyz'); BEGIN Z pozoru wszystko jest w porzdku. Jednak je[li funkcja przechwyci wyjtek, to okazuje si¹, |e |aden kod obsBugi wyjtku w tej sekcji nie zdoBa przechwyci wyjtku, który ewentualnie mo|e pojawi si¹ po takim wywoBaniu funkcji book_copy_qty. A zatem: DECLARE ile INTEGER := book_copy_qty('xyz'); BEGIN ...cokolwiek... EXCEPTION WHEN OTHERS THEN /* NIESPODZIANKA! Wyjtki przechwycone w sekcji deklaracji || NIE MOG by obsBu|one w tym miejscu! */ ... END; / WytBumaczenie powodu takiego zachowania wykracza poza zakres niniejszej ksi|ki. Dlatego nale|y po prostu zapami¹ta, |e nie nale|y dokonywa prób inicjalizowania zmiennych za pomoc funkcji. Z pewno[ci Czytelnik chciaBby kontynuowa rozwijanie tworzonej, przykBadowej aplikacji. Nie mo|na jednak zapomina o konsekwentnym upewnianiu si¹, |e zapisany od nie zawiera bB¹dów. Z tego te| wzgl¹du poni|ej zamieszczono pewnego rodzaju dygresj¹. Z pewno[ci ka|dy zetknB si¹ ju| z wyra|eniem garbage in, garbage out (GIGO). Jest to wyra|e- nie do[ cz¹sto u|ywane lub sByszane przez telefon podczas rozmowy z obsBug techniczn. Oznacza ono mniej wi¹cej tyle, co  wprowadzasz bB¹dne dane  uzyskujesz bB¹dne wyniki . Unikni¹cie problemu GIGO jest spraw do[ problematyczn. Istnieje tendencja do nieuzasadnione- go optymizmu w kwestii wykorzystywania utworzonych aplikacji. Ch¹tniej przyjmuje si¹ zaBo|enie tidy in, tidy out (wprowadzasz poprawne dane  uzyskujesz poprawne wyniki)3. Nikt nie lubi z góry planowa dziaBaD zapobiegawczych wzgl¹dem zastosowania niepoprawnych danych wej[ciowych. W celu unikni¹cia nieprzewidzianych zaBamaD programu trzeba przeprowadzi serie testów. Prze- prowadzenie dobrych testów oznacza generowanie przeró|nych kombinacji danych testowych, które potencjalnie powinny  zawiesi program. Potem nale|y sprawdzi oczekiwany wynik, uru- chomi program, porówna z danymi wyj[ciowymi, poprawi program i wreszcie& ponownie przeprowadzi testy. Z pewno[ci warto upro[ci ten caBy proces. Monotonne wykonywanie fragmentu kodu z ró|nymi danymi wej[ciowymi jest dobr okazj do na- pisania pewnych programów u|ytkowych. Poni|ej przedstawiono sposób zautomatyzowania tego m¹czcego procesu za pomoc takich programów. DziaBanie pierwszego, sprawdzajcego programu polega na porównywaniu dwóch warto[ci i wy[wie- tlaniu komunikatu o pomy[lnym lub niepomy[lnym przebiegu tego testu. U podstaw testowania le|y wBa[nie porównywanie warto[ci  warto[ci faktycznej ze spodziewan warto[ci wyj[ciow. Dlatego te| wspomniany program jest bardzo u|yteczny. ZawieraB on tak|e opis poszczególnych iteracji, tak aby umo|liwi otrzymanie informacji o tym, dla jakich warto[ci wykonanie programu b¹dzie niepomy[lne. Poni|ej znajduje si¹ kod tej procedury  test równo[ci (testrownosci): CREATE OR REPLACE PROCEDURE reporteq (description IN VARCHAR2, expected_value IN VARCHAR2, actual_value IN VARCHAR2) AS BEGIN DBMS_OUTPUT.PUT(description || ': '); IF expected_value = actual_value OR (expected_value IS NULL AND actual_value IS NULL) THEN DBMS_OUTPUT.PUT_LINE('PASSED'); 3 NieprzetBumaczalna gra sBów: garbage to po angielsku [mieci, bzdury; tidy  czysty, schludny  przyp. tBum. ELSE DBMS_OUTPUT.PUT_LINE('FAILED. Expected ' || expected_value || '; got ' || actual_value); END IF; END; / W powy|szej procedurze porównywaniu podlegaj cigi znaków (VARCHAR2), ale mo|na oczywi- [cie napisa analogiczne procedury obsBugujce liczby, daty czy te| warto[ci logiczne. Kolejnym krokiem b¹dzie napisanie programu wywoBujcego procedur¹ add_book na wiele spo- sobów  tak|e w razie zastosowania nieprawidBowych danych wej[ciowych. Poni|szy program ze wzgl¹du na jego obszerno[ (89 linii kodu) podzielono na fragmenty. Dodatkowo ponumerowano poszczególne linie w celu uBatwienia odwoBywania si¹ do nich. 1 DECLARE 2 l_isbn VARCHAR2(13) := '1-56592-335-9'; 3 l_title VARCHAR2(200) := 'Oracle PL/SQL Programming'; 4 l_summary VARCHAR2(2000) := 'Reference for PL/SQL developers, ' || 5 'including examples and best practice recommendations.'; 6 l_author varchar2(200) := 'Feuerstein, Steven, and Bill Pribyl'; 7 l_date_published DATE := TO_DATE('01-WRZ-1997', 'DD-MON-YYYY'); 8 l_page_count NUMBER := 987; 9 l_barcode_id VARCHAR2(100) := '100000001'; 10 11 CURSOR bookCountCur IS 12 SELECT COUNT(*) FROM books; 13 14 CURSOR copiesCountCur IS 15 SELECT COUNT(*) FROM book_copies; 16 17 CURSOR bookMatchCur IS 18 SELECT COUNT(*) FROM books 19 WHERE isbn = l_isbn AND title = l_title AND summary = l_summary 20 AND author = l_author AND date_published = l_date_published 21 AND page_count = l_page_count; 22 23 CURSOR copiesMatchCur IS 24 SELECT COUNT(*) FROM book_copies 25 WHERE isbn = l_isbn AND barcode_id = l_barcode_id; 26 27 how_many NUMBER; 28 l_sqlcode NUMBER; Poni|ej znajduje si¹ kilka wyja[nieD dotyczcych przedstawionego fragmentu kodu. Linie 2.  9. S to deklaracje zmiennych lokalnych, które reprezentuj warto[ci u|ywane w ró|nych testach. Przechowywanie tych warto[ci w zmiennych uBatwia programowanie z uwagi na mo|li- wo[ ich wielokrotnego u|ycia. Przedrostek l_ oznacza, |e s to zmienne lokalne. Linie 11.  12. Jest to deklaracja pierwszego z kursorów programu. Kursor umo|liwia pobieranie warto[ci z bazy danych za pomoc instrukcji j¹zyka SQL SELECT. Ta konkretna instrukcja oblicza caBkowit liczb¹ rekordów w tabeli ksiazki. Linie 14.  15. Jest to równie| deklaracja kursora programu  umo|liwia on obliczanie caBkowi- tej liczby egzemplarzy ksi|ki. Linie 17.  21. Ten kursor sBu|y do obliczania liczby ksi|ek, dla których warto[ci kolumn odpo- wiadaj warto[ciom zmiennych lokalnych. Linia 27. Zmienna lokalna ile przechowuje tymczasowo rezultat dziaBania powy|szych zapytaD. Linia 28. Zmienna l_sqlcode przechowuje tymczasowo warto[ wyj[ciow wewn¹trznej funk- cji PL/SQL  SQLCODE. Jej dziaBanie zostanie omówione nieco dalej. Poni|ej przedstawiono sekcj¹ wykonawcz omawianego programu. Rozpoczyna ona swoje dziaBa- nie od usuni¹cia zawarto[ci obydwóch tabel w bazie danych. W ten sposób uzyskuje si¹ pewno[, |e wszelkie operacje zliczania b¹d dotyczy jedynie bie|cych danych testowych, a nie innych, które mogBy pozosta po wcze[niejszych wykonaniach. Oczywi[cie, caBa ta procedura powinna doty- czy pewnej testowej bazy danych, a nie bazy podstawowej. 29 BEGIN 30 DELETE book_copies; 31 DELETE books; 32 33 add_book(isbn_in => l_isbn, barcode_id_in => l_barcode_id, 34 title_in => l_title, summary_in => l_summary, author_in => l_author, 35 date_published_in => l_date_published, page_count_in => l_page_count); 36 37 OPEN bookMatchCur; 38 FETCH bookMatchCur INTO how_many; 39 reporteqbool('add procedure, book fetch matches insert', 40 expected_value => TRUE, actual_value => bookMatchCur%FOUND); 41 CLOSE bookMatchCur; 42 Linie 33.  41. W tym miejscu nast¹puje pierwsze wywoBanie procedury add_book. Wykorzy- stywane s wszystkie zdefiniowane wcze[niej parametry i oczekiwane jest poprawne zakoDczenie procedury. WywoBanie to rozpoczyna proces sprawdzajcy, czy procedura dodawania ksi|ki dziaBa poprawnie. Nast¹puje to przez otwarcie kursora, pobranie z niego danych i sprawdzenie, czy, zgodnie z oczekiwaniami, rekord zostaB utworzony. W liniach 39.  40. znajduje si¹ wywoBa- nie procedury reporteqbool  jest to odmiana procedury reporteq, która wykorzystuje warto[ci logiczne (Boolean) zamiast cigów znaków. Je[li pobranie danych do kursora koDczy si¹ powodzeniem, warto[ci bookMatchCur%FOUND jest TRUE (wi¹cej informacji na temat wyko- rzystania tej techniki znajduje si¹ w rozdziale 5.). Jak wynika z tre[ci linii 41., dobrym zwyczajem jest zamykanie kursora po jego u|yciu. 43 BEGIN 44 add_book(isbn_in => NULL, barcode_id_in => 'foo', title_in => 'foo', 45 summary_in => 'foo', author_in => 'foo', 46 date_published_in => SYSDATE, page_count_in => 0); 47 l_sqlcode := SQLCODE; 48 EXCEPTION 49 WHEN OTHERS THEN 50 l_sqlcode := SQLCODE; 51 END; 52 53 reporteq('add procedure, detection of NULL input', 54 expected_value => '-6502', actual_value => TO_CHAR(l_sqlcode)); 55 Linie 43.  54. Ten fragment kodu sBu|y do przeprowadzenia kolejnego testu  tym razem nast¹- puje próba okre[lenia warto[ci NULL dla parametru isbn w celu sprawdzenia prawidBowego dziaBania detekcji bB¹dnych danych wej[ciowych. Je[li procedura add_book dziaBa poprawnie, po- winna przechwyci wyjtek NO_DATA_FOUND. Programista powinien zosta poinformowany o tym fakcie, a zatem tekst zostaB umieszczony w bloku zagnie|d|onym. W ten sposób mo|na obsBu|y wyjtek niejako w kolejnej instrukcji zamiast przeskakiwa do koDcowej cz¹[ci bloku gBównego (sekcji obsBugi wyjtków). W celu zachowania zgodno[ci z innymi przeprowadzanymi testami, tu równie| trzeba przeprowa- dzi porównanie otrzymanej warto[ci z pewn warto[ci oczekiwan. PL/SQL zawiera specjaln funkcj¹ wewn¹trzn SQLCODE, która wywoBana z poziomu kodu obsBugi wyjtku zawsze zwraca okre[lon warto[ ró|n od zera. Z uwagi na fakt, |e warto[ ta ma zosta wykorzystana poza ko- dem obsBugi wyjtku, w linii 50. nast¹puje przypisanie tej warto[ci zmiennej l_sqlcode, która nast¹pnie jest wykorzystywana w liniach 53. i 54. podczas wywoBania procedury reporteq. Z linii 54. wynika, |e warto[ oczekiwana wynosi  6502. Jest to warto[, któr PL/SQL przypi- suje SQLCODE w sytuacji, gdy pojawia si¹ wyjtek NO_DATA_FOUND. 56 OPEN bookCountCur; 57 FETCH bookCountCur INTO how_many; 58 reporteq('add procedure, book_record count', expected_value => '1', 59 actual_value => how_many); 60 CLOSE bookCountCur; 61 62 OPEN copiesCountCur; 63 FETCH copiesCountCur INTO how_many; 64 reporteq('add procedure, book_copy record count', expected_value => '1', 65 actual_value => how_many); 66 CLOSE copiesCountCur; 67 68 OPEN copiesMatchCur; 69 FETCH copiesMatchCur INTO how_many; 70 reporteqbool('add procedure, book copy fetch matches insert', 71 expected_value => TRUE, actual_value => copiesMatchCur%FOUND); 72 CLOSE copiesMatchCur; 73 Linie 56.  72. Kolejne linie kodu sBu| do sprawdzenia, czy w tabeli znajduje si¹ oczekiwana liczba rekordów. 74 BEGIN 75 add_book(isbn_in => l_isbn, barcode_id_in => l_barcode_id, 76 title_in => l_title, summary_in => l_summary, author_in => l_author, 77 date_published_in => l_date_published, 78 page_count_in => l_page_count); 79 l_sqlcode := SQLCODE; 80 EXCEPTION 81 WHEN OTHERS THEN 82 l_sqlcode := SQLCODE; 83 END; 84 reporteq('add procedure, detection of duplicate isbn', 85 expected_value => '-1', actual_value => l_sqlcode); 86 END; 87 / Linie 74.  85. Kolejny test, uwzgl¹dniony w omawianym programie, polega na sprawdzeniu, czy próba wprowadzenia drugi raz tej samej warto[ci isbn spowoduje przechwycenie wyjtku. Sys- tem Oracle powinien w takiej sytuacji ustawi warto[ SQLCODE na  1, co oznacza wBa[nie prób¹ wstawienia rekordu o takim samym kluczu gBównym, co rekord ju| istniejcy (w rzeczywisto[ci jest to test poprawno[ci projektu bazy danych). Jest to w zasadzie ostatni punkt kontrolny testu poprawno[ci procedury add_book. Je|eli przed uruchomieniem programu wykonano komend¹ SERVEROUTPUT ON (dokBadniejszy opis znajduje si¹ w rozdziale 2.), wywoBanie omawianego programu z poziomu SQL*Plus powoduje wy[wietle- nie nast¹pujcych informacji: add procedure, book fetch matches insert: PASSED add procedure, detection of null input: PASSED add procedure, book record count: PASSED add procedure, book_copy record count: PASSED add procedure, book_copy fetch matches insert: PASSED add procedure, detection of duplicate isbn: PASSED By mo|e Czytelnik zauwa|yB, |e powy|szy kod sBu|y jako test jednostki programowej (unit test)4. Mo|e on tak|e posBu|y jako zapisany przykBad wywoBywania programu, co mo|e okaza si¹ przy- datne w razie zaistnienia wtpliwo[ci dotyczcych sposobu przeprowadzenia podobnej procedury. Poni|szy program sBu|y do testowania pracy funkcji book_copy_qty. Zasadniczo sposób jego dziaBania jest taki sam, jak w przypadku poprzedniego programu. 1 DECLARE 2 l_isbn VARCHAR2(13) := '1-56592-335-9'; 3 l_isbn2 VARCHAR2(13) := '2-56592-335-9'; 4 l_title VARCHAR2(200) := 'Programowanie w Oracle PL/SQL'; 5 l_summary VARCHAR2(2000) := 'Kompendium informacji o jzyku PL/SQL ' || 6 'wraz z przykBadami i poradami na temat programowania.'; 7 l_author varchar2(200) := 'Feuerstein, Steven, Bill Pribyl'; 8 l_date_published DATE := TO_DATE('01-WRZ-1997', 'DD-MON-YYYY'); 9 l_page_count NUMBER := 987; 10 l_barcode_id VARCHAR2(100) := '100000001'; 11 l_barcode_id2 VARCHAR2(100) := '100000002'; 12 l_barcode_id3 VARCHAR2(100) := '100000003'; 13 14 how_many NUMBER; 15 BEGIN 16 DELETE book_copies; 17 DELETE books; 4 Wyra|enie  jednostka programowa (unit) odnosi si¹ tu do pojedynczej jednostki programowej w przeciwieDstwie do innych rodzajów testów, które pozwalaj upewni si¹, co do prawidBowej wspóBpracy poszczególnych jednostek w ramach caBej aplikacji. 18 19 reporteq('book_copy_qty function, zero count', '0', 20 TO_CHAR(book_copy_qty(l_isbn))); 21 22 /* ZakBadamy, |e procedura add_book dziaBa prawidBowo */ 23 add_book(isbn_in => l_isbn, barcode_id_in => l_barcode_id, 24 title_in => l_title, summary_in => l_summary, author_in => l_author, 25 date_published_in => l_date_published, page_count_in => l_page_count); 26 27 reporteq('book_copy_qty function, unit count', '1', 28 TO_CHAR(book_copy_qty(l_isbn))); 29 30 add_book_copy(isbn_in => l_isbn, barcode_id_in => l_barcode_id2); 31 add_book_copy(isbn_in => l_isbn, barcode_id_in => l_barcode_id3); 32 33 reporteq('book_copy_qty function, multi count', '3', 34 TO_CHAR(book_copy_qty(l_isbn))); 35 36 reporteq('book_copy_qty function, null ISBN', '0', 37 TO_CHAR(book_copy_qty(NULL))); 38 END; 39 / Linie 30.  31. Ten fragment kodu zawiera wywoBania procedury, która jeszcze nie zostaBa Czy- telnikowi przedstawiona. Procedura ta sBu|y do wstawienia rekordu do tabeli book_copies. Je|eli uruchomienie jednostki testowej powoduje wy[wietlenie wyników pokazanych poni|ej (przy zaBo|eniu, |e przed uruchomieniem programu wykonano polecenie SERVEROUTPUT ON), ozna- cza to prawidBowe dziaBanie funkcji book_copy_qty: book_copy_qty function, zero count: PASSED book_copy_qty function, unit count: PASSED book_copy_qty function, multi count: PASSED book_copy_qty function, null ISBN: PASSED By mo|e Czytelnik si¹ zastanawia nad zasadno[ci tworzenia takiej ilo[ci dodatkowego kodu. By mo|e po prostu wystarczyBoby przegldanie programu w celu wyszukania ewentualnych bB¹dów. Takie sprawdzanie kodu jest sposobem post¹powania przeci¹tnego programisty. Istot¹ problemu najlepiej oddaje sprawdzenie warto[ci NULL, wykonywane w liniach 40.  41. omawianego pro- gramu sprawdzajcego. Co prawda, ostateczny test wersji procedury add_book przebiegB po- my[lnie, jednak pocztkowo Autorzy wcale nie brali pod uwag¹ konieczno[ci sprawdzania warto- [ci NULL. Dopiero w trakcie pisania jednostki testowej okazaBo si¹, |e nale|y uwzgl¹dni co najmniej trzy przypadki wprowadzania danych wej[ciowych: okre[lenie danych poprawnych, niepoprawnych oraz uwzgl¹dnienie tej problematycznej warto[ci NULL. UstaleD tych dokonano jedynie dzi¹ki anali- zie mo|liwych danych wej[ciowych, które nale|y uwzgl¹dnia podczas planowania testów. Wcze- [niejsze poprawne dziaBanie programu okazaBo si¹ kwesti przypadku. Testowanie i sposób jego zaplanowania umo|liwia analiz¹ tworzonego kodu z zupeBnie odmiennego punktu widzenia, co po- zwala na uzyskanie nowych, wa|nych informacji. Czas przeznaczony na testowanie aplikacji jest niekiedy ograniczany z powodów finansowych lub w rezultacie decyzji kierownictwa firmy. Cz¹[ciej jednak testowanie aplikacji jest pomijane przez programistów, którzy postrzegaj t¹ czynno[ jako nudn lub nawet niepotrzebn. Bezwzgl¹dnie nale|y jednak wyrobi sobie nawyk testowania pisanych przez siebie aplikacji. Dotychczas Czytelnik zapoznaB si¹ z kodem umo|liwiajcym przeprowadzanie kilku operacji zwi- zanych z obsBug katalogu. Przedstawiono tak|e kod kilku narz¹dzi sBu|cych do testowania. Poni|ej opisano pewne uproszczenia, jakie dotychczas dopuszczano wobec omawianego problemu. Przedstawiono tak|e kilka sposobów pokonania tych ograniczeD. Kod, który zaprezentowano we wcze[niejszych podrozdziaBach, nie rozwizuje jeszcze pewnych wa|nych zagadnieD, takich jak: " Mo|liwo[, |e rekord wstawiany do tabeli books ju| istnieje. Trzeba sprawdzi, czy jest to traktowane tak samo, jak wprowadzenie informacji o nowym egzemplarzu. " Sposób modyfikowania danych w katalogu. " Sytuacja, w której dany rekord katalogu biblioteki zostanie przypadkowo usuni¹ty lub utracony. Trzeba przeanalizowa mo|liwo[ci wykorzystania PL/SQL do przekazania tej informacji do systemu bazy danych. " Sytuacja, w której zaistnieje potrzeba wykonania wielu ró|nych zapytaD, np. wyszukiwanie ksi|ek na podstawie kilku ró|nych kryteriów. Oczywi[cie, w dalszej cz¹[ci niniejszej ksi|ki zostan przedstawione sposoby rozwizania wielu z powy|szych problemów. Zaprezentowane b¹d odpowiednie fragmenty kodu i sposób ich doda- wania. Z powy|szego wynika, |e wygodnym rozwizaniem byBoby posiadanie mechanizmu pozwa- lajcego na organizowanie kodu w taki sposób, aby umo|liwi jego Batwiejsze rozwijanie i utrzy- mywanie. Mechanizmem takim s pakiety (packages). Pakiet j¹zyka PL/SQL jest pewnym nazwanym zbiorem, który mo|e zwiera dowoln liczb¹ pro- cedur i funkcji. Pakiety mog tak|e przechowywa inne obiekty, na przykBad wyjtki, zmienne czy deklaracje typów danych. W trakcie lektury dalszej cz¹[ci niniejszej ksi|ki Czytelnik przekona si¹ o ogromnych korzy[ciach, które pByn z tych dodatkowych mo|liwo[ci. W tym rozdziale jednak zostanie przedstawiony tylko sposób wykorzystania teoo mechanizmu do wstawienia ju| utworzo- nego programu do pakietu. W przypadku innych j¹zyków programowania  na przykBad Java lub Ada  tak|e istniej konstrukcje zwane pakietami. Jednak pakiety w j¹zyku PL/SQL charakteryzuj specyficzne definicje i zachowania. Warto o tym pami¹ta w przypadku zapoznawania si¹ z tymi strukturami w innych j¹zykach. Z powodów, które stan si¹ niedBugo oczywiste, pakiety skBadaj si¹ zazwyczaj z dwóch cz¹[ci: specyfikacji (specification)  w skrócie spec  oraz ciaBa (body). Specyfikacja pakietu zawiera jedynie informacje o jego mo|liwo[ciach (przeznaczeniu), ale nie ma tu |adnych wiadomo[ci o sposobie jego wykonania. Specyfikacja zawiera jedynie nagBówki jednostek programowych, a nie kod wykonywalny. Jest to rodzaj sekcji deklaracyjnej, wyst¹pujcej w jed- nostkach programowych. Uproszczony wzorzec skBadni definicji pakietu przedstawiono poni|ej: CREATE OR REPLACE PACKAGE nazwa_pakietu AS nagBówek_programu1; nagBówek_programu2; nagBówek_programu3; END nazwa_pakietu; / nazwa_pakietu jest opisow nazw, jak u|ytkownik nadaje danemu pakietowi (nazwa ta podle- ga zasadom nadawania nazw obowizujcym w j¹zyku PL/SQL). Poni|ej przedstawiono sposób utworzenia pakietu, sBu|cego do zarzdzania ksi|kami w bazie danych. Pierwszym problemem jest nadanie odpowiedniej nazwy. Cz¹[ programistów uwa|a, |e taki rodzaj pakietu peBni rol¹ zarzdcy (manager) i dlatego zastosowan przez nich nazw byBoby book_mgr lub book_man. Inni raczej podkre[laj rodzaj obiektu i u|yliby nazwy book_pkt. Autorzy preferuj jednak nazwy krótkie i proste  a zatem wybrali prost nazw¹ book5. Poni|ej przedstawiono przykBadow specyfikacj¹ pakietu: CREATE OR REPLACE PACKAGE book AS PROCEDURE add(isbn_in IN VARCHAR2, title_in IN VARCHAR2, author_in IN VARCHAR2, page_count_in IN NUMBER, summary_in IN VARCHAR2 DEFAULT NULL, date_published_in IN DATE DEFAULT NULL, barcode_id_in IN VARCHAR2 DEFAULT NULL); PROCEDURE add_copy(isbn_in IN VARCHAR2, barcode_id_in IN VARCHAR2); FUNCTION book_copy_qty(isbn_in IN VARCHAR2) RETURN NUMBER; PROCEDURE change(isbn_in IN VARCHAR2, new_title IN VARCHAR2, new_author IN VARCHAR2, new_page_count IN NUMBER, new_summary IN VARCHAR2 DEFAULT NULL, new_date_published IN DATE DEFAULT NULL); 5 WywoBywanie programów umieszczonych w pakietach odbywa si¹ w nast¹pujcy sposób: nazwa_pakietu. nazwa_programu  std mo|liwe okazuje si¹ u|ywanie zwi¹zBych, lecz zrozumiaBych wywoBaD w rodzaju book.add(...). PROCEDURE remove_copy(barcode_id_in IN VARCHAR2); PROCEDURE weed(isbn_in IN VARCHAR2); END book; / W wi¹kszo[ci przypadków (tak|e w powy|szym) nie ma potrzeby umieszczania w specyfikacji pa- kietu procedur i funkcji w okre[lonym porzdku. Warto zauwa|y, |e instrukcja definicji specyfikacji pakietu rozpoczyna si¹ od wyra|enia CREATE OR REPLACE, za[ poszczególne programy w nagBówku maj posta: FUNCTION nazwa ... lub: PROCEDURE nazwa ... Jest to spowodowane faktem, |e w przypadku j¹zyka PL/SQL caBy kod pojedynczego pakietu jest tworzony, uaktualniamy lub usuwany jednocze[nie, tak wi¹c sensowne jest tylko zastosowanie jed- nej instrukcji CREATE. Z powy|szego wynika, |e w planach rozwoju aplikacji uwzgl¹dniono dodanie kilku brakujcych funk- cji (jednak|e metody niezb¹dne do pobierania danych z bazy danych nie zostan na razie utworzone). Specyfikacja pakietu peBni rol¹ interfejsu programowania aplikacji (application programming interface, API) w odniesieniu do pakietu. Nazwa ta jest by mo|e nieco nie[cisBa, lecz oddaje istot¹ idei stosowania pakietu. Ka|dy API sBu|y bowiem jako forma komunikacji mi¹dzy u|ytkownikami (np. mi¹dzy piszcymi program i wykorzystujcymi go). Sens takiego post¹powania polega na ukry- ciu niejednokrotnie bardzo skomplikowanych rozwizaD programistycznych za ich prost prezentacj. CiaBo pakietu zawiera elementy strukturalne jednostek programowych, czyli instrukcje wykonawcze odpowiadajce nagBówkom podanym w specyfikacji pakietu. Uproszczony wzorzec skBadniowy ciaBa pakietu znajduje si¹ poni|ej: CREATE OR REPLACE PACKAGE BODY nazwa_pakietu AS programy_prywatne; /* opcjonalnie */ ciaBo_programu1; ciaBo_programu2; ciaBo_programu3; END nazwa_pakietu; / Innymi sBowy, ciaBo pakietu jest t lokalizacj, gdzie si¹ umieszcza implementacje programów wy- mienionych w specyfikacji. Niemal zawsze ciaBo pakietu tworzy si¹ po zdefiniowaniu jego specyfikacji. Kompilator sprawdza, z któr specyfikacj jest zwizane dane ciaBo poprzez sprawdzenie jego nazwy, która musi by iden- tyczna z wymienion w specyfikacji. Ponadto ciaBo pakietu musi zawiera definicje wszystkich programów, jakie zostaBy wymienione w specyfikacji  w przeciwnym wypadku kompilacja si¹ nie powiedzie. Jednak|e warto zauwa|y, |e zasada ta nie dziaBa odwrotnie  ciaBo pakietu mo|e zawiera pewne dodatkowe programy, których nie wymieniono w specyfikacji pakietu. Na przed- stawionym powy|ej wzorcu opisano je jako programy_prywatne. Kod ciaBa pakietu book zawiera jedn procedur¹ prywatn (private): CREATE OR REPLACE PACKAGE BODY book AS /* "prywatna" procedura u|ywana tylko w ciele tego pakietu */ PROCEDURE assert_notnull (tested_variable IN VARCHAR2) IS BEGIN IF tested_variable IS NULL THEN RAISE VALUE_ERROR; END IF; END assert_notnull; FUNCTION book_copy_qty(isbn_in IN VARCHAR2) RETURN NUMBER AS number_o_copies NUMBER := 0; CURSOR bc_cur IS SELECT COUNT(*) FROM book_copies WHERE isbn = isbn_in; BEGIN IF isbn_in IS NOT NULL THEN OPEN bc_cur; FETCH bc_cur INTO number_o_copies; CLOSE bc_cur; END IF; RETURN number_o_copies; END; PROCEDURE add(isbn_in IN VARCHAR2, title_in IN VARCHAR2, author_in IN VARCHAR2, page_count_in IN NUMBER, summary_in IN VARCHAR2, date_published_in IN DATE, barcode_id_in IN VARCHAR2) IS BEGIN assert_notnull(isbn_in); INSERT INTO books (isbn, title, summary, author, date_published, page_count) VALUES (isbn_in, title_in, summary_in, author_in, date_published_in, page_count_in); IF barcode_id_in IS NOT NULL THEN add_copy(isbn_in, barcode_id_in); END IF; END add; PROCEDURE add_copy(isbn_in IN VARCHAR2, barcode_id_in IN VARCHAR2) IS BEGIN assert_notnull(isbn_in); assert_notnull(barcode_id_in); INSERT INTO book_copies (isbn, barcode_id) VALUES (isbn_in, barcode_id_in); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN NULL; END; PROCEDURE change(isbn_in IN VARCHAR2, new_title IN VARCHAR2, new_author IN VARCHAR2, new_page_count IN NUMBER, new_summary IN VARCHAR2 DEFAULT NULL, new_date_published IN DATE DEFAULT NULL) IS BEGIN assert_notnull(isbn_in); UPDATE books SET title = new_title, author = new_author, page_count = new_page_count, summary = new_summary, date_published = new_date_published WHERE isbn = isbn_in; IF SQL%ROWCOUNT = 0 THEN RAISE NO_DATA_FOUND; END IF; END change; PROCEDURE remove_copy(barcode_id_in IN VARCHAR2) IS BEGIN assert_notnull(barcode_id_in); DELETE book_copies WHERE barcode_id = barcode_id_in; END remove_copy; PROCEDURE weed(isbn_in IN VARCHAR2) IS BEGIN assert_notnull(isbn_in); DELETE book_copies WHERE isbn = isbn_in; DELETE books WHERE isbn = isbn_in; IF SQL%ROWCOUNT = 0 THEN RAISE NO_DATA_FOUND; END IF; END weed; END book; / W powy|szym, do[ dBugim przykBadzie znajduje si¹ kilka dotd nie omówionych konstrukcji, przy- kBadowo, konstrukcja SQL%ROWCOUNT. Zostan one jednak omówione w dalszych rozdziaBach. Wi¹kszo[ programistów umieszcza programy w ciele pakietu w takiej samej kolejno[ci, jak w przy- padku specyfikacji (programy prywatne uwzgl¹dnia si¹ na pocztku, gdy| ze wzgl¹du na wymagania kompilatora ich definicja musi si¹ znajdowa przed ewentualnym wywoBaniem). W razie niezdefi- niowania której[ z jednostek programowych, wymienionych w specyfikacji, kompilator nie prze- prowadzi kompilacji, dopóki bBd ten nie zostanie naprawiony. programy_prywatne s  prywatne w sensie dost¹pno[ci jedynie z poziomu pakietu. Jego u|yt- kownicy nie mog bezpo[rednio wywoBywa |adnego z programów prywatnych. Pozwala to na konstruowanie narz¹dzi o specjalnym przeznaczeniu, które b¹d dost¹pne tylko dla innych pro- gramów, zdefiniowanych w ramach pakietu. W podanym wy|ej przykBadzie dodano tylko jedn, prost procedur¹ assert_notnull, która pozwala na niepowtarzanie kilku linii kodu w ka|dej definiowanej procedurze. U|ywanie takich lokalnych programów cz¹sto jest bardzo wygodne. Najcz¹[ciej speBniaj one nast¹pujce zadania: " sBu| jako dodatkowe metody, wykorzystywane przez inne programy zawarte w pakiecie; " pozwalaj na unikni¹cie powtarzania tego samego kodu; " s dobr metod przechowywania lub zmieniania warto[ci pewnej zmiennej wewn¹trznej. Z kolei programy, które s wymienione w specyfikacji pakietu, mog by wywoBywane w dowol- ny sposób i nazywa si¹ je programami publicznymi (public). Rysunek 3.7 przedstawia graficzn reprezentacj¹ porównania programów publicznych z prywatnymi. Rysunek 3.7. Pakiety udostpniaj interfejs publiczny ukrywajcy wewntrzn implementacj Wielu programistów nie dostrzega wa|no[ci zagadnieD zwizanych z wykorzystaniem programów publicznych i prywatnych, mimo |e jest to jedna z technik pozwalajcych na tworzenie trwaBego, zrozumiaBego i Batwego do ponownego wykorzystania kodu. Informatycy, którzy wszystkiemu na- daj pewne formalne nazwy, powiedzieliby, |e oznacza to tworzenie  abstrakcji (abstraction) ksi|ki poprzez ukrywanie informacji (information hiding)  patrz: sBowniczek. Poni|ej wymieniono najistotniejsze korzy[ci wynikajce z wykorzystywania pakietów: Organizacja Wi¹kszo[ ludzi docenia dobre zorganizowanie dziaBania. Grupowanie powizanych ze sob jednostek programowych w pakiety pozwala na tworzenie kodu zorganizowanego w wygodne do stosowania struktury. U|ywajc terminologii fachowej mo|na powiedzie, |e pakiety pozwalaj na u|ycie mechanizmów abstrakcji, enkapsulacji oraz ukrywania informacji. ZrozumiaBo[ Pakiety w ogromnym stopniu uBatwiaj zarzdzanie du| liczb jednostek programowych. Pewne badania z dziedziny psychologii dowiodBy, |e czBowiek w jednym czasie mo|e zajmowa si¹ jedynie okoBo siedmioma zagadnieniami. Oczywi[cie, nie zawsze mo|na ograniczy liczb¹ komponentów pakietu do takiej liczby, ale ich grupowanie z pewno[ci uBatwia prac¹. Mo|liwo[ci projektowe Rozwizanie skomplikowanego problemu odbywa si¹ zazwyczaj na drodze rozbicia go na mniejsze skBadowe. Dwa najpopularniejsze, zupeBnie od siebie ró|ne, sposoby rozwizywania tego problemu (czyli dekompozycji) to podej[cie funkcjonalne (functional) oraz obiektowe (object-based). Zastosowanie pakietów wspomaga obydwie te techniki projektowe. Wydajno[ Podczas pierwszego w danej sesji uruchomienia programu zapisanego w pakiecie system Oracle wczytuje do pami¹ci caB zawarto[ pakietu, a nie tylko program wBa[nie wywoBany. Pozwala to na znaczce zwi¹kszenie wydajno[ci wywoBania innych programów pakietu, gdy| nie b¹dzie konieczne korzystanie z danych zapisanych na wolniejszym dysku twardym. Z powy|szego jednocze[nie wynika, |e w pakiecie warto przechowywa tylko te komponenty, które s ze sob zwizane. Wygoda pracy sesyjnej Czasem jest przydatna mo|liwo[ przechowywania w pami¹ci pewnych tymczasowych lub staBych warto[ci w trakcie trwania sesji (przyj¹to, |e sesj nazywa si¹ okres zalogowania u|ytkownika w systemie bazy danych). Dzi¹ki wykorzystaniu pakietów warto[ci takie mo|na przechowywa w globalnych lub lokalnych zmiennych. Trzeba jednak pami¹ta, |e cecha ta staje du|o mniej przydatna w przypadku aplikacji dziaBajcych w sieci Internet. Aplikacje te zazwyczaj nie s zale|ne od sesji  wi¹cej informacji dotyczcych tego tematu znajduje si¹ w rozdziale 4. Bez zastosowania pakietów warto[ci takie musiaByby by przechowywane w samej bazie danych, co miaBoby niekorzystny wpByw na wydajno[ systemu. Problematyczne te| staBoby si¹ odwoBywanie si¹ do pewnej warto[ci po wycofaniu transakcji. Szczególne cechy PL/SQL Jedn z najciekawszych mo|liwo[ci uzyskiwanych dzi¹ki wykorzystaniu pakietów jest mo|liwo[ tworzenia wielu jednostek programowych o takiej samej nazwie. Pozwala to na wywoBywanie jednego programu, który mo|e obsBugiwa dane wej[ciowe o ró|nych typach. Zastosowanie tej techniki, zwanej przeci|aniem (overloading) i niedost¹pnej dla programów napisanych bez u|ycia pakietów, pozwala na uczynienie programu pozornie bardziej ogólnym. PrzykBadowo, funkcja TO_CHAR systemu Oracle jest przeci|ana w celu umo|liwienia przyjmowania parametrów o ró|nym typie danych, na przykBad NUMBER lub DATE. Opis techniki przeci|ania oraz przykBadowy program znajduj si¹ w koDcowej cz¹[ci niniejszego rozdziaBu, w podrozdziale  Uproszczenie poprzez przeci|enie . Mniejsze problemy z rekompilacj W du|ych systemach skBadajcych si¹ z dziesitków lub setek programów du|ym problemem jest zazwyczaj rekompilowanie cz¹[ci skBadowych programu po dokonaniu pewnych zmian. Dzi¹ki pakietom mo|na unikn wielu trudno[ci dzi¹ki temu, |e mo|na rekompilowa zawarto[ ciaBa pakietu bez konieczno[ci rekompilacji programów, które wykorzystuj zmodyfikowany program. W przypadku zmiany specyfikacji pakietu trzeba ju| jednak ponownie skompilowa ka|dy program uwzgl¹dniony w pakiecie, ale cz¹sto system Oracle robi to automatycznie. Usuwanie programów magazynowanych Warto zwróci uwag, |e kod procedury add_book wprowadzony do pakietu nie ró|ni si od procedury oryginalnej poza zmienion nazw dodaj, gdy| bdzie ona stosowana tylko w kontek[cie pakietu book. Oryginalna procedura add_book wci| istnieje, ale mo|na j usun  po cz[ci dlatego, |e dziki wykorzystaniu pakietu procedura ta ju| nie jest potrzebna. Poni|ej zatem pokazano sposób usuwania procedury. Odpowiedni instrukcj SQL, która w nieodwracalny sposób usuwa procedur z bazy danych, jest instrukcja DROP PROCEDURE: DROP PROCEDURE add_book; Jest to instrukcja SQL, a nie PL/SQL. Std poni|szy sposób wykonania: BEGIN DROP PROCEDURE add_book; /* nie zadziaBa w TYM miejscu */ END; spowoduje bBd kompilacji i wy[wietlenie komunikatu: drop procedure add_book; * BAD w linii 2: ORA-06550: linia 2, kolumna 1: PLS-00103: Napotkano symbol "DROP" gdy oczekiwano jednego z nastpujcych: ...ciach... Z powy|szego wynika, |e PL/SQL rzeczywi[cie nie jest peBnym nadzbiorem jzyka SQL. Po usuniciu procedury nie jest mo|liwe jej odzyskanie bez pomocy administratora bazy da- nych, który musi przeprowadzi pewne dziaBania zwizane z odzyskiwaniem danych. Je[li jednak istnieje plik zawierajcy kod zródBowy, mo|na po prostu utworzy ponownie dan procedur. W rzeczywisto[ci nie powinno si usuwa obiektów bazy danych bez upewnienia si, |e nie s ju| potrzebne  w przeciwnym wypadku wcze[niej czy pózniej spowoduje to problemy. Dobrym zwyczajem jest przechowywanie specyfikacji oraz ciaBa pakietu w dwóch oddzielnych plikach. W ten sposób Batwo mo|na podda rekompilacji samo ciaBo po dokonaniu pewnych zmian. Niepotrzebne wykonanie instrukcji zawartych w specyfikacji pakietu sprawiBoby, |e nieaktualne staByby si¹ powizania innych programów z pakietem, a zatem tak|e wymagana ich rekompilacja. Jak si¹ okazuje, istnieje wiele powodów, dla których warto u|ywa pakietów. A zatem warto powró- ci do zagadnieD zwizanych z programami testujcymi i umie[ci je w pakiecie. Poni|ej przedstawiono sposób utworzenia kolejnego pakietu. Zorganizowanie procedur testowych w jednym pakiecie sBu|y ma gBównie w celu utrzymania porzdku w kodzie. Na tym etapie zostan pomini¹te kwestie zwizane z wydajno[ci i kilkoma innymi zagadnieniami, które omówiono wcze- [niej. Pakiet testujcy zapewnia wygodny sposób obsBugi, a jego struktura umo|liwia [wietn wspóB- prac¹ ze struktur pakietu book, którego budow¹ przedstawiono we wcze[niejszej cz¹[ci niniejszego rozdziaBu. Poni|ej zamieszczono specyfikacj¹ omawianego pakietu: CREATE OR REPLACE PACKAGE test_book AS PROCEDURE run (verbose IN BOOLEAN DEFAULT TRUE); PROCEDURE add; PROCEDURE add_copy; PROCEDURE book_copy_qty; PROCEDURE change; PROCEDURE remove_copy; PROCEDURE weed; END test_book; / Ka|da jednostka programowa gBównego pakietu book posiada odpowiednik w pakiecie test_book, cho nie uwzgl¹dniono |adnych parametrów. Mo|na wywoBywa je pojedynczo lub wywoBa ogóln procedur¹ run, która uruchamia wszystkie pozostaBe. Posiada ona jeden opcjonalny parametr lo- giczny wskazujcy, czy maj by prezentowane szczegóBowe informacje dotyczce testów. Oprócz tego ka|da procedura zawiera kod sBu|cy do testowania. Je[li wszystko przebiega prawidBowo, przeprowadzenie testu z poziomu SQL*Plus wyglda na- st¹pujco: SQL> SET SERVEROUTPUT ON SIZE 1000000 SQL> execute test_book.run Testing book package... ...add procedure, detection of NULL input: PASSED ...add procedure, book_record count: PASSED ...add procedure, book_copy record count: PASSED ...add procedure, book fetch matches insert: PASSED ...add procedure, book copy fetch matches insert: PASSED ...add procedure, detection of duplicate isbn: PASSED ...add_copy procedure, nominal case, first book: PASSED ...add_copy procedure, nominal case, second book: PASSED ...add_copy procedure, ignore duplicates: PASSED ...add_copy procedure, bad isbn detection: PASSED ...add_copy procedure, NULL isbn detection: PASSED ...add_copy procedure, NULL barcode_id detection: PASSED ...book_copy_qty function, zero count: PASSED ...book_copy_qty function, non-zero count: PASSED ...change procedure, single field test: PASSED ...change procedure, NULL barcode_id detection: PASSED ...remove_copy procedure, book count normal: PASSED ...remove_copy procedure, book copy count normal: PASSED ...remove_copy procedure, superfluous invocation: PASSED ...weed procedure, book count normal: PASSED ...weed procedure, book copy count normal: PASSED ...weed procedure, superfluous invocation: PASSED book package: PASSED Mo|na tak|e wyBczy tryb szczegóBowych komunikatów, podajc warto[ FALSE przy wywoBa- niu procedury run. Odpowiednie polecenie przedstawiono poni|ej: SQL> SET SERVEROUTPUT ON SIZE 1000000 SQL> execute test_book.run(verbose => FALSE) book package: PASSED Omawiany pakiet jest zbyt obszerny, aby zamie[ci go w tym miejscu. Posiada on kilka udogodnieD w porównaniu do wersji pierwotnej. PeBna wersja omawianego pakietu znajduje si¹ pod adresem ftp://ftp.helion.pl/przyklady/orplsq.zip Odwiedzajc witryn¹ wydawnictwa O Reilly, Czytelnik mo|e tak|e zapozna si¹ z utPLSQL (http://oracle.oreilly.com/utplsql), darmow aplikacj sBu|c do te- stowania. By mo|e Czytelnik uwa|a, |e w tre[ci niniejszego rozdziaBu poBo|ono zbyt du|y nacisk na kwesti¹ testowania oprogramowania. Warto jednak u[wiadomi sobie, |e programowanie jest dziaBaniem ukierunkowanym na szczegóBy  u|ytkownicy aplikacji s bardzo wymagajcy i jakiekolwiek lekcewa|enie potencjalnych problemów jest bardzo ryzykown postaw (istnieje tak zwany  styl programowania ekstremalnego 6 gloryfikujcy tak postaw¹). A zatem program testowy nale|y two- rzy bardzo wcze[nie. Niektórzy uwa|aj, |e program testowy powinien by tworzony jeszcze przed napisaniem gBównej aplikacji. Zbyt dBugie zwlekanie z napisaniem programu testowego mo|e w efek- cie spowodowa, |e nigdy nie powstanie, a nawet je[li powstanie, ewentualna zwBoka mo|e unie- mo|liwi osigni¹cie pewnych korzy[ci wynikajcych z testowania. My[lc o spodziewanych wy- nikach na wczesnym etapie tworzenia aplikacji Batwiej jest znalez bB¹dy i naprawi je szybko i bez ponoszenia zb¹dnych kosztów. Pisanie dobrych programów testowych nie jest zadaniem trywialnym. Dlatego wielu programistów, piszcych aplikacje pod presj czasu, stwierdza, |e mo|e pomin ten etap. Warto jednak zapa- mi¹ta nast¹pujc dewiz¹: Je[li nie ma czasu, aby wykona zadanie prawidBowo za pierwszym razem, to skd wzi czas, aby wykona je od nowa? Autorzy uwa|aj, |e aby zosta naprawd¹ dobrym programist, nale|y tworzy programy testowe. Taki sposób post¹powania umo|liwi sp¹dzanie wi¹kszej ilo[ci czasu na pisaniu nowych programów, a mniej na usuwaniu bB¹dów w programach starych. Po zdobyciu pewnego do[wiadczenia w wykorzystywaniu procedur, funkcji i pakietów Czytelnik z pewno[ci zechce podnie[ poziom swojej pracy programistycznej. Poni|ej znajduje si¹ kilka po- rad i sugestii dotyczcych tego zagadnienia. 6 Wi¹cej informacji na ten temat mo|na znalez w ksi|ce po[wi¹conej tej tematyce, której autorem jest Kent Beck lub zajrze na witryn¹ http://www.extremeprogramming.org/. Przyj¹cie odpowiedniego sposobu nazywania plików, które zawieraj kod zródBowy tworzonych programów, jest z pewno[ci bardzo wa|nym zagadnieniem. PrzykBadowo, w przypadku plików zawierajcych kod PL/SQL warto, aby rozszerzenie nazwy pliku odzwierciedlaBo jego zawarto[. W rozdziale 6. znajduje si¹ bardziej szczegóBowe omówienie tego zagadnienia. Poni|ej podano jedy- nie kilka gBównych wytycznych: Wzorzec nazwy pliku Zawarto[ nazwa.pro (Pojedyncza) procedura magazynowana nazwa.fun (Pojedyncza) funkcja magazynowana nazwa.sql Blok anonimowy lub skrypt zawierajcy wiele bloków, instrukcji SQL i (lub) poleceD SQL*Plus nazwa.pks Specyfikacja pakietu nazwa.pkb CiaBo pakietu W razie zastosowania powy|szych konwencji niektóre z plików, które wymieniono w niniejszym rozdziale, nosiByby nast¹pujce nazwy: add_book.pro Procedura magazynowana add_book book_copy_qty.fun Funkcja magazynowana book_copy_qty test_add_book.sql Program testujcy dla add_book book.pks Specyfikacja pakietu book book.pkb CiaBo pakietu book Specyfikacja i ciaBo pakietu powinny by umieszczone w oddzielnych plikach. Czytelnik nie powinien sdzi, |e wydajno[ pracy programisty jest wprost proporcjonalna do liczby linii napisanego kodu. Dawno temu byB to pogld licznych teoretyków programowania. Jednak maBe jest pi¹kne  programista powinien stara si¹ osiga du|y efekt kosztem maBego wysiBku. Oto pew- na historyjka: Pewien Prawdziwy Programista zdoBaB zmie[ci program dopasowywania do wzorca (pattern matching) w kilkuset kilobajtach nieu|ywanej pamici sondy Voyager, której zadaniem byBo odszukanie i sfotografowanie nowego ksi|yca Jowisza7. Bez wzgl¹du na to, czy powy|sza anegdota jest prawdziwa czy nie, ka|dy programista powinien stara si¹ pisa kod zwi¹zBy (ale nie niezrozumiaBy). Jednym ze sposobów na osigni¹cie tego celu jest projektowanie kodu mo|liwego do ponownego wykorzystania. Poni|szy przykBad umo|liwi zrozumienie problemu. 7 Fragment pochodzi z artykuBu  Real Programmers Don t Use PASCAL , Datamation, July 1983, s. 263  265. Poni|ej przedstawiono dziaBanie procedury reporteq. Wypisz opis testu. Porównaj warto[ oczekiwan z warto[ci otrzyman. Je[li obydwie warto[ci s równe, wypisz komunikat PASSED, je[li nie  FAILED. Poni|szy kod ju| byB omawiany w niniejszym rozdziale, ale zostaB powtórzony dla zachowania przej- rzysto[ci wykBadu. CREATE OR REPLACE PROCEDURE reporteq (description IN VARCHAR2, expected_value IN VARCHAR2, actual_value IN VARCHAR2) AS BEGIN DBMS_OUTPUT.PUT(description || ': '); IF expected_value = actual_value OR (expected_value IS NULL AND actual_value IS NULL) THEN DBMS_OUTPUT.PUT_LINE('PASSED'); ELSE DBMS_OUTPUT.PUT_LINE('FAILED. Expected ' || expected_value || '; got ' || actual_value); END IF; END; / Program ten porównuje dwie zmienne typu VARCHAR2. Nast¹pna funkcja, reporteqbool, po- siada identyczny pseudokod, ale jest przeznaczona do porównywania warto[ci logicznych typu BOOLEAN. Mo|na by dokona tylko drobnych modyfikacji w oryginale, jak pokazano w poni|szym fragmencie kodu: CREATE OR REPLACE PROCEDURE reporteqbool (description IN VARCHAR2, expected_value IN BOOLEAN, actual_value IN BOOLEAN) AS BEGIN DBMS_OUTPUT.PUT(description || ': '); IF (expected_value AND actual_value) OR (expected_value IS NULL AND actual_value IS NULL) THEN DBMS_OUTPUT.PUT_LINE('PASSED'); ELSE DBMS_OUTPUT.PUT_LINE('FAILED.'); END IF; END; / Nawet programista, który nie jest odpowiedzialny za oprogramowanie sondy Voyager, mo|e za- uwa|y, |e powy|szy kod charakteryzuje si¹ pewn nadmiarowo[ci. W razie konieczno[ci mody- fikacji dziaBania cz¹[ci testujcej lub raportujcej (na przykBad w celu zapisania wszystkich opisów i wyników testu w tabeli bazy danych) okazaBoby si¹, |e trzeba wykona dwa razy wi¹cej pracy. Problematyczne te| mo|e okaza si¹ okre[lenie dwóch ró|nych miejsc, w których nale|y dokona zmian. Cz¹sto takie zmiany s dokonywane przez kogo[ innego, ni| twórca oryginalnej wersji. Oso- ba taka mo|e nie by [wiadoma istnienia konieczno[ci zmodyfikowania kodu w dwóch miejscach. W rezultacie powstanie niezgodno[, której wykrycie b¹dzie kwesti przypadku. W j¹zyku PL/SQL istnieje mo|liwo[ unikni¹cia takiego problemu przez zmodyfikowanie drugiej procedury w taki sposób, aby wywoBywaBa pierwsz. Aby to umo|liwi, nale|y przekonwertowa warto[ci logiczne BOOLEAN na VARCHAR2. Niestety, funkcja TO_CHAR nie obsBuguje zmiennych typu BOOLEAN. Mo|na jednak napisa wBasn funkcj¹ dokonujc tej konwersji. Zgodnie z obo- wizujcymi w systemie Oracle zasadami nadawania nazw funkcjom konwersji, jej nazw b¹dzie booleantochar: CREATE OR REPLACE FUNCTION booleantochar(is_true IN BOOLEAN) RETURN VARCHAR2 AS BEGIN IF is_true THEN RETURN 'TRUE'; ELSIF NOT is_true THEN RETURN 'FALSE'; ELSE RETURN TO_CHAR(NULL); END IF; END booleantochar; / Teraz mo|na ju| zmodyfikowa procedur¹ reporteqbool w nast¹pujcy sposób: CREATE OR REPLACE PROCEDURE reporteqbool (description IN VARCHAR2, expected_value IN BOOLEAN, actual_value IN BOOLEAN) AS BEGIN reporteq(description, booleantochar(expected_value), booleantochar(actual_value)); END reporteqbool; / Najwa|niejsza kwesti, na któr nale|y zwróci uwag¹, jest to, |e caBy kod zwizany z testowa- niem znajduje si¹ w procedurze reporteq. A zatem w razie konieczno[ci zmiany sposobu jej dziaBania wystarczy tylko zmieni kod jednego programu. Nawet je[li osoba zajmujca si¹ kon- serwacj danego kodu nie b¹dzie wiedziaBa, który program nale|y zmieni, omawiany sposób two- rzenia kodu umo|liwi jej szybkie zorientowanie si¹ w sytuacji. Nie jest to jednak ostatnia metoda uBatwiania sobie pracy. Mo|na upro[ci j jeszcze bardziej za pomoc techniki zwanej przeci|aniem (overloading). Czytelnik zapewne przypomina sobie, |e we wcze[niejszej cz¹[ci niniejszego rozdziaBu opisano w skrócie technik¹ przeci|ania. Opisano utworzenie procedury reporteq, która obsBuguje cigi znakowe oraz procedury reporteqbool, wykonujcej porównania na warto[ciach logicznych typu BOOLEAN. Prawdopodobnie potrzebna byBaby tak|e wersja obsBugujca daty  funkcja reporteqdate, i tak dalej. Zadania wykonywane przez te wszystkie programy byByby bardzo podobne. Warto zatem byBoby utworzy jeden program (lub przynajmniej zastosowa tylko jedn nazw¹ programu), który peBniBby funkcje wszystkich wy|ej wymienionych. PozwoliBoby to na prze- niesienie wielu obowizków u|ytkownika na program u|ytkowy. Im mniej nazw programów trze- ba zapami¹ta, tym lepiej. Technika przeci|ania sBu|y wBa[nie do osigni¹cia tych celów. Uogólniajc, przeci|enie proce- dury oznacza zdefiniowanie wi¹cej ni| jednej procedury o tej samej nazwie. W ramach pakietu ma si¹ wówczas dost¹p do faktycznie czterech ró|nych procedur. Poni|ej znajduje si¹ przykBad wy- korzystania tej techniki w pakiecie zawierajcym zbiór programów testowych. Poni|ej przedsta- wiono kod przykBadowej specyfikacji pakietu: CREATE OR REPLACE PACKAGE tut AS PROCEDURE reporteq (description IN VARCHAR2, expected_value IN VARCHAR2, actual_value IN VARCHAR2); PROCEDURE reporteq (description IN VARCHAR2, expected_value IN NUMBER, actual_value IN NUMBER); PROCEDURE reporteq (description IN VARCHAR2, expected_value IN BOOLEAN, actual_value IN BOOLEAN); PROCEDURE reporteq (description IN VARCHAR2, expected_value IN DATE, actual_value IN DATE); PROCEDURE inna_procedura; END; / Poszczególne procedury reporteq maj t sam nazw¹ i ró|ni si¹ tylko typami danych parame- trów. To jest cz¹[  ukryta . Nale|y jeszcze zaimplementowa wszystkie cztery procedury w jed- nym ciele pakietu. Mo|na uwzgl¹dni ich wzajemne wywoBywanie si¹, co opisano we wcze[niej- szej cz¹[ci niniejszego rozdziaBu. Autorzy pozostawili utworzenie ciaBa pakietu jako wiczenie dla Czytelnika. Ogromn zalet techniki przeci|ania jest to, |e u|ywajc takiej procedury lub funkcji PL/SQL, samodzielnie rozpoznaje ona, któr z nich nale|y wywoBa: DECLARE rozmiar_buta NUMBER; rezultat_szukania VARCHAR(64); BEGIN ... tut.reporteq('procedura flubber, wykrycie maksymalnego rozmiaru buta', expected_result => 15, actual_result => rozmiar_buta); tut.reporteq('procedura flubber, wyszukiwanie morsa', expected_result => 'Jestem morsem', actual_result => rezultat_szukania); END; Oznacza to, |e ka|de wywoBanie procedury reporteq zostaje dopasowane do odpowiedniej sytuacji. Istnieje kilka sytuacji, w których metoda przeci|ania nie umo|liwia prawidBowego dziaBania syste- mu. BBd jednak zostanie zwrócony dopiero w czasie próby uruchomienia programu. Poni|ej wy- mieniono podstawowe zasady, których przestrzeganie pozwoli na prawidBowe dziaBanie mechani- zmu przeci|ania: 1. Przeci|ane programy musz posiada tak sam nazw¹ oraz znajdowa si¹ w tym samym pakiecie8. 8 Mo|na tak|e przeci|a programy doBczone w sekcji deklaracji. 2. Przeci|ane programy musz ró|ni si¹ albo liczb parametrów, albo rodzajem typu danych parametrów (uwzgl¹dniajc pozycyjne porównanie). PrzykBadowo, w przypadku mechanizmu przeci|ania system bazy danych, który wykonuje program, nie mo|e stwierdzi ró|nicy pomi¹dzy typami NUMBER a INTEGER, ale b¹dzie to mo|liwe w przypadku typów NUMBER i VARCHAR2, gdy| nale| one do ró|nych rodzajów typów danych. 3. Procedura mo|e by przeci|ona funkcj, nawet je[li powy|sze dwa warunki nie s speBnione. 4. Przeci|ane funkcje musz si¹ ró|ni czym[ wi¹cej, ni| tylko typem danych warto[ci zwracanej. W przypadku niespeBnienia którego[ z wymienionych warunków zazwyczaj pojawia si¹ bBd wy- konania: PLS-00307: too many declarations of  <nazwa podprogramu> match this call. W niniejszym rozdziale przedstawiono ró|ne porady dotyczce programowania obronnego. Ten styl pracy uwzgl¹dnia mo|liwo[ wyst¹powania najgorszych sytuacji. PrawidBowo napisany program powinien radzi sobie z bB¹dnymi danymi wej[ciowymi nie dajc jednocze[nie bB¹dnych danych wyj[ciowych. Istnieje co najmniej kilka mo|liwo[ci unikni¹cia  syndromu bB¹dów na wyj[ciu . Niektóre z nich zostaBy omówione w trakcie omawiania sposobu tworzenia pakietu, który obsBuguje i chroni dane o ksi|kach przechowywane w bazie danych. Podsumowujc: " Nale|y zawsze pami¹ta o tym, |e zmienne lub parametry PL/SQL mog mie warto[ NULL, co jest szczególnie wa|ne w przypadku konstruowania instrukcji IF-THEN. " Nale|y wykorzystywa  obwoluty tabel i rozwija w sobie dyscyplin¹ potrzebn do u|ywania tej techniki. " Podczas deklarowania parametrów programów magazynowanych nale|y nadawa warto[ci domy[lne wsz¹dzie tam, gdzie jest to uzasadnione. " Ogólnie rzecz biorc, nale|y korzysta raczej z notacji wymieniajcej ni| pozycyjnej, szczególnie w sytuacji, gdy daje to dodatkowe informacje, które nale|y uwzgl¹dni. " Nale|y unika powtarzania tego samego kodu, w przeciwnym razie przyszBe jego modyfikacje b¹d bardziej nara|one na powstawanie bB¹dów. " Nale|y organizowa kod w postaci pakietów, zamiast u|ywania wielu pojedynczych procedur i funkcji. " Nale|y obsBugiwa wyjtki tam, gdzie jest to uzasadnione oraz przechwytywa je w sytuacji, gdy istnieje mo|liwo[ zaistnienia problemów, których tworzony program nie b¹dzie rozwizywaB samodzielnie. " Nale|y korzysta z mechanizmu przeci|ania w celu zmniejszenia zBo|ono[ci aplikacji, upraszczajc tym samym przyszBy jej rozwój. " Nale|y tworzy pewne programy testujce dla ka|dej z tworzonych jednostek programowych. W kolejnym rozdziale zostanie opisane rozszerzenie tworzonej aplikacji  na zewntrz , w kierun- ku u|ytkownika koDcowego poprzez utworzenie interfejsu u|ytkownika, sBu|cego do obsBugi nie- których z cech.

Wyszukiwarka

Podobne podstrony:
Oracle?tabaseg Programowanie w jezyku PL SQL or10ps
17 Procedury składowane w języku PL SQL (Oracle)
informatyka programowanie serwera oracle 11g sql i
Oracle?tabaseg Programowanie w jezyku PL SQL or11ps
Oracle8 Programowanie w jezyku PL SQL or8pls
SQL10G pl sql
kurs oracle podstawy sql
Linux Tablice informatyczne
informatyka windows 7 pl pierwsza pomoc adam jozefiok ebook
zasady sc i zasady etyki ksc tablica informacyjna

więcej podobnych podstron